Task 3: four registry-wide structural tests in tools.rs, iterating registry()
so a future tool that crosses the D-09 ceiling fails CI rather than depending
on a reviewer noticing:
- registry_never_exposes_excluded_authority (S-04/T-13-24): scans every
ToolDef's name+description for EXCLUDED_AUTHORITY_TERMS.
- read_tools_never_confirm (S-07/T-13-31): every non-destructive tool
executes via the real execute_tool choke point without raising anything
confirmation-shaped. bitcoin_status/network_status excluded from live
execution (their handlers make real outbound network calls that would
make this test flaky on a sandboxed box); their destructive:false
placement is still covered by the other assertions.
- loop_is_bounded (S-13/D-05): MAX_TURNS is enforced, and 3 consecutive
malformed-argument calls for the same tool name abort the turn with an
apology before a 4th scripted backend turn is ever polled.
- every_tool_has_explicit_category_and_destructive: sanity-checks the
registry has exactly the 13 hand-written tools (4 destructive) that made
it in, as a runtime backstop to the acceptance criteria's static grep for
`..Default::default()`.
Negative-case demonstration (per the plan's acceptance criteria): a
hypothetical `wallet_send_sats` tool with a description mentioning
"spending sats" trips EXCLUDED_AUTHORITY_TERMS's "spend" term, verified by
tracing the exact haystack-contains logic registry_never_exposes_excluded_authority
runs (see 13-05-SUMMARY.md for why this was traced rather than executed).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>