Roundtrip Radar

SkillMonitoring & ops

Per-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.

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

CommandDescription
/roundtrip-radarStart with Step 0 (discover), then prompt for Step 1
/roundtrip-radar discoverRun Step 0 only — find all workflows
/roundtrip-radar [WORKFLOW]Run Step 1 for a specific workflow
/roundtrip-radar rollupRun Step 2 — cross-cutting analysis
/roundtrip-radar trace "A → B → C"Trace a specific user flow path (see below)
/roundtrip-radar diffCompare findings against previous audit
--show-suppressedShow findings suppressed by known-intentional entries
--accept-intentionalMark 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

  1. Parse the path — Split on , ->, or , into discrete steps
  2. Identify code locations — For each step, search for:
    • View names matching the step
    • Sheet triggers, navigation actions
    • Button labels, action handlers
  3. 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)
  4. 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)
  5. 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

  1. Identify the baseline session — read .radar-suite/ledger.yaml, find the most recent prior session entry with skill: roundtrip-radar. With --since YYYY-MM-DD, use the latest entry on or after that date instead.
  2. 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.
  3. 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 with status: fixed
    • Regressed — present in baseline with status: fixed, present in current with status: open (also flag if file_hash changed since the fix, per the Regression Detection protocol in radar-suite-core.md)
    • New — RS-NNN ID is in current but not baseline
    • Persistent — present in both with the same status (open or deferred)
  4. Apply optional filters: --workflow [NAME] restricts to findings whose workflow field 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
  • --since date 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) in radar-suite-core.md, archive any existing .agents/research/*-[WORKFLOW]-audit.md matching 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 the AskUserQuestion next-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 categoryDefault axisReclassification rule
Data loss on cancelaxis_1_bugStays axis_1 (user-facing data loss)
Data loss on erroraxis_1_bugStays axis_1
Missing feedback after saveaxis_1_bugStays axis_1
Field written but not readaxis_3_smellyReclassify to axis_1_bug ONLY if a user feature depends on the field (check feature flags and view usage)
Field read but not writtenaxis_3_smellyReclassify to axis_1_bug if feature claims the field is set
Field exists but unwired end-to-endaxis_3_smellyReclassify to axis_1_bug if a user action should write it
Round-trip path opaque (cannot be traced from UI to persistence)axis_2_scatterStays axis_2 — data flow is correct but impossible to verify
Inconsistent serialization across paths (CSV, backup, CloudKit)axis_1_bugStays axis_1 — ONE path loses user data
Serialization paths duplicated across multiple managersaxis_2_scatterStays axis_2 — correct but hard to maintain
Serialization call reaches a dead branch (e.g., guard always true)axis_3_dead_codeStays axis_3
CloudKit sharing contract violation (write dropped or identity withheld server-side)axis_1_bugStays 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

  1. Full-path trace (MANDATORY for every finding) — walk UI → manager → model → persistence → UI. Log every hop.
  2. Pattern citation lookup (MANDATORY) — find an existing correct round-trip pattern in the same codebase and cite it by file:line in better_approach.
  3. 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).
  4. 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:

  • axis field is missing
  • before_after_experience is missing or incomplete
  • better_approach lacks a file:line citation matching the pattern shape
  • verification_log lacks a pattern_citation_lookup entry

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)

  1. Known-intentional suppression: Run the protocol in radar-suite-core.md § Known-Intentional Suppression. Core owns this — do not restate the steps here.

  2. 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

  1. Search for navigation entry points:
    • .sheet, .fullScreenCover, .navigationDestination
    • NavigationLink, TabView tabs
    • Button actions that trigger multi-step flows
  2. Search for data operations:
    • modelContext.insert, modelContext.delete, context.save
    • Import/export, backup/restore, sync operations
    • API calls, file I/O
  3. Search for state machines:
    • Enums with cases like .idle, .processing, .complete
    • Multi-step @State progressions
    • isProcessing, isImporting, isSaving patterns

Output

List each workflow with:

#WorkflowEntry PointKey FilesComplexityData Risk
1[Name][Where user starts it][2-4 main files]Low/Med/HighNone/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 contents
  • Grep — search file contents
  • Glob — find files by pattern

It will NOT use:

  • Bash — no shell commands (grep via Grep tool instead)
  • Edit / Write — no file modifications
  • AskUserQuestion — 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
Advanced
Catalog kind
skill
Gateway key
roundtrip-radar
Source
github.com/terryc21/radar-suite