[DO NOT MERGE] execution runtime architecture - sandboxing prototype - #5740
[DO NOT MERGE] execution runtime architecture - sandboxing prototype#5740habdelra wants to merge 93 commits into
Conversation
Two planning documents for completing Capsule/Sandbox parity: a root-cause diagnosis with ordered work slices, and the protocol-first replan that derives the smallest rendering contract from main and treats the three trust tiers as conforming adapters. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
evaluateModuleInCurrentRealm again sticks the AMD registration onto the define function itself, with the original comment explaining why: Rollup removes locals that are only visible to eval, so a closure variable is not safe in a production build. Deletes zero-referenced runtime code: TrustedBaseFormat, LocalSurfaceClient (the surface modifiers are the Direct/Capsule dispatch path), the evaluator's format-only import facade and test shim escape hatches, the classifier's unconsumed format-only-import analysis, and the loader's write-only fetched-shim bookkeeping. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The normative rendering contract extracted from main: component entry, formats and the cascade table, field/model/argument semantics, computed values (function-form only), configuration, routing rules R1-R5, the five-state relationship model, instance identity, edit/save (full-document PATCH, clientRequestId echo suppression, no revision token), the context plane with exact degraded behaviors, scoped CSS, prerender constraints, protocol records/operations, tier obligations, conformance machinery, and the deferred/excluded lists. Statements carry RP-x.y ids for the statement-to-test bijection; DRAFT until the Direct equivalence suite is green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The addon's package root is its Node-only Ember CLI build hook; Vite bundles it into the test build, and evaluating window.require crashes bundle load before any test runs. Alias the bare import to the addon-test-support browser module and supply the broccoli-generated env module from a local stub, following the existing classic-addon alias pattern in this config. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The protocol module now owns the cross-boundary record vocabulary: the SafeEvent/SafeEventTarget projection, the template bundle with its typed render-dependency union (authored-component | trusted-export | literal-value), and version/feature assertions. Bundles carry a protocol version and are validated before reification; an unknown dependency kind rejects the whole bundle. The execution engine asserts the semantic protocol version and required features on every render record, so an unsupported record fails closed to last-known-good instead of rendering an unknown shape. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
BoxelRenderRecord now has exactly one producer shape. A new pure module, lib/boxel-projection.ts, owns the semantic projection of a canonical instance (description, resolved fields with linked values as BoxelValueReference references, merged field configuration, field descriptions, instance presentation) plus the trusted-semantics document projection, which now returns a new document instead of mutating the request in place. buildBoxelRenderRecord() is the one assembly point and derives the model from the resolved fields, so tiers cannot disagree about declared values. Direct consumes the shared pipeline directly and remains the reference implementation. Capsule adopts the Host projection per instance (wired through the execution engine), so trusted-Base semantics materialize once, Host-side, and cross as data, while the Capsule evaluator keeps ownership of authored templates, getters, computeVia, and actions; its Host-less fallback now conforms to the shared shapes (reference-shaped values, format inventory from the declared vocabulary rather than a hard-coded list, writability defaulting to false absent a Host grant). The Sandbox child already builds records with the Direct runtime, so it inherits the shared pipeline unchanged. The record-diff conformance test renders one fixture through Direct and Capsule and deep-diffs the BoxelDescription, resolved fields, instance identity, and presentation, alongside shape probes that pin the reference semantics themselves. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The vendored currency-code-symbol-map data exists solely so the Host can shim the esm.run package of the same name, which deployed realm code (including base/currency.gts) imports. Base's Currency field goes back to importing that package identifier, served by the Host-owned shim in every tier's loader, and the map is no longer re-exported from the runtime-common index, so nothing can reach for it as a semantic substitute for trusted Base behavior. Trusted getters such as CurrencyField.symbol cross execution boundaries as data via the Host projection pipeline. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Direct is the reference implementation, so correctness is enforced by three layers: an equivalence suite proving the protocol's Direct tier renders identically to main's legacy CardRenderer path, a conformance suite exercising routing, the format cascade, computed fields, links, error chrome, and the Direct-vs-Capsule semantic record diff, and a statement<->test bijection checker that fails CI when a test cites a statement the spec does not make (RP-0.3). Coverage of the reverse direction stays report-only until the spec reaches NORMATIVE status (--strict); skipped tests never count as coverage. BoxelExecutionRenderer now seeds both default-format axes from the caller's format exactly as main does (RP-1.5), with the Capsule child-format cascade (RP-2.6) supplied by a provider scoped to the Capsule slot. Verified by the equivalence suite: 14/14 against the live test stack. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
isolated HTML is rendered and stored on prerendered_html.isolated_html during indexing, but it was not queryable through the entry/search APIs: isolated was absent from PRERENDERED_HTML_FORMATS, so assertHtmlQuery rejected format=isolated with a 400 and store.fetchCardEntry's format param would not typecheck, and the search projection never selected the column so the enumerators had nothing to emit. Add isolated to the format allowlist, select ph.isolated_html in the renderSet projection that feeds searchEntries (hence /_search and /_federated-search), and emit an isolated candidate from the row and file rendering enumerators. isolated is a scalar column rendered at the row's native type, so it behaves like atom/head. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ence Browser comparison of real cards between this branch's host and the deployed host surfaced four defect families; each is fixed at its root: - Projection collapsed every card-shaped value to a reference stub. contains/containsMany composites and loaded, side-loaded links now expand recursively (cycle-guarded, depth bounded by what the document side-loads); unloaded links keep the RP-7 reference form. This restores nested composite values, computed titles over compound entries, enum labels, and authored code that reads a loaded link's fields. - The sandbox module allowlist was seeded only from the entry module's static import graph. Modules declared by the document's own resource meta (linksTo/linksToMany targets) are now granted per-document via modulesConsumedInMeta, still an exact allowlist. - A sandbox child failure after bootstrap was structurally silent: the parent removed its only control-port listener when bootstrap settled, and a hung child left renders pending forever. The control protocol gains a runtime-error variant with a persistent listener, renders get a bounded timeout, and the child installs error/unhandledrejection reporters wired to that contract, so failures surface as the standard error presentation instead of a blank card. - Scoped CSS with network-bearing values (@import/url) classified to Capsule, whose CSS policy rejects those spellings, and the prerendered placeholder path swallowed the rejection silently. The classifier now routes network-bearing scoped CSS to the Sandbox tier using the same shared pattern the policy enforces, and a rejected placeholder stylesheet is logged instead of vanishing. The prerendered placeholder for isolated surfaces now prefers the isolated-format entry (falling back to embedded), building on the isolated prerender exposure cherry-picked from main. New unit and integration coverage accompanies each fix, including the first RP-15.3-cited sandbox conformance tests (19 of 91 statements covered). Suites are authored and type-checked; the full browser test battery runs next as its own step. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Analysis of the frozen reference branch's instant-reload system for iframe rendering, mapped onto this branch's transport and authority seams: inventory, mechanism walkthrough, the hard-won edge cases that must be honored, per-piece portability verdicts, and an ordered extraction plan. Notable scope findings: the iframe tier needs no DOM-adoption primitive (that machinery is Capsule-only), and the module authority's observe()-grown admission already matches the reference behavior, leaving generations, acknowledgements, and last-known-good retention as the work to implement. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Volatility is a mode orthogonal to execution tier: cards run stable by default and promote to a volatile Capsule/Sandbox session — draft buffers, HMR generations, a lease-based quiet-period demotion — only while a user or agent is actively editing their source. The plan states the isolation requirement (an edit session shadows only the edited modules and never invalidates loaders shared with other mounted cards), the vite-like refresh/flash budget, and the sequencing after sandbox HMR. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Once a module goes volatile it stays volatile in the loader until the tab closes; the next session starts stable from persisted state. This removes the quiet-period lease and its lease-expiry-mid-save race from the design — per-tab volatile state is bounded and evaporates with the tab, and stable-graph isolation keeps the rest of the workspace unaffected either way. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fixes verified against real cards rendered side by side with the deployed host, plus two named residuals: - Relationship values: linksToMany no longer silently drops mid-resolution slots (membership state is read through the sanctioned API after the field getter triggers resolution), and the execution session re-projects when a pending relationship settles — first paint stays immediate with the link absent, settlement republishes one fresh generation through the existing update path. - Sandbox child boot: the credentialless iframe no longer constructs MatrixService (a telemetry constructor captured the user id at boot, dragging the whole matrix stack into the child); a sandbox-gated initializer registers a stub service ahead of any lookup, and the auth service-worker initializer is gated on the same boot check. Dynamic import() calls in authored modules are rewritten through the child Loader instead of evaluating natively against the host bundle's base URL, closing an authority bypass. Child errors before ready are buffered and reported after; stage breadcrumbs across the bootstrap/RPC/render chain log at warn level for live diagnosis. - Sandbox RPC hangs: all runtime RPCs carry the same bounded timeout the render channel got earlier, so a stalled child surfaces the error presentation instead of leaving a placeholder up forever. - Module admission: CDN-agnostic (binary content types are skipped, everything else is parsed; the esm.sh hostname carve-out is gone) and bare specifiers inside third-party modules are no longer mis-resolved into bogus same-origin URLs. - Theme rendering: trusted-module stylesheets are exempt from the shared-document Capsule CSS policy; runtime-generated theme sheets (bare theme-scope selectors declaring only custom properties) are admitted; the render record carries a computed themeScope token that the renderer stamps on the capsule slot, normalized through unresolveURL so it matches the compiled stylesheet selector. - Prerendered placeholders wrap multi-root isolated HTML so htmlComponent accepts them. Residuals, tracked for follow-up: a user-realm theme's stamped token still misses the installed selector (unresolveURL only maps registered realms — the token form for unregistered realms needs a decision), and sandbox child paint remains unverified live (breadcrumbs are in place to pinpoint any remaining stall). docs/ gains the maintainer-lens minimality review with its ordered slim-down plan. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…undary Relationship family (Capsule): the renderer now consumes every settle-republished generation into @model (not just the first), the engine explicitly drives pending linksTo loads through the same StoreService the classic path uses (card-api's own lazy-load trigger is only store-wired for the canonical root, not nested contains() sub-instances), and the Host-owned field portals reproduce main's array-like plural contract (numeric index, length, iterator) so authored templates that index @fields.<linksToMany|containsMany> render each item. Theme family: InstancePresentation carries themeCss and cssImports alongside the scope token, and the Capsule slot makes the identical trusted CardContainer invocation main's field-component makes — stamp, scoped theme stylesheet, @imports, and the container's semantic-token derivation — verified pixel-equal (background rgb(17,23,19)) against the classic path. Sandbox lifecycle (RP-15.3): the iframe is born inside its presentation slot and never re-parented — the parking-lot design reloaded the child's document on every adopt/park, destroying completed renders. The renderer classifies early (memoized, pure), reserves the Sandbox process ahead of materialize(), and awaits mount before the first RPC, breaking the mount⇄materialize cycle. The prerendered placeholder overlays the live, never-hidden iframe until the child's first real paint; the child reports intrinsic height over the surface layout channel; render diagnostics now measure paint truth (an AND of content and on-screen size, plus body composition, root rect, offsetParent, visibilityState) and authority denials name the URL. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…branch parity The bijection checker becomes a one-way ratchet: RP-0 (meta, enforced by this script and CI) and RP-17 (deferred) are exempt; every other statement counts against a recorded ceiling that CI refuses to let rise and prompts to tighten whenever coverage lands. Two new suites take coverage from 21 to 59 of the 85 coverable statements — protocol statics (format inventories, context tokens, version/feature admission, classification and containment tables, themeScope determinism) and rendered semantics (component entry, format resolution, arguments, computed values, field configuration, context plane, presentation statics, identity/documents), each test phrased so a failure points at the violated spec sentence. The parity audit distills the frozen reference branch's 42.5k-line delta through one question — what does the Capsule/Sandbox system necessitate for existing users and cards — into nine ranked redo items, an explicit not-ported table, and the projected end-state line budget. It also resolves the minimality review's F10: the frozen branch's CI collapse is the empirical evidence that the materialization-purpose split is protocol-reserved, not dead code. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…metry A card's own mount-time code legitimately assumes real element size — main guarantees it, and a WebGL card sizes its renderer exactly once from the mount modifier. The child now waits (bounded) for its render root to have nonzero geometry before mounting the card's component, and re-measures the render diagnostic on subsequent root resizes so a post-paint size change still reports paint truth. Verified live: the Three.js 3MF viewer renders its scene at full size on both fresh load and reload, and the placeholder hands off to the painted child. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Un-defers RP-17.1's HMR for the Sandbox tier as spec section RP-18, with all seven statements conformance-covered and the whole rp- battery green in a real browser run (100/100). The mechanism, per the extraction dossier's seven steps: BoxelExecutionSession.pushDraft(moduleIdentifier, source) re-classifies the draft, serves its source through the module-read channel's exact-URL-only override, and drives a process-monotonic generation over the render wire (echoed on every response; parent state transitions only on a matching echo). The child drops stale generations on arrival and after every await, invalidates only the edited module, and re-derives the card from the same document so instance data survives while component identity changes. A failed generation retains last-known-good alongside its error; reloadSandbox() is the sole path that remints iframe identity, also clearing draft overrides and resetting the module authority. An ordinary draft never re-enters the placeholder. Defects the first real execution of these suites surfaced and fixed: update() re-broadcast the previous generation's record at the top of every replace (a duplicate-notification bug that would have double-fired on every future draft too); bootstrap failures surfacing through materialize() left a stale sandbox slot outranking the error presentation (all failure paths now converge on clearing the slot, generation-guarded); and the runtime error reporter dispatched on the real window, which any host test runner's global handler also observes — it now takes an injectable event source. The RP-18.2 conformance test waits on the server's own arrival bookkeeping rather than assuming timer and MessagePort task-source ordering. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
First real runs (the test-realm stack was previously unavailable to these suites) surfaced three tests asserting the spec through illegal or mistaken sequences: the RP-8.2 mismatch probe forced a second local id for a claimed remote id — through the Host store the sanctioned observable of that sequence IS the hard error, now asserted as such and noted in the spec's layering note; the RP-8.3 fixture omitted the resource linkage (`data.id`) its own statement names as the side-loading key, accidentally reproducing the statement's negative; RP-8.4 expected a raw URL where the execution document correctly carries the canonical scoped identifier — the expectation now derives from the live VirtualNetwork mapping. The RP-4.4 fixture's field named `name` tripped a genuine main-behavior artifact — the fields proxy's ownKeys trap appends declared names to the component class's built-ins without dedupe, violating the proxy invariant — recorded as an RP-17.3 gap; the fixture moves off the colliding spelling. rp-conformance 14/14 and rp-semantics 25/25 in real browser runs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The policy layer over RP-18's source volatility, per the volatile execution plan: promoteToVolatile(moduleIdentifier) marks a module as under active editing for the rest of the tab's session — one-way, no lease, no demotion, inert for trusted Host modules. Volatility is a routing input that can only strengthen isolation: a promoted module routes to the Sandbox tier regardless of its Capsule classification, checked live at materialization so a promotion landing mid-request still takes effect. Promotion of a mounted card re-routes it live through the ordinary generation-replace path. The renderer establishes a per-module tracked dependency synchronously in its resource's tracking frame — one cell per module, deliberately not a global counter, so promoting one card never re-instantiates (or flickers) an unrelated card's renderer. The isolation guarantee is conformance-tested from both sides: a volatile session's drafts leave the host loader's cached module identity untouched, and a neighboring session's subscriber observes zero notifications during another session's draft cycle. Spec section RP-19 (four statements, all cited) lands with the implementation; the ratchet holds at 102 statements / 70 covered. rp-volatile 7/7, full rp- battery 100/100 in real browser runs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The child announces its own boots, but only the parent knows the surface identity that ties successive boots together — a process created more than once for the same surface in quick succession is the signature of a renderer resource re-instantiating on a tracked-state tick, observed in the wild as a card visibly flashing every ~13 seconds. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nstant The child previously reported its render root's getBoundingClientRect() height — the laid-out box, bounded by the iframe's current viewport — and the parent applied it as a min-height. Measuring the box the parent sizes is a feedback loop: an isolated card grew 150px → 448px → 544px and never reached its content height. The child now reports the root's scrollHeight (the content's demand, independent of the current box, exactly what the frozen branch's realm-iframe-height-service measured), re-measuring on subtree mutations, fonts.ready, and window resize; SurfaceService owns what a report MEANS: intrinsic mode sets an explicit clamped (40–2400px) height, allocated mode (fitted) sets height: 100% and ignores nothing — the child simply never reports in allocated mode, via the shared surfaceHeightModeFor() both sides derive from. The prerendered placeholder is now in-flow while the Sandbox boots — it SIZES the slot (no white gap, no reflow at handoff) while the iframe sits absolute behind it at opacity 0, exactly the frozen branch's loading presentation; the child's first-paint diagnostic swaps them with a fade. The placeholder fetch moved after classification and is Sandbox-only, isolated/edit-format only, always fetching the isolated prerender — it previously fired a network round-trip for every card render, Capsule included, for a placeholder that was rarely shown. Also fixes a silent scoped-css hazard found while verifying: a selector compound containing :global() drops its scoped prefix entirely, so the booting iframe rules (position: absolute; opacity: 0) were being applied to EVERY iframe on the page. The full selector now lives inside :global(...). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adorn/overlays discover rendered cards through exactly one mechanism: the ElementTracker modifier that operator mode injects via CardContext and field-component.gts applies to every nested card container. The execution runtime bypassed all of it — the field portal rendered authored cards bare, the Capsule's @consume(CardContextName) facade returned a frozen empty object, and the slot roots carried no card identity — so every overlay-eligible card silently vanished from operator mode. Three restorations, mirroring what the frozen branch's realm-sandbox-render.gts deliberately preserved: - BoxelFieldPortal re-stamps field-component's contract on its rendered root (tracker modifier + data-boxel-card-id/format + data-test-card attributes), with the field's own type/name threaded through from buildFieldPortals. The stamped element is always parent-document DOM, so even a Sandbox-routed nested card stays discoverable. - The Capsule @context facade now plucks exactly two Host presentation capabilities from the renderer-passed projection — the ElementTracker modifier and the search rendering surface — instead of freezing everything away; no Store, loader, or service authority crosses. - The Capsule and Sandbox slot roots stamp card identity attributes. Stack close could permanently die: handleAnimationCompletion's non-Abort rejection path logged the error but never resolved, wedging startAnimation's dropTask forever, after which every close click was silently dropped. The animation promise now always settles, and dismissStackedCardsAbove bounds its cosmetic animation wait with a 1s race so no animation can ever gate dismissal. Also honors the ContentElement modifier's teardown (class modifiers ignore modify()'s return value), which leaked a MutationObserver per stack item. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fonts.ready and late observer tails can invoke the reporter after stop(); a torn-down reporter must never land another layout report. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A credentialless iframe strips the browser session that lets main render private-realm <img>s in-document, so every asset in a sandboxed card 401'd (all 20 TierList logos, per the localhost-vs-staging comparison). Relative authored URLs additionally resolved against the sandbox origin. The fix is the frozen branch's media bridge, ported to the new transport: the child-side SandboxMediaBridge discovers img[src] under the render root, resolves each against its owning card's data-boxel-card-id (never the iframe route), strips the src before the browser can race an unauthenticated request into a card's permanent error fallback, and swaps in a blob from the fetch channel's new 'media' purpose lane. The parent side never consults the module graph for media — an image must never become admitted module state — and bounds the lane to GET, image/* responses, and the shared size cap. The Host fetch carries the user's realm authorization, which is the same authority main already grants every in-document <img> via the browser session. Authored code never sees the capability or the authenticated response. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… boundary Cross-view sync is main's core behavior: one instance per id, autotracked reads in every template, so any field set re-renders every view in place. The execution runtime broke that twice — first by accident (a tracking leak re-materialized the whole session per save: the flash), then by design error (an event-subscription reprojection pipeline whose reader wrote back to the instance and looped through auto-save, corrupting data; docs/boxel-sync-root-cause-2026-08-06.md is the full post-mortem). The correct translation, per the maintainer's rule (study main; only add what the boundary needs): createLiveBoxelModel — @model becomes a Proxy whose property reads project the canonical instance's CURRENT value as cloneable data. Reads are pure (relationships via membership state only; loading stays materialize/settlement's job; pending subtrees answer with the materialize-time fallback) and autotracked, so the framework's render pass is the delivery pipeline — there is nothing to order because there is only one channel. Two bridge details make the tracking complete: peekAtField alone tracks TrackedArray items but not the field slot (a save echo replacing an array froze the model mid-word), so every read also consumes a per-instance tracked version cell whose subscriber is a bump-only observer; and the capsule component manager's argument-update revision now invalidates via microtask, since live args legally change during a render pass. With delivery structural, the renderer resource unrepeats the original sin under untrack(): its tracked dependencies are exactly card identity, format, and volatility — a save can never again tear down the DOM. The acceptance bar (RP-20.5) passes live: a sentence typed into a field lands intact, same element, same focus, while the isolated view of the same card tracks every keystroke. RP-20 (Rehydration continuity, 5 statements) specifies the contract; the rp-continuity suite covers all five (typing stability, two-view convergence, live-model purity+liveness, scroll retention, media-cache rehydration — the Sandbox media bridge now caches one blob per source so re-created images swap in synchronously). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@habdelra The hosted Sandbox deployment follow-up is now pushed at What changed:
Verification:
The PR remains draft and DO NOT MERGE. Real production stays configured for Please re-review at |
|
Small final follow-up: Both preview deploy jobs succeeded again at the new head. I repeated the signed-in Library → FORGE card → Edit → Finish Editing → isolated-card flow on the rebuilt staging artifact: nonce iframe present, card rendered before and after the toggle, and zero browser-console errors. Please use |
|
Follow-up fix is deployed at head f94b650. This closes the transient private-realm source 401 that could occur when an interactive Boxel execution source load overlapped background prerender state: interactive source loads now enter a concurrency-safe reauthentication scope, while the dedicated prerender app remains storage-only. Deployed verification on the production preview URL:
@habdelra please re-review the latest head when convenient. The PR remains draft and explicitly DO NOT MERGE; the preview is ready for broader corpus testing. |
|
Google Fonts parity follow-up is pushed and deployed at head 38fe0e6. Change:
Verification:
@habdelra please include this latest head in the re-review. The PR remains draft and DO NOT MERGE. |
|
Most of the host tests failwith the same error: could you have your agent try to address this? it seems critical |
Direct RP regression coverageThis update deliberately moves the affected Host regression tests through the Direct Render Protocol path instead of continuing to instantiate card components through the legacy shortcut.
Local pre-push evidence: Host lint passed; Base lint passed; Direct preview 10/10; RP conformance 15/15; execution engine 20/20; smoke-runner unit tests 9/9; environment-config verification passed. The accompanying wild-corpus runner contains URLs and observations only—no private workspace files. |
|
looks good! feel free to push on teh CI failures as much as you want. but i think we are probably over the hump in terms of a prototype |
|
CI follow-up in fc5bf89:\n\n- Host regression call sites continue to exercise their original product behavior through the Direct RP adapter. The nested-card editor assertion now keys off the actual isolated-format fixture marker instead of assuming the pre-RP direct-child DOM topology.\n- Direct RP now retains a same-card/same-format presentation across resource acknowledgements, with focused tests for DOM/input identity and edit→isolated format transitions.\n- Authored relationship portals keep present authored values on the execution router while delegating only terminal broken-link slots to trusted Base; coverage includes a live present→broken transition and a real realm-backed 404 inside a Capsule.\n- Software Factory treats repeated opencode transport failures as terminal blocked results instead of mistaking a dead child for idle and retrying until the Playwright timeout.\n\nLocal verification: Host lint; Host Vite test build; RP continuity 12/12; focused relationship tests; formerly failing nested create/edit workflow; Software Factory JS/format lint and new transport-liveness tests. Private workspace files and unrelated dirty files were not committed. |
No description provided.