Roundtrip Radar
SkillMonitoring & opsPer-journey code audit tracing data through complete user flows for bugs, data safety, performance, and round-trip completeness. Discovers workflows, audits each end-to-end, rolls up cross-cutting issues, and supports natural-language flow tracing. Triggers: "roundtrip audit", "trace user journey", "/roundtrip-radar".
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Roundtrip Radar skill
What this skill tells your AI
The instructions your AI receives, as published by terryc21/radar-suite in skills/roundtrip-radar/SKILL.md and read by ahel’s review.
This skill audits application workflows for bugs, data-safety issues, performance problems, and data round-trip completeness. It operates in three primary steps plus two targeted entry points:
- Step 0 — Discover all workflows (run once, or when workflows change)
- Step 1 — Deep audit one workflow at a time (one prompt per workflow)
- Step 2 — Roll-up cross-cutting patterns across all audited workflows
- Trace — Audit a specific user journey described in natural language (see § Trace Command)
- Diff — Compare findings against the previous audit's ledger entries (see § Diff Command)
Usage
| Command | Description |
|---|---|
/roundtrip-radar | Start with Step 0 (discover), then prompt for Step 1 |
/roundtrip-radar discover | Run Step 0 only — find all workflows |
/roundtrip-radar [WORKFLOW] | Run Step 1 for a specific workflow |
/roundtrip-radar rollup | Run Step 2 — cross-cutting analysis |
/roundtrip-radar trace "A → B → C" | Trace a specific user flow path (see below) |
/roundtrip-radar diff | Compare findings against previous audit |
--show-suppressed | Show findings suppressed by known-intentional entries |
--accept-intentional | Mark current finding as known-intentional (not a bug) |
Trace Command
Targeted flow tracing — trace a specific user journey described in natural language.
Usage
/roundtrip-radar trace "Dashboard → Add Item → Photo → Save"
/roundtrip-radar trace "Settings, Export, CSV, Email"
How It Works
- Parse the path — Split on
→,->, or,into discrete steps - Identify code locations — For each step, search for:
- View names matching the step
- Sheet triggers, navigation actions
- Button labels, action handlers
- Trace step by step — For each transition:
- File and line number
- State changes (sheet presentations, navigation, @State mutations)
- Data transformations (what model fields are read/written)
- Check for issues at each step:
- Is data preserved between steps? (Round-trip completeness)
- Are collections preserved or silently narrowed? (Collection narrowing)
- Are there error paths that lose context? (Error handling)
- Is the user's intent preserved? (Data safety)
- Are there race conditions? (Concurrency)
- Output — Issue Rating Table for findings + step-by-step trace with receipts
Output Format
Trace: Dashboard → Add Item → Photo → Save
| Step | Action | File | Lines | Data In | Data Out | Finding |
|------|--------|------|-------|---------|----------|---------|
| 1 | Dashboard tap "Add" | DashboardView.swift | 142-145 | — | activeSheet = .addItem | ok |
| 2 | Add Item sheet presents | AddItemView.swift | 1-50 | Item.draft | item.title, item.category | ok |
| 3 | Photo picker | PhotoPicker.swift | 23-89 | item.id | PhotoAttachment | ⚠️ orientation lost |
| 4 | Save item | ItemViewModel.swift | 112-134 | item + attachments | modelContext.save() | ok |
Issues Found:
| # | Finding | Urgency | Risk: Fix | Risk: No Fix | ROI | Blast Radius | Fix Effort | Status |
When to Use
- Debugging a specific user report — "When I add a photo and save, the orientation is wrong"
- Verifying a fix — Trace the exact path to confirm data flows correctly
- Pre-release spot check — Trace critical paths without a full audit
Diff Command
Compare findings against the previous roundtrip-radar audit — surface what regressed, what got fixed, and what's new since the last run.
Usage
/roundtrip-radar diff
/roundtrip-radar diff --since 2026-04-01
/roundtrip-radar diff --workflow Backup
Source of Truth
The diff reads from .radar-suite/ledger.yaml — the only authoritative cross-session store of roundtrip-radar findings. Per-workflow handoff YAMLs (.agents/ui-audit/roundtrip-radar-handoff.yaml) are overwritten each run, so they cannot serve as a diff baseline.
The "previous audit" is defined as the most recent ledger session entry with skill: roundtrip-radar that is strictly older than the current session. If no prior session exists, the diff command MUST refuse with:
"No prior roundtrip-radar audit found in
.radar-suite/ledger.yaml. Run a workflow audit first to establish a baseline."
Do not invent a baseline. Do not fall back to memory or .agents/research/ markdown reports.
How It Works
- Identify the baseline session — read
.radar-suite/ledger.yaml, find the most recent prior session entry withskill: roundtrip-radar. With--since YYYY-MM-DD, use the latest entry on or after that date instead. - Identify the current session — either the in-progress session (if the user just ran an audit and is asking for the diff) or the most recent completed session.
- Bucket every finding from the union of baseline + current into one of four categories by RS-NNN ID:
- Fixed — present in baseline with
status: open, present in current withstatus: fixed - Regressed — present in baseline with
status: fixed, present in current withstatus: open(also flag iffile_hashchanged since the fix, per the Regression Detection protocol inradar-suite-core.md) - New — RS-NNN ID is in current but not baseline
- Persistent — present in both with the same status (open or deferred)
- Fixed — present in baseline with
- Apply optional filters:
--workflow [NAME]restricts to findings whoseworkflowfield matches.
Output Format
Diff: 2026-04-15 → 2026-05-12 (27 days, 4 sessions)
✅ Fixed (3)
| RS-NNN | short_title | Workflow | Fixed in |
|--------|-------------|----------|----------|
| RS-042 | Backup drops attachment storage | Backup | 2026-04-22 |
...
🔴 Regressed (1)
| RS-NNN | short_title | Workflow | Was fixed | file_hash changed? |
|--------|-------------|----------|-----------|--------------------|
| RS-019 | CSV import loses Room field | CSV Import | 2026-04-18 | yes (CSVImportManager.swift) |
🆕 New (5)
| RS-NNN | short_title | Workflow | Urgency |
|--------|-------------|----------|---------|
📌 Persistent (12)
[collapsed by default; pass --verbose to expand]
When to Use
- Pre-PR review — confirm the changes in this PR didn't reintroduce any previously-fixed bug
- Post-release retrospective — what got fixed this release cycle, what slipped
- Suspecting a regression —
--workflow [NAME]narrows to one user journey
Refusal cases
- No prior ledger session: refuse with the message above
--sincedate is in the future: refuse with "Date is in the future; no audits to compare"--workflow [NAME]matches no findings in either baseline or current: print "No findings in workflow [NAME] across either session" (not a refusal — a legitimate empty result)
Skill Introduction (MANDATORY — run before anything else)
This section replaces radar-suite-core.md § Session Setup for the roundtrip-radar entry point. Do NOT also run core's 4-question Session Setup — its questions are consolidated below. All four setup questions go in ONE AskUserQuestion call on first invocation. Step 1's per-workflow flow reuses these answers and never re-asks them.
Question 1: "What's your experience level with Swift/SwiftUI?"
- Beginner — New to Swift. Plain language, analogies, define terms on first use.
- Intermediate — Comfortable with SwiftUI basics. Standard terms, explain non-obvious patterns.
- Experienced (Recommended) — Fluent with SwiftUI. Concise findings, no definitions.
- Senior/Expert — Deep expertise. Terse, file:line only, skip explanations.
Question 2: "How should fixes be handled?"
- Auto-fix safe items (Recommended) — Apply isolated, low-blast-radius fixes automatically. Present cross-cutting fixes and design decisions for approval first.
- Review first — Present all findings with ratings, then ask before making any changes. Fixes still happen — you just approve each wave first.
- Batch mode — Approve all fixes in each wave at once.
IMPORTANT: All three modes lead to fixes. "Review first" means the user sees the plan before code changes — it does NOT mean "skip fixes and jump to handoff." After presenting findings, ALWAYS offer to fix them regardless of which mode was selected. (Exception: Hands-Free mode overrides this — see Question 4.)
Question 3: "How should results be delivered?"
- Display only (Recommended) — Show findings in the conversation. No file written.
- Report only — Write findings to
.agents/research/[DATE]-[WORKFLOW]-audit.md. Minimal conversation output. Before writing, per Artifact Lifecycle (Class 3) inradar-suite-core.md, archive any existing.agents/research/*-[WORKFLOW]-audit.mdmatching the same workflow to.agents/research/archive/superseded/. - Display and report — Show findings in the conversation AND write to file.
Question 4: "Will you be stepping away during the audit?"
- I'll be here (Recommended) — Normal mode. Permission prompts may appear for writes/edits.
- Run the full analysis without stopping to ask — no code changes — Hands-Free mode. Restricts to read-only tools (Read, Grep, Glob). No Bash, no Edit, no Write — nothing that triggers a permission prompt. Hands-Free overrides Question 2: all fixes are deferred regardless of
FIX_MODE. The progress banner still prints, but theAskUserQuestionnext-wave prompt is suppressed; the skill emits the "audit complete through Step N" completion message instead (see Hands-Free Mode below). - Pre-approved — You have already configured Claude Code permissions for this session (see Permission Setup below). Run at full speed without restriction.
Store as: USER_EXPERIENCE, FIX_MODE, DELIVERY, PRESENCE_MODE. Apply to ALL output for session, per radar-suite-core.md § Experience-Level Output Rules. Also persist to .radar-suite/session-prefs.yaml per radar-suite-core.md § Session Persistence.
Question 5 (optional follow-up): "Would you like a brief explanation of what this skill does?"
- No, let's go (Recommended) — Skip explanation, proceed to audit.
- Yes, explain it — Show a 3-5 sentence explanation adapted to the user's experience level (see below), then proceed.
Experience-adapted explanations for Roundtrip Radar:
-
Beginner: "Roundtrip Radar follows your data through complete user journeys — like tracking a package from warehouse to doorstep and back. For example, it checks: if you create an item, back it up, delete it, and restore — does everything come back exactly? It finds bugs where data gets lost, corrupted, or silently dropped along the way. It audits one workflow at a time (backup, add item, sync, etc.) so nothing gets missed."
-
Intermediate: "Roundtrip Radar audits individual workflows end-to-end for data safety, error handling, concurrency, and round-trip completeness. It traces data through create → modify → export → import cycles, checks transaction boundaries, verifies error recovery paths, and identifies where data is silently lost. Works one workflow at a time to stay thorough."
-
Experienced: "Per-workflow code audit: data safety, error handling, concurrency, performance, contract mismatches, and round-trip completeness. Discovers workflows, audits each with issue rating tables and fix plans, then rolls up cross-cutting patterns."
-
Senior/Expert: "Workflow-scoped audit: data safety + error paths + concurrency + round-trip completeness. Rating tables + fix plans + cross-workflow rollup."
Store the experience level as USER_EXPERIENCE and apply to ALL output for the session.
User impact explanations: Can be toggled at any time with --explain / --no-explain. When enabled, each finding gets a 3-line companion explanation (what's wrong, fix, user experience before/after). See the shared rating system doc for format and rules. Store as EXPLAIN_FINDINGS (default: false).
Experience-level auto-apply: If USER_EXPERIENCE = Beginner, auto-set EXPLAIN_FINDINGS = true and default sort to impact. If Senior/Expert, default sort to effort. Apply all output rules from Experience-Level Output Rules table in radar-suite-core.md.
Subsequent workflows: Do NOT re-ask the full setup questions. Instead, show a one-line reminder before each workflow:
Using: [Experienced] mode, [Auto-fix safe items], [Display only], [I'll be here]. Type "adjust" to change, or press Enter to continue.
The four bracketed values map to USER_EXPERIENCE, FIX_MODE, DELIVERY, PRESENCE_MODE set during the Skill Introduction. If the user types "adjust", re-ask only the question(s) they want to change. Users may want to adjust experience level after a few workflows (beginner explanations may feel too simple, expert too terse).
Shared Patterns
See radar-suite-core.md for: Tier System, Pipeline UX Enhancements, Table Format, Plain Language Communication, Work Receipts, Contradiction Detection, Finding Classification, Audit Methodology, Context Exhaustion, Progress Banner, Issue Rating Tables, Handoff YAML schema, Known-Intentional Suppression, Pattern Reintroduction Detection, Experience-Level Output Rules, Implementation Sort Algorithm, short_title requirement.
Axis Classification Protocol (MANDATORY — before emitting any finding)
Every roundtrip-radar finding must be classified on the 3-axis framework and pass the schema gate in radar-suite-core.md before emission. The framework is defined in skills/radar-suite-axis-classification/SKILL.md.
Roundtrip-specific axis mapping
roundtrip-radar's findings are organized by what part of the round-trip path is broken. Each finding category maps to a default axis, with reclassification rules based on verification checks.
| Finding category | Default axis | Reclassification rule |
|---|---|---|
| Data loss on cancel | axis_1_bug | Stays axis_1 (user-facing data loss) |
| Data loss on error | axis_1_bug | Stays axis_1 |
| Missing feedback after save | axis_1_bug | Stays axis_1 |
| Field written but not read | axis_3_smelly | Reclassify to axis_1_bug ONLY if a user feature depends on the field (check feature flags and view usage) |
| Field read but not written | axis_3_smelly | Reclassify to axis_1_bug if feature claims the field is set |
| Field exists but unwired end-to-end | axis_3_smelly | Reclassify to axis_1_bug if a user action should write it |
| Round-trip path opaque (cannot be traced from UI to persistence) | axis_2_scatter | Stays axis_2 — data flow is correct but impossible to verify |
| Inconsistent serialization across paths (CSV, backup, CloudKit) | axis_1_bug | Stays axis_1 — ONE path loses user data |
| Serialization paths duplicated across multiple managers | axis_2_scatter | Stays axis_2 — correct but hard to maintain |
| Serialization call reaches a dead branch (e.g., guard always true) | axis_3_dead_code | Stays axis_3 |
| CloudKit sharing contract violation (write dropped or identity withheld server-side) | axis_1_bug | Stays axis_1 — the trace terminates at the server boundary by construction, not from opacity, so the full-path rule's axis_2_scatter fallback does NOT apply (see § Full-path verification rule, external-boundary clause). Reclassify to axis_3_smelly only if no user-visible surface consumes the affected permission or identity |
Full-path verification rule (roundtrip-specific)
Every finding must cite the full roundtrip path in its verification_log. The path is the sequence of file:line hops from UI entry point to persistence and back to UI. If the path cannot be traced end-to-end, the finding is axis_2_scatter regardless of its category (the data flow is opaque even if correct).
Example verification_log for a roundtrip finding:
verification_log:
- check: full_path_trace
path:
- ImportCSVView.swift:142 (user taps Import)
- CSVImportManager.swift:420 (parse loop)
- Item.swift:58 (Item init with room: nil ← MISSING FIELD)
- ModelContext (save)
- ItemListView.swift:84 (Query fetches items)
- ItemRowView.swift:29 (displays room, which is nil)
result: "path traced end-to-end; room field is dropped at CSVImportManager.swift:420 and displayed as nil downstream"
- check: pattern_citation_lookup
result: "found existing round-trip pattern at Sources/Managers/BackupManager.swift:NNN which correctly serializes room"
External-boundary exception. A path that reaches an external system (a sync server, a payment
processor, a third-party API), and resumes on the other side, is traced — not opaque. The
axis_2_scatter fallback above applies to paths that cannot be followed within the codebase,
not to paths that leave it. Mark the crossing explicitly and keep the finding's category axis:
verification_log:
- check: full_path_trace
path:
- FamilySharingView.swift:NNN (owner sets Member Access to Viewer)
- FamilySharingManager.swift:NNN (participant.permission = ckPermission)
- [SERVER BOUNDARY: CKShare save succeeds; server discards the write]
- FamilySharingView.swift:NNN (participant still renders as Editor)
result: "path traced to the server boundary and resumed on the read side; terminates at an
external system, NOT from opacity — axis_1_bug stands. Confidence: needs-runtime
(2-account round-trip required to observe the server's actual behavior)"
Distinguish this from a genuine gap: a [SERVER BOUNDARY] marker asserts you traced the code up
to the call and picked the path back up after it. If you could not find the read side either, that
is opacity — use [GAP: ...] and take axis_2_scatter.
If any hop cannot be found (e.g., "no persistence call in this workflow"), the path entry documents the gap:
path:
- AddItemView.swift:120 (user taps Save)
- AddItemViewModel.swift:85 (validate inputs)
- [GAP: no modelContext.insert found for this workflow in scope]
result: "round-trip path INCOMPLETE; finding classified as axis_2_scatter (opaque flow)"
Required checks before emission
- Full-path trace (MANDATORY for every finding) — walk UI → manager → model → persistence → UI. Log every hop.
- Pattern citation lookup (MANDATORY) — find an existing correct round-trip pattern in the same codebase and cite it by file:line in
better_approach. - Whole-file scan (MANDATORY when claiming a field is "not serialized") — scan the ENTIRE serializer file (CSV import/export, backup encode/decode, CloudKit mapper) for the field name. If found, it IS serialized — the finding is probably about a different code path (reclassify as axis_2_scatter if the serialization is scattered).
- Multi-path comparison (MANDATORY for serialization findings) — a field may be serialized in one path (backup) but not another (CSV). Check ALL known serialization paths before claiming "missing." Stuffolio has at least 4: CSV export, CSV import, backup (JSON), CloudKit (CKRecordMapper).
Schema gate
Per radar-suite-core.md, a finding is REJECTED if:
axisfield is missingbefore_after_experienceis missing or incompletebetter_approachlacks a file:line citation matching the pattern shapeverification_loglacks apattern_citation_lookupentry
Rejected findings are NOT silently dropped: downgrade confidence to possible, mark as coaching incomplete, and increment rejected_no_citation in the handoff's axis_summary.
Axis summary block
At the end of every roundtrip-radar handoff:
axis_summary:
axis_1_bug: [count] # data loss, missing feedback, broken serialization paths
axis_2_scatter: [count] # opaque flows, duplicated serialization
axis_3_dead_code: [count] # unreachable serialization branches
axis_3_smelly: [count] # unwired fields with no user feature dependency
rejected_no_citation: [count]
Pre-Scan Startup (MANDATORY — before any workflow scan)
-
Known-intentional suppression: Run the protocol in
radar-suite-core.md § Known-Intentional Suppression. Core owns this — do not restate the steps here. -
Pattern reintroduction detection: Run the protocol in
radar-suite-core.md § Pattern Reintroduction Detection. Core owns this.
Step 0: Workflow Discovery
Run first if workflows are unknown or have changed.
Scan the codebase and identify all user-facing workflows.
What Counts as a Workflow
A workflow is a multi-step user action that:
- Spans 2+ screens or states (not a single tap)
- Involves data creation, modification, deletion, or transfer
- Has a distinct entry point and completion state
How to Find Them
- Search for navigation entry points:
.sheet,.fullScreenCover,.navigationDestinationNavigationLink,TabViewtabs- Button actions that trigger multi-step flows
- Search for data operations:
modelContext.insert,modelContext.delete,context.save- Import/export, backup/restore, sync operations
- API calls, file I/O
- Search for state machines:
- Enums with cases like
.idle,.processing,.complete - Multi-step
@Stateprogressions isProcessing,isImporting,isSavingpatterns
- Enums with cases like
Output
List each workflow with:
| # | Workflow | Entry Point | Key Files | Complexity | Data Risk |
|---|---|---|---|---|---|
| 1 | [Name] | [Where user starts it] | [2-4 main files] | Low/Med/High | None/Read/Write/Delete |
Complexity Criteria
- Low — 1-2 files, linear flow, no branching
- Medium — 3-4 files, some branching, error handling
- High — 5+ files, async operations, multiple outcomes, data transformation
Data Risk Criteria
- None — Display only
- Read — Fetches but doesn't modify
- Write — Creates or updates data
- Delete — Removes data or replaces state
Priority Recommendation
After listing all workflows, recommend which to audit first based on:
- High complexity + Write/Delete data risk = audit first
- Medium complexity + Write risk = audit second
- Everything else = audit if time permits
Do NOT write a report file. Output the table directly.
Step 1: Per-Workflow Audit
One workflow per prompt. Run as a separate agent or conversation per workflow to prevent context exhaustion.
Audit the [WORKFLOW NAME] workflow for bugs, data-safety issues, performance problems, and data round-trip completeness.
Before Starting (First Workflow Only)
All setup questions were captured during the Skill Introduction call (USER_EXPERIENCE, FIX_MODE, DELIVERY, PRESENCE_MODE). Do NOT re-ask any of them. Show the one-line settings reminder from § Skill Introduction and proceed to the audit.
If any of the four variables is missing for some reason (e.g., session-prefs file deleted mid-session), re-run the full Skill Introduction call before continuing — never partially re-ask, since the questions are interdependent (Question 4 overrides Question 2).
Permission Modes
Normal Mode
- Read any file without asking.
- Edit files listed in "Files to Read" and their corresponding test files freely.
- For files outside that list, edit only if directly required by a P0-P1 fix. Note which external files were changed in your output.
- Build and run tests without asking.
- If a fix breaks the build, restore the original code and document the finding as "Documented" instead of "Fixed".
Hands-Free Mode
Guarantees no blocking prompts. The skill will ONLY use these tools:
Read— read file contentsGrep— search file contentsGlob— find files by pattern
It will NOT use:
Bash— no shell commands (grep via Grep tool instead)Edit/Write— no file modificationsAskUserQuestion— no interactive prompts
Precedence rules (load-bearing — Hands-Free wins all ties):
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 20
- Forks
- 1
- Last commit
- Aug 2026
ahel review
K1binfo
installs-packages (in radar-suite-core.md)
Automated review, not a security audit. Ruleset v1+k2.
Advanced
- Catalog kind
- skill
- Gateway key
roundtrip-radar- Source
- github.com/terryc21/radar-suite