> ## Documentation Index
> Fetch the complete documentation index at: https://docs.parable.work/llms.txt
> Use this file to discover all available pages before exploring further.

# Policies

> Decide who can view, create, edit, and delete each part of a Pane, and which values and rows they see.

# Policies

Policies decide who can do what to each part of a Page or Pane. Every Page and Pane carries its own Policies, saved and versioned with it, that answer two questions: which action, and on which content. Policies exist so access is written down, reviewable, and enforced on the server, instead of implied by what a screen happens to show.

The actions are view, create, edit, and delete. The content targets are preferences (using the Page or Pane, its saved rows, and the rows its Plots return), pane (the React source), perception (the declaration), plots (the SQL of the Pane's Plots), palette (its CSS), policies (the Policies themselves), and data (the Pane's own data: view reads it, and create, edit and delete propose a change to an item). View and edit can name all seven targets; create and delete name preferences, pane, plots, palette, and data. A new Page or Pane needs a participant who may edit the Parable, and create.pane of the Page or Pane it lands under: the one that declares it, a Page's parent Page, or the Home Page for one under nothing. Each grant lists Parable permissions: peeping (the value for Peeking), pinging, publishing, and primary. Matching any listed permission allows the action, and broader participation includes the narrower permissions. A grant can also name people and Workspace Roles in actors, at most 50, each `{"kind": "person" or "role", "id": ...}`: it then also admits each person it names and anyone who holds a named Role in this Workspace, as long as they hold a seat on the Parable. Use names for the few people who need an action their participation does not give them, such as who may change a shared row for everyone, and give everyone else access through participation. A save that names someone outside the Workspace, or a Role that does not exist, is refused, and its details give the personId or roleId. View as decides by the previewed person's participation alone, so a name never shows in a preview. A grant can also read its value from a saved row with fromSetting, `{"paneKey": ..., "itemId": ...}`, naming one item of a Page or Pane of the same Parable. It reads This Parable's row of that item, else the Parable's Default row, never a person's or a team's (a person's or a team's row of that item is refused), and decodes the row's grant fields without its id: while they hold a valid grant, its levels and names replace the grant's own, and otherwise the grant decides with its own. That is how a Pane lets people change who may do something: make an Audiences Pane, a saved-data Pane whose type is a grant with an id (`export interface Audience extends ParticipantGrant { readonly id: Generic.Text }`, with ParticipantGrant imported from parable/foundation), have the Policy read one of its items, such as editors, and the Pane saves that item for This Parable. Draw the control with AudiencePicker from parable/panes/placeholders, whose value is that grant; its choices come from a Plot of the Pane over the Workspace's people and Roles, and audienceWidens says when a choice admits anyone new, so the Page can ask before it saves. Changing or deleting that row needs permission to edit the Policies that read it as well as the row's own grants, and each change is recorded. Set the Audiences Pane's own Policies so that only people who may edit those Policies write its rows. A save from the Pane's code of a row that a Policy reads asks the reader to confirm it in a dialog the host draws, and the server refuses it unless the Pane's author also may make it. A save or Prepare after which no active member could edit the Policies that the row governs is refused (PA-AU-068); a grant that admits nobody is still allowed. Filter Policies then narrow which rows a permitted person sees; they never grant an action, and they read the result columns of the Plots they cover. A Plot and a Palette have no Policies of their own: the Policies of the Page or Pane that owns them govern them for the same Version. A bound Pane uses its parent's Policies and cannot narrow them yet, so leave its own Policies at the defaults. There is no separate Policy Piece to attach or share.

