@henols/c64-re-tools 0.2.3 → 0.2.5

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.
@@ -77,10 +77,11 @@ loop: ldx $dc01 ; $DC01 = Port B, keyboard matrix ro
77
77
  rts
78
78
  ```
79
79
 
80
- A header block listing every referenced address with its full description, symbol
81
- and region is prepended (elided above): measured on the two examples on this page,
82
- the eleven-line listing above grows a 23-line header and the nine-line IRQ excerpt
83
- below grows a 25-line one — a little over 2x the input either way. Pass
80
+ `annotate` prepends a header block that lists every referenced address with its
81
+ full description, symbol and region (elided above). Measured on the two examples
82
+ on this page, the eleven-line listing above grows a 23-line header and the
83
+ nine-line IRQ excerpt below grows a 25-line one — a little over 2x the input
84
+ either way. Pass
84
85
  `--no-header` to drop it and get the annotated body alone.
85
86
 
86
87
  Options:
@@ -91,8 +92,8 @@ Options:
91
92
  (`$0400-$07E7`, 1000 bytes) or the `$C000-$CFFF` block still earns an inline
92
93
  comment, while the 8 KB BASIC and KERNAL ROM blocks do not — a branch
93
94
  annotated "KERNAL ROM (8192 bytes)" teaches nobody anything. The cap applies
94
- only to non-flow instructions: flow instructions (`JMP`, `JSR`, branches,
95
- `RTS`, `RTI`) are held to 2 bytes regardless of `--max-span`, so a jump or
95
+ only to non-flow instructions. `annotate` holds flow instructions (`JMP`,
96
+ `JSR`, branches, `RTS`, `RTI`) to 2 bytes regardless of `--max-span`, so a jump or
96
97
  branch only earns a comment when it targets a specific vector such as
97
98
  `$0314`. `--max-span 2` gives register- and variable-level comments only.
98
99
  - `--no-header` suppresses the prepended header block, for piping annotated
@@ -128,11 +129,11 @@ Weigh a comment by the region it describes:
128
129
  equally solid wherever ROM is banked in — `$01` bits #0-#2 select it, and the
129
130
  vector at `$0314` shows whether the KERNAL IRQ path is in use.
130
131
  - **Zero page, `$0200-$07FF` and the BASIC area describe BASIC and KERNAL usage.**
131
- Read them as a strong hint and confirm against the program's own behaviour
132
+ Read them as a strong hint and check against the program's own behaviour
132
133
  before adopting the name. A game that banks ROM out keeps its own variables
133
134
  there. A real case: at `$08E6` a game's `LDA $49` gets labelled `FORPNT`
134
135
  ("value of current variable during LET"), when `$49` is really one of that
135
- game's own variables. Take the address, verify the meaning.
136
+ game's own variables. Take the address, check the meaning.
136
137
  - **A region-only answer is not an error.** An address that no source names
137
138
  specifically prints only the wider regions enclosing it — no error, no
138
139
  not-found line. `node $D lookup '$1234'` prints:
@@ -154,7 +155,7 @@ Weigh a comment by the region it describes:
154
155
  table that loses coverage, not for anything the current one omits.
155
156
 
156
157
  For a game, the fastest route to a real name is to annotate with `--max-span 2`,
157
- trust the I/O lines immediately, and confirm the rest by watching what the code
158
+ trust the I/O lines immediately, and check the rest by watching what the code
158
159
  does with them.
159
160
 
160
161
  ## Where the data comes from
@@ -170,16 +171,16 @@ what the others leave out:
170
171
  | [C64io.txt](https://www.zimmers.net/anonftp/pub/cbm/maps/C64io.txt) | VIC/SID/CIA registers broken down per bit |
171
172
 
172
173
  The built table is committed alongside the script, so `lookup` and `annotate` need
173
- only Node. Rebuild when a source publishes a correction; `lookup`'s `<src>` tags
174
+ only Node. Rebuild when a source publishes a correction. `lookup`'s `<src>` tags
174
175
  show which table any given claim came from.
175
176
 
176
177
  `memmap` overwrites the committed, git-tracked `memmap.json` (driver.mjs:270 —
177
- 235,925 bytes as of 2026-08-04, confirm with `wc -c`) **in place, with no backup
178
- and no diff.** One of the four sources (`http://unusedino.de/…`, driver.mjs:33)
179
- is fetched over plain HTTP with no TLS, and the only guard against a bad rebuild
178
+ 235,925 bytes as of 2026-08-04, check with `wc -c`) **in place, with no backup
179
+ and no diff.** `memmap` gets one of the four sources (`http://unusedino.de/…`,
180
+ driver.mjs:33) over plain HTTP with no TLS. The only guard against a bad rebuild
180
181
  is a per-source emptiness check plus a 600-entry floor across all sources
