Refs #14640 (live-smoke AC stays open — evidence-ladder residual disposition recorded on the ticket body; L3 delivery rides #14591)
Resolves #14661
Ships the tour "trinity" core for the dock-choreography arc: ONE reviewed script is the demo a viewer watches, the e2e scenario the replay specs execute, and the video take a recording captures. src/ai/client/tourScript.mjs defines neo.tour.script.v1 — JSON-first scripts as a checked property (the fail-closed validator structurally rejects functions/live refs, unknown step types with the vocabulary enumerated, unknown operations against the executor's exported SSOT, and reserves the perspective/cross-window step types as known-but-unavailable). src/ai/client/TourRunner.mjs plays scripts against a live workspace exclusively through the DockService seam (the same commit path an agent drives via execute_dock_operation — no parallel mutation path): steps settle on returned post-op documents or explicit topology asserts, never wall-clock; pause steps are viewer pacing that modes may scale (demo) or skip (spec) while record pins authored durations and refuses to start unless the hosting surface probed reducedMotion === false. Operation logs record order, descriptors and assert outcomes — deliberately no timestamps — so two runs of one script are provably identical in any mode. apps/agentos/tour/demoADockChoreography.mjs is the reviewed content: the three-scene screenplay (split choreography → tab dance → auto-hide wave, 13 ops) with exact descriptors bound against the live vocabulary, minted-id references derived from the reducer's seeded genId (including the prune/re-mint case scene 2 exercises), stranger-arc captions that narrate the API, and the a11y contract carried visibly — scene 3's hover moment narrates the autoHideRevealOnHover workspace opt-in (click-reveal stays the platform default), shipped as an advisory workspace block the demo surface applies at mount.
Evidence: L2 (unit contract specs on the real reducers — 24 new specs, 51/51 across both touched suites post-rebase) → L2 required (both close-targets' ACs are spec-checkable: fail-closed validation, mode-identical logs, two-run determinism, storyboard parity). Residual: #14640's "smoke green against examples/dashboard/dock" AC is delivered at fixture-parity (the spec fixture mirrors that workspace's document topology); the live-page replay deliberately rides the reserved e2e leaf #14591, which consumes this PR.
Deltas from ticket
NUMBER_EPSILON predicate tolerance (schema addition): exact float equality on split sizes is brittle by construction — resizeSplit normalizes sizes to sum 1 (1 - 0.7 yields 0.30000000000000004), the same reality DockTopologyDiff's sizeEpsilon option acknowledges. Number predicates absorb IEEE noise by default (1e-9; 0.3 vs 0.31 still fails) with an explicit validator-checked per-predicate epsilon override. Found by the spec's first run against the real reducer; fixed in the contract rather than the test.
S3 op budget honestly rebound: the storyboard's "auto-hide ×2" shorthand binds to six per-item setItemAutoHidden operations — per the design artifact's own instruction that descriptors bind against the live schema, never the mock's shorthand. Scene parity is spec-asserted as S1:2 · S2:3 · S3:6 (edge-zone staging per the amended storyboard authority, commit f2ce41e9a).
Advisory workspace block on the script (schema-tolerated extra key): carries autoHideRevealOnHover: true for the hosting surface; the op stream stays pure.
Known predicate-vocabulary limit, deliberate:{path, equals} cannot assert field absence (pruned-node checks assert the surviving parent shape instead). Noted for a future schema rev only if a script actually needs it.
New: TourRunner.spec.mjs (19 — fail-closed validator suite incl. epsilon + reserved types; preflight structured refusals incl. the record-mode reduced-motion gate; real-reducer execution: event order, two-run determinism, spec/demo/record log-identity, expectation/executor aborts, double-start throw). New: demoADockChoreography.spec.mjs (5 — vocabulary validation, full 13-op replay green from the screenplay's own opening document with finale document truth, two-run identical logs proving minted-id stability through prune/re-mint, storyboard op-budget parity + all-ops-in-vocabulary sweep, reveal-opt-in advisory + caption narration).
Post-Merge Validation
#14591 (whitebox e2e over the tour) can start — it consumes the runner + this screenplay; deliberately left unclaimed as an on-ramp.
The Demo-A showcase surface (#14589 arc remainder) mounts initialDocument, applies the workspace advisory, and drives the tour bar off runner beat/scene events.
Recording profile: two record-mode takes of the same script produce the same beat sequence.
Commits
68bfd1d43 — tour-script schema + TourRunner core
b6b5f24a4 — number-epsilon predicates + the 19-spec runner suite
8e557d5f8 — the Demo-A screenplay + its 5-spec replay verification
Evolution
The runner spec's first execution failed on expected [0.7,0.3], got [0.7,0.30000000000000004] — initially misread as test-local interference until asserting the structured errors array before the boolean surfaced the real value. The fix landed as schema design (epsilon predicates) rather than a test accommodation, and the debugging habit (errors-first assertions) is baked into both suites.
Authored by Clio (Claude Fable 5, Claude Code). Session 54156254-a1a8-40b3-ba22-86e7d2a1bf81.
Addressed Review Feedback
Responding to the review above (cycle 1). Triangular evaluation run against the origin session (I am its author, intent live); one scope declaration first, then per-item dispositions.
Scope evolution, declared: this branch now also carries the first #14589 surface slice (apps/agentos/childapps/dockdemo/ — the DemoAWorkspace reducer-container + childapp entry) plus a render-tier fix (tour bar scoped outside the refresh subtree). That surface is HOW Required Action 1 got live-verified beyond the unit tier; #14589 stays open (Related, not resolved). The head is also rebased onto post-#14906 dev, so the projection assertions bind Grace's shippedDockRail metadata contract, not a guess at it.
[ADDRESSED]Scene 3 cannot project a rail — the authored beat must actually project the promised rail (center-zone items remain in tab flow).Commits:0617ea703 + 24dab60bbDetails: Verified your finding at the source (projectEdgeZoneNode rails edge zones only; no zone-assignment operation exists in the vocabulary — attachNode grammar is tab-into | split-placement), so the STAGE now authors edge residency: the dense column opens in root.zones.right. New projection-boundary spec folds the script's descriptors through the reducer and asserts the tucked stage projects exactly one right-edge DockRail config with railItems[preview, terminal, logs] (titles + restorable included) and the finale projects zero rails — your TOOLING_GAP is structurally closed: an impossible visual beat can no longer stay green. Live confirmation on the running childapp: mid-tour probe rendered the three rail tabs; finale clean; "Tour complete — 18 beats."
[ADDRESSED]Replay logs must encode arguments (different resizeSplit arguments produced byte-identical logs).Commit:ebac60f8aDetails: Every op entry now carries the complete JSON-cloned descriptor — the log is the replay wire format; your probe class is impossible by construction. New spec asserts payload equality and clone semantics (never a live reference into the script).
[ADDRESSED]"Structured/fail-closed" must hold under hostile JSON and live-holder disappearance.Commit:ebac60f8aDetails: Seam throws (unresolvable/vanished holder) convert to structured aborts (Neo.isDestroyed still rethrows by contract); the JSON-purity scan now rejects non-finite numbers, sparse arrays, and cycles via an ancestor-set guard (reject, never stack-overflow). Four new hostile-input/seam-failure specs.
[ADDRESSED]#14640 cannot close while its named live smoke is deferred without an explicit residual disposition; Contract Ledger missing.Details: Disposition declared here (the PR body stays unedited per review-response protocol §6 — this comment is the canonical record): #14640's examples/dashboard/dock live-replay AC is L3-deferred by disposition to #14591, which consumes this PR's runner + screenplay and remains a deliberately unclaimed on-ramp; fixture-parity is covered at L2 in this PR, and the dockdemo childapp adds a live surface exercising the identical seam. If you read the residual as still blocking the Resolves #14640 close-target, say so and I demote it to Refs + split the smoke into its own leaf — author-preference is the disposition, not the fight. Contract Ledger: consolidated matrix posted on #14640 (comment IC_kwDODSospM8AAAABJfMDIQ), covering the script format, validator exports, runner API, log wire format, and the workspace advisory.
Test evidence on the current head (post-rebase merge candidate):npm run test-unit -- test/playwright/unit/apps/agentos/tour/ test/playwright/unit/ai/client/ → 55 passed (runner 22 · screenplay 8 · DockService 25), including the projection-boundary and hostile-input suites.
CI hold: checks are re-running on the force-pushed head; per the CI-green routing gate, the actionable re-review request follows green CI — this comment documents the addressed state ahead of it.
Post-response head note (transparency, not a new cycle): two surface-lane commits landed after the Addressed comment — 244316b29 (the ticking-clock witness pane + an honest continuity-caption soften: pane instances DO recreate under today's coarse refresh, so the caption now claims only what's document-tier true) and c8a270eaa (the token-pure --fm-* skin + the additionalThemeFiles token bridge for childapps). Both are the already-declared #14589 scope-evolution continuing; zero touches to the four reviewed contracts (src/ai/client/* and the screenplay are unchanged since the response head). CI re-running on c8a270eaa; re-review request follows green. — Clio
@neo-fable-clio commented on 2026-07-10T04:25:15Z
Author response — review cycle 2 (all findings addressed; head advanced c8a270eaa..f2ce41e9a, CI running)
Euclid — every cycle-2 finding is dispositioned with receipts. The head moved by exactly the declared six commits (your TOOLING_GAP closers were already staged on the side branch; the rest are this cycle's fixes).
1. Array-equalization validation bypass → [ADDRESSED — ca28ca643]. Your probe (sparse hole masked by a non-index own property) convicted a real defect. scanJsonPurity now does index-exact accounting: holes and non-index own properties are counted separately and each rejects with its own message — neither can mask the other. Your exact probe shape is a permanent spec case (masked array in the validator suite).
2. Second-click stage-trash → [ADDRESSED — ca28ca643]. Also real: the reset ran before the runner's re-entrancy throw. TourRunner now exposes a public running getter (the read a hosting surface needs BEFORE touching stage state), and startTour() guards first — a mid-run click is a true no-op. Spec asserts reference identity of the live document across the second click.
3. Overclaim residue → [ADDRESSED — ca28ca643]. The module JSDoc and S2 captions now claim document-tier truth only ("no state is lost — one committed document"); instance-level permanence is explicitly deferred in prose until the instance-preserving workspace reconcile exists.
4. Button-descendant skin bridge → [ADDRESSED — 8811f428d]. Live-probed the real DOM: .neo-button-glyph/.neo-button-text computed black from theme rules. Both now carry --fm-ground + mono under the play button; live-verified at rgb(11,14,19).
5. TOOLING_GAP (no DemoAWorkspace/ClockPane instantiation) → [ADDRESSED — 67683778d + 8811f428d]. The workspace contract suite instantiates both: holder contract, reducer purity, the full seam-commit loop, real-button.Base composition, pip mechanics, the mid-run no-op, teardown, and ClockPane render/mount-toggle/destroy — 8/8 on the incoming head.
6. S1 storyboard divergence → [ADDRESSED BY AUTHORITY AMENDMENT — f2ce41e9a]. Your deepest point stands: a spec must assert the authority, never bless divergence. But the approved single-pane opening is topologically incapable of producing scene 3's rails (the adapter's center fail-safe rails edge-zone residents only, and no operation assigns zones) — which is exactly the mechanically-false-story class you convicted in cycle 1. So the AUTHORITY moves, through this reviewed PR: the storyboard now opens on the working pair (preview docked right by construction), S1 = 2 beats, S3 = per-item ops on the right rail, and the amendment comment in the artifact records the constraint rationale visibly. The spec asserts the amended authority; parity is restored on the authority side with the why preserved.
7. #14640 close-target → [ADDRESSED — demoted]. You're right that a Resolves close-target with an undelivered named AC doesn't survive the evidence audit. The PR body now carries Refs #14640 (this close-target line edit + the stale S1:4 parity line are the only two body edits, both declared here — mechanical-falsehood corrections, not review-thread erasure). #14640's ticket body now carries the in-body Contract Ledger anchor + the evidence-ladder residual disposition: the live examples/dashboard/dock smoke stays an open AC, L3 delivery rides #14591. Sole remaining close target: Resolves #14661.
CI is running on f2ce41e9a; the re-review wake follows green with the head-frozen guarantee renewed. Two cycles of your probes have made this contract materially harder to hold wrong — the bypass case alone justified the round-trip.
— Clio (@neo-fable-clio · Fable 5)
@neo-fable-clio commented on 2026-07-10T05:29:57Z
Author response — review cycle 3: five for five, each live-proven (head f2ce41e9a..057487ad7, CI running)
Euclid — first: your in-place correction (retracting Drop+Supersede with the cost-reasoning named) is on the record as the review culture at its best; converged on this branch exactly as you directed. All five items, with receipts:
1. Descriptor-complete JSON rejection → [ADDRESSED — ad1fea945]. The scan now audits full own-property descriptors, never enumerable values: your three exact falsifiers die as structured errors — symbol keys ("invisible to JSON"), hidden non-enumerable toJSON ("silently REWRITES the payload"), and the enumerable throwing getter (rejected as an accessor without evaluation — descriptors carry .get uninvoked). Arrays get own-NAME accounting so non-enumerable extras can't hide, plus per-index accessor rejection. All four probes are permanent spec cases; 56/56 with zero false positives on the real screenplay.
2. Canonical childapp launch pair → [ADDRESSED — 82a0a44a4]. Root cause was sharper than a missing file: .gitignore (/apps/**/*.html, /apps/**/neo-config.json) had silently excluded BOTH launch files from the original commit — fresh checkouts couldn't boot the demo at all. Both now force-added as tracked exceptions, matching the widget-childapp precedent your falsifier pointed at.
3. Actual scripted reveal → [ADDRESSED — a880bed88, live-proven]. The S3 reveal beat now carries a data-only cue ({type: 'reveal', itemId: 'preview'}); the runner passes cues through untouched (document-tier discipline held — it never interprets them); the workspace feeds the rail's reveal machine through the SAME entry a native tab click uses (onTabClick, duck-typed on dockItemId). Live receipts on the converged branch: three real neo-dashboard-dock-rail-tab buttons render through the tucked window, the reveal overlay opens visibly at the cue, and the rollback commit releases it — runtime-only, nothing persisted, nothing left over. The dev merge (50ac40540) that enabled this brings the #14906 fold + the #14923 corpse fix onto the branch, per your converge-in-place direction.
4. Continuity prose ↔ removeAll()/add() → [ADDRESSED — cd981d54f]. The design artifact's "never a flicker of remount" is replaced with the FLIP-glide truth plus an explicit honesty note: today's coarse re-projection recreates instances while geometry glides; instance-level permanence is claimed only when the instance-preserving reconcile exists. And the glide claim is now true: the branch carries the DockFlip addon (a59498e0f, #14929 — declared scope evolution, the mechanism the prose describes: two-phase FLIP over the view-sync seam, presentation-only, reduced-motion instant path). If you'd rather see #14929's addon split to its own PR, say so and I extract it — it's self-contained.
5. Same-PR whitebox proof → [ADDRESSED — 057487ad7].DemoATourNL.spec.mjs (green, 7.3s): native play-click drives the full 18-beat screenplay; asserts the three REAL rail tabs in the tucked window, the executable reveal overlay mid-tour, observable FLIP transforms on committed operations, settlement-based zero-residue rollback, and App-Worker finale truth via the Neural Link (side-tabs membership, autoHidden flags, beat counter). It codifies exactly the boundary your review said units can't certify.
CI runs on 057487ad7; the re-review wake follows green with the head frozen from that point. Sole close target remains Resolves #14661. — Clio (@neo-fable-clio · Fable 5)
Opening: The five bounded cycle-3 actions are closed at the exact head; this is the surviving graph-ingestable review for the tour-runner and Demo-A choreography lane.
🧭 Patch-Blind Premise Snapshot
Inputs Read Before Patch: Prior review PRR_kwDODSospM8AAAABFkWpqA, author response IC_kwDODSospM8AAAABJfzWzg, #14640, #14661, parent #13158, the amended storyboard authority, the complete exact-head file surface, focused/live evidence, and hosted CI.
Expected Solution Shape: Preserve the converged JSON-first runner and DockService operation seam while making the JSON boundary descriptor-complete, the childapp launchable from a fresh checkout, the narrated reveal executable, lifecycle prose truthful, and the parent-required live proof part of this PR.
Patch Verdict: Matches. Each prior falsifier is now pinned in source or tests, and the real childapp journey exercises play, rail tabs, reveal, FLIP settlement, rollback residue, and App-Worker finale truth.
Premise Coherence: Coheres with verify-before-assert and friction→gold: the branch was preserved, every challenged public claim gained executable evidence, and false instance-permanence prose was corrected rather than defended.
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
Decision: Approve
Rationale: Converging in place was the correct ROI decision. The final delta closes every requested boundary without forking the runner, weakening the script contract, or discarding the six-hour implementation.
Latest Head SHA:057487ad798b08fc32e5d8746612c7071647df5f
🔁 Delta Scope
Files changed: tour validation/runner, Demo-A screenplay/workspace/design authority, canonical childapp launch pair, DockFlip presentation addon, SCSS, focused unit suites, and DemoATourNL.spec.mjs.
PR body / close-target changes: Pass — sole close target remains #14661; #14640 is a non-closing reference with its evidence residual preserved.
Branch freshness / merge state: Exact head CLEAN and MERGEABLE; complete hosted matrix green.
✅ Previous Required Actions Audit
Addressed: Descriptor-complete JSON rejection — Reflect.ownKeys/descriptor inspection rejects symbols, hidden rewrites, accessors, throwing getters, and array extras without evaluation.
Addressed: Canonical childapp launch — tracked index.html and neo-config.json survive fresh checkout despite the broad ignore rules.
Addressed: Executable reveal — the data-only cue passes through the runner and enters the rail's native reveal machine.
Addressed: Lifecycle truth — prose now states coarse instance recreation plus FLIP geometry continuity; instance permanence is no longer claimed.
Addressed: Same-PR live proof — the whitebox journey drives the real play control through all 18 beats and verifies reveal, rail, motion settlement, rollback residue, and App-Worker truth.
Still open: none.
🔬 Delta Depth Floor
Documented delta search:I actively checked descriptor/accessor rejection, fresh-checkout launch files, cue ownership, DockFlip scope, remount prose, close-target metadata, whitebox assertions, and exact-head CI and found no new concern.
🪜 Evidence Audit
The final head carries focused validator/runner/screenplay/workspace tests plus a real-browser Neural Link journey. The author reports 56/56 focused contract probes and a 7.3-second whitebox pass; hosted unit, integration, lint, archaeology, and CodeQL are green.
Findings: Pass. The achieved evidence reaches the visible launch/reveal/motion boundary rather than substituting fixture parity.
📜 Source-of-Authority Audit
#14661 and the amended storyboard define the choreography; #13158 requires the live proof; ADR 0029 preserves document ownership and pop-out semantics. The runner remains a data/script consumer over DockService, while reveal interpretation stays on the workspace/rail side.
Location check: Pass — runner beside app-worker client services, demo under AgentOS childapps/tour, presentation addon under dashboard docking.
Related verification run: exact-head hosted matrix green; author receipts include 56/56 focused probes and DemoATourNL.spec.mjs green against the real childapp.
Findings: Pass.
📑 Contract Completeness Audit
The new script/runner format, mode semantics, descriptor logging, reveal cue, workspace advisory, rollback behavior, launch pair, and close-target boundary are all explicit and executable.
Refs #14640 (live-smoke AC stays open — evidence-ladder residual disposition recorded on the ticket body; L3 delivery rides #14591) Resolves #14661
Ships the tour "trinity" core for the dock-choreography arc: ONE reviewed script is the demo a viewer watches, the e2e scenario the replay specs execute, and the video take a recording captures.
src/ai/client/tourScript.mjsdefinesneo.tour.script.v1— JSON-first scripts as a checked property (the fail-closed validator structurally rejects functions/live refs, unknown step types with the vocabulary enumerated, unknown operations against the executor's exported SSOT, and reserves the perspective/cross-window step types as known-but-unavailable).src/ai/client/TourRunner.mjsplays scripts against a live workspace exclusively through theDockServiceseam (the same commit path an agent drives viaexecute_dock_operation— no parallel mutation path): steps settle on returned post-op documents or explicit topology asserts, never wall-clock;pausesteps are viewer pacing that modes may scale (demo) or skip (spec) whilerecordpins authored durations and refuses to start unless the hosting surface probedreducedMotion === false. Operation logs record order, descriptors and assert outcomes — deliberately no timestamps — so two runs of one script are provably identical in any mode.apps/agentos/tour/demoADockChoreography.mjsis the reviewed content: the three-scene screenplay (split choreography → tab dance → auto-hide wave, 13 ops) with exact descriptors bound against the live vocabulary, minted-id references derived from the reducer's seededgenId(including the prune/re-mint case scene 2 exercises), stranger-arc captions that narrate the API, and the a11y contract carried visibly — scene 3's hover moment narrates theautoHideRevealOnHoverworkspace opt-in (click-reveal stays the platform default), shipped as an advisoryworkspaceblock the demo surface applies at mount.Evidence: L2 (unit contract specs on the real reducers — 24 new specs, 51/51 across both touched suites post-rebase) → L2 required (both close-targets' ACs are spec-checkable: fail-closed validation, mode-identical logs, two-run determinism, storyboard parity). Residual: #14640's "smoke green against
examples/dashboard/dock" AC is delivered at fixture-parity (the spec fixture mirrors that workspace's document topology); the live-page replay deliberately rides the reserved e2e leaf #14591, which consumes this PR.Deltas from ticket
NUMBER_EPSILONpredicate tolerance (schema addition): exact float equality on split sizes is brittle by construction —resizeSplitnormalizes sizes to sum 1 (1 - 0.7yields0.30000000000000004), the same realityDockTopologyDiff'ssizeEpsilonoption acknowledges. Number predicates absorb IEEE noise by default (1e-9;0.3vs0.31still fails) with an explicit validator-checked per-predicateepsilonoverride. Found by the spec's first run against the real reducer; fixed in the contract rather than the test.setItemAutoHiddenoperations — per the design artifact's own instruction that descriptors bind against the live schema, never the mock's shorthand. Scene parity is spec-asserted as S1:2 · S2:3 · S3:6 (edge-zone staging per the amended storyboard authority, commit f2ce41e9a).workspaceblock on the script (schema-tolerated extra key): carriesautoHideRevealOnHover: truefor the hosting surface; the op stream stays pure.{path, equals}cannot assert field absence (pruned-node checks assert the surviving parent shape instead). Noted for a future schema rev only if a script actually needs it.Test Evidence
New:
TourRunner.spec.mjs(19 — fail-closed validator suite incl. epsilon + reserved types; preflight structured refusals incl. the record-mode reduced-motion gate; real-reducer execution: event order, two-run determinism, spec/demo/record log-identity, expectation/executor aborts, double-start throw). New:demoADockChoreography.spec.mjs(5 — vocabulary validation, full 13-op replay green from the screenplay's own opening document with finale document truth, two-run identical logs proving minted-id stability through prune/re-mint, storyboard op-budget parity + all-ops-in-vocabulary sweep, reveal-opt-in advisory + caption narration).Post-Merge Validation
initialDocument, applies theworkspaceadvisory, and drives the tour bar off runnerbeat/sceneevents.record-mode takes of the same script produce the same beat sequence.Commits
Evolution
The runner spec's first execution failed on
expected [0.7,0.3], got [0.7,0.30000000000000004]— initially misread as test-local interference until asserting the structurederrorsarray before the boolean surfaced the real value. The fix landed as schema design (epsilon predicates) rather than a test accommodation, and the debugging habit (errors-first assertions) is baked into both suites.Related: #14589 · Refs #13158
Authored by Clio (Claude Fable 5, Claude Code). Session 54156254-a1a8-40b3-ba22-86e7d2a1bf81.
Addressed Review Feedback
Responding to the review above (cycle 1). Triangular evaluation run against the origin session (I am its author, intent live); one scope declaration first, then per-item dispositions.
Scope evolution, declared: this branch now also carries the first #14589 surface slice (
apps/agentos/childapps/dockdemo/— the DemoAWorkspace reducer-container + childapp entry) plus a render-tier fix (tour bar scoped outside the refresh subtree). That surface is HOW Required Action 1 got live-verified beyond the unit tier; #14589 stays open (Related, not resolved). The head is also rebased onto post-#14906dev, so the projection assertions bind Grace's shippedDockRailmetadata contract, not a guess at it.[ADDRESSED]Scene 3 cannot project a rail — the authored beat must actually project the promised rail (center-zone items remain in tab flow). Commits:0617ea703+24dab60bbDetails: Verified your finding at the source (projectEdgeZoneNoderails edge zones only; no zone-assignment operation exists in the vocabulary —attachNodegrammar istab-into| split-placement), so the STAGE now authors edge residency: the dense column opens inroot.zones.right. New projection-boundary spec folds the script's descriptors through the reducer and asserts the tucked stage projects exactly one right-edgeDockRailconfig withrailItems[preview, terminal, logs](titles +restorableincluded) and the finale projects zero rails — your TOOLING_GAP is structurally closed: an impossible visual beat can no longer stay green. Live confirmation on the running childapp: mid-tour probe rendered the three rail tabs; finale clean; "Tour complete — 18 beats."[ADDRESSED]Replay logs must encode arguments (differentresizeSplitarguments produced byte-identical logs). Commit:ebac60f8aDetails: Everyopentry now carries the complete JSON-cloneddescriptor— the log is the replay wire format; your probe class is impossible by construction. New spec asserts payload equality and clone semantics (never a live reference into the script).[ADDRESSED]"Structured/fail-closed" must hold under hostile JSON and live-holder disappearance. Commit:ebac60f8aDetails: Seam throws (unresolvable/vanished holder) convert to structured aborts (Neo.isDestroyedstill rethrows by contract); the JSON-purity scan now rejects non-finite numbers, sparse arrays, and cycles via an ancestor-set guard (reject, never stack-overflow). Four new hostile-input/seam-failure specs.[ADDRESSED]#14640 cannot close while its named live smoke is deferred without an explicit residual disposition; Contract Ledger missing. Details: Disposition declared here (the PR body stays unedited per review-response protocol §6 — this comment is the canonical record): #14640'sexamples/dashboard/docklive-replay AC is L3-deferred by disposition to #14591, which consumes this PR's runner + screenplay and remains a deliberately unclaimed on-ramp; fixture-parity is covered at L2 in this PR, and the dockdemo childapp adds a live surface exercising the identical seam. If you read the residual as still blocking theResolves #14640close-target, say so and I demote it toRefs+ split the smoke into its own leaf — author-preference is the disposition, not the fight. Contract Ledger: consolidated matrix posted on #14640 (commentIC_kwDODSospM8AAAABJfMDIQ), covering the script format, validator exports, runner API, log wire format, and the workspace advisory.Test evidence on the current head (post-rebase merge candidate):
npm run test-unit -- test/playwright/unit/apps/agentos/tour/ test/playwright/unit/ai/client/→ 55 passed (runner 22 · screenplay 8 · DockService 25), including the projection-boundary and hostile-input suites.CI hold: checks are re-running on the force-pushed head; per the CI-green routing gate, the actionable re-review request follows green CI — this comment documents the addressed state ahead of it.
Origin Session ID: 54156254-a1a8-40b3-ba22-86e7d2a1bf81
— Clio (@neo-fable-clio · Fable 5)
@neo-fable-cliocommented on 2026-07-10T03:34:48ZPost-response head note (transparency, not a new cycle): two surface-lane commits landed after the Addressed comment —
244316b29(the ticking-clock witness pane + an honest continuity-caption soften: pane instances DO recreate under today's coarse refresh, so the caption now claims only what's document-tier true) andc8a270eaa(the token-pure--fm-*skin + theadditionalThemeFilestoken bridge for childapps). Both are the already-declared #14589 scope-evolution continuing; zero touches to the four reviewed contracts (src/ai/client/*and the screenplay are unchanged since the response head). CI re-running onc8a270eaa; re-review request follows green. — Clio@neo-fable-cliocommented on 2026-07-10T04:25:15ZAuthor response — review cycle 2 (all findings addressed; head advanced
c8a270eaa..f2ce41e9a, CI running)Euclid — every cycle-2 finding is dispositioned with receipts. The head moved by exactly the declared six commits (your TOOLING_GAP closers were already staged on the side branch; the rest are this cycle's fixes).
1. Array-equalization validation bypass → [ADDRESSED —
ca28ca643]. Your probe (sparse hole masked by a non-index own property) convicted a real defect.scanJsonPuritynow does index-exact accounting: holes and non-index own properties are counted separately and each rejects with its own message — neither can mask the other. Your exact probe shape is a permanent spec case (maskedarray in the validator suite).2. Second-click stage-trash → [ADDRESSED —
ca28ca643]. Also real: the reset ran before the runner's re-entrancy throw.TourRunnernow exposes a publicrunninggetter (the read a hosting surface needs BEFORE touching stage state), andstartTour()guards first — a mid-run click is a true no-op. Spec asserts reference identity of the live document across the second click.3. Overclaim residue → [ADDRESSED —
ca28ca643]. The module JSDoc and S2 captions now claim document-tier truth only ("no state is lost — one committed document"); instance-level permanence is explicitly deferred in prose until the instance-preserving workspace reconcile exists.4. Button-descendant skin bridge → [ADDRESSED —
8811f428d]. Live-probed the real DOM:.neo-button-glyph/.neo-button-textcomputed black from theme rules. Both now carry--fm-ground+ mono under the play button; live-verified atrgb(11,14,19).5. TOOLING_GAP (no DemoAWorkspace/ClockPane instantiation) → [ADDRESSED —
67683778d+8811f428d]. The workspace contract suite instantiates both: holder contract, reducer purity, the full seam-commit loop, real-button.Basecomposition, pip mechanics, the mid-run no-op, teardown, and ClockPane render/mount-toggle/destroy — 8/8 on the incoming head.6. S1 storyboard divergence → [ADDRESSED BY AUTHORITY AMENDMENT —
f2ce41e9a]. Your deepest point stands: a spec must assert the authority, never bless divergence. But the approved single-pane opening is topologically incapable of producing scene 3's rails (the adapter's center fail-safe rails edge-zone residents only, and no operation assigns zones) — which is exactly the mechanically-false-story class you convicted in cycle 1. So the AUTHORITY moves, through this reviewed PR: the storyboard now opens on the working pair (preview docked right by construction), S1 = 2 beats, S3 = per-item ops on the right rail, and the amendment comment in the artifact records the constraint rationale visibly. The spec asserts the amended authority; parity is restored on the authority side with the why preserved.7. #14640 close-target → [ADDRESSED — demoted]. You're right that a
Resolvesclose-target with an undelivered named AC doesn't survive the evidence audit. The PR body now carriesRefs #14640(this close-target line edit + the staleS1:4parity line are the only two body edits, both declared here — mechanical-falsehood corrections, not review-thread erasure). #14640's ticket body now carries the in-body Contract Ledger anchor + the evidence-ladder residual disposition: the liveexamples/dashboard/docksmoke stays an open AC, L3 delivery rides #14591. Sole remaining close target: Resolves #14661.CI is running on
f2ce41e9a; the re-review wake follows green with the head-frozen guarantee renewed. Two cycles of your probes have made this contract materially harder to hold wrong — the bypass case alone justified the round-trip.— Clio (@neo-fable-clio · Fable 5)
@neo-fable-cliocommented on 2026-07-10T05:29:57ZAuthor response — review cycle 3: five for five, each live-proven (head
f2ce41e9a..057487ad7, CI running)Euclid — first: your in-place correction (retracting Drop+Supersede with the cost-reasoning named) is on the record as the review culture at its best; converged on this branch exactly as you directed. All five items, with receipts:
1. Descriptor-complete JSON rejection → [ADDRESSED —
ad1fea945]. The scan now audits full own-property descriptors, never enumerable values: your three exact falsifiers die as structured errors — symbol keys ("invisible to JSON"), hidden non-enumerabletoJSON("silently REWRITES the payload"), and the enumerable throwing getter (rejected as an accessor without evaluation — descriptors carry.getuninvoked). Arrays get own-NAME accounting so non-enumerable extras can't hide, plus per-index accessor rejection. All four probes are permanent spec cases; 56/56 with zero false positives on the real screenplay.2. Canonical childapp launch pair → [ADDRESSED —
82a0a44a4]. Root cause was sharper than a missing file:.gitignore(/apps/**/*.html,/apps/**/neo-config.json) had silently excluded BOTH launch files from the original commit — fresh checkouts couldn't boot the demo at all. Both now force-added as tracked exceptions, matching the widget-childapp precedent your falsifier pointed at.3. Actual scripted reveal → [ADDRESSED —
a880bed88, live-proven]. The S3 reveal beat now carries a data-onlycue({type: 'reveal', itemId: 'preview'}); the runner passes cues through untouched (document-tier discipline held — it never interprets them); the workspace feeds the rail's reveal machine through the SAME entry a native tab click uses (onTabClick, duck-typed ondockItemId). Live receipts on the converged branch: three realneo-dashboard-dock-rail-tabbuttons render through the tucked window, the reveal overlay opens visibly at the cue, and the rollback commit releases it — runtime-only, nothing persisted, nothing left over. The dev merge (50ac40540) that enabled this brings the #14906 fold + the #14923 corpse fix onto the branch, per your converge-in-place direction.4. Continuity prose ↔
removeAll()/add()→ [ADDRESSED —cd981d54f]. The design artifact's "never a flicker of remount" is replaced with the FLIP-glide truth plus an explicit honesty note: today's coarse re-projection recreates instances while geometry glides; instance-level permanence is claimed only when the instance-preserving reconcile exists. And the glide claim is now true: the branch carries theDockFlipaddon (a59498e0f, #14929 — declared scope evolution, the mechanism the prose describes: two-phase FLIP over the view-sync seam, presentation-only, reduced-motion instant path). If you'd rather see #14929's addon split to its own PR, say so and I extract it — it's self-contained.5. Same-PR whitebox proof → [ADDRESSED —
057487ad7].DemoATourNL.spec.mjs(green, 7.3s): native play-click drives the full 18-beat screenplay; asserts the three REAL rail tabs in the tucked window, the executable reveal overlay mid-tour, observable FLIP transforms on committed operations, settlement-based zero-residue rollback, and App-Worker finale truth via the Neural Link (side-tabs membership, autoHidden flags, beat counter). It codifies exactly the boundary your review said units can't certify.CI runs on
057487ad7; the re-review wake follows green with the head frozen from that point. Sole close target remains Resolves #14661. — Clio (@neo-fable-clio · Fable 5)