fix(mcp): non-mutating query-only store resolve; annotate the ten read-only tools - #1871
Conversation
|
Thanks for opening this — it has been seen, and it is queued. This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence. Current review status: working through a backlog. What that means for this PR, concretely:
Things that will genuinely speed it up whenever review does happen:
If this fixes a bug, a reproduction we can run is worth more than a description of the symptom. Thanks for contributing, and sorry in advance for the wait. |
|
Thank you for grounding the MCP read-only annotations in an actually non-mutating corrupt-store path rather than only changing the hints. This touches both client safety metadata and store-recovery semantics, so we need more time to review the boundary carefully. The contribution queue is quite full, but we will come back with grounded feedback as soon as possible. |
|
Approved. The important thing here is what you did not do: flip the booleans. The annotations were conservative for a real reason — The split is clean and I checked both sides. And the query path is structurally read-only, not merely disciplined. On a failed integrity check it closes the store and reopens through Reporting the corruption honestly is the other half of the fix. "project store is corrupt (left untouched); run index_repository to rebuild it" is a far better answer than "project not found", which sent people looking for a configuration problem that did not exist. Keeping TRANSIENT retryable-busy preserves the distinction that matters. Your tests target the right property. Asserting One thing worth stating plainly rather than leaving implied: this closes the mutation the prior comment identified, and your lease assertion guards the lease path — but neither independently re-proves the ten tools are read-only in every other respect. That was already the codebase's position before this PR, so it is not a regression and I am not asking you to prove it. Just worth having said, since Please rebase — this touches Noting there was no issue for this and offering to adjust direction was the right way to raise it. There is now: the annotations were wrong, and this makes them right. |
4772f47 to
2283bcb
Compare
…d-only tools search_graph, query_graph, trace_path, get_code_snippet, get_graph_schema, get_architecture, search_code, index_status, check_index_coverage and detect_changes were annotated readOnlyHint=false / destructiveHint=true because resolve_store()'s corrupt-store recovery quarantines database files - a mutation. That conservatism locked every plan-mode client out of the read-only analysis surface (DeusData#1100 calls the same tools "eleven read-only analysis tools"), since spec-compliant plan gates refuse tools that are not declared read-only. This closes the gap the annotation comment pointed at. The query-only resolve now classifies a failed integrity check without mutating: no mutation lease, no quarantine. A confirmed-corrupt database is reported (a new STORE_RECOVERY_CORRUPT status; the tool reply names the corruption and points at index_repository instead of a misleading "project not found") and left in place for a write-side open to quarantine and rebuild, exactly as before. Transient verdicts stay retryable. Write-side opens (index_repository, manage_adr updates) keep the existing blocking recovery, quarantine, and generation re-check semantics unchanged. The ten query tools' annotations flip to readOnlyHint=true / destructiveHint=false, making them callable under plan mode in Claude Code, Codex, ZCode, and every other client that gates on the hints. Tests: the annotations expectation table is flipped; the query branch of the guard-balance and guard-denial tests now assert zero leases taken and byte-identical files; the ghost-db test (DeusData#704) expects the corruption message; the four write-side recovery tests (generation re-check after lease wait, unique backup naming, publish failure, published-WAL completeness) are driven through manage_adr update - the write path where that recovery now lives. Signed-off-by: 周文瑄 <zhouwx1997@126.com>
…nges The CI lint gate flagged 18 clang-format violations in the lines the previous commit touched (the read-only verdict branch inside resolve_store_internal, the REQUIRE_STORE macro, and the two call sites that switched to build_no_store_error_checked). No semantic change: whitespace and line wrapping only; the mcp suite still passes 202/0/7. Signed-off-by: 周文瑄 <zhouwx1997@126.com>
The local clang-format 15 that produced the previous commit removes the space in 'char (*mods)[CBM_SZ_128]' (pointer-to-array declaration), while the CI formatter keeps it; 15 also rewrote those two pre-existing detect_changes lines even though they were untouched by this PR. Restore the upstream spelling so the CI format gate passes and the PR diff no longer touches lines it has no reason to touch. Signed-off-by: 周文瑄 <zhouwx1997@126.com>
CI's tsan and lsan-macos runs failed the mutation-guard suite on ASSERT(cbm_file_exists(db_path)) at the guard-balance test, while the behavior suite passed everywhere. The assertion ran after the test's own teardown: cleanup_project_db() unlinks the same db path before the assertion block, and the manage_adr branch above replants and quarantines that very path, so the late file check observed the test's cleanup, not the query-only resolve it was meant to pin. Whether it tripped depended on unlink/visibility timing, which is why it surfaced only under some schedulers and never in the single-suite local runs. Capture cbm_file_exists() into query_db_left_in_place right after the query branch completes, before anything replants or removes the file, and assert on that snapshot. Signed-off-by: 周文瑄 <zhouwx1997@126.com>
2283bcb to
adb49b3
Compare
|
Merged as The reason this landed instead of a one-line annotation flip: Your last commit deserves specific credit. The mutation-guard suite was failing on tsan and lsan-macos while the behaviour suite passed everywhere, and the diagnosis was right — the assertion ran after the test's own teardown had unlinked the path, so Two smaller things worth noting for anyone reading this later: the tests assert The residual I raised earlier stands as a note and not a defect: this closes the mutation that was identified and the lease assertion guards the lease path, but neither independently re-proves the ten tools are read-only in every other respect. That was already the codebase's position before this PR, so it is not a regression introduced here. Thanks also for the rebase — |
Problem
The ten pure query tools (search_graph, query_graph, trace_path,
get_code_snippet, get_graph_schema, get_architecture, search_code,
index_status, check_index_coverage, detect_changes) are annotated
readOnlyHint=false / destructiveHint=true. Plan-mode clients (ClaudeCode, Codex, ZCode, ...) gate tool availability on these hints, so the
entire read-only analysis surface is unavailable while planning.
The annotations were deliberately conservative (see the previous test
comment):
resolve_store()'s corrupt-store recovery quarantines databasefiles - a filesystem mutation reachable from a "query".
Fix
This closes the gap that comment pointed at, rather than flipping the
booleans blindly:
resolve_store_internal()gains anallow_autorecoveryflag. Thequery-only path (
resolve_store()) passesfalse: a failed integritycheck is classified read-only (no mutation lease, no quarantine). A
confirmed CORRUPT database is reported - the tool reply now says
"project store is corrupt (left untouched); run index_repository to
rebuild it" instead of a misleading "project not found" - and left in
place. TRANSIENT verdicts stay retryable-busy, as before.
existing blocking recovery, quarantine, and post-lease generation
re-check semantics byte-for-byte.
readOnlyHint=true / destructiveHint=false,which is now honest, so plan-mode clients can expose them.
Tests
tool_corrupt_store_cleanup_guard_is_balanced_and_not_nested: thequery branch now asserts no lease is taken, the corrupt DB stays in
place, and the reply names the corruption. The manage_adr branch is
unchanged.
tool_corrupt_store_cleanup_guard_denial_preserves_db_and_wal: thequery path requests no lease at all (begin_count 0).
wait, unique backup naming, publish failure, published-WAL snapshot
completeness) are driven through
manage_adrupdate - the write pathwhere that recovery lives.
Local Windows verification: mcp suite 202 passed / 0 failed / 7 skipped
(POSIX-only skips). No issue exists for this yet as far as I could find -
happy to adjust if there is a preferred direction.