From radar-suite
Classifies code findings into axis_1 (bug), axis_2 (scatter), or axis_3 (dead/smelly), verifies with checklists, and requires coaching citing file:line patterns from the codebase. Invoked by radar-suite skills before emitting findings.
npx claudepluginhub terryc21/radar-suite --plugin radar-suiteThis skill is limited to using the following tools:
> Every radar in the suite invokes this skill before emitting findings. This is the verification gate and the coaching engine. Findings that do not pass the gate are rejected.
Aggregates 5 companion radar skills plus 5 grep domains for unified A-F codebase grading and ship/no-ship decisions. Tracks velocity, diffs audits, and celebrates improvements.
Runs modular quality probes adapted to detected tech stack, presents findings for interactive triage, creates VCS issues for confirmed problems.
Challenges code project assumptions, architecture, design decisions, and testing strategies as Devil's Advocate. Delivers periodic deep analysis in multi-agent workflows.
Share bugs, ideas, or general feedback.
Every radar in the suite invokes this skill before emitting findings. This is the verification gate and the coaching engine. Findings that do not pass the gate are rejected.
Three things, in order:
better_approach section that cites a real file:line pattern from the audited codebase (not generic advice).Any radar can invoke this skill. The skill itself does not scan code directly — it provides the framework, the checklist, and the schema gate that each radar uses before writing its handoff YAML.
Code does the wrong thing from the user's perspective. The behavior needs to change.
Examples:
Default audience: end_user
Severity: 4-tier scale (critical, high, medium, low)
Grade impact: Yes — counts toward fix-before-shipping grade
Code runs correctly but is structured in a way that makes the next developer's job harder. The fix is reorganization, not behavior change. No user-visible change after the fix.
Examples:
#if os(iOS) / #else forks for the same UI concern across multiple filesDefault audience: code_reader
Severity: Hygiene scale (urgent, rolling, backlog)
Grade impact: No — lives in the hygiene backlog, does not affect ship grade
Either unreachable (dead code) or reachable but not clearly justified (smelly). The fix is delete, document, or interrogate.
Two sub-labels:
Examples:
guard let on a value that is constructed two lines above and cannot be nilDefault audience: future_maintainer
Severity: Hygiene scale
Grade impact: No — lives in the hygiene backlog
A radar MUST run these checks before assigning an axis and emitting the finding. Each check that was run is logged in the finding's verification_log field. A finding without a verification_log is rejected by the schema gate.
Rule: Before emitting "this branch is a user-facing dead end," trace the branch back to a production call site.
How:
Log entry:
- check: reachability_trace
result: "reached from MyProductsView.swift:915 via galleryContent(items) — reachable"
# or:
result: "no production call site found; reclassified to axis_3_dead_code"
Rule: Before claiming a state / case / branch is unhandled, scan the ENTIRE file (not just the flagged region) for a handler.
How:
Log entry:
- check: whole_file_scan
result: "scanned 1169 lines; no other handlers for .empty case found — finding stands as axis_1"
# or:
result: "scanned 1169 lines; handler at LegacyWishesView.swift:847; reclassified to axis_2_scatter"
#if claim)Rule: Before classifying a #if os(iOS) (or any conditional compilation block) as iOS-only or platform-broken, READ both the #if and the #else branches. Do not drop the #else.
How:
#if block, read the full block including all #elseif and #else clauses#else branch handles the case and the radar missed it, the finding is a false positiveLog entry:
- check: branch_enumeration
result: "#if os(iOS) block at lines 102-118 has #else at 112-116 that handles the macOS case; finding retracted"
# or:
result: "#if os(iOS) block at lines 102-118 has no #else; iOS-only code confirmed"
Rule: The better_approach coaching field MUST cite an existing pattern in the SAME codebase being audited. Grep for the pattern shape before writing the recommendation. Generic advice ("consider using a protocol abstraction") without a citation is rejected.
How:
better_approach, identify the pattern shape (protocol abstraction, async bridge, typed navigation enum, etc.)better_approach bodycoaching-examples-generic.md AND note explicitly "no existing pattern found in this codebase"Log entry:
- check: pattern_citation_lookup
result: "found similar pattern at Sources/Protocols/CloudSyncManaging.swift:14 (protocol + @MainActor class)"
# or:
result: "no existing protocol abstraction pattern found in codebase; using generic template"
Rule: Before claiming a field / type / symbol is unused, enumerate the project's actual source roots. Do not hardcode Sources/ as the only root.
How:
project.pbxproj (Xcode project) or Package.swift (SPM) to get the actual source root listSources/Views/ AND Sources/Features/ AND Sources/Shared/), grep all of them before emitting an "unused" findingLog entry:
- check: source_root_introspection
source_roots: ["Sources/"]
result: "single source root confirmed; full-root grep ran"
Every finding MUST populate these fields. A finding missing any mandatory field is rejected by the schema gate.
findings:
- id: [unique-hash]
# Axis classification (REQUIRED)
axis: axis_1_bug | axis_2_scatter | axis_3_dead_code | axis_3_smelly
# Audience (REQUIRED — defaults by axis but may be overridden per finding)
# axis_1 default: end_user
# axis_2 default: code_reader
# axis_3 default: future_maintainer
before_after_experience:
audience: end_user | code_reader | future_maintainer
before: "Concrete description of the experience today from the named audience's POV"
after: "Concrete description after the fix, same audience"
# Coaching fields (ALL REQUIRED, including for axis_2 and axis_3)
current_approach: |
How the code is structured today. Specific file:line references.
Describe the shape, not just the location.
suggested_fix: |
The minimum change that addresses the immediate finding.
For axis_1: the bug fix. For axis_2: the reorganization. For axis_3: delete or document.
better_approach: |
How a senior reviewer would write this area of the codebase beyond the minimum fix.
MUST cite an existing pattern in the user's codebase by file:line.
Format: "Follow the pattern at [File.swift:NN] which [describes what the pattern does]."
A better_approach without a pattern_citation_lookup entry in verification_log is REJECTED.
better_approach_tradeoffs: |
Honest tradeoffs. When the better approach is overkill. When it is the right call.
At least one sentence of each: when to apply, when not to apply.
# Verification log (REQUIRED — at minimum, pattern_citation_lookup)
verification_log:
- check: reachability_trace | whole_file_scan | branch_enumeration | pattern_citation_lookup | source_root_introspection
result: "concrete outcome of the check"
# Existing fields (unchanged from radar-suite-core.md schema)
description: [plain language]
confidence: verified|probable|possible
urgency: critical|high|medium|low
status: open|fixed|deferred|accepted
file: [path]
line: [number]
file_last_modified: [ISO-8601]
group_hint: [category for batch operations]
pattern_fingerprint: [normalized anti-pattern name]
grep_pattern: [regex]
exclusion_pattern: [regex]
A finding is REJECTED (not emitted, returned to the radar for correction) if any of these apply:
axis field is missing or not one of the four valid valuesbefore_after_experience is missing or any sub-field is emptycurrent_approach, suggested_fix, or better_approach is missing or emptybetter_approach does not contain a file:line citation (format: [A-Za-z0-9_/+.-]+\.swift:\d+)verification_log is missing or does not contain a pattern_citation_lookup entrybetter_approach_tradeoffs is missing or does not contain both a "when to apply" and a "when not to apply" sentenceWhen a finding is rejected: the radar must either (a) fix the finding by running the missing checks and populating the missing fields, or (b) downgrade the finding's confidence to possible and explicitly mark it as "coaching incomplete" in the handoff so it is visible as a low-confidence entry rather than dropped silently.
Grade impact: CRITICAL findings cap grade at C. HIGH findings cap at B+. (Same rules as radar-suite-core.md.)
Grade impact: NONE. Hygiene findings do not count toward the A-F grade. They live in a separate capstone section.
A radar may emit both axis_1 findings (severity: critical) and axis_2 findings (severity: rolling_hygiene) in the same handoff YAML. The capstone reader splits them by axis, not by severity value.
Every finding declares its audience. The audience is who experiences the before/after change.
| Axis | Default Audience | Override When |
|---|---|---|
| axis_1 | end_user | The "bug" is a developer ergonomic issue (e.g., crash on a debug-only code path) — override to code_reader |
| axis_2 | code_reader | The scatter is so bad it causes observable lag from bundle size or view recomputation — override to end_user |
| axis_3 | future_maintainer | The smelly code is a hygiene issue a code reviewer would catch in the next PR — override to code_reader |
Why explicit audience matters: axis_2 and axis_3 findings have no natural end_user experience. Forcing every finding to phrase before/after for the end user makes axis_2/3 findings hand-wavy. Naming the correct audience keeps the coaching grounded.
Writing the before/after per audience:
end_user — describe what the app does today vs after (from a user's perspective, not developer's)code_reader — describe what the code looks like today vs after (from a developer reading the file for the first time)future_maintainer — describe what a developer inheriting this code in 6 months would think / trip overBefore writing better_approach for any finding, the radar loads coaching examples in this order:
.radar-suite/project.yamlcoaching_examples: array — e.g., [stuffolio, generic] or [generic]skills/radar-suite-axis-classification/coaching-examples-<name>.mdExample .radar-suite/project.yaml for Stuffolio:
coaching_examples:
- stuffolio
- generic
Example for a new project with no overlay:
coaching_examples:
- generic
No project.yaml means: load generic only.
Pattern match precedence: if the Stuffolio overlay has an example for "protocol abstraction" and the generic file also has one, the Stuffolio example is used. If Stuffolio does NOT have an example for "typed navigation destination enum" but generic does, the generic example is used.
Every radar must include a checks_performed block in its handoff YAML. This makes "no findings in this category" distinguishable from "this category was not scanned."
checks_performed:
source_roots_scanned: ["Sources/"]
files_scanned: 588
patterns_checked:
- reachability_trace
- whole_file_scan
- branch_enumeration
- pattern_citation_lookup
- source_root_introspection
patterns_not_run: [] # empty if all checks ran
reason_for_skipped_checks: null
If a check is deliberately skipped: document why.
patterns_not_run: ["branch_enumeration"]
reason_for_skipped_checks: "no #if conditional compilation blocks found in scope"
This skill does not run as a standalone orchestrator. Each radar invokes it via the following protocol:
pattern_citation_lookup..radar-suite/project.yaml from the target repo and load the example files.current_approach, suggested_fix, better_approach (with citation), better_approach_tradeoffs.checks_performed block summarizing what the radar actually scanned.axis_summary counting findings by axis:
axis_summary:
axis_1_bug: 12
axis_2_scatter: 7
axis_3_dead_code: 2
axis_3_smelly: 4
rejected_no_citation: 3 # findings dropped at the gate for missing coaching
rejected_no_citation count is visible so capstone knows the radar had candidate findings it could not coach.coaching-examples-generic.md — Anonymized worked examples for all 3 axes. Ships with the skill. Default fallback.coaching-examples-stuffolio.md — Stuffolio-specific overlay with real file:line citations from the Stuffolio codebase. Loaded first when auditing Stuffolio.Future projects with their own overlays: create coaching-examples-<projectname>.md in this skill's directory and reference it in the target project's .radar-suite/project.yaml.