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.
23 KiB
Foundation inspector — rocko build report r4 (FI-ROCKO-6: corrections for FI-FILBERT-6 findings F1–F6)
Author: rocko (Claude Fable 5.1). Coordinator: darkwing. Reviewer: filbert. Task: FI-ROCKO-6. Written 2026-09-07 14:40 UTC. Supersedes nothing: the original report, r2 and r3 reports/manifests, the charter, the addendum and both verdicts are preserved unedited. This revision records the corrections to filbert's NOT APPROVED code verdict (FI-FILBERT-6), what changed r3 → r4, the new witness receipts, and the frozen candidate for independent re-review.
0. Admission, compatibility and blockers
FI-ROCKO-6 is admitted and compatible with the standing chain, the FI-ROCKO-3 build request and the corrections request; the code/test work is complete under the original allowlist plus the two new r4 receipt paths. C1 (Archify rev 3) remains HELD with no lane action.
One test-authorization blocker is reported, not worked around (details in §7):
scripts/test-task.sh and scripts/test-release.sh were not run in r4. In this
session docker info succeeds, so both suites would execute their Docker branches,
and test-task.sh would additionally execute its live branch (real run-task.sh
engine launches with the operator's configuration and credentials). The corrections
request forbids silently running legacy live branches and forbids substituting skips or
stubs to claim the gate green. Darkwing owns arranging that isolated integration gate.
The three suites without Docker/live/credential branches (test-config.sh,
test-conductor.sh, test-auth.sh) were run and pass (§6).
Inputs bound to this revision:
| Input | sha256 |
|---|---|
Charter candidate 3 docs/plans/2026-09-06_foundation-inspector-charter.md (unchanged) |
19b6721128a627a2032ffdb95ece2d50abe69a8f6d521e9eff8bbdaff22798b6 |
| Addendum FI-C2-1 (unchanged) | afe2980be2f91e701dae5af3018831ac5c300474f52bcc06e740ce5b5cc68ca5 |
Filbert code verdict FI-FILBERT-6 2026-09-06_foundation-inspector-code-verdict.md |
e4cc5970aab20240e6ea3a9a1513ef942ff167fefbb03356b9a32c89999adb3d |
Corrections request 2026-09-07_foundation-inspector-corrections-request.md |
35c237f5c001832a0cfed23b03ff7530ffa78443612ffe11130fe456b968bd61 |
records.schema.json / check.py / records.fixtures.json (pinned, unchanged) |
05774aaf…72af6 / 82564a7d…4607 / d433d06d…da85 (full values in the manifest; re-verified by oracle gate 1) |
| r3 report / r3 manifest (preserved) | ec0444c94c9caf16472fdba1ff3fbc767dffd1a798b9a2da837598c9f4b25508 / 3c2253b6c9f31e448c77aaac53977d41baecfb30e15845dcfffd8dc694428547 |
| Integration HEAD (unchanged, nothing staged) | 9a5fbdbda74b16adf488fe28138b2ba69ea5e669 |
Machine-generated manifest 2026-09-07_foundation-inspector-rocko-build-manifest-r4.json |
2a2e885f9df3dd626a09fe5db6e28af67c289e54660872031c18f8aa40cb0826 (331 files) |
Toolchain measured: Node v26.8.1, CPython 3.12.8, jsonschema 4.26.0, Linux 7.2.2-1-cachyos x86_64.
1. Evidence preservation
The declared scratch evidence still exists at
/tmp/fi-filbert-6.42ru903e-evidence/witnesses/. All nine witness bundles named in
the verdict were re-hashed before use and match the verdict's listed values:
missing-agent-registry-declarations 78efd6fb…, consulted-dependency-undeclared-authorization cc78be28…,
assigned-change-without-work-read 35ee45e6…, proposal-task-only-contexts-without-work-read e1a9cd88…,
proposal-issuer-denies-work-read 34d1ed80…, acyclic-versioned-history-false-cycle e3dd1cd3…,
shape-order-forward 689f9aa9…, shape-order-reversed d14fca5e…,
message-priority-after-structural-validation 9e2ec77b…. Each recipe was rebuilt from
the frozen demo bundles inside build-fixtures.mjs; four rebuilt fixtures are
byte-identical to the corresponding witness files
(adm-assigned-task-without-work-read, cycle-acyclic-versioned-history-file-change,
prop-issuer-denies-work-read, prop-task-only-contexts-without-work-read), the
other five are semantically equivalent reconstructions. No other reviewer/fleet files
were inspected. Prior r1–r3 evidence, fixtures and goldens are preserved: all 259
previously indexed cases keep their expectations, the five demo bundles and their
goldens are byte-identical to r3.
2. Per-finding closure
Pre-fix outcomes below were measured on the r3 candidate against the witness files; post-fix outcomes are the r4 receipts (§6, all with empty stderr).
F1 — referenced declarations incompletely enforced → CLOSED
Root cause: harnessRef, settingsRef, soulRef, instructionRefs, skillRefs
and endpointRefs were shape-checked but never resolved against the declared
registries; consulted dependency/mission authorizations were used without a
declaration check.
Change (resolve.mjs): new Model.requireRegistryDeclaration(ref, where) resolves a
reference by exact four-field match (registry, id, revision, digest) against the
declared registries and refuses 3 / missing-state / registry-declaration-missing
otherwise; new Model.declaredLayer(restrictions, where) resolves every
endpointRefs[i] before computing a layer, and every layer computation in the Model
(registry content, registration, delegation issuer ceiling, task, mission, execution,
proposal issuer) now goes through it. computeContext resolves the selected agent's
harness/settings/soul/instruction/skill references at the admission stage (after the
agent-status check, before the mandatory policy ceiling) and calls
requireAuthorization for each consulted dependency (mission authorization was already
checked). evaluateProposal step 5 additionally requires the subject task's
authorization (previously only the target task's).
Witnesses: missing-agent-registry-declarations exit 0 allowed → 3 refused /
missing-state / registry-declaration-missing; consulted-dependency-undeclared-authorization
exit 0 allowed → 3 refused / missing-state / authorization-undeclared.
Fixtures (14): nine absence/mismatch negatives (adm-registry-declaration-missing-agent-refs,
-missing-settings, -missing-soul, -missing-instruction, -missing-skill,
-missing-endpoint-execution, -missing-endpoint-task, -digest-mismatch,
-revision-mismatch), adm-dependency-authorization-undeclared,
adm-mission-authorization-undeclared, prop-subject-task-authorization-undeclared,
and positive controls adm-registry-declaration-unselected-agent-ignored,
adm-registry-declaration-endpoint-declared, adm-unconsulted-authorization-ignored.
Unit tests: "F1: consulted registry references resolve by exact four-field declaration
at the admission stage", "F1: consulted dependency and mission authorizations must be
declared".
F2 — task-only contexts evade required work.read → CLOSED
Root cause: consultedWork was set only when a mission or dependency was resolved, so
a bound task without those references was never treated as consulted work; the same
condition was in checkWorkAccess.
Change: the assigned task is consulted work by definition; computeContext sets
consultedWork when the task is bound (L7), and checkWorkAccess requires work.read
unconditionally after its scope guards. Genuinely taskless reads (no assignment) are
unchanged.
Witnesses: assigned-change-without-work-read exit 0 allowed → 3 refused /
not-authorized / consulted-work-not-readable; proposal-task-only-contexts-without-work-read
exit 3 unresolved → 3 refused / consulted-work-not-readable, proposal step
requester-lacks-original-scope-authority. Fixtures (6): adm-assigned-task-without-work-read,
adm-assigned-task-without-work-read-read-op (a read operation still needs
work.read), prop-task-only-contexts-without-work-read (original step),
prop-task-only-target-context-without-work-read (target step,
requester-lacks-target-scope-authority), positives assigned-task-only-with-work-read
(exit 0) and prop-task-only-contexts-with-work-read (unresolved). Unit test: "F2: a
bound task is consulted work; work.read is required even without mission/dependency
references".
F3 — issuer narrowing does not recheck work access → CLOSED
Root cause: work access was checked before the issuer ceiling was applied; only
assignment.change was rechecked on the narrowed layers.
Change: evaluateProposal now runs recheck(id, context, work, scope, label) for
both requester contexts on the issuer-narrowed layer
(intersectLayers(context.layer, issuer)): work.read on the narrowed layer
(consulted-work-not-readable), assignment.change on the narrowed layer
(operation-not-permitted, where <label>+issuer), then the full checkWorkAccess
path/network intersection.
Witness: proposal-issuer-denies-work-read exit 3 unresolved → 3 refused /
not-authorized / consulted-work-not-readable, step
requester-lacks-original-scope-authority. Fixtures (3): prop-issuer-denies-work-read,
prop-issuer-denies-work-read-task-only (F2+F3 combined), positive
prop-issuer-grants-work-read (unresolved). Unit test: "F3: the issuer ceiling
narrows both requester calculations and work access is rechecked" (includes an
intersectLayers algebra witness for the target scope; see §3(c)).
F4 — cycle construction merges historical revisions → CLOSED
Root cause: checkCycles keyed dependency/parent/supersedes nodes by identity without
revision and unioned edges over every historical record.
Change: nodes are exact record keys (identity and revision) and edges are the exact four-field references of each record; the identity-merged union and its post-sort loop were removed. Cycle-before-continuity precedence is unchanged.
Witness: acyclic-versioned-history-false-cycle exit 2 dependency-cycle → exit 0
allowed. Fixtures (5): positives cycle-acyclic-versioned-history (read) and
cycle-acyclic-versioned-history-file-change (byte-identical to the witness);
cycle-dependency-cross-revision still detects a real cycle through exact revisions
(dependency-cycle); cycle-mission-parent-old-revision-only (self-parent in a
superseded revision remains mission-parent-cycle);
cycle-mission-parent-previous-revision-not-a-cycle (a workspace mission whose parent
is its own previous revision is acyclic in the exact graph and fails the ownership
stage as mission-parent-scope-mismatch). Unit test: "F4: cycle graphs are
revision-exact; contiguous history with reversed edges is not a cycle" (compares
findCycle on the exact graph versus the old merged graph).
F5 — first-failure ordering not preserved → CLOSED
Root causes: (1) record shape validation walked the input array before the Model's
stable sort; (2) the message-is-not-authority check ran after requester admission.
Change: (1) new shapeValidationOrder(records) orders records before shape
validation using a tolerant key (kind, id, scope, revision when present; identified
records first, then a canonical-content tie-break, then input index) so the first
shape failure is independent of input order even when a record is too malformed to
key; (2) evaluateProposal performs the §5 message check immediately after both
requester contexts bind (structural validation) and before any head/authority step;
step 3 keeps only delegation-missing.
Witnesses: shape-order-forward / shape-order-reversed (shape-enum-mismatch /
shape-unknown-field) → both shape-enum-mismatch;
message-priority-after-structural-validation exit 3 operation-not-permitted /
requester-lacks-original-scope-authority → 3 refused / not-authorized /
message-is-not-authority, proposal rule message-is-not-authority. Fixtures (8):
shape-order-forward, shape-order-reversed, shape-order-malformed-record-sorts-last,
shape-order-only-malformed-record, prop-message-precedes-requester-admission,
prop-message-precedes-stale-subject, prop-message-after-structural-failure
(structural failure still wins: requester-context-mismatch),
prop-delegation-missing-after-requester-admission (no message: requester admission
still precedes delegation-missing). Unit tests: "F5: the first shape failure is
independent of record input order, including malformed records" (four permutations,
malformed record moved, two unidentified records), "F5: message-is-not-authority
follows structural validation and precedes requester admission".
F6 — inventories omit ownership → CLOSED
cli.test.mjs inventory rows now include uid and gid; test-foundation.sh
inventories with stat -c '%n %F %s %a %u %g %i %Y' and the check is labelled
"sandbox inventory (path/type/size/mode/uid/gid/inode/mtime/sha256) unchanged by runs".
3. Design decisions and disclosures for the reviewer
- (a) Rule identifier
registry-declaration-missingis writer-chosen. The charter names the outcome (missing declaration → missing-state admission refusal) but not an identifier; the vocabulary entry sits in the stage-9 group next toauthorization-undeclared/artifact-undeclared. No new contract rule is claimed; if darkwing/filbert prefer an existing identifier, the rename is mechanical. - (b) Declared lists are still shape-validated in input order.
shapeValidationOrderapplies tobundle.recordsonly;registries,artifacts,authorizationsanddelegationInputsremain in inventory order. The verdict's F5 witnesses concern records; extending the sort to declaration lists is a small follow-up if required. - (c) The target-scope post-issuer failure is unreachable through the CLI. Issuer
narrowing is scope-independent, so whenever the narrowed target layer lacks
work.readthe original scope has already failed first. The target branch is covered by theintersectLayersalgebra assertion in the F3 unit test, not by a CLI fixture. - (d) Subject-task authorization is now required at step 5 alongside the target task's. This follows the F1 principle (consulted work must be declared); it was not an explicit verdict witness and is flagged in case the reviewer reads §5 more narrowly.
- (e) No currentness rule was added for harness/settings/context-content/endpoint
references: they must match a declaration exactly (§10.1); only the mandatory policy
keeps its
policy-ceiling-stalecurrentness check. - (f) Agent declaration checks run after the agent-status check and before the policy
ceiling; a disabled agent therefore still refuses as
agent-disabledfirst. - (g) Correction to r3 §6. r3 stated "no engine launch". That was true of the
inspector work, but the r3
test-task.shreceipt (90/0) included the suite's Docker and live branches (live hello, session fork, onboarding recall) because Docker was reachable during that run. r3's receipt therefore rested on a live legacy branch that FI-ROCKO-6 identifies as unauthorized; r4 does not repeat it (§7). The r3 report is preserved unedited; this entry is the correction.
4. Changed files (r3 → r4 sha256; everything else byte-identical, 37 fixtures added)
| File | r3 | r4 |
|---|---|---|
scripts/foundation/resolve.mjs |
eaa4a41961832891… |
777dd415021a54a3… |
scripts/foundation/resolve.test.mjs |
d7de059015edcf0b… |
cab963cd7b80957d… |
scripts/foundation/cli.test.mjs |
a0bda7779739021d… |
566abb49770b5d23… |
scripts/foundation/fixtures/build-fixtures.mjs |
0386276f0e0ba8fb… |
f731b1f1da04ecc2… |
scripts/foundation/fixtures/index.json |
c013090406bb6bbb… |
9a963a0e58770e4f… |
scripts/foundation/fixtures/README.md |
ed0376589b203b1b… |
9dc57df95eb6849d… |
scripts/test-foundation.sh |
73417979d1f93206… |
6f808ea8f4a021e3… |
Full hashes for every file, plus per-directory aggregates, are in the r4 manifest.
Untouched: foundation-inspect.mjs, strict-json.mjs, canonical.mjs,
validate-record.mjs, verify-schema.py, fixtures.test.mjs, all 259 prior
bundles/raw cases, all demo bundles and goldens.
5. New fixture inventory (37 cases; 296 total)
Groups after r4: admission 62, positive 21, continuity 2, cycle 6, ownership 10, proposal 48, identity 5, operation 7, profile 37, shape 61, lexical 19, registration-delegation 13, structure 5.
| Case | Group | exit result / reason / rule [/ proposal rule] |
|---|---|---|
| adm-registry-declaration-missing-agent-refs, -missing-settings, -missing-soul, -missing-instruction, -missing-skill, -missing-endpoint-execution, -missing-endpoint-task, -digest-mismatch, -revision-mismatch | admission | 3 refused / missing-state / registry-declaration-missing |
| adm-dependency-authorization-undeclared, adm-mission-authorization-undeclared | admission | 3 refused / missing-state / authorization-undeclared |
| adm-registry-declaration-unselected-agent-ignored, adm-registry-declaration-endpoint-declared, adm-unconsulted-authorization-ignored | positive | 0 allowed |
| adm-assigned-task-without-work-read, adm-assigned-task-without-work-read-read-op | admission | 3 refused / not-authorized / consulted-work-not-readable |
| assigned-task-only-with-work-read | positive | 0 allowed |
| prop-task-only-contexts-without-work-read, prop-issuer-denies-work-read, prop-issuer-denies-work-read-task-only | proposal | 3 refused / not-authorized / consulted-work-not-readable / requester-lacks-original-scope-authority |
| prop-task-only-target-context-without-work-read | proposal | 3 refused / not-authorized / consulted-work-not-readable / requester-lacks-target-scope-authority |
| prop-task-only-contexts-with-work-read, prop-issuer-grants-work-read | proposal | 3 unresolved / unknown-effects / runtime-reconciliation-required / runtime-reconciliation-required |
| prop-subject-task-authorization-undeclared | proposal | 3 refused / missing-state / authorization-undeclared / intent-not-current |
| cycle-acyclic-versioned-history, cycle-acyclic-versioned-history-file-change | positive | 0 allowed |
| cycle-dependency-cross-revision | cycle | 2 invalid / invalid-request / dependency-cycle |
| cycle-mission-parent-old-revision-only | cycle | 2 invalid / invalid-request / mission-parent-cycle |
| cycle-mission-parent-previous-revision-not-a-cycle | ownership | 2 invalid / invalid-request / mission-parent-scope-mismatch |
| shape-order-forward, shape-order-reversed, shape-order-malformed-record-sorts-last | shape | 2 invalid / invalid-request / shape-enum-mismatch |
| shape-order-only-malformed-record | shape | 2 invalid / invalid-request / shape-missing-field |
| prop-message-precedes-requester-admission, prop-message-precedes-stale-subject | proposal | 3 refused / not-authorized / message-is-not-authority / message-is-not-authority |
| prop-message-after-structural-failure | proposal | 2 invalid / invalid-request / requester-context-mismatch |
| prop-delegation-missing-after-requester-admission | proposal | 3 refused / not-authorized / operation-not-permitted / requester-lacks-original-scope-authority |
6. Receipts (run 2026-09-07 09:2x–14:39 UTC at HEAD 9a5fbdbd)
| Check | Result |
|---|---|
Verdict witness files (nine, hashes verified), run with env -i HOME=/nonexistent PATH=/nonexistent |
missing-agent-registry-declarations → 3 refused/missing-state/registry-declaration-missing; consulted-dependency-undeclared-authorization → 3 refused/missing-state/authorization-undeclared; assigned-change-without-work-read → 3 refused/not-authorized/consulted-work-not-readable; proposal-task-only-contexts-without-work-read → 3 refused/consulted-work-not-readable (step requester-lacks-original-scope-authority); proposal-issuer-denies-work-read → same; acyclic-versioned-history-false-cycle → 0 allowed; shape-order-forward and shape-order-reversed → 2 shape-enum-mismatch; message-priority-after-structural-validation → 3 refused/not-authorized/message-is-not-authority (proposal rule message-is-not-authority); positive-control → 0 allowed. stderr empty for all. The three exploratory blocked-subject/target probes in the same directory remain unresolved/runtime-reconciliation-required, as the verdict §5 expects. |
node --check on all 10 .mjs files; ast.parse on verify-schema.py |
OK |
node --test scripts/foundation/ |
70 tests, 70 pass, 0 fail (was 63; +7 F1–F5 tests) |
python3 scripts/foundation/verify-schema.py |
PASS, exit 0. Corpus 1563 records (38 pinned fixtures, 473 unique bundle records, 1052 typeCase/mutation/lexical). Schema column: agree-valid 539, agree-invalid 987, DISAGREEMENTS 0; strict-only 27; unsupported-kind not assessed 10. Profile column: profile-valid 509, profile-invalid 30; 30 refusals asserted, 73 named probes verified |
NO_COLOR=1 scripts/test-foundation.sh |
selftest: 43 passed, 0 failed, including "sandbox inventory (path/type/size/mode/uid/gid/inode/mtime/sha256) unchanged by runs" |
python3 docs/plans/foundation-v1-candidate/check.py |
exit 0, PASS: 35 |
scripts/test-config.sh / test-conductor.sh / test-auth.sh |
24/0, 17/0, 15/0 passed/failed (no Docker, no network, no credentials; conductor commits only inside its sandbox clones) |
scripts/test-task.sh / scripts/test-release.sh |
NOT RUN — test-authorization blocker, §7 |
| Fixture regeneration | build-fixtures.mjs into a sandbox equals checked-in bundles/, raw/, index.json, demo bundles (296/296 cases match through the CLI) |
git rev-parse HEAD; git status |
9a5fbdbd…; nothing staged; only the pre-existing tracked modifications (BUILD-LOG.md, docs/SESSIONS.md, docs/plans/CURRENT.md) plus untracked candidate/review files |
__pycache__ directories |
none created (PYTHONDONTWRITEBYTECODE=1) |
7. Integration-gate blocker (reported, not skipped)
scripts/test-task.shgates two sections ondocker info: the adapter-seam mock cases (container launches, no provider) and the live cases (run-task.sh runwith the real engine, provider credentials, session forks and onboarding recall). In this sessiondocker inforeturns 0, so an unmodified run executes both sections.scripts/test-release.shgates its state-machine cases ondocker info(package / activate / rollback against Docker images).- Running either suite would launch containers and, for
test-task.sh, a live engine under the operator's configuration: outside FI-ROCKO-6's authorization. Masking Docker (for example an emptyPATH) would print the suites' own "skip … (docker unavailable)" lines and additionally failtest-task.sh's unconditional onboarding recall; that is the substitute-skip the request forbids. The suites are outside the allowlist, so no fast-only entry point can be added by the writer. - Required from darkwing: an explicitly authorized, isolated, non-live run of the two suites (or a ruling that the fast sections are sufficient for this gate), as the verdict §5 already identified. Nothing in r4 touches the code those suites exercise.
8. Constraints honoured and freeze
No edit to charter, addendum, verdicts, corrections request, 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 in r4. Tests spawn the inspector; the inspector spawns
nothing. Finite tests and static flags are evidence, not sandbox proof.
Frozen at the r4 manifest (…-rocko-build-manifest-r4.json, sha256 2a2e885f…0826;
331 files) 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.