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.
321 lines
26 KiB
Markdown
321 lines
26 KiB
Markdown
# FI-ROCKO-3 — synthetic inspector build report (review candidate)
|
||
|
||
Writer: rocko (sole implementation writer). Requester/integration owner: darkwing.
|
||
Independent reviewer: filbert (not yet dispatched to code review). Issue: #53.
|
||
Status: **delivered as a frozen review candidate, not accepted work.** No owner
|
||
acceptance is claimed. Code and fixtures are frozen at the hashes below until
|
||
darkwing reconciles filbert's findings; only rocko fixes owned code, producing a
|
||
newly hashed candidate.
|
||
|
||
## 1. Admission (returned 2026-09-06T17:05Z; unchanged)
|
||
|
||
- Compatible, no blocker. Archify C1 rev 3 stays bound and HELD for Jason's T2/T3
|
||
rulings (waiting state, no due action); nothing was displaced.
|
||
- All authorized paths were absent at admission and are new untracked files now.
|
||
No other helper path or specification decision was needed; nothing outside the
|
||
allowlist was written.
|
||
- Build request identity: admitted at sha256
|
||
`fd70962f36f81c515ffefae21fd9e56f90655718067bca8db11a9fc510fbb455` (17:01Z read).
|
||
The file on disk now hashes
|
||
`90a1f329e859152d4ce8e157cbd6c56e6bcced16b4ed757822d2309514fa9a15` (mtime 17:02:59Z).
|
||
Verified by diff against the copy read at admission: the only change is the
|
||
appended "Transport (2026-09-06 17:02 UTC)" footnote; the contract text is identical.
|
||
|
||
## 2. Pinned contract inputs versus measured integration state
|
||
|
||
| Input | Identity |
|
||
|---|---|
|
||
| Charter candidate 3 `docs/plans/2026-09-06_foundation-inspector-charter.md` | sha256 `19b6721128a627a2032ffdb95ece2d50abe69a8f6d521e9eff8bbdaff22798b6` |
|
||
| Filbert verdict r3 | sha256 `15f3d04cb74a7296be6a1a26f2c0907b9dd2b08fdd1eb0ef51c95c7a52ff0399` |
|
||
| r2 feasibility note (incorporated, overridden by charter §10) | sha256 `f2f47fcfe22dca79f10f885b83d87a2f846fdb560425a4e20705c40ce4a123e1` |
|
||
| Source/schema baseline | `d4696d09eb1b5dcf1028f30db2cd63735f51cb16` |
|
||
| Accepted map | `7345f330fc6bfae5aa1d896c78cfb7cbe62efbae` |
|
||
| `docs/plans/foundation-v1-candidate/records.schema.json` | sha256 `05774aaf6943cb69c113e39ff1c29676a2a230ca7bf665c50dbcaa8049672af6` |
|
||
| `docs/plans/foundation-v1-candidate/check.py` | sha256 `82564a7d3200afcdda0850a9454cac6e6cd6a76687d2162c13cf214d7eac4607` |
|
||
| `docs/plans/foundation-v1-candidate/records.fixtures.json` | sha256 `d433d06da5cd38baf9e51c8857244ee70375db3b68e02a5325a6d1c2cc47da85` |
|
||
| Measured integration HEAD (unchanged throughout the build) | `9a5fbdbda74b16adf488fe28138b2ba69ea5e669` |
|
||
|
||
The three pinned schema/checker files in the working tree hash identically to the
|
||
baseline; `verify-schema.py` re-checks these three hashes on every run and fails
|
||
closed on mismatch.
|
||
|
||
Toolchain (measured on this host): Node `v26.8.1`, Python `3.12.8`,
|
||
`jsonschema 4.26.0` (existing installation; nothing installed). No repo Node pin
|
||
exists; `node --test` (built-in runner) is the only test framework.
|
||
|
||
## 3. Changed-file list with SHA-256 (the frozen candidate manifest)
|
||
|
||
All files are new and untracked. Nothing existing was edited.
|
||
|
||
| File | Lines | SHA-256 |
|
||
|---|---|---|
|
||
| `scripts/foundation-inspect.mjs` (CLI) | 239 | `bfa1b78007c772c54fe1dab90a53e19e6bce7e4888a5adb2de0b2cfe43c5cddd` |
|
||
| `scripts/foundation/strict-json.mjs` | 327 | `7c31fe6be8cd29ee07662a21bb2e490a2ec799e263dec981ee257fcf7e6f6ebf` |
|
||
| `scripts/foundation/canonical.mjs` | 87 | `a7760882c4c49992b9d702eb125a3e8f63048be543516b0eba61231018b90172` |
|
||
| `scripts/foundation/resolve.mjs` | 1625 | `9ae8b4255b5dc1f1e9b0d36549865268c12dc53f010984eb1e5616b127d1d8a2` |
|
||
| `scripts/foundation/validate-record.mjs` (test-only bridge) | 66 | `e4e70f60cce68e535ef98b0627647c440d620432cf8ddaed074df4e252ecde58` |
|
||
| `scripts/foundation/verify-schema.py` (verification only) | 453 | `7e3098655b2e5f261391d788c2112a6ffb055895e357b427bc68e5f2fa7b52d7` |
|
||
| `scripts/foundation/strict-json.test.mjs` | 145 | `b40488edfc4eba6962e8c0949ddf1f92fdc15d630b7e9bdff72ac6d06bdb092e` |
|
||
| `scripts/foundation/canonical.test.mjs` | 106 | `f504321983b2c41eff5af7e6dc27e40e360e0aae299d0a9abc369c743f5384f7` |
|
||
| `scripts/foundation/resolve.test.mjs` | 294 | `05f27aa6c8a1b8ff2ee45e5de03a9aea5ed13cf011b2464c5865022dc9781449` |
|
||
| `scripts/foundation/cli.test.mjs` | 279 | `b7e9a13c11e3e6f487ada2779c892cdf848526de1ef8b21387d15d4a461ddb62` |
|
||
| `scripts/foundation/fixtures.test.mjs` | 93 | `2827de36214c8014471fed3478c42bf48eddb3fbdbff82cac9e27851646b15d2` |
|
||
| `scripts/foundation/fixtures/build-fixtures.mjs` (generator) | 908 | `094ecc811b85465cc0748a86b76b75c1784a2e0296f242b6ff2dbd1660b426a9` |
|
||
| `scripts/foundation/fixtures/index.json` (204 cases) | | `74988a1dcd4b48b0be2243d3fefff3b6de5d90a947094be201c3486142ca12a2` |
|
||
| `scripts/foundation/fixtures/README.md` | | `aba48ba054d09247b048a8955507b87a275cd585870f1f658b7c6b826fc892bd` |
|
||
| `scripts/test-foundation.sh` (executable) | 132 | `76fb7ba9da4345271b6ba93228a9da69c7e55c4e44b9f4033e84a8f4b430e8ec` |
|
||
|
||
Generated fixture trees (deterministic output of `build-fixtures.mjs`; the suite
|
||
fails if a checked-in file differs from a fresh generation):
|
||
|
||
| Tree | Files | Bytes | Manifest sha256 of `find <tree> -type f \| LC_ALL=C sort \| xargs sha256sum` (run in `scripts/foundation/fixtures/`) |
|
||
|---|---|---|---|
|
||
| `scripts/foundation/fixtures/bundles/` | 185 | 9,235,245 | `a804e4ab253839ba2bb8ad7475d27512b2ef88e70a9779f9093fee5478de4823` |
|
||
| `scripts/foundation/fixtures/raw/` | 19 | 1,336,985 | `508ad85208f4b69676f3d041faa4ff4cd4a2f8de74b7bde9b0b89123a8485cc4` |
|
||
|
||
Owner-demo copies and goldens (`scripts/foundation/fixtures/demo/`, 249,096 bytes):
|
||
|
||
| File | SHA-256 |
|
||
|---|---|
|
||
| `demo-read-w1.json` | `7a3cfc58c1356cc2a986e0a6ed8f9f2dffbc33277ea1b7800020bfc55624b750` |
|
||
| `demo-read-w1.expected.txt` | `8bfff519ce8275cfe59562efd04647c242c328a09b301b91d70491f030cf1600` |
|
||
| `demo-read-w1.expected.json` | `55e10c1693787cd8e39d3a66841d30e2336080d2ae4450a806a7ae8373db476b` |
|
||
| `demo-read-w1.expected.exit` (0) | `9a271f2a916b0b6ee6cecb2426f0b3206ef074578be55d9bc94f6f3fe3ab86aa` |
|
||
| `demo-file-change-src.json` | `7c0948d39abd3f1eeb0b0990766cbf584959712000faacaf47ae0d3501def3cc` |
|
||
| `demo-file-change-src.expected.txt` | `f5387217ca0a41d437468af33b7d87d06c0c5535ab5490b568f9866a13b2732e` |
|
||
| `demo-file-change-src.expected.json` | `88c7793c6af17ca255525451a499d9f8bb165155e50d2ee936bd68ba82a876a7` |
|
||
| `demo-file-change-src.expected.exit` (0) | `9a271f2a916b0b6ee6cecb2426f0b3206ef074578be55d9bc94f6f3fe3ab86aa` |
|
||
| `demo-change-w1.json` | `54aad9047f7fe86892889ead543403c42986f591722d0dd23e0e027c3b7191d5` |
|
||
| `demo-change-w1.expected.txt` | `2a1090e5f5ad08e2175830943a7c81928de970470893e803b1e440843152c348` |
|
||
| `demo-change-w1.expected.json` | `36c287cba327070f7ff3dd9846421bee3ebd0dd52e9c602b68e84fa620ef4fc5` |
|
||
| `demo-change-w1.expected.exit` (3) | `1121cfccd5913f0a63fec40a6ffd44ea64f9dc135c66634ba001d10bcf4302a2` |
|
||
| `adm-registration-revoked.json` | `ff7b859cd959876b2b6ede97fff90383a38acde765a16294b095ba220290c579` |
|
||
| `adm-registration-revoked.expected.txt` | `624c9e5991597d59fc3379343b16e7eab9cb6434f054da3a4df7518742e3b36c` |
|
||
| `adm-registration-revoked.expected.json` | `b966d939e0d2851ef731462a0fda932e75f53b9aac406216ad440f781e036d0f` |
|
||
| `adm-registration-revoked.expected.exit` (3) | `1121cfccd5913f0a63fec40a6ffd44ea64f9dc135c66634ba001d10bcf4302a2` |
|
||
| `prop-message-is-not-authority.json` | `f1c6bd523cdff161e51da156fd00cfaa652d193f41541686548fc023378fd8ab` |
|
||
| `prop-message-is-not-authority.expected.txt` | `e7b0e9fa64abe0c0f8c91fbc9aa565988ce76cb3967672bfacafab350e20d8be` |
|
||
| `prop-message-is-not-authority.expected.json` | `53884bfdea21185141b9a06d52aa1c0fe8e7bfae6627b465929403521f9bc4d8` |
|
||
| `prop-message-is-not-authority.expected.exit` (3) | `1121cfccd5913f0a63fec40a6ffd44ea64f9dc135c66634ba001d10bcf4302a2` |
|
||
|
||
Reviewer re-derivation (from the repository root):
|
||
|
||
```sh
|
||
sha256sum scripts/foundation-inspect.mjs scripts/test-foundation.sh scripts/foundation/*.mjs \
|
||
scripts/foundation/verify-schema.py scripts/foundation/fixtures/build-fixtures.mjs \
|
||
scripts/foundation/fixtures/index.json scripts/foundation/fixtures/README.md
|
||
(cd scripts/foundation/fixtures && sha256sum demo/*)
|
||
(cd scripts/foundation/fixtures && for d in bundles raw; do \
|
||
echo "$d $(ls $d | wc -l) $(find $d -type f | LC_ALL=C sort | xargs sha256sum | sha256sum | cut -d' ' -f1)"; done)
|
||
```
|
||
|
||
## 4. What was built (charter mapping)
|
||
|
||
- `strict-json.mjs` — byte-level strict JSON parser (charter §6, §10.5): UTF-8
|
||
validation with distinct codes (`utf8-invalid`, `utf8-overlong`, `utf8-surrogate`,
|
||
`utf8-out-of-range`, `utf8-truncated`), duplicate-key refusal with byte offset,
|
||
safe-integer-only numbers (no fraction/exponent/`-0`), raw controls in strings
|
||
refused, BOM/trailing content refused, bounds: input 1 MiB, string 4096 bytes,
|
||
container items 1024, nesting 32 (container nesting; a scalar inside the 32nd
|
||
container is depth 32), all reported as `StrictJsonError` with `byteOffset`.
|
||
Objects are built with null prototypes (`__proto__`/`constructor` keys are plain
|
||
own keys and never pollute).
|
||
- `canonical.mjs` — canonical form and `sha256:` digest (charter §6, vectors V1–V5):
|
||
UTF-16 code-unit key ordering, ASCII-only strings, safe integers only,
|
||
depth 64, refusals typed as `CanonicalError` with reason `unsupported-capability`.
|
||
- `resolve.mjs` — pure evaluation (charter §§3–5, §7, §10.1–10.4): shape gate,
|
||
record validation (schema-equivalent field/pattern/enum/calendar/path rules),
|
||
identity/duplicate/reference/revision/cycle graph checks in the §10.4 fixed
|
||
sub-order, registration/delegation with explicit issuer bounds (§10.1),
|
||
structural ownership versus consulted work access (§10.2), direct declared
|
||
delegation inputs only (§10.3), mandatory ceilings (agent/project/workspace
|
||
policies, scope role, registration, execution, mission/task restrictions)
|
||
intersected by least privilege, four supported operations only, and the
|
||
reassignment proposal path whose only terminal outcomes are `refused` or
|
||
`unresolved` (assignment.change has no allowed branch). Closed vocabularies
|
||
`RULES` (108), `REASONS`, `RESULTS`, `PROPOSAL_STEPS`, `SUPPORTED_OPERATIONS`,
|
||
`RESULT_KEYS`; `buildResult` throws on any rule/reason outside them.
|
||
- `validate-record.mjs` — test-only bridge exposing per-record schema-shape
|
||
validity to the Python oracle (stdin JSON in, verdict JSON out). Not used by
|
||
the CLI.
|
||
- `foundation-inspect.mjs` — CLI: `node scripts/foundation-inspect.mjs [--json] <bundle.json>`.
|
||
Opens the input with `O_RDONLY|O_NOFOLLOW`, requires a regular file, refuses
|
||
size changes between fstat and read, applies the 1 MiB gate before parsing,
|
||
renders text or JSON from one result object, escapes every risky code point in
|
||
echoed identifiers/paths, exits with the result's `exit`. Imports only
|
||
`node:fs`, `node:url`, `node:path` and the local modules; the only `process.`
|
||
uses are `argv`, `exitCode`, `stdout`. It never spawns, never reads env/config/
|
||
HOME/cwd, never touches the network. Output starts with
|
||
`SYNTHETIC PREVIEW — NO LIVE EFFECTS` and carries the preview/authentication/
|
||
declarations disclaimers in both renderings.
|
||
- `verify-schema.py` — mandatory differential oracle against the pinned
|
||
`records.schema.json` with the explicit `jsonschema 4.26.0`; missing dependency
|
||
or hash mismatch is a failure, never a skip.
|
||
- Fixtures — 204 deterministic synthetic cases (185 bundles, 19 raw byte-exact
|
||
files) generated by `build-fixtures.mjs`, indexed with expected
|
||
exit/result/reason/rule/proposalRule (and byteOffset for lexical cases);
|
||
5 demo copies with byte-exact goldens.
|
||
- `test-foundation.sh` — repository-style selftest (syntax, fixture diff,
|
||
`node --test`, oracle, exit receipts, goldens, `env -i` sandbox non-effect and
|
||
canary checks).
|
||
|
||
## 5. Commands and results (all run from the repository root at HEAD 9a5fbdb)
|
||
|
||
```sh
|
||
node --version # v26.8.1
|
||
python3 --version # 3.12.8
|
||
python3 -c 'import importlib.metadata as m; print(m.version("jsonschema"))' # 4.26.0
|
||
|
||
node --test scripts/foundation/ # ℹ tests 57 ℹ pass 57 ℹ fail 0
|
||
python3 scripts/foundation/verify-schema.py # PASS (see lines below)
|
||
NO_COLOR=1 scripts/test-foundation.sh # selftest: 37 passed, 0 failed (rc 0)
|
||
python3 docs/plans/foundation-v1-candidate/check.py # PASS: 35 synthetic ... cases (rc 0)
|
||
scripts/test-config.sh # selftest: 24 passed, 0 failed (rc 0)
|
||
scripts/test-task.sh # selftest: 90 passed, 0 failed (rc 0)
|
||
scripts/test-release.sh # selftest: 14 passed, 0 failed (rc 0)
|
||
scripts/test-conductor.sh # selftest: 17 passed, 0 failed (rc 0)
|
||
scripts/test-auth.sh # selftest: 15 passed, 0 failed (rc 0)
|
||
```
|
||
|
||
Oracle summary lines (verbatim from the final run):
|
||
|
||
```
|
||
PASS: python 3.12.8 jsonschema 4.26.0
|
||
PASS: 38 pinned record fixtures agree with the pinned expectations
|
||
node v26.8.1; corpus 1431 records (38 pinned fixtures, 410 unique bundle records, 983 typeCase/mutation/lexical cases)
|
||
schema column agreement: 1388; strict-only (parser-bound) cases: 27; unsupported-kind records not schema-assessed by the inspector: 10
|
||
known divergences reproduced: 6/6
|
||
PASS: differential schema oracle (finite corpus; compatibility evidence, not equivalence proof)
|
||
```
|
||
|
||
Node test breakdown: strict-json 12, canonical 10, resolve 16, cli 14, fixtures 4
|
||
(= 57). The five repository suites were run unchanged against the same working
|
||
tree; they do not exercise the new code and are reported as integration receipts
|
||
only. Unrelated concurrent working-tree changes (not mine, untouched): modified
|
||
`BUILD-LOG.md`, `docs/SESSIONS.md`, `docs/plans/CURRENT.md`; untracked
|
||
`docs/plans/2026-09-06_*.md`, `docs/plans/foundation-v1-candidate/`,
|
||
`docs/plans/reviews/*` (except this report), `skills/ms-*`,
|
||
`tasks/foundation-phase2-source-facts.json`.
|
||
|
||
Git state: HEAD `9a5fbdbda74b16adf488fe28138b2ba69ea5e669` before and after;
|
||
nothing staged, committed, checked out, reset or pushed. Only read-only git
|
||
inspection was used. A stray `scripts/foundation/__pycache__/` produced by an
|
||
earlier `py_compile` syntax step was deleted and the suite now uses an
|
||
AST-only parse so no bytecode is written.
|
||
|
||
## 6. A1–A8 coverage (named evidence, not aggregate counts)
|
||
|
||
Fixture groups from `index.json` (204 cases): positive 14, shape 37, profile 3,
|
||
identity 5, structure 5, cycle 4, continuity 2, ownership 9, operation 7,
|
||
admission 49, registration-delegation 13, proposal 37, lexical 19. Expected
|
||
outcome classes: exit 0 allowed 14; exit 2 invalid 102; exit 3 refused 86;
|
||
exit 3 unresolved 2. Every rule in `RULES` except the five CLI/I-O rules is
|
||
exercised by at least one fixture (`resolve.test.mjs` enforces this); the CLI
|
||
rules are exercised by `cli.test.mjs`.
|
||
|
||
| Gate | Evidence |
|
||
|---|---|
|
||
| A1 positive previews | Fixtures `demo-read-w1` (work.read), `demo-file-read-src`, `demo-file-change-src` (assigned file.change), `taskless-file-read`, `taskless-work-read`, `deleg-approved-file-read`, `mission-/execution-/registration-restrictions-narrow-ok`, `work-parent-project-mission`, `file-read-with-unaccepted-dependency`, `p2-inventory-unselected`. Byte-exact text/JSON/exit goldens (`fixtures.test.mjs` "owner demo goldens"); text derived from the same result as JSON (`cli.test.mjs` "text output is derived…"); determinism across HOME/config (`cli.test.mjs` "HOME/config independence"); disclaimer first line and closing `exit:` line checked for all 204 cases. |
|
||
| A2 unregistered/cross-project selection | `adm-workspace-registration-missing`, `adm-selected-workspace-missing`, `adm-project-registration-missing`, `adm-selected-project-missing`, `adm-cross-workspace-mission`, `adm-cross-project-dependency`, `adm-assignment-other-workspace`, `own-workspace-project-missing`, `prop-target-cross-project-*`. No fallback: selection shows `assignment null` and result is refused. No unrelated payload: every result is walked against the closed key vocabulary (`resolve.test.mjs` `unknownKeys`), and rendered text is scanned for raw risky code points for every case. |
|
||
| A3 graph negatives | Duplicates `dup-record-identity`, `dup-registry-identity`, `dup-artifact-identity`, `dup-authorization`, `dup-delegation-input`; references `ref-missing-*` (5); ownership `own-*` (9); revision/continuity `continuity-revision-gap`, `continuity-supersedes-other-identity`, `shape-record-rev1-with-supersedes`; cycles `cycle-dependency-self`, `cycle-dependency-pair`, `cycle-mission-self-parent`, `cycle-supersedes-self-rev2`. Detector unit tests (`findCycle` self/pair/diamond/missing/20000-node chain, `deepEqual`) are separate from the CLI fixture pass; §10.4 first-failure precedence asserted in `resolve.test.mjs`. |
|
||
| A4 ceilings and narrowing | Missing/empty authority: `adm-agent-policy-missing`, `adm-project-policy-missing`, `adm-workspace-policy-missing`, `adm-scope-role-missing`, `adm-authorization-undeclared`, `adm-dependency-grants-nothing`, `adm-policy-ceiling-stale`. Narrowing per layer: `adm-operation-not-permitted-{role,agent-policy,execution}`, `adm-path-not-permitted-{prefix-string,read-execution,task-narrows,write-outside}`, `rdeleg-issuer-ceiling-narrows-path`, `rdeleg-narrows-to-delegated-ops`, `rdeleg-exceeds-issuer-ceiling`. Cross-assignment union impossible: `adm-assignment-other-agent`, `adm-assignment-other-workspace`, `own-assignment-task-other-workspace`; unassigned change `adm-assignment-required-for-change`. Unit: `intersectLayers` (network none dominates, endpoint structural intersection, delegated ops), `intersectGrants`, `pathPermitted`. |
|
||
| A5 lexical versus schema/profile | Raw byte cases: `raw-duplicate-key`, `raw-bom-prefix`, `raw-invalid-utf8`, `raw-utf8-surrogate`, `raw-lone-escape-surrogate`, `raw-raw-control-in-string`, `raw-fraction-number`, `raw-exponent`, `raw-negative-zero`, `raw-unsafe-integer`, `raw-string-too-long`, `raw-array-too-long`, `raw-depth-33`, `raw-oversize-file`, `raw-empty-file`, `raw-not-object`, `raw-trailing-content`, `raw-proto-key`, `raw-constructor-key` (each with expected byteOffset). Schema/profile: `shape-record-bad-time`, `shape-record-calendar-invalid`, `shape-record-leap-second`, `shape-record-unknown-field`, `shape-unknown-top-field`, `shape-record-displayname-too-long`, `shape-target-{backslash,control-char,dotdot,empty-segment,wrong-root}`, `shape-registry-content-non-ascii`, `shape-unsupported-kind-session` (unsupported-kind, not invalid), `shape-unknown-kind`. Parser unit tests (12) and the oracle report schema agreement separately from parser-bound (27) and unsupported-kind (10) columns. |
|
||
| A6 no effects, no ambient lookup | Static import boundary test: pure modules import only `node:crypto` and local modules; the CLI imports only `node:fs`/`node:url`/`node:path` plus local; `process.` uses are exactly `argv`, `exitCode`, `stdout`; forbidden module names (`node:child_process`, `net`, `http`, `os`, `dns`, `tls`, `worker_threads`, `vm`, …) absent everywhere, and `process`, `Date`, `fetch`, `Math.random` and dynamic `import()` absent from the pure modules. Descriptor checks: symlink → exit 4 `input-open-failed` (O_NOFOLLOW), directory and FIFO → `input-not-regular`, chmod 000 → open failure, size change guard. Inventory comparison (path/type/size/mode/inode/mtime/sha256) of a disposable sandbox with fake HOME/.mosaic credentials, config, cwd, data-root before and after every run kind; canary strings never printed; `test-foundation.sh` repeats this under `env -i HOME=<sandbox> PATH=/nonexistent`. These are bounded evidence, not an OS sandbox proof (see §8). |
|
||
| A7 cross-lane proposal | 37 `prop-*` cases plus `demo-change-w1`, `op-change-without-proposal`. Both requester contexts: `prop-requester-context-wrong-{agent,scope}`, `prop-original-requester-{lacks-change,assignment-paused,registration-revoked}`, `prop-original-context-no-work-read`, `prop-target-requester-lacks-change`, `prop-target-{workspace-retired,task-stale,cross-project-*}`. Intent/delegation: `prop-intent-*`, `prop-delegation-*` (10), `prop-change-*`, `prop-message-is-not-authority`, `prop-subject-*`. Original selection preserved: `prop-selection-agent-mismatch`, `prop-selection-null-assignment`, and every proposal's `selectedAssignmentRef` equals the selection. Fully supplied mock evidence cannot yield allowed: `prop-all-pass-restricted-contexts` → `unresolved / unknown-effects / runtime-reconciliation-required`, exit 3. Index check: all 39 assignment.change bundles expect exit 2 or 3; the 14 exit-0 cases are work.read/file.read/file.change only. `PROPOSAL_STEPS` values are asserted to be only refused/unresolved. |
|
||
| A8 closed result contract | Result key order `RESULT_KEYS` and nested closed keys asserted for every case; `resultFor` mapping exit→result asserted; exit classes 0/2/3/4 all exercised: usage (2), oversize (2, null diagnostic), parse failure (2, byteOffset, inputPath null), I/O (4, inputPath echoed only there), refusals (3), unresolved (3), allowed (0). Escaping: ESC, U+2028, DEL, backslash and astral characters in agentId/paths are escaped in both renderings (`escapeText` unit vector), stdout is the only stream, stderr asserted empty for all 204 spawned runs. |
|
||
|
||
§10.1–10.5 fixture mapping: 10.1 `rdeleg-*` (13) and `shape-delegation-*`,
|
||
`shape-plan-with-delegated-operations`; 10.2 `adm-consulted-work-not-readable`,
|
||
`adm-cross-workspace-mission`, `own-*`, `work-parent-project-mission`,
|
||
`file-read-with-unaccepted-dependency`; 10.3 `rdeleg-subject-form-task`,
|
||
`rdeleg-subject-form-three`, `rdeleg-scope-not-modelled`, `prop-delegation-input-missing`;
|
||
10.4 precedence tests and the four `cycle-*` cases; 10.5 the raw lexical corpus,
|
||
the oracle's typeCase/mutation/lexical corpus (983 cases) and the platform notes
|
||
in §8 below.
|
||
|
||
## 7. Design decisions taken inside the charter (for reviewer attention)
|
||
|
||
1. Nesting bound counts containers only (a scalar inside the 32nd container is
|
||
depth 32; a 33rd container fails at its opener offset).
|
||
2. Oversize input (>1 MiB) is exit 2 `invalid-request` / `input-too-large` with a
|
||
null diagnostic; exactly 1 MiB is parsed.
|
||
3. `diagnostic.inputPath` is set only on I/O failure (exit 4); `byteOffset` only on
|
||
parse failure. No other path, cwd, HOME or locator is ever emitted.
|
||
4. `registration-ambiguous` (two current registrations for one identity) is an
|
||
invalid bundle (exit 2), not a refusal.
|
||
5. U+2028/U+2029 in relative paths are accepted (the pinned checker accepts them)
|
||
but always escaped on output; astral characters pass through unescaped.
|
||
6. Unsupported record kinds are refused at the kind gate (`unsupported-kind`) and
|
||
are not schema-assessed; the oracle reports them in a separate column.
|
||
7. Strict parser string bound is 4096 UTF-8 bytes, tighter than the schema's
|
||
4000 code points for non-ASCII text; the 27 oracle "strict-only" cases are
|
||
exactly that difference (parser refuses, schema would accept).
|
||
8. All generated fixtures are checked in (about 10.9 MB) rather than generated at
|
||
test time, so the reviewed candidate is byte-frozen; the suite diffs them
|
||
against a fresh generation.
|
||
|
||
## 8. Known limitations and untested limits
|
||
|
||
- Finite corpus: the oracle is compatibility evidence over 1431 records, not a
|
||
proof of schema equivalence. Six known, directional divergences are pinned and
|
||
must reproduce exactly: four trailing-newline pattern cases (python accepts,
|
||
inspector refuses, because Python `$` matches before a trailing newline) and
|
||
years 0001–0999 in `time` fields (python refuses because glibc `%Y` is unpadded
|
||
so its round-trip fails; the inspector accepts calendar-valid years 1–9999).
|
||
- Sandbox claims are bounded: canary/inventory/static-import checks and
|
||
`env -i` runs show no observed effect or lookup in the tested paths; they do not
|
||
prove absence of all reads, containment or crash safety. A temporary HOME is not
|
||
an OS sandbox.
|
||
- Node has no `fs.constants.O_CLOEXEC` on this host; the open flags are
|
||
`O_RDONLY|O_NOFOLLOW` plus fstat/regular-file/size-stability checks only.
|
||
- Authentication is not modelled; declarations are unverified simulation. No
|
||
mock evidence, however complete, reaches `allowed` for assignment.change.
|
||
- Hidden delegation chains are not detected (§10.3 by design); only direct
|
||
declared delegation inputs are evaluated.
|
||
- The FIFO test requires `mkfifo`; the chmod-000 test is skipped when run as root.
|
||
- Nothing native, sync, live-registry or runtime was touched or tested.
|
||
|
||
## 9. Owner-demo commands (A9, for darkwing to run with Jason after review)
|
||
|
||
All from the repository root; each prints the disclaimer first and changes no file.
|
||
|
||
```sh
|
||
# 1. selected agent/project/workspace with a permitted read preview (exit 0)
|
||
node scripts/foundation-inspect.mjs scripts/foundation/fixtures/demo/demo-read-w1.json
|
||
|
||
# 2. assigned file.change permission preview (exit 0), then show nothing changed
|
||
sha256sum -c <(sha256sum scripts/foundation/fixtures/demo/*.json) >/dev/null && \
|
||
node scripts/foundation-inspect.mjs scripts/foundation/fixtures/demo/demo-file-change-src.json; \
|
||
sha256sum -c <(sha256sum scripts/foundation/fixtures/demo/*.json)
|
||
|
||
# 3. unregistered workspace selected: refusal without fallback (exit 3, assignment null)
|
||
node scripts/foundation-inspect.mjs scripts/foundation/fixtures/bundles/adm-workspace-registration-missing.json
|
||
|
||
# 4. cross-lane reassignment preview: original assignment stays selected, mock evidence cannot yield allowed (exit 3, unresolved)
|
||
node scripts/foundation-inspect.mjs scripts/foundation/fixtures/demo/demo-change-w1.json
|
||
node scripts/foundation-inspect.mjs scripts/foundation/fixtures/bundles/prop-all-pass-restricted-contexts.json
|
||
|
||
# additional negatives used in the goldens (exit 3)
|
||
node scripts/foundation-inspect.mjs scripts/foundation/fixtures/demo/adm-registration-revoked.json
|
||
node scripts/foundation-inspect.mjs scripts/foundation/fixtures/demo/prop-message-is-not-authority.json
|
||
|
||
# machine-readable form of any of the above
|
||
node scripts/foundation-inspect.mjs --json scripts/foundation/fixtures/demo/demo-read-w1.json
|
||
|
||
# full offline selftest
|
||
scripts/test-foundation.sh
|
||
```
|
||
|
||
Expected exits: step 1 → 0; step 2 → 0 with both checksum passes; step 3 → 3
|
||
(`workspace-registration-missing`); step 4 → 3 twice (`runtime-reconciliation-required`,
|
||
result `unresolved`). Jason's answer on clarity and acceptance is to be recorded
|
||
separately by darkwing; this report claims no acceptance.
|
||
|
||
## 10. Freeze
|
||
|
||
Code, tests and fixtures are frozen at the manifest in §3 for filbert's
|
||
independent review. Rocko will change nothing under the allowlist until darkwing
|
||
returns reconciled findings; any fix produces a newly hashed candidate and a new
|
||
report revision. No dependent live-registry/runtime work, migration, staging,
|
||
commit, push or issue closure follows from this delivery.
|