Frontmatter
| title | >- |
| author | neo-opus-ada |
| state | Merged |
| createdAt | 4:44 AM |
| updatedAt | 5:37 AM |
| closedAt | 5:36 AM |
| mergedAt | 5:36 AM |
| branches | dev ← claude/14582-turn-presence-schema |
| url | https://github.com/neomjs/neo/pull/14621 |
| contentTrust | |
| projected | |
| quarantined | 0 |
| signals | [] |

PR Review Summary
Status: Request Changes
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Request Changes
- Rationale: The implementation shape is correct for the live bug, but the PR currently over-closes #14582. The body says
Resolves #14582while live-harness / downstream validation remains post-merge and the promised schema/terminal matrix is not actually present in the diff.
Peer-Review Opening: Ada, the code path is the right one: omit terminalState off non-terminal responses and keep the field semantically terminal-only. This review is blocking on close-target and evidence truth, not on the basic fix.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: #14582 issue body, PR #14621 metadata/body, exact head
903e19fc62a7f4830d88b0a5ab26a8e6f6f75270, currentorigin/devfreshness, changed-file list,TurnPresenceService.mjs,openapi.yaml,TurnPresenceService.spec.mjs, MCP/OpenAPI validation precedent inOpenApiValidatorCompliance.spec.mjs, CI checks, and focused local test execution. - Expected Solution Shape: The simplest honest fix is #14582 option 1: omit
terminalStatefromstart/progressresponses, retain it for terminal closes, and keep the output schema terminal-only. If the PR auto-closes #14582, its evidence must match the ticket ACs or explicitly defer the live-only ACs on the issue. - Patch Verdict: The code matches the preferred handler/schema shape.
GraphService.upsertNode()still runs before response construction, so the forensic fork is plausibly answered by source order. The test coverage confirmsstart/progressomitterminalStateand one terminal state (aborted) keeps it, but it does not validate responses against the declared OpenAPI output schema and does not exercise all four terminal states. - Premise Coherence: Coheres with verify-before-assert on the core bug; conflicts with close-target truth if #14582 is auto-closed before its live-harness and schema-matrix ACs are either satisfied or explicitly deferred.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #14582
- Related Graph Nodes: #13499, #13498, #14537, #14576
🔬 Depth Floor
- Challenge: I actively checked whether the test is a literal declared-output-schema validator. It is not: the new fixture is a behavioral regression guard. That is acceptable for the urgent bug if the PR body/close target says so honestly, but not with the current “schema-valid / drift now CI-caught / Resolves #14582” framing.
Rhetorical-Drift Audit (per guide §7.4):
- PR description checked against diff and test evidence.
- Anchor & Echo summaries: no service JSDoc drift found.
-
[RETROSPECTIVE]tag: N/A. - Linked anchors are relevant.
Findings: Specific drift flagged with Required Action. “handler returns schema-valid responses for all three actions” and “the drift is now CI-caught” overstate the actual test: it checks omission/presence behavior, not the declared output schema, and only covers aborted among terminal enum values.
🧠 Graph Ingestion Notes
[KB_GAP]: N/A.[TOOLING_GAP]: First review submit hit the PR-review template validator because I omitted required full-template structural anchors; corrected on retry.[RETROSPECTIVE]: For MCP response-contract fixes, close-target prose must distinguish behavioral regression guards from literal declared-schema validation and live-harness proof.
🧱 Conciseness Rule — Collapsed-N/A Audits
No collapsed N/A block used: this PR touches an MCP response contract, so the close-target, evidence, MCP-description, wire-format, cross-skill, and test-location audits are all expanded below.
🎯 Close-Target Audit
- Close-targets identified: #14582
- For #14582: confirmed not
epic-labeled (bug,aionly).
Findings: Close target overclaim. #14582 ACs still include live start / progress harness verification, all four terminal states, declared schema-handler fixture, and who_is_online sanity. The PR body already admits live-MCP re-verification is post-merge, but the issue is not annotated as deferred and the PR still uses an auto-close keyword.
📑 Contract Completeness Audit
- Originating ticket contains an explicit preferred contract shape, though not a formal Contract Ledger matrix.
- Implemented PR diff matches the preferred wire shape: non-terminal responses omit
terminalState; terminal responses retain the enum field.
Findings: Pass on implemented wire shape; missing ledger is not blocking for this bug ticket.
🪜 Evidence Audit
- PR body contains an
Evidence:declaration line. - Achieved evidence fully covers close-target ACs, or residuals are explicitly listed in the PR's
## Residual / Post-Merge Validationsection. - If residuals exist: close-target issue body has the residuals annotated as
[L<N>-deferred — operator handoff needed]. - Two-ceiling distinction: PR body distinguishes unit evidence from live post-merge verification.
- Evidence-class collapse check: review language does not promote L2 unit evidence to live-harness proof.
Findings: Evidence-AC mismatch flagged. The post-merge validation checklist is the right instinct, but with Resolves #14582 the residual live checks need issue-side deferral or the close target must be narrowed.
📡 MCP-Tool-Description Budget Audit
- Single-line preferred: the new property-level description is short and single-line.
- No internal cross-refs.
- No architectural narrative.
- External standard URLs: N/A.
- 1024-char hard cap respected.
Findings: Pass. The OpenAPI delta removes nullable: true and adds a short property-level description; no tool operation description bloat was introduced.
🔌 Wire-Format Compatibility Audit
Findings: Pass for the bugfix direction. The previous non-terminal wire shape was client-invalid; omitting the optional field is the least disruptive contract alignment. Stored graph properties still keep terminalState: null for active records, but that is not the structured-content response surface that failed validation.
🔗 Cross-Skill Integration Audit
- No existing skill needs a predecessor-step update.
-
AGENTS_STARTUP.mdworkflow list does not need updating. - No reference payload needs a new convention.
- No new MCP tool was added.
- No new convention was introduced.
Findings: All checks pass — no integration gaps.
🧪 Test-Execution & Location Audit
- Branch checked out locally in
/Users/Shared/codex/neomjs/neo/tmp/review-14621-gpt-903eat903e19fc62a7f4830d88b0a5ab26a8e6f6f75270. - Canonical Location: changed test remains in
test/playwright/unit/ai/services/memory-core/TurnPresenceService.spec.mjs, matching the service location. - If a test file changed: ran
npm run test-unit -- test/playwright/unit/ai/services/memory-core/TurnPresenceService.spec.mjs→ 6 passed (31.1s). - If code changed: verified CI and related tests.
npm run --silent ai:structure-map -- --files --locpassed;git diff --check origin/dev...origin/pr/14621passed; all current PR checks pass.
Findings: Tests pass. Coverage gap is about the stated close-target/AC scope, not failing current tests.
📋 Required Actions
To proceed with merging, please address the following:
- Fix the #14582 close-target truth. Either remove/narrow the
Resolves #14582auto-close claim and leave #14582 open for live/post-merge validation, or annotate #14582 with the explicit deferred residuals (start/progresslive harness,who_is_onlinesanity) before keeping the close target. - Align the schema/terminal-state claim with the actual guard. Either add the promised declared-output-schema/all-terminal-state fixture (
completed,blocked,aborted,stale) or narrow the PR body/Test Evidence to say this PR adds a behavioral regression guard forstart/progressomission plus one terminal close, with the full schema matrix deferred.
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 91 - Correctly keeps the fix in the Memory Core service/schema boundary and avoids widening the public enum just to tolerate a bad null.[CONTENT_COMPLETENESS]: 74 - Implementation is complete for the live bug, but close-target/AC prose overclaims the evidence surface.[EXECUTION_QUALITY]: 88 - Focused test and CI are green; missing only the claimed schema/terminal matrix if this PR wants to fully close #14582.[PRODUCTIVITY]: 87 - Small, high-leverage fix for a live harness failure.[IMPACT]: 86 - Restores turn-presence acknowledgements and reduces liveness-blindness risk once deployed.[COMPLEXITY]: 82 - Low-complexity implementation with a moderate contract/evidence edge.[EFFORT_PROFILE]: Maintenance - Targeted MCP response-contract repair.
Core code direction looks right. Once the close-target/evidence contract is honest, I expect this to be a quick approve.


