@henols/c64-re-tools 0.2.1 → 0.2.3
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.
- package/README.md +1 -1
- package/THIRD-PARTY-NOTICES.md +26 -0
- package/bin/cli.mjs +18 -7
- package/package.json +6 -4
- package/skills/acme-build/SKILL.md +83 -33
- package/skills/acme-build/scripts/acme.mjs +159 -64
- package/skills/acme-build/template.a +1 -1
- package/skills/c64-disk-access/SKILL.md +156 -0
- package/skills/c64-disk-access/scripts/c1541.mjs +569 -0
- package/skills/c64-memory-mapping/SKILL.md +419 -23
- package/skills/c64-memory-mapping/scripts/driver.mjs +1 -1
- package/skills/c64-petcat/SKILL.md +87 -0
- package/skills/c64-petcat/scripts/petcat.mjs +221 -0
- package/skills/c64-program-recon/SKILL.md +497 -92
- package/skills/c64-program-recon/references/control-flow.md +12 -15
- package/skills/c64-program-recon/references/graphics.md +1 -1
- package/skills/c64-program-recon/references/observation-hazards.md +18 -16
- package/skills/c64-program-recon/references/reconstruction.md +11 -6
- package/skills/c64-program-recon/references/sound-and-input.md +6 -8
- package/skills/c64-program-recon/references/tool-selection.md +37 -18
- package/skills/c64-program-recon/scripts/packer-finding.mjs +709 -0
- package/skills/c64-program-recon/templates/memory-map.template.md +27 -13
- package/skills/c64-provenance-diff/SKILL.md +43 -8
- package/skills/c64-provenance-diff/scripts/diff-images.mjs +9 -6
- package/skills/c64-provenance-diff/scripts/recovery-schema.mjs +20 -8
- package/skills/c64-ram-capture/RELEASES.json.example +17 -0
- package/skills/c64-ram-capture/SKILL.md +147 -46
- package/skills/c64-ram-capture/scripts/compare.mjs +2 -2
- package/skills/c64-ram-capture/scripts/derive-transients.mjs +575 -0
- package/skills/c64-ram-capture/scripts/dump-artifacts.mjs +3 -3
- package/skills/c64-ram-capture/scripts/mcp-module.mjs +174 -0
- package/skills/c64-ram-capture/scripts/project-paths.mjs +1 -1
- package/skills/c64-ram-capture/scripts/releases.mjs +1 -1
- package/skills/c64-ram-capture/scripts/vsf-slice.mjs +147 -0
- package/skills/c64-ram-capture/scripts/watch-loads.mjs +19 -13
- package/skills/c64-ram-capture/templates/capture-record.template.md +44 -4
- package/skills/c64-ram-capture/transients/README.md +136 -0
- package/skills/routine-queue-walker/SKILL.md +365 -0
- package/skills/routine-queue-walker/scripts/completeness-report.mjs +463 -0
- package/skills/vice-wedge-triage/SKILL.md +104 -97
- package/skills/c64-provenance-diff/scripts/diff-images.test.mjs +0 -665
- package/skills/c64-ram-capture/scripts/d64-parse.mjs +0 -243
- package/skills/c64-ram-capture/scripts/d64-parse.test.mjs +0 -243
- package/skills/c64-ram-capture/scripts/dump-artifacts.test.mjs +0 -133
- package/skills/c64-ram-capture/scripts/test-corpus.mjs +0 -75
- package/skills/c64-ram-capture/scripts/watch-loads.test.mjs +0 -339
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: routine-queue-walker
|
|
3
|
+
description: Drive an existing C64 annotation store's backlog of undocumented routines and auto-named symbols to closure — build the candidate queue from labels and comments, work it one entry at a time against explicit addresses, rebuild it after every pass, and report every leftover. Use when asked to annotate every remaining routine in a project, document all undocumented subroutines left in an annotation project, rename the leftover auto-generated labels, clear a backlog of unnamed symbols, drive an annotation pass to completion, or list what is still unannotated after a pass.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Walking the routine and symbol queue to closure
|
|
7
|
+
|
|
8
|
+
**Do not start annotating whatever is in front of you.** The expensive failure
|
|
9
|
+
here is not slow work — it is a pass that *looks* finished while a hundred
|
|
10
|
+
`p_XXXX` labels are still nameless and nobody wrote down which ones. Build the
|
|
11
|
+
queue first, from data, then walk it to the end.
|
|
12
|
+
|
|
13
|
+
This playbook assumes block classification has already happened and an
|
|
14
|
+
annotation store already exists. If you do not yet know what the program is —
|
|
15
|
+
where it starts, which vector is live, which regions are code — stop and run
|
|
16
|
+
`c64-program-recon` first. That skill answers *what is this program*; this one
|
|
17
|
+
answers *what is still undocumented in it, and how do I finish*.
|
|
18
|
+
|
|
19
|
+
## The one rule that makes this different from upstream's version
|
|
20
|
+
|
|
21
|
+
**Work the queue one entry at a time.** Not as a throughput compromise — as an
|
|
22
|
+
accurate model of the store underneath. One `.annostore` is one writer: every
|
|
23
|
+
mutating call opens it, commits and closes inside the call, and every one of
|
|
24
|
+
them accepts an optional `base_revision` compare-and-swap that REFUSES a write
|
|
25
|
+
computed against a revision the store has already moved past. Fanning several
|
|
26
|
+
writers at one store therefore buys **zero** extra throughput and costs
|
|
27
|
+
correctness: the losers come back as named stale-revision refusals you then
|
|
28
|
+
have to re-derive and replay. Reading fan-out — several agents *thinking* over
|
|
29
|
+
already-fetched answers — is fine, and its value is reasoning bandwidth, never
|
|
30
|
+
I/O.
|
|
31
|
+
|
|
32
|
+
**Every call names its own store.** There is no ambient "current store" on this
|
|
33
|
+
surface: pass `store` (a `.annostore` path) on every call, and pass `image` as
|
|
34
|
+
well on every call that derives its answer from the program's bytes rather than
|
|
35
|
+
from the annotations — `anno_get_binary_info`, `anno_read_region`,
|
|
36
|
+
`anno_disassemble`, `anno_get_cross_references`, `anno_search` and
|
|
37
|
+
`anno_get_address_details`. The store holds annotations and never bytes, so an
|
|
38
|
+
omitted image would read as a plausible success against whatever was recorded
|
|
39
|
+
last.
|
|
40
|
+
|
|
41
|
+
## Phase 0 — context, and the packed-binary gate
|
|
42
|
+
|
|
43
|
+
1. Call `anno_get_binary_info`. Keep `origin`, `size`, `system`, `filename`,
|
|
44
|
+
`description` and `may_contain_undocumented_opcodes` — every later step
|
|
45
|
+
quotes them.
|
|
46
|
+
2. Read the returned `entropy` against the threshold of **7.5** carried in that
|
|
47
|
+
tool's own description. At or above it, the bytes are very likely packed.
|
|
48
|
+
3. If the binary looks packed, **stop and say so.** Do not annotate a packed
|
|
49
|
+
image: you would be documenting a decruncher, and every label you write is
|
|
50
|
+
thrown away the moment the real image is recovered. This project's route to
|
|
51
|
+
an unpacked image is `c64-ram-capture` — run the program in the emulator and
|
|
52
|
+
capture RAM at a checkpoint past the decrunch — plus the packer-identity
|
|
53
|
+
finding in `c64-program-recon`, which names the packer when an oracle can.
|
|
54
|
+
Come back with the captured image and start again at Phase 0.
|
|
55
|
+
|
|
56
|
+
Upstream's in-place `unpack_binary` step is deliberately not carried: it is
|
|
57
|
+
destructive (it clears the comments, labels and blocks already in the store)
|
|
58
|
+
and this project has a non-destructive route to the same answer.
|
|
59
|
+
|
|
60
|
+
## Phase 1 — make sure blocks are classified
|
|
61
|
+
|
|
62
|
+
Region classification is a prerequisite for everything below: a routine
|
|
63
|
+
candidate is only meaningful once the bytes around it are known to be code.
|
|
64
|
+
|
|
65
|
+
1. Follow `src/skills/c64-memory-mapping/SKILL.md` for the classification pass
|
|
66
|
+
and for what each region type means.
|
|
67
|
+
2. Do that pass yourself, in one sitting. It is a single long walk over the
|
|
68
|
+
whole binary, not a queue of independent items.
|
|
69
|
+
|
|
70
|
+
## Phase 2 — the routine queue
|
|
71
|
+
|
|
72
|
+
### 2.1 Build the candidate list
|
|
73
|
+
|
|
74
|
+
A routine counts as **already documented** when its entry address carries a
|
|
75
|
+
line comment. That is the only test; do not guess from the label name.
|
|
76
|
+
|
|
77
|
+
1. Call `anno_get_symbols` for all labels — user, system and external, with
|
|
78
|
+
an explicit `max_results` above the program's label count (`max_results` is
|
|
79
|
+
REQUIRED on this surface and has no default, so a truncated answer is always
|
|
80
|
+
a ceiling you chose). Keep the answer; Phase 3 reuses it.
|
|
81
|
+
2. Call `anno_get_comments`, again with an explicit `max_results`. Keep that
|
|
82
|
+
too — the true match count rides beside the list, so truncation is a fact
|
|
83
|
+
you are told rather than one you infer.
|
|
84
|
+
3. **Candidate source A — cross-reference and block-derived, checked FIRST and
|
|
85
|
+
independently of whatever `anno_get_symbols` returned.** Call
|
|
86
|
+
`anno_get_blocks` with `block_type: "code"` for every code-typed range,
|
|
87
|
+
read each one with `anno_disassemble`, and collect every `jsr` target
|
|
88
|
+
address. For each candidate target, confirm it and gather its full caller
|
|
89
|
+
list with `anno_get_cross_references` (a generous `max_results` — this is
|
|
90
|
+
also the call that fills in "called from" when the entry is written up in
|
|
91
|
+
Phase 2.2). Every one of these targets is a routine candidate **regardless
|
|
92
|
+
of whether it carries any label at all**. `docs/phase45-wave0-
|
|
93
|
+
measurements.md`'s own MEASUREMENT A found that a purely dxa/Ghidra-derived
|
|
94
|
+
store carries ZERO labels of any shape — derivation writes typed ranges and
|
|
95
|
+
cross-references, never names — so a queue built only from Candidate source
|
|
96
|
+
B below finds nothing to do on such a store and silently reports a clean,
|
|
97
|
+
empty queue on a program nothing has been named in yet. Source A does not
|
|
98
|
+
depend on step 1 having found anything.
|
|
99
|
+
4. **Candidate source B — the label-prefix path, for a store that DOES carry
|
|
100
|
+
externally-imported auto-names.** Keep a label as a routine candidate when
|
|
101
|
+
any of these holds:
|
|
102
|
+
- its name starts with `s_` (an auto-generated subroutine label);
|
|
103
|
+
- it sits in a code region and is the target of at least one `JSR`
|
|
104
|
+
cross-reference (`anno_get_cross_references`);
|
|
105
|
+
- it is a `p_XXXX` label sitting **inside a code region**. These come from
|
|
106
|
+
split lo/hi immediate loads and from address tables, and they are almost
|
|
107
|
+
always chained raster-IRQ handlers, hardware- or shadow-vector handlers,
|
|
108
|
+
or jump-table and callback targets. Treat every one of them as a
|
|
109
|
+
candidate rather than pattern-matching specific vector addresses;
|
|
110
|
+
- it is the label named exactly `start`.
|
|
111
|
+
5. **Union sources A and B by address** — a routine reachable both ways counts
|
|
112
|
+
once. A store may carry either shape, or both, so neither source alone is
|
|
113
|
+
sufficient.
|
|
114
|
+
6. Drop every candidate that already carries a line comment.
|
|
115
|
+
7. What is left is the routine queue.
|
|
116
|
+
8. **Order it with `start` first** when `start` is in it. The entry point sets
|
|
117
|
+
the context every other routine is read against.
|
|
118
|
+
|
|
119
|
+
### 2.2 Walk it
|
|
120
|
+
|
|
121
|
+
Take **one** entry at a time, to completion, before starting the next — the
|
|
122
|
+
queue discipline this section owns. For each entry, run `c64-program-recon`
|
|
123
|
+
`SKILL.md`'s **"Documenting one routine, end to end"** procedure (steps 1-7)
|
|
124
|
+
against the entry's explicit address — including its 4096-byte
|
|
125
|
+
`anno_read_region` cap (consecutive ranges above it, never a raised cap) and
|
|
126
|
+
its tail-call / fall-through bounds rules (`JMP shared_epilogue` still ends
|
|
127
|
+
the routine; no return may mean fall-through — say so). Do not re-derive or
|
|
128
|
+
paraphrase that procedure here.
|
|
129
|
+
|
|
130
|
+
Record per entry, for Phase 4: the address, the old label, the new label, a
|
|
131
|
+
one-line summary, and any uncertainty.
|
|
132
|
+
|
|
133
|
+
### 2.3 Refresh point
|
|
134
|
+
|
|
135
|
+
When the queue is empty, read the store's revision with `anno_save_project`.
|
|
136
|
+
**It performs no write, and it exists to say so:** every mutating verb on this
|
|
137
|
+
surface has already committed and fsynced its own write by the time it
|
|
138
|
+
returned, so there is nothing for an explicit save to flush. Record the
|
|
139
|
+
revision — it is the checkpoint this pass is measured from, and the
|
|
140
|
+
`base_revision` a later compare-and-swap write would quote. Everything after
|
|
141
|
+
this point re-reads the store, because Phase 2 has just changed the label names
|
|
142
|
+
Phase 3 filters on.
|
|
143
|
+
|
|
144
|
+
## Phase 3 — the symbol queue
|
|
145
|
+
|
|
146
|
+
### 3.1 Build the candidate list
|
|
147
|
+
|
|
148
|
+
A symbol counts as **already documented** when it has a name a human chose, or
|
|
149
|
+
when it is a well-known system address (hardware register, KERNAL entry point,
|
|
150
|
+
OS variable).
|
|
151
|
+
|
|
152
|
+
1. Call `anno_get_symbols` **again** — Phase 2 renamed things.
|
|
153
|
+
2. **Candidate source A — cross-reference and block-derived, checked FIRST
|
|
154
|
+
and independently of whatever label population exists.** Call
|
|
155
|
+
`anno_get_blocks` (with `include: ["enum_usage"]` where useful) for every
|
|
156
|
+
typed range, then use `anno_get_cross_references` to find every address
|
|
157
|
+
that is: referenced by one half of a split lo/hi pair or by an address
|
|
158
|
+
table (a `lo_hi_address`/`hi_lo_address`/`lo_hi_word`/`hi_lo_word` range —
|
|
159
|
+
the `_address` forms produce cross-references, the `_word` forms do not,
|
|
160
|
+
per that data type's own schema distinction), OR referenced from a code
|
|
161
|
+
range while NOT itself sitting inside one. Every one of these is a symbol
|
|
162
|
+
candidate **regardless of whether it carries any label at all**.
|
|
163
|
+
`docs/phase45-wave0-measurements.md`'s own MEASUREMENT A found that a
|
|
164
|
+
purely dxa/Ghidra-derived store carries ZERO labels of any shape, so
|
|
165
|
+
Candidate source B below finds nothing to do on such a store and silently
|
|
166
|
+
reports a clean, empty queue on a program nothing has been named in yet.
|
|
167
|
+
3. **Candidate source B — the label-prefix path, for a store that DOES carry
|
|
168
|
+
externally-imported auto-names.** Keep every label whose name still
|
|
169
|
+
matches an auto-generated pattern: `zpp_XX`, `zpf_XX`, `zpa_XX` in the zero
|
|
170
|
+
page; `p_XXXX`, `f_XXXX`, `a_XXXX` and `e_XXXX` outside it.
|
|
171
|
+
4. Exclude, from BOTH sources: `s_XXXX` (Phase 2 handled those), `b_XXXX`
|
|
172
|
+
(branch targets, not data symbols), and any `p_XXXX`-shaped or
|
|
173
|
+
xref-derived candidate inside a code region (also Phase 2's).
|
|
174
|
+
5. **Union sources A and B by address** — a symbol reachable both ways counts
|
|
175
|
+
once.
|
|
176
|
+
6. What is left is the symbol queue.
|
|
177
|
+
|
|
178
|
+
### 3.2 Walk it
|
|
179
|
+
|
|
180
|
+
Same discipline as Phase 2: explicit address, one entry at a time, to
|
|
181
|
+
completion. For each symbol, use `anno_get_cross_references` to find who
|
|
182
|
+
touches it — a symbol's meaning is what its callers do with it — then rename it
|
|
183
|
+
and comment it. Classify it plainly: flag, counter, pointer, state variable,
|
|
184
|
+
buffer, table.
|
|
185
|
+
|
|
186
|
+
**No premature halting.** The symbol queue is routinely far larger than the
|
|
187
|
+
routine queue — fifty, a hundred entries is normal. Do not truncate it, do not
|
|
188
|
+
skip "secondary" symbols, and do not stop early because it is long. Feeding the
|
|
189
|
+
whole queue through is the job. Stopping early and labelling the remainder
|
|
190
|
+
"skipped for review" is a failed pass, not a completed one — unless the
|
|
191
|
+
remainder is reported explicitly, in full, under Phase 4's leftovers table.
|
|
192
|
+
|
|
193
|
+
For naming conventions and for what any given hardware or KERNAL address
|
|
194
|
+
means, follow `src/skills/c64-memory-mapping/SKILL.md` rather than guessing.
|
|
195
|
+
|
|
196
|
+
### 3.3 Refresh point
|
|
197
|
+
|
|
198
|
+
Read the revision again with `anno_save_project` and record it. No write is
|
|
199
|
+
performed; the writes already landed.
|
|
200
|
+
|
|
201
|
+
## Phase 4 — save and report
|
|
202
|
+
|
|
203
|
+
1. Read the revision one last time with `anno_save_project` and quote it in
|
|
204
|
+
the report, so the pass is attributable to an exact store state.
|
|
205
|
+
2. Write the report. Four sections, all of them required:
|
|
206
|
+
|
|
207
|
+
**Regions.** How many regions are classified, grouped by type, plus anything
|
|
208
|
+
notable — text at a fixed address, a jump table, a sprite block.
|
|
209
|
+
|
|
210
|
+
**Routines.**
|
|
211
|
+
|
|
212
|
+
| Address | Old label | New label | What it does |
|
|
213
|
+
| ------- | --------- | --------- | ------------ |
|
|
214
|
+
| `$C000` | `s_C000` | `init_screen` | Clears screen RAM, sets the border colour |
|
|
215
|
+
|
|
216
|
+
**Symbols.**
|
|
217
|
+
|
|
218
|
+
| Address | Old label | New label | Classification |
|
|
219
|
+
| ------- | --------- | --------- | -------------- |
|
|
220
|
+
| `$02` | `zpp_02` | `ptr_screen` | Zero-page indirect pointer |
|
|
221
|
+
|
|
222
|
+
**Leftovers — uncertain, skipped, or still unannotated.** This section is not
|
|
223
|
+
optional and it is not allowed to be empty when the queues were not emptied.
|
|
224
|
+
List every routine and every symbol that was left undone, with its address and
|
|
225
|
+
the reason. Never report "no uncertain areas" or "nothing left" while a single
|
|
226
|
+
`f_XXXX` or `a_XXXX` label is still auto-named or a queued routine is still
|
|
227
|
+
uncommented — those must be listed by name for a human to pick up.
|
|
228
|
+
|
|
229
|
+
## Phase 5 — measure the pass instead of asserting it finished
|
|
230
|
+
|
|
231
|
+
A report that says "all routines documented" is a claim about the report, not
|
|
232
|
+
about the program. Measure it. From the repository root:
|
|
233
|
+
|
|
234
|
+
```
|
|
235
|
+
node src/mcp/vice/vice-proxy.ts anno coverage game.prg --store game.annostore
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**`--store` is REQUIRED and is a second path, not a spelling of the first.**
|
|
239
|
+
`<program>` supplies the payload bytes and the load origin; `--store` names the
|
|
240
|
+
annotation store holding the labels, comments and typed ranges. The store holds
|
|
241
|
+
annotations and never bytes, so the verb refuses to guess either path from the
|
|
242
|
+
other.
|
|
243
|
+
|
|
244
|
+
**Dated note, 2026-08-30 — the positional is a program IMAGE, and the command
|
|
245
|
+
above is now correct against the shipped verb.** `<program>` is a `.prg` (a
|
|
246
|
+
2-byte little-endian load address followed by the payload) or an
|
|
247
|
+
**exactly-65536-byte** flat capture with a `.raw` or `.bin` extension — the two
|
|
248
|
+
forms every other verb and tool on this surface already reads, and the two
|
|
249
|
+
`c64-ram-capture` produces. The intermediate project-file format this verb
|
|
250
|
+
previously required has **no producer left in this repo**; it is still accepted
|
|
251
|
+
so an existing project file keeps working, but nothing here writes one, so do
|
|
252
|
+
not go looking for a step that produces it.
|
|
253
|
+
|
|
254
|
+
Dispatch is by **file extension first, length second**. A short flat capture is
|
|
255
|
+
therefore refused by name — `a flat 64K capture must be exactly 65536 bytes` —
|
|
256
|
+
rather than misread as a `.prg` whose first two payload bytes become the load
|
|
257
|
+
address. If you get that refusal, the capture is truncated; re-capture it, do
|
|
258
|
+
not rename it.
|
|
259
|
+
|
|
260
|
+
Add `--out coverage.json` to keep the machine-readable report, `--force` to
|
|
261
|
+
overwrite one, and `--sample N` to widen the reproducibility sample. The verb
|
|
262
|
+
reads the same store every call in this playbook writes to, and exits **0 even
|
|
263
|
+
when the numbers are bad** — a low measurement is a result, not a failure.
|
|
264
|
+
Non-zero means a caller error, an image it could not read, or a store it could
|
|
265
|
+
not read at all.
|
|
266
|
+
|
|
267
|
+
**Run it three times:** once before Phase 2, so the pass has a starting point
|
|
268
|
+
to be compared against; once at Phase 2.3's refresh point; and once at the end,
|
|
269
|
+
after Phase 4's final save. The last run is what goes in the report.
|
|
270
|
+
|
|
271
|
+
**Read the three numbers against each other. Never quote one of them alone.**
|
|
272
|
+
There is deliberately no single "percent documented" figure, because one
|
|
273
|
+
combined number lets a weak measure hide behind a strong one and makes the
|
|
274
|
+
claim unfalsifiable:
|
|
275
|
+
|
|
276
|
+
- **A high user fraction beside a large unreached count means the wrong things
|
|
277
|
+
were named.** Every label got a human name, but most of the image was never
|
|
278
|
+
reached by the descent walk from any seed — the queue was worked over the
|
|
279
|
+
easily-visible part of the program and the rest was never entered. Go back to
|
|
280
|
+
Phase 0 and find more entry points (chained IRQ vectors, dispatch tables),
|
|
281
|
+
not more labels.
|
|
282
|
+
- **A large divergence means the store and the bytes disagree about what is
|
|
283
|
+
code.** Bytes the census reached as instructions that the store does not call
|
|
284
|
+
`Code` are places where Phase 1's classification is behind the actual control
|
|
285
|
+
flow. The reverse direction (the store calls it `Code`, the census never
|
|
286
|
+
reached it) is ordinary on an image with unreachable filler — read it, do not
|
|
287
|
+
chase it.
|
|
288
|
+
- **A low distinct-comment ratio means the comments are filler.** Fifty
|
|
289
|
+
addresses carrying the same sentence counts once, not fifty times. That is
|
|
290
|
+
the number that catches a pass which renamed everything and explained
|
|
291
|
+
nothing.
|
|
292
|
+
|
|
293
|
+
Anything the per-measure findings list names belongs in Phase 4's leftovers
|
|
294
|
+
table, by address. A finding is a named defect in one named measure — it is
|
|
295
|
+
never a rating, and there is no number to report as "the coverage".
|
|
296
|
+
|
|
297
|
+
### The decomposition-completeness gate
|
|
298
|
+
|
|
299
|
+
This is a DIFFERENT, non-overlapping measurement from the `anno coverage`
|
|
300
|
+
call above — neither replaces the other. `anno coverage` is the byte-census
|
|
301
|
+
and label-ratio instrument: a derived-from-bytes census this store's own
|
|
302
|
+
block table cannot move. `anno decomp-completeness` is the
|
|
303
|
+
disagreement-gated closure gate: whether this fixture's byte-derived block
|
|
304
|
+
classification and its own real, observed-execution evidence agree, every
|
|
305
|
+
code entry point carries a name and a complete purpose comment, every
|
|
306
|
+
referenced non-hardware address resolves to a name or a decline, and no
|
|
307
|
+
auto-named survivor remains in a code region — with the disagreement query
|
|
308
|
+
itself a required, non-defaultable input rather than an optional
|
|
309
|
+
cross-check.
|
|
310
|
+
|
|
311
|
+
```
|
|
312
|
+
node src/mcp/vice/vice-proxy.ts anno decomp-completeness --store <fixture>.annostore --disagreements <fixture>-disagreements.json --manifest src/mcp/vice/fixtures/decomp-execution-manifest.json
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
All three arguments are REQUIRED, and none is derived from another: `--store`
|
|
316
|
+
names the annotation store; `--disagreements` names the JSON `anno
|
|
317
|
+
evid-disagreements --store <same store> --json` wrote for THIS store's own
|
|
318
|
+
run; `--manifest` names the committed execution manifest recording which of
|
|
319
|
+
the nine fixtures were actually run under the reproducible-run protocol, and
|
|
320
|
+
which were declared not-executed and why. Omitting any of the three refuses
|
|
321
|
+
by name rather than rendering an empty-disagreement report — "the query was
|
|
322
|
+
never run" and "the query found nothing" must never read the same.
|
|
323
|
+
|
|
324
|
+
**The stop condition is a measured exit code, not a belief.** The walk
|
|
325
|
+
described in Phases 2-4 above is finished for a fixture when `node
|
|
326
|
+
src/skills/routine-queue-walker/scripts/completeness-report.mjs --store
|
|
327
|
+
<fixture>.annostore --disagreements <fixture>-disagreements.json --manifest
|
|
328
|
+
src/mcp/vice/fixtures/decomp-execution-manifest.json` **exits 0** — never when
|
|
329
|
+
the agent believes the queue is empty. A non-zero exit names, by address,
|
|
330
|
+
exactly which measure still fails (an Undefined byte, a surviving auto-name,
|
|
331
|
+
an entry point missing a name or a purpose-comment element, an unresolved
|
|
332
|
+
referenced address, or an unresolved disagreement); go back to the
|
|
333
|
+
corresponding phase and close it, then re-run the gate. Do not report a pass
|
|
334
|
+
from reading the rendered text alone — read the process exit code.
|
|
335
|
+
|
|
336
|
+
## When something fails
|
|
337
|
+
|
|
338
|
+
- A failed call is not a reason to drop a queue entry. Log the address, the
|
|
339
|
+
call and the error, put the entry back on the queue, and carry on with the
|
|
340
|
+
next one. Report every one of those in the leftovers table.
|
|
341
|
+
- A refused write is not silent and must not be treated as one. A
|
|
342
|
+
stale-revision refusal (a `base_revision` that the store has moved past), an
|
|
343
|
+
illegal label name, or a scope that overlaps an existing one all come back
|
|
344
|
+
REFUSED and named, with nothing written. Re-read, re-derive and replay that
|
|
345
|
+
one entry; never widen the range or drop the `base_revision` to make the
|
|
346
|
+
refusal go away.
|
|
347
|
+
- Never invent an answer to make a queue entry go away. An honest "this looks
|
|
348
|
+
like a table, callers unclear" in the leftovers table is worth more than a
|
|
349
|
+
confident wrong label that the next reader has to un-learn.
|
|
350
|
+
- **A genuinely unresolvable target gets a `DECLINED:` comment, never a
|
|
351
|
+
fabricated name.** When a referenced address's target is truly
|
|
352
|
+
path-dependent or otherwise cannot be determined, record it with
|
|
353
|
+
`anno_set_comment` using the literal prefix `DECLINED:` naming what is
|
|
354
|
+
unknown and why — the same convention `.annostore`'s own importer already
|
|
355
|
+
uses for bank-state declines, never a second mechanism. A confident wrong
|
|
356
|
+
label is worse than an absent one.
|
|
357
|
+
- **An accepted disagreement gets a `DISAGREEMENT-ACCEPTED:` comment.** When
|
|
358
|
+
the decomposition-completeness gate's disagreement census flags a byte the
|
|
359
|
+
byte-derived block table calls `data` but the runtime evidence shows
|
|
360
|
+
executing, and review confirms the runtime evidence is correct (or the
|
|
361
|
+
disagreement is otherwise a reviewed, accepted fact rather than a
|
|
362
|
+
classification bug), record it with `anno_set_comment` using the literal
|
|
363
|
+
prefix `DISAGREEMENT-ACCEPTED:` naming why — greppable, and read by the gate
|
|
364
|
+
itself as the resolution for that address. Both conventions ride the
|
|
365
|
+
existing `anno_set_comment` tool; neither is a new mechanism.
|