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

Sol design review — Shell & rendering (Prism / Xenon)

Part of the site’s external review; reproduced verbatim below the header. sol’s positions are folded into the design frontier as External review input lines.

  • Date: 2026-07-18
  • Reviewer: gpt-5.6-sol (via codex exec, model_reasoning_effort=xhigh), run on lane-182
  • Scope: src/part2/shell-rendering.md (architecture), src/part3/shell-rendering.md (design review + gap register G1–G6), and the shell-rendering marker block of src/part5/emerging-specs.md (Prism↔app contract v1, super-app packaging profile v1)

Orchestrator summary (5 lines):

  1. Sol judges the layer’s honesty real but several headline claims overreach: the CSP is not the whole outbound trust surface (guests still make their own network requests), a Controlled Frame protects the shell from the guest but not the guest from the shell (the host can observe cookies, passwords, uploads), and the hash-linked journal is truncatable without signed/anchored checkpoints — so “exit without loss” is today an intention, not a guarantee.
  2. On G6 (headline gap) sol lands on a hybrid: Prism owns policy, shielding, persistence, and journaling; Chrome/OS keeps final device selection and enforcement; the effective outcome is the intersection, never the union. Shield-by-default is infeasible via injected JS because the Controlled Frame permissionrequest API can only allow/cancel — real shielding needs a Xenon browser-process permission delegate or a resource portal.
  3. On the launch seam (d/104) sol says keep the descriptor as the canonical seam but do not ratify the current label → launch_url shape (it conflates presentation, identity, and routing); bind launch to a key-derived app_id + release_digest + mutability_tier resolved by an authenticated plane router, enforced by a Xenon browser-process navigation guard (NavigationThrottle) bound to a verified LaunchGrant. d/104 also embeds an unresolved HTTP-vs-HTTPS Controlled Frame portability decision.
  4. The agency ladder should become typed attenuated leases (one guarded dispatcher, complete mediation, fail-closed receipts) and is better modeled as a capability lattice than an ordinal ladder; the four-verb contract should split into a cooperative lifecycle RPC and a separately-audited automation gateway (drop raw tab.open{url} and key).
  5. Top-5 ranked: (i) hybrid permission-broker MVP, (ii) signed LaunchDescriptor+LaunchGrant, (iii) typed-lease agency ladder, (iv) contract v1.1 as lifecycle RPC, (v) one PaneHost abstraction gating composition migration on parity. Twelve added agenda questions — foremost the identity/update model for ordinary HTTP apps and how guest identity is shown (anti-impersonation) without an address bar.

The documents are unusually candid about implementation gaps, but several conclusions are stronger than the evidence supports:

  • The CSP is a useful shell boundary, not “the whole outbound trust surface.” It limits Prism’s own fetches and framed top-level origins; guest applications can still make their own network requests.
  • A Controlled Frame protects the shell from a guest process, but does not protect the guest from the shell. Prism can inject code, intercept requests, observe input, and potentially access session data. The Controlled Frame specification explicitly recognizes those risks.
  • A hash-linked journal is tamper-evident only relative to a trusted head. Without signed or externally anchored checkpoints, the whole chain can be truncated or replaced.
  • “Exit without loss” is currently a product intention. The launch, storage, composition, and journal-export contracts needed to make it a guarantee remain incomplete.

(1) G6 — the in-frame permission model

Prism should own policy, explanation, shielding, persistence, and journaling. Xenon/Chromium and the operating system should remain the final enforcement and device-selection layer.

That distinction matters. The current Controlled Frame permissionrequest shape exposes only coarse permission types—media, geolocation, pointerLock, download, filesystem, fullscreen, and hid—and its controller can only allow or cancel. It cannot itself return an approximate location, a restricted clipboard, or a virtual camera. Those require a Xenon browser-process permission delegate or a true resource portal, not an injected JavaScript patch. The current Controlled Frame draft confirms this limitation.

The broker should therefore produce one of four internal outcomes:

DENY
ALLOW_REAL
ALLOW_PORTAL(resource_handle)
ALLOW_VIRTUAL(shield_profile)

