@henols/vice-mcp 0.2.2 → 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 +2 -2
- package/THIRD-PARTY-NOTICES.md +422 -1
- package/anno-bank.ts +171 -0
- package/anno-cli.ts +1674 -99
- package/anno-enum-gen.ts +416 -30
- package/anno-export-asm.ts +1175 -89
- package/anno-graphics.ts +338 -0
- package/anno-hazard-report.ts +1367 -0
- package/anno-import.ts +495 -0
- package/anno-join.ts +480 -0
- package/anno-provenance-ledger.ts +472 -0
- package/anno-register.ts +159 -0
- package/anno-store-export.ts +661 -0
- package/anno-store.ts +518 -2
- package/anno-tools.ts +1169 -16
- package/anno-types.ts +275 -2
- package/backend-detect.mts +124 -312
- package/build.ts +3 -1
- package/capture-predicate.ts +597 -0
- package/channel-lock.ts +349 -0
- package/evid-ingest.ts +217 -0
- package/evid-reconcile.ts +316 -0
- package/host-tool-client.ts +430 -0
- package/incident-record.ts +23 -12
- package/install-resources.ts +29 -13
- package/memmap-lookup.ts +285 -0
- package/package.json +27 -8
- package/prg-image.ts +1 -2
- package/repo-root.ts +87 -3
- package/resources/backend-detect.mjs +98 -236
- package/resources/broker-control.mjs +189 -16
- package/resources/broker-epoch.mjs +1 -1
- package/resources/broker-kill.mjs +8 -2
- package/resources/broker-launch.mjs +365 -210
- package/resources/broker-state.mjs +64 -18
- package/resources/container-guard.mjs +1 -1
- package/resources/ghidra-project.mjs +790 -0
- package/resources/host-tool.mjs +2561 -0
- package/resources/vice-broker.mjs +330 -184
- package/resources/vice-launcher.sh +127 -9
- package/stock-address.ts +1 -1
- package/stock-condition.ts +1 -1
- package/stock-connect.ts +9 -5
- package/stock-derived.ts +29 -37
- package/stock-diagnose.ts +200 -36
- package/stock-dispatch.ts +179 -77
- package/stock-handler.ts +1 -1
- package/stock-paths.ts +18 -14
- package/stock-petscii.ts +1 -1
- package/stock-protocol.ts +1 -1
- package/stock-recycle.ts +83 -2
- package/stock-reproducible-run.ts +811 -0
- package/stock-run-until.ts +100 -1
- package/stock-symbols.ts +4 -4
- package/stock-timing.ts +1 -1
- package/stop-oracle.ts +167 -0
- package/text-capability-probe.ts +660 -0
- package/text-connect.ts +157 -0
- package/text-protocol.ts +810 -0
- package/text-tools.ts +778 -0
- package/textmon-backtrace.ts +385 -0
- package/textmon-cpuhistory.ts +335 -0
- package/textmon-memmap.ts +494 -0
- package/textmon-profile.ts +458 -0
- package/textmon-registers.ts +748 -0
- package/tools-manifest.stock.json +864 -3
- package/vice-broker-client.ts +189 -42
- package/vice-errors.ts +268 -0
- package/vice-proxy.ts +339 -2144
- package/vsf-slice.ts +640 -0
- package/anno-d64.ts +0 -310
- package/capability-registry.ts +0 -390
- package/refresh-manifest.ts +0 -124
- package/tools-manifest.json +0 -1223
- package/vice-probe.ts +0 -278
- package/vice-sync.ts +0 -336
- package/vice.ts +0 -772
package/anno-types.ts
CHANGED
|
@@ -111,7 +111,7 @@ import { existsSync, lstatSync, readlinkSync, realpathSync } from "node:fs";
|
|
|
111
111
|
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
112
112
|
|
|
113
113
|
import { OPCODES } from "./disasm-opcodes.ts";
|
|
114
|
-
import { ViceError, type ViceErrorOptions } from "./vice.ts";
|
|
114
|
+
import { ViceError, type ViceErrorOptions } from "./vice-errors.ts";
|
|
115
115
|
|
|
116
116
|
/**
|
|
117
117
|
* The on-disk schema version every store file carries in `anno_meta`. A
|
|
@@ -182,8 +182,158 @@ import { ViceError, type ViceErrorOptions } from "./vice.ts";
|
|
|
182
182
|
* exist, and it would put new code into a module six hardening rounds went
|
|
183
183
|
* into. Stating the difference is the point: this one is a choice, not an
|
|
184
184
|
* impossibility.
|
|
185
|
+
*
|
|
186
|
+
* ---------------------------------------------------------------------------
|
|
187
|
+
* VERSION 4, 2026-09-10 (EVID-02) -- THE DECISION IS `reaffirm-refusal`, AND
|
|
188
|
+
* THE FACTUAL BASIS IS TRANSCRIBED HERE RATHER THAN LEFT IN A PLANNING
|
|
189
|
+
* DIRECTORY, for the same reason VERSION 3's paragraph gives.
|
|
190
|
+
*
|
|
191
|
+
* WHAT THE BUMP BUYS: `anno_evid_exec`, the durable, run-identity-keyed table
|
|
192
|
+
* that records ONE fact per row -- an address was OBSERVED EXECUTING during a
|
|
193
|
+
* specific run -- so a later session can query accumulated runtime evidence
|
|
194
|
+
* instead of re-running the program. See `anno-store.ts`'s `DDL` and its
|
|
195
|
+
* `insertExecObservations` / `listExecObservations` / `listObservedRuns` /
|
|
196
|
+
* `deleteExecObservationsForRun`.
|
|
197
|
+
*
|
|
198
|
+
* THE OPTION SELECTED, BY NAME: `reaffirm-refusal`. The strict-equality
|
|
199
|
+
* refusal inside `openStore` stays exactly as VERSION 3 left it -- a
|
|
200
|
+
* version-3 store does not open under this `SCHEMA_VERSION`, no migration arm
|
|
201
|
+
* is written, and the single-witness property (one comparison site, no
|
|
202
|
+
* second write of `anno_meta.schema_version`) is unchanged.
|
|
203
|
+
*
|
|
204
|
+
* THE FACTUAL CHECK, RUN 2026-09-10, SCOPE ONE DEVELOPMENT MACHINE:
|
|
205
|
+
* 1. `find / -xdev -name '*.annostore'`, with `.git` directories excluded --
|
|
206
|
+
* empty. The broader `find "$HOME" -name '*.annostore'` (closing the `-xdev`
|
|
207
|
+
* mount-boundary gap) found five hits, all inside a dated (2026-08-27)
|
|
208
|
+
* scratch probe cache (`~/.cache/gsd-probe/c4/...`), with
|
|
209
|
+
* fixture-pattern names (`t-half`, `t-zero`, `t-tail-100`, `p`, `proj`)
|
|
210
|
+
* and one file zero bytes -- synthetic test fixtures, not a real
|
|
211
|
+
* project's store.
|
|
212
|
+
* 2. `git log --oneline --diff-filter=A -- '*.annostore'` -- empty. No
|
|
213
|
+
* `.annostore` has ever been added to this repository's history.
|
|
214
|
+
* 3. Release tags versus when the store landed: `anno-store.ts` was added
|
|
215
|
+
* by `4c9cea3c` (2026-08-27). `v0.7.0` (2026-09-01) and `v0.8.0`
|
|
216
|
+
* (2026-09-06) BOTH POSTDATE that landing and the VERSION 3 bump
|
|
217
|
+
* itself. **THIS CORRECTS THE VERSION 3 PARAGRAPH ABOVE**: its stated
|
|
218
|
+
* justification -- "the last release tag (`v0.5.0`, 2026-08-25)
|
|
219
|
+
* PREDATES the store entirely -- so no tagged release has ever shipped
|
|
220
|
+
* a store at all" -- was true when written (2026-08-29) and is STALE
|
|
221
|
+
* now. Two tagged releases since then could, in principle, have shipped
|
|
222
|
+
* a working store to a real user.
|
|
223
|
+
* 4. Nothing outside that dated scratch/probe cache directory, and nothing
|
|
224
|
+
* tracked in git, was found on this machine.
|
|
225
|
+
*
|
|
226
|
+
* THE RE-AFFIRMATION IS MADE DESPITE THAT CORRECTION, on the strength of the
|
|
227
|
+
* observed NULL RESULT (zero real stores found), not on the strength of the
|
|
228
|
+
* now-stale "no release ever shipped one" framing. What changed since VERSION
|
|
229
|
+
* 3 is the *possibility* of a field store, not an observation of one, and the
|
|
230
|
+
* two directions' costs are asymmetric in reversibility: re-affirming refusal
|
|
231
|
+
* STAYS REVERSIBLE -- a migration arm can be added later, at version 5,
|
|
232
|
+
* against real evidence -- while shipping a mutating open path now adds a
|
|
233
|
+
* half-reasoned migration to a module that also has a corruption-refusal
|
|
234
|
+
* path, exactly where silent corruption lives, inside a plan whose actual job
|
|
235
|
+
* is an evidence table rather than a schema-migration redesign. House style
|
|
236
|
+
* settles the shape too: this project's standing pattern for a mismatched or
|
|
237
|
+
* missing external state is DETECT, THEN REFUSE BY NAME WITH THE REMEDY IN
|
|
238
|
+
* THE MESSAGE (`CLAUDE.md`'s "external tools are never auto-installed"
|
|
239
|
+
* constraint states the same discipline for a different kind of missing
|
|
240
|
+
* state) -- `openStore`'s refusal message is extended to name that remedy
|
|
241
|
+
* explicitly and to say the refused file is left untouched, so a user who
|
|
242
|
+
* hits it is not left inferring either fact.
|
|
243
|
+
*
|
|
244
|
+
* THE FACTUAL BASIS IS ONE MACHINE ONLY, and the limit travels with the
|
|
245
|
+
* decision: this is not a global guarantee that no field store exists --
|
|
246
|
+
* exactly the scope VERSION 3's own paragraph already accepted once.
|
|
247
|
+
*
|
|
248
|
+
* THE VERSION 1 PARAGRAPH ABOVE IS STILL THE PRECEDENT THIS IS MEASURED
|
|
249
|
+
* AGAINST, and this refusal is, again, a CHOICE and not an impossibility:
|
|
250
|
+
* version 4 COULD be given a migration arm and deliberately is not, for the
|
|
251
|
+
* reasons above.
|
|
252
|
+
*
|
|
253
|
+
* THE REVERSAL CONDITION, RECORDED SO THIS DOES NOT QUIETLY HARDEN INTO
|
|
254
|
+
* PRECEDENT: a migration arm at version 5 is justified if a real, non-scratch
|
|
255
|
+
* `.annostore` file is found in the field -- a user's own project, a bug
|
|
256
|
+
* report attaching one, or a support request -- or if a documented
|
|
257
|
+
* distribution channel is shown to have shipped a version-3 or version-4
|
|
258
|
+
* store to users who have not yet upgraded past it. Absent that evidence, the
|
|
259
|
+
* refusal stays the default.
|
|
260
|
+
*
|
|
261
|
+
* ---------------------------------------------------------------------------
|
|
262
|
+
* VERSION 5, 2026-09-11 (BUILD-07) -- THE DECISION IS `reaffirm-refusal`, THE
|
|
263
|
+
* SAME OPTION VERSION 4 SELECTED, AND THE FACTUAL BASIS IS TRANSCRIBED HERE
|
|
264
|
+
* RATHER THAN LEFT IN A PLANNING DIRECTORY, for the same reason every prior
|
|
265
|
+
* version's paragraph gives.
|
|
266
|
+
*
|
|
267
|
+
* WHAT THE BUMP BUYS: `anno_excluded_range`, the durable record of a
|
|
268
|
+
* user-requested exclusion -- its extent AND the reason the user gave -- so
|
|
269
|
+
* the export can emit the range's real bytes tagged with a visible marker
|
|
270
|
+
* comment instead of a hole, which is `BUILD-07`'s whole invariant: an
|
|
271
|
+
* exclusion is a RECORDED, VISIBLE fact, never a silent drop. See
|
|
272
|
+
* `anno-store.ts`'s `DDL` and its three verbs, `addExcludedRange` /
|
|
273
|
+
* `listExcludedRanges` / `removeExcludedRange`.
|
|
274
|
+
*
|
|
275
|
+
* THE OPTION SELECTED, BY NAME: `reaffirm-refusal`. The strict-equality
|
|
276
|
+
* refusal inside `openStore` stays EXACTLY as VERSION 4 left it -- this bump
|
|
277
|
+
* does not touch that comparison site at all: a version-4 store does not open
|
|
278
|
+
* under this `SCHEMA_VERSION`, no migration arm is written, and the
|
|
279
|
+
* single-witness property (one comparison site, no second write of
|
|
280
|
+
* `anno_meta.schema_version`) is unchanged.
|
|
281
|
+
*
|
|
282
|
+
* THE FACTUAL CHECK, RUN 2026-09-11, SCOPE ONE DEVELOPMENT MACHINE -- the
|
|
283
|
+
* same three checks VERSION 4 ran, re-run rather than inherited, with the
|
|
284
|
+
* REAL results transcribed as of today:
|
|
285
|
+
* 1. `find "$HOME" -name '*.annostore'`, with `.git` directories excluded --
|
|
286
|
+
* SIX hits, not VERSION 4's five. The same five fixture-pattern files
|
|
287
|
+
* inside the dated (2026-08-27) scratch probe cache (`t-half`, `t-zero`,
|
|
288
|
+
* `t-tail-100`, `p`, `proj`) are still present, UNCHANGED. The SIXTH is
|
|
289
|
+
* NEW since VERSION 4's check: `.c64-re-tools/phase45-scratch/
|
|
290
|
+
* tracer.annostore`, inside THIS repository's own gitignored scratch
|
|
291
|
+
* directory, timestamped 2026-09-10 -- its path and name identify it as
|
|
292
|
+
* Phase 45's own tracer/scratch fixture, not a real consuming project's
|
|
293
|
+
* store. Six real files, zero real stores.
|
|
294
|
+
* 2. `git log --oneline --diff-filter=A -- '*.annostore'` -- still empty.
|
|
295
|
+
* No `.annostore` has ever been added to this repository's tracked
|
|
296
|
+
* history.
|
|
297
|
+
* 3. Release tags versus when the store landed: `anno-store.ts` was added
|
|
298
|
+
* by `4c9cea3c` (2026-08-27). Since VERSION 4's check, ONE MORE tagged
|
|
299
|
+
* release has been cut -- `v0.9.0` (2026-09-10) -- joining `v0.7.0`
|
|
300
|
+
* (2026-09-01) and `v0.8.0` (2026-09-06). All THREE now postdate the
|
|
301
|
+
* store's landing and VERSION 3's original bump, so three tagged
|
|
302
|
+
* releases, not two, could in principle have shipped a working store to
|
|
303
|
+
* a real user. No result differs in KIND from VERSION 4's; the count of
|
|
304
|
+
* possible-exposure releases has grown by one, consistent with time
|
|
305
|
+
* having passed rather than with any new evidence of a real store.
|
|
306
|
+
*
|
|
307
|
+
* THE RE-AFFIRMATION IS MADE ON THE SAME BASIS VERSION 4 USED: the observed
|
|
308
|
+
* NULL RESULT (zero real, non-scratch stores found across six candidate
|
|
309
|
+
* files), not on a claim that no release could have shipped one. The new
|
|
310
|
+
* sixth file changes nothing about that null result -- it is this project's
|
|
311
|
+
* OWN scratch output, in a directory this project's own tooling writes to and
|
|
312
|
+
* that ships nothing.
|
|
313
|
+
*
|
|
314
|
+
* WHY A NEW TABLE WAS CHOSEN OVER A NULLABLE `excluded`/`exclusion_reason`
|
|
315
|
+
* COLUMN PAIR ON `anno_range`, recorded because it is the one part of this
|
|
316
|
+
* decision that is structural rather than stylistic: an exclusion's extent is
|
|
317
|
+
* chosen by the USER and has no reason to coincide with a typed range's
|
|
318
|
+
* boundaries, so a column on `anno_range` would force `retype()`'s carve to
|
|
319
|
+
* split, duplicate, or lose an exclusion's reason every time a range boundary
|
|
320
|
+
* moved underneath it -- `retype()` knows nothing about exclusions today and
|
|
321
|
+
* a column would force it to. A separate table keeps the user's own words
|
|
322
|
+
* independent of the store's typing churn entirely. This also happens to
|
|
323
|
+
* match the project's existing preference (`anno_evid_exec` at VERSION 4 over
|
|
324
|
+
* widening `anno_range`), but that precedent is the WEAKER of the two
|
|
325
|
+
* arguments -- the structural one above is the one that would still hold even
|
|
326
|
+
* if this project had no such precedent.
|
|
327
|
+
*
|
|
328
|
+
* THE REVERSAL CONDITION, RECORDED SO THIS DOES NOT QUIETLY HARDEN INTO
|
|
329
|
+
* PRECEDENT: a migration arm at version 6 is justified if a real, non-scratch
|
|
330
|
+
* `.annostore` is found in the field -- a user's own project, a bug report
|
|
331
|
+
* attaching one, or a support request -- or if a documented distribution
|
|
332
|
+
* channel is shown to have shipped a version-4 or version-5 store to users
|
|
333
|
+
* who have not yet upgraded past it. Absent that evidence the refusal stays
|
|
334
|
+
* the default.
|
|
185
335
|
*/
|
|
186
|
-
export const SCHEMA_VERSION =
|
|
336
|
+
export const SCHEMA_VERSION = 5;
|
|
187
337
|
|
|
188
338
|
/** The 6510's address space, inclusive at both ends. */
|
|
189
339
|
export const ADDRESS_MIN = 0x0000;
|
|
@@ -464,6 +614,23 @@ export interface ScopeRow {
|
|
|
464
614
|
endInclusive: number;
|
|
465
615
|
}
|
|
466
616
|
|
|
617
|
+
/** One user-requested exclusion as the store holds it, added at
|
|
618
|
+
* `SCHEMA_VERSION` 5 (`BUILD-07`). Both ends are INCLUSIVE, matching every
|
|
619
|
+
* other range-shaped row this store persists. There is no `bank` column,
|
|
620
|
+
* because an exclusion is a statement about a span of the SUBJECT PROGRAM the
|
|
621
|
+
* user asked to leave out of the rebuild -- not a memory view -- and there is
|
|
622
|
+
* no confidence, verdict, grade or severity column, because this row holds
|
|
623
|
+
* WHAT THE USER ASKED FOR and nothing the tool concluded about it. A
|
|
624
|
+
* judgement column here would be the exact "tool is the decider" shape
|
|
625
|
+
* `BUILD-05`'s 2026-09-10 rewording removed: the store answers "what did the
|
|
626
|
+
* user record", never "should this range be excluded". */
|
|
627
|
+
export interface ExcludedRangeRow {
|
|
628
|
+
id: number;
|
|
629
|
+
start: number;
|
|
630
|
+
endInclusive: number;
|
|
631
|
+
reason: string;
|
|
632
|
+
}
|
|
633
|
+
|
|
467
634
|
/** One project-local enum as the store holds it. `variants` is keyed by the
|
|
468
635
|
* numeric-string forms the schema names -- decimal, `0x`/`$` hex, `0b`/`%`
|
|
469
636
|
* binary -- and its values are variant names. */
|
|
@@ -505,6 +672,81 @@ export interface XrefRow {
|
|
|
505
672
|
bank: number | null;
|
|
506
673
|
}
|
|
507
674
|
|
|
675
|
+
/**
|
|
676
|
+
* The three memory regions `memmapshow` reports an execute observation
|
|
677
|
+
* against, `SCHEMA_VERSION` 4 (EVID-01). This is the ONE place this
|
|
678
|
+
* vocabulary is written down.
|
|
679
|
+
*
|
|
680
|
+
* ALL THREE ARE INCLUDED DELIBERATELY, not for symmetry: `AccessFlags`
|
|
681
|
+
* (`textmon-memmap.ts`) carries `read`/`write`/`execute` as three
|
|
682
|
+
* INDEPENDENT bits per region, and dropping any one of the three regions
|
|
683
|
+
* here would discard a genuine positive observation the wire already
|
|
684
|
+
* reported -- `io.execute` is exactly as real a fact as `ram.execute`.
|
|
685
|
+
*/
|
|
686
|
+
export const EVID_SOURCE_BANKS = Object.freeze(["ram", "rom", "io"] as const);
|
|
687
|
+
|
|
688
|
+
/** One of the three evidence source banks. */
|
|
689
|
+
export type EvidSourceBank = (typeof EVID_SOURCE_BANKS)[number];
|
|
690
|
+
|
|
691
|
+
/**
|
|
692
|
+
* The runtime evidence layer's own classification of an address, `SCHEMA_VERSION`
|
|
693
|
+
* 4 (EVID-04). This is a TYPE-LEVEL control, not a runtime check: the union has
|
|
694
|
+
* exactly two members and NO `"data"` member exists for a caller to return,
|
|
695
|
+
* mistakenly or otherwise.
|
|
696
|
+
*
|
|
697
|
+
* THIS IS THE SAME DISCIPLINE `textmon-memmap.ts` STATES FOR ITSELF, carried
|
|
698
|
+
* forward rather than re-derived: that module's own header forbids adding
|
|
699
|
+
* "a field, key, label or enum member anywhere in this module or its answer
|
|
700
|
+
* types that classifies an address as DATA on the strength of never having
|
|
701
|
+
* been observed" (`textmon-memmap.ts:32-38`). `BlockClass`'s three-valued
|
|
702
|
+
* union (`"code" | "data" | "undefined"`, `block-class.ts`) is the byte-derived
|
|
703
|
+
* classifier's own vocabulary and is DELIBERATELY NOT REUSED here: that union
|
|
704
|
+
* exists to name a byte-derived guess, and this one exists to name only what
|
|
705
|
+
* was actually witnessed executing. `"unobserved"` means exactly "no
|
|
706
|
+
* execution was ever recorded at this address" -- never "this address is
|
|
707
|
+
* data" -- and no code path in this layer may treat the two as
|
|
708
|
+
* interchangeable (see the ban on deriving `data` from absence, Pitfall 3 in
|
|
709
|
+
* this phase's research).
|
|
710
|
+
*/
|
|
711
|
+
export type RuntimeExecClass = "code" | "unobserved";
|
|
712
|
+
|
|
713
|
+
/**
|
|
714
|
+
* One runtime-execution observation as the store holds it (`anno_evid_exec`,
|
|
715
|
+
* `SCHEMA_VERSION` 4). Keyed by the bare run-identity triple
|
|
716
|
+
* `(imageSha256, argvDigest, seed)` plus `address` plus `sourceBank` -- the
|
|
717
|
+
* `no-change` assumption-delta decision plan 43-01's live A/B selected
|
|
718
|
+
* (`docs/phase43-instrumentation-perturbation-ab.md`): there is no
|
|
719
|
+
* `run_class` discriminator column, because instrumentation was measured
|
|
720
|
+
* `no-perturbation` at anchor hit depths 10 and 50.
|
|
721
|
+
*
|
|
722
|
+
* A row here asserts exactly ONE fact: this address was observed executing,
|
|
723
|
+
* in this source bank, during this run. There is no `bank`-reserved column
|
|
724
|
+
* (unlike the annotation tables) and no nullable column -- every field is a
|
|
725
|
+
* fact this table is licensed to assert, or the row does not exist.
|
|
726
|
+
*/
|
|
727
|
+
export interface EvidExecRow {
|
|
728
|
+
id: number;
|
|
729
|
+
imageSha256: string;
|
|
730
|
+
argvDigest: string;
|
|
731
|
+
seed: string;
|
|
732
|
+
address: number;
|
|
733
|
+
sourceBank: EvidSourceBank;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/**
|
|
737
|
+
* One distinct run identity's accumulated observation count, as
|
|
738
|
+
* `listObservedRuns()` reports it. `observationCount` is a COUNT, never a
|
|
739
|
+
* percentage or rate -- see `listObservedRuns`'s own doc comment in
|
|
740
|
+
* `anno-store.ts` for the denominator this count is a fraction of (EVID-04:
|
|
741
|
+
* a count with no denominator invites the reading "the rest is data").
|
|
742
|
+
*/
|
|
743
|
+
export interface ObservedRunRow {
|
|
744
|
+
imageSha256: string;
|
|
745
|
+
argvDigest: string;
|
|
746
|
+
seed: string;
|
|
747
|
+
observationCount: number;
|
|
748
|
+
}
|
|
749
|
+
|
|
508
750
|
/** What `resolveSplitTargets()` returns: the entry count, the resolved 16-bit
|
|
509
751
|
* targets in table order, and whether this layout produces cross-references at
|
|
510
752
|
* all. Nothing here is ever written to disk. */
|
|
@@ -1300,6 +1542,37 @@ export function assertAccessKind(value: unknown): XrefAccessKind {
|
|
|
1300
1542
|
return assertMember(value, XREF_ACCESS_KINDS, "access kind");
|
|
1301
1543
|
}
|
|
1302
1544
|
|
|
1545
|
+
/** Narrows an unvalidated argument to an `EvidSourceBank`, or throws
|
|
1546
|
+
* `AnnoTypeError` carrying the offending value and all three valid members. */
|
|
1547
|
+
export function assertEvidSourceBank(value: unknown): EvidSourceBank {
|
|
1548
|
+
return assertMember(value, EVID_SOURCE_BANKS, "source bank");
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
/** Exactly 64 lowercase hex characters -- the shape `argvDigest()`
|
|
1552
|
+
* (`capture-predicate.ts`) and a sha256 image hash both already produce.
|
|
1553
|
+
* Refuses anything else BY NAME, including a correctly-shaped but
|
|
1554
|
+
* UPPERCASE digest, rather than lower-casing it silently: two callers
|
|
1555
|
+
* disagreeing on case is exactly the kind of divergence a store write must
|
|
1556
|
+
* not launder into agreement. */
|
|
1557
|
+
export function assertRunIdentityDigest(value: unknown, what: string): string {
|
|
1558
|
+
if (typeof value === "string" && /^[0-9a-f]{64}$/.test(value)) {
|
|
1559
|
+
return value;
|
|
1560
|
+
}
|
|
1561
|
+
throw new AnnoTypeError(
|
|
1562
|
+
`${what} ${JSON.stringify(value)} is not exactly 64 lowercase hex characters -- expected a sha256 hex digest such as argvDigest() or an image hash produces`,
|
|
1563
|
+
{ dataType: value },
|
|
1564
|
+
);
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
/** A non-empty string. `seed` is not a digest and carries no shape beyond
|
|
1568
|
+
* that -- REPRO-04's run-identity composite treats it as an opaque token. */
|
|
1569
|
+
export function assertRunIdentitySeed(value: unknown): string {
|
|
1570
|
+
if (typeof value === "string" && value.length > 0) {
|
|
1571
|
+
return value;
|
|
1572
|
+
}
|
|
1573
|
+
throw new AnnoTypeError(`seed ${JSON.stringify(value)} is not a non-empty string`, { dataType: value });
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1303
1576
|
/** The legal-identifier shape, quoted from the schema's own sentence
|
|
1304
1577
|
* (`anno-tools.ts:246-251`): "starts with a letter or underscore, followed by
|
|
1305
1578
|
* letters/digits/underscores only". Used for label names and for project-enum
|