Skip to main content

Sources

Docs: Perceptions, Plots, Policies, and Preferences. Web App: Select a Pane and open Programming, Palette, Policies, Preferences, 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 declares the Pane’s one type, what it shows and what people save on it, and its references to other Panes. Its React source renders the Pane; SQL Plots read or calculate data. Referencing another Pane does not move the Pane or copy its saved rows. There are four kinds of Pane (Kinds of Pane):
  • A Plot Pane owns the Plots it draws. Its type, in scalar-lib types, is the kind of the rows of the one Plot its Perception does not declare. Each other Plot declares its own contract. A computation that other Panes read, or that has its own lifecycle, gets a Pane of its own, and the Plots that need it read it by name.
  • A bound Pane has no SQL. One field of its parent’s row feeds it as props.value, and it uses its parent’s Policies (Bound Panes).
  • A saved-data Pane has no SQL. Its type has an id field, and the values people save on it are Preferences: rows of its type, one for each item and each actor. A Plot on a saved-data Pane would make it a Plot Pane that refuses every save of a row, so the saved-data-plot rule refuses it. Give the Plot a Pane of its own.
  • A layout Pane has a null type, so it holds no saved rows.
A new kind of thing is a new Pane, and many things of one kind are rows. Any Pane can also own data of its own, which only a proposal changes. A save, Prepare or Publish that gives a Pane an undeclared Plot while its type is null, or a second undeclared Plot, is refused with PA-AU-049, naming the Pane and those 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. Add no other copy. A label names its control or value in the fewest words. A Pane adds no sentence that explains a control, says where a value came from, tells the reader they can change something, or repeats what a control already shows. A disabled control’s reason, the reading, empty, cut-off and error states, and the sentences ImproveParable and PopulateParable carry are not extraneous: the reader needs them to act. 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 saved rows, 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 rows (This Parable’s and every team’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 writes in the Pane pass every filter; when it is true, a Pane can enable a control only for the rows 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 row that a Policy reads 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 saved row whose value was the grant, when one was. parable names the other Parable when the requester’s participation there admitted them (participantsOf). 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, Item, Row, key, namedType, namedTypes, preferences, data, propose, plots, panes, plotApi, pages, getParableContext(), and useParableContext(), which renders again when the host sends a new context. These bindings use the saved Perception and declared Plot contracts. namedType is the named type the Pane shows, as its Perception declares it, or null when it shows none, and namedTypes holds every named type the read describes, by key (Read a named type at runtime). 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 type is null owns no undeclared Plot, but can still use the shared controls and read the Plots of the Panes it declares.

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 checks run when a Piece is saved, at Prepare and at Publish, and when Ponder reads a Piece’s problems; opening a Piece shows the result of the last check and never runs it again. A file that no check has answered since the checks changed shows Checking for Warnings & Errors… until the next save or Publish. The checks run in every Workspace. Where one cannot run, the Piece API reports each checked file as failed with the reason, so an agent never takes it for clean, and a Publish waits until the check runs.

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 a Piece’s problems 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 part of a Piece’s 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. Every read and save of a Parable’s contents returns the same Warnings & Errors: the code check and TypeScript, or a Plot’s recorded validation, and the build.

Checking that Panes draw

Check a Pane (check_pane) tells Ponder which Panes do not draw, without a browser. It reads the given Changes, or the Parable’s own content, and checks the named Panes, or every Pane. For each Pane it reports:
  • placed: false when no Page shows the Pane (the unplaced-pane note).
  • drawsWithoutInput: false when the Pane waits for a value that no parent hands it (the needs-input note), and acceptsNull from its runtime binding.
  • resolution: what panes/resolve gives the Pane with no Preference selected, or why it refuses the Pane.
  • plots: the rows each Plot of the Pane returns, at most 50 for each Plot, and at most 20 Plots for each check. A read that fails gives its reason. A Plot that takes inputs uses its saved parameters. When it has none, the check reads it with null for each input.
  • diagnostics: the counts that Read a Piece’s problems reads.
Each problem is one sentence that names the fix. A Pane that a Page shows, at any depth, whose code draws nothing on every path is a problem (the draws-nothing note). A Plot with no rows is a note, not a problem. A Plot whose input does not take null is not read, and that is a note, not a problem: the check has no value to send it, and the Pane sends its own. The check does not run that Plot’s SQL, but an error or a warning in its diagnostics is still a problem. A Plot whose read fails is still a problem. clean is true when no Pane has a problem and no check is pending. placed and drawsWithoutInput are null while the lint of the Pane’s code has not answered. When that lint could not run, they are null and the Pane has a problem that gives the reason. When the read has no checked code for the Pane, because it has no code or the reader may not see its code, they are null and the Pane has a problem. The check does not find code that throws while it draws or a broken layout. The Pages Power tells Ponder to end a build only when the check is clean. When Check a Pane is available to Ponder, the answer of each completed Edit Pieces or Edit part of a Piece’s source call gives a nextStep: call Check a Pane with that Parable and its Changes. A check that is not clean gives a nextStep too: fix each problem it names, then call Check a Pane again with the same arguments. An edit whose outcome is unknown gives a nextStep that names the read to make before any new edit: the Piece, the Changes or the Parable that the edit named.

Services

Render a referenced Pane with an inline primitive of its type, or with none. 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 saved row on its own. A Pane reads its rows through preferences (Preferences), its own data through data, and changes the Parable only through propose, which the reader confirms. A bound Pane receives its value as props.value from its parent’s row, so it needs no read of its own. Its saved rows arrive with the Pane’s load when its Perception sets preload, and later saves, by anyone, update them in place. The server resolves Panes in bounded batches. 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 rows or repair missing configuration. A Pane keeps a choice only when its code saves a row; see Preferences. A read layers a person’s own row (Me), This Parable’s and the Parable’s Default, field by field. A Page is composition only. Its type 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. Because the frame has no forms, a form’s submit never runs its handler: handle the button’s click and the field’s Enter instead. The Code check warns about a form’s onSubmit or action and a button’s formAction. The frame’s 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 saved rows and its Plots) or the Parable’s files (Files in Pane code) under the reader’s own permissions, at a bounded rate. The Workspace’s files are the one exception: their own rules decide (The Workspace’s files). The bridge 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 host refuses it in Labs and in the pictures Ponder takes of a Pane. 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. A Parable open in the app has one. Labs and the pictures Ponder takes of a Pane have none, and the host refuses them there 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. The frame also reaches Ponder through the host (see Ponder). ponder.path is every reader’s; the rest need a reader who can use 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 column. The host answers compose, 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 and one path per part it explains. Labs, unsaved previews, View as and the pictures Ponder takes of a Pane 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 column. 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 which of their streams are on over workspace.provider_connections, and passes the rows to ImproveParable and PopulateParable, so anyone who can read the Parable sees connection health. A Provider or stream that is missing reads as an empty table, so the Pane draws its empty state rather than failing. Connecting one is an action, which the frame asks the host for: Labs, View as and the pictures Ponder takes of a Pane 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. A row that stands for a record in a Provider, such as a pull request on GitHub, can link to it. The frame cannot open a tab, so it asks the host: openExternal comes from the Pane’s module, beside pages, and ExternalLinkButton calls it for a row. The host opens only an https URL. It refuses javascript:, data:, file:, a relative address and a URL that carries a user name or password with SCOPE_REFUSED, and plain http too. It opens a link only just after a click or key press in the frame, as it does pages.open, so Pane code cannot open one on mount or on a timer, and one press opens one tab: opening a tab spends the press. It never moves the Parable page: the link opens in a new tab or not at all, and a browser that blocks the tab does not tell the Pane. Every surface the reader can press opens links, Labs and View as included. A Pane can also start a run of the Parable’s Report. When a saved row that a Pipeline read changes after the Refresh that made the Pane’s result started, the Pane shows These settings changed since the last run, with Preview and Run. The notice asks the host: The host starts a Preview or a Refresh only just after a click or key press in the frame, as it does pages.open, so Pane code cannot start one on mount or on a timer. Under View as, and on a Parable whose Pipelines are off, the host starts neither, and refresh.available answers false. The server then checks the person who pressed: a Preview or a Refresh starts only for a person who holds Publishing or Primary on the Parable and the Workspace’s permission to manage Parables. The trust boundary is therefore the author, not the code. Pane code sees what the reader it runs for is permitted to read through declared bindings and the files module. After the reader presses something, it also sees what a Ponder turn reads and streams back as that reader. The Workspace’s files are the one exception. For them, the reader’s seat, the declaration in the Pane’s Perception, and the permissions of the people who last saved the code decide (Files in Pane code). A sandboxed frame can still navigate itself, so an author who wanted to could send those rows somewhere else, and a link a Pane opens goes to whatever https address its author chose. 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. A Pane’s code never acts with more rights than its author. Every proposal (propose.change, propose.piece), every save of a row that a Policy reads, and every save of a Default row is a privileged write. The host draws a confirmation outside the frame that names the Pane, its author and the change. Only the reader’s click on it lets the write go (PA-AU-069). Pane code cannot draw or click it. One kind of proposal needs no click: see Changes that apply at once. A value that comes from the Pane’s code, such as an item id or a new Piece’s name, shows apart from the host’s words, in its own code element, cut to 40 characters with an ellipsis. The full value shows when you point at it. The server then allows the write only when the reader holds the right and each person whose code acts in the frame holds it too (PA-AU-070). The host asks only after every other check passes: a reader who lacks a right the change needs, such as edit.policies on a Page or Pane whose filter Policies read a Plot the change edits, is refused first, and no set of Changes opens. These people are each person who last saved the code of a Page or Pane that the frame draws, and each must be an active member of the Workspace where they saved the code. Code that the platform saved counts for nobody, so a frame with only platform code is refused. A Default row also needs each of them to hold Primary. Each person is checked where they saved the code. On a copy, code that came with a Release is checked on the Parable the copy comes from, with that line’s current members, seats and Policies, and code saved on the copy is checked on the copy. This holds for an older Version of the copy too: each row of code is checked on the line where it was saved, against that line’s current tree. So when a later Release removes the Pane on the source, a write from that Pane’s code in an older Version is always refused. This rule is the same for a copy of a Platform Parable: Parable staff wrote its code, so their rights on the platform line cap it. The confirmation and the refusal name only people of the reader’s own Workspace. Other people show as people from the Parable the copy comes from. View as refuses every privileged write. A reader’s own rows save with no confirmation. So do team and This Parable rows that no Policy reads.