Unsupported ALLOW_PORTAL or ALLOW_VIRTUAL results must fail closed to DENY.

Permission taxonomy

Risk groupCapabilitiesDefaultEnforcement
Interaction and attentionFullscreen, pointer lock, focus, popups, external navigation, clipboard write, downloads, wake lockAllow once only with a fresh user gesture and visible pane; otherwise denyShell gesture check plus browser guard
Shieldable personal valuesLocation, clipboard read, contacts, simple sensorsShield once by default; prompt for real dataShell value provider or scoped portal
User-selected resourcesFile open/save, directory access, photo selection, display/window captureAlways invoke a shell/native chooser; never grant an ambient directory or screen capabilityOpaque resource handles
Live captureCamera and microphoneVirtual feed if configured; otherwise deny by default; real access requires explicit promptBrowser/OS device controls and visible indicators
Background or durable attentionNotifications, background sync, periodic work, persistent storageDeny until enabled through an in-context prompt or app settingsShell notification/lifecycle service
Physical or system authorityUSB, HID, serial, Bluetooth, MIDI SysEx, local-network discovery, protocol handlersDeny by default; explicit device- and session-scoped native chooserBrowser/OS; no shell-synthesized substitute
Credential and payment authorityPasskeys, payment credentials, secure authenticationDelegate entirely to browser/OS after shell eligibility checkNative trusted UI

“Shield by default” should not be treated as universally meaningful:

  • Location can be fixed, rounded, delayed, or bounded to a region.
  • Clipboard read can expose only an explicitly selected clipboard capsule.
  • File access can expose only user-selected resources through opaque handles.
  • Camera and microphone can use an unmistakably labelled virtual feed or silence.
  • USB, HID, passkeys, and payment credentials cannot usefully be “shielded.” Their safe default is denial.

Prompt UX

The shell should prompt only when all of the following are true:

  1. The request comes from the current, verified frame and document epoch.
  2. The top-level pane is visible and foregrounded.
  3. The descriptor declares the capability as optional or required.
  4. Any required user activation is fresh and browser-attested.
  5. There is no applicable stored rule or active task lease.
  6. The request has not been suppressed by rate limiting.

Requests from hidden panes, cross-origin subframes not declared by the app, stale documents, or prompt loops should be auto-denied and journaled without interrupting the user.

The prompt should appear in non-guest-controlled shell chrome and show:

  • Verified app name and immutable app ID.
  • Current top-level origin.
  • The actual requesting origin if it is a subframe.
  • The capability and requested scope: exact/coarse location, camera versus microphone, file versus directory, named hardware device.
  • Whether the request followed a user action.
  • An app-supplied explanation clearly marked as untrusted app text.
  • The agent policy or prior rule that would otherwise answer.
  • Duration choices.

The choices should be capability-specific. A useful baseline is:

Use shield once          — default where shielding exists
Use real data once
Allow while this app is open
Always allow             — omitted for raw capture and hardware initially
Deny once
Always deny

Camera, microphone, screen capture, and hardware access require a second native device/resource chooser where applicable. Avoid two semantically identical prompts: Prism decides whether the request is eligible; the native UI selects or confirms the actual device.

Continuous access needs persistent shell indicators. Clicking the camera, microphone, location, or screen indicator must revoke the active stream immediately.

Auto-answer policy

Prism may auto-answer when:

  • A matching user-authored rule exists.
  • A still-valid, attenuated task lease covers this capability and scope.
  • A low-risk request is backed by a fresh gesture, such as same-pane fullscreen.
  • A global browser or OS prohibition makes denial inevitable.
  • Shielding is the stored default for that app and capability.

An agent should not independently grant real camera, microphone, display, directory, or physical-device access merely because the pane has reached a higher agency rung. Those need explicit prior user policy or contemporaneous user confirmation.

Persistence, inspection, and revocation

“Per-origin” memory is necessary but insufficient. Rules should be keyed by:

user_profile
shell_identity
immutable_app_id
top_level_origin
requesting_origin
capability
scope

They should also record the descriptor/publisher identity under which they were created. A mutable label or .localhost hostname is not enough.

