Skip to main content

Sources

Docs: Panes, Perceptions, Plots, Preferences, and Primary. Web App: Select a Page or Pane and open its Policies tab.

Structure

Policies answer two questions: which action and on which content. These are a Parable’s Policies. Every Page and Pane carries its own Policies as part of its definition. They are saved and versioned with it, so each Version of the Parable keeps the Policies it was published with. There is no separate Policy Piece to attach, share, or delete. The Workspace’s rules for Provider tables are a separate layer, Provider Policies. They apply first, to every read of a Provider table, and a Parable’s Policies can only narrow what they leave. Participants are separate from Policies. The Parable’s participants and their permissions are not versioned, so adding or removing a participant takes effect on the next request in every Version. A Page’s or Pane’s Policies govern it and everything it owns: A Plot and a Palette have no Policies of their own; their Page’s or Pane’s Policies govern them. A bound Pane uses its parent’s Policies and cannot narrow them yet, so its own Policies stay at the defaults (bound-policy). A Page has no Plots. A Report’s schedule belongs to the Parable, not to a Pane: changing one takes the schedule permission and Publishing or Primary (see Who runs a schedule). view and edit can name all seven targets. create and delete name preferences, pane, plots, palette, and data. The Perception and Policies are fields of their Page or Pane: change them through edit; they are never created or deleted on their own. A missing grant admits nobody, for data as for every other target. Policies written before Typed Panes name no data grant. Convert a Versioned Pane writes them: each data grant is a copy of the preferences grant of the same action, so the people who could read and change the Pane’s values read and change its data. That copy needs no edit.policies, because it gives nobody a new right. Any other change of the data grants needs edit.policies. A Pane that holds data and whose Policies name no view.data grant is an error (data-grants).

Schema

All four action objects are required, and so is filters, which is always the empty list: a Page’s or Pane’s row filters are its filter Policies (below). Each target is independent: a missing or null target grants nobody access. An empty permission array also grants nobody access, including a Primary participant. Nothing inherits from another action or target. A new Page or Pane that names no Policies starts with these. A new Probe Page also gets view.responses at Publishing and delete.responses at Primary. Only a Probe Page has the responses target.
participantPermission is an array of existing Parable permissions: peeping (Peeking), pinging, publishing, and primary. Matching any listed permission allows that action. Broader participation includes its subordinate permissions. Unknown fields, targets, permissions, and repeated permissions are refused. A grant can also name people and Workspace Roles in actors, a list of at most 50, each a person or a role with its id, none named twice. The grant then admits anyone a listed permission admits, each person it names, and anyone who holds a named Role in this Workspace:
A name admits only someone who holds a seat on the Parable: every action needs participation first, so naming someone without one reaches nothing. A Role counts while it exists and the person’s membership is active; a parent Role does not pass it down, and holding it in another Workspace does not count. A save that names someone who is not an active member of the Workspace, or a Role that does not exist, is refused. A name already saved stays when that person leaves or the Role is removed, and admits no one. A grant can also take its value from a saved row with fromSetting: the key of a Page or Pane and the id of one of its items. This is how a Pane changes who may do something: it saves the row, and the Policy reads it. The Pane that holds such rows, such as an Audiences Pane, is a saved-data Pane whose type is a grant with an id:
In Publishing mode, Policies change through a Version. What must change for every Version at once, such as an audience a Policies Page edits, is a row a Policy reads: every Preference is Live.
The Policy 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, because it would change only what that person’s read shows, not what the server enforces. While the row holds a valid grant that reads no setting itself, its grant fields, without its id, replace the grant’s participantsWith and actors. A missing or invalid row leaves the grant’s own, so the grant above admits the Primary until someone saves editors. The Page or Pane it names is part of the same Parable, unless the reference names another Parable (Read another Parable). Changing or deleting the row needs permission to edit the Policies that read it, as well as the row’s own create, edit or delete.preferences, and its value must be a valid grant whose names belong to the Workspace. Every change is recorded with its value before and after. Set the Audiences Pane’s own Policies so that only people who may edit the Policies that read it write its rows. A person or Team row saved before the Policy started to read the item stays stored. Layered reads ignore that row and show the Workspace or default value that the Policy uses. A save from a Pane’s code of a row that a Policy reads asks the reader to confirm it in a dialog that the host draws, and the server refuses it unless the Pane’s author may make it too. A save after which no active member could edit the Policies that a row governs is refused (PA-AU-068). Prepare lists such a Patch as a finding that stops Publish. A grant that admits nobody is still allowed. When a Policy starts to read a row, Prepare shows the row with its value. The Policies tab sends edit grants that name a Role, a person, or a setting to the server. In Personal mode, the server refuses a save or archive import that removes the last active person who holds a participation and may change the Policies of a Page or Pane. A new Page or Pane must have at least one such person. In Publishing mode, Prepare and Publish make that check before the Changes take effect.

