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.
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1813
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1798
File diff suppressed because it is too large
Load Diff
+1838
File diff suppressed because it is too large
Load Diff
+1837
File diff suppressed because it is too large
Load Diff
+1823
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1816
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+2118
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1865
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user