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.
20 KiB
Foundation inspector — rocko build report r5 (FI-ROCKO-7: §10.4 stable traversal of the declared inventories)
Author: rocko (Claude Fable 5.1). Coordinator: darkwing. Reviewer: filbert. Task: FI-ROCKO-7.
Written 2026-09-07 15:03 UTC. Supersedes nothing: the original report, the r2/r3/r4
reports and manifests, the charter, the addendum, both verdicts, the corrections
request, the ordering follow-up and the demo test-gate decision are preserved unedited.
This revision closes the F5 remainder disclosed in r4 §3(b) (declared inventories were
still shape-validated in input order; the registry digest traversal at r4
resolve.mjs:831 used input order), records what changed r4 → r5, the per-family
permutation evidence, the owner's demo test-gate decision, and the frozen candidate
for independent re-review.
0. Admission, compatibility and blockers
FI-ROCKO-7 is admitted and compatible with the standing chain, the FI-ROCKO-3 build request, the corrections request, the ordering follow-up and the demo test-gate decision; the code/test work is complete under the original allowlist plus the two r5 receipt paths named in the follow-up. C1 (Archify rev 3) remains HELD with no lane action.
No open blocker. The r4 §7 integration-gate blocker (scripts/test-task.sh and
scripts/test-release.sh not runnable here without executing Docker/live branches) is
now governed by the owner decision recorded in
docs/plans/reviews/2026-09-07_foundation-inspector-demo-test-gate-decision.md
(sha256 62cea74b…4898, 2026-09-07 14:47 UTC): both suites are NOT RUN / DEFERRED
for this offline demo (§7). They are not reported green and no live test authority is
claimed. The decision changes only the offline-demo test prerequisite; full
deployment/integration testing remains a later gate.
Inputs bound to this revision (all hashes machine-read; full list in the r5 manifest
pinnedInputs):
| Input | sha256 |
|---|---|
charter docs/plans/2026-09-06_foundation-inspector-charter.md |
19b6721128a627a2032ffdb95ece2d50abe69a8f6d521e9eff8bbdaff22798b6 |
| addendum FI-C2-1 | afe2980be2f91e701dae5af3018831ac5c300474f52bcc06e740ce5b5cc68ca5 |
| code verdict FI-FILBERT-6 | e4cc5970aab20240e6ea3a9a1513ef942ff167fefbb03356b9a32c89999adb3d |
| corrections request | 35c237f5c001832a0cfed23b03ff7530ffa78443612ffe11130fe456b968bd61 |
| r4 report | dff9f676ad0a97f6333a59d527e02ed55e7bcdca986fe9c1488280b84d4e677f |
| r4 manifest (331 files) | 2a2e885f9df3dd626a09fe5db6e28af67c289e54660872031c18f8aa40cb0826 |
ordering follow-up …_foundation-inspector-ordering-followup.md |
e93a65b94fd4df8bd6e74c2f38afaf02e0f86b36632ff5a820fd8ac464c22101 |
demo test-gate decision …_foundation-inspector-demo-test-gate-decision.md |
62cea74bea59e69f29c8a29a9c0311fdc6feffa2c337bc6a141db55149204898 |
| pinned schema / checker / fixtures | 05774aaf…2af6 / 82564a7d…4607 / d433d06d…da85 |
Git: HEAD 9a5fbdbda74b16adf488fe28138b2ba69ea5e669 (main), unchanged throughout;
nothing staged; the only tracked modifications are the pre-existing ones
(BUILD-LOG.md, docs/SESSIONS.md, docs/plans/CURRENT.md, not touched by rocko).
All candidate files remain untracked. Toolchain: node v26.8.1, Python 3.12.8,
jsonschema 4.26.0, Linux 7.2.2-1-cachyos.
1. Evidence preservation
- r4 report and manifest: unedited, hashes above re-verified after the r5 build.
- r3 report (
ec0444c9…5508) and manifest (3c2253b6…8547): unedited. The r4 §3(g) correction stands and is repeated here so it stays visible in history: the r3test-task.sh90/0 receipt did execute the suite's Docker and live branches (Docker was reachable), contradicting r3 §6 "no engine launch". r3 is not relabeled; those actions were not repeated in r4 or r5 (§7). - Charter, addendum, verdicts, corrections request, follow-up, decision doc, pinned
schema/checker/fixtures: unedited (manifest
pinnedInputs). - Every pre-existing fixture bundle, raw case, demo copy and golden is byte-identical
to r4 (manifest diff: 5 files changed, 38 bundles added, 0 removed; §4). Every prior
index.jsonexpectation is unchanged; only 38 cases were appended.
2. Closure of the ordering follow-up
2.1 What §10.4 requires and what r4 still did
Charter §10.4: "Within a stage use stable kind/id/scope/revision and field ordering,
not input order." r4 applied this to bundle.records only. Registries, artifacts,
authorizations and delegationInputs were traversed in input order at the shape stage
(checkArray per family), at the profile stage (the profile sink is filled in
validation order, so it inherited input order for these families), at the
content-digest check (r4 resolve.mjs:831, b.registries.forEach), at the identity
stage (duplicate checks per family) and at the structural stage (delegationInputs
decisionRef existence). The first failure within any of those traversals therefore
depended on input position.
2.2 Implementation (scripts/foundation/resolve.mjs)
stableOrder(items, keyOf)(exported, r5 lines 730–767): the generic stable traversal.keyOfreturns a typed key (array ofstring | integer | nullcomponents) ornullwhen the item has no readable identity. Order: keyed items before unkeyed; keys component-wise (anullcomponent after every readable value; strings by code unit; integers numerically); equal keys tie-break on canonical content (canonicalize,CanonicalError→ empty string); then input index. Returns input indices, so every locator path keeps the input index (privacy and locator semantics unchanged;detailremains internal).ORDER_KEYS(exported, 801–807), the typed identity key per family:- records:
[kind, id, scopeKey, revision](tolerant, exactly the r4 rule: unreadable kind/id/scope kind → unkeyed; non-integer revision →nullcomponent);shapeValidationOrdernow delegates tostableOrder, behaviour-preserving (all r4 F5 tests and fixtures unchanged); - registries:
[registry, id, revision, digest]; unkeyed unlessregistryandidare strings; - artifacts:
[runId, artifactId, digest]; unkeyed unlessrunId/artifactIdare strings; - authorizations:
[runtimeId]; unkeyed unless a string; - delegationInputs: the
decisionRefkind/id/scope/revision key; unkeyed unless the ref is readable.
- records:
checkInventory(v, path, itemCheck, keyOf)(813–818): bounds first (shape-type-mismatch,shape-bound-exceededat the array path, as before), then each item in stable order with its input-index path. Used for the four declared inventories invalidateBundleShapeScoped(821–823 and 857–864). Family precedence is unchanged: records → registries → artifacts → authorizations → selection → operation → proposal → delegationInputs.- Profile stage: unchanged code;
profileSink[0]is now the first violation in stable order for every family because the sink is filled in traversal order. - Digest stage (871–884): content-digest traversal iterates
stableOrder(b.registries, ORDER_KEYS.registries); rules, reasons and paths unchanged. Modelconstructor (1084–1089): computesthis.order(stable index lists for the four families) once;indexIdentities(stage 3) walks each family's duplicate check in that order;checkStructuralReferences(stage 4, 1181) walks delegationInputs in that order. Lookup-based consumers (requireRegistryDeclaration,registryContent,requireArtifacts, the authorizationSet,delegationInputs.find) are order-independent once duplicates are rejected and are untouched.- Semantic sequence arrays are not reordered.
checkArrayis unchanged and still used, in input order, foroperations,readPaths,writePaths,endpointRefs, instruction/skill/context-content lists,dependencies,subjectRefs,evidenceRefsand every other ordered array; canonical content is never reordered;evaluatedoes not mutate or reorder the input bundle (asserted). - Stage/field precedence preserved: every shape failure before any profile violation, every profile violation before any digest failure, identity before structural; within an entry the field order of the existing checkers is unchanged.
- No new rule, reason or exit; the closed vocabulary is unchanged. No input file is mutated; no exception is invented for declaration lists.
2.3 Per-family evidence (fixtures in build-fixtures.mjs 1076–1230; tests in resolve.test.mjs 548–712)
Each fixture pair carries two different failures on two entries; the expected first
rule is determined by the typed key, and the "swapped" pairs move the errors between
the same two entries so the expected rule changes with the key, not the position.
assertPermutationStable re-evaluates every permutation of the family (all
permutations for inventories of ≤ 4 entries; for larger inventories a fixed
deterministic family: identity, reverse, descending sort, odd/even interleave, every
rotation and twelve seeded Fisher–Yates shuffles) and asserts the identical located
first failure (rule, reason, exit, proposal step, and the locator resolved to the
entry's typed key plus field tail). Expected keys are asserted explicitly, so the
tests demonstrate intended first-rule stability, not merely a consistent nonzero exit.
| Family / stage | Fixtures (group) | Expected first rule and locator |
|---|---|---|
| registries, shape | shape-order-registries-{forward,reversed} (shape) |
shape-missing-field at agent-policy/ap-full (missing digest) before shape-unknown-field at project-policy/pp-p1 |
| registries, shape, swapped | shape-order-registries-swapped-{forward,reversed} |
shape-unknown-field at ap-full (errors exchanged) |
| registries, shape, malformed | shape-order-registries-malformed-sorts-last, -only-malformed |
{registry: 7} (unkeyed) sorts last → shape-enum-mismatch at the keyed bad entry .registry; a lone "not-an-entry" → shape-type-mismatch |
| registries, profile | profile-order-registries-{forward,reversed} (profile) |
profile-pattern-mismatch at agent-policy/ap-reader .id before scope-role/role-reader |
| registries, shape > profile | profile-order-shape-precedes-profile-registries (shape) |
shape-unknown-field at project-policy/pp-p2 although ap-reader carries the (earlier-key) profile violation |
| registries, digest | shape-order-registry-digest-{forward,reversed} (profile) |
mock-content-unsupported (unsupported-capability) at ap-full .content before registry-digest-mismatch at role-writer |
| registries, digest, swapped | shape-order-registry-digest-swapped-{forward,reversed} |
registry-digest-mismatch at ap-full .digest |
| registries, profile > digest | shape-order-profile-precedes-digest-registries |
profile-pattern-mismatch at pp-p2 .id although ap-full carries the digest mismatch |
| registries, two digest mismatches | shape-order-two-digest-mismatches-reversed |
registry-digest-mismatch at scope-role/role-reader (lower key) in every order |
| artifacts, shape | shape-order-artifacts-{forward,reversed}, -swapped-{forward,reversed}, -malformed-sorts-last |
shape-pattern-mismatch at run-1/art-1 .digest before shape-unknown-field at art-2; swapped → shape-unknown-field at art-1; {runId: 1} sorts last |
| artifacts, profile | profile-order-artifacts-reversed |
profile-pattern-mismatch at run-1/art-2 .artifactId (art-1's violation is on .runId, a higher key after the LF) |
| authorizations, shape | shape-order-authorizations-{forward,reversed}, -malformed-sorts-last |
shape-pattern-mismatch at the lower runtime id …-1000-…0002 in every order; a non-string entry sorts last |
| authorizations, profile and shape > profile | profile-order-authorizations-reversed, profile-order-shape-precedes-profile-authorizations |
profile-pattern-mismatch at …0001\n; a pattern failure on the higher id precedes a profile violation on the lower one |
| delegationInputs, shape | shape-order-delegation-inputs-{forward,reversed}, -swapped-{forward,reversed}, -malformed-sorts-last |
shape-enum-mismatch at decision/d-deleg-b .mode before shape-missing-field at d-deleg-reg; swapped → shape-missing-field at d-deleg-b; {decisionRef: null} sorts last |
| delegationInputs, structural | struct-order-delegation-inputs-{forward,reversed} (structure) |
record-reference-missing (missing-state) at d-deleg-b revision 9 .decisionRef in every order |
| delegationInputs, identity | dup-order-delegation-inputs-reversed (identity) |
duplicate-delegation-input located at the d-deleg-reg duplicate although a valid lower-key input is listed after it |
| family precedence | shape-order-family-precedence-{registries-before-artifacts,artifacts-before-authorizations,authorizations-before-delegation-inputs} |
the earlier family's failure wins regardless of positions |
| identity precedence | dup-order-registries-precede-artifacts (identity) |
duplicate-registry-identity before duplicate-artifact-identity |
| identity, differing digests (unit only) | resolve.test.mjs "family precedence and identity-stage order" |
duplicate plain-registry and artifact identities with differing digests: the higher digest is the reported entry in every order |
Unit test stableOrder: typed keys … pins the helper itself on hand-built inventories
(integer-before-null revision, digest tie-break, duplicate index tie-break, unkeyed
items ordered by canonical content, records/artifacts/authorizations/delegationInputs
keys) and asserts evaluate leaves the bundle byte-identical.
Mutation witness (scratchpad only, discarded): with stableOrder short-circuited to
input order for the four families, the seven new r5 tests fail (stableOrder, the
five per-family tests and the precedence test) while all r4 tests still pass; the
r5 tests therefore detect the r4 behaviour.
3. Disclosures for the reviewer
- (a) Tie-break for byte-identical duplicates. Two entries with equal typed key and equal canonical content are indistinguishable; the duplicate reported at the identity stage is then the higher input index. This is position-dependent only in the degenerate case where the two positions hold identical bytes, so no observable result changes. Entries with equal key but different content (e.g. duplicate registry identity with a different digest) are ordered by content and are permutation-stable (asserted).
- (b)
registry-digest-mismatch/mock-content-unsupportedshare one traversal. Both are raised in a single stable pass over registries after the profile stage; an unsupported content on a lower key precedes a mismatch on a higher key and vice versa. This is the intended first-rule order (key order, not rule severity). - (c)
registry-declaration-missingsemantics. Unchanged from r4 (accepted by darkwing as diagnostic naming only); the reviewer's semantic confirmation is still open and nothing in r5 alters that path. - (d) Permutation family for large inventories is a fixed deterministic subset (§2.3), not all n! orders; the base bundle carries ten registries. All-permutation coverage applies to the artifact, authorization and delegation-input inventories (2–3 entries). The helper's own ordering is asserted directly on hand-built lists.
- (e) Locator (
detail) remains internal. The tests read it throughevaluateonly;inspect/CLI output still exposes no path or value (fixtures.test and the suite's privacy checks unchanged and green). - (f) r3 live-branch correction (r4 §3(g)) remains in force and unrelabeled (§1, §7).
4. Changed files (r4 → r5 sha256; everything else byte-identical, 38 fixtures added, 0 removed)
| File | r5 sha256 | Change |
|---|---|---|
scripts/foundation/resolve.mjs |
892f95ab8a971d93060353e43d53cb6988e7e61f2a5bae71f6f2aaf2b7c1f09f |
stableOrder, ORDER_KEYS, checkInventory; stable traversal at shape/profile/digest/identity/structural stages (§2.2) |
scripts/foundation/resolve.test.mjs |
0fdcbf80edfc35e877132566b9af5b1256d5efd3e69d4fc809eb0ca259a5bba3 |
seven FI-ROCKO-7 tests, firstLocated, permutations, assertPermutationStable |
scripts/foundation/fixtures/build-fixtures.mjs |
273f3f12d1911aaa067a1046bbea20c5eb27b5b80c9913a833c0863b8e06ab7c |
38 ordering cases (§2.3) |
scripts/foundation/fixtures/index.json |
31c6fab4d27f3e9c3e26cdcf343171f9c744404d359d042c80dc5a8566a57ea0 |
334 cases (was 296) |
scripts/foundation/fixtures/README.md |
f3d548908f8bde629525ac0be90df40bbfaf01faff79980474ef4164f306ec7e |
FI-ROCKO-7 paragraph |
scripts/foundation/fixtures/bundles/* |
38 added (manifest) | none modified |
Group counts (index.json): admission 62, continuity 2, cycle 6, identity 7 (+2),
lexical 19, operation 7, ownership 10, positive 21, profile 47 (+10), proposal 48,
registration-delegation 13, shape 85 (+24), structure 7 (+2).
5. Receipts (run 2026-09-07 15:0x UTC at HEAD 9a5fbdbd; logs kept in the session scratchpad)
| Check | Result |
|---|---|
NO_COLOR=1 PYTHONDONTWRITEBYTECODE=1 scripts/test-foundation.sh |
43 passed, 0 failed (syntax, fixture regeneration equality for bundles/raw/index/demo, node tests, oracle, demo exits, goldens, sandbox inventory incl. uid/gid, canaries) |
node --test scripts/foundation/ |
77 tests, 77 pass, 0 fail (was 70) |
python3 scripts/foundation/verify-schema.py (jsonschema 4.26.0, pinned hashes) |
PASS; corpus 1563 records; schema column agree-valid 539, agree-invalid 987, DISAGREEMENTS 0; profile refusals asserted 30 |
python3 docs/plans/foundation-v1-candidate/check.py |
PASS (155 shape fixtures, 5 obligations, 35 model cases) |
scripts/test-config.sh |
24 passed, 0 failed |
scripts/test-conductor.sh |
17 passed, 0 failed (disposable test copies only) |
scripts/test-auth.sh |
15 passed, 0 failed |
scripts/test-task.sh |
NOT RUN / DEFERRED (owner decision, §7) |
scripts/test-release.sh |
NOT RUN / DEFERRED (owner decision, §7) |
every new fixture through the CLI (env -i-style PATH/HOME) |
38/38 match index.json; every pre-existing case unchanged |
| git | HEAD unchanged, nothing staged, no candidate file tracked; no __pycache__ created (the one present under .pi/evidence/goal56/ predates this work, 2026-09-06) |
6. Constraints honoured
No edit to charter, addendum, verdicts, corrections request, follow-up, decision doc,
pinned schema/checker/fixtures, prior reports or manifests, CURRENT, shared logs,
root/package files, policies or runtime data. No new dependency. No staging, commit,
checkout/reset or push (Dewey's index untouched). No live, native/sync, credential or
~/.mosaic work; no network; no engine launch; no container launch. Tests spawn the
inspector; the inspector spawns nothing. Finite tests and static flags are evidence,
not sandbox proof. No fake full-suite pass, no new waiver.
7. Deferred coverage (owner decision, recorded verbatim in scope)
Per 2026-09-07_foundation-inspector-demo-test-gate-decision.md (Jason, 2026-09-07
14:47 UTC, after clarification): scripts/test-task.sh and scripts/test-release.sh
are deferred for this offline inspector demo and are reported NOT RUN / DEFERRED,
never passed or fully covered. The deferral changes only the test prerequisite for
the bounded offline demo; it authorizes no live model calls, deployment actions,
weaker inspector behaviour or permanent removal of tests. Still required and
delivered here: inspector unit/CLI/privacy/non-effect/differential checks, the
foundation checker and the authorized isolated non-live integration checks (§5).
Still required and not rocko's to grant: filbert's independent code approval and
Jason's separate synthetic demo acceptance. Full deployment/integration testing
remains a later gate before dependent live runtime work. The r3 execution of the
live branches (r4 §3(g)) is neither authorized nor relabeled by this decision.
8. Freeze
Frozen at the r5 manifest (docs/plans/reviews/2026-09-07_foundation-inspector-rocko-build-manifest-r5.json,
sha256 a63bb103e4cfe51bbd8a42cd95545f935ac83c1da51cf469298375cf94ced135; 369 files:
source 6, tests 5, suite 1, fixtures-meta 3, bundles 315, raw 19, demo 20; aggregate
scripts/foundation/ 367 files 126b05e4…82ae) for filbert's independent re-review.
Rocko changes nothing under the allowlist until darkwing returns reconciled findings.
C1 (Archify rev 3) remains HELD; no lane action taken.