181
- combined (driver.mjs:262, 268) — so a partially-reachable or partially-changed
182
- source set can silently replace good tracked data with less of it. Rebuild, then
182
+ combined (driver.mjs:262, 268). A partially-reachable or partially-changed source
183
+ set can therefore silently replace good tracked data with less of it. Rebuild, then
183
184
  run `git diff --stat` on `memmap.json` before accepting the result, and
184
185
  `git checkout` the file if the diff is not explainable as the correction you
185
186
  were expecting. **`memmap` mutates tracked files** — unlike `lookup` and
@@ -191,8 +192,8 @@ tree, and review the diff before you commit it.
191
192
  `memmap.json`'s structured `bits` entries are the source of the curated register bit-name table used
192
193
  to generate program-specific enums for this project's annotation store: register
193
194
  writes disassemble as `lda #D011_YSCROLL3_ROW25_SCREENON_TEXT` instead of a bare `#$1b`. The
194
- generator is `src/mcp/vice/anno-regbits-gen.ts`; its committed output is
195
- `src/mcp/vice/anno-regbits.json`; and that output is **digest-pinned** to `memmap.json` — a
195
+ generator is `src/mcp/vice/anno-regbits-gen.ts`. Its committed output is
196
+ `src/mcp/vice/anno-regbits.json`. That output is **digest-pinned** to `memmap.json`. A
196
197
  `node anno-regbits-gen.ts` run compares its own fresh build against the committed file, and CI fails
197
198
  if `memmap.json` changed without a re-run.
198
199
 
@@ -200,7 +201,7 @@ if `memmap.json` changed without a re-run.
200
201
  `$D017`, `$D01A` and `$D01B`–`$D01D` — the sprite-plane bitmask registers a real game writes
201
202
  constantly — are **not** among those 29, so the enum generator supplies them from its own curated
202
203
  override table (`OVERRIDES` in `anno-regbits-gen.ts`), not from this file. Widening `memmap.json`'s
