Skip to main content

Sources

Docs: Perceptions, Plots, Policies, and Preferences. Web App: Select a Pane and open Programming, Perception, Palette, Policies, Plots, or Panes in its editor drawer.

Structure

A Pane carries its Perception and its Policies, and it owns a Palette and its Plots. Adding a Pane opens a dialog that asks for its name, one sentence on what it is for, and an icon; every Pane needs a description, shown in the band under its header. The Perception describes its native value and references to other Panes. Its React source renders the selected value; SQL Plots read or calculate data. Referencing another Pane does not transfer ownership or copy its saved settings. A Pane that owns a Plot declares its primitive in scalar-lib types, with preferences in its Perception. It owns one Plot, which returns rows of that type. A second computation gets a Pane of its own, and the Plots that need it read it by name. A Pane that owns no Plot, such as a settings or layout Pane, needs no such type. A save, Prepare or Publish that gives a Pane a Plot while its primitive is null, or a second Plot, is refused with PA-AU-049, naming the Pane and its Plots. A Pane the published Version already holds that way is history: its Warnings & Errors show it as info, which never blocks, and every other change still saves and publishes. A Pane reads at most 10,000 rows from a Plot. Read only what it draws: a chart or a total reads rows its Plot’s SQL has already aggregated, heavy work is read from a stored output, and a table a person browses reads a page at a time. See Large results. The editor drawer has one tab for each part: A Page has the same drawer, with a Plots tab that lists only its Panes’ Plots, because a Page owns none. The tab that holds the React source is Programming on both, the name the Policies tab gives the code. Switching tabs keeps each draft. Moving to another Pane or Page keeps the drawer open or closed and on the same tab, so a Pane’s Policies opens on the next Pane’s Policies. A Piece without that tab opens on its first tab. In a drawer too narrow for every tab’s name, the tabs other than the open one show their glyph alone, and name themselves on hover. In Auto the preview shows a Pane as a card centred on the canvas, as tall as what it draws. A missing or hidden source does not remove the Pane or its other tabs. The source editor shows Source unavailable, and a Plot remains listed even when its SQL is hidden. An allowed compiled Page or Pane still renders when its React or Perception source is hidden. Its declared Pane references remain available. Unsaved source edits use the editing preview until a matching build is available. An unsaved Perception or Policies change is not code the preview runs, so the compiled preview stays on the canvas while it saves. When Ponder takes a picture of a Pane, it uses the light or dark theme shown when you sent the Message, including your system theme when you follow it. A later theme change applies to new pictures; images already in the conversation keep the appearance in which they were captured. The host supplies these React props: A referenced Pane that throws while it loads or renders shows Couldn’t populate with its name and the error’s message in its place. The Page or Pane that mounted it and its other Panes keep rendering. When the Page or Pane on screen itself throws, the frame shows the same card. policies.capabilities.edit.preferences decides whether an editing action is enabled. Keep a control the requester cannot use on screen, disabled, with why: when seatCapabilities allows it, switching to their fullest participation mode turns it on; otherwise say who can. Hide only what a view capability or a filter Policy keeps from them. A true capability describes participant eligibility; capabilities.conditional means actual values or rows may still need condition checks: it is true when a filter Policy covers the Pane, from its holder’s tree, the line’s root Page for a Pane nothing declares, or the Pane’s own Plots, and does not let this requester read every row. It does not look at what the Pane’s Plots read. A filter narrows only a Plot that reads Provider data, so a Pane whose Plots read only settings, Workspace tables or literal values reads in full even when conditional is true. capabilities.writeConditional is true when a filter Policy for create, edit or delete binds this requester’s writes of the Pane’s shared settings (This Parable’s and every group’s): the write is checked against the filter’s conditions and may be refused by its value. It is never true for the Primary. When it is false, the requester’s shared-setting writes in the Pane pass every filter; when it is true, a Pane can enable a control only for the settings a Plot of its own says the requester may change, and say why the others are off. Neither boolean nor authorityKey authorizes a later request. When the host reads a Pane’s Policies again, after a setting changes or a write is refused, the decisions on screen stay until the new ones arrive, which then apply at once, a lost permission included; a control a capability gates does not blink out meanwhile. A Pane given another input is denied everything until that input’s decisions arrive. policies.admissions says, for each action and part the requester may take, which grant admitted them: by is participation (with the grant’s lowest listed level their seat meets), person, or role (with roleId and roleName), and setting names the This Parable setting whose value was the grant, when one was. A refused action and part has no entry. viewAs is true under a View as preview, where grants admit by participation alone. policies.seatCapabilities is present only while the page works in a participation mode below the seat the requester holds (under View as, the previewed person’s), such as a Publishing author in Peeking. It holds the decisions at that seat, in the shape of capabilities, while capabilities holds the mode’s. At the seat, and in a mode at or above it, it is absent. It never authorizes anything: the server refuses a change the mode does not allow, whatever seatCapabilities says. Use @parable/<parable>/<pane> for Props, key, preferences, plots, panes, plotApi, pages, and getParableContext(). These bindings use the saved Perception and declared Plot contracts. Other application components enter through declared Pane references; the approved React, Motion, Kysely, scalar, and shared-control libraries remain available. Only a Page is composition only: its code may import only the Panes it declares and the runtime layout modules. A Pane whose primitive is null can still use the shared controls and read its Plots.

