# Workflow: rcode-status

<purpose>
Render a human-readable project status dashboard. All data comes from a single `rcode-tools progress init` call — this workflow does NOT parse ROADMAP.md, walk SUMMARY.md files, or grep state.json itself. Rendering only. See `rcode-tools.cjs` `cmdProgress` for the source-of-truth logic.

**SSOT:** `.rcode/state.json`. `/rcode-status` and `/rcode-progress` both call the same CLI so they cannot disagree. If the CLI reports a drift insight, surface it — do not silently compensate.
</purpose>

<required_reading>
@.rcode/references/auto-init-guard.md
@.rcode/references/output-format.md
</required_reading>

<process>

## Step 1 — Fetch the snapshot

```bash
SNAPSHOT=$(node .rcode/bin/rcode-tools.cjs progress init)
VERBOSE=$(node .rcode/bin/rcode-tools.cjs config-get output.verbose 2>/dev/null || echo "false")
```

Parse as JSON. If `SNAPSHOT.ok` is not true, print a one-line error and stop.

**Slim mode** (default when `VERBOSE != "true"`): Output Steps 2–3 only (banner + phases list). Skip decisions, blockers detail, and route menu — just print the top route as a single "Next: `/rcode-X`" line. Append `(run /rcode-status --verbose for full detail)`.

**Verbose mode** (`VERBOSE == "true"` or `$ARGUMENTS` contains `--verbose`): Full Steps 2–6 output.

If `SNAPSHOT.project` is empty and `SNAPSHOT.phases` is empty, print:

```
No state found. Run a council session or execute a plan to initialize state.
```

Then stop.

## Step 2 — Print banner + dashboard

```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 rcode ► STATUS — {SNAPSHOT.project}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

╭─ rcode Status — {SNAPSHOT.project} ─────────────────────╮
│ Milestone:  {SNAPSHOT.milestone or "—"}                 │
│ Phase:      {SNAPSHOT.current_phase or "none started"}  │
│ Progress:   {SNAPSHOT.bar}                              │
│ Weighted:   {SNAPSHOT.weighted_bar}                     │
│ Updated:    {relative_time(SNAPSHOT.updated)}           │
╰─────────────────────────────────────────────────────────╯
```

If `SNAPSHOT.weighted_progress > 0` but `SNAPSHOT.completed_count === 0`, display
the weighted bar as the primary progress indicator to avoid a misleading `0/N (0%)`.

### Milestone health

After the main dashboard, call `rcode-tools milestone-health` and surface
a gauge when the milestone is full:

```bash
HEALTH=$(node ".rcode/bin/rcode-tools.cjs" milestone-health 2>/dev/null)
```

Parse `recommendation`, `open_phases`, `phase_count`. Display ONLY when
`recommendation` is not `healthy`:

```
⚠ Milestone health: {open_phases} open / {phase_count} total — {recommendation}
   → /rcode-complete-milestone to close, or /rcode-new-milestone to fork
```

**State-drift exception:** If `recommendation === "healthy"` AND `phase_count === 0` AND
`SNAPSHOT.insights[]` is non-empty (drift insights present), the "healthy" reading is a
false negative caused by state.json being out of sync with disk. In this case print:

```
⚠ Milestone health: unreadable — state.json not synced with disk.
   Fix: node .rcode/bin/rcode-tools.cjs state sync --from-disk
```

When truly healthy (phase_count > 0, no drift insights), print nothing — keeps status terse for normal projects.

## Step 3 — Phases section

For each entry in `SNAPSHOT.phases[]`:

**Null guard:** If `phase.disk` is `null` or missing (state-disk drift — state.json not yet synced), treat the phase as `○` (planned) and append a note `(disk state unavailable — run: node .rcode/bin/rcode-tools.cjs state sync --from-disk)`. Do NOT attempt to access fields on a null `phase.disk`.

- `▶` if `phase.number === SNAPSHOT.current_phase`
- `✓` if `phase.disk.summary_count > 0` AND `phase.disk.summary_count >= phase.disk.plan_count` AND `phase.disk.has_verification` (complete + verified; if VERIFICATION.md absent, use `◎` and label "complete-unverified")
- `◎` if `phase.disk.summary_count > 0` AND `phase.disk.summary_count >= phase.disk.plan_count` AND NOT `phase.disk.has_verification` (work done, awaiting verification)
- `◆` if `phase.disk.plan_count > phase.disk.summary_count` (executing — has plans, not all summarized)
- `◇` if `phase.disk.has_context && !phase.disk.plan_count` (discussing — CONTEXT.md exists but no plan yet)
- `◈` if `phase.disk.has_research && !phase.disk.plan_count` (researched — RESEARCH.md but no plan)
- `○` otherwise (planned — no artifacts on disk)

**Edge case — summary without sprint:** If `summary_count > 0` AND `plan_count === 0`, treat as `◎ complete-unverified` (sprint was archived or the phase used an older single-file workflow; summary is evidence of completed work).

```
Phases:
  ▶ [04] Component compaction — executing (1/3 plans)
  ✓ [03] Auth hardening — complete
  ◇ [05] Billing rewrite — discussing
  ◈ [06] API optimization — researched
  ○ [07] Final cleanup — planned
```

If a phase number starts with `999.`, render with a `🅿` marker and the label `(parking lot)`.

## Step 4 — Insights

If `SNAPSHOT.insights[]` is non-empty, print above the Next Up section:

```
Insights:
  ⚠ {insight.message}       (for severity: warn)
  ℹ {insight.message}       (for severity: info)
```

Do NOT hide insights. They exist because the CLI noticed something the workflow would otherwise gloss over.

## Step 5 — Recent decisions + blockers

- If `SNAPSHOT.decisions.length > 0`, print the last 3 (most recent first).
- If `SNAPSHOT.blockers.length > 0`, render each with ⚠, the blocker description, and its age. Compute age from `blocker.date` to now: if > 7 days, append `(⚡ {N} days old)` in amber; if > 30 days, append `(🔥 {N} days — stale)`. If no `date` field, render `(age unknown)`.

Omit a section entirely when its array is empty.

## Step 6 — Next Up (intent-tree)

Render `SNAPSHOT.routes[]` as a Route A/B/C menu. Each route is **one line** — the command is the thing you copy and run:

```
Next Up:

  [A] /rcode-execute 4
  [B] /rcode-plan 5
  [C] /rcode-audit-milestone 28 --fix-drift
  [C] /rcode-complete-milestone
```

Format: `  [{letter}] {command}` — no label, no arrow, no indented second line. The command already contains the relevant arguments (phase number, count, flags). Group routes by letter; multiple routes sharing a letter appear on consecutive lines. If there are no routes, print the fallback suggestion from the CLI output.

</process>

## Success Criteria

- [ ] State read via `progress init` — no direct ROADMAP.md or SUMMARY.md parsing
- [ ] Drift insights surfaced if present
- [ ] Banner + dashboard printed
- [ ] Phases section shows symbols based on CLI-computed disk state
- [ ] Next Up is a route tree, not a single suggestion

## On Error

- **CLI not found:** "rcode install missing. Run: npx @hanzlaa/rcode install"
- **state.json invalid JSON:** report the CLI's exact error string — the CLI already has a clean error shape.
- **Unexpected shape:** fall back to the banner + "State present but unreadable. Try: node .rcode/bin/rcode-tools.cjs state read"

## Next Up

- `/rcode-next` — auto-advance to the next logical step based on current state
- `/rcode-do` — take action on what the status dashboard surfaced
