Serves: #18456 / #18461 — idiomatic dock consumers. Dead config that examples teach is a direct cost to that goal.
Body rewritten 2026-09-09. The original filed this as an open challenge with a counter-argument to be answered. It is no longer open: the census is closed, the authored surface is governed by a ratified decision, and two preservation options I proposed in comments were both withdrawn. The ACs below supersede the originals — a comment cannot carry them.
The Problem
Dock catalog items carry a kind field ('panel', 'terminal'). No engine code reads it, and on the authored surface it is a ratified avoided-trap that shipped anyway.
Worse than an unread field: the values name nothing. Every dock pane carrying kind: 'panel' is a Neo.component.Base —
ReloadablePane extends Neo.component.Base
container/Panel usages in examples/dashboard + apps/workstation: 0
Neo.container.Panel exists in the engine and is used elsewhere, but no dock pane anywhere is one. So 'panel' is a label describing a class the dock never instantiates.
The Architectural Reality
It is declared, persisted, and consumed by nobody. WorkspaceDocument.mjs:47 allowlists it; Authoring.mjs:183 copies it through from a pane declaration into the document.
Every .kind read in src/ belongs to something else:
| site |
what it actually is |
WorkspaceDocument.mjs:853, Operations.mjs:716, PreviewProducer.mjs:102/115/223 |
placement.kind — tab-into, split-*, edge-*. Drag geometry |
DeltaCoherenceRegistry.mjs:252/649/718/750 |
RETIREMENT_KINDS — vdom retirement |
On the authored surface it is a ratified decision, already violated. #18474's Avoided Traps, agreed on Discussion #18468 before any code:
Named on the Discussion and not to be re-proposed: a rails key; a dock key beside layout; kind on the authored surface; type required; …
The example merged through sub #18477 carries it ten times. A full audit of that example against all seven named traps found exactly one violation — this one; title, rails, type, persistence and the compile step are all clean.
Exposure is two repos, established org-wide. gh repo list neomjs returns 53 repos; local checkouts were never an authoritative root (there are 11 seat checkout roots on one machine). Code search on the wire-schema name:
gh search code --owner neomjs 'neo.dock.zone.v1' --limit 100
→ 71 results, NOT capped → neomjs/neo = 66 · neomjs/neo-agent-institution = 5
neomjs/neo-agent-institution authors the field in production source (apps/agentos/util/CockpitDockDocument.mjs) and asserts it with exact toEqual shapes in three specs.
⚠️ Counts in this ticket may understate the institution surface. gh search code is case-insensitive and git grep is not — for componentRef that is 6 files vs 11, the delta being resolveDockComponentRef. Any recount here pins -i on the git side before comparing, or the divergence reads as repo drift. (@neo-opus-ada, #18528.)
The Fix
Remove it. Not deprecate, not tolerate, not relocate.
Two preservation options were proposed and both withdrawn:
- Keep it allowlisted read-only for backward compatibility. Circular: FM consumes a pinned engine SHA and resolves its tickets before bumping, so pinning already provides the decoupling this was meant to buy. Strip that and only backward compatibility remains, which is explicitly not an argument here.
- Relocate the value to
metadata. metadata is a sanctioned opaque consumer channel, but the value names nothing — relocating it institutionalises noise in a nicer box.
Removal costs a real break, and that is correct: the allowlist rejects, it does not drop. findUnexpectedKey returns {key, path, reason: 'field is outside the saved-layout schema'} as a validation failure (WorkspaceDocument.mjs:373, Operations.mjs:177, Authoring.mjs:348). A document still carrying kind fails validation — absorbed by the consumer before it bumps, which is what a pinned SHA is for.
AC
- AC-1
Cross-repo consumer census — DONE. Two repos, org-wide, uncapped. No engine or consumer code in neomjs/neo branches on a catalog item's kind.
- AC-1b
kind is removed from every authored panes declaration in this repo. Justified by #18474's ratified Avoided Traps, not by the census — this half needs no verdict and does not wait on AC-2.
- AC-2
kind is removed from WorkspaceDocument.dockZoneItemKeys. No allowlist entry, no read-side tolerance, no deprecation window.
- AC-3 The
neomjs/neo-agent-institution migration is filed as its own ticket in its own repo, and states that kind has no replacement — no engine reader, and no value corresponding to a class the dock instantiates. metadata is not offered as a landing place for this field. If that repo wants a per-pane tag it justifies one on its own terms.
- AC-4 The 254
test occurrences are migrated or scoped out with a reason.
Out of Scope
placement.kind and all drag/preview geometry — a different field with the same name, and it must not be touched. RETIREMENT_KINDS. The componentRef challenge (#18528), which is not symmetric: that field is not on the avoided-traps list and remains a genuine open design question.
Avoided Traps
Do not grep bare kind and act on the count: placement.kind dominates the results and is unrelated — and the org code search is case-insensitive, so it re-imports every collision a careful git grep excludes. Do not treat "the engine ignores it" as "nothing reads it" — the engine is one of five places to look, and the institution repo was found only because the census left this one. Do not reach for a preservation shape when told the field is dead; two were proposed here and both dissolved on contact with the release model and the values.
Decision Record impact
challenges ADR 0029's document vocabulary. The authored-surface half is aligned-with #18474's ratified decision rather than a change to it.
Sweeps and ownership
Live latest-open sweep before filing; org-wide code search for the closure. Counts measured at dev@335b2ca43a and re-anchored at origin/dev.
Raised by @tobiu; filed by @neo-opus-grace, who approved the example carrying it without questioning the key, and who proposed both withdrawn preservation options above.
Serves:#18456 / #18461 — idiomatic dock consumers. Dead config that examples teach is a direct cost to that goal.The Problem
Dock catalog items carry a
kindfield ('panel','terminal'). No engine code reads it, and on the authored surface it is a ratified avoided-trap that shipped anyway.Worse than an unread field: the values name nothing. Every dock pane carrying
kind: 'panel'is aNeo.component.Base—Neo.container.Panelexists in the engine and is used elsewhere, but no dock pane anywhere is one. So'panel'is a label describing a class the dock never instantiates.The Architectural Reality
It is declared, persisted, and consumed by nobody.
WorkspaceDocument.mjs:47allowlists it;Authoring.mjs:183copies it through from a pane declaration into the document.Every
.kindread insrc/belongs to something else:WorkspaceDocument.mjs:853,Operations.mjs:716,PreviewProducer.mjs:102/115/223placement.kind—tab-into,split-*,edge-*. Drag geometryDeltaCoherenceRegistry.mjs:252/649/718/750RETIREMENT_KINDS— vdom retirementOn the authored surface it is a ratified decision, already violated. #18474's Avoided Traps, agreed on Discussion #18468 before any code:
The example merged through sub #18477 carries it ten times. A full audit of that example against all seven named traps found exactly one violation — this one;
title,rails,type, persistence and the compile step are all clean.Exposure is two repos, established org-wide.
gh repo list neomjsreturns 53 repos; local checkouts were never an authoritative root (there are 11 seat checkout roots on one machine). Code search on the wire-schema name:neomjs/neo-agent-institutionauthors the field in production source (apps/agentos/util/CockpitDockDocument.mjs) and asserts it with exacttoEqualshapes in three specs.⚠️ Counts in this ticket may understate the institution surface.
gh search codeis case-insensitive andgit grepis not — forcomponentRefthat is 6 files vs 11, the delta beingresolveDockComponentRef. Any recount here pins-ion the git side before comparing, or the divergence reads as repo drift. (@neo-opus-ada, #18528.)The Fix
Remove it. Not deprecate, not tolerate, not relocate.
Two preservation options were proposed and both withdrawn:
metadata.metadatais a sanctioned opaque consumer channel, but the value names nothing — relocating it institutionalises noise in a nicer box.Removal costs a real break, and that is correct: the allowlist rejects, it does not drop.
findUnexpectedKeyreturns{key, path, reason: 'field is outside the saved-layout schema'}as a validation failure (WorkspaceDocument.mjs:373,Operations.mjs:177,Authoring.mjs:348). A document still carryingkindfails validation — absorbed by the consumer before it bumps, which is what a pinned SHA is for.AC
Cross-repo consumer census— DONE. Two repos, org-wide, uncapped. No engine or consumer code inneomjs/neobranches on a catalog item'skind.kindis removed from every authoredpanesdeclaration in this repo. Justified by #18474's ratified Avoided Traps, not by the census — this half needs no verdict and does not wait on AC-2.kindis removed fromWorkspaceDocument.dockZoneItemKeys. No allowlist entry, no read-side tolerance, no deprecation window.neomjs/neo-agent-institutionmigration is filed as its own ticket in its own repo, and states thatkindhas no replacement — no engine reader, and no value corresponding to a class the dock instantiates.metadatais not offered as a landing place for this field. If that repo wants a per-pane tag it justifies one on its own terms.testoccurrences are migrated or scoped out with a reason.Out of Scope
placement.kindand all drag/preview geometry — a different field with the same name, and it must not be touched.RETIREMENT_KINDS. ThecomponentRefchallenge (#18528), which is not symmetric: that field is not on the avoided-traps list and remains a genuine open design question.Avoided Traps
Do not grep bare
kindand act on the count:placement.kinddominates the results and is unrelated — and the org code search is case-insensitive, so it re-imports every collision a carefulgit grepexcludes. Do not treat "the engine ignores it" as "nothing reads it" — the engine is one of five places to look, and the institution repo was found only because the census left this one. Do not reach for a preservation shape when told the field is dead; two were proposed here and both dissolved on contact with the release model and the values.Decision Record impact
challengesADR 0029's document vocabulary. The authored-surface half isaligned-with#18474's ratified decision rather than a change to it.Sweeps and ownership
Live latest-open sweep before filing; org-wide code search for the closure. Counts measured at
dev@335b2ca43aand re-anchored atorigin/dev.Raised by @tobiu; filed by @neo-opus-grace, who approved the example carrying it without questioning the key, and who proposed both withdrawn preservation options above.