203
- `io` parser (or repairing the OCR damage already present in some `bits` prose, e.g. a letter `O` for
204
+ `io` parser (or correcting the OCR damage already present in some `bits` prose, e.g. a letter `O` for
204
205
  the digit `0`) so those registers get a real structured entry here is separate work belonging to this
205
206
  skill, not the generator.
206
207
 
@@ -208,10 +209,10 @@ skill, not the generator.
208
209
  table above only builds `anno-regbits.json`. Turning a specific program's register *writes* into
209
210
  named enum variants was the `gen-enums` CLI verb, and **that verb is WITHDRAWN from this surface, and
210
211
  no phase currently owns its return.** This notice previously forecast that it would come
211
- back as a rebuild over the annotation store alongside the ACME export route; the ACME export route
212
+ back as a rebuild over the annotation store alongside the ACME export route. The ACME export route
212
213
  did come back on 2026-08-31, but the phase that rebuilt it covered that route only — no requirement
213
- and no success criterion of it mentioned `gen-enums`. That forecast is corrected here rather than
214
- deleted. Do not invoke the verb — it does not exist, and the invocation fails with an unknown-verb
214
+ and no success criterion of it mentioned `gen-enums`. This notice corrects that forecast rather than
215
+ removing it. Do not invoke the verb — it does not exist, and the invocation fails with an unknown-verb
215
216
  error and nothing to explain it.
216
217
 
217
218
  What it did, so the rebuild has a specification and so a reader knows what is missing: it read the
@@ -229,7 +230,7 @@ manual where `gen-enums` was bulk, but it writes exactly the same rows into the
229
230
  Two deeper jobs feed the annotate/lookup job above, rather than standing apart from it: knowing
230
231
  what a whole region actually is (code, or one of eight kinds of data) before it can be annotated
231
232
  at all, and knowing what one of a program's own addresses represents when no published table can
232
- say. Both exist to serve a documented listing; neither is invoked as a job on its own.
233
+ say. Both exist to serve a documented listing. You do not invoke either one as a job on its own.
233
234
 
234
235
  ### Classifying every region of an annotation project
235
236
 
@@ -242,7 +243,7 @@ data?**
242
243
  answers the *live* code-versus-data question — its step 5 is "what the PC
243
244
  actually visits across full coverage", and an execution trace beats every
244
245
  static heuristic on this page. Run the live pass when you have a running
245
- machine; run this one when all you have is a file, and treat a later trace as
246
+ machine. Run this one when all you have is a file, and treat a later trace as
246
247
  the thing that overrules it.
247
248
 
248
249
  When a binary is first loaded, the auto-analyzer traces reachable code from the
@@ -279,11 +280,11 @@ four hundred lines of fiction.
279
280
  #### The order of the passes
280
281
 
281
282
  Work the Undefined blocks in four passes, in this order. Do not interleave
282
- them; each pass makes the next one cheaper.
283
+ them. Each pass makes the next one cheaper.
283
284
 
284
285
  1. **Provably-reachable code** — read from the entry point of each region that
285
286
  meets the proof bar above with `anno_disassemble`, then type the range you
286
- actually verified as `code` with `anno_set_data_type`. **Reading and typing
287
+ actually checked as `code` with `anno_set_data_type`. **Reading and typing
287
288
  are two calls on this surface, and that is deliberate:** `anno_disassemble`
288
289
  decodes fresh from the image bytes and writes nothing at all, so nothing is
289
290
  ever classified as code by a decoder's guess — the boundary you record is
@@ -291,7 +292,7 @@ them; each pass makes the next one cheaper.
291
292
  2. **Text** — PETSCII and screencode strings.
292
293
  3. **Tables** — byte, word, address and split (lo/hi, hi/lo) tables.
293
294
  4. **Whatever is left** — decide data, or leave it Undefined for a human.
294
- **Never** speculatively disassemble in this pass; by definition nothing here
295
+ **Never** speculatively disassemble in this pass. By definition nothing here
295
296
  met the proof bar.
296
297
 
297
298
  #### Scope, and reading a region
@@ -309,24 +310,24 @@ them; each pass makes the next one cheaper.
309
310
  data** — they are valid instructions. The flag is a human's hint, not a
310
311
  guarantee: some programs use them with the flag false.
311
312
  2. `anno_get_blocks` to see what is already classified, and focus on the
312
- Undefined entries. `max_results` is REQUIRED with no default; pass a ceiling
313
+ Undefined entries. `max_results` is REQUIRED with no default. Pass a ceiling
313
314
  above the range count you expect and compare the returned count against it.
314
315
  3. Read each candidate region twice, through `anno_read_region` (which names
315
316
  both the `store` and the `image`): `view:
316
317
  "hexdump"` shows the byte patterns, and **omitting `view`** gives the
317
318
  disassembly view — that is the parameter's documented default — which shows
318
- how the region would decode. The combined byte count is capped at **4096 bytes** per call
319
- (`ANNO_READ_REGION_MAX_BYTES`), and a request above the cap is refused by
320
- name rather than truncated — so walk a large binary in consecutive ranges.
319
+ how the region would decode. `anno_read_region` caps the combined byte count
320
+ at **4096 bytes** per call (`ANNO_READ_REGION_MAX_BYTES`). It refuses a
321
+ request above the cap by name rather than truncating it — so walk a large binary in consecutive ranges.
321
322
  Chunks of **256–512 bytes** are the practical working size for
322
- classification; a 4096-byte hexdump is more than can be read carefully in
323
+ classification. A 4096-byte hexdump is more than can be read carefully in
323
324
  one pass.
324
325
 
325
326
  #### Applying the classification
326
327
 
327
328
  - **Code**: `anno_disassemble` from the entry-point address to READ, then
328
- `anno_set_data_type` with `"code"` to RECORD the range you verified.
329
- `anno_disassemble` performs no write, so nothing is classified until you say
329
+ `anno_set_data_type` with `"code"` to RECORD the range you checked.
330
+ `anno_disassemble` performs no write, so it classifies nothing until you say
330
331
  so. Type only as far as you actually followed the flow — the end of a routine
331
332
  at its `RTS`/`RTI`/`JMP`, not "to the end of the region" — because the typed
332
333
  `code` ranges are what `anno_get_cross_references` and `anno_search` decode
@@ -337,9 +338,9 @@ them; each pass makes the next one cheaper.
337
338
  - **A wrong classification is not a disaster and does not need undoing.**
338
339
  `anno_set_data_type` is idempotent over a range: set the correct type again
339
340
  over the same range and the previous one is gone, and an identical repeat
340
- succeeds reporting `changed: false`. (Upstream reaches for an undo call here;
341
- this project does not expose one, and does not need to.)
342
- - **Read the disclosures on a successful retype; they are not errors and they
341
+ succeeds reporting `changed: false`. (Upstream reaches for an undo call here.
342
+ This project does not expose one, and does not need to.)
343
+ - **Read the disclosures on a successful retype. They are not errors and they
343
344
  are never dropped.** `contradictedComments` names comments whose recorded
344
345
  confidence now contradicts the type you just applied, and
345
346
  `reinterpretedSplitTables` names every split table the write FRAGMENTED, with
@@ -349,9 +350,9 @@ them; each pass makes the next one cheaper.
349
350
  ones a human recorded.
350
351
  - A split layout REFUSES an odd byte count — the low half and the high half must
351
352
  be the same length.
352
- - Re-read `anno_get_blocks` after each batch to confirm what actually landed.
353
- `max_results` is REQUIRED on that read and has no default; the true match
354
- count is returned beside the list.
353
+ - Re-read `anno_get_blocks` after each batch to check what actually landed.
354
+ `max_results` is REQUIRED on that read and has no default. That read returns
355
+ the true match count beside the list.
355
356
 
356
357
  Example of a valid data-only batch, then the code regions separately:
357
358
 
@@ -368,7 +369,7 @@ then: anno_get_blocks max_results=500 # refresh
368
369
 
369
370
  | Block type | `data_type` | When |
370
371
  |---|---|---|
371
- | **Code** | `code` | Provably-executed instructions. Read the extent with `anno_disassemble` first — it writes nothing — then record exactly what you verified. |
372
+ | **Code** | `code` | Provably-executed instructions. Read the extent with `anno_disassemble` first — it writes nothing — then record exactly what you checked. |
372
373
  | Byte | `byte` | Raw 8-bit data: sprites, bitmaps, charsets, lookup tables, variables, unknowns |
373
374
  | Word | `word` | 16-bit little-endian values: 16-bit variables, math constants, SID frequencies |
374
375
  | Address | `address` | 16-bit LE pointers — jump tables, vector lists. Creates cross-references |
@@ -383,17 +384,17 @@ then: anno_get_blocks max_results=500 # refresh
383
384
 
384
385
  #### Recognising each kind
385
386
 
386
- **Byte data** — regular patterns that form no valid instruction sequence;
387
- addressed by `LDA addr,X` / `LDA addr,Y` table lookups; sprite data in 63-byte
388
- (padded to 64) units, usually grouped; bitmap data in 8-byte character cells;
389
- colour data confined to `$00`–`$0F`; or random-looking bytes between two code
387
+ **Byte data** — regular patterns that form no valid instruction sequence.
388
+ Addressed by `LDA addr,X` / `LDA addr,Y` table lookups. Sprite data in 63-byte
389
+ (padded to 64) units, usually grouped. Bitmap data in 8-byte character cells.
390
+ Colour data confined to `$00`–`$0F`. Or random-looking bytes between two code
390
391
  blocks whose disassembly is nonsense.
391
392
 
392
393
  **Word data** — byte pairs forming meaningful 16-bit values (screen addresses,
393
- timer values); loaded low-then-high by adjacent `LDA addr` / `LDA addr+1`.
394
+ timer values). Loaded low-then-high by adjacent `LDA addr` / `LDA addr+1`.
394
395
 