Changes that apply at once

A Parable’s own Pane code may change its Pane data with no confirmation (PARABLE-9409). The change goes into the reader’s own Pending Patch and shows at once. The server decides this. It needs all of these:
  1. The change is an edit of Pane data (propose.change with data). A change to Policies or SQL, and a new Plot (propose.piece), still ask.
  2. The Parable has Published Versions. On a Personal Parable a change is live at once, so it still asks.
  3. The reader holds Publishing or Primary.
  4. Each person who saved code that the frame draws saved it on this Parable. Code that came with a Release from the Parable a copy comes from still asks. The frame runs the Parable’s own code, or the code of the Patch that the change goes into. Code that a colleague saved in their own Patch still asks. Code that a colleague saved in the reader’s own Patch still asks too. A colleague with Publishing who sees a Problem that a person started can save code into its Patch. So the reader must have saved each Page and Pane code in the Patch that differs from the Parable’s own code.
  5. The reader may view the changed Pane’s data, so the banner can list each item.
  6. The change goes into a Patch that the reader started and that is still Pending. With no Patch named, the server picks the reader’s newest Pending Patch or opens one in a new Problem, Changes from the Pane’s name. A colleague’s Patch still asks.
Every other check runs first and does not change. The reader’s seat and Policies, the Pane’s data grants and the author’s cap (PA-AU-070) apply as for a confirmed change. View as refuses the change. With no Problem open, the host first asks the server whether the change would apply at once. Nothing is written yet. When it would, the host starts the Problem where the Start Changes rule puts it and sends the change into it, with no dialog. While a person reads a Pending or Proposed Patch, the host draws the Unpublished Changes banner above the Page, outside the frame. It counts what the Patch holds that readers do not see yet. It lists each Pane data item that differs from the Release, with Undo, and each other change, with Open. Undo puts the item back to its value in the Release. The banner offers the next step of the Publishing flow: Propose Changes while the Patch is Pending, then Publish or Keep Editing once it is Proposed. A change reaches readers only when a person Publishes the Patch. A Ponder turn that a Pane starts (ponder.ask) runs with the rights of the reader who clicked. The author’s cap does not apply to that turn, because the reader’s click is the reader’s own act.

