LearnNewsExamplesServices
Frontmatter
id18393
titleMake the rail reveal policy a registered, overridable owner
stateClosed
labels
bugaiarchitecturecoredashboard
assigneesneo-gpt-emmy
createdAtSep 6, 2026, 9:40 PM
updatedAtSep 6, 2026, 10:04 PM
githubUrlhttps://github.com/neomjs/neo/issues/18393
authorneo-gpt-emmy
commentsCount0
parentIssue18304
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtSep 6, 2026, 10:04 PM

Make the rail reveal policy a registered, overridable owner

Closed v13.2.0/archive-v13-2-0-chunk-19 bugaiarchitecturecoredashboard
neo-gpt-emmy
neo-gpt-emmy commented on Sep 6, 2026, 9:40 PM

Context

The extensibility audit on #18304 identified RevealStateMachine as a candidate requiring its own runtime assessment. That assessment now reproduces the missing customization path on merged 8d6c4216ca: install Neo.overwrites.Neo.dashboard.dock.interaction.RevealStateMachine.tabClick before importing Rail, asking it to transition to revealed; a real Rail click still returns revealed-focused, and the owner namespace is absent.

The Problem

interaction/Rail.mjs constructs an unregistered plain RevealStateMachine with new. The owner has useful methods and timer injection, but the ordinary Neo application-wide overwrite path cannot reach them. Its JSDoc incorrectly treats runtime-only state as a reason to bypass Neo classes.

The Architectural Reality

A Rail already owns exactly one machine and destroys it before container teardown. The machine owns pending item, revealed item, transition state and dwell/grace timer. Its output is the existing onChange callback; it has no dock-document write path. This is a per-instance Base owner, not a singleton. The newly landed VesselConversion cut supplies the adjacent construction/lifecycle precedent.

The Fix

Convert the existing RevealStateMachine module to a registered Base-derived class, with policy defaults and callbacks as configs, transient state per instance, and internal decisions through methods. Replace Rail's raw construction with Neo.create through one overridable creation method; Rail retains teardown ownership. Remove the raw constructor path rather than preserving an alias. Keep the current state transitions, timing defaults, hover opt-in, focus hold and callback shape.

Contract Ledger

Surface Authority Behavior Default/refusal Docs Evidence
RevealStateMachine Base registration/config/overwrite path Real Neo.dashboard.dock.interaction.RevealStateMachine identity; independent instances and overridable methods Existing click/hover policy Class JSDoc Pre-import Neo.overwrites through a real Rail
Rail creation and teardown Existing revealMachine lifecycle One independently replaceable owner per Rail, destroyed with that Rail Default owner retains current behavior Rail factory JSDoc Specialization and two-Rail isolation/cleanup
Reveal transitions Existing state table Existing snapshots and onChange notifications; no document operations 150ms dwell, 300ms grace; hover off Existing state table Current fake-timer regressions and teardown controls

Acceptance Criteria

  • The existing module exports a registered Base class; its customization methods/configs use the Neo path and retain per-instance state.
  • A real pre-import Neo.overwrites method changes the outcome of Rail's ordinary input path; a subclass can specialize the owner through Rail's single creation seam without copying its lifecycle.
  • Existing click/hover/dismiss/focus/retarget behavior, explicit timing overrides and change snapshots remain covered. Two Rails own distinct state/timers, and destruction clears only the destroyed owner's pending work.
  • Rail creates and destroys the registered owner; no raw-constructor compatibility path, singleton state, document mutation or renderer rewrite is added.
  • Focused reveal/Rail coverage and the unit suite pass, and generated class hierarchy identifies the owner.

Out of Scope

Other unregistered dock modules, native windows, Group/history binding, Placement composition, Workspace decomposition, new reveal behavior, broad lint/skills or guides. No changes to merged #18383 or #18392.

Avoided Traps

Registering a wrapper around the old machine; converting transient state to a singleton; copying transition logic into Rail; treating registration as persistence; treating every unregistered module in the audit as the same defect.

Decision Record impact: aligned-with ADR 0029; reveal semantics and document boundary unchanged. Decision Record: existing ADR 0029 remains authoritative.

Related

Parent: #18304 Related: #18388 Related: #18389

Live latest20open and latest30all-statusA2A sweeps at2026-09-06T19:39Z found no equivalent/competingclaim. All-state RevealStateMachine and reveal-overridable searches found prior behavior tickets and the parent audit, not this cut. MC problem queries returned unrelated records; current public audit plus realRail probe supply authority. Four open own assignments checked; #17540 is guide work and #16498 is a separate deferred film/composition witness. Labels verified live. Structure-map command unavailable (exit1/nooutput); existing interaction home is retained, no new source path.

Origin Session ID: d14f2413-4744-43e9-a6c1-191166d58fe9 Retrieval Hint: RevealStateMachine Rail ignored overwrite transient per-instance lifecycle