Read another Parable

A Policy can use what another Parable holds, in the same Workspace. Two parts of a grant name the other Parable by its id:
  • fromSetting.parable reads a row of a Pane of that Parable.
  • participantsOf admits people by their participation on that Parable.
This is how one Parable keeps answers for other Parables. For example, a Policies Parable keeps the answer “Who can change Policies?” for Perceptions. Perceptions reads the answer, and anyone with Primary on Perceptions may change it in Policies:
A Workspace holds at most one live line of a Parable. The read takes that line in the reader’s Workspace. A copy of a Platform Parable has the same id as its source, so one Release of Perceptions reads each Workspace’s own copy of Policies. Which row. The read takes the other line’s This Parable row of the item, else its Default row, as a read of the same Parable does. A row is not part of a Release. A saved answer applies at once, and a switch saved there turns a filter on or off at once. On a copy of a Platform Parable, the Default row is the one that the copy’s current Release brought, so an answer of Parable staff applies with the next Release of the Parable that holds it. The read never takes a row about a subject: a row that a Pane with a Parable.Subject field saved with its subject. Such a row shows only to a reader who can read its subject, and the Parable that reads it would show its levels to its own readers. The server and the Query Layer both skip such a row. The value. The row’s value holds participantsWith and actors only. The server judges it against the reader’s seat on the Parable that reads it. “Publishing” in the row for Perceptions means Publishing on Perceptions. A value that holds participantsOf or fromSetting is not a grant: the server and the Query Layer both apply the reading grant’s own value instead. Who is admitted by participantsOf. Each entry names a Parable and up to four participations. It admits a person whose seat on that Parable’s line meets a listed participation. The person still needs a seat on the Parable whose Policy decides, as for every grant. On a copy of a Platform Parable that is Visible, every member of the Workspace holds Pinging, so a person with Primary on Perceptions and no participation of their own on Policies passes. When the page works in a participation mode below the person’s seat, that mode also caps their seat on the other Parable. Under View as, participantsOf admits nobody. admissions names the other Parable in parable when participantsOf admitted the reader. When the other Parable is missing. If the Workspace has no live line of the named Parable, or that line has no row, the grant’s own participantsWith and actors apply. A participantsOf entry with no seat there admits nobody. A check that cannot read the other Parable’s row admits nobody by that grant, because the grant’s own value may admit more people than the row does. Who may change the row. The Policies of the Pane that holds the row decide, with participantsOf when that Pane names the Parable that reads the row. The Parable that reads the row does not check its own edit.policies for that save. When a Policy reads a row of another Parable, the Parable that reads the row gives that answer to the people the other Pane admits. The save of such a row does not know that another Parable reads it. So the protections for a row that a Policy of the same Parable reads do not apply: no confirm dialog for a save from a Pane’s code, no lockout check (PA-AU-068), no check that the value is a grant, and no parable.policy_setting record. The row’s own history still records each change. Give the Pane that holds such rows Policies that admit only the people who may change the answers. Where it is allowed. Every grant may read a row of another Parable with fromSetting.parable, and a filter Policy’s switch may name one in enabledFromSetting.parable. The Query Layer decides view.preferences and filter Policies in SQL, and it reads the other Parable’s row there too. So AI ROI’s filter “Hide data outside reporting chain” can take its switch and its “Sees every row” audience from Policies. participantsOf is not allowed in view.preferences, create.plots or a filter Policy’s audience, because the Query Layer decides them and judges a seat on this Parable only. The save refuses it there. Save checks. A save that adds another Parable to a Policy is refused when:
  • the Parable is this Parable (drop parable to read this Parable’s own row);
  • the Workspace has no live line of it, or you cannot see that line;
  • a fromSetting names a Page or Pane that the other line’s current tree does not hold;
  • a fromSetting or a switch names a Page or Pane whose rows you may not read there (view.preferences under that line’s current Policies). A seat on the other line is not enough. In that check, a grant of the other line that reads a third Parable, or that admits by participantsOf, admits nobody.
The refusal does not say whether a Parable that you cannot see exists, or whether you may read the row. A later change that narrows the other Pane’s view.preferences does not remove a binding that a save already made. A Delivery, a staff move, and every change to a copy of a Platform Parable apply Policies that a person already saved on the source, so they do not repeat these checks.

Filter Policies