Durations should include:

  • One operation.
  • Until navigation.
  • Until pane close.
  • Until Prism exit.
  • Time bounded.
  • Persistent.

For unsigned or mutable HTTP application code, persistent real-device grants should initially be disallowed or downgraded to session-only. A stable publisher/app key can allow permissions to survive routine content updates, but a publisher-key change, app-ID change, or capability-manifest expansion must invalidate or re-prompt.

Prism needs an inspectable permission center organized by app and origin, showing:

  • Current grants, denials, shields, and expirations.
  • Last requested and last used times.
  • Active streams or handles.
  • The policy or user action responsible.
  • The requesting suborigin.
  • A one-click revoke control and global emergency stop.

Revocation must remove the Prism rule, invalidate matching leases and resource handles, terminate live streams, and clear any corresponding Chromium content setting. Chrome should receive only ephemeral or tightly scoped grants where possible so Prism is not maintaining a contradictory second permission database.

Chrome already provides one-time, visit-scoped, persistent, revocable site permissions and automatically removes permissions for inactive sites. Chrome’s site-permission controls are the minimum parity target.

Journal binding

Every answer should create a permission.answer record containing:

request_id
wall_time and monotonic sequence
frame_id and document_epoch
launch_instance_id
immutable_app_id
descriptor_digest and release_digest
top_level_origin and requesting_origin
capability and normalized scope
visibility and user_activation state
requested outcome
effective outcome
decision source: user | stored-rule | task-lease | system | agent
policy_rule_id or lease_id
shield_profile_id and profile digest
duration, expiry, and use limit
prompt UI version
browser/OS result and denial reason
previous permission decision reference

Do not journal raw locations, clipboard contents, filenames, captured media, device serial numbers, or notification bodies. Record opaque handles, sizes, types, and keyed fingerprints where correlation is needed.

Long-running access also needs permission.use.start, permission.use.stop, and permission.revoke records. The journal should append an intent before enabling the capability and a completion or failure afterward. If the journal cannot append, high-risk operations should fail closed.

Finally, periodically sign and anchor the journal head using the device key or a user-selected external store. A local hash chain alone does not prove that an earlier suffix was not discarded.

Honest comparison with Chrome-native prompts

Prism is genuinely better where it can provide:

  • Shielded values rather than binary allow/block.
  • App identity that is more meaningful than foo.localhost.
  • Purpose- and task-scoped agent leases.
  • One policy view across browser, files, composition, and cross-app actions.
  • Receipts tied to the action that caused the request.
  • Origin-aware mediation for embedded subframes.
  • Cross-app resource handles instead of broad ambient access.

Prism is mostly reimplementing Chrome where it provides:

  • Allow once, while visiting, always allow, and block.
  • Site settings and revocation.
  • User-gesture checks.
  • Prompt-abuse suppression and quiet UI.
  • Accessible and localized device dialogs.
  • Camera/microphone indicators.
  • OS privacy integration and device enumeration.
  • Browser-level handling of navigation races and compromised renderers.

Chrome has years of hardening around these cases. Replacing its trusted UI wholesale would enlarge Xenon’s patch burden and likely produce a less accessible and less consistent experience.

The right hybrid is:

  • Prism brokers: location shielding, clipboard capsules, file portals, notification identity and rate limits, focus, downloads, external intents, agent/task leases, cross-app transfers, persistence policy, and journal records.
  • Chrome/OS delegates: raw camera/microphone access, display capture, USB/HID/serial/Bluetooth, passkeys, payments, credential selection, and physical device controls.
  • Both participate: Prism performs eligibility and policy; Chrome/OS performs final resource selection and enforcement. The effective outcome is the intersection, never the union, of their decisions.

(2) The launch seam — d/104

The descriptor should remain the canonical launch seam, but the present descriptor shape should not be ratified.

label -> launch_url confuses presentation, identity, and routing:

  • A label is mutable and non-unique.
  • A URL is a locator, not an app identity.
  • The catalog comes from an unauthenticated loopback endpoint.
  • The wildcard CSP admits every matching .localhost origin.
  • Assigning activeFrame.src constrains only the initial navigation.
  • Redirects, links, window.open, script navigation, and later channel verbs can leave the intended origin.
  • Reusing a hostname for different code can inherit that origin’s stored data and permissions.

