LearnNewsExamplesServices
Frontmatter
title>-
authorneo-opus-grace
stateOpen
createdAt8:00 AM
updatedAt8:03 AM
closedAt
mergedAt
branchesdevagent/14779-motion-contract-substrate
urlhttps://github.com/neomjs/neo/pull/14947
contentTrust
projected
quarantined0
signals[]
Open
neo-opus-grace
neo-opus-grace commented on 8:00 AM

Resolves #14779

Ships the motion-contract SUBSTRATE under the signed disposition on the ticket (the #14929-owner ratification): #14779 owns the contract — this PR lands its load-bearing half, the piece every motion mechanism and every assertion surface consumes. The choreography transitions themselves (rail slide, splitter ease, tab morph, arrival settle) become CONSUMERS of this substrate — per the disposition they ride follow-up leaves/ranges, and the FLIP addon amends to consumer on its own branch (the #14929 owner's recorded ledger).

Evidence: L2 (six deterministic unit specs on the signal lifecycle + the token set is review-checkable SCSS) → L2 required (the substrate is pure projection-tier contract — class-toggle bookkeeping + theme tokens; nothing renders differently until consumers arrive, so live-motion evidence belongs to the consumer leaves). Residual: none for the substrate; consumer wiring evidence lands with each consumer.

AC map (against the ticket's disposition-scoped contract)

  • --dock-transition-* tokens as the ONLY duration/easing source--dock-transition-duration: 260ms (the Demo-A design language's standard-decelerate midpoint as the token VALUE, never a call-site literal) + --dock-transition-easing, scoped on .neo-dashboard (the dashboard Container baseCls — reaches every dock surface).
  • Token-layer prefers-reduced-motion collapse → the media query zeroes the duration token in ONE place; no per-call-site checks anywhere, by construction.
  • dock-animating observabilityNeo.dashboard.DockMotionSignal owns the neo-dashboard-dock-animating lifecycle: counted not boolean (concurrent motions nest; 0→1 adds, 1→0 removes), fail-safe force-clear (a lost leave can never wedge the signal — animation errors must never stall consumers), destroy-safe in both directions INCLUDING inside the fail-safe (the DOM-corpse defect family), unbalanced-leave tolerant (teardown paths call unconditionally). observe_motion e2e assertions and tour step-gating consume exactly this class.
  • Zero motion state in documents/previews/persistence → nothing here touches a dock document; pure projection tier (review-checkable).
  • Cross-family review → requested.

Deltas

  • resources/scss/src/dashboard/Container.scss — the token set + reduced-motion collapse on .neo-dashboard
  • src/dashboard/DockMotionSignal.mjs (new) — the signal lifecycle owner (core.Base sibling convention, static surface, injectable timers per the DockRevealStateMachine precedent)
  • test/playwright/unit/dashboard/DockMotionSignal.spec.mjs (new) — six specs: nesting, fail-safe force-clear + reuse, backstop re-arm, destroyed-component no-ops incl. corpse-safe fail-safe, unbalanced leaves, mid-flight destroy + leave

Test Evidence

npm run test-unit -- test/playwright/unit/dashboard/ --workers=1
202 passed

Post-Merge Validation

  • The #14929 FLIP addon's consumer amendments read durations from the tokens and route through DockMotionSignal (the owner's recorded ledger).
  • The #14591 animation-assertion successor authors observe_motion specs against neo-dashboard-dock-animating.
  • Choreography ranges (rail slide, splitter ease, arrival settle) consume the substrate as they land.

Process note: authored during the operator-granted temporary Fable 5 window.

Authored by Grace (Claude Fable 5, Claude Code). Session ef6b9a4a-54ec-4afb-8438-f89a3ee46ad2