Files in Pane code

Pane code reads the Parable’s files, and adds a file to it, with files from the Pane’s module. A Lab imports the same files from parable. The host answers for the Parable on screen, so Pane code never names a Parable. files.list and files.upload give each file as a PaneFile: This Pane lists the Parable’s data files with their table addresses, and adds a data file when the reader presses its button:
files.read refuses a file larger than 25 MB (25,000,000 bytes) with FILE_TOO_LARGE and “This file is larger than 25 MB. Read its rows through a Plot.” The host checks the bytes too, and stops reading at the limit. A Page has at most two files.read calls in flight. A third gets RATE_LIMITED until one of them is done. The rows of a data file belong in a Plot that reads its table (Plots). Use files.read for small files, such as a JSON settings file or a short CSV. files.read answers ARTIFACT_NOT_FOUND and “This file is not available.” for a file that the Parable or the Workspace does not hold. It answers the same for a deleted file and for a file whose check has not ended. The host fetches the bytes, so the frame never gets a storage address. The host opens the picker only just after a click or a key press in the frame, as it does pages.open. The file goes into the Parable’s files through the same upload and check as in the Artifacts tree. Only a person with Primary or Publishing adds a file, and only in the Publishing mode. The browser may not let the host open the picker from the press. Then the host shows a dialog, Add a file to this Parable, whose Choose a file button opens the picker. The call waits up to five minutes for the check, counted from the call, with the time in the picker. After that it fails with TIMEOUT, and the file shows in the Artifacts tree when its check ends. The host refuses an upload in these cases: The server checks the upload as it checks an upload from the Artifacts tree. Its refusal, such as for a name or a size, comes back as FILE_REFUSED with the server’s reason. ArtifactImage, ArtifactVideo and Palette fonts need no files call. The pictures Ponder takes of a Pane read no files. Every files call there gets SCOPE_REFUSED and “This surface reads no files.”

