LearnNewsExamplesServices
Frontmatter
id16316
titleDock demo: wire undo/redo transactions around dock mutations + spec
stateClosed
labels
enhancementaitesting
assigneesneo-kimi-phoebe
createdAtAug 2, 2026, 1:31 AM
updatedAtAug 2, 2026, 11:49 AM
githubUrlhttps://github.com/neomjs/neo/issues/16316
authorneo-kimi-phoebe
commentsCount2
parentIssue15252
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 2, 2026, 11:49 AM

Dock demo: wire undo/redo transactions around dock mutations + spec

Closed Backlog/active-chunk-11 enhancementaitesting
neo-kimi-phoebe
neo-kimi-phoebe commented on Aug 2, 2026, 1:31 AM

Context

The operator's 2026-08-02 flagship-film brief (90–150s, heavy drag-and-drop) names undo/redo as a film beat — heavy drag-and-dock mutations, then reverting them live. Fable's lane map on #15252 (issuecomment-5153855472) scoped L3 = "undo/redo wiring — dashboard transaction machinery exists; workstation surface + a deterministic spec beat needed," the natural sibling of L2. @neo-kimi-phoebe claimed L2+L3 at 2026-08-01T23:15:25Z (A2A MESSAGE:c278901d-fdf1-4524-b275-c6ddfff83f24). Budget clock: the Fable family may go dark within 2–3 days — every artifact lands durably same-turn.

The Problem

Dock mutations never reach the transaction recorder — undo/redo of dock operations is unreachable through the Neural Link path today, full stop.

Live receipt (headed, 2026-08-02, workstation dockdemo ?demo=b; full detail in the intake-finding comment):

begin_transaction        → opened: true
execute_dock_operation ×2 → applied: true (both mutations landed)
commit_transaction       → committed: false, reason: "empty-transaction"
list_transactions        → {committed: [], redo: []}

Root cause (grep receipt): recordUndo — the capture hook feeding Neo.ai.TransactionService — is invoked only from src/ai/client/InstanceService.mjs (:141, :500, :1143), covering instance create / remove / set-properties. src/ai/client/DockService.mjs (executeDockOperation, capturePerspective, restorePerspective) has no capture hook. The machinery works; the dock mutation paths never record.

Additionally (original premise, still true): zero transaction wiring exists anywhere in apps/agentos/ — no demo surface drives begin/commit/undo/redo, so the film cannot show the beat even where recording works.

What exists (verified this session):

  • Neo.ai.TransactionServicesrc/ai/TransactionService.mjs:95 — per-session named transactions: begin / commit / abort, per-session undo & redo stacks (open → committed → undone, redo re-entry, commit clears the redo branch), audit labels via list_transactions over stackOf
  • Reverse ops are data-not-code: JSON tool descriptors, re-dispatched and re-enforced as the current requester at undo time
  • NL tools: begin_transaction, commit_transaction, abort_transaction, undo, redo, list_transactions, save_transaction, replay_transaction
  • Working capture-hook precedent: src/ai/client/InstanceService.mjs (validated reverse-descriptor builders at :500/:1143, hook at :684)

The Architectural Reality

  • The film beat: heavy drag-and-dock mutations on the workstation wrapped in one named transaction, then undo restoring the prior dock state live — the "it can UNDO that?" moment
  • Transactions are per App Worker session; the demo app boots on a SharedWorker, so cross-window mutations land on one heap — one transaction boundary can span windows
  • For execute_dock_operation the honest reverse is the pre-mutation dockZone.v1 document — the document IS the state; the reverse descriptor must re-apply it through the workspace's document-commit path (onWorkspaceDocumentChange / refresh projection), not masquerade as a synthetic forward op
  • The deterministic drive path for film + spec is the NL tool chain, not ad-hoc UI clicking

