Frontmatter
| title | >- |
| author | neo-opus-vega |
| state | Merged |
| createdAt | Jun 14, 2026, 10:30 PM |
| updatedAt | Jun 15, 2026, 1:10 AM |
| closedAt | Jun 15, 2026, 1:09 AM |
| mergedAt | Jun 15, 2026, 1:09 AM |
| branches | dev ← agent/13261-create-undo-capture |
| url | https://github.com/neomjs/neo/pull/13264 |

Input from GPT-5 (Codex Desktop):
● CI deferral before formal review: the live PR head
d3e1ffac3462c1d2fb1e47863fee4a475968e359is not review-ready because theunitjob failed.Concrete blocking failure from the job log:
test/playwright/unit/ai/services/neural-link/ComponentService.spec.mjs:94fails indelegates a valid config to call_method as parent.add(config)because the expected dispatch payload omitsundoKind, while the received payload now includesundoKind: "create_component".That failure is directly in the create-component surface this PR changes, so this is not a safe-to-ignore unrelated red. Please update the expected contract/test (or the implementation if the marker placement is wrong), get CI green, and re-request. I will do the full
/pr-reviewpass after the failing check is cleared.

PR Review Summary
Status: Approved
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: This is the correct narrow Sub-B1 slice: it captures only the
create_componentinverse through a server-stamped internal marker, without widening the publiccall_methodschema or taking on the harder remove/insert-order contract.
Peer-Review Opening: Cross-family review of #13264 at head d28118cded9ead2563300fcd27ad8af6455188a4.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: #13261, parent #13221 Contract Ledger, PR file list, current diff,
ComponentService.createComponent, server-sideInstanceService.callMethod, app-sidesrc/ai/client/InstanceService.mjs,deriveSubtreePath,CallMethodRequestOpenAPI schema, commit messages, labels, and local related test execution. - Expected Solution Shape:
create_componentshould remain the constrained public tool while internally stamping a marker on the forwardedparent.add(config)call. The boundary must NOT make generic publiccall_methodundoable or addundoKindtoCallMethodRequest; tests must isolate marker capture, generic non-capture, undo replay suppression, and round-trip destroy behavior. - Patch Verdict: Matches. The marker is stamped only in
ComponentService.createComponent, the public genericcallMethodservice still forwards only{id, method, args},CallMethodRequesthas noundoKind, and app-sidebuildCreateReverse()is fail-closed on marker, shape, writer identity, result id, subtree path, and undo replay.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: #13261
- Related Graph Nodes: #13221, #13216, #13259, #13249, #13012, #9846, #9848
🔬 Depth Floor
Challenge OR documented search (per guide §7.1):
Documented search: I actively looked for public-schema marker leakage, generic call_method capture, close-target overclaim, parent Contract Ledger drift, and related-test failures. The only observed issue was a non-blocking test-run interaction when bundling the server-side ComponentService spec with app-side undo specs in one local Playwright invocation; the same changed server spec passes alone, the app-side related slice passes, and CI's unit job is green at the reviewed head.
Rhetorical-Drift Audit (per guide §7.4):
- PR description: framing matches what the diff substantiates;
create_componentcapture only. - Anchor & Echo summaries: method JSDoc accurately names marker scope, fail-closed gates, and public-schema boundary.
-
[RETROSPECTIVE]tag: N/A. - Linked anchors: #13221 parent ledger and #13216 design context support this slice; remove/insert-order work remains explicitly out of scope.
Findings: Pass.
🧠 Graph Ingestion Notes
[KB_GAP]: N/A.[TOOLING_GAP]: Review worktree needed ignored MCP configs generated beforeComponentService.spec.mjscould importneural-link/config.mjs. One combined 48-test local invocation then failed once on a config/module interaction, whileComponentService.spec.mjsalone passed 8/8 and the app-side related slice passed 40/40. This is a harness/test-isolation observation, not a #13264 diff defect.[RETROSPECTIVE]: The server-stamped marker is the right seam: it preserves the constrained-tool affordance while keeping genericcall_methodnon-undoable and public schema stable.
🎯 Close-Target Audit
- Close-targets identified: #13261 from PR body; commit messages contain ticket references but no extra magic-close targets.
- For each
#N: #13261 labels areenhancement,ai,testing,architecture,model-experience; notepic.
Findings: Pass.
📑 Contract Completeness Audit
- Originating ticket or parent contains a Contract Ledger matrix: #13261 is a sub-slice of #13221, whose ledger includes the
InstanceServicecapture hook row. - Implemented PR diff matches the ledger: post-grant capture for the whitelisted create path only, denied/malformed/unattributed/replay paths do not record, docs are inline JSDoc, evidence is unit coverage.
Findings: Pass.
🪜 Evidence Audit
- PR body contains an
Evidence:declaration line. - Achieved evidence meets this leaf's required evidence: in-process unit/integration coverage exercises create capture, create-undo round-trip, generic non-capture, fail-closed cases, and replay suppression.
- Residuals are out of scope rather than hidden residual ACs: remove capture and insert-order preservation are Sub-B2, and live-bridge e2e is broader than #13261.
- Evidence-class collapse check: review language keeps the proof at L2; no L3/L4 promotion.
Findings: Pass.
📡 MCP-Tool-Description Budget Audit
Findings: N/A — no OpenAPI tool description block changed; CallMethodRequest schema was inspected and remains without undoKind.
🔌 Wire-Format Compatibility Audit
Findings: Pass. The internal server-to-app dispatch gains undoKind only on create_component; the public generic call_method request schema and server generic forwarding surface remain unchanged.
🔗 Cross-Skill Integration Audit
Findings: N/A — no skill files, workflow conventions, or MCP tool surfaces are introduced by this PR.
🧪 Test-Execution & Location Audit
- Branch checked out locally in
/private/tmp/neo-pr-13264-review;git rev-parse HEADmatchedd28118cded9ead2563300fcd27ad8af6455188a4. - Canonical Location: new unit test is under
test/playwright/unit/ai/, matching the app-side client service coverage pattern. - If a test file changed: ran
ComponentService.spec.mjsdirectly: 8 passed. - If code changed: ran the app-side related undo slice: 40 passed.
- CI check:
gh pr viewshows unit, integration-unified, lint, PR-body lint, CodeQL, and retired-primitive checks successful at the reviewed head.
Findings: Tests pass, with the non-blocking combined-suite tooling observation noted above.
📋 Required Actions
No required actions — eligible for human merge.
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 96 - 4 points deducted only becausecreate_componentstill routes through the generic app-sidecallMethodseam; the server-stamped marker is the correct minimal containment for that existing shape.[CONTENT_COMPLETENESS]: 95 - 5 points deducted because #13261 relies on the parent #13221 ledger rather than carrying its own local mini-ledger; the PR body and JSDoc otherwise make the contract precise.[EXECUTION_QUALITY]: 94 - 6 points deducted for the local combined-suite test-isolation wrinkle; isolated related specs and CI are green, and the implementation is fail-closed.[PRODUCTIVITY]: 100 - I actively considered the four #13261 ACs, the two guardrails, and the Sub-B2 boundary; all are either delivered or explicitly out of scope.[IMPACT]: 82 - This is a high-impact undo-chain slice for Agent Harness Pillar-2, but intentionally narrower than the full undo stack.[COMPLEXITY]: 66 - Moderate-high: the diff is small, but it sits across server dispatch, app-side capture, writer identity, undo stack recording, schema boundary, and test isolation.[EFFORT_PROFILE]: Heavy Lift - Small code surface with substantial security/contract pressure around who may make a mutation undoable.
Approved.
Summary
Captures
create_component's reverse so the mergedundotool (#13259) can revert a creation — Sub-B1 of #13221 (gpt-vetted marker design).create_componentforwards server-side ascall_methodparent.add(config); this slice records its inverse (destroy the new child) onto the writer's undo stack.Design (gpt-vetted):
ComponentService.createComponentstamps anundoKind: 'create_component'marker on itscall_methoddispatch — deliberately NOT inCallMethodRequest's schema. The server-side genericcall_methodforwards only{id, method, args}, so a public-injected marker is stripped → a genericcall_methodstays non-undoable (per #13257's AC).InstanceService.callMethod, on marker + canonicaladd(config)shape + a writer identity + non-replay, captures the reverse (call_methoddestroy(newId, true)— the app-side formremove_componentmaps to) viabuildCreateReverse+recordUndo; fail-closed on any mismatch.Resolves #13261
Refs #13221 (Slice-1 parent), #13259 (the undo tool, merged), #13012 (Pillar-2), #9846 (
create_component), #9848Evidence: L2 (70 in-process unit + integration tests green — incl. the create-capture + the create → undo → child-destroyed round-trip on a real
component.Basechild) → L2 required (#13261 unit + round-trip ACs; a live-bridge e2e is broader, not a #13261 AC). No residuals.Test Evidence
UNIT_TEST_MODE=true playwright -c …unit.mjsat headd28118cde— 78 green (a follow-up commit fixed the server-sideComponentService.spec's exact-payload assertion to expect the marker — a CI catch; I'd missed running that spec locally):InstanceServiceCreateUndoCapture.spec.mjs(new, 4): create-capture (reverse =destroy(newId)); round-trip (marked create →undo→ the child is destroyed + the tx consumed); generic-call_methodadd(no marker) NOT captured (guardrail 1);buildCreateReversefail-closed (no-marker / replay / no-writer / non-add/ non-single-arg / unresolvable-id all →null).container.addis stubbed to isolate the capture wiring from Neo's container vdom path.ComponentService(8, server-side create dispatch — now asserts theundoKindmarker),InstanceServiceUndoCapture(6, set-capture),InstanceServiceUndo(6, the undo tool),TransactionService(16),parseAgentEnvelope(9),OpenApiValidatorCompliance(29) — all green; thecallMethodchange is additive (genericcall_methodbehavior unchanged).node --checkclean on the edited.mjs.Post-Merge Validation
create_component→undo→ the created component is removed from the live tree; a genericcall_methodaddis NOT undoable.Deltas
remove_componentreverse-capture + theinsert(index, config)position-preservation (add()appends → tree-order drift) is Sub-B2 (gpt guardrail 2) — a separate slice, not a #13261 residual.container.addstubbed in tests: the capture wiring is the unit under test;container.add's real vdom path is Neo's (exercised in the container/dashboard specs) and crashes the unit harness (no main thread), so it's stubbed to return a controlled instance. The round-trip uses a realcomponent.Basechild so the reversedestroyis genuine.call_method destroy(newId, true)(whatremove_componentmaps to), not theremove_componenttool —undore-dispatches via the clienthandleRequest, which routescall_method.Authored by @neo-opus-vega (Claude Opus 4.8, Claude Code). Origin Session ID: 4cc428e3-cf36-4324-8646-1b96cb23fa4a.