diff --git a/docs/conventions/rendered-views/CHANGELOG.md b/docs/conventions/rendered-views/CHANGELOG.md index 8835349dc2..0b46a9bd16 100644 --- a/docs/conventions/rendered-views/CHANGELOG.md +++ b/docs/conventions/rendered-views/CHANGELOG.md @@ -3,6 +3,20 @@ Notable changes to the rendered-views contract. The contract is not versioned; this log records each change to it. +## The Claude-interactive tier opens to builder pages, 2026-10-03 + +- **`session-bridge` meets rule 9, and the triage board and plan view adopt the tier (#5868).** Every wait + answer now carries the untrusted-content framing contract as its data note. The bridge's new view app + hands the token only to same-origin page script, so it never enters the page's markup, ends itself and + its token 600 seconds after the session's watcher last waited, and takes page + actions holding only builder keys, row ids and the reader's notes. The builder's `--connect` adds one + `connect-src` naming the loopback origin, which the validator checks. The tier stays closed to + model-written pages. Rules 3 and 9 and View tiers record the change. +- **Rule 9's token wording states what the code does.** The token is minted per server run, and the + server exits `IDLE_SECONDS` after the session's last wait (and on stop). The view app also matches + its validators in full, so a trailing newline no longer passes, and refuses a data dir that is not + owned by the user or is open to group or other. + ## The digest publishes as an Artifact by default, 2026-10-03 - **`review:explain-change` ships `medium: artifact` (#5856).** With no layer setting diff --git a/docs/conventions/rendered-views/README.md b/docs/conventions/rendered-views/README.md index f42eca5dda..b82886b9e1 100644 --- a/docs/conventions/rendered-views/README.md +++ b/docs/conventions/rendered-views/README.md @@ -49,9 +49,12 @@ A view sits on one of four tiers, chosen per use case from the defaults below. - **Reports may be static.** A report is read, not answered, so it may ship without script. A report may still filter, collapse, or animate; what it never carries is a loop-closure control (see Loop closure and the export obligation). -- **The Claude-interactive tier is closed to every content class.** No page, K0, K1, or - K2, uses it until `session-bridge` exists and meets interactive-profile rule 9. Until - then a page stops at client-interactive and closes the loop with a copied payload. +- **The Claude-interactive tier is open only to builder pages.** `session-bridge` meets + interactive-profile rule 9, so a page of any class reaches it when the shared builder + built it with `--connect` and the bridge's view app serves it + (`lib/session-bridge/README.md`, "The view app"). A model-written K0 or K1 page does not + use it: it stops at client-interactive and closes the loop with a copied payload. A + builder page with no live session says so and keeps its copy and save controls. - **A K2 page's payloads carry no K2 text.** Every copy, export, or download payload on a K2 page, at any tier, holds to rule 9's first bullet: what the reader entered plus ids the builder assigned, never a string taken from the data block. A K2 page @@ -127,8 +130,8 @@ came from, not by who wrote it down. the charset meta is a ``, because a meta policy does not apply to content before it. The policy is exactly `default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; - form-action 'none'`, plus one permitted addition: `connect-src` naming the - `session-bridge` origin, once the Claude-interactive tier opens. The policy caps a misclassified page: + form-action 'none'`, with no `connect-src`: the Claude-interactive tier is open to + builder pages only (see View tiers). The policy caps a misclassified page: injected script runs but cannot fetch, beacon, or submit a form. It can still navigate the page to a URL that carries data out, and CSP3 has no directive that stops navigation, so the authoring-context rule, not the policy, is what keeps K2 @@ -177,9 +180,11 @@ from the one the browser runs. It checks the runtime body by hash before any oth `form-action 'none'`, which do not fall back to `default-src`. Its content is the builder's exact policy string. It is the only `http-equiv` meta the page carries: any other, such as `refresh`, which navigates and is not blocked by the policy, fails. - Once the Claude-interactive tier opens (rule 9), a page on it adds `connect-src` - naming the `session-bridge` origin and nothing else; `session-bridge` owns that - origin, and rule 9 governs what crosses it. + A Claude-interactive page (rule 9) adds one last directive, `connect-src` naming the + `session-bridge` origin `http://127.0.0.1:` and nothing else; the builder writes + it from `--connect`, the validator refuses any other `connect-src`, and the runtime + reaches only that origin. `session-bridge` owns that origin, and rule 9 governs what + crosses it. 4. **No inline handlers, no navigation.** No `on*` attribute, no `style` attribute, no `
`, `