Warnings & Errors

Every check reports a warning or error in a Page’s, Pane’s or Plot’s code the same way: what it is, the check that found it, its rule or code, and its line and column. The editor underlines each warning and error and marks its line in the gutter. Hovering it shows its message, its rule, and any fix as a button. A fix labelled changes behaviour can change what the code does; read it before applying it. The footer under every code editor lists the Warnings & Errors. Folded, it shows a count for each severity, or No Warnings & Errors. Opened, it lists each one with the check that found it and its line and column, errors first; choosing one moves the editor to that line. The footer stays open or folded as you move between Pieces, and each editor tab shows how many errors and warnings its document has. Warnings & Errors never block a save, and viewing a Parable never waits on them. Publishing does: a Publish refuses Changes while any Page, Pane or Plot in them has a warning or an error, and the refusal names each one and its counts. The Publish button says how many there are before you press it. Info findings never block. No code publishes unchecked: a file over 256 KB is too large to check, and a Publish refuses it until it is made smaller or split into more Panes; a file whose check could not finish is refused until a later Publish finds it checked. The code check, TypeScript and the build describe the text that was saved. Once you type, their underlines clear until the next save, and the editing preview reports errors in the text you typed. Checking for Warnings & Errors… means a result is not ready yet, and Warnings & Errors could not be checked gives the reason; neither means the source is clean. The code check runs where the server has its runner: local development and CI today. Until the runner ships to deployed Workspaces, the Piece API reports each checked file as failed with the reason, so an agent never takes it for clean, and a Publish there is not held for a check that cannot run; local development says Warnings & Errors are not checked on this server when the runner is not configured.

A Pane that does not build

Each Page and Pane compiles on its own. A Pane that does not build draws This Pane did not build and its first error where it would be, and the rest of the Page renders around it. Selected alone, it shows … did not build on the canvas, with every error listed under its code. Publishing refuses Changes in which any Page or Pane does not build.

Fixing Warnings & Errors with Ponder