Filter Policies decide which rows each reader reads across many Plots at once, and which shared rows each writer may create, edit or delete. A Page's or Pane's Policies can hold up to ten in filterPolicies, each `{key, name, actions, covers, enabled, enabledFromSetting, rules, everyoneElse}`. actions names the verbs it narrows, one to four of view, create, edit and delete: view narrows the rows of the Plots it covers; create, edit and delete let the writers it binds make that change to the shared rows (This Parable's and every team's) of the Panes it covers only when the row passes its conditions, which read pane\_key, item\_id, actor\_kind, actor\_id and value (JSON text): a create checks the new row, an edit the stored one and the new one, a delete the stored one, as the writer, and a refusal names the filter; a writer's own Me rows are never limited. covers is tree, the Plots of the holder and of everything it declares at any depth, and a Page's child Pages; or own, only the holder's own Plots. A Pane nothing declares, and a Page under no Page, fall under the Home Page, so a tree filter on Home covers every Pane of the Parable; put a filter meant for the whole Parable there. Every enabled filter that covers a Plot's Pane applies, joined by AND. A reader gets the union of the rules whose admits grant admits them (access all\_rows, rows\_where with conditions, or hidden), and everyoneElse when none does; the Primary always reads every row, so a condition every reader must meet, the Primary included, belongs in the Plot's own SQL. enabledFromSetting names one item of a Switches Pane, `{"paneKey": ..., "itemId": ...}`, whose This Parable row, else Default row, switches the filter live with a boolean enabled field, and changing it needs permission to edit those Policies. A filter applies above the Plot a Pane asks for and above each Plot SQL names; inside a Plot's SQL, a Plot it reads applies the filters that do not also cover the outer Plot, and every own filter that covers it, so no Plot reads past a filter from outside its reach. It binds only a Plot that reads Provider data, directly or through what it reads: such a Plot must output every column the conditions read, usually identity\_account\_id, or a reader it binds is refused with QL-PL-015; a Plot that reads only saved rows, Workspace tables or literal values reads in full. View as applies both people's filters, and a Report run applies none. Leave the Policies key filters as an empty list: write a Pane's row filter as an own filter Policy.

A missing target, a null target, or an empty list grants nobody access, including the Primary. Nothing inherits across actions or targets, so permission to edit does not include permission to view. Participants are separate from Policies and are not versioned, so adding or removing a participant takes effect on the next request in every Version. The React code receives resolved decisions that guide the interface but never authorize the next request; the server checks every request again. Proposed Policies cannot approve their own installation: changing them needs edit permission on policies under the Policies already in force. Rendering a Pane delivers its JavaScript and CSS to the browser, so hiding a source editor does not make those assets secret. SQL stays on the server, so readers can use a Plot's output without seeing its query. Plot output is read-only even if the Policies list create, edit, or delete. A restriction that must hold for every query over a Provider table belongs in that table's Provider Policy, which a Workspace administrator sets in Protection. Filters accept scalar conditions combined with AND and trusted values such as the authenticated email; an invalid or unsupported condition refuses execution rather than returning unfiltered data.

1. Write the access matrix first: ordinary readers, contributors, administrators, and support people. Separate using a value, inspecting source, editing configuration, and editing the Policies.
2. Ask Ponder to read the Page or Pane: Read a Piece's problems returns its Policies with its code and Perception, and the Parable's outline lists which Pieces have Policies. They are withheld from anyone without view permission on policies.
3. Ask Ponder to draft a complete replacement. Name each action and target explicitly, and add filter Policies only as restrictions.
4. Save the Policies with the Page or Pane in its Policy tab. Publishing mode saves to Changes and publishing activates the rules; Personal mode saves directly. A changed definition refuses a stale save: keep the draft, reload, review, and save again.
5. For a Plot, set its Pane's plots target for the SQL, its preferences target for who reads the rows, and a filter Policy for which rows. Put any rule that must apply to every query over a Provider table in that table's Provider Policy, not in one Pane.

Good Policies make every target an intentional choice and match the access matrix. Check them with real people or test accounts: an allowed actor succeeds, a denied actor is refused, a reader sees permitted data without the hidden source, an invalid filter refuses, and revoked access takes effect. A stale save and a self-authorizing change are both refused. Never infer authority from a UI label, an associated actor, or a Power.

Related Powers: Participants, Panes, Preferences, Plots, Publishing. Find each by its title; do not guess stored names.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.