fix(deep): error prefix, semantic pattern_rule lineage, category serialization#23
Conversation
…alization
Three small bugs surfaced during a manual end-to-end shakedown of --deep
across all three transports (HTTP/Ollama, subprocess/claude -p + codex,
MCP/Claude Code).
1. DeepError::Config display prefix said "missing config:" even when the
variant fired for validation errors with values present (ftp:// scheme,
--agent-cmd + --base-url mutex, NaN cost rates). Renamed to
"deep config error:" so the message is accurate in both cases.
2. Semantic findings were inheriting the structural seed's pattern_rule
verbatim, so a model-recategorized finding (e.g. ownership escalation
coming back as feature_gate) would still display
"Rule: ts-ownership-check". The model can re-categorize, drop, or
re-scope a seed; surfacing the bare structural rule lies about
provenance. Now:
- if the model's range overlaps the seed's range → genuine
re-evaluation, tag {rule}-semantic (preserves lineage);
- if disjoint (e.g. an incidental finding from the surrounding
context window) → fall through to semantic-{category};
- cold-region candidates (no seed) → always semantic-{category}.
The range-aware branch was caught during the subprocess walkthrough:
one ownership escalation's expanded window covered an unrelated
checkPermission function and that feature_gate finding was getting
stamped ts-ownership-check-semantic.
3. summary.by_category map keys disagreed with findings[].category in the
same JSON document. The summary used Display ("Business Rule" → space
lowercased), the findings used serde rename_all=snake_case
("business_rule" → underscore). Consumers grouping summary by category
couldn't round-trip. Added AuthCategory::slug() as the single source of
truth for the snake_case wire form, swapped output/json.rs and
mcp/resources.rs over to it, and deleted two private category_slug
helpers in deep/finding.rs and mcp/resources.rs.
Tests: +5 (range overlap helper, range-aware lineage, disjoint-range
fallback, plus existing-test updates). 313 total passing, clippy + fmt
clean.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughIntroduces Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~30 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Review rate limit: 4/5 reviews remaining, refill in 12 minutes. Comment |
There was a problem hiding this comment.
This PR successfully addresses three distinct bugs discovered during end-to-end testing of the --deep mode. The changes are well-structured, properly tested, and maintain backward compatibility.
Key fixes validated:
- Error message prefix now accurately reflects both missing and malformed config scenarios
- Range-aware semantic finding lineage prevents false attribution when model identifies incidental findings outside seed range
- Category serialization consistency achieved through centralized
AuthCategory::slug()method
All 310 tests pass, manual testing across three transport mechanisms completed successfully, and the implementation demonstrates careful attention to edge cases. The changes are ready to merge.
You can now have the agent implement changes and create commits directly on your pull request's source branch. Simply comment with /q followed by your request in natural language to ask the agent to make changes.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/mcp/resources.rs (1)
45-46: Centralize slug parsing alongside emission.
AuthCategory::slug()now owns the write-side contract, butcategory_from_slug()below still hand-maintains the reverse mapping. That leaveslist_resources()andread_resource()able to drift on the next category add/rename. Consider moving the parse side intoimpl FromStr for AuthCategory(or equivalent) and reusing it here.Also applies to: 83-83
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/mcp/resources.rs` around lines 45 - 46, The code duplicates slug logic: AuthCategory::slug() defines the write-side format while category_from_slug() manually reverses it, risking drift; implement parsing centrally by adding impl FromStr for AuthCategory (or a parse_slug method) and replace manual parsing calls in category_from_slug(), list_resources(), and read_resource() to use AuthCategory::from_str (or the shared parse_slug) so both emission (AuthCategory::slug()) and parsing share the same contract.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/mcp/resources.rs`:
- Around line 45-46: The code duplicates slug logic: AuthCategory::slug()
defines the write-side format while category_from_slug() manually reverses it,
risking drift; implement parsing centrally by adding impl FromStr for
AuthCategory (or a parse_slug method) and replace manual parsing calls in
category_from_slug(), list_resources(), and read_resource() to use
AuthCategory::from_str (or the shared parse_slug) so both emission
(AuthCategory::slug()) and parsing share the same contract.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 477e4e7e-5731-4cab-b644-74e333f1eefd
📒 Files selected for processing (6)
plans/done/00-deep-mode-overview.mdsrc/deep/error.rssrc/deep/finding.rssrc/mcp/resources.rssrc/output/json.rssrc/types.rs
Captures the manual shakedown session that produced the fixes in this branch. Six runs against the same fixture (or a paired cold-region-only fixture) across HTTP/Ollama, MCP/Claude Code, and subprocess/claude-p + subprocess/codex-exec. Real commands, real outputs, real timing/cost numbers. Sections: - TL;DR matrix mapping each mode to "when to use it" - Fixture rationale (one escalation candidate + one cold-region candidate in a single TS file) - Static baseline vs each transport, with the actual JSON they returned - Comparison table across runs - The pattern_rule lineage rules (escalation+overlap, escalation+disjoint, cold region) as a table — reproduces the truth table that drove this PR's Fix #2 refinement - Surprises encountered during the shakedown that aren't bugs but are worth knowing (Ollama's lax json_schema support, escalation suppression of overlapping cold regions, claude -p cold-start timeouts) README points to the new doc from the deep-mode section.
Summary
Three small bugs caught during an end-to-end shakedown of
--deepacross all three transports (HTTP via Ollama, subprocess viaclaude -p+codex exec, and MCP via Claude Code).Fixes
1.
DeepError::Configdisplay prefix —src/deep/error.rsSaid
missing config:even when the variant fired for validation errors with values present (ftp://scheme,--agent-cmd+--base-urlmutex, NaN cost rates). Renamed todeep config error:.2. Semantic findings inheriting structural
pattern_ruleverbatim —src/deep/finding.rsA model-recategorized finding (ownership seed → feature_gate verdict) was still displaying
Rule: ts-ownership-check. The model can re-categorize, drop, or re-scope a seed; the bare structural rule lies about provenance. Now:{rule}-semantic(genuine re-evaluation, lineage preserved)semantic-{category}semantic-{category}The range-aware branch was caught during the subprocess walkthrough: one ownership escalation's expanded window covered an unrelated
checkPermissionfunction and that feature_gate finding was getting stampedts-ownership-check-semantic.3.
summary.by_categorykeys disagreeing withfindings[].category—src/output/json.rs,src/types.rs,src/mcp/resources.rsSummary used
Display("Business Rule"→ lowercased to"business rule"with a space), findings used serderename_all="snake_case"("business_rule"). Two spellings of the same enum in one JSON document. AddedAuthCategory::slug()as the single source of truth for the snake_case wire form, swapped output/json.rs and mcp/resources.rs over to it, deleted two duplicate privatecategory_slughelpers.Test plan
ranges_overlaphelper and disjoint-range lineage)cargo clippy --all-targets -- -D warningscleancargo fmt --checkcleanclaude -p(Opus 4.7) andcodex exec— both produced 3 findings on the same fixturesemantic-feature_gateinstead ofts-ownership-check-semanticFollow-ups (not in this PR)
discover_cold_regionstool to bring Tier 1 into parity with Tier 2/3.--agent-cmd(exit 127) currently per-candidate-skips withBadResponsewarnings; arguably should fail fast at first invocation. Design tradeoff between best-effort enrichment and clear misconfiguration feedback.req.user.role !== 'admin'(negated form) andreq.user.hasRole(...)(member-expression call) didn't match the existing rules in a hand-written fixture.Summary by CodeRabbit
Bug Fixes
New Features / Behavior
Documentation
Tests