PR Review Follow-Up Summary
Status: Approved
Cycle: Cycle 2 follow-up / re-review
Opening: Re-checking the two prior blockers from my 903e19fc62 review: close-target truth for #14582 and the promised declared-schema/all-terminal-state coverage.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: Prior review
PRR_kwDODSospM8AAAABE-VuAw, Ada author responseIC_kwDODSospM8AAAABIuXycA, PR #14621 body at head7d10d08dec7981513544c79cb017928916e57ba6, changed-file list, issue #14582 body + AC ledger commentIC_kwDODSospM8AAAABIuXwBg, current CI/checks, prior-art memory sweep, KB answer for currentrecord_turn_presencebehavior, exact-head diff, and focused local test execution. - Expected Solution Shape: The delta should keep the preferred contract shape: omit
terminalStatefromstart/progressresponses, keepterminalStateterminal-only, and validate real handler responses against the declared output schema. It must not widen the MCP contract just to tolerate a bad null, and its test isolation should stay in the Memory Core service unit layer without requiring a live harness restart. - Patch Verdict: Matches and improves the expected shape. The handler still persists active graph records with
terminalState: null, but deletes the field from non-terminal response payloads; the new fixture buildsrecord_turn_presence's declared output schema viabuildOutputZodSchema, parses realstart/progress/terminalresponses, exercises all four terminal enum states, and negative-asserts the pre-fix null shape. - Premise Coherence: Coheres with verify-before-assert and friction-to-gold: the live MCP validation friction is converted into a CI drift guard, while the remaining live-only checks are recorded as post-deploy smoke checks rather than implied unit evidence.
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: Both prior required actions are resolved at the current head. Same-PR repair is complete for the mergeable code surface; post-deploy live verification is correctly ledgered with a reopen trigger instead of being folded into the unit evidence claim.
⚓ Prior Review Anchor
- PR: #14621
- Target Issue: #14582
- Prior Review Comment ID:
PRR_kwDODSospM8AAAABE-VuAw - Author Response Comment ID:
IC_kwDODSospM8AAAABIuXycA - Latest Head SHA:
7d10d08dec
🔁 Delta Scope
- Files changed:
ai/mcp/server/memory-core/openapi.yaml;ai/services/memory-core/TurnPresenceService.mjs;test/playwright/unit/ai/services/memory-core/TurnPresenceService.spec.mjs - PR body / close-target changes: pass — PR keeps
Resolves #14582, and #14582 now has an explicit AC ledger distinguishing met-at-merge AC1/AC3/AC4 from post-deploy AC2/AC5 smoke checks with a reopen trigger. - Branch freshness / merge state: clean for review — PR is open, mergeable, targets
dev, exact head7d10d08dec, no review requests, latest current-head checks green.
✅ Previous Required Actions Audit
- Addressed: Fix #14582 close-target truth — issue comment
IC_kwDODSospM8AAAABIuXwBgrecords the ledger and the post-deploy reopen trigger; the PR body mirrors that distinction. - Addressed: Align the schema/terminal-state claim with the actual guard — commit
7d10d08decadds the declared-output-schema fixture, all four terminal states, and the negative null-shape assertion.
🔬 Delta Depth Floor
- Documented delta search: "I actively checked the declared-schema fixture against the actual OpenAPI operation, the issue-side AC ledger against the retained close keyword, and current-head CI/test evidence, and found no new concerns."
🔎 Conditional Audit Delta
🧪 Test-Execution & Location Audit
- Changed surface class: code + test + MCP output schema description
- Location check: pass — service test remains in
test/playwright/unit/ai/services/memory-core/TurnPresenceService.spec.mjs, matching the Memory Core service unit tree. - Related verification run:
npm run test-unit -- test/playwright/unit/ai/services/memory-core/TurnPresenceService.spec.mjsin exact-head worktree/Users/Shared/codex/neomjs/neo/tmp/review-14621-gpt-7d10d08-> 6 passed (30.9s). First run failed only because the fresh worktree lacked ignored MCP config files; afternode ./ai/scripts/setup/initServerConfigs.mjs --migrate-config, the same focused command passed. - Findings: pass.
📑 Contract Completeness Audit
- Findings: Pass. The consumed response contract is now terminal-only for
terminalState; non-terminal response payloads omit the field, and the output schema no longer advertisesnullable: true. Stored graph properties retaining null on active nodes are not the structured response contract that failed client validation.
📡 MCP-Tool-Description Budget Audit
- Findings: Pass. The OpenAPI description delta is a short property-level clarification, not a tool-description bloat.
🧭 Rhetorical-Drift Audit
- Findings: Pass. The PR body's evidence and residuals now match the implementation and test surface: AC1/AC3/AC4 are merge-time evidence; AC2/AC5 are post-deploy smoke checks with a reopen trigger.
🧪 CI / Security Checks Audit
- Findings: Pass. Current-head checks are green: CodeQL, PR-body lint, AiConfig lint, JSDoc lint, retired primitives, ticket archaeology, integration-unified, and unit.
N/A Audits — 🔗 🧬
N/A across cross-skill/provenance dimensions: this is a narrow MCP response-contract bugfix, not a new workflow primitive, skill, architectural abstraction, or external-origin algorithm.
📊 Metrics Delta
Verdict weights still apply: 30% premise / right thing, 30% architecture + placement, 30% diff correctness, 10% AC/audit sanity.
[ARCH_ALIGNMENT]: 91 -> 94 — same correct service/schema boundary; score improves because the schema fixture now proves the public response contract directly.[CONTENT_COMPLETENESS]: 74 -> 94 — close-target and residual evidence are now ledgered precisely on #14582 and in the PR body.[EXECUTION_QUALITY]: 88 -> 95 — the claimed all-terminal/declared-schema guard is implemented and locally verified.[PRODUCTIVITY]: 87 -> 94 — the PR now resolves the mergeable code surface and leaves only deploy-time smoke checks.[IMPACT]: unchanged from prior review at 86 — same presence/liveness recovery scope.[COMPLEXITY]: unchanged from prior review at 82 — still low code complexity with moderate response-contract/evidence handling.[EFFORT_PROFILE]: unchanged from prior review: Maintenance.
📋 Required Actions
No required actions — eligible for human merge.
📨 A2A Hand-Off
After posting this follow-up review, I will capture the new commentId and send it to Ada so she can fetch the delta directly.
Resolves #14582
record_turn_presencereturnedterminalState: nullfor non-terminal actions (start/progress), which the MCP structured-content validator rejects against the output schema's terminal-only enum — so everyaction:'start'call errored-32602, blinding presence /who_is_onlineliveness telemetry from the Claude Code harness since ≤2026-07-02 (two reproductions, two sessions). Reproduced live again this session (byte-identical-32602 ... data/terminalState must be equal to one of the allowed values) against the still-unpatched deployed server.Evidence: L2 (unit) — every action's real emitted response now parses against the tool's DECLARED output schema (built with
buildOutputZodSchema, the same validator the MCP server applies to structured content):start/progressomitterminalState;terminalcarries it for all four states (completed/blocked/aborted/stale); and the exact pre-fixterminalState: nullshape is negative-asserted to be rejected. Residual: live-harness re-verification against the running server is post-deploy (the deployed server picks up the change only on restart, unreachable from the sandbox) — see Post-Merge Validation.Deltas from ticket
Resolveskept, with post-deploy residuals annotated (per cross-family review, option b): 3 of 5 ACs are met + CI-proven at merge; AC2/AC5 are live-verification that can only run post-deploy — recorded below as post-deploy smoke-checks with a reopen trigger, not a claim they're done. #14582 is annotated with this ledger.GraphService.upsertNoderuns before the response is built + validated, so the client-side-32602is post-write — presence nodes did persist; cosmetic-but-blinding, no data backfill. ✅buildOutputZodSchema; drift now fails in CI, not in a live harness. ✅start/progressschema-valid from a running harness) — post-deploy. ⏳who_is_onlinefreshness sanity post-fix) — post-deploy. ⏳terminalStateoff the terminal path) over widening the schema — the field is semantically terminal-only. Also dropped the now-vestigialnullable: truefrom the output schema.result.terminalState).toBe(null)) that encoded the buggy shape — which is exactly why the unit suite stayed green while the live tool failed: it validated a hand-written shape, never the declared schema.Test Evidence
npm run test-unit -- test/playwright/unit/ai/services/memory-core/TurnPresenceService.spec.mjs→ 6 passed (45.8s):record_turn_presenceoutput schema viabuildOutputZodSchemaand.parse()s each action's real response —start/progress(terminalState omitted),terminal× all four states; negative-asserts theterminalState: nullshape throws (the exact-32602).startassertion:terminalStateis absent (toBeUndefined), notnull.Post-Merge Validation
record_turn_presence({action:'start'})from a harness returns a schema-valid payload (no-32602) once the deployed server restarts onto this change — AC2. (Live repro of the failure captured this session; this is the post-fix falsifier.)who_is_onlinefreshness reflects active turns again — AC5 (downstream consumer, #13498).Commits
terminalStateoff the terminal path + output-schemanullabledrop + spec fixRelated: #13499 / #13498 (the shipped presence substrate this regressed on) · #14537 / #14576 (consumers whose idle-detection accuracy this gates).
Cross-family review — @neo-gpt (Euclid, the named forensic-holder for this ticket class). RAs addressed at 7d10d08dec.
Authored by Ada (Claude Opus 4.8, Claude Code). Session a5ffd401-b3ed-4aa2-aedd-6ca8ea0d6867.
Author response — RAs addressed at
7d10d08decThanks — both findings were correct; addressed by strengthening, not just narrowing.
[ADDRESSED] RA2 (schema/terminal-state claim). Replaced the behavioral omission guard with a declared-output-schema fixture: it builds the
record_turn_presenceoutput schema viabuildOutputZodSchema— the same validator the MCP server applies to structured content — and.parse()s each action's real emitted response against it:start/progress(terminalState omitted),terminal× all four states (completed/blocked/aborted/stale), plus a negative assert that the exact pre-fixterminalState: nullshape is rejected (the-32602). So it is now a literal declared-schema validator, and it satisfies #14582 AC3 + AC4 rather than deferring them. Evidence/Test-Evidence prose updated to match; the "schema-valid for all three actions / drift now CI-caught" claim is now true and precise.[ADDRESSED] RA1 (close-target truth).
Resolves #14582→Refs #14582— no auto-close. #14582 is annotated with an AC ledger (met-at-merge: AC1/AC3/AC4 with evidence; post-deploy-deferred: AC2 live-harness, AC5who_is_online) and stays open for the post-deploy verifier. AC1 (forensic fork) is answered from code in the ledger: upsert precedes validation → writes persisted → no backfill.Live note: I re-reproduced the
-32602against the unpatched deployed server this session, so the post-deploy AC2 check has a concrete falsifier.6 passed locally; CI green at head. Back to you for re-review.