feat(foundation): offline synthetic scope/permission inspector (FI-FILBERT-8 APPROVED r6)

Rocko-authored, Filbert-reviewed inspector (r6 manifest
a4a44930...) with full review/build/verdict evidence under
docs/plans/reviews. 43/0 selftests, oracle zero-disagreement,
foundation checker PASS. Owner A9 acceptance recorded separately.
This commit is contained in:
2026-09-07 14:06:35 -05:00
parent 127a54fdff
commit 8ebddd6f93
423 changed files with 665972 additions and 0 deletions
+101
View File
@@ -0,0 +1,101 @@
# Foundation inspector fixtures
Synthetic, deterministic inputs for `scripts/foundation-inspect.mjs` and its tests.
Nothing here is live: identities, digests, times and paths are invented by
`build-fixtures.mjs` (SHA-256 of `synthetic:<label>` for every fake digest).
| Path | Content |
| --- | --- |
| `build-fixtures.mjs` | Generator. `node scripts/foundation/fixtures/build-fixtures.mjs <out-dir>` |
| `bundles/<case>.json` | One complete bundle per evaluation case (pretty JSON, trailing newline) |
| `raw/<case>.json` | Byte-exact lexical cases (duplicate keys, BOM, invalid UTF-8, oversize, ...) |
| `index.json` | Expected `exit/result/reason/rule/proposalRule[/byteOffset]` per case, sorted by name |
| `demo/<case>.json` | Owner-demo copies of five bundles, byte-identical to `bundles/` |
| `demo/<case>.expected.{txt,json,exit}` | Goldens: text output, `--json` output and exit code |
## Regeneration
```sh
node scripts/foundation/fixtures/build-fixtures.mjs /tmp/fx
diff -r /tmp/fx/bundles scripts/foundation/fixtures/bundles
diff -r /tmp/fx/raw scripts/foundation/fixtures/raw
diff /tmp/fx/index.json scripts/foundation/fixtures/index.json
```
`scripts/test-foundation.sh` performs exactly this comparison; a checked-in
fixture that differs from a fresh generation fails the suite. Goldens are
produced by running the inspector on the demo copies:
```sh
cd scripts/foundation/fixtures/demo
for f in *.json; do case "$f" in *.expected.*) continue;; esac
b="${f%.json}"
node ../../../foundation-inspect.mjs "$f" > "$b.expected.txt"; echo $? > "$b.expected.exit"
node ../../../foundation-inspect.mjs --json "$f" > "$b.expected.json"
done
```
## Case groups (see `index.json`)
positive, shape, profile, identity, structure, cycle, continuity, ownership,
operation, admission, registration-delegation, proposal, lexical (raw). Every
rule in the closed vocabulary except the CLI/I-O rules (covered by
`../cli.test.mjs` with a disposable sandbox) is exercised by at least one case;
`../resolve.test.mjs` enforces that.
The `profile-*` cases (addendum FI-C2-1) cover the strict typed-string profile:
one final LF on an `id`/`runtimeId`/`digest` value is schema-valid under the pinned
checker's `$` semantics and refused by the inspector as `profile-pattern-mismatch`
before any identity lookup (group `profile`); two final LFs, CRLF, CR, interior LF,
U+2028 and U+2029 fail the schema pattern itself (group `shape`); free-form text
with escaped newlines stays allowed (group `positive`).
The FI-FILBERT-6 correction cases (verdict findings F1F5) are the review's witness
recipes rebuilt from the frozen demo bundles, each with positive controls:
`adm-registry-declaration-*` and `adm-*-authorization-undeclared` (F1: every consulted
registry reference resolves by exact registry/id/revision/digest, rule
`registry-declaration-missing`; consulted dependency/mission/subject-task
authorizations must be declared), `adm-assigned-task-without-work-read*` and
`prop-task-only-*` (F2: a bound task is consulted work), `prop-issuer-*` (F3: the
issuer ceiling narrows both requester calculations and work access is rechecked),
`cycle-*versioned*` / `cycle-*-cross-revision` / `cycle-mission-parent-*revision*`
(F4: revision-exact cycle graphs), `shape-order-*` and `prop-message-*` /
`prop-delegation-missing-after-requester-admission` (F5: first failure independent of
record input order; message-is-not-authority after structural validation, before
requester admission). `../resolve.test.mjs` asserts each recipe's first failure and
permutation independence directly.
The FI-ROCKO-7 ordering cases extend F5 to the declared inventories (charter §10.4
applies beyond records): `shape-order-registries-*`, `shape-order-artifacts-*`,
`shape-order-authorizations-*`, `shape-order-delegation-inputs-*` (two different shape
errors per pair, forward and reversed, plus a "swapped" pair where the errors change
places and a malformed entry without a readable typed key, which sorts last),
`shape-order-family-precedence-*` (records, registries, artifacts, authorizations,
delegationInputs stay in that stage order), `profile-order-*` (strict-profile
violations follow the same key; any shape failure precedes them),
`shape-order-registry-digest-*` / `shape-order-profile-precedes-digest-registries` /
`shape-order-two-digest-mismatches-reversed` (content-digest traversal in
registry/id/revision/digest order after the profile stage), `dup-order-*` (identity
stage) and `struct-order-delegation-inputs-*` (structural stage). Typed keys:
registries `registry/id/revision/digest`, artifacts `runId/artifactId/digest`,
authorizations the runtime id, delegationInputs `decisionRef` kind/id/scope/revision;
equal keys tie-break on the entry's total ordering form (below). Semantic sequence arrays (instruction,
skill, endpoint, dependency, subject and evidence lists, paths, canonical content) are
never reordered. `../resolve.test.mjs` asserts the located first failure over every
permutation (all permutations for inventories of up to four entries, a fixed
deterministic family beyond that).
The FI-ROCKO-8 cases (FI-FILBERT-7 finding R5-1) fix the tie-break itself: r5 broke
ties on the ASCII-only mock-digest canonicalizer and mapped every non-ASCII entry to one
empty form, so two distinct Unicode entries with equal (or no) typed keys fell back to
input order. The inspector now orders ties by a total ordering form defined over the
whole strict-JSON input domain (sorted keys, array order kept, every string as a JSON
literal, no normalization), which is injective on distinct values and never a digest or
a validity judgement. `shape-order-unkeyed-unicode-<family>-{forward,reversed}` (two
unreadable non-ASCII entries per family: a string and an object, `shape-type-mismatch`
in both orders), `shape-order-equal-key-unicode-{records,registries}-{forward,reversed}`
(two copies with identical typed keys, a legitimate non-ASCII value and one different
shape error each: `shape-unknown-field` in both orders) and
`positive-unicode-display-name-allowed` (control). `../resolve.test.mjs` asserts the
form's totality and injectivity against `canonicalize()` refusals and the permutation
stability of every pair.