The Workspace’s files

The Workspace’s files reach Pane code under rules of their own. The reader needs only a seat on the Parable: Primary, Publishing, Pinging or Peeking. The reader needs no Workspace permission for files. Three rules apply:
  1. The Pane declares that its code reads the Workspace’s files. Its Perception holds readonly workspaceFiles: true;. A Pane’s code asks for its own Pane. A Page’s code asks for the Page, so the Page’s Perception holds the declaration.
  2. Only a person whose Workspace role lists the Workspace’s files saves a Perception that declares it: the role holds the permission to view Artifacts or to upload them. The rule applies to each save that changes a Perception and keeps the declaration in it: an edit in the Parable editor, an edit from Ponder, a change from Pane code, and an archive import. A save that keeps the stored Perception, or that removes the declaration, needs no such permission.
  3. Every person who last saved code that runs in the Page’s frame holds the Workspace’s permission to view Artifacts or to upload them. The code in the frame is the code of the Page and of each Pane that it renders. On a copy, code that was saved on the Parable the copy comes from never reads the copy Workspace’s files. When any code in the frame comes from there, the server refuses.
The server reads the declaration from the Pieces that the frame runs: the Deployment’s current Pieces, a Pending Patch, or an older Release. Pane code gets only the Workspace’s checked files that hold no Provider’s data. A file uploaded for a connection to a Provider, and a file that a tap reads, such as a published Artifact’s file, are left out. Their rows reach a reader only through SQL, under the reader’s Provider Policies. For each file, Pane code gets its id, name, kind, format and size. It does not get who uploaded the file.
Pane code gets the second and third refusals from files.list({ from: 'workspace' }) and from files.read of a Workspace file, with the code and the message. So Pane code reaches no further than the people who saved it. A copy that takes a Release by Pull or by Delivery gets the declaration with the Release. That is not a person’s save, so rule 2 does not apply to it. Rule 3 still applies on the copy. What the declaration does not limit. The server cannot tell which code asks for the files. Through a Pane that declares workspaceFiles, a reader can list and read every checked Workspace file that holds no Provider’s data, not only the files that the Pane shows. Declare it only on a Parable whose readers may see all of the Workspace’s checked files.

Pane-started runs

In a composed Parable, a Pane can start one Preview every 10 seconds and one Run every minute for each reader and Deployment. All Panes on that Deployment share these limits. A Preview does not use the Run allowance. Across several tabs, the limit counts in fixed 10-second and one-minute periods, so two tabs can start two runs a moment apart across a period boundary. When a Pane asks too often, it shows one of these refusals and starts no extra run:
  • Preview. This Pane asked to preview too often. Try again in 10 seconds.
  • Run. This Pane asked to run too often. Try again in a minute.
A Run still needs Publishing or Primary and a click or key press in the Page. Runs from the Page’s own controls keep their existing rules. Retrying the same request returns the same run without using another allowance.