A Page’s or Pane’s Policies can hold filterPolicies: at most ten, each deciding which rows a reader reads of the Plots it covers, and which shared rows a writer may create, edit or delete on the Panes it covers. covers says what it covers: tree, the Plots of the Page or Pane that holds it and of everything that Page or Pane declares, at any depth, and a Page’s child Pages; or own, only the holder’s own Plots. A Pane no Page or Pane declares, and a Page under no Page, fall under the Parable’s Home Page, so a tree filter on Home covers every Pane of the Parable. A read applies every enabled filter Policy that covers the Plot’s Pane, joined by AND, so a Pane under two filtered Pages is held to both.
  • Audiences. A reader gets the union of the rules whose admits grant admits them: any all_rows reads every row; only hidden reads none; otherwise the rows where any rule’s conditions all hold. A reader no rule admits gets everyoneElse. The Primary always reads every row, so a condition every reader must meet, the Primary included, belongs in the Plot’s own SQL. A rule’s grant can name people and Roles and read a saved row, like any grant.
  • The switch. enabled is the authored default. enabledFromSetting names one item of a Switches Pane, whose This Parable row, else Default row, turns the filter on or off for every Version at once with a boolean enabled field; changing it needs permission to edit the Policies that read it, and every change is recorded.
  • What the tabs show. The Policies tab asks the server whether a saved setting turns each filter on or off. The Performance tab asks the same server for the audience that a saved setting supplies. It shows holds no grant when the setting supplies none. Both tabs read again after the setting changes. If you cannot read the shared Preferences of the Page or Pane that holds the setting, the tabs show that its decision is not known.
  • Where it applies. Above the Plot a Pane asks for, and above each Plot your SQL names. Inside a Plot’s SQL, a Plot it reads applies the filters that do not also cover the outer Plot, which meet the rows above it instead, and every own filter that covers it, which applies at each read of its Plots. So no Plot reads past a filter by reading a filtered Plot from outside the filter’s reach.
  • Plots about people. A filter applies to a Plot that reads Provider data, directly or through the Plots and stored outputs it reads. Such a Plot must output every column the conditions read, usually identity_account_id: a read the filter binds is refused with QL-PL-015 until it does. The refusal names the filter in error.details.filter, and the Pane shows “Hidden by” and the filter’s name instead of an error. A Plot that reads no Provider table, only saved rows, Workspace tables or literal values, reads in full.
  • View as. A preview applies both people’s filter Policies.
  • Runs. A Report run applies no reader filter while it writes one stored table per Plot. Each read applies the current filters of the Parable that stored it and its upstream Platform Parables. The run records which output columns retain each source’s filter keys. A Plot that loses a required key refuses storage with QL-PL-022. Current data retries once as live saved SQL (Reports).
  • Refreshes. A filter is access control, and access control is always current. Under a chosen Refresh the rows are that run’s, but the filter’s conditions, and the in_plot sets they read, read the data as it is now: a reader the reporting-chain filter narrows sees the Refresh’s rows for the people in their chain today. If a new filter needs a column the stored output did not retain, the read refuses that output. Current data can retry live. A chosen historical Refresh stays pinned and returns the refusal.
  • Typed rows in a condition. An in_plot set whose Plot reads a Pane’s rows by name reads them with no reader: This Parable’s and Default rows, never a person’s or a team’s own. A reader cannot widen their own filter by saving a row of their own. A value that does not decode for its column refuses the read instead of reading as not set.
  • actions. The verbs it narrows, one to four of view, create, edit and delete, as a database row policy names its commands. view narrows the rows of the Plots it covers. create, edit and delete limit the shared rows, This Parable’s and every team’s, of the Panes it covers: a writer such a filter binds may make that change only when the row passes its conditions, which read the row’s pane_key, item_id, actor_kind, actor_id and value (JSON text). A create checks the new row, an edit both the stored row and the new one, and a delete the stored row. The check runs as the writer, so an in_plot condition reads the writer’s own set, and a refusal names the filter. A writer’s own Me rows are never limited. A Pane’s policies.capabilities.writeConditional is true where such a filter binds the requester (Panes).

Services

