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 isfilters, 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:
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:
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.parablereads a row of a Pane of that Parable.participantsOfadmits people by their participation on that Parable.
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
parableto read this Parable’s own row); - the Workspace has no live line of it, or you cannot see that line;
- a
fromSettingnames a Page or Pane that the other line’s current tree does not hold; - a
fromSettingor a switch names a Page or Pane whose rows you may not read there (view.preferencesunder 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 byparticipantsOf, admits nobody.
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 holdfilterPolicies: 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
admitsgrant admits them: anyall_rowsreads every row; onlyhiddenreads none; otherwise the rows where any rule’s conditions all hold. A reader no rule admits getseveryoneElse. 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.
enabledis the authored default.enabledFromSettingnames 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 booleanenabledfield; 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 grantwhen 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
ownfilter 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 withQL-PL-015until it does. The refusal names the filter inerror.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_plotsets 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_plotset 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 ofview,create,editanddelete, as a database row policy names its commands.viewnarrows the rows of the Plots it covers.create,editanddeletelimit 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’spane_key,item_id,actor_kind,actor_idandvalue(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 anin_plotcondition reads the writer’s own set, and a refusal names the filter. A writer’s own Me rows are never limited. A Pane’spolicies.capabilities.writeConditionalis 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 setsview 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, theview.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.datadecides, 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.dataof the set or Version you read, and theview.dataof 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.dataof the set or Version you read decides alone.
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: