# 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 `