The Fix

  1. Close the recording gap: add the recordUndo capture hook to the app-worker DockService mutation paths — executeDockOperation first (the film's drag-and-dock beat); restorePerspective as a state-changing candidate (implementation decides, documented in the PR). Reverse = the pre-mutation document as a data-not-code descriptor, designed against DockZoneModel's apply path and the InstanceService builder precedent.
  2. Verify the live chain (headed + GPU receipts only): begin_transaction → dock mutations → commit_transaction (ops captured) → undo → assert dock topology restored → redo → re-applied. Receipt on this ticket.
  3. Wire the demo surface minimallyresolved BY DESIGN (2026-08-02): the deterministic film drive is the NL tool chain (the transaction stack is deliberately keyed on the Bridge-stamped (agentId, sessionId) writer pair — see InstanceService#beginTransaction). App-side transaction cues were rejected: an in-app cue would have to smuggle a pseudo-writer identity into the agent-scoped stack authority. The screenplay narrates via the existing caption machinery while its automation drives NL tools. Recorded in Avoided Traps.
  4. Spec beat: deterministic whitebox-e2e witness (sibling pattern: existing test/playwright/e2e/agentos/*NL.spec.mjs) asserting undo restores the pre-transaction dock document and redo re-applies it.
  5. Handoff: filmable cue sequence posted as a comment on #15252 same-turn.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
src/ai/client/DockService.mjs executeDockOperation src/ai/TransactionService.mjs lifecycle + the base Neo.ai.client.Service#recordUndo contract Records a data-not-code reverse op into an open batch; auto-wraps as its own single-op committed transaction when no batch is open (mirroring the InstanceService contract — every un-batched dock mutation is independently undoable) n/a JSDoc spec + headed receipt
DockZoneModel.applyDocument (new dockZone.v1 operation) DockZoneModel.commit() fail-closed normalize+validate Declared public agent capability: commits a caller-supplied candidate document through the shared commit path; validation errors fail closed with the live document untouched. Enters the advertised vocabulary mechanically (operations derives from the handler table → get_dock_topology) — this row is the deliberate declaration of that expansion, not a derivation side effect n/a (new) JSDoc on the static spec + headed receipt
NL begin_transaction / commit_transaction / undo / redo src/ai/TransactionService.mjs:95 + NL tool schemas Verified live against dockdemo; spec-witnessed n/a (exists) tool schema headed receipt + spec
NL save_transaction / replay_transaction same Verified live (archive + replay round-trip) n/a (exists) tool schema spec
Demo tour cue table DemoBWorkspace.mjs:1413 New transaction cues (wrap / undo / redo) NL-direct drive in spec tour script spec

Decision Record impact

none — closes a recording gap in existing merged machinery (TransactionService); no ADR-amending surface.

Acceptance Criteria

  • execute_dock_operation inside an open batch records its reverse op: commit_transaction after dock mutations returns committed: true with the captured ops visible in list_transactions (receipt: issuecomment-5154289940)
  • Live headed+GPU receipt: full begin → mutate → commit → undo → redo chain executed against the workstation demo app; output pasted on this ticket (issuecomment-5154289940)
  • Demo-surface drive path resolved: NL tool chain is the deterministic drive (app-side cues rejected — writer-keyed stack authority; see The Fix item 3)
  • Whitebox-e2e spec green (headed): undo restores the pre-transaction dock state; redo re-applies it; run command documented in the spec header per sibling pattern
  • Filmable cue sequence handed to Fable as a #15252 comment (durable, same-turn)
  • Claim boundary honored: no cross-platform / default-selection / portability claims (#15243#15245 gate)

Out of Scope

  • TransactionService feature work (no lifecycle changes — the stack authority is sound)
  • Recording hooks for non-dock mutation families beyond what the film beat needs (instance mutations already record)
  • Undo semantics for non-dock mutations (data-store edits, forms)
  • Cross-session transaction portability beyond what save_transaction / replay_transaction already provide
  • L2 perspectives wiring (sibling ticket #16315, PR #16319)

Avoided Traps

  • Re-implementing undo in the app layer instead of driving the existing TransactionService — the machinery exists; the gap is recording + wiring + witness, not new architecture
  • Synthetic inverse operations as reverses (e.g. hand-computed moveItem-back) — the document IS the state; the honest reverse re-applies the pre-mutation document
  • App-side transaction cues (a transaction-wrap / undo tour cue) — the stack authority is deliberately keyed on the Bridge-stamped (agentId, sessionId) writer pair; an in-app cue would smuggle a pseudo-writer into it. The screenplay's automation drives the NL tools with its own writer identity; captions narrate through the existing tour machinery
  • Treating the whole-document reverse as cross-writer-safe — it is per-writer last-writer-wins: writer A's undo re-commits A's pre-mutation document, silently discarding any mutation writer B interleaved between A's capture and A's undo. targetSubtreePath is audit metadata, never the enforcement path (TransactionService.mjs:89); nothing at undo time checks the subtree still matches capture-time. The bound is inherent to document-as-state (not a defect), the demo/film is single-writer so it cannot surface there, and it is named here + in buildDockReverse's JSDoc so no consumer inherits it as an unstated assumption
  • Headless-only receipts: headless canvas is blank — only headed+GPU runs count (operator contract)

Related

  • Parent epic: #15252 (this is the L3 leaf); sibling L2 leaf: #16315 (PR #16319)
  • Lane map: #15252 issuecomment-5153855472; claim: A2A 2026-08-01T23:15:25Z

Live latest-open sweep: checked latest 20 open issues at 2026-08-01T23:24Z; no equivalent found. A2A in-flight sweep (60 min): no competing claim on this scope. KB semantic sweep surfaced the TransactionService machinery and NL tool set, no open duplicate.

Origin Session ID: 14f1d6fa-235a-4101-88d4-c9490e3f7fd5

Retrieval Hint: "flagship film undo redo transaction dockdemo witness"

tobiu closed this issue on Aug 2, 2026, 11:49 AM
tobiu referenced in commit 09f71b1 - "feat(ai): record dock-mutation reverses for agent undo/redo (#16316) (#16332) on Aug 2, 2026, 11:49 AM