The Policies tab shows the selected Page’s or Pane’s Policies. Ponder reads one Page’s or Pane’s Policies with Read a Piece’s problems, under the same view permission on Policies. The info glyph at the right of the tab’s header says that Page and Pane Policies apply to everything they own. The tab reads left to right in three columns, like drilling in. The first lists the Page or Pane, then each Pane it declares, as a tree: a Pane several Panes declare is listed once, under the first that declares it. Selecting one shows, in the third column, its own row of View, Create, Edit, and Delete. Each is the same picker a Pane’s audience rows use: Nobody, or a participation (Primary, Publishing, Pinging or Peeking) and any Workspace Roles and people it names. A participation admits everyone at or above it, so Pinging also admits Publishing and Primary participants; to narrow one, take away the participation above it. Each of the row’s choices sets that action on every part of the Page or Pane: View sets view on every part, and Create, Edit and Delete set that action on every part that has it. Edit never covers who may change the Policies themselves. When the parts differ, the choice reads Mixed, and one choice sets them all. Choices for a declared Pane save to that Pane’s Policies, and Open selects the Pane; saving a Page’s Policies does not change a Pane’s. Most Policies are set there. The second column, Advanced, lists the selected Page’s or Pane’s parts, each a row of its own: Preferences, Perception, Programming, Palette and Policies. Selecting a part shows its row in place of the Page’s or Pane’s own; selecting the Page or Pane again goes back to its own row. In a narrow drawer the two lists sit side by side above the row. Programming is who sees and changes the React code and its Plots’ SQL. The Performance tab’s Policy decisions use these same names, so the code and the Plots are both Programming. Programming starts at the Page’s or Pane’s own row; set it apart to let people use or configure a Pane without seeing or changing how it is built. A later choice on the own row sets Programming again, so set it apart after one. A Page’s Programming has no Plots. Who may change the Policies is set in the Policies row alone. Under a Page’s or Pane’s own row, its filter Policies are one list. Each row shows the filter’s name; the verbs it narrows (View, Create, Edit, Delete), each a toggle, at least one on; its switch; then Everyone except with the audience it never narrows, besides the Primary; then what everyone else keeps, Rows where its conditions hold, or Nothing. The conditions are chips: a column, an operator and a value, joined by AND, read from the columns every one of the Pane’s Plots returns for View, and from a saved row’s columns (its item, actor, team, Pane and value) for the other verbs. A condition only SQL can say, such as in_plot(...), shows as its SQL and is kept as written. Drag a row by the grip that takes its bullet’s place on hover, or move it with Space and the arrow keys; the order changes nothing, since every filter applies. Add filter starts a new one, which saves once it keeps something. A filter with several audiences of its own shows its name, verbs and switch, and leaves the rest to Ponder. A filter whose switch a saved setting controls names the Page or Pane that holds it, as On, switched by Who sees what. The tab asks the server for that state. When the setting holds no value, the server uses the switch written in the Policy. The switch shows the answer and does not change it. The server gives no answer if you cannot read the holder’s shared Preferences, or the composed Parable no longer holds that Page or Pane. While the answer loads, and wherever you may not know it, the filter names the holder as Switched by Who sees what and shows no state. A grant that reads a saved row names it under its choice, as From setting rename of Changes for everyone. Once that row is saved, it decides who is admitted; the choice sets who is admitted until then, and choosing keeps the row each part reads. A filter’s Everyone except audience reads its row too. While the row holds an audience, the filter shows that audience, which the server admits in place of the filter’s own, and its picker is locked: From setting seesEveryRow of Who sees what. While the row holds none, the picker shows and sets the filter’s own audience, and a choice keeps the row: Until setting seesEveryRow of Who sees what is saved. While the tab cannot tell, it shows the filter’s own audience and says so: Unless setting seesEveryRow of Who sees what is saved. Each choice saves as it is made, like the rest of the definition: Personal mode saves the working definition directly, and Publishing mode saves it to Changes, which take effect when published. A new filter saves once it has a name, a verb and something to keep. If the Policies changed elsewhere after you started, your draft is kept and the panel offers to apply it to the latest Policies or discard it; for a declared Pane, the panel names that Pane. For edit grants expressed only through participation levels, the tab holds a choice that would lock you out and says why. It sends grants that name people, Roles, or a setting to the server checks described above. When you may not change the Policies, the controls are off and the tab’s header reads Read-only. When you may not see them, it reads Policies hidden; if you may still change them, Replace starts a complete replacement at your own participation.

Security

Source inspection of a published Version follows the Policies the line holds today and the requester’s current participation. Selecting an older Version does not recover access to SQL, React, or Perception source that current Policies hide. Saved rows also follow current Policies, and they are not part of a Version: a reader of an older Version reads today’s rows, and a Policy reads today’s row. A Pane’s data has a floor too. When a Pane reads its data, or its items are read by id or by page, in a set of Changes or in an older Version, the view.data grant that applies depends on the line’s history of that Pane. A Preview of a set of Changes captures Pane data by the same rule (Reports):
  • The current Release holds the Pane. The current Release’s view.data decides, also when its data is empty. A set or an older Version cannot give back data that the line has since hidden.
  • A later Release removed the Pane. Both grants must admit you: the view.data of the set or Version you read, and the view.data of the newest Version of the line that held the Pane. So a set that adds the Pane back can narrow who reads its data, but it cannot widen it.
  • No Version of the line ever held the Pane. The view.data of the set or Version you read decides alone.
