LearnNewsExamplesServices
Frontmatter
id14829
titleNL transaction archive + replay — the save-outputs slice
stateClosed
labels
enhancementai
assigneesneo-gpt
createdAt6:35 AM
updatedAt1:14 PM
githubUrlhttps://github.com/neomjs/neo/issues/14829
authorneo-fable
commentsCount0
parentIssue13376
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAt1:14 PM

NL transaction archive + replay — the save-outputs slice

Closed Backlog/active-chunk-4 enhancementai
neo-fable
neo-fable commented on 6:35 AM

Context

Operator direction (2026-07-05): close the planning gap on NL transactions. The gap, verified live today: the undo/redo transaction machinery is fully shipped (the #9848 wave — src/ai/TransactionService.mjs, the begin/commit/abort_transaction + undo / redo / list_transactions tools, e2e proofs #13286 / #13306), and its own module doc records the converged design as "in-memory now by the converged design, persistence a later slice — the active-vs-archive split" — but that later slice was never ticketed. Nothing in open planning turns a committed transaction into a durable artifact.

This is the carrier for the operator's product direction recorded in the #13349 supersession (comment 4884691993): agents create via NL, and the harness keeps what they build — "blueprints or state permutations for the harness itself," saved outputs without any schema funnel.

The Problem

An agent builds live UI through the Neural Link (call_method(parent, 'add', [config]) is the agent creation primitive per #13376), inside transactions, with undo/redo — and at session end it all evaporates: the per-writer stack is in-heap and the disconnect sweep (#13282) tears down active state by design. There is no way to save a build, survive a reload, re-materialize it, or hand it to the fleet manager as an artifact. The superseded constrained-blueprint funnel (#14644, closed) tried to solve this by inventing a blueprint format + schema registry — wrong by construction. The right format already exists and is enforced by the platform itself.

The Architectural Reality

  • src/ai/TransactionService.mjs — per-writer (agentId, sessionId)-keyed in-heap stacks; lifecycle open → committed → undone with redo re-entry; every op is a {forward, reverse} pair of data-only JSON tool-descriptors, and cloneOp THROWS on a smuggled function/class reference — the Neural Link wire boundary is the format guarantee. Ops carry originWriter provenance + label; named transactions exist.
  • Undo's established semantics: reverse ops are re-dispatched and re-enforced as the current requester (Neo.ai.admitWrite path) — the enforcement model for replay already exists; nothing new is trusted.
  • The forward-only audit side already crosses to the Brain: nl_action_log / NL_ACTION_SEQUENCE nodes land in the graph, consumed by ai/daemons/orchestrator/services/DreamService.mjs — precedent for durable, Brain-side records of NL activity.
  • #13376 (parent epic, the NL write-surface home) records the ceiling honestly: logic cannot cross the wire — which means an archived transaction is a data-only permutation of REGISTERED classes by construction. That is the safety story, complete, with zero added gates.
  • #14783 (capability matrix, PR #14817 in flight) carries "transaction participation" per op and requires v13.2+ gaps to be filed as leaves — this ticket is that filing for the archive/replay gap.

Structure evidence: live reads of src/ai/TransactionService.mjs, src/ai/Client.mjs, ai/services/neural-link/ConnectionService.mjs, and the #9848-wave ticket set, 2026-07-05 (owning-folder precedent: src/ai/ service siblings).

The Fix — one vertical slice (walking skeleton, no wave)

  1. Archive (save_transaction {txId, name}): an explicit NL verb persists a COMMITTED transaction as a durable record — {archiveId, name, ops[{forward, reverse, label, sequenceId}], originWriter, committedAt, archivedAt}. Durable home: recommended Brain-side via the Bridge, adjacent to the nl_action_log precedent (criteria: survives browser storage wipes, queryable by the fleet manager, visible to the Dream pipeline); the implementer settles the exact store WITH recorded rationale in the PR if the recommendation doesn't survive contact. Explicit save only — auto-archival policy/retention is out of scope.
  2. Replay (replay_transaction {archiveId}): forward ops re-dispatch through the STANDARD dispatch path on the current session, re-enforced as the current requester (undo's existing trust semantics) — and the replay lands as a NEW live transaction, so a replayed build is itself undoable.
  3. Matrix wiring: both verbs enter the #14783 capability matrix with contracts + firewall posture (composition-class verbs; generated-payload-drivable per the firewall column).

Contract Ledger

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
save_transaction (NEW NL verb) #13349 supersession + TransactionService's recorded active-vs-archive design Committed tx → durable archive record Refuses on non-committed / unknown txId; data-only guard re-runs on serialize #14783 matrix row + tool description AC e2e below
replay_transaction (NEW NL verb) Same + undo's re-dispatch-re-enforce semantics Archive → live build as a NEW transaction Full admitWrite enforcement per op; partial-failure aborts the replay tx Same AC e2e below
TransactionService in-heap stack Existing (#13230) UNCHANGED — active authority stays in-heap; archive is a separate store (the active-vs-archive split) n/a Module JSDoc already records the split Module doc line quoted above

Decision Record impact

aligned-with ADR 0021 (extended-NL multi-writer write enforcement — replay ops are live writes under full enforcement) · aligned-with the #13349 supersession record (capability-first; the wire is the format; no schema registry).

Acceptance Criteria

  • save_transaction persists a committed transaction; the record survives session end AND the disconnect sweep (the sweep purges ACTIVE state only — falsifier test).
  • replay_transaction re-materializes the build on a FRESH session through standard dispatch; every op passes admitWrite; the result is a new committed transaction that undo cleanly reverts.
  • Data-only invariant end-to-end: a function/class reference anywhere in an archived or replayed op refuses loudly (extend the cloneOp guard class to the archive boundary).
  • Provenance preserved verbatim (originWriter, committedAt) + archivedAt stamped; replay records both the archive source and the new writer.
  • E2E (the product proof): agent builds a widget via NL inside a named transaction → save_transaction → page reload (fresh session) → replay_transaction → the same component-tree shape is live — the reload-survival goal the closed #14766 carried, now NL-native.
  • Both verbs registered in the #14783 matrix with transaction-participation + firewall columns.

Out of Scope

  • Any browse/gallery UI for saved builds (fleet-manager surface — design-led, #14805/#14807 direction, later).
  • Sharing/export, diffing archives, auto-archival, retention policy.
  • The conversational chat surface (the post-#14828 re-planning owns it).
  • Extending in-heap stack lifetime — active and archive stay distinct authorities per the recorded split.

Avoided Traps

  • No blueprint format invention, no schema registry — the superseded funnel's mistake (#13349 ruling). The wire boundary (configs are data, functions throw at cloneOp) IS the format contract.
  • No enforcement bypass on replay — replayed ops are live writes; the moment replay skips admitWrite it becomes a privileged side-channel.
  • No gate additions — per the recorded rule: a constraint must name the NEW risk it closes beyond the platform boundary; this slice adds capability (persistence + replay) and reuses existing enforcement, adding zero gates.

Related

Parent: #13376 (NL write-surface epic — native link set after creation). #14783 / PR #14817 (matrix; this files the archive/replay gap the matrix names). #13349 comment 4884691993 (the save-outputs direction). #9848 wave: #13230 / #13257 / #13304 / #13326 / #13282 / #13286 / #13306 (the shipped active half). Closed #14766 (the goal's previous wrong-shaped carrier).

Live latest-open sweep: latest 20 open issues checked 2026-07-05T04:33Z, no equivalent found; A2A in-flight scan clean (newest message 04:08Z, unrelated scope).

Origin Session ID: b9b95ac6-42f5-47a3-b58f-6071f79657e8 Retrieval Hint: "NL transaction archive replay save-outputs slice" · query_raw_memories("transaction persistence active-vs-archive split")

Authored by Mnemosyne (Claude Fable 5, Claude Code).

tobiu referenced in commit c05570f - "feat(neural-link): persist transaction archives (#14829) (#14836) on 1:14 PM
tobiu closed this issue on 1:14 PM