395
396
  **Address tables** — byte pairs that read as little-endian addresses landing
396
- *inside* the binary; reached by `JMP ($addr)` or indexed indirect reads. Jump
397
+ *inside* the binary. Reached by `JMP ($addr)` or indexed indirect reads. Jump
397
398
  tables, dispatch tables and vector lists all live here.
398
399
 
399
400
  **Split lo/hi (or hi/lo) tables** — two equal halves, one of plausible low
@@ -404,25 +405,25 @@ on the 6502. **The total byte count must be even and the halves equal** — an
404
405
  odd count means the boundary is in the wrong place.
405
406
 
406
407
  **PETSCII text** — bytes in `$20`–`$7E` (unshifted) or `$C0`–`$DF` (shifted),
407
- often recognisably English since PETSCII shares `$20`–`$5F` with ASCII;
408
- terminated by `$00`, `$0D`, or a high-bit sentinel; reached by `$FFD2` (CHROUT)
408
+ often recognisably English since PETSCII shares `$20`–`$5F` with ASCII.
409
+ Terminated by `$00`, `$0D`, or a high-bit sentinel. Reached by `$FFD2` (CHROUT)
409
410
  or `$AB1E` (BASIC STROUT). `GAME OVER`, `PRESS FIRE`, menus, credits.
