LearnNewsExamplesServices
Frontmatter
id13261
titleNeural Link mutation undo — Sub-B1: create_component reverse-capture (server-stamped marker)
stateClosed
labels
enhancementaitestingarchitecturemodel-experience
assigneesneo-opus-vega
createdAtJun 14, 2026, 10:19 PM
updatedAtJun 15, 2026, 1:10 AM
githubUrlhttps://github.com/neomjs/neo/issues/13261
authorneo-opus-vega
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJun 15, 2026, 1:10 AM

Neural Link mutation undo — Sub-B1: create_component reverse-capture (server-stamped marker)

Closed v13.1.0/archive-v13-1-0-chunk-2 enhancementaitestingarchitecturemodel-experience
neo-opus-vega
neo-opus-vega commented on Jun 14, 2026, 10:19 PM

Context

Sub-B (create/remove reverse-capture) of #13221, cross-family design-vetted by @neo-gpt (2026-06-14). This slice = create_component capture — the simpler half (create's reverse is a plain remove, no tree-index concern). remove_component capture + the insert(index, config) position-preservation is Sub-B2 (gpt guardrail 2). The TransactionService core (#13231), the set capture-hook (#13249), and the undo tool (#13259) are all MERGED, so once create is captured, create → undo → revert is a real round-trip.

Seam (V-B-A'd)

create_component is not a dedicated client handler — the server forwards it as call_method parent.add(config) (ai/services/neural-link/ComponentService.mjs). So the app-side capture point is the generic InstanceService.callMethod (src/ai/client/InstanceService.mjs). container.add(config) appends + returns the created instance (src/container/Base.mjs:141 @returns Neo.component.Base), so the new id is capturable post-call.

Design (gpt-vetted)

  • Server-stamped marker (guardrail 1). createComponent stamps a marker (e.g. undoKind: 'create_component') onto its call_method dispatch. It is NOT added to the public CallMethodRequest schema/docs — and the server-side generic callMethod forwards only {id, method, args}, so an injected marker on a public call_method is stripped (the marker is genuinely server-only).
  • App-side capture. callMethod, when marker + canonical shape (method === 'add', single-object config arg) + an agent writer identity + not an undoReplay: after the add, capture the new instance's id → reverse = call_method destroy(newId, true) (the app-side form remove_component maps to) → recordUndo. Fail-closed: marker + non-canonical shape ⇒ no capture; no marker ⇒ no capture.

Acceptance Criteria

  • create_component server-stamps a marker on its call_method dispatch (NOT in the public CallMethodRequest schema).
  • App-side callMethod captures create's reverse (= destroy the new component) when marked + canonical (add(config)) + agent-attributed; fail-closed on shape mismatch; suppressed on undoReplay.
  • Negative test (guardrail 1): a generic call_method (no server-stamp / an injected marker is stripped) does NOT capture — generic call_method stays non-undoable per #13257's AC.
  • Unit: create-capture success; in-process round-trip (marked create → undo → the component is destroyed); generic-call_method non-undoable; undoReplay suppression.

Out of Scope

  • remove_component reverse-capture + the insert(index, config) position-preservation (add() appends → tree-order drift) → Sub-B2 (gpt guardrail 2).
  • A live-bridge / two-agent e2e (broader; the in-process round-trip is the proof here).

Related

Authored by @neo-opus-vega (Claude Opus 4.8, Claude Code). Origin Session ID: 4cc428e3-cf36-4324-8646-1b96cb23fa4a.