feat(contracts): carry problem detail through edit, graph, diagnostics - #2289
Conversation
The source-edit and graph-tool client adapters flattened a daemon problem into a project-route error before MCP or CLI output, so a missed writer lock deadline reached clients as a sentence without its typed detail, retry directive, or legal actions. Source-edit refusals and detailed graph-tool refusals now render the whole record through the one application result renderer, which moved into tracedecay-mcp. The graph-tool owner maps a lock deadline to its typed detail. The TypeScript diagnostics producers wrote the unowned file, the searched tsconfigs, and the pending producer into message text. They now build diagnostics_unsupported and diagnostics_pending details through ApplicationProblem::from_detail; unsupported problems may carry detail. The adoption census test lists the graph lookup capabilities the retrieval family composes.
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 20dd81a8da
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| || deadline.saturating_duration_since(Instant::now()) <= OWNER_MOUNT_RESEND_DELAY | ||
| { | ||
| break outcome?; | ||
| .await?; |
There was a problem hiding this comment.
Restore cold-start retries for CLI graph tools
The new .await? propagates code-only graph refusals before this loop can inspect them. execute_graph_tool_surface still returns no-detail problems as an outer Err, and ApplicationProblem::runtime_mounting() has no detail, so a tracedecay tool graph command issued while a cold project is mounting now exits immediately instead of sleeping and retrying as the surrounding comment and previous implementation promise. Handle the outer mounting error in the loop or preserve it as an inner refusal.
AGENTS.md reference: AGENTS.md:L209-L212
Useful? React with 👍 / 👎.
Follow-ups to #2259.
What was wrong
tracedecay_mcp::handlers::edit::render_source_edit_outcomeand the graph-tool client path turned the daemon'sApplicationProblemRecordintoTraceDecayError::ProjectRoute { reason_code, retryable, detail: String }. MCP andtracedecay tooltherefore saw a JSON-RPC project-route error: nostructuredContent.problem, nolegal_actions, and nodetail. A missed source-edit writer lock deadline (lock_deadline) reached clients only as a sentence. The graph-tool owner also mappedTraceDecayError::LockDeadlineto a genericgraph_tool.failed.affected,ast-grep-search,branch-*,by-qualified-name,changelog,commit-context,config,derives,diff-context,files,find-exact-symbol,grep,pr-context,retrieve,signature). They are real, callable primitive-namespace capabilities, so the production side is right and the test list was stale.no tsconfig owns X (searched ...)andThe TypeScript producer (...) has not published ... yetwere formatted intoSafeDiagnostic.message.What changed
render_application_result) moved from the root crate intotracedecay-mcp(application_output::tool_result). A newApplicationRefusal { operation, binding_id, problem }keeps the daemon's whole problem envelope.run_source_editreturnsErr(ApplicationRefusal)andrender_source_edit_outcomerenders it. Every source-edit refusal is now a semantic tool error carrying the record:problembeside the text, which MCP publishes asstructuredContent.problemand--jsonprints. The CLI's mounting resend readsproblem.owner_mount_resend_delay().detailrenders whole. A code-only refusal stays the handler's argument or project-route error. Those problems are the owner's own flattening of handler errors (graph_tool_error_problem), with no kind or action of their own.graph_tool_error_problemnow mapsLockDeadlinethroughApplicationProblemDetailV1::from_lock_deadline.ApplicationProblem::from_detail:diagnostics_unsupported { file, searched: [{path, present}] }: unsupported, never retried,correct_request.Unsupportedproblems may now carrydetail, in the record decoder, the wire, and the TS SDK.diagnostics_pending { producer, generation }: unavailable,after_delay,retry.generationis the last generation the producer published, or null.Diagnostics file,Searched tsconfigs,Diagnostics producer,Last published generation.no_tsconfig_problemand the pending arm ofunpublished_diagnostics_problem. The producer path is now forward-slashed.detailonunsupported. It also validatesreset_requireddetail: feat(contracts): carry the reset-required store as typed problem detail #2283 added that kind to Rust but not to the SDK, which refused it as malformed.dashboard/src/contracts, the schema bundle, and SDKtypes.ts.contracts:checkis green.Fail before / pass after
tracedecay-mcp handlers::edit::tests(reverting onlyrender_source_edit_outcometo the flattening): 6 refusal tests fail witha refused source edit renders as a tool result: ... project route error (...). They pass with the fix. The newa_missed_writer_lock_deadline_reaches_mcp_as_its_typed_detailassertsdetail == {kind: lock_deadline, resource: "source-edit writer lock", deadline_ms: 30000},saturated, and["retry"].mcp_suite str_replace_behavior_test::str_replace_behind_a_held_writer_lock_reports_the_lock_deadline_detailholds the realsource-edit-transactions-v1/source-edit.lockwith an flock, then callstracedecay_str_replaceover MCP. It assertsstructuredContent.problem=saturated/application.lock-deadline/after_delay/["retry"]/detail.kind == "lock_deadline". On master the same call is a JSON-RPC error, soresultis null.daemon-service adoption_observation::tests::census_counts_each_composed_family_and_omits_uncomposed_families: on master it fails withcomposed but not listed: [("retrieval", "capability.application.primitive.affected", ...), ...], and passes here.mcp_suite diagnostics_read_test::diagnostics_read_names_a_missing_producer_and_rejects_a_bad_scopepins the full problem record includingdetail. On master,detailisnull.typescript_file_no_tsconfig_owns_names_the_searched_pathsasserts{kind: diagnostics_unsupported, file: "scripts/release.ts", searched: [{scripts/tsconfig.json,false},{tsconfig.json,false}]}.typescript_producer_still_running_is_pending_with_typed_detailuses a held fixture compiler (newTypeScriptFixtureCompiler::Held) and asserts{kind: diagnostics_pending, producer: "node_modules/.bin/tsc", generation: null}.--json:core_cli_suite tool_diagnostics_json_carries_the_unowned_scope_detailandtool_diagnostics_json_carries_the_pending_producer_detail.client.ts:surfaces the diagnostics detail an unsupported problem carriesandsurfaces the reset-required store detailfail (malformed response), and pass here.Runtime journey (debug CLI from this branch)
Isolated
HOME/TRACEDECAY_DATA_DIR, one daemon undersystemd-run --user --scope -p MemoryMax=6G -p MemorySwapMax=1G.Local verification
tracedecay-contracts420 andcontracts_suite277tracedecay-mcp391tracedecay-daemon-service321tracedecay-source-edit88tracedecay-application: 466 passed, 11 failed. All 11 also fail on master since perf(graph-db): store each code edge as one relation row #2277 (code graph row file-record has the wrong type), filed as test(application): symbol-graph lib tests red after single-row code edges (#2277) #2279. They passed on this change before the rebase over perf(graph-db): store each code edge as one relation row #2277.tracedecaylibmcp::tools::handlers::: 77mcp_suite(full, before the perf(graph-db): store each code edge as one relation row #2277 rebase): 576/576. After rebasing over perf(graph-db): store each code edge as one relation row #2277, 572 passed. The 5 failures are read-cost pins that perf(graph-db): store each code edge as one relation row #2277 moved (test(application): symbol-graph lib tests red after single-row code edges (#2277) #2279, comment). After rebasing over feat(contracts): carry the reset-required store as typed problem detail #2283 and refactor(mcp): answer retrieve through the owner #2284, the source-edit, diagnostics, graph-refusal, str_replace, and retrieve subsets passed: 153 + 46 tests.core_cli_suite: 144/144.tool_subset 53/53 after the last rebases. Five tests failed under load or with the host-CLI example not built, and all passed on an isolated rerun.typecheck. Dashboard: vitest 210 files / 2028 tests,typecheck,contracts:check.cargo clippy --all-targets -D warningsis clean on contracts, application, mcp, daemon-service, tracedecay, cli, and sdk, both with and withouttest-transport/test-helpers.cargo fmt --all -- --checkis clean.Left open
ProjectRouteare a separate surface, split to fix(mcp): code-index corruption refusals format park facts into a route detail #2280.lock_deadline) render whole on graph tools.Fixes #2255
Fixes #2246