@andresmassello/uscha 1.51.3 → 1.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,168 +1,192 @@
1
- ---
2
- name: uscha-mirador
3
- description: >
4
- Bird's-eye status view ("mirador") of a spec-loop project: one glance at
5
- readiness, sub-scores, the phase path, invariants, QA loops and a readiness
6
- time-lapse. Runs `qa_ledger.py dashboard --json` (read-only, deterministic,
7
- zero LLM narration), injects that JSON into mirador.template.html, writes
8
- mirador.html at the project root and opens it. The skill WIRES, it does not
9
- calculate — every number comes from the ledger (truth-pass: a field with no
10
- source shows null and the template degrades, never invented). Invoke for
11
- "mirador", "vista de estado", "bird's-eye", "dashboard del proyecto".
12
- allowed-tools: Read, Write, Glob, Grep, Bash
13
- ---
14
-
15
- # uscha-mirador — bird's-eye status view
16
-
17
- Paints the REAL state of the project at a glance. It does not narrate or estimate: it
18
- wires the JSON the engine emits into the template. Read-only.
19
-
20
- ## Contract
21
-
22
- - **Source of truth:** `qa_ledger.py dashboard --json` — aggregates ONLY state the
23
- ledger already has (readiness, subscores, phases, acceptance, adrs, inv, layers, loops,
24
- snapshots, evidence). A field with no source comes out `null`/`[]`; the template
25
- degrades. **A datum is never invented.**
26
- - **Template:** `mirador.template.html` (in this folder). The data block lives between
27
- `/*MIRADOR_DATA_START*/` and `/*MIRADOR_DATA_END*/`; the sample `const DATA` it ships
28
- with is the **offline fallback**. The skill replaces ONLY that region; it does not
29
- touch the rest of the HTML.
30
- - **Project name (top):** the mirador shows the project name prominently at the top, from
31
- `config.project` in `uscha.config.json` (set it in `uscha-discovery`); if unset, it falls
32
- back to the joined repo names (truth-pass — no invented name).
33
- - **Execution policy (bird's-eye):** `dashboard --json` also exposes
34
- `execution_policy` plus `phase.execution` for each trail node. This is routing metadata
35
- from `config.defaults.execution_policy` (`method`, `tier`, `model`, `effort`,
36
- `uncorrelated`), not a score. The template renders it as a separate panel so the human
37
- sees which methodology/model/effort is selected per phase without mixing it into
38
- readiness.
39
- - **Discovery intake:** `dashboard --json` carries `discovery_intake` from readiness:
40
- open `production_findings`, `spec_doubts`, and `spec_change_requests`. The current template keeps the top-level
41
- verdict honest through readiness/caps; future panels may render the intake directly.
42
- - **ADR experiments:** ADR rows may carry `adr_status: "experiment"`, `review_by`,
43
- `review_trigger`, `experiment_valid`, `experiment_missing`, and `expired`; top-level
44
- `adr_experiments` summarizes open/malformed/expired experiments. This is advisory
45
- visibility for measured hypotheses, not readiness scoring.
46
- - **Session telemetry (optional, vendor-reported):** if `.uscha/telemetry.jsonl` exists,
47
- the skill aggregates it and MERGES a `telemetry` object into `DATA`. This is the ONE
48
- panel that is **narrated by the vendor (Claude Code), not measured by the engine** —
49
- tokens, wall time, model, effort — so it renders in a **segregated strip** labeled as
50
- such, never mixed with the measured panels. `dashboard --json` NEVER emits it; it enters
51
- only through this adapter. Absent file → no strip (degrades). This is the doctrinal
52
- line: telemetry is neither a fact-gate nor a guess-advisor, so it must not dilute
53
- *measured beats narrated*.
54
-
55
- ## Flow
56
-
57
- 1. **Resolve the engine.** Use the first one that exists:
58
- - `./.claude/skills/uscha-devloop/qa_ledger.py` (per-project install)
59
- - `~/plugins/uscha/skills/uscha-devloop/qa_ledger.py` (Codex plugin install)
60
- - `~/.codex/skills/uscha-devloop/qa_ledger.py` (Codex raw-skills install)
61
- - `~/.claude/skills/uscha-devloop/qa_ledger.py` (Claude global install)
62
-
63
- 2. **Resolve the ledger.** `QA-LEDGER.json` in the cwd (or the `--ledger` the user
64
- points to). If it does not exist, warn: you have to run `uscha-devloop` (or
65
- `qa_ledger.py init`) first — with no ledger there is no state to look at.
66
-
67
- (`<skill-dir>` below = this folder: `.claude/skills/uscha-mirador/` per-project, or `~/plugins/uscha/skills/uscha-mirador/` / `~/.codex/skills/uscha-mirador/` / `~/.claude/skills/uscha-mirador/` global.)
68
-
69
- 3. **(Optional) record this session's telemetry.** For the vendor-telemetry strip, append
70
- the current Claude Code session to the sidecar:
71
- ```bash
72
- python3 <skill-dir>/telemetry-extract.py <path-to-CC-transcript.jsonl>
73
- ```
74
- It **upserts by session** (safe to re-run — a watch loop won't inflate the totals). Skip
75
- this for a pure measured view.
76
-
77
- 4. **Render `mirador.html`** with the standalone renderer — it runs `dashboard --json`,
78
- merges the sidecar telemetry if present, injects `const DATA`, writes the file, prints its
79
- absolute path (`OPEN IT: ...`), and opens it in the default browser **the first time it
80
- creates the file** (see step 5 — a re-render updates the open tab instead). From the project root,
81
- with no long paths — `--engine` and `--template` default to the renderer's sibling skill
82
- files (kit 1.41.2):
83
- ```bash
84
- python3 <skill-dir>/mirador-render.py --ledger QA-LEDGER.json
85
- ```
86
- The engine stays model-agnostic — telemetry is merged by the renderer (the adapter), NOT
87
- by `dashboard`. If the ledger is missing, warn and stop (run `uscha-devloop` first). The
88
- time-lapse feeds from `qa_ledger.py readiness --record` — since kit 1.47.0 the dev-loop
89
- records at every pass close, so history accumulates without extra ceremony.
90
-
91
- 5. **Where to look:** the renderer opens `mirador.html` **once — only the first time it is
92
- created** — and always prints its absolute path on the `OPEN IT:` line; surface that path to
93
- the operator. Re-rendering (this skill invoked again on a later pass, or the watch loop)
94
- rewrites the SAME file, and the page's built-in auto-refresh reloads the already-open tab in
95
- place, so a re-render never spawns a new browser tab. On a fresh session the file is already
96
- on disk, so nothing pops — open the printed path once, or pass `--open` (`uscha mirador
97
- --open`) to force a reopen when you closed the tab. `--no-open` suppresses opening
98
- everywhere and wins over `--open` (headless/CI, or the watch loop, which passes it);
99
- `--refresh 0` writes a frozen snapshot with no auto-reload.
100
-
101
- ## For a human at a terminal: `uscha mirador`
102
-
103
- The one-liner above is what THIS skill runs. A human who just wants the dashboard — without a
104
- Claude Code session — has a zero-friction verb instead (kit 1.43.0): from the project root,
105
-
106
- ```bash
107
- uscha mirador # render + open, defaults to the QA-LEDGER.json convention
108
- uscha mirador --watch # live second-screen view (auto-refresh, one self-reloading tab)
109
- npx @andresmassello/uscha mirador # same, no install
110
- ```
111
-
112
- No python, no paths: the verb resolves the engine, template and ledger on its own.
113
-
114
- ## Live second-screen view
115
-
116
- For a mirador that updates while you keep coding in the terminal, run the watch loop in a
117
- spare terminal and open `mirador.html` on a second monitor (or just use `uscha mirador --watch`):
118
-
119
- ```bash
120
- # Windows: powershell -NoProfile -File <skill-dir>\mirador-watch.ps1 -Interval 30
121
- # Unix: bash <skill-dir>/mirador-watch.sh 30
122
- ```
123
-
124
- It re-renders `mirador.html` every N seconds (default 30) from the current ledger, rendered
125
- with a matching `<meta http-equiv="refresh">` so the open page reloads on its own — **no
126
- server**. It is only as live as the **ledger**: the picture changes at the dev-loop's
127
- measured checkpoints (snapshots, gates, `readiness --record`), not per keystroke. Honest by
128
- design — it shows measured state, which changes at measured moments.
129
-
130
- ## Session telemetry — sidecar contract
131
-
132
- `.uscha/telemetry.jsonl` is an **append-only** file, one JSON object per session/run:
133
-
134
- ```jsonl
135
- {"at": "2026-07-05T23:40:00Z", "model": "claude-opus-4-8", "tokens_in": 240000, "tokens_out": 41000, "ms": 4200000, "by_model": [{"model": "claude-opus-4-8", "tokens_in": 240000, "tokens_out": 41000}], "note": "mirador build"}
136
- ```
137
-
138
- `effort` and `note` are **optional** and are NOT produced by `telemetry-extract.py` (a Claude
139
- Code transcript carries no reliable effort label) — add them by hand if you want them; the
140
- strip shows `—` when `effort` is absent. `by_model` is per-**tokens** (session-level `ms` only).
141
-
142
- - **Who writes it:** the AGENT / operator, NEVER the engine (the engine is model-agnostic
143
- and cannot see tokens). Two honest sources:
144
- - **`telemetry-extract.py <transcript.jsonl>`** (shipped in this skill folder): parses a
145
- Claude Code session transcript — each assistant turn carries a `usage` block
146
- (`input_tokens` / `cache_*_input_tokens` / `output_tokens`) and a `model` — sums per
147
- model, computes wall time from the timestamps, and appends one line (with a `by_model`
148
- breakdown). Real, vendor-native data. Best-effort: unknown/older schemas degrade, never
149
- crash; no usage found → nothing appended.
150
- - **Manual append**: paste the session's numbers from Claude Code's own cost view.
151
- - **Persistence:** the file itself IS the history (portable, diffable, greppable). Add it to
152
- the project's `.gitignore` — it is per-machine telemetry, not repo state. (A pure-client
153
- alternative is `localStorage` inside `mirador.html`, but the sidecar survives regeneration,
154
- so it is the default.)
155
- - **Boundary (non-negotiable):** this is the ONLY place vendor-narrated numbers enter the
156
- mirador. They are shown, never gated, never fed into readiness — telemetry answers "what
157
- did it cost", the measured panels answer "is it correct". Keep them apart.
158
-
159
- ## Rules
160
-
161
- - **Zero computation in the skill.** The numbers come from the ledger. If a panel looks
162
- empty, it's because the engine doesn't have that source yet (truth-pass), not because
163
- painting it was missed.
164
- - **Read-only.** The skill does not run gates or modify the ledger. `dashboard` is
165
- read-only; the only one that writes (opt-in) is `readiness --record`, and that is the
166
- loop's decision, not this skill's.
167
- - **`mirador.html` is a generated artifact** — suggest adding it to the project's
168
- `.gitignore`; it regenerates whenever you want.
1
+ ---
2
+ name: uscha-mirador
3
+ description: >
4
+ Bird's-eye status view ("mirador") of a spec-loop project: one glance at
5
+ readiness, sub-scores, the phase path, invariants, QA loops and a readiness
6
+ time-lapse. Runs `qa_ledger.py dashboard --json` (read-only, deterministic,
7
+ zero LLM narration), injects that JSON into mirador.template.html, writes
8
+ mirador.html at the project root and opens it. The skill WIRES, it does not
9
+ calculate — every number comes from the ledger (truth-pass: a field with no
10
+ source shows null and the template degrades, never invented). Invoke for
11
+ "mirador", "vista de estado", "bird's-eye", "dashboard del proyecto".
12
+ allowed-tools: Read, Write, Glob, Grep, Bash
13
+ ---
14
+
15
+ # uscha-mirador — bird's-eye status view
16
+
17
+ Paints the REAL state of the project at a glance. It does not narrate or estimate: it
18
+ wires the JSON the engine emits into the template. Read-only.
19
+
20
+ ## Orientation markers (non-negotiable)
21
+
22
+ The operator must never have to ask "where am I?" or "what happens now?".
23
+
24
+ This skill is a **one-shot read-only readout**: its block IS the answer. It therefore does NOT
25
+ take the conversational close block — that would be exactly the padding this skill forbids.
26
+ It carries the two minimal markers instead.
27
+
28
+ **Open with a breadcrumb:**
29
+
30
+ `[uscha · mirador · step <n> → <target>]`
31
+
32
+ **End with the two routing lines, and nothing else:**
33
+
34
+ ```
35
+ Next: <the next action, derived from what this readout just showed>
36
+ Run: <the exact command or skill to invoke>
37
+ ```
38
+
39
+ `Next` is **derived** from the state you just read — never copied from a fixed route,
40
+ including any `Flow:` line in this file. If nothing is actionable, say that plainly rather
41
+ than inventing a step. Keep the CONTENT in the conversation's language and the labels
42
+ (`Next`, `Run`) verbatim — the smoke suite checks for them.
43
+
44
+ ## Contract
45
+
46
+ - **Source of truth:** `qa_ledger.py dashboard --json` — aggregates ONLY state the
47
+ ledger already has (readiness, subscores, phases, acceptance, adrs, inv, layers, loops,
48
+ snapshots, evidence). A field with no source comes out `null`/`[]`; the template
49
+ degrades. **A datum is never invented.**
50
+ - **Template:** `mirador.template.html` (in this folder). The data block lives between
51
+ `/*MIRADOR_DATA_START*/` and `/*MIRADOR_DATA_END*/`; the sample `const DATA` it ships
52
+ with is the **offline fallback**. The skill replaces ONLY that region; it does not
53
+ touch the rest of the HTML.
54
+ - **Project name (top):** the mirador shows the project name prominently at the top, from
55
+ `config.project` in `uscha.config.json` (set it in `uscha-discovery`); if unset, it falls
56
+ back to the joined repo names (truth-pass — no invented name).
57
+ - **Execution policy (bird's-eye):** `dashboard --json` also exposes
58
+ `execution_policy` plus `phase.execution` for each trail node. This is routing metadata
59
+ from `config.defaults.execution_policy` (`method`, `tier`, `model`, `effort`,
60
+ `uncorrelated`), not a score. The template renders it as a separate panel so the human
61
+ sees which methodology/model/effort is selected per phase without mixing it into
62
+ readiness.
63
+ - **Discovery intake:** `dashboard --json` carries `discovery_intake` from readiness:
64
+ open `production_findings`, `spec_doubts`, and `spec_change_requests`. The current template keeps the top-level
65
+ verdict honest through readiness/caps; future panels may render the intake directly.
66
+ - **ADR experiments:** ADR rows may carry `adr_status: "experiment"`, `review_by`,
67
+ `review_trigger`, `experiment_valid`, `experiment_missing`, and `expired`; top-level
68
+ `adr_experiments` summarizes open/malformed/expired experiments. This is advisory
69
+ visibility for measured hypotheses, not readiness scoring.
70
+ - **Session telemetry (optional, vendor-reported):** if `.uscha/telemetry.jsonl` exists,
71
+ the skill aggregates it and MERGES a `telemetry` object into `DATA`. This is the ONE
72
+ panel that is **narrated by the vendor (Claude Code), not measured by the engine** —
73
+ tokens, wall time, model, effort — so it renders in a **segregated strip** labeled as
74
+ such, never mixed with the measured panels. `dashboard --json` NEVER emits it; it enters
75
+ only through this adapter. Absent file → no strip (degrades). This is the doctrinal
76
+ line: telemetry is neither a fact-gate nor a guess-advisor, so it must not dilute
77
+ *measured beats narrated*.
78
+
79
+ ## Flow
80
+
81
+ 1. **Resolve the engine.** Use the first one that exists:
82
+ - `./.claude/skills/uscha-devloop/qa_ledger.py` (per-project install)
83
+ - `~/plugins/uscha/skills/uscha-devloop/qa_ledger.py` (Codex plugin install)
84
+ - `~/.codex/skills/uscha-devloop/qa_ledger.py` (Codex raw-skills install)
85
+ - `~/.claude/skills/uscha-devloop/qa_ledger.py` (Claude global install)
86
+
87
+ 2. **Resolve the ledger.** `QA-LEDGER.json` in the cwd (or the `--ledger` the user
88
+ points to). If it does not exist, warn: you have to run `uscha-devloop` (or
89
+ `qa_ledger.py init`) first — with no ledger there is no state to look at.
90
+
91
+ (`<skill-dir>` below = this folder: `.claude/skills/uscha-mirador/` per-project, or `~/plugins/uscha/skills/uscha-mirador/` / `~/.codex/skills/uscha-mirador/` / `~/.claude/skills/uscha-mirador/` global.)
92
+
93
+ 3. **(Optional) record this session's telemetry.** For the vendor-telemetry strip, append
94
+ the current Claude Code session to the sidecar:
95
+ ```bash
96
+ python3 <skill-dir>/telemetry-extract.py <path-to-CC-transcript.jsonl>
97
+ ```
98
+ It **upserts by session** (safe to re-run — a watch loop won't inflate the totals). Skip
99
+ this for a pure measured view.
100
+
101
+ 4. **Render `mirador.html`** with the standalone renderer — it runs `dashboard --json`,
102
+ merges the sidecar telemetry if present, injects `const DATA`, writes the file, prints its
103
+ absolute path (`OPEN IT: ...`), and opens it in the default browser **the first time it
104
+ creates the file** (see step 5 — a re-render updates the open tab instead). From the project root,
105
+ with no long paths — `--engine` and `--template` default to the renderer's sibling skill
106
+ files (kit 1.41.2):
107
+ ```bash
108
+ python3 <skill-dir>/mirador-render.py --ledger QA-LEDGER.json
109
+ ```
110
+ The engine stays model-agnostic — telemetry is merged by the renderer (the adapter), NOT
111
+ by `dashboard`. If the ledger is missing, warn and stop (run `uscha-devloop` first). The
112
+ time-lapse feeds from `qa_ledger.py readiness --record` — since kit 1.47.0 the dev-loop
113
+ records at every pass close, so history accumulates without extra ceremony.
114
+
115
+ 5. **Where to look:** the renderer opens `mirador.html` **once — only the first time it is
116
+ created** — and always prints its absolute path on the `OPEN IT:` line; surface that path to
117
+ the operator. Re-rendering (this skill invoked again on a later pass, or the watch loop)
118
+ rewrites the SAME file, and the page's built-in auto-refresh reloads the already-open tab in
119
+ place, so a re-render never spawns a new browser tab. On a fresh session the file is already
120
+ on disk, so nothing pops — open the printed path once, or pass `--open` (`uscha mirador
121
+ --open`) to force a reopen when you closed the tab. `--no-open` suppresses opening
122
+ everywhere and wins over `--open` (headless/CI, or the watch loop, which passes it);
123
+ `--refresh 0` writes a frozen snapshot with no auto-reload.
124
+
125
+ ## For a human at a terminal: `uscha mirador`
126
+
127
+ The one-liner above is what THIS skill runs. A human who just wants the dashboard — without a
128
+ Claude Code session — has a zero-friction verb instead (kit 1.43.0): from the project root,
129
+
130
+ ```bash
131
+ uscha mirador # render + open, defaults to the QA-LEDGER.json convention
132
+ uscha mirador --watch # live second-screen view (auto-refresh, one self-reloading tab)
133
+ npx @andresmassello/uscha mirador # same, no install
134
+ ```
135
+
136
+ No python, no paths: the verb resolves the engine, template and ledger on its own.
137
+
138
+ ## Live second-screen view
139
+
140
+ For a mirador that updates while you keep coding in the terminal, run the watch loop in a
141
+ spare terminal and open `mirador.html` on a second monitor (or just use `uscha mirador --watch`):
142
+
143
+ ```bash
144
+ # Windows: powershell -NoProfile -File <skill-dir>\mirador-watch.ps1 -Interval 30
145
+ # Unix: bash <skill-dir>/mirador-watch.sh 30
146
+ ```
147
+
148
+ It re-renders `mirador.html` every N seconds (default 30) from the current ledger, rendered
149
+ with a matching `<meta http-equiv="refresh">` so the open page reloads on its own — **no
150
+ server**. It is only as live as the **ledger**: the picture changes at the dev-loop's
151
+ measured checkpoints (snapshots, gates, `readiness --record`), not per keystroke. Honest by
152
+ design — it shows measured state, which changes at measured moments.
153
+
154
+ ## Session telemetry — sidecar contract
155
+
156
+ `.uscha/telemetry.jsonl` is an **append-only** file, one JSON object per session/run:
157
+
158
+ ```jsonl
159
+ {"at": "2026-07-05T23:40:00Z", "model": "claude-opus-4-8", "tokens_in": 240000, "tokens_out": 41000, "ms": 4200000, "by_model": [{"model": "claude-opus-4-8", "tokens_in": 240000, "tokens_out": 41000}], "note": "mirador build"}
160
+ ```
161
+
162
+ `effort` and `note` are **optional** and are NOT produced by `telemetry-extract.py` (a Claude
163
+ Code transcript carries no reliable effort label) — add them by hand if you want them; the
164
+ strip shows `—` when `effort` is absent. `by_model` is per-**tokens** (session-level `ms` only).
165
+
166
+ - **Who writes it:** the AGENT / operator, NEVER the engine (the engine is model-agnostic
167
+ and cannot see tokens). Two honest sources:
168
+ - **`telemetry-extract.py <transcript.jsonl>`** (shipped in this skill folder): parses a
169
+ Claude Code session transcript — each assistant turn carries a `usage` block
170
+ (`input_tokens` / `cache_*_input_tokens` / `output_tokens`) and a `model` — sums per
171
+ model, computes wall time from the timestamps, and appends one line (with a `by_model`
172
+ breakdown). Real, vendor-native data. Best-effort: unknown/older schemas degrade, never
173
+ crash; no usage found → nothing appended.
174
+ - **Manual append**: paste the session's numbers from Claude Code's own cost view.
175
+ - **Persistence:** the file itself IS the history (portable, diffable, greppable). Add it to
176
+ the project's `.gitignore` — it is per-machine telemetry, not repo state. (A pure-client
177
+ alternative is `localStorage` inside `mirador.html`, but the sidecar survives regeneration,
178
+ so it is the default.)
179
+ - **Boundary (non-negotiable):** this is the ONLY place vendor-narrated numbers enter the
180
+ mirador. They are shown, never gated, never fed into readiness — telemetry answers "what
181
+ did it cost", the measured panels answer "is it correct". Keep them apart.
182
+
183
+ ## Rules
184
+
185
+ - **Zero computation in the skill.** The numbers come from the ledger. If a panel looks
186
+ empty, it's because the engine doesn't have that source yet (truth-pass), not because
187
+ painting it was missed.
188
+ - **Read-only.** The skill does not run gates or modify the ledger. `dashboard` is
189
+ read-only; the only one that writes (opt-in) is `readiness --record`, and that is the
190
+ loop's decision, not this skill's.
191
+ - **`mirador.html` is a generated artifact** — suggest adding it to the project's
192
+ `.gitignore`; it regenerates whenever you want.
@@ -18,6 +18,46 @@ disable-model-invocation: false
18
18
  opposite. The system already runs; its observable behavior is the ground truth. **You do
19
19
  not invent anything — you characterize what is already there, as facts.**
20
20
 
21
+ ## Orientation markers (non-negotiable)
22
+
23
+ The operator must never have to ask "where am I?" or "what happens now?". Two markers, always.
24
+ They are navigation, not ceremony: one line per turn, one block at the end.
25
+
26
+ **Open every turn with a breadcrumb**, then the content:
27
+
28
+ `[uscha · reverse-discovery · <step> → <target>]`
29
+
30
+ - `<step>` — `Q<n>` for a question, `pass <n>` for a loop iteration, `step <n>` otherwise.
31
+ Count what has actually happened. **Never write a denominator** (`Q4/12`): this phase
32
+ converges, its length is not known in advance, and an invented total is exactly the kind of
33
+ narrated number the method forbids. **When the ledger already measures the count** (the QA
34
+ loop's `loop_count`), use the measured number — never keep a parallel tally of your own.
35
+ - `<target>` — the artifact this turn feeds (`SPEC`, `ADR-003`, `ACCEPTANCE`, `LEDGER`,
36
+ `RECEIVED`, ...). Drop `→ <target>` only when the turn genuinely feeds none.
37
+
38
+ **Close with the close block ONCE, when the skill finishes** — not on every turn. Ending
39
+ without it is a defect, even when the phase converged cleanly:
40
+
41
+ ```
42
+ [uscha · reverse-discovery · CLOSED]
43
+ Produced: <files actually written, or "nothing">
44
+ Blocks: <what stands between here and the next phase, or "nothing">
45
+ Next: <the next action, and why it is that one>
46
+ Run: <the exact command or skill to invoke>
47
+ ```
48
+
49
+ This is **not** the implementation handoff some skills also emit: that one is a prompt for
50
+ whoever implements next, this one is navigation for the human operator, and both can appear.
51
+
52
+ `Blocks` and `Next` are **derived from the state you just produced** — never copied from a
53
+ fixed route, **including any `Flow:` line in this file**. Those lines are the nominal path;
54
+ open ADR experiments, an unclosed spike, an unapproved golden or a red gate all change what
55
+ genuinely comes next, and the derived answer wins. If the next phase cannot start yet, name it
56
+ and say exactly what unblocks it.
57
+
58
+ Keep the CONTENT in the conversation's language, but keep the labels (`CLOSED`, `Produced`,
59
+ `Blocks`, `Next`, `Run`) verbatim — they are the method's vocabulary and the smoke checks them.
60
+
21
61
  ## The one non-negotiable: produce ONLY facts
22
62
 
23
63
  A system map (from static analysis) and a golden suite (byte-captured) are FACTS —
@@ -94,6 +134,8 @@ Flow (migration): `uscha-reverse-discovery` (facts) → human writes SPEC + `/us
94
134
  module decisions) → `/uscha-devloop` (restructure; `golden-diff` + `ApplicationModules.verify()`
95
135
  stay green the whole way) → readiness + human gate.
96
136
 
137
+ That route is the **nominal** one, not the answer: the `Next:`/`Run:` you emit in the close block are DERIVED from the state you actually produced, and override it whenever an open experiment, an unclosed spike, an unapproved golden or a red gate stands in between.
138
+
97
139
  ## Relationship to the other skills
98
140
 
99
141
  - **discovery** (greenfield): you PROPOSE the shape from an idea. **reverse-discovery**