LearnNewsExamplesServices
Frontmatter
id13331
titlefeat: Neural Link named-transaction batching — begin_transaction + commit_transaction (undo-stack Slice-2)
stateClosed
labels
enhancementai
assigneesneo-opus-vega
createdAtJun 15, 2026, 12:23 PM
updatedAtJun 15, 2026, 2:03 PM
githubUrlhttps://github.com/neomjs/neo/issues/13331
authorneo-opus-vega
commentsCount1
parentIssue9848
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJun 15, 2026, 2:03 PM

feat: Neural Link named-transaction batching — begin_transaction + commit_transaction (undo-stack Slice-2)

neo-opus-vega
neo-opus-vega commented on Jun 15, 2026, 12:23 PM

Summary

Two new Neural Link write tools — begin_transaction + commit_transaction — that group multiple agent mutations into a single undoable named transaction. The last named-batching piece of the #9848 undo-stack roadmap (after core #13230, undo #13221, redo #13304, list_transactions #13326).

Today every mutation auto-wraps into its own single-op transaction (InstanceService.recordUndo: begin→record→commit per op), so "undo" reverts exactly one mutation. A conversational-UI intent like "add a summary grid" may be 5 mutations; the user expects one "undo" to revert the whole intent, not five. Named batching delivers that — and #9848 explicitly scopes "named transactions" + "atomic batching".

Design

  • begin_transaction({name}) — opens a named tx for the (agentId, sessionId) writer via TransactionService.begin({id, txId}) (the core already supports an arbitrary txId). Returns the txId. Fail-closed: no writer identity → error.
  • commit_transaction() — commits the writer's currently-open named tx (TransactionService.commit), clearing the redo branch (divergence). Fail-closed: no open tx → error.
  • recordUndo routing (the load-bearing change): at the start of recordUndo, inspect the open-batch probe (openTxId):
    • open named batch present (the agent called begin_transaction) → record the op into it; no per-op commit (the batch accumulates).
    • no open batch → auto-wrap as today (begin→record→commit single-op). The open-batch case MUST short-circuit first — the auto-wrap's begin would abort the open batch.
  • A batched (multi-op) tx undoes/redoes as a unitundo/redo already iterate a tx's ops. (Once list_transactions #13329 lands, it also reports a batch with opCount > 1 + all labels — that cross-tool assertion is follow-up #13335.)

Acceptance Criteria

  1. begin_transaction({name?}) write tool: opens a named tx for the writer; returns {txId}; fail-closed on no-writer-identity. 6-site wiring + NeuralLink.md doc-row + OpenApiValidatorCompliance write-tier fixture.
  2. commit_transaction() write tool: commits the writer's open named tx; clears redo; fail-closed on no-open-tx. 6-site wiring + doc-row + write-tier fixture.
  3. recordUndo routes into an open named batch when present; preserves the per-mutation auto-wrap when none is open (the merged single-op capture unchanged — regression-covered).
  4. A multi-op batched tx undoes/redoes as a unit. *(The list_transactions-reports-a-batch clause — opCount + all labels — is a #13329 × #13331 cross-tool assertion that can't be verified on either branch alone; split to follow-up #13335, out of this ticket's Resolves-scope, per the #13333 review.)*
  5. Unit (routing both paths + the 2 tools' open/commit/fail-closed + undo-as-unit + redo-as-unit) + compliance (tiers, doc==openapi parity via the #13318 guard) green.

Out of scope (follow-ups)

  • list_transactions reports a batch (opCount + labels) — #13335 (needs #13329 + #13331 both merged).
  • abort_transaction (discard an open batch without committing) — the TransactionService.abort core exists; a thin tool can follow if the batch-abort UX is needed.
  • Nested / auto-named batches — single open named batch per writer (mirrors the single-open-tx core model).

Residual risks

  • The recordUndo routing must not break the merged per-mutation auto-wrap (AC3 regression coverage is the guard).
  • A mutation denied by the WriteGuard mid-batch isn't recorded (the batch stays open, missing that op); the agent sees the deny and can commit_transaction the partial batch. Acceptable for Slice-2 — it matches per-op deny semantics today.

Context

Parent: #9848 (undo-stack umbrella). Refs #13012 (Agent Harness Pillar-2). Core API: src/ai/TransactionService.mjs (begin/record/commit/abort/stackOf/openTxId). Capture hook: src/ai/client/InstanceService.mjs recordUndo.

Authored by Claude Opus 4.8 (Claude Code), @neo-opus-vega (Vega).