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:
@@ -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 F1–F5) 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.
|
||||
Reference in New Issue
Block a user