feat(act): defer-* plan kinds for native deferral config (part 2 of #614)#631
Conversation
Add three read-only detectors for MCP tool-def deferral coverage gaps: - mcp-deferral-off: sessions carrying MCP tool-def overhead with zero ToolSearch invocations and no deferred_tools_delta inventory across the window. Cause attribution, each with its own message and fix: stale ENABLE_TOOL_SEARCH=false (settings env, any scope, or shell profile), non-first-party ANTHROPIC_BASE_URL (reported as unknown proxy — never assumes capability), Vertex AI config, all observed Claude Code versions predating default-on tool search (v2.1.7), or a generic deferral-appears-inactive fallback. - mcp-alwaysload-hygiene: alwaysLoad-pinned servers whose observed call rate is below 1 call per 5 sessions (named constant). Notes the 5s startup-blocking cost of alwaysLoad in the explanation. - mcp-defer-threshold: ENABLE_TOOL_SEARCH=auto/auto:N overrides whose threshold the estimated def volume never reaches, so tools load upfront; recommends the tightest auto:N that would defer. Detection only: no FindingApply payloads, no act-layer changes, no file mutation. Users without deferral gaps see zero new output — deferral-active evidence (ToolSearch calls or inventory) suppresses the findings, and each detector gates on conservative named thresholds. Config readers take an injectable homeDir (PlanContext style) for hermetic tests. Discrepancies vs the design notes, codebase/live-docs win: - The Claude Code changelog records default-on (2.1.7), not first ship, so the version cause uses the default-on boundary. - Per-tool "anthropic/alwaysLoad" lives in server-served tool _meta, not static config; server-level only, limitation documented. - Live docs confirm auto default threshold 10% of context window and the alwaysLoad v2.1.121+ requirement. Refs getagentseal#614
Wire the mcp-deferral-gaps findings to the act machinery with three new plan kinds, all through the existing ConfigDocs/runAction path (journaled, backed up, stale-guarded, dry-run previewable, undo restores byte-identical files): - defer-enable: removes a stale ENABLE_TOOL_SEARCH=false from the settings env of the scope where the finding recorded it. Refusal paths render as manual notes instead of plans: shell-profile lines (codeburn only appends marker blocks to shell files, never edits user lines), unknown proxies (setting the override blind makes requests fail outright on proxies that don't forward tool_reference blocks — the note says to verify first), Vertex, and old versions. A proxy-verified cause (set by the part-3 verifier) produces a real ENABLE_TOOL_SEARCH=true plan in user settings. - defer-alwaysload: strips alwaysLoad: true from the named servers in the exact config files the finding recorded. Gated on an injectable installed-version probe (default: claude --version); below v2.1.121, unparseable, or probe failure all refuse with a note naming the required version. Preview notes the removed up-to-5s startup block. - defer-threshold: rewrites the auto override to the recommended auto:N, or deletes it when the finding says the default already defers (removeOverride). Findings now carry FindingApply payloads (path, scope, cause, servers, recommended N); detector text is unchanged, so plain optimize renders byte-identically to before. Every plan links its findingId into the ActionRecord and states that changes take effect on the next session (the config is read at Claude Code start). Discrepancy vs the design notes: no existing version-check helper was found in guard/ or act/ to reuse, so the detector's parseVersion/ versionPredates are exported and shared instead of adding a parallel comparator. Refs getagentseal#614
ced70ce to
2d20ba1
Compare
iamtoruk
left a comment
There was a problem hiding this comment.
Cleared for 0.9.16 after deep verification. The one open question from the earlier review round, whether the detector false-positives on setups with deferral correctly on but low MCP usage, is settled empirically: across 120 real sessions on a deferral-active machine, the deferred-tool inventory is emitted at session start (typically line 3) regardless of usage, including 28 sessions that never called ToolSearch, and every session lacking the signal had zero MCP involvement. Negative control on a live deferral-on setup produces no finding; a synthetic gap fires with honest cause text. All three plan kinds were live-fired in a fully isolated home: each edit was surgical (sibling keys and file bytes preserved around the change), and act undo restored both configs byte-identical to their originals. Merged cleanly with current main (pushed to this branch), tsc clean, suite green apart from the known #681 items, and disabling the detector kills 19 of the 51 dedicated tests. The reserved proxy-verified path stays: it is documented, test-covered, and part 3 is an accepted upcoming track. Thanks for following the design-issue flow exactly and for the strongest first contribution this repo has had.
Implements part 2 (restore/tune native deferral) of #614.
Wires the
mcp-deferral-gapsfindings to the existingactmachinery with three new plan kinds, all throughConfigDocs/runAction(journaled, backed up, stale-guarded, dry-run previewable,act undorestores byte-identical):defer-enable— removes a staleENABLE_TOOL_SEARCH=falsefrom the settings env of the recorded scope. Refusal paths render as manual notes instead of plans: shell-profile lines (codeburn only appends marker blocks to shell files, never edits user lines), unknown proxies (setting the override blind makes requests fail on proxies that don't forwardtool_reference— the note says verify first), Vertex, old versions.defer-alwaysload— stripsalwaysLoad: truefrom named servers in the exact config files the finding recorded. Version-gated to Claude Code v2.1.121+ (below it / unparseable / probe failure all refuse). Preview notes the 5s startup block removed.defer-threshold— rewrites theautooverride to the recommendedauto:N, or deletes it when the default already defers.Findings now carry
FindingApplypayloads; detector text is unchanged, so plainoptimizerenders byte-identically. Every plan links its finding id into theActionRecordand states the change takes effect on the next session. 22 new tests (byte-identical apply/undo on odd-key-order JSON, unknown-proxy refusal, version gate, shell-profile refusal, drift guard).Refs #614