Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Review: Shell & rendering (Prism / Xenon)

This review takes the layer as described and asks three questions: what verifiably holds, what is built or proven but not yet the design, and what still needs design. The lens throughout is the sovereignty litmus (inspect what it sees · fork permissions · BYO models + keys · movable memory · auditable actions · exit without loss). Verdicts cite code at agent54/prism main @98acaa3 and the Xenon packet record; gap IDs (G1–G6) are this beat’s register and feed Part IV.

The one line to carry out of this review: the highest-leverage undesigned sovereignty surface in the whole layer is G6 — the in-frame permission model. Whether a page’s request for the camera, microphone, or location is answered by the user’s own agent (shielded by default, journaled) or by Chrome’s native prompt decides whether the phrase “your agent answers for you” is real or marketing. It is not built for installed apps, and it is Luke’s call.

What verifiably holds

  • The trust boundary is one readable line. The baked CSP (packaging/bundle/headers.json) reduces the shell’s outbound trust to two origins — 127.0.0.1:5454 for the catalog and *.localhost:5454 for app panes — and nothing else. A reviewer can hold the entire network surface of the shell in their head. That is the sovereignty litmus’s inspect what it sees criterion, met by construction.
  • Guests are unprivileged by default, and the shell says how. Apps load into partitioned Controlled Frames (persist:prism-fleet-apps); the only way back to the shell is a MessageChannel gated by port identity, a 128-bit nonce, and an exact schema, carrying exactly four tab verbs (src/channel/message.ts:15, :41-63). Every accept and every reject is journaled. The boundary is small enough to audit.
  • Honesty is enforced, not hoped. A static lint forbids control ever riding over console output (scripts/check-channel-boundary.mjs); offline apps are shown greyed with a last-seen time rather than hidden (iwa-controlledframe-app.ts:161-193); the dev-signed trust tier is printed in the app’s own name. The journal is hash-linked and separately verifiable (journal:verify).
  • It runs on a real device. Prism installed and rendered a guest inside a genuine HTMLControlledFrameElement on an Android emulator (P-195, merged PR#17) — the Controlled-Frame story is proven, not aspirational.

Built or proven, but not yet the design

  • Two engines (P-192). The same signed bundle rendered on Blink and Servo. Real, and strategically large (see below) — but the Servo path is CF-shaped, not CF-strong, so it is inspiration for a standards story, not a shippable second engine yet.
  • Composition. A working, receipted carry between two apps exists — on <iframe>, not Controlled Frames (web/index.html:28-29). The mechanism is proven; its migration onto the Controlled-Frame + catalog path is not built (G3).
  • The launch seam. The catalog-descriptor launch path is already the code (iwa-controlledframe-app.ts:258), but blessing it as the canonical cross-platform seam is a proposal awaiting Luke (d/104). The code has run ahead of the ratified design; the review flags the gap rather than pretending it is closed.

Desired vs current vs gap — the map

AreaDesiredCurrentGap
App tier (d/101)Most apps plain http(s); IWA reserved for the shellExactly this — only Prism is bundled; every proven guest ran plain http— (holds)
Launch seam (d/104)One catalog descriptor is the launch path, all platformsCode already sets frame src = launch_url; Android can’t repoint installed guestRatify d/104 (G-seam)
In-frame permissionsShell brokers every permission, shield-by-default, journaledOnly geolocation, only in the dev driver, same-originG6 — undesigned
Composition (d/103)Any two fleet apps compose via CF + plane originsTwo fixture apps compose via iframesG3
Frame↔shell contractApp can title / notify / report liveness safelyFour tab verbs, one-way; no title/notifyG2
Production identityReal key ceremony, independent reviewDev-signed; name reads “(DEV-SIGNED)”G1
Local trustAuthenticated wake / bind of the planeCSP trusts whatever binds the portsG4
Fork burdenMinimal patches, upstream-aligned3-patch series, no rebase cadence setG5

Gap register (this beat — shell & rendering)

G6 — The in-frame permission model (the headline gap)

Exists: only geolocation, and only in the development driver, applied same-origin (src/spectrum/permission.ts, src/gateway/gateway.ts:128-143). The installed-driver mechanism is deliberately not built — when it cannot mint a lease or journal the answer, the gateway refuses rather than fake a result (permission.ts:4-13, gateway.ts:130-135). Answers can already be allow, deny, or shield (return a user-chosen value; the page never sees the real device).

Why design is needed: three questions are open and every one of them is a sovereignty question. Who prompts — the shell, or Chrome’s native dialog inside the partition? Who remembers — is there per-origin persistence the user can inspect and revoke? And the whole non-geolocation capability set (camera, microphone, clipboard, USB) is undesigned for the installed Controlled-Frame driver.

Options and trade-offs — presented for Luke to weigh:

Option A — shell brokers everythingOption B — delegate to Chrome
Who promptsThe user’s agent, via the agency ladderChrome’s native per-origin prompt
Default answerShield by default (user-chosen value)Whatever Chrome offers (allow / block)
RecordJournaled, inspectable, revocableChrome’s site settings
Litmus fitInspect what it sees + auditable both metCedes “your agent answers for you”
CostReal browser-driver engineering per capabilityNearly free — it already works

Who decides: Luke — this is litmus-touching. Option A is the entire differentiator of the product (“your agent answers for you”); Option B is free but concedes the sovereignty claim at exactly the surface where users feel it most. A design packet should precede any implementation.

G1 — Production signing / the key ceremony

Exists: development signing by key-path (d/066, orchestrator-held build-phase key); the installed name literally reads “(DEV-SIGNED)”. Why design is needed: the ceremony (offline root, Luke + Jan) is unbuilt; nothing yet rotates the dev key out or establishes a world-facing, independently reviewed identity. Options: (a) a single offline-root ceremony at world-release (current plan) — every install shows DEV until then; (b) an intermediate cross-signed release tier before public. Decides: Luke + Jan (key custody is a hard rule; d/066 is a bounded, build-phase-only override). Queued behind the publishing gate.

G2 — The frame↔shell communication contract

Exists: an asymmetric, minimal surface. App→shell is the four-verb nonce channel; shell→app is a capability-leased gateway reaching the pane, plus an opt-in cooperative bridge an app may expose (web/dev-origins/site.html). Why design is needed: there is no contract for an app to set a window title, raise a notification, request focus, or report liveness. A guest sets document.title, but the shell has no defined reaction. Options: (a) extend the nonce-authed verb set with a small app-declared surface (title / notify / badge); (b) keep apps fully unprivileged and derive what the shell needs by observation. Trade-off: (a) is ergonomic but every verb is a capability whoever holds the port then holds (the channel doc’s own caveat); (b) keeps the boundary tiny but apps cannot cooperate. Decides: Fable proposes the verb-set delta; Luke on anything touching user-visible identity (notifications).

G3 — Multi-app composition

Exists: the Composition surface frames two fixture apps and carries a leased “carry” record between them (read → consent card with a payload fingerprint → leased write → undo) — on iframes (web/index.html:28-29). Why design is needed: composition across arbitrary catalog apps in Controlled Frames (vs two hard-coded embeds) is aspired, not built; d/103 (compose UIs are plane origins) is the intended generalization. Options: (a) promote composition onto the CF + catalog path so any two fleet apps compose; (b) keep composition a curated shell feature over fixtures. Decides: Luke (product surface).

G4 — The local-trust boundary

Exists: the CSP pins trust to 127.0.0.1:5454 + *.localhost:5454. Why design is needed: the shell trusts whatever binds those ports. d/053’s own gate says “unauthenticated loopback TCP is disqualifying by our own standard” — yet the IWA→Boot-Service wake channel’s authentication is explicitly OPEN (d/053:44-49). Options: per-install token provisioned at install; IWA Direct Sockets with an authenticated handshake; or OS socket activation (launchd / systemd / Windows service triggers). Decides: Luke — security and litmus-touching; a design packet is required before implementation.

G5 — Chromium-fork maintenance burden

Exists: agent54/android-iwa is deliberately a patch series, not a full fork — three patches (0181 / 0182 / 0183) on a stock Chromium base plus gn args and validation scripts. Controlled Frame and IWAs are real upstream Chromium features (origin trial), so the divergence is small and upstream-aligned. Why design is needed: no rebase cadence, patch-count budget, or upstreaming path is recorded. Options: (a) ride the desktop-android variant + origin-trial features and drive patches toward zero as upstream lands (lowest burden, dependent on upstream timing); (b) maintain a standing carry-patch set (control at the cost of rebase toil). Decides: Jan + Luke (fork strategy). Note d/098 — no agent-opened upstream PRs, ever; upstreaming is a human-published contribution.

P-192 — Two engines, and the standards story

The single result most worth understanding strategically is that the same signed bundle rendered on two independent engines: Blink via a real IWA install, and Servo via a Rust isolated-app:// scheme handler that verifies the bundle’s Ed25519 signature offline before serving a byte (a tampered bundle is refused, test-pinned). This converts “a Chromium-fork feature” into “a web-platform shape with more than one implementation” — which is precisely the argument a standards body wants to hear, and precisely the position that keeps the Xe Computer from being a single-vendor dependency.

The honesty caveat is load-bearing: the Servo side is CF-shaped, not CF-strong. It reproduces the API surface and the origin-verification discipline, but not the isolation fundamentals — no OS sandbox, no cross-origin-isolation implementation, permissions-policy commented out (P-190/P-191, PARKED). So P-192 is a credible standards and independence story and a reminder that a second production engine is real work, not a flag flip. The verdict on Servo as a base was INSPIRATION / NOT-VIABLE-YET, revisited the week of Jul 20.

Sovereignty litmus check

CriterionVerdict for this layer
Inspect what it seesHolds by construction. The whole outbound trust surface is two CSP origins; the shell can executeScript-observe guests, and every observation is leasable and journaled.
Fork permissionsPartial — and this is G6. Permission shielding exists in the dev driver (geolocation), but the installed-app broker is unbuilt; the choice between shell-brokered and Chrome-native prompts is undesigned and decides whether this criterion is truly met.
BYO models + keysHolds for shape, pending ceremony (G1). Signing keys are local and never escrowed; the dev key is honestly labelled; the production ceremony is ahead.
Movable memoryStructurally present. Guest state lives in a named partition; app data single-homing is a site-wide finding (Part IV), not this layer’s to close.
Auditable actionsHolds. Hash-linked journal, separately verifiable; channel rejections recorded with cause; leased reads receipted.
Exit without lossHolds as intent, written into the product. “Swap this shell and keep your apps, your data, and your journal” (spectrum.ts:163-165) — Prism is interchangeable by design; the guarantee firms up once composition and the launch seam are the ratified path (G3, d/104).

Questions for the Luke + Jan session

  1. In-frame permission model (G6, the headline). Does the shell broker all app permissions via the agency ladder — shield-by-default, journaled — or delegate to Chrome’s native per-origin prompts inside the partition? This is the highest-leverage undesigned sovereignty surface in the layer.
  2. Ratify d/104? Bless the catalog descriptor (label → http://<app>.localhost:5454) as the single Controlled-Frame launch seam on every platform, or hold out for an explicit install-time guest-manifest launch contract? (Unblocks the Android frame-cell.)
  3. Wake-channel authentication (d/053 OPEN, G4). Per-install token, IWA Direct Sockets handshake, or OS socket activation for IWA→Boot-Service? This is the load-bearing piece of the local-trust boundary.
  4. Fork strategy (G5). Commit to minimizing android-iwa toward zero patches as upstream Controlled Frame / IWA lands (accepting an upstream-timing dependency), or maintain a standing carry-patch set? Rebase cadence and patch-count budget are unset.
  5. Composition scope (G3). Promote composition onto the Controlled-Frame + catalog path (any two fleet apps compose), or keep it a curated shell feature over the two fixtures?
  6. Production signing timing (G1). Confirm the key ceremony triggers at world-release and that nothing ships publicly under DEV-SIGNED.