The safer identity is a stable key-derived app_id, with a release digest identifying the exact version. The URL should be resolved from that identity by an authenticated plane router.

A launch descriptor should contain at least:

schema_version
app_id                    # hash/public-key-derived stable identity
publisher_id
display_name and icons    # presentation only
release_version
release_digest            # exact immutable release/snapshot
mutability_tier           # sealed | signed-update | mutable
canonical_origin
start_path
allowed_top_level_origins
allowed_path_prefixes
allowed_redirect_origins
allowed_subframe_origins
external_navigation_policy
partition_id
declared_capabilities
contract_versions
device_id and service_instance_id
issued_at, expires_at, sequence
descriptor_signature
revocation/reference status

For an inherently dynamic server that cannot supply a meaningful content digest, the descriptor must say mutable. Such an app should not inherit durable high-risk grants as though its code were sealed.

The catalog label can change freely. The app_id, publisher key, partition assignment, and permission identity cannot.

The default policy should be:

  • Initial navigation must equal the resolved canonical origin plus an allowed start path.
  • Same-origin top-level navigation is permitted within allowed path prefixes.
  • Cross-origin top-level redirects are blocked unless explicitly listed.
  • Cross-origin links open outside the privileged pane through an external.open policy path and require a user gesture.
  • javascript:, file:, data:, arbitrary isolated-app:, and unknown schemes are rejected.
  • blob: top-level navigation is allowed only if its creator origin matches the current allowed origin and the browser can verify that binding.
  • window.open is denied by default. Approved new windows receive a fresh frame, partition decision, launch grant, channel, and leases.
  • The app channel is closed and re-keyed on every committed top-level document.
  • All leases bind to a document epoch and become invalid on navigation.
  • Permission requests from subframes are attributed to both the app and actual subframe origin.

This policy concerns top-level pane navigation. Guest subresource requests need a separate network policy; silently restricting all APIs and CDNs to the top-level origin would break ordinary web apps.

Enforcement point

The durable enforcement point should be a Xenon browser-process navigation guard—conceptually a NavigationThrottle—bound to a verified LaunchGrant for that Controlled Frame. Shell JavaScript is not a sufficient sole guard because it may observe a redirect or commit too late.

An interim implementation can use blocking Controlled Frame request interception plus loadredirect, newwindow, and loadcommit checks, but any unexpected commit must destroy and recreate the frame, not navigate it “back.”

There is also an unresolved standards mismatch: the current Controlled Frame draft states that Controlled Frames work with https: content, while Prism’s architecture uses http://*.localhost:5454. The local exception may work in the current Xenon patch set, but it is not the documented portable contract. Ratifying d/104 must explicitly resolve whether this is:

  • An upstream-supported trustworthy-localhost exception.
  • A permanent Xenon divergence.
  • Or a migration to authenticated HTTPS plane origins.

Until then, d/104 is not merely a product decision; it embeds a browser-portability decision.

(3) Prism↔app contract v1 — verbs and gateway

The asymmetry is correct, but the current division is not.

There should be two specifications:

  1. A cooperative app protocol for lifecycle, presentation, and intents.
  2. A privileged automation gateway for observing and changing uncooperative content.

readDom, request rewriting, mutation, and CDP control are not a normal app contract. They are shell authority over a guest and should be specified and audited separately.

The four current verbs are also narrow in the wrong direction. They omit basic lifecycle cooperation while exposing raw navigation and a generic key actuator. tab.open{url} directly conflicts with a descriptor-constrained launch model. key{key} is too generic to justify as an app-to-shell primitive and should be removed.

The nonce should not be described as app authentication. The port is already a bearer capability; sending a nonce over the same port adds message validation but not an independent identity factor. Any holder has both. Close and recreate the port on navigation, bind it to frame_id + document_epoch + app_id, and describe it as a nonce-gated bearer channel.