Ponder reads and fixes Warnings & Errors with two tools. read_piece_diagnostics returns one Piece’s documents, its code and its Palette, each with its exact text, that text’s revision, and every current warning and error from the code check, TypeScript, the build and Plot SQL validation, with line, column, offsets and the text of the line. pending is true while a check has not answered for that text. For a Page or Pane it also returns the Perception source and the Policies, so Ponder reads one Piece whole without reading the whole Parable; Policies are left out for anyone without view permission on Policies. Ponder reads a whole Parable as an outline of its Pieces, with no code. edit_piece_source replaces exact passages of one document. Each passage must occur exactly once in the text, or nothing is saved and the refusal (PA-AU-045) says how many times it occurs. The edit is refused (PA-AU-002) when the document changed after it was read, so it never lands on text Ponder has not seen. Its answer carries the new revision and every warning and error after the save. A refused save tells Ponder which Piece, import or handle is at fault and its line and column, never the submitted code. When Ponder previews a Pane that does not build, the answer names the first error and the Pane to read. The Panes and Plots Powers teach the loop: read the Warnings & Errors, make the smallest edit that fixes one, and read them again. The Piece API returns the same Warnings & Errors as sourceLint on every package read and save result: lint for the code check and TypeScript, or a Plot’s recorded validation, and build for the compile.

Services

Render a referenced Pane with an inline primitive or a saved setting’s preferenceId. The host resolves the selection and supplies composition, owned Plots, and current policy decisions. Caller props cannot replace those decisions or bindings. A null-compatible Pane can render without a selected value; other Panes stay unfilled. Parable never picks a setting on its own. A Pane whose Perception declares preferences is always null-compatible and takes no preferenceId: its settings are its Preferences, which its code reads through preferences.values. preferences.mode reads live or versioned, and preferences.plotSql whether the settings are the Pane’s Plot SQL, as the Perception declares them; a save’s outcome says whether it applied live, published a Version, or proposed Changes (Preferences). The server resolves Panes in bounded batches through resolveParablePanes. A refused item does not discard permitted siblings. The host can also request capabilities alone without receiving values, source, bindings, or private schema. A compiled Page also keeps rendering when a declared Pane’s module is withheld from its reader. That Pane shows This Pane is unavailable in its place; the Page and its permitted siblings remain visible. A root Page without its own compiled module is still an error. Ordinary React state and Context coordinate inputs and charts without saving every change. A declared Pane’s module exposes its React exports as a Promise; React.use(panes.state.module) lets referenced Panes share an exported Context. Data refreshes and Current/Report changes do not need to recreate that state. Changing the requesting actor or Workspace replaces the renderer’s context.

Storage

A Pane’s Perception and Policies are fields of the Pane, saved and versioned with it. Its Palette and its Plots are Pieces the Pane owns. Creating a Pane creates its Palette, and deleting a Pane deletes its Palette and its Plots. Deleting a Pane is refused while another Page or Pane still uses it: one whose Perception declares it, or whose code reads one of its Plots. The refusal names them; change or remove them first. Reads never create settings or repair missing configuration. A Pane keeps a choice only when its code saves a setting; see Preferences. Parable applies no fallback between a person’s own setting (Me) and the shared one (This Parable). A Page is composition only. Its primitive is null; it arranges referenced Panes that own application values and queries.

Security

Using a Pane and its selected value requires current view.preferences access. Inspecting its Perception, Plot source, CSS, or Policies uses the corresponding view target. Permission to inspect source is not required merely to render an allowed Pane or read permitted SQL output. A permitted renderer receives executable JavaScript and CSS. Source-editor restrictions cannot make delivered assets secret. SQL source can remain private because named execution resolves it on the server. Every query and stored write checks current Policies independently of what the component displays.

What a Pane’s code can reach