410
411
 
411
- **Screencode text** — bytes in `$00`–`$3F` where `$00` is `@` and `$01` is `A`;
412
- copied directly to `$0400`–`$07E7`. `LDA data,X / STA $0400,X` is the
412
+ **Screencode text** — bytes in `$00`–`$3F` where `$00` is `@` and `$01` is `A`.
413
+ Copied directly to `$0400`–`$07E7`. `LDA data,X / STA $0400,X` is the
413
414
  give-away. A full screen dump is exactly 1000 bytes.
414
415
 
415
416
  **External file** — a large contiguous non-code block matching a known format:
416
417
  a `PSID`/`RSID` header, a 2048-byte charset (256 chars × 8 bytes), sprite data
417
418
  in multiples of 64, or a bitmap. Export it rather than annotate it.
418
419
 
419
- **PETSCII is not screencode.** If it is copied to `$0400`, it is screencode; if
420
- it is passed to CHROUT, it is PETSCII. Getting this backwards produces text
420
+ **PETSCII is not screencode.** If the program copies it to `$0400`, it is
421
+ screencode. If the program passes it to CHROUT, it is PETSCII. Getting this backwards produces text
421
422
  that renders as garbage in exactly one of the two places.
422
423
 
423
424
  #### The adjacent-table limitation, and how it was closed
424
425
 
425
- **Dated limitation, recorded 2026-08-24; CLOSED 2026-08-29 when the store
426
+ **Dated limitation, recorded 2026-08-24. CLOSED 2026-08-29 when the store
426
427
  changed underneath it.** The old store auto-merged two adjacent regions of the
427
428
  *same* type into one block, so two byte tables side by side — or the two halves
428
429
  of a split table sitting next to each other — lost their boundary on read, and
@@ -443,7 +444,7 @@ So the working rules are now the ordinary ones:
443
444
  - **Do** still record the boundary in the annotations as well — an
444
445
  `anno_set_label_name` at the start of the second table and a line comment on
445
446
  both naming the extent you determined. A name and an evidence line survive a
446
- later retype; a row boundary does not.
447
+ later retype. A row boundary does not.
447
448
  - **Do not** carry the old over-merge caveat into a report taken from this
448
449
  store. It was true of the retired one and is not true here.
449
450
 
@@ -464,14 +465,14 @@ Then report, and mean it:
464
465
  regions on a real game is almost always a report that stopped looking.
465
466
  - The store revision, read with `anno_save_project`. That verb performs **no
466
467
  write** — every classification call above already committed and fsynced its
467
- own — so quoting the revision is how the report is pinned to an exact store
468
+ own — so quoting the revision pins the report to an exact store
468
469
  state rather than to "after the pass".
469
470
 
470
471
  #### What goes wrong
471
472
 
472
473
  | Symptom | What it actually is |
473
474
  |---|---|
474
- | A region disassembles beautifully but has no incoming reference | Data. Decodability is not evidence; leave it Undefined. |
475
+ | A region disassembles beautifully but has no incoming reference | Data. Decodability is not evidence. Leave it Undefined. |
475
476
  | Disassembly full of impossible branches or `BRK` (`$00`) floods | Data misread as code. |
476
477
  | Odd-looking instructions, but real `JSR`/`JMP` cross-references land here | Probably code using undocumented opcodes. Check the `may_contain_undocumented_opcodes` hint. |
477
478
  | A split table's addresses recombine to nonsense | The half boundary is misplaced, or the table is hi/lo rather than lo/hi. |
@@ -485,7 +486,7 @@ a hardware register, a KERNAL entry point, an OS variable. That answer comes
485
486
  from four tables and holds for every program.
486
487
 
487
488
  This section is the other half: **what a program's *own* address represents.**
488
- No table can tell you, because the meaning was decided by the program's code.
489
+ No table can tell you, because the program's code decided the meaning.
489
490
  When `lookup` returns a region-only answer — the dominant case for a game's own
490
491
  code and variables, as noted above — this is the procedure that gets you a
491
492
  name.
@@ -507,7 +508,7 @@ name.
507
508
  #### 2. Gather the usage
508
509
 
509
510
  `anno_get_cross_references` on the address — naming the `store`, the `image` and
510
- a REQUIRED `max_results` — returns everywhere it is touched. Read the
511
+ a REQUIRED `max_results` — returns every site that touches it. Read the
511
512
  instruction at each site, because the instruction is the evidence:
512
513
 
513
514
  - **Writes**: `STA`, `STX`, `STY`
@@ -540,14 +541,14 @@ field of auto-generated offsets.
540
541
 
541
542
  **An external ROM or system routine?** An `e_` prefix, or an address in KERNAL
542
543
  space (`$E000`–`$FFFF`), or a standard shadow vector. `lookup` gives the
543
- routine's published name; rename to the conventional form — `$FFD2` becomes
544
+ routine's published name. Rename to the conventional form — `$FFD2` becomes
544
545
  `KERNAL_CHROUT`, `$EA31` becomes `SYSTEM_IRQ_HANDLER`.
545
546
 
546
547
  **A 16-bit pointer?** Below `$0100`, and used with indirect-indexed `($xx),Y`
547
548
  or indexed-indirect `($xx,X)`. Rename to `ptr_`/`vec_` form and comment what it
548
549
  points *to*, which is the thing the name cannot carry.
549
550
 
550
- **A flag or bitmask?** Only ever `$00`/`$01` or `$00`/`$FF`; tested with `BIT`
551
+ **A flag or bitmask?** Only ever `$00`/`$01` or `$00`/`$FF`. Tested with `BIT`
551
552
  or `LDA`/`BEQ`. Name it as a predicate — `is_active`, `has_collided`. When the
552
553
  individual bits carry separate meanings, that is an enum: define it with
553
554
  `anno_create_project_enum` (`$01 = ACTIVE`, `$02 = COLLIDED`, `$04 =
@@ -559,8 +560,8 @@ with `CPX`/`CPY`/`CMP`. `loop_idx`, `sprite_count`, `delay_timer`.
559
560
 
560
561
  **A state variable?** Several distinct values, often feeding a dispatch
561
562
  (`ASL` / `TAX` / `JMP (table,X)`). Name it `game_state` or `current_mode` — and
562
- these are the best enum candidates of all. Look for an existing enum first;
563
- define one (`0 = INIT`, `1 = TITLE`, `2 = GAMEPLAY`, `3 = GAME_OVER`) with a
563
+ these are the best enum candidates of all. Look for an existing enum first.
564
+ Define one (`0 = INIT`, `1 = TITLE`, `2 = GAMEPLAY`, `3 = GAME_OVER`) with a
564
565
  real `description` if none matches, then apply it to every instruction reading
565
566
  or writing the variable.
566
567
 
@@ -612,19 +613,19 @@ still readable even though the store cannot format it.
612
613
  variable, dead.
613
614
  - **Evidence**: the specific cross-references or usage patterns that decided
614
615
  it. A classification with no evidence line is a guess wearing a name.
615
- - **Actions taken**: what was renamed, what was commented, which enums were
616
+ - **Actions taken**: what you renamed, what you commented, which enums were
616
617
  defined or applied.
617
618
  - **Uncertainty**: if `anno_get_cross_references` returned nothing, say which
618
619
  of the three explanations in step 2 you could and could not rule out.
619
620
 
620
621
  ## Troubleshooting
621
622
 
622
- | Symptom | Fix |
623
+ | Symptom | Correction |
623
624
  |---|---|
624
- | Comments land on regions too wide to be useful | `--max-span 2`; the default is 4096 bytes. |
625
- | A `JSR` or branch target got no comment at all | Flow instructions are capped at 2 bytes regardless of `--max-span`; `lookup` the target directly for the ROM routine name. |
625
+ | Comments land on regions too wide to be useful | `--max-span 2`. The default is 4096 bytes. |
626
+ | A `JSR` or branch target got no comment at all | `annotate` caps flow instructions at 2 bytes regardless of `--max-span`. `lookup` the target directly for the ROM routine name. |
626
627
  | The output is mostly header | `--no-header`. |
627
- | `lookup` printed only wide region lines and no specific name | Nothing in the four tables names that address; expected for the game's own code — take the region and name the address from what the code does with it. |
628
- | `lookup` printed `(not in memory map)` | Nothing covers it; check the address parsed as intended, since a bare `1234` reads as decimal. |
629
- | `no memmap.json; run: node driver.mjs memmap` | Restore the committed table with `git checkout` rather than rebuilding; the rebuild needs network and overwrites tracked data. |
630
- | `memmap` rewrote `memmap.json` and the diff is large or negative | A source was unreachable or changed; `git checkout` the file. |
628
+ | `lookup` printed only wide region lines and no specific name | Nothing in the four tables names that address. This answer is normal for the game's own code. Take the region and name the address from what the code does with it. |
629
+ | `lookup` printed `(not in memory map)` | Nothing covers it. Check the address parsed as intended, since a bare `1234` reads as decimal. |
630
+ | `no memmap.json; run: node driver.mjs memmap` | Restore the committed table with `git checkout` rather than rebuilding. The rebuild needs network and overwrites tracked data. |
631
+ | `memmap` rewrote `memmap.json` and the diff is large or negative | A source was unreachable or changed. `git checkout` the file. |
@@ -14,11 +14,11 @@ S=src/skills/c64-petcat/scripts/petcat.mjs # from the repo root
14
14
  node $S decode --image path/to/program.prg # detokenize + resolve the SYS handover
15
15
  ```
16
16
 
17
- The script wraps `petcat` and nothing else. `--image` is required; `--out-dir`
18
- is optional, defaulting to the image's own directory, exactly like
19
- `acme-build`'s own `--out-dir` default. Both are resolved
20
- **workspace-relative** to the smallest ancestor directory containing both,
21
- before the request ever reaches the seam — the same resolution
17
+ The script wraps `petcat` and nothing else. The script requires `--image`.
18
+ `--out-dir` is optional, defaulting to the image's own directory, exactly like
19
+ `acme-build`'s own `--out-dir` default. The script resolves both
20
+ **workspace-relative** to the smallest ancestor directory containing both.
21
+ This happens before the request ever reaches the seam — the same resolution
22
22
  `acme-build`/`c64-disk-access` already go through.
23
23
 
24
24
  Options: `--image PATH` `--out-dir DIR` `--json`.
@@ -67,15 +67,15 @@ posture `acme-build` already takes for its own assembler target.
67
67
 
68
68
  ## Failure shape
69
69
 
70
- A file `petcat` does not recognise as a BASIC program at all — including a
71
- missing file — is reported as `{"ok":false,"message":"..."}` with a
72
- non-zero exit code, never a success envelope carrying an empty or guessed
73
- verdict. `petcat` itself exits `0` even on garbage input; the seam's own
74
- classifier, not the exit code, is what decides success here.
70
+ The seam reports a file `petcat` does not recognise as a BASIC program at
71
+ all — including a missing file — as `{"ok":false,"message":"..."}` with a
72
+ non-zero exit code. It never reports a success envelope carrying an empty
73
+ or guessed verdict. `petcat` itself exits `0` even on garbage input. The
74
+ seam's own classifier, not the exit code, is what decides success here.
75
75
 
76
76
  ## What this skill does NOT do
77
77
 
78
- - **No direct binary spawn.** `petcat` runs host-side; this script only ever
78
+ - **No direct binary spawn.** `petcat` runs host-side. This script only ever
79
79
  constructs a typed request and reads the produced listing file back off
80
80
  the shared workspace tree — the host-tool execution seam is the only
81
81
  route.