A real protocol also needs version negotiation, request IDs, responses, typed errors, cancellation, quotas, sequence/replay handling, and channel-close semantics.

Proposed additions

AdditionPathCapability cost and constraints
Window title, subtitle, badgeNonce channel: ui.setMetadataLow. Sanitize length and characters, rate-limit, and always render the immutable shell-owned app identity beside it. App text must not replace identity.
Notification requestNonce channel: notification.request; notification action returns through a single-use gateway deliveryMedium/high attention capability. Requires a separate notification permission, quotas, origin-labelled chrome, no arbitrary HTML, and body redaction in the journal. Possessing the port grants the ability to request, not to display.
Focus/attentionNonce channel: ui.requestAttention or ui.requestFocusMedium. Require browser-attested user activation or explicit shell policy. Never allow hidden scripts to steal focus.
LivenessControlled Frame load/crash events for process liveness; nonce channel app.ready/app.health for cooperative readinessLow, but untrusted. A heartbeat proves only that the app script is responding. Rate-limit it and do not use it as a security assertion.
ResizeNonce channel for advisory ui.requestSize; normal viewport/resize events from shell to appLow/medium. Shell retains layout control, clamps dimensions, and prevents resize loops. No privileged gateway is needed merely to tell a page its viewport changed.
ClipboardUse the permission broker and native Clipboard API for normal apps; use a leased gateway only for an agent placing a specific clipboard capsule into a specific fieldHigh for reads, medium for writes. A general clipboard.read verb would let any port holder exfiltrate ambient clipboard data.
File open/saveBrowser/shell resource portal, not a generic channel verb; inbound selected-file delivery through a leased gateway using an opaque handleHigh. Never deliver arbitrary host paths. Scope handle by app, mode, resource, TTL, and document epoch.
Inbound file handlingLeased gateway: intent.deliverFileHigh. Single app, typed content, selected file, explicit read/write mode. Revocation must invalidate the handle.
Deep link or cross-app intentOutbound request on nonce channel: intent.open; inbound delivery on leased gateway: intent.deliverHigh cross-app authority. Target by immutable app ID and declared intent type, not URL. Require consent for sensitive payloads and pass opaque references where possible.
Notification click/actionLeased gateway bound to notification ID and action IDMedium. Single use, short TTL, and no ambient ability to focus or drive the app.

The key contract rule should become: the channel conveys requests; operation-specific policy grants authority. Merely adding a verb must not implicitly grant the capability to every script holding the port.

Gateway leases also need stronger attenuation. A five-minute single-use lease should additionally bind:

actor
app_id
frame_id
document_epoch
operation
argument constraints
selector or resource
purpose
issued_at and expiry
use count
undo strategy

Read, mutation, input, network interception, composition, and CDP leases should be distinct types. A generic Stage-0 lease does not enforce the agency ladder.

(4) The agency ladder — vocabulary to enforcement

The ladder should not be an ordinal authorization check. “Composed” is not necessarily more powerful than “driven,” and a one-record cross-app transfer can be less invasive than full DOM observation. Represent the ladder as named capability sets; derive the user-facing rung from active capabilities.

RungMinimal enforcement point
NothingFrame session starts with no injected bridge, automation attachment, or active lease. The gateway dispatcher default-denies every operation lacking an explicit typed lease.
Allowed / denied / shieldedBrowser-process permission delegate accepts only a valid PermissionLease or stored rule and appends the answer before applying it.
ObservedReadLease guard immediately before executeScript, DOM extraction, field reads, or request observation. DOM contents and network bodies should be separate scopes.
EnhancedEnhancementLease guard before insertCSS or isolated-world annotation injection, restricted to shell-bundled assets and bounded selectors.
MutatedRequestRewriteLease at the blocking network interceptor, constrained by URL patterns, methods, headers, and permitted transformations.
ControlledInteractionLease at the input/navigation dispatcher, bound to a frame, document epoch, action types, selectors, and navigation policy.
DrivenDevToolsLease at CDP attachment and again at every CDP command dispatch, with a command allowlist, short TTL, visible indicator, and emergency revocation.
Composed / generated / delegatedTransferLease at the composition broker, binding source read, destination write, schema, payload fingerprint, consent record, use count, and undo operation.
Super-user-agentA non-exportable ShellRoot authority minted only after Xenon verifies the installed Prism IWA identity and manifest policies. Every permission, gateway, CDP, and composition service requires this root to mint narrower leases. Guests never receive it.