The history of a composed Parable includes its own Releases. On a Workspace copy, it also includes the upstream Release the copy accepted and its earlier Releases. A newer upstream Release cannot widen or narrow this floor until the copy accepts it. The Releases of another Workspace’s copy never count. Live Plot and SQL reads use the same floor for saved settings and Pane data. When a Problem adds back a removed Pane, both the Problem’s Policies and the Policies of the newest accepted Release that held the Pane must permit the read. Missing or invalid retained Policies refuse the read, including for a person with Primary. A Pane never held by an accepted Release keeps the Problem’s Policies. View as cannot widen the real reader’s access. Both the previewed participation and the real reader must pass every Policy required by this floor. The floor does not change which published filter Policies apply. On an installed Parable, the current definition includes the exact Version the Workspace accepted and its own changes. Publishing a newer upstream Version does not change that pin. A local Policy override takes precedence over the inherited Policy, and a deleted Piece cannot recover access through its base. A Pane’s React receives resolved decisions in props.policies; they guide the interface and never authorize a request. A reader without view.policies does not receive the Policies text. View as decides by the previewed person’s participation alone. A Page’s or Pane’s grant that names them, or a Role they hold, does not apply in the preview, since it may admit them where it does not admit you. A filter Policy row that names them or their Role does apply: such a row can narrow what they read, and your own filter Policies still apply beside theirs, so the preview never shows you more than you read. Creating a Page or Pane needs a participant who may edit the Parable, and create.pane of the Page or Pane where it lands, by the Policies that Page or Pane held before the change. A create.pane grant to Peeking or Pinging does not let a participant who may not edit create one. A Pane lands under each Page or Pane that declares it, and a Page under its parent Page. A Pane that nothing declares, and a Page under no Page, land under the Home Page. When that Page or Pane is new in the same change, the question passes up to where it lands, so the Policies a new Page or Pane carries never authorize it. Restoring a deleted Page or Pane is judged by the Policies it held when it was deleted. Restoring unchanged content needs delete.pane. Changes made during restoration also need their usual permissions: edit.pane for the Page or Pane and its React, edit.perception for Perception, edit.plots or create.plots for Plots, edit.palette for its Palette, and edit.policies for Policies. Omitted owned parts return with their stored source and identities. If the retained content needed to check a restore is unavailable, the restore is refused. Without recorded Policies, only the Primary may restore it. Changing Policies needs edit.policies under the Policies already in force. Policies in a draft or in an incoming Version cannot approve their own installation. A Plot that a filter Policy’s in_plot condition reads, or a Plot that such a Plot reads, decides who reads which rows. So changing or deleting it also needs edit.policies on each Page or Pane whose filter Policies read it. The refusal names that Page or Pane and the Plot. A proposal from a Pane’s code asks for this right before the host asks the reader to confirm. A delete retains the Page’s or Pane’s stored Policies. Sending different Policies with a delete, including a repeated delete, cannot change who may restore it later. Source changes require a live Piece; a save cannot hide a source edit behind a deleted Page or Pane. view.plots governs SQL source inspection; view.pane governs React source inspection. A permitted Pane can render without granting source-editor access. Rendering React or CSS delivers executable code or styles to the browser, so this distinction does not promise secrecy for those assets. SQL stays on the server while permitted readers consume its output. A Plot’s rows follow its Pane’s Policies: view.preferences decides who may read them, and the filter Policies that cover it narrow them. Plot output stays read-only even if the Policies grant create, edit, or delete. A restriction that must hold for every read of a Provider table, in every Parable and in SQL, belongs in that table’s Provider Policy, not in one Pane’s Policies. A Publish acts for one person, and a Refresh then runs the published SQL with the Parable’s authority. So a Publish refuses SQL that reads a Plot that the person who publishes may not read by its Pane’s view.preferences, whoever saved that SQL (Plots). A person whom a Pane keeps from a Plot cannot copy its rows into a Plot on another Pane, directly or through another Plot. Filters further restrict rows; they never grant an action. For example, a Pane’s own filter can leave each reader but the Primary only the rows belonging to their email:
A filter’s conditions read the result columns of the Plots it covers; a Provider Policy uses the same language on the table’s columns. Conditions do not authorize replacement of the Policies themselves. Unsupported or invalid conditions refuse execution. See Execution context for filter and Report limits.