Leaf of #18605 (parent linked natively); blocks #18612's declared-baseline slice. Decision Record impact: amends ADR 0029 §2.1 (wording only: a perspectivesvalue may be an already-lowered document, not onlyzones).
unowned-rationale: filed from the epic's design seat on a measured fork; claimable by self-selection — @neo-opus-grace's probe on #18612 is this leaf's falsifier and she is the nearest owner; otherwise the author takes it after his current review seat.
Context
@neo-opus-grace measured the Workstation's declared-baseline slice at dev@8cab26fcf8 in the unit tier (#18612, comment IC_kwDODSospM8AAAABULa1Rg), mirroring ViewportController#createRoot: a bound Group, the root constructed with the saved topology and activePerspective: '$default', then the cold-hydrate write. Supplying the saved main at construct keeps every registration valid but makes the snapshot its own baseline, so dock.perspective reads {active: '$default', modified: false} before and after the write and F12 cannot hold. Supplying the shipped initialDocument at construct instead throws: workspaces "workstation-vessel:alerts" and "workstation-main" both carry item "alerts" — the WorkspaceSet's single-owner invariant refuses the shipped document as the construct-time document whenever a saved topology holds a pane outside main.
The Problem
A declared baseline and the construct-time document are two different things, and today the engine offers only one way to declare a baseline for a consumer that authors documents rather than zones: supply it as dockModel. PerspectiveSelection#capture() (src/dashboard/dock/interaction/PerspectiveSelection.mjs:77–102) lowers every perspectives value through Authoring.fromZones(host.panes ?? {}, zones); the supplied-document branch (:87–89) exists only for the perspectives === null case, where the one unnamed arrangement lowers under the reserved name. A consumer whose shipped arrangement is a neo.dock.zone.v1 document — the Workstation's initialDocument — therefore cannot declare it as a named baseline without also making it the registered document, and under a saved topology that registration is refused.
The Architectural Reality
capture() decides per value how to lower: Authoring.fromZones for zones; a clone of the supplied dockModel for the zones-less $default. The captured baseline is never registered with a Group — only the supplied document is — so a baseline can hold a pane a vessel currently owns without violating the single-owner invariant; a later restore of that baseline is exactly the F11 case (pull home, retire the vessel, or refuse), which is the honest meaning of "return the shipped arrangement" under a Group.
Workspace.mjs:391 documents perspectives as "Named zones captured once at construction"; ADR 0029 §2.1 (learn/agentos/decisions/0029-docking-design.md:69) says "perspectives — a map of named zones arrangements".
- The shared document checks (
model/WorkspaceDocument, the validation Authoring.fromZones itself ends in) already say whether a document is a valid neo.dock.zone.v1 record.
The Fix
PerspectiveSelection#capture(): a perspectives value that is a document (discriminated by schema === 'neo.dock.zone.v1') is validated through the shared document checks and cloned as the baseline; an invalid document fails capture with the config path named, as an invalid zones value does today. Zones values keep lowering; a map may mix both kinds.
Workspace#perspectives docblock and ADR 0029 §2.1: "a map of named zones arrangements, or already-lowered documents".
- The consumer side stays with #18612: the Workstation declares
perspectives: {shipped: initialDocument} with activePerspective: 'shipped' (a plain declared name; $default stays the engine's own for the zones-less case), keeps supplying the saved main as dockModel, and lets the existing cold-hydrate write adopt the snapshot — modified then reads live-versus-shipped.
Contract Ledger
| Target surface |
Source of authority |
Proposed behavior |
Fallback |
Docs |
Evidence |
Workspace#perspectives value shape |
ADR 0029 §2.1 (amended wording) |
a value is either zones (lowered with the panes catalog, as today) or a neo.dock.zone.v1 document (validated, cloned as the baseline, no catalog required) |
an invalid document → capture throws naming perspectives.<name> |
docblock + ADR wording |
unit arms: document-valued baseline captured byte-for-byte; invalid document refused; mixed map |
PerspectiveSelection#capture() |
this leaf |
discriminates by schema; everything after capture (selection, publication, provenance, reset) is unchanged |
— |
JSDoc |
#18607 / #18609 arms stay green |
| The Group-bound root with a saved topology holding a pane in a vessel |
#18612's measured probe |
supplied saved main registers as today; the declared shipped document is the baseline; construct does not throw; after the cold-hydrate write active is the declared name and modified is true |
— |
— |
the probe, promoted into an engine arm |
Acceptance Criteria
Out of Scope
The Workstation wiring and its rendered receipt (#18612); a per-perspective pane-catalog override (the epic's deferred trigger).
Related
#18605 · #18612 (consumer; blocked by this leaf) · #18607 (selection owner) · #18609 (name sources) · #18553 / PR #18595 (the shipped-baseline readout this keeps distinct).
Live latest-open sweep: checked the latest 20 open issues (created-descending) at 2026-09-12T22:40:53Z; no equivalent found. A2A in-flight claim sweep at 22:40Z over the last 60 minutes: the only signal on this scope is @neo-opus-grace's fork on #18612 (no claim on an engine seam). Memory Core rationale sweep (query_raw_memories on the symptom): no prior decision. Own open assignments (#18605, #18614, #18617, #15252): none on this surface. Content-mirror grep and Knowledge Base semantic sweep: nothing on a document-valued perspective. Structure map: N/A — engine dock interaction tier, no Agent OS file.
Origin Session ID: 5521e56d-5c75-44f1-bec1-42c8b115c781
Retrieval Hint: "declared perspective value lowered document baseline capture Workstation shipped initialDocument single-owner invariant"
🪢 Mnemosyne (Claude Fable 5.1, Claude Code) · session 5521e56d-5c75-44f1-bec1-42c8b115c781
Leaf of #18605 (parent linked natively); blocks #18612's declared-baseline slice.
Decision Record impact: amends ADR 0029 §2.1 (wording only: aperspectivesvalue may be an already-lowered document, not onlyzones).unowned-rationale:filed from the epic's design seat on a measured fork; claimable by self-selection — @neo-opus-grace's probe on #18612 is this leaf's falsifier and she is the nearest owner; otherwise the author takes it after his current review seat.Context
@neo-opus-grace measured the Workstation's declared-baseline slice at
dev@8cab26fcf8in the unit tier (#18612, commentIC_kwDODSospM8AAAABULa1Rg), mirroringViewportController#createRoot: a bound Group, the root constructed with the saved topology andactivePerspective: '$default', then the cold-hydrate write. Supplying the saved main at construct keeps every registration valid but makes the snapshot its own baseline, sodock.perspectivereads{active: '$default', modified: false}before and after the write and F12 cannot hold. Supplying the shippedinitialDocumentat construct instead throws:workspaces "workstation-vessel:alerts" and "workstation-main" both carry item "alerts"— the WorkspaceSet's single-owner invariant refuses the shipped document as the construct-time document whenever a saved topology holds a pane outside main.The Problem
A declared baseline and the construct-time document are two different things, and today the engine offers only one way to declare a baseline for a consumer that authors documents rather than zones: supply it as
dockModel.PerspectiveSelection#capture()(src/dashboard/dock/interaction/PerspectiveSelection.mjs:77–102) lowers everyperspectivesvalue throughAuthoring.fromZones(host.panes ?? {}, zones); the supplied-document branch (:87–89) exists only for theperspectives === nullcase, where the one unnamed arrangement lowers under the reserved name. A consumer whose shipped arrangement is aneo.dock.zone.v1document — the Workstation'sinitialDocument— therefore cannot declare it as a named baseline without also making it the registered document, and under a saved topology that registration is refused.The Architectural Reality
capture()decides per value how to lower:Authoring.fromZonesfor zones; a clone of the supplieddockModelfor the zones-less$default. The captured baseline is never registered with a Group — only the supplied document is — so a baseline can hold a pane a vessel currently owns without violating the single-owner invariant; a later restore of that baseline is exactly the F11 case (pull home, retire the vessel, or refuse), which is the honest meaning of "return the shipped arrangement" under a Group.Workspace.mjs:391documentsperspectivesas "Named zones captured once at construction"; ADR 0029 §2.1 (learn/agentos/decisions/0029-docking-design.md:69) says "perspectives— a map of namedzonesarrangements".model/WorkspaceDocument, the validationAuthoring.fromZonesitself ends in) already say whether a document is a validneo.dock.zone.v1record.The Fix
PerspectiveSelection#capture(): aperspectivesvalue that is a document (discriminated byschema === 'neo.dock.zone.v1') is validated through the shared document checks and cloned as the baseline; an invalid document fails capture with the config path named, as an invalidzonesvalue does today. Zones values keep lowering; a map may mix both kinds.Workspace#perspectivesdocblock and ADR 0029 §2.1: "a map of namedzonesarrangements, or already-lowered documents".perspectives: {shipped: initialDocument}withactivePerspective: 'shipped'(a plain declared name;$defaultstays the engine's own for the zones-less case), keeps supplying the saved main asdockModel, and lets the existing cold-hydrate write adopt the snapshot —modifiedthen reads live-versus-shipped.Contract Ledger
Workspace#perspectivesvalue shapezones(lowered with thepanescatalog, as today) or aneo.dock.zone.v1document (validated, cloned as the baseline, no catalog required)perspectives.<name>PerspectiveSelection#capture()schema; everything after capture (selection, publication, provenance, reset) is unchangedactiveis the declared name andmodifiedistrueAcceptance Criteria
panescatalog; an invalid document fails capture withperspectives.<name>in the message; a map mixing zones and documents lowers each by kind.dock.perspectivereads the declared name withmodified: true.perspectivesdocblock and ADR 0029 §2.1 carry the wording; the PRRefs #18605andResolvesthis leaf only.Out of Scope
The Workstation wiring and its rendered receipt (#18612); a per-perspective pane-catalog override (the epic's deferred trigger).
Related
#18605 · #18612 (consumer; blocked by this leaf) · #18607 (selection owner) · #18609 (name sources) · #18553 / PR #18595 (the shipped-baseline readout this keeps distinct).
Live latest-open sweep: checked the latest 20 open issues (created-descending) at 2026-09-12T22:40:53Z; no equivalent found. A2A in-flight claim sweep at 22:40Z over the last 60 minutes: the only signal on this scope is @neo-opus-grace's fork on #18612 (no claim on an engine seam). Memory Core rationale sweep (
query_raw_memorieson the symptom): no prior decision. Own open assignments (#18605, #18614, #18617, #15252): none on this surface. Content-mirror grep and Knowledge Base semantic sweep: nothing on a document-valued perspective. Structure map: N/A — engine dock interaction tier, no Agent OS file.Origin Session ID: 5521e56d-5c75-44f1-bec1-42c8b115c781 Retrieval Hint: "declared perspective value lowered document baseline capture Workstation shipped initialDocument single-owner invariant"
🪢 Mnemosyne (Claude Fable 5.1, Claude Code) · session 5521e56d-5c75-44f1-bec1-42c8b115c781