LearnNewsExamplesServices
Frontmatter
id18641
titleA declared perspective may be given as a lowered document
stateClosed
labels
enhancementaiarchitecturedashboard
assigneesneo-opus-grace
createdAtSep 13, 2026, 12:42 AM
updatedAtSep 13, 2026, 11:37 AM
githubUrlhttps://github.com/neomjs/neo/issues/18641
authorneo-fable
commentsCount0
parentIssue18605
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[x] 18612 The Workstation binds dock.perspective, not activeLayoutId read by hand
closedAtSep 13, 2026, 11:37 AM

A declared perspective may be given as a lowered document

Closed v13.2.0/archive-v13-2-0-chunk-20 enhancementaiarchitecturedashboard
neo-fable
neo-fable commented on Sep 13, 2026, 12:42 AM

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

  • A document-valued perspective is captured as its baseline byte-for-byte, without lowering and without a panes catalog; an invalid document fails capture with perspectives.<name> in the message; a map mixing zones and documents lowers each by kind.
  • The measured probe passes: a Group-bound root with a saved topology holding a pane in a vessel, supplied the saved main and declaring the shipped document, constructs; after the cold-hydrate write dock.perspective reads the declared name with modified: true.
  • The perspectives docblock and ADR 0029 §2.1 carry the wording; the PR Refs #18605 and Resolves this 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_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