A Pane’s compiled React runs in the reader’s browser inside a sandboxed frame with an opaque origin. That frame has no forms, no downloads, no pop-ups, no network access, and no remote scripts; everything it renders is inlined. Its only way to the application is the host bridge, which answers requests that name a live Page or Pane of the mounted Parable (its value, its settings and its Plots) under the reader’s own permissions, at a bounded rate, and starts the actions below only after a press. A Pane’s module names that Pane and the Panes it declares, but one frame renders a whole Page, so the host cannot tell which Pane’s code sent a request: Pane code can reach any Pane of the Parable the reader can, not only its own. The bridge also carries what the frame draws but cannot fetch: Font Awesome glyphs, and the company logos BrandLogo shows, which the host fetches through the app and hands over as image data. A Pane can preview SQL of its own in place of a Plot’s (plotApi.preview) in the Piece editor’s canvas and on a Page in Ponder’s chat. The host sends it to the server, which runs it only for a reader who may save that Plot’s SQL and refuses anyone else with HTTP 403, PA-AU-019 and the reason before any query starts (Plots). The preview camera and Labs refuse it. The frame cannot move the reader, but it can ask the host to. pages in the Pane’s module moves between the Parable’s Pages: The host answers open and back only just after a click or key press in the frame, only for a live Page of the mounted Parable (anything else is HANDLE_UNDECLARED), at most once a second, and only on a surface that has an address of its own: the Ponder routes do; the preview camera and Labs refuse with SCOPE_REFUSED. Call them from an event handler, never on mount. A Page is composition only and cannot import the shared controls, so a designed control that moves between Pages belongs in a Pane. A press counts as in the frame only when three things hold: the frame has focus, the browser reports a fresh click or key press, and the reader has pressed nothing elsewhere in the app since the frame took focus. Typing in Ponder’s composer, or clicking the app around the Page, is not a press in the frame, so Pane code that calls on a timer is refused while the reader works elsewhere. After a click outside the frame that leaves focus in it, the reader clicks into the frame again before it may act. One gap remains. Pane code that moves focus into its own frame, for example by calling focus() on one of its inputs, passes this check while the reader’s last press elsewhere is still fresh, about five seconds. The reader sees it: their typing lands in the Pane instead of where they were typing. For a reader who can use Ponder, the frame also reaches Ponder through the host (see Ponder): Each turn is an ordinary Ponder turn under the reader’s own permissions, with Ponder’s tools; a tool call that changes something waits for the reader’s approval in Ponder’s drawer. The host answers open, ask, path and continue only just after a click or key press in the frame, as it does pages.open, so Pane code cannot start a turn on mount, on a timer, or while the reader types in Ponder, short of the focus gap above. It checks that the calling Pane is one of the Page’s and that a named Plot is one it declares, and keeps one turn running per Pane. Labs, the preview camera, unsaved previews and View as get none of these. Stopping a turn ends its reply in Ponder, not only on the page: the host calls Ponder’s stop for the reply, so it runs no further, and the conversation shows it stopped. A new ask from the same Pane stops the last one the same way and waits for it to end before it sends, since Ponder runs one turn at a time per conversation. A turn stopped before its reply has started is stopped as soon as the reply starts. When a Pane’s remembered conversation no longer exists, the next ask starts a new one; any other failure, such as a cut off reply or a refusal, reaches the Pane and keeps the conversation. A turn a Pane starts is the one exception to a Pane reading only its declared Plots: it keeps the reader’s whole Workspace reach. The Pane names what the reader pointed at, and Ponder’s tools then read anything the reader may read, as they do in Ponder’s drawer. The Pane’s own Policies limit what its Plots return, not what that turn reads. Which Providers the Workspace has connected is Pane data: a Pane reads it with a Plot over workspace.providers and passes the rows to ImproveParable and PopulateParable, so anyone who can read the Parable sees connection health. Connecting one is an action, which the frame asks the host for: The preview camera, Labs and View as get no providers.connect, and the components there offer no Connect. A reader who may not create a connection reads “View only” on the setup page. It needs a click or key press in the frame, as pages.open does. Setup never runs in the frame: a credential form there would run in the author’s code, and OAuth needs a window the frame cannot open. The trust boundary is therefore the author, not the code. Authored code sees exactly what the reader it runs for is permitted to read through declared bindings and, after the reader presses something, what a Ponder turn reads and streams back as that reader. A sandboxed frame can still navigate itself, so an author who wanted to could send those rows somewhere else. Treat the ability to author or propose a Pane like the ability to write its SQL: grant it through Publishing permissions, review proposals before accepting them, and use Policies to limit what a Pane’s Plots return rather than expecting the renderer to hide anything from its own author. Policies do not limit a Ponder turn the reader starts from a Pane; the reader’s own permissions do.

Reference

Generated Workspace API reference for this Piece: