1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
|
# 40 — New-version triage (one command)
> **Status: in development (2026-10-03).** Implemented, tested and measured on
> the TU104 570.144 image; the measured value proof is section 5. Interfaces
> and report fields may still change. Simulator-only: never touches hardware,
> GPU, mdev, a kernel module or a guest; nothing is downloaded.
>
> **Audience:** agents and maintainers of risc-v-gsp-rm-debugger.
>
> This document is public-safe: it describes components, behaviour and
> measured numbers only.
---
## 1. Why this exists (U46)
The program has one goal: cut the time from a new NVIDIA RM driver / GSP
firmware release to supported in `vgsp`. Today a new image is triaged by hand
by reading docs/07 P1 and invoking four different tools in sequence (probe,
native boot, A/B, version diff), then collecting session paths and writing a
summary.
`harness/triage.py` turns that into **one bounded command** that reuses the
existing tools - it does not reimplement any of them:
| Step | Reuses | Answers |
|---|---|---|
| `identity` | `greeneye.elf`, `sha256` | what is the image, which version, which baseline |
| `probe` | `harness/sim_qemu_line.py:run_qemu_baseline` (the v0.1 probe path) | where does it first fault / first touch under QEMU |
| `native_boot` | `python3 -m sim.gsp_boot` (S1 device model + boot ladder) | how far does the native ladder get (B0–B4) |
| `ab_eval` | `harness/sim_qemu_line.py:run_harness` | QEMU vs native A/B, determinism, frozen thresholds |
| `version_diff` | `harness/version_diff.py` (only with `--baseline`) | image/symbol/corpus/probe/behavior delta, RM 610 gate respected |
| `features` | none (introspection) | hooks/watch/memory/session API, native sim, TCG plugin, MCP, demo |
| `support_readiness` | derived | blockers and ordered next actions for `vgsp` support work |
Every step is wrapped: a failing step is recorded as `status: error`, the
remaining steps still run, and the report is still written. Every session a
step used is listed with its sha256 hashes.
---
## 2. Usage
Run from the tool root (`open-iov/debug/risc-v-gsp-rm-vm`):
```bash
# Plan only (no targets opened, no --out created)
python3 harness/triage.py \
--firmware ../../firmware/57X-GSP/570.144/gsp-570.144.fwimage.bin \
--version 570.144 --out dumps/triage-570.144 --dry-run
# Single new image: identity + probe + bootstrap ladder + A/B + features
python3 harness/triage.py \
--firmware <new.fwimage.bin> --version <label> --out dumps/triage-<label>
# With a baseline: adds the full version diff (docs/21)
python3 harness/triage.py \
--firmware <new.fwimage.bin> --version <new-label> \
--baseline <old.fwimage.bin> --baseline-label <old-label> \
--out dumps/triage-<old>-<new>
# One command via the launcher or make
./risc-v-gsp-rm-debugger.sh triage --firmware <new> --out dumps/triage-new
make triage FW=<new> OUT=dumps/triage-new TRIAGE_ARGS="--baseline <old>"
```
Flags: `--firmware` (required), `--baseline`, `--version`, `--baseline-label`,
`--out` (required unless `--dry-run`), `--budget` (native instructions per
attempt, default 200000, hard cap 2000000), `--qemu-duration` (default 0.5s),
`--step-timeout` (per-step wall-clock net, default 300s), `--release`,
`--approval-token`, `--dry-run`.
Safety: `--dry-run` opens no target and creates no `--out`. The RM 610 gate
runs first in every mode (docs/23) and refuses with exit `3`; labels checked
are `--release`, `--version`, `--baseline-label` and both file basenames.
Exit codes: `0` report written (skipped steps included), `1` at least one step
errored, `2` tool/input error (or firmware absent), `3` RM 610 refusal.
Output tree under `--out`:
```text
<out>/
triage-report.json stable machine-readable report
triage-report.md rendered report
sessions/qemu-probe/ QEMU probe session
sessions/native-boot/ S1 boot-ladder session
ab-eval/ docs/37 A/B report + sim-qemu-line.json|.md + sessions/
version-diff/ only with --baseline (docs/21 tree)
```
---
## 3. Report schema (`greeneye-new-version-triage/1`)
```json
{
"format": "greeneye-new-version-triage/1",
"tool": "harness/triage.py",
"generated_at": "2026-10-03T04:44:24Z",
"rm610_gate": {"status": "passed", "labels": ["570.144"]},
"input": {
"firmware": {"path": "...", "sha256": "...", "size": 28528288,
"version": "570.144W", "version_source": "gsp_version.txt sidecar"},
"baseline": null, "baseline_supplied": false,
"budget": 200000, "qemu_duration": 0.5, "triage_command": "..."
},
"thresholds": {"frozen_on": "2026-10-03", "manual_baseline_s": 1800.0,
"triage_wall_s_max": 600.0},
"steps": [
{"name": "identity", "status": "ok", "wall_s": 0.099, "firmware": {...}, "elf": {...}},
{"name": "probe", "status": "ok", "rung": "pre-B0", "first_fault": {...},
"stopped_pc": 0, "sessions": [...]},
{"name": "native_boot", "status": "ok", "rung": "B2",
"instructions_executed": 14682, "stop": {...}},
{"name": "ab_eval", "status": "ok", "native_rung": "B2",
"native_identical": true, "above_qemu_line": true, "verdict": "above"},
{"name": "version_diff", "status": "skipped", "reason": "no --baseline supplied"},
{"name": "features", "status": "ok", "checks": {...}, "unavailable": []}
],
"sessions": [{"step": "probe", "name": "qemu-probe", "dir": "sessions/qemu-probe",
"present": true, "hashes": {"session.json": "...", "events.jsonl": "...", "summary.md": "..."}}],
"support_readiness": {"verdict": "sim-observable", "baseline_compared": false,
"observable_rung": "B2", "blockers": [], "next_actions": ["..."]},
"threshold_checks": {"triage_wall_s": 2.781, "triage_wall_s_max": 600.0,
"wall_within_max": true, "manual_baseline_s": 1800.0,
"speedup_x": 647.2, "beats_manual_baseline": true,
"required_steps_missing": []},
"wall_s": 2.781,
"artifacts": {"report_json": "<out>/triage-report.json", "report_md": "<out>/triage-report.md"}
}
```
The `wall_s`/`threshold_checks` values above are the **measured 2026-10-03
sample** and are host-load dependent, not fixed constants.
Key fields:
* `steps[].status` is `ok | skipped | error`; `skipped` carries a reason and
never fails the run.
* `support_readiness.verdict` is `blocked` (identity/step errors),
`first-touch-only` (no runtime observation yet) or `sim-observable` (native
ladder reached `B2`+, the point where the firmware runs past boot and can be
instrumented).
* `support_readiness.next_actions` is the ordered work list for `vgsp` support
(device-model gaps, symbol DBs, A/B above-the-line work, missing inputs).
* `sessions[].hashes` is the docs/07 evidence-checklist hash list; attach it
with the recorded sessions.
---
## 4. Worked example — 570.144 (measured 2026-10-03)
Commands (real, read-only; `/usr/bin/time` around the wrapper):
```bash
./risc-v-gsp-rm-debugger.sh triage \
--firmware ../../firmware/57X-GSP/570.144/gsp-570.144.fwimage.bin \
--version 570.144 --out dumps/triage-570.144
```
Measured output (trimmed):
```text
[triage] identity: status=ok
[triage] probe: status=ok reason=ok
[triage] native_boot: status=ok
[triage] ab_eval: status=ok
[triage] version_diff: status=skipped reason=no --baseline supplied
[triage] features: status=ok
[triage] readiness: sim-observable (baseline_compared=False)
[triage] next: native ladder is at B2 (runtime-observable): inspect the milestone/stop with hooks ...
[triage] next: native A/B is not yet above the QEMU line (verdict=above_lenient_only): device model ...
[triage] next: re-run with --baseline <previous.fwimage> for the symbol/behavior delta ...
[triage] wall: 2.781s vs manual baseline 1800.0s (speedup 647.2x)
```
The `2.781s`/`647.2x` line is the **measured 2026-10-03 sample** (host-load
dependent, not a fixed constant).
What the report recorded:
| Step | Measured | Meaning |
|---|---|---|
| identity | `570.144W` via `gsp_version.txt`, sha256 + 28,528,288 bytes | image paired and hashed before any run |
| probe | QEMU first fault `pc_fw 0x4009014`, load access at `0x2000000000000A00` | matches the docs/37 QEMU reference first touch |
| native_boot | rung **B2**, 14,682 instructions, stop fault `pc_fw 0x400EA0C`, 0 unknown MMIO | S1 ladder is two rungs past the QEMU fault; boot shim consumed, relocation milestone hit |
| ab_eval | native `B2` (14,682 instructions, 0 unknown MMIO), identical across the repeat, `above_qemu_line: true`, verdict `above` | post-S1 re-run (2026-10-03, later): the discovered `sim/profiles` model + shim now satisfy the docs/37 line contract; the pre-S1 run was `B0`/`above_lenient_only` |
| features | greeneye API, native backend, boot ladder, A/B, version_diff, TCG plugin, MCP, demo, QEMU all present | capability surface for the follow-up work |
Post-S1 re-run (2026-10-03, later; same command, after S1 and the harness
wiring landed): `ab_eval` reports native rung **B2**, all five frozen
thresholds true and `above_qemu_line: true`; the "native A/B is not yet above
the QEMU line" next-action line no longer appears. Wall ≈2.7 s
(host-load dependent). The pre-S1 trace above is kept as the recorded
before/after evidence.
Baseline variant (same image both sides, an unchanged-version rehearsal with
the docs/21 path):
```bash
./risc-v-gsp-rm-debugger.sh triage \
--firmware ../../firmware/57X-GSP/570.144/gsp-570.144.fwimage.bin \
--baseline ../../firmware/57X-GSP/570.144/gsp-570.144.fwimage.bin \
--version 570.144 --baseline-label 570.144 --out dumps/triage-570.144-baseline
```
Measured (2026-10-03, host-load dependent): **11.388s** internal wall
(11.64s including interpreter startup);
`version_diff` = 8.526s, sections `image/probe/behavior: ok`,
`symbols/corpus: skipped` with reasons; image self-diff `same: true`; 7 session
directories hashed (probe, native boot, 2 A/B native, A/B QEMU, version-diff
probe + behavior). Readiness stayed `sim-observable`, `baseline_compared:
true`, with next actions for the missing symbol/corpus inputs.
Frozen thresholds (recorded in `harness/triage.py` on 2026-10-03 **before**
the runs, per handoff §14.5): manual baseline `1800s`, triage wall max
`600s`. Result: `wall_within_max: true`, `beats_manual_baseline: true`,
speedup `647x` (single image) / `158x` (with baseline) — both wall times are
**measured 2026-10-03 samples (host-load dependent)**, not fixed constants. The
manual baseline is
a conservative understatement of the steps replaced (read docs/07 P1, choose
budgets, run probe + boot ladder + A/B, run version diff, collect session
hashes and write the summary for one image).
---
## 5. Value proof and its limits
* The frozen contract is in the report itself (`thresholds`,
`threshold_checks`); the same numbers are restated in the module docstring
and here. Never move them silently.
* The measured numbers above are from this checkout on 2026-10-03; reproduce
with the exact commands in section 4.
* **Conservative baseline:** 1800s is an *estimate of manual effort*, not a
timed human study. The speedup numbers are reported against it, and the
report flags them as such.
* **What the run proves:** one bounded command produces the identity, probe,
boot-ladder, A/B and capability evidence with hashed sessions in seconds -
the mechanical part of docs/07 P1.
* **What it does not prove:** that the remaining human work (interpreting the
deltas, extending the device model, the accuracy loop, the `vgsp` change) is
automated; it is not, and the next-actions list is where it stays explicit.
---
## 6. Release-to-support mapping
| Triage output | Next workflow (docs) |
|---|---|
| identity + hash + version | docs/07 P1 step 1, docs/22 pairing checks, docs/28 sweep input |
| probe first fault / first touch | docs/07 P1 step 2, docs/24 device map harvest |
| native boot rung + stop | docs/35 §3.3 ladder; the `vgsp` support scope starts at `B2`+ |
| A/B verdict | docs/37 line contract (U50) |
| version_diff sections + symbol/corpus skips | docs/21, docs/14 §6 evidence pack |
| readiness next actions | docs/07 P1.7 acceptance, the actual `vgsp` support work items |
| RM 610 gate | docs/23 (never bypassed) |
---
## 7. Not verified (explicit)
* **No real 570.211+ new-version pair exists locally**; the cross-version
delta path is exercised only by the self-diff rehearsal in section 4.
* **Symbols and corpus are skipped for raw `.fwimage` targets** (no `.symtab`,
no Ghidra exports supplied): the handler-inventory delta is not measured
until those inputs are supplied.
* **The S4 A/B verdict is `above` on the frozen checks after S1 landed**
(B2, documented device model + shim, deterministic, within the wall
bound); B3/B4 are not reached and triage makes no "beats QEMU" claim beyond
the documented rung contract (`above_lenient_only` was the pre-S1 result).
* **Fidelity:** L0/L1 execution facts only; no L2 timing and no full L3
device-environment claims (docs/06, docs/36). Cycles are modeled; the boot
shim values are declared assumptions.
* **No physical backend, `/dev`, module, mdev, guest or network access** was
used or is performed by the tool.
---
## 8. Tests
```bash
python3 -m unittest tests.test_triage -v # 14 tests
make test # full suite
```
`tests/test_triage.py` covers the version-label extraction chain, the report
shape and artifact writes, session hashing, partial-failure handling
(injected step failure still yields a report), missing-firmware behaviour
(reported, not raised), budget bounds, RM 610 refusal (exit `3`), dry-run
side-effect freedom, and a tiny-budget integration run against the real
570.144 image that skips cleanly when the image or QEMU is absent.
<!-- change (2026-10-03): new document recording the one-command new-version
triage workflow (U46), its measured 570.144 value proof and its limits;
scope: docs/40 only; benefit: the release-to-support loop has one documented
entry point and one attachable evidence bundle. -->
|