The smallest adequate enforcement kernel is:

  1. Static ceiling: signed IWA identity, CSP, Permissions Policy, and Controlled Frame availability.
  2. Verified frame context: immutable app identity, descriptor digest, partition, navigation policy, and document epoch.
  3. Typed attenuated leases: resource, verb, actor, argument constraints, TTL, use count, and delegation chain.
  4. Complete mediation: one guarded dispatcher for every privileged Controlled Frame, permission, request, input, CDP, and composition operation.
  5. Fail-closed receipts: append intent before effect; append result and undo reference afterward.

A journal record alone is not an enforcement boundary. It becomes one only if the operation cannot proceed when authorization or append fails.

(5) Iframes versus Controlled Frames in composition

Migration should not be treated as an automatic upgrade. Controlled Frames give Prism more power over guests; they are not simply “better-isolated iframes.” The current specification recommends ordinary iframes where they suffice and explicitly notes that an IWA host may observe activity, session cookies, passwords, uploads, and network behavior in a Controlled Frame. Controlled Frame security and privacy considerations.

Migration criteria

Composition should move to Controlled Frames only when all of these are true:

  • d/103 plane origins have stable app IDs and authenticated routing.
  • The replacement for launch_url and its navigation guard is implemented.
  • The HTTP-versus-HTTPS Controlled Frame discrepancy is resolved on every supported platform.
  • G6 handles permission requests in multiple simultaneous panes.
  • Each pane receives a deliberate partition assignment; per-app, per-instance, and shared-session behavior is specified.
  • The cooperative channel is bound and re-keyed by document epoch.
  • Cross-app payloads use typed TransferLease records with consent, fingerprints, and real undo behavior.
  • Focus, keyboard, IME, screen-reader, resize, drag/drop, file picker, clipboard, and popup behavior have parity tests.
  • Crash, freeze, visibility, and memory-pressure behavior is defined for multiple Controlled Frame processes, particularly on Android.
  • Apps that rely on window.parent, ordinary iframe postMessage, embedding headers, or shared browsing-context assumptions have migration adapters.
  • The shell visibly identifies the origin and agency state of each pane.

What breaks if migration is premature

  • Local HTTP origins may simply fail in an upstream-conforming Controlled Frame.
  • Existing iframe postMessage and parent/child assumptions may stop working.
  • Authentication and service-worker state may move into a different partition.
  • Two instances of the same app may unexpectedly share or fail to share state.
  • Permission requests can be attributed or persisted incorrectly.
  • Popups and cross-origin redirects can escape the composition policy.
  • Mobile memory use increases because each guest is a top-level-like isolated context.
  • Accessibility, focus, IME, and resize behavior may regress.
  • Moving to Controlled Frames silently grants Prism observation and mutation powers that the iframe composition demonstration did not require.

Should the surfaces unify?

Unify the identity, descriptor, PaneHost abstraction, lifecycle, permission broker, journal, and composition lease model. Do not require one embedding primitive.

Use:

  • <iframe> for cooperative plane apps where normal web isolation and embedding consent are sufficient.
  • <controlledframe> when Prism needs to host content that refuses iframe embedding, enforce navigation, provide automation, or intercept requests.

If the product promise remains “any two catalog apps,” Controlled Frames will be necessary for some composition cases. They should be selected by declared capability need, not used as a visual-compliance milestone.

(6) Prior art

Browser extensions

MV3’s split between required permissions, optional runtime permissions, host permissions, and gesture-derived activeTab authority transfers directly. Prism should have:

  • Descriptor-declared possible capabilities.
  • Optional runtime grants.
  • Exact host/origin scopes.
  • An activePane-style, short-lived gesture capability for observation or interaction.

