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.
181 lines
14 KiB
Markdown
181 lines
14 KiB
Markdown
# Foundation inspector — rocko build report r3 (FI-ROCKO-5: C2 correction under addendum FI-C2-1)
|
||
|
||
Author: rocko (Claude Fable 5.1). Coordinator: darkwing. Task: FI-ROCKO-5.
|
||
Written 2026-09-06 21:25 UTC. Supersedes nothing: the original report
|
||
(`…-rocko-build.md`, sha256 `857470d97af6aeae4e7d7942c2a1d8455bfcda74ff68b8e1dc4ba8d066521fa4`)
|
||
and the r2 report/manifest (`…-rocko-build-r2.md` `0dabd82fffdc3a56ebf9a1d8b851832c3acee2cb9332892bde9dbb13151d5e19`,
|
||
`…-rocko-build-manifest-r2.json` `2e8b5f1998a3be6cc7fcc3fba308724d2a29ca166c08f005e1bca88ddbc14196`)
|
||
are preserved unedited. This revision records the C2 correction only, what
|
||
changed, and the new frozen candidate.
|
||
|
||
## 0. Compatibility statement
|
||
|
||
FI-ROCKO-5 is compatible with the standing chain and with the FI-ROCKO-3 build
|
||
request; **no blocker**. The open item of r2 §5 (the C2 pattern-class ruling)
|
||
is closed by darkwing's written addendum FI-C2-1 as approved by filbert
|
||
(FI-FILBERT-5). Nothing outside the original implementation/test allowlist was
|
||
touched; C1 (Archify rev 3) remains HELD with no lane action.
|
||
|
||
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 `2026-09-06_foundation-inspector-pattern-profile-addendum.md` (exact bytes) | `afe2980be2f91e701dae5af3018831ac5c300474f52bcc06e740ce5b5cc68ca5` |
|
||
| Filbert verdict `2026-09-06_foundation-inspector-pattern-profile-verdict.md` | `03c979b77cc6b03b6685ba51ed1ce24c3f1d7b274ce8f772263a103670050da7` |
|
||
| `records.schema.json` / `check.py` / `records.fixtures.json` (pinned, unchanged) | `05774aaf…72af6` / `82564a7d…4607` / `d433d06d…da85` (full values re-verified by oracle gate 1 and listed in the manifest) |
|
||
| Build request `2026-09-06_foundation-inspector-rocko-build-request.md` | `90a1f329e859152d4ce8e157cbd6c56e6bcced16b4ed757822d2309514fa9a15` |
|
||
| Original report / r2 report / r2 manifest (preserved) | `857470d9…21fa4` / `0dabd82f…1e19` / `2e8b5f19…4196` |
|
||
| Integration HEAD (unchanged, nothing staged) | `9a5fbdbda74b16adf488fe28138b2ba69ea5e669` |
|
||
| Machine-generated manifest `2026-09-06_foundation-inspector-rocko-build-manifest-r3.json` | `3c2253b6c9f31e448c77aaac53977d41baecfb30e15845dcfffd8dc694428547` |
|
||
|
||
The charter, addendum and verdict hashes above are also asserted by a unit
|
||
test (`resolve.test.mjs`, "the unchanged charter, the exact addendum and its
|
||
verdict are bound"); a byte change to any of the three fails the suite.
|
||
|
||
Toolchain measured: Node v26.8.1, CPython 3.12.8, jsonschema 4.26.0, Linux
|
||
7.2.2-1-cachyos x86_64, glibc 2.44 (`strftime("%Y")` for year 999 → `999`).
|
||
|
||
## 1. Design of the correction (addendum FI-C2-1, point by point)
|
||
|
||
**Schema column (genuine pinned compatibility).** The pinned checker validates
|
||
`pattern` with Python `re.search`, whose `$` matches at end of string *or*
|
||
before exactly one final `\n`. `resolve.mjs` now exports `PINNED_PATTERNS`
|
||
(`id`, `runtimeId`, `digest`), `pinnedPatternMatches(re, v)` =
|
||
`re.test(v) || (v.endsWith("\n") && re.test(v.slice(0, -1)))`, and
|
||
`strictPatternMatches(re, v)` = `re.test(v)`. The shape gate
|
||
(`checkPattern`) uses the pinned semantics for `shape-pattern-mismatch`, so the
|
||
four r2 witnesses become schema agreements and the schema column has **zero**
|
||
disagreements with no named exceptions (r2's `KNOWN_DIVERGENCES` set is gone).
|
||
|
||
**Strict production profile.** After the pinned check, `checkPattern` applies
|
||
the strict check on every occurrence of the three typed families (records,
|
||
scope ids, actor ids, supersedes, dependency refs, registry refs, payload ids,
|
||
unselected records, registry entries, artifacts, authorization, selection,
|
||
proposal and delegation inputs). A violation is recorded into a per-call
|
||
`profileSink` (path only; never the value). `validateRecordShape` returns
|
||
`{ verdict: "valid", profileViolations: [...] }` so the schema and profile
|
||
verdicts are independent. `validateBundleShape` collects violations from every
|
||
record and wrapper field and, after shape validation succeeds and before any
|
||
identity index or registry-digest profile, refuses with exit 2,
|
||
`invalid-request`, rule `profile-pattern-mismatch`, path of the first
|
||
violation in validation order. Closed §7 fields are unchanged; selection and
|
||
operation are withheld (`null`); the offending value is never echoed.
|
||
|
||
**No trimming, normalization or waiver.** The original string is preserved;
|
||
no identity index is built from a profile-invalid value; no case name is
|
||
whitelisted anywhere. Precedence: profile refusal wins over a dangling
|
||
reference on the same field, so a profile-invalid ref is distinguishable from
|
||
a missing one (unit test with `ref-missing-dependency` vs
|
||
`profile-record-dependency-ref-id-dangling-one-final-lf`).
|
||
|
||
**Free-form text, time and path keep their semantics.** Escaped newlines in
|
||
`mission.objective` / `task.purpose` stay schema- and profile-valid
|
||
(`profile-escaped-newline-free-text-allowed`, exit 0). `time` with a final LF
|
||
fails `shape-pattern-mismatch` (strptime refuses it in the pinned checker
|
||
too); `relativePath` with a final LF fails `path-invalid`. Neither is in the
|
||
profile.
|
||
|
||
**Bridge.** `validate-record.mjs` now reports `schemaValid` and
|
||
`profileValid` independently, with `rule: "profile-pattern-mismatch"` and the
|
||
first violating path when the record is schema-valid but profile-invalid.
|
||
|
||
**Oracle.** `verify-schema.py` builds an in-memory strict variant of the
|
||
pinned schema (only the three `$defs` patterns, trailing `$` → `\Z`;
|
||
`check_schema` passes; pinned bytes untouched) and computes the profile
|
||
column with the real jsonschema validator, never by name. The four original
|
||
witnesses are preserved by name as declared probes (schema True / profile
|
||
False); a newline matrix (valid, one final LF, two final LF, CRLF, CR,
|
||
interior LF, U+2028, U+2029) runs across 8 sites of the three families with
|
||
declared schema/profile outcomes; every strict-only refusal must carry the
|
||
fixed rule and a path; a run with no refusals or an unobserved declared
|
||
refusal is a problem.
|
||
|
||
**One incidental fix in the allowlist.** The eight payload-level scope
|
||
re-checks previously re-validated `rec.scope` under the bare path `scope`,
|
||
which would have double-counted a profile violation; they now use
|
||
`requireScopeKind` (kind-only check with the proper `record.scope.kind` path).
|
||
No verdict of the 204 pre-existing fixtures changed (`index.json` gained 55
|
||
entries and nothing else; demo goldens byte-identical).
|
||
|
||
## 2. Filbert's FI-FILBERT-5 matrix, as implemented
|
||
|
||
Per family (`id`, `runtimeId`, `digest`): Python / Node schema / strict.
|
||
|
||
| Value | Python (pinned) | Node schema column | Strict profile | Inspector verdict |
|
||
|---|---|---|---|---|
|
||
| valid | T | T | T | proceeds |
|
||
| one final LF | T | T | **F** | exit 2 `invalid-request` `profile-pattern-mismatch` |
|
||
| two final LF, CRLF, CR, interior LF, U+2028, U+2029 | F | F | F | exit 2 `invalid-request` `shape-pattern-mismatch` |
|
||
|
||
Asserted three ways: unit test on the exported predicates, 55 CLI fixtures,
|
||
and the oracle's declared probes against the real Python validators.
|
||
|
||
## 3. Changed files (r2 → r3 sha256; everything else byte-identical)
|
||
|
||
| File | Lines | r2 sha256 | r3 sha256 |
|
||
|---|---|---|---|
|
||
| `scripts/foundation/resolve.mjs` | 1646→1713 | `aa842898ebb0bb2a911406314c4c3a2c4079b46bfd674c4ffba0176a1e32766c` | `eaa4a419618328915cd470ba192a88b8d313ee8fa48f600289ffe39df15280b2` |
|
||
| `scripts/foundation/validate-record.mjs` | →71 | `e4e70f60cce68e535ef98b0627647c440d620432cf8ddaed074df4e252ecde58` | `dcff28b53501b68fe7368adcbf02db0526ab4273d1c1c42e47df9a78a0bd9b4b` |
|
||
| `scripts/foundation/verify-schema.py` | 467→575 | `b61031b6c2cea126133afda70894e7f2429b08bf2cd50fc766ec6b99f348c966` | `e5fce462abd0e8c5be4e4543fd31146a35aba41a653d2aa105c28ca5a20deb67` |
|
||
| `scripts/foundation/resolve.test.mjs` | 333→425 | `6bb6d40fa6ec90fb52db658f77ca9fd27cc3eb8673f040f52fc126e67983a571` | `d7de059015edcf0bded7c4da901a7302394a42bf1e38b86bd403fbb01f5327ff` |
|
||
| `scripts/foundation/cli.test.mjs` | 281→317 | `ccec06c266e03d878c1ecd9e8c20ee3f1fb82f478daead25efa4661b7090d83f` | `a0bda7779739021da7cbe03b46209e370f7443100f6ea56a512468003d60b74c` |
|
||
| `scripts/foundation/fixtures/build-fixtures.mjs` | →979 | `094ecc811b85465cc0748a86b76b75c1784a2e0296f242b6ff2dbd1660b426a9` | `0386276f0e0ba8fbb3f4126ffabadd6afec90fc3a92749fe314783d26300aa5c` |
|
||
| `scripts/foundation/fixtures/index.json` | 204→259 cases | `74988a1dcd4b48b0be2243d3fefff3b6de5d90a947094be201c3486142ca12a2` | `c013090406bb6bbb7b490b952eb4020065b4c732e4aecb0e6cf5c5c8037a6663` |
|
||
| `scripts/foundation/fixtures/README.md` | →51 | `aba48ba054d09247b048a8955507b87a275cd585870f1f658b7c6b826fc892bd` | `ed0376589b203b1bcea6e1d82322311ec843eb7537756762bf917b8552d29523` |
|
||
| `scripts/test-foundation.sh` | 132→143 | `fdfa13ce247bc9ad8f3617e248913aef384029198924685ada3431006ffdf114` | `73417979d1f9320603b0244350f9665d2bdf1485084c0928002ba033929b3c19` |
|
||
|
||
Added: 55 bundle fixtures `scripts/foundation/fixtures/bundles/profile-*.json`
|
||
(generator output; listed individually in the manifest). Removed: none.
|
||
Unchanged: `scripts/foundation-inspect.mjs`, `strict-json.mjs`,
|
||
`canonical.mjs`, `fixtures.test.mjs`, `canonical.test.mjs`,
|
||
`strict-json.test.mjs`, all 19 raw fixtures, all 20 demo files and goldens
|
||
(demo aggregate `6a32862b…8956` and raw aggregate `dbc620a7…60d3` identical to r2).
|
||
|
||
Manifest r3 aggregates (sha256 of the LC_ALL=C sorted `sha256sum` listing):
|
||
`fixtures/bundles/` 240 files `aa4836a4a4f989ecc70acf8df770b894c6ef77e85c4e913c24bb422b1aef0afa`;
|
||
`fixtures/` 282 `3de4c896d63041db0b6b5beb961d9dfa6486f7681dd16f91abb5d8ef48c16bfb`;
|
||
`scripts/foundation/` 292 `4fbdcfb8d71612d4ac21dc0b7f5b60064847d7087bfbe8ec215a9f1abdbafb9a`;
|
||
`scripts/` 294 `e5f9039cf4614e8acc3f6c6a71f0a03dbc1c29002703029180d1ccef5757979c`.
|
||
|
||
## 4. New fixture inventory (55 cases)
|
||
|
||
| Group | Rule | Count | Cases |
|
||
|---|---|---|---|
|
||
| profile | `profile-pattern-mismatch` | 34 | one final LF at 3 family sites (`id-record-id`, `runtime-id-authorization-ref`, `digest-registry-ref`) plus 31 further occurrence sites: record scope project/workspace ids, actor principal/execution ids, supersedes, dangling dependency ref, registry ref id, agent type, file root id, registration/assignment agent ids, criterion id, decision subject ref, unselected record id and its scope, registry id and plain/content-bearing digests, artifact run/id/digest, authorization, selection agent/project/workspace/assignment-ref ids and assignment-ref scope, proposal requester/target/context ids, delegation input decision ref |
|
||
| shape | `shape-pattern-mismatch` | 19 | two-final-lf, crlf, cr, interior-lf, u2028, u2029 at each of the 3 family sites (18) + `profile-time-one-final-lf` |
|
||
| shape | `path-invalid` | 1 | `profile-path-one-final-lf` |
|
||
| positive | — (exit 0) | 1 | `profile-escaped-newline-free-text-allowed` |
|
||
|
||
Every `profile` case is asserted to return `selection: null`, `operation:
|
||
null`, and no `\n` inside any result string (loop in `resolve.test.mjs`).
|
||
|
||
## 5. Receipts (all run 2026-09-06 21:0x–21:23 UTC at HEAD 9a5fbdbd)
|
||
|
||
| Check | Result |
|
||
|---|---|
|
||
| `node --check` on all 10 `.mjs` files; `ast.parse` on `verify-schema.py` | OK |
|
||
| `node --test scripts/foundation/` | 63 tests, 63 pass, 0 fail (was 58; +5: binding, matrix, independence/order, precedence, CLI negative control) |
|
||
| `python3 scripts/foundation/verify-schema.py` | **PASS**, exit 0. Corpus 1539 records (38 pinned fixtures, 449 unique bundle records, 1052 typeCase/mutation/lexical). Schema column: agree-valid 519, agree-invalid 983, **DISAGREEMENTS 0**; strict-only (parser-bound) 27; unsupported-kind not assessed 10. Profile column: profile-valid 489, profile-invalid 30. `profile refusals asserted: 30 … 12 declared by name; 73 named probes verified` |
|
||
| `NO_COLOR=1 scripts/test-foundation.sh` | **`selftest: 43 passed, 0 failed`** (was 36/1); new checks: zero schema disagreements, refusals counted, profile exits 2/2/0, JSON refusal shape with value never echoed |
|
||
| CLI negative controls | selection `agentId` + one LF → status 2, `invalid-request`, `profile-pattern-mismatch`, selection/operation null, `agent-a` absent from JSON and text; two LFs → `shape-pattern-mismatch`; escaped newlines in free text → exit 0 |
|
||
| `python3 docs/plans/foundation-v1-candidate/check.py` | exit 0, `PASS: 35` |
|
||
| `scripts/test-config.sh` / `test-task.sh` / `test-release.sh` / `test-conductor.sh` / `test-auth.sh` | 24/0, 90/0, 14/0, 17/0, 15/0 passed/failed |
|
||
| Fixture regeneration | `build-fixtures.mjs` into a sandbox equals checked-in `bundles/`, `raw/`, `index.json`, demo bundles |
|
||
| `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 |
|
||
| `scripts/foundation/__pycache__`, `docs/plans/foundation-v1-candidate/__pycache__` | absent |
|
||
|
||
## 6. Constraints honoured and freeze
|
||
|
||
No edit to charter, addendum, verdict, 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. Tests spawn the inspector; the inspector
|
||
spawns nothing. Finite tests and static flags are evidence, not sandbox proof.
|
||
|
||
Frozen at the r3 manifest (`manifest-r3.json`, sha256 `3c2253b6…8547`; 294
|
||
files) for filbert's full code review. Rocko changes nothing under the
|
||
allowlist until darkwing returns reconciled findings. C1 (Archify rev 3)
|
||
remains HELD; no lane action taken.
|