Chrome explicitly recommends optional permissions so users grant functionality in context, and activeTab provides temporary host authority following a user action. Chrome extension permission model.

What does not transfer is the extension principal model. Extensions are installed, signed code with a stable extension identity and browser-defined APIs. Most Prism guests are mutable HTTP applications, and a MessagePort holder is not equivalent to an extension service worker.

Wayland and xdg-desktop-portal

Portals are the strongest direct model for files, screen capture, devices, and notifications:

  • The sandbox asks an external trusted service.
  • Trusted UI identifies the requesting app.
  • The user selects a specific resource.
  • The app receives an opaque handle rather than ambient host access.
  • A permission store supports inspection and revocation.

The XDG permission store is explicitly keyed by application and resource, and document portals expose only granted resources to sandboxed applications. XDG Permission Store, Document Portal.

What does not transfer is principal authentication. Flatpak portals receive a sandbox-established application ID. Prism must first establish that an HTTP origin really corresponds to the catalog app ID. Portals also do not provide DOM/CDP automation or shielded synthetic values.

Mobile entitlements and runtime permissions

Transfer:

  • Static manifest declarations as a maximum capability ceiling.
  • In-context runtime requests.
  • One-time and while-in-use grants.
  • Automatic expiry or reset.
  • Persistent privacy indicators.
  • Graceful behavior after denial.
  • Resource pickers and scoped storage instead of broad filesystem permission.

Android’s guidance explicitly recommends asking only when the user invokes the relevant task and degrading gracefully after denial. Its Storage Access Framework grants access to user-selected files through scoped URIs rather than broad storage authority. Android runtime permissions, Storage Access Framework. Apple’s App Sandbox similarly treats entitlements as narrowly restoring specific capabilities to an otherwise contained application. Apple App Sandbox.

What does not transfer is OS-level attribution. Android and iOS usually see Xenon or Prism as the app principal, not each HTTP guest. Prism therefore needs its own subordinate authority model. Mobile systems also rarely offer synthetic shielding beyond coarse location or selected resources.

IWA, Controlled Frame, and Web Bundles

Transfer:

  • Key-derived identity for Prism itself.
  • Signed, offline-verifiable shell code.
  • Default-none IWA Permissions Policy.
  • Separate Controlled Frame storage partitions.
  • Browser-provided permission, navigation, popup, lifecycle, scripting, and request hooks.
  • Conformance tests tied to the draft APIs rather than private abstractions.

IWA identity is tied to the bundle signing key, while permissions remain dynamic and independently auditable. IWA architecture.

What does not transfer is identity for ordinary guests. Prism’s signed bundle authenticates Prism, not app.localhost. Controlled Frames are also an incubating API, not a W3C standard, and their current draft states HTTPS-only navigation. They deliberately allow the host to bypass ordinary embedding restrictions and control the guest; that is an authority requiring governance, not a free security improvement.

Capability systems: OCap, UCAN, and macaroons

Transfer:

  • Possession conveys authority.
  • Capabilities should name a resource and operation.
  • Delegation must only attenuate authority.
  • Tokens should bind audience, scope, time, use count, argument constraints, and purpose.
  • Invocation and receipt are separate from delegation.
  • Short-lived, single-use capabilities reduce leakage impact.

UCAN specifies verifiable attenuated delegation and separates delegation from invocation; macaroons add contextual caveats constraining when, where, and for what a bearer credential works. UCAN delegation, Macaroons paper.

What does not transfer is an automatic solution to port leakage. UCANs and macaroons are still credentials; a script that steals a usable bearer token can exercise it. In Prism’s single-device broker, cryptographic tokens may also be unnecessary internally—a non-forgeable in-memory lease handle with the same attenuation can be simpler. Use cryptography when leases cross processes, devices, or journal/export boundaries.

Electron and embedded-browser shells

Electron’s hard-earned checklist transfers almost verbatim: explicitly handle permissions, limit navigation and window creation, validate IPC senders, keep remote content sandboxed, and never pass untrusted URLs directly to external-open APIs. Electron security guidance.

What does not transfer is Electron’s Node/native integration model. Prism should not expose a general native bridge or reproduce Electron’s broad renderer-to-host API surface.

(7) Top-5 concrete improvement proposals, ranked

  1. Ship a hybrid permission broker MVP. Add a browser-process permission delegate, typed PermissionRequest model, per-app/origin rule store, shell prompt, live indicators, revocation, and fail-closed journal records; initially support location, media, files, clipboard, notifications, and downloads. Closes G6. Cost: Large—roughly 2–3 engineer-months for a credible MVP, excluding virtual camera/microphone work.

  2. Replace launch_url with signed LaunchDescriptor + LaunchGrant. Introduce key-derived app IDs, release digests, authenticated plane resolution, per-app partitions, exact navigation rules, channel re-keying, and a browser-process navigation guard. Closes d/104’s unsafe shape, navigation escape, and part of G4. Cost: Large—approximately 1–2 engineer-months plus a Xenon integration patch.

  3. Implement the agency ladder as typed leases. Split read, enhancement, rewrite, interaction, CDP, permission, and transfer authority; bind each lease to app, frame, document epoch, constraints, TTL, uses, purpose, and receipt. Closes the vocabulary-to-enforcement gap. Cost: Medium/large—approximately 4–8 engineer-weeks and gateway refactoring.

  4. Publish contract v1.1 as lifecycle RPC, not automation RPC. Remove raw tab.open{url} and key; add versioning, request/response IDs, title, readiness, attention, notification requests, constrained intents, quotas, navigation epochs, and typed errors. Keep the automation gateway as a separate specification. Closes G2 and the port-capability ambiguity. Cost: Medium—approximately 3–5 engineer-weeks plus app-adapter updates.

  5. Create one PaneHost abstraction and gate composition migration on parity. Support iframe and Controlled Frame adapters behind the same identity, permission, lifecycle, and journal interfaces; prove one arbitrary catalog-app transfer with focus, accessibility, storage, crash, and undo tests before general migration. Closes G3 without making Controlled Frames mandatory where they add unnecessary host authority. Cost: Large—approximately 6–10 engineer-weeks after proposals 1–4.

(8) Missing session-agenda questions

The Luke + Jan agenda should also ask:

  1. What is the identity and update model for ordinary HTTP apps? Who signs an app descriptor, how is an app_id created, and what happens to data and permissions when publisher key, release digest, or routing changes?

  2. What exact navigation policy applies after launch? Are redirects, OAuth origins, external links, popups, downloads, and deep links allowed, and where is the policy enforced?

  3. How is guest identity shown without an address bar? What shell-owned chrome prevents an app from impersonating Prism or another app, especially in prompts and notifications?

  4. Is the upstream HTTPS-only Controlled Frame constraint acceptable? Is local HTTP a temporary Xenon patch, a standards proposal, or an architectural dependency that must be removed?

  5. What is the partition unit? Per shell, app, app instance, user, composition session, or device? How are state clearing, export, revocation, service workers, and concurrent instances handled?

  6. Who may mint agency leases? Which operations require current user presence, which can a resident agent exercise unattended, and what is the global emergency-stop path?

  7. Is the agency model intentionally a ladder or actually a capability lattice? How should simultaneous capabilities be displayed, and can composed authority exist without observation or driving?

  8. What is the channel’s actual threat model? Is XSS inside a guest considered equivalent to app compromise? Does the port authenticate an app, an origin, a document, or only possession?

  9. What is the journal adversary model? How are chain heads anchored, rollback and truncation detected, sensitive metadata protected, retention limited, and exports authenticated?

  10. What constitutes a valid undo? For network requests, notifications, file writes, messages, purchases, and cross-app carries, which actions are reversible and which must be labelled irreversible before consent?

  11. What is the fallback on browsers without production-strength Controlled Frames? Does Prism refuse to run, degrade to cooperative iframes, or expose a visibly lower assurance tier?

  12. What is the conformance and patch-budget gate? Which permission, navigation, isolation, accessibility, and multi-pane tests must pass before a Xenon rebase or Controlled Frame API update ships?

SOLREV-SHELL-DONE