feat(foundation): offline synthetic scope/permission inspector (FI-FILBERT-8 APPROVED r6)

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.
This commit is contained in:
2026-09-07 14:06:35 -05:00
parent 127a54fdff
commit 8ebddd6f93
423 changed files with 665972 additions and 0 deletions
@@ -0,0 +1,416 @@
# Foundation synthetic inspector — frozen charter candidate 3
Issue: #53. Author/integrator: darkwing. Feasibility contributor: rocko.
Independent reviewer: filbert, pending exact-candidate review.
Status: proposed implementation contract, NOT permission to implement.
Jason authorized continuation of planning after accepting the reviewed map.
No source changes, migration, publication, push or live fleet activity authorized.
## 1. Bound inputs and interpretation
Accepted map/handoff: commit 7345f330fc6bfae5aa1d896c78cfb7cbe62efbae.
Source/plan baseline: d4696d09eb1b5dcf1028f30db2cd63735f51cb16.
Map verdict: FM-FILBERT-1, SHA-256
6b08c6fac0718d3db527cf9ffbfab49407e7b289d09782f5d1d0e26493eaabb3.
That approval does not cover this new charter.
Detailed incorporated specification: sections 513 of
reviews/2026-09-06_foundation-inspector-rocko-feasibility-r2.md,
SHA-256 f2f47fcfe22dca79f10f885b83d87a2f846fdb560425a4e20705c40ce4a123e1.
The explicit corrections/decisions below override that note. Its other sections
are contributor rationale/history, not normative repository facts. Original r1
and the FI-ROCKO-2 corrections remain history, not alternate specifications.
Any ambiguity or contradiction discovered at implementation is a charter defect
to resolve, not permission for a coder to guess or weaken refusal rules.
Candidate records.schema.json SHA-256:
05774aaf6943cb69c113e39ff1c29676a2a230ca7bf665c50dbcaa8049672af6.
Candidate check.py SHA-256:
82564a7d3200afcdda0850a9454cac6e6cd6a76687d2162c13cf214d7eac4607.
Both resolve under docs/plans/foundation-v1-candidate at d4696d09.
## 2. Deliverable and non-goals
One local CLI over an explicitly supplied synthetic bundle, with deterministic
text and JSON previews of selected agent/project/workspace permission. No cwd
inference of scope, live registry, config bootstrap, account lookup, engine launch,
assignment mutation or real permission grant. Every result, including parser/I/O
failures, says SYNTHETIC PREVIEW — NO LIVE EFFECTS and authentication: not-modelled.
Implemented operations: work.read (null target), file.read/file.change (logical
workspace-relative target), and assignment.change as a negative/unresolved check
only. The other 25 known catalog names return unsupported-capability, exit 2.
Unknown names return invalid-request, exit 2. No assignment-change success path.
No execution.stop operation is invented; the catalog contains execution.control.
No general RPC, sandbox, authentication, command audit, stopping, durability,
legacy adoption, OAuth refresh or extension integration is delivered.
Operator supplies synthetic files only. The CLI reads just that explicit input,
never discovers credentials/config. It cannot know whether arbitrary operator-
selected file bytes contain secrets before reading them; this is not a general
credential-read prevention boundary. Never pass credentials or live records to it.
Tests and agents are not authorized to access such files.
## 3. Input, identity and graph rules
Use the closed bundle/selection/registry/artifact/authorization shapes in r2 §5,
subject to the proposal and output overrides below. All fields shown there are
required except message. proposal is explicitly null outside assignment.change;
assignment.change requires non-null proposal and null operation.target. The
subjectAssignmentRef must exactly equal selection.assignmentRef; selection agent,
project and workspace must match that assignment. Never infer a different subject.
Eight supported record kinds: agent-definition, project, workspace, registration,
mission, task, assignment and decision. Other candidate kinds refuse unsupported-
kind. Candidate record shapes remain unchanged; simulation-specific fields exist
only in the enclosing bundle, never appended to accepted records.
Record references are kind/id/scope/revision, WITHOUT digest. Registry references
include registry/id/revision/digest. Artifact references and authorization IDs
match declared simulation inputs; their presence proves neither publication
permission, authentication, authentic evidence nor current real-world authority.
Decision approvals are evaluated as synthetic fixture facts, not verified signatures.
Missing declarations refuse; no flag can turn them into actual authenticated facts.
Reject duplicate record identities, duplicate registry identities even with different
digests, duplicate artifact identities (runId/artifactId) even with different digests,
and duplicate authorization IDs. Do not choose one of ambiguous registrations:
more than one current active registration for the same agent/scope refuses ambiguity.
Revision rules: complete contiguous history from 1, or a single revision-1 record.
Structural references on every revision must resolve. Apply head/current-admission
checks only to head records used for this calculation and their consulted chain;
historical records do not fail merely because their then-current refs are now old.
Explicit historical supersedes/decision subject references may name existing old
revisions. Current selected intent/task/mission/registration/delegation/proposal
refs must name heads; no invented predecessor, repair or fallback.
Cycle checks cover task.dependencies, mission.parentMissionRef and supersedes as
separate edge relations. Before tests are counted, show that each fixture reaches
the intended rule rather than failing an earlier shape error. Workspace ownership,
mission parent scope and registration parent match the accepted schema/README.
Dependencies grant no ownership/access. A selected task's same-project dependencies
must be accepted to permit file.change; another project's dependency never lends
permission. Broader dependency execution semantics are unsupported in this slice.
## 4. Mandatory policy and assignment calculation
Adopt r2 §7 L1L9: enabled agent ceiling, both active registrations each bounded by
its mandatory scope-role ceiling, required project and workspace policy, exact
assignment/task/intent checks, applicable task/mission narrowing and an explicit
simulation execution layer. Workspace policy never falls back to a scope role.
Null optional restrictions mean no additional narrowing; missing required ceiling
never means unrestricted. Empty operations/path grants mean none. Exactly one
selected assignment contributes; no union across assignments.
Selected project/workspace must be active. Assignment is selected, belongs to the
selected agent and workspace, and binds the selected task. Task is ready/active,
with approved current plan-approval intent whose subjects include that exact task.
Assignment intent is an approved current plan-approval, delegation or assignment-
change decision covering the task/assignment. An unrelated approved acceptance
or owner-checkpoint decision is not a substitute. Mission chain must be active.
Taskless work.read/file.read skips assignment/task/mission only when assignmentRef
is explicitly null. Supplying an invalid assignment never falls back to taskless.
Paths use logical workspace roots and component-prefix intersection, never raw
string prefixes or physical filesystem traversal. Network restrictions are parsed
and intersected but no network operation is implemented or performed.
## 5. Reassignment negative check — tightened requester context
Extend r2 §5 proposal with required requesterContexts, a closed object:
- original: {assignmentRef, execution}
- target: {assignmentRef, execution}
Each assignmentRef is non-null recordRef; execution uses the same mandatory
selection.execution shape. No extra keys. Original scope derives from the subject
assignment; target scope derives from targetTaskRef. Both requester contexts belong
to requesterAgentId and the corresponding scope, not the subject agent.
Apply L1L9 to the requester in BOTH scopes for assignment.change, using those
contexts. Role membership alone is insufficient; task/mission/intent and execution
limits also narrow the request. Require original subject and target task current
intent/status checks. Apply r2 §8 recipient/subject-bounded delegation and recorded
change checks, with approved outcomes and exact current references. Artifact basis
is evidence only. Delegations are direct declared simulation assumptions as specified in §10;
this inspector cannot detect chains hidden in artifacts or omitted from the bundle.
No message authorizes a change. Missing delegation with a message yields the
message-is-not-authority rule once structural validation succeeds. Other failures
use fixed deterministic original-scope, target-scope, delegation, change, intent
ordering. If all simulation checks pass, return unresolved/unknown-effects with
runtime-reconciliation-required, NOT allowed. No supplied runtime observations
field exists. Echo the original selection unchanged on every admitted proposal.
This is a negative preview, not a real assignment engine or proof of stopping.
## 6. Canonicalization and precise limits
Adopt separately named inspector-content-digest/1 for mock registry content only:
sorted keys, compact encoding, ASCII string domain, safe integer values, array order
preserved. No launch fingerprint or full JCS claim. V1V3 in r2 were independently
recomputed and match. Use 1.5 (not 1.0) for the nonintegral-number V4 test: JavaScript
cannot distinguish numeric 1.0 from 1 after parsing. Reject negative zero and unsafe
integer values. Strict bundle number tokens use integer notation only: reject
fraction/exponent forms and negative zero, bound integer tokens exactly before
Number conversion. This prevents precision loss from hiding unsupported values.
This lexical restriction is an inspector profile rule, not a change to candidate
JSON Schema integer semantics; the differential record validator tests shapes
separately from this strict-input profile.
Non-ASCII mock content refuses unsupported-capability; candidate record and target
paths still use the candidate Unicode/path formats. Validation tests separate schema
validity from the stricter inspector input/canonicalization domain.
Bounds: file <=1 MiB; each top-level inventory <=256; arrays <=1024; nesting <=32;
strings <=4096 UTF-8 bytes subject to stricter candidate limits. Duplicate JSON keys,
malformed UTF-8, invalid calendar dates, forbidden path characters/segments and
unknown fields refuse. Parser object construction must not invoke prototype setters;
__proto__/constructor keys are ordinary unknown keys, never executable behavior.
Never normalize an invalid path into a permitted one.
Linux input open: require available O_RDONLY, O_NOFOLLOW and O_NONBLOCK; open the
final component without following its symlink, fstat regular type and bounded size,
read within limit with an extra-byte/truncation check, close in finally. Parent-path
containment is NOT claimed. Missing/symlink/FIFO/nonregular input refuses exit 4.
Do not OR an undefined O_CLOEXEC constant: host Node v26.8.1 exposes none (measured).
No child spawning or close-on-exec guarantee is claimed. The CLI itself never spawns;
verification harness processes are separate test effects. Same-size concurrent file
mutation is not ruled out by size checks: operator/test inputs must remain quiescent.
## 7. Output and exits — replaces r2 §9 shape
Closed result fields, emitted on every outcome:
- disclaimer: fixed SYNTHETIC PREVIEW — NO LIVE EFFECTS
- preview: fixed preview: no live registrations or permission grants
- bundleVersion: 1
- authentication: fixed not-modelled
- declarations: fixed unverified-simulation
- result: allowed | refused | unresolved | invalid
- reason: allowed | invalid-request | missing-state | stale-revision |
not-authorized | unsupported-capability | unsupported-kind | unknown-effects | io-failure
- rule: fixed documented rule identifier or null; never input-derived prose
- selection: null before safe structural validation, otherwise exactly the selected
{agentId, projectId, workspaceId, assignmentRef} supplied by the caller
- operation: null before safe validation, otherwise the validated {name, target}
- proposal: null outside a valid assignment.change input, otherwise
{result, reason, rule, selectedAssignmentRef}, with no allowed result
- diagnostic: null or {byteOffset, inputPath}, each member nullable; offset only for
parse failure, original argv path only for I/O failure, never file contents
No consulted inventory, global counts, unrelated identities/payloads or raw parser
messages. Text and JSON derive from the same result. JSON is ordinary valid JSON
with the disclaimer field, not a non-JSON preamble. Text escapes control characters
in echoed arguments/targets so diagnostics cannot inject terminal controls.
No time/random data. No output claims authentic publication or real grants.
Exits: 0 permitted permission preview; 2 malformed/structurally incoherent or
unsupported input; 3 simulated permission refusal or unresolved admission; 4 I/O.
Missing required JSON keys (including execution) are structural: 2 invalid-request.
Absent referenced ordinary records are incoherent: 2 missing-state. Absent declared
mandatory policy/artifact/authorization inputs: 3 missing-state. Existing historical
reference used for current admission: 3 stale-revision. Cycles/duplicates: 2 invalid-
request. These override inconsistent example exits in r2. Refusal is never repaired.
## 8. Physical paths, toolchain and verification
Proposed implementation allowlist only:
- scripts/foundation-inspect.mjs (CLI; eventual packages/mosaic)
- scripts/foundation/{strict-json,canonical,resolve}.mjs (pure; eventual packages/config)
- scripts/foundation/validate-record.mjs (test-only differential bridge)
- scripts/foundation/verify-schema.py (verification only)
- scripts/foundation/*.test.mjs and scripts/foundation/fixtures/**
- scripts/test-foundation.sh
This is not yet a code-write authorization. No root/package-manager files, packages/
scaffolds, duplicate runtime sources, .pi/extensions, Dewey scripts, roles or config
changes. Pure modules never import live config, filesystem/process/network APIs or
read environment/clock. CLI handles input/output only, with no ambient config lookup.
Node ESM, zero new runtime dependencies. Record exact tested Node version; proposed
minimum 22 is not evidence of testing every supported version. Host measured 26.8.1;
container source uses node:24-bookworm-slim, not the first CLI's test environment.
No new repository engines pin is inferred. No automatic installation.
Mandatory verification uses existing explicitly selected Python/jsonschema 4.26.0,
checking pinned schema/checker hashes first. Missing dependency fails, never skips.
The differential bridge compares field-level validation over supported candidate
fixtures plus deterministic mutations, not invocation of check.py as a library.
Keep record-schema verdict distinct from unsupported-kind/profile/graph refusal.
Use calendar/path format semantics from the pinned checker, not string-only tests.
Unit/CLI tests cover r2 §12 with these overrides. Separate observed fixture/home/cwd/
data-root roots from harness output. Compare before/after path/type/size/mode/owner/
inode/content inventories; canaries and static import checks are bounded evidence,
not a sandbox or proof of no reads. No native synchronization or live fleet tests.
Required five repository suites and foundation author checks must remain green.
## 9. Acceptance and gates
A1. Positive read and assigned file.change permission previews with coherent records;
deterministic text/JSON, explicit disclaimers and no effects.
A2. Unregistered second workspace/cross-project selection refuses without fallback
or unrelated payload disclosure.
A3. Ownership/reference/duplicate/revision/cycle negatives hit the intended rules.
A4. Required role ceilings and all applicable layers narrow; empty/missing authority,
cross-assignment union and unassigned change refuse.
A5. Encoding, duplicate keys, calendar, path, bounds and unknown-field tests refuse
safely with the documented schema/profile distinction.
A6. Input/observed roots unchanged; no bootstrap, ambient config/credential lookup,
engine, network, installation or migration action.
A7. Cross-lane proposal preserves original selection; requester limits in both
scopes enforced; even fully supplied mock evidence cannot yield allowed.
A8. All output/exit combinations match the closed result contract, including parse
and I/O failure. No raw contents, unrelated metadata or terminal injection.
A9. Jason runs the positive and negative demo and understands the limitation before
any dependent live-registry/runtime increment begins.
First: Filbert independently reviews the frozen charter and incorporated note at
exact hashes without authorship or edits. Resolve substantive findings as a new
candidate. Then present the reviewed build scope to Jason for implementation
approval; prior map acceptance does not supply it. After authorized implementation,
retain separate author/reviewer roles, serialize shared index use, run all required
checks and obtain owner demo acceptance before dependent work. No automatic push,
issue closure, implementation or next-phase advancement follows from this charter.
## 10. Candidate 3 corrections — normative overrides for FI-FILBERT-2
These rules resolve findings 15 and override any remaining inconsistent shorthand
in this charter or the incorporated note. Candidate 2 and its NOT APPROVED verdict
are preserved separately; approval of this revision is not yet established.
### 10.1 Registration delegation and explicit mock issuer bounds (finding 1)
Add required top-level `delegationInputs`, an array of at most 256 closed objects:
`{decisionRef, mode, issuerCeiling}`. decisionRef is a candidate recordRef of kind
decision; mode is exactly `direct-declared`; issuerCeiling is candidate restrictions.
No extra fields. Duplicate exact decisionRef entries are structural invalid-request,
exit 2. This is another explicit simulation input, not an accepted record-schema
change or a runtime authority record. Empty array is allowed when none is consulted.
Its ceiling is an unverified stand-in for the referenced decision author's reviewed
delegation ceiling; it proves neither authorship nor actual permission to delegate.
For each consulted current L2/L3 registration:
1. Check current registration identity, active status, correct agent/owning scope
and required parent registration. Revoked registration: exit 3 not-authorized,
rule registration-revoked. Resolve mandatory scope-role and policy ceilings.
2. delegationRef null explicitly models owner-origin registration under the
declared authorization ID. That is a fixture assumption, not verified owner
issuance. Other mandatory checks/ceilings still apply; null is not a grant.
3. Non-null delegationRef must name a current head decision. Old decision reference:
exit 3 stale-revision, registration-delegation-stale. Its decisionKind must be
delegation and outcome approved; otherwise exit 3 not-authorized,
registration-delegation-not-approved. No new revoked field is invented: changing
the decision head to rejected blocks admission, as does using its old revision.
4. Supported scope is exactly the registration's scope. A broader/other scope is
exit 3 unsupported-capability, registration-delegation-scope-not-modelled.
subjectRefs must be exactly the current agent-definition reference for that
registration's agent and the exact current registration reference. A wrong
recipient/registration is exit 3 not-authorized, registration-delegation-bounds;
additional subject forms are exit 3 unsupported-capability,
registration-delegation-subject-form. No ambiguous pairing of multiple recipients.
5. Require the exact decision's delegationInputs entry. Missing: exit 3 missing-state,
delegation-input-missing. Every delegatedOperation must be in issuerCeiling's
operations; otherwise exit 3 not-authorized, delegation-exceeds-issuer-ceiling.
6. Intersect the role ceiling, optional registration restrictions, delegated
operation set AND the issuerCeiling restrictions (operations, paths, network and
endpoints), then all other L1L9 layers. No union or skipping the role ceiling.
Current consulted scope-role/agent-policy/project-policy references must name the
highest declared revision of that registry/id; an older ceiling is exit 3
stale-revision, policy-ceiling-stale. Historical records may retain exact old refs.
This is currentness within the explicit mock inventory, never live-current proof.
Apply the same exact delegationInputs/issuer bound check to the proposal's explicit
delegation after its approved kind/outcome/recipient/subject tests. Its issuer
restrictions additionally narrow the requester's calculations in both scopes.
No source of declared authority overrides any required role, policy or assignment.
Required coherent tests: owner-origin null; approved applicable direct delegation
with file.read permitted; rejected delegation; unrelated plan-approval/acceptance;
wrong recipient; wrong registration; unsupported scope; role allows file.change
but delegated operations/issuer paths do not; missing issuer input; active registration
pointing to an old approved decision whose newer head rejects it; reference updated
to that rejected head; and revoked registration. Each must reach its named gate.
### 10.2 Structural ownership versus consulted work access (finding 2)
Structural graph validation uses EACH record's own scope, never the global selected
project. Every task mission must belong to the task's project (project-level mission
or a workspace mission in that project). A mismatch is exit 2 invalid-request,
mission-owning-project-mismatch. Workspace mission parents must be project missions
in their own project; project missions have no parent. Dependencies may structurally
reference tasks in other scopes/projects; they confer no permission or ownership.
Unselected P2 tasks with P2 missions remain valid when the caller selects P1.
For each actual calculation context (main selection, or requester original/target):
- Consulted tasks/mission/dependency references may target the SAME workspace or
the parent project only. A different workspace of the same project is exit 3
unsupported-capability, cross-workspace-work-reference-not-modelled. Another
project is exit 3 unsupported-capability, cross-project-work-reference-not-modelled.
Apply these refusals even if that agent has another registration there. The first
slice deliberately does not model additional cross-scope visibility contexts.
Do not inspect that referenced work's status/restrictions for admission or silently
omit the reference from readiness checks. Structural existence/type checks are
distinct and operate on the supplied synthetic inventory, not live private data.
- References within the supported relation require work.read in the caller's full
applicable L1L9 intersection, as well as the requested operation. Otherwise exit 3
not-authorized, consulted-work-not-readable. The parent-project registration and
policy are already mandatory layers, as are the acting workspace restrictions.
The calculator may combine supplied mock restrictions to derive this intersection;
it returns no referenced bodies and does not claim authentic private-record access.
- Dependencies of a task used for file.change or proposal requester authority must
be accepted. Otherwise exit 3 not-authorized, dependency-not-accepted. A reference
rejected by the scope guard cannot be skipped because its status says accepted.
Taskless work.read/file.read does not traverse unrelated tasks or their dependencies.
- Apply the same reference-access rules when the proposal checks its subject/target
work: original requester context for the subject; target requester context for
the target. Dependency refs never become extra assignments or execution authority.
Tests: local workspace mission/dependency permitted with work.read; parent project
mission permitted; work.read removed while file.change remains; W1 task referring
to W2 mission or accepted dependency while agent registered only W1; same case even
with W2 registration (still unsupported in this slice); cross-project dependency;
and independent P2 task/mission inventory under a P1 selection, which must not fail
merely because it is unselected. All outputs remain body-free.
### 10.3 Direct assumptions, not hidden-chain detection (finding 3)
The model supports only the direct-declared delegationInputs form in §10.1. There is
NO claim to detect a chain concealed behind an artifact, a declaration or an omitted
record. A decision subject reference to another decision is not automatically a
parent-delegation edge. Historical subject references retain their defined meaning.
No artifact body is read and artifact presence is not authentic authority.
An input adding parentDelegationRef or another undocumented field fails the closed
shape rule: exit 2 invalid-request. A mode other than direct-declared likewise fails
shape; it is not a successfully detected hidden chain. A valid direct declaration
with opaque artifact pointers is checked as a declared assumption and cannot prove
absence of chaining. Test these three distinctions explicitly. Proposal success
remains unreachable, even when all direct simulation checks pass.
### 10.4 Fixed graph sub-order and fixture reachability (finding 4)
Global order: input bounds/lexical parsing; closed shapes/profile/supported kinds;
identity index and duplicate checks; structural reference existence/type; cycles
(task.dependencies, then mission.parentMissionRef, then supersedes); revision-chain
continuity; per-record ownership/parent-scope checks; supported operation selection;
then context binding/current-head, work-scope guards and ordered admission checks.
Within a stage use stable kind/id/scope/revision and field ordering, not input order.
Use the documented missing-declaration/current-admission exit exceptions in §7.
Schema-valid workspace mission self-parent and revision-2 self-supersedes fixtures
must hit their cycle rule BEFORE parent-scope or predecessor-continuity refusal.
Use separate detector unit tests and CLI-precedence tests. Never count an earlier
schema/ownership rejection as demonstrated cycle-detector coverage. Missing required
policy/artifact/authorization declarations are admission failures at their documented
stage, not swallowed by the ordinary-record structural missing-reference rule.
### 10.5 Differential corpus and platform boundary additions (finding 5)
Add scalar type substitution; every null-versus-absent branch; integer min/max,
boolean-versus-integer and numeric 1.0 schema cases; nested object-order-insensitive
uniqueItems comparisons; BMP/non-BMP code-point length boundaries; UTF-8 byte-path
boundaries; and escaped surrogate cases. Schema verdict and strict bundle/profile
verdict are separate expected columns. Strict bundle strings reject unpaired escaped
surrogates as profile-invalid; this is not an assertion about unformatted candidate
JSON Schema strings. A passing finite corpus is compatibility evidence, not proof
of complete schema equivalence. Actual Node versions tested must be reported.
O_RDONLY availability checks use presence/type, not truthiness: its valid value is 0.
@@ -0,0 +1,82 @@
# FI-ROCKO-4 — build admission findings before independent code review
Coordinator: darkwing. Build report SHA-256 verified:
857470d97af6aeae4e7d7942c2a1d8455bfcda74ff68b8e1dc4ba8d066521fa4.
These are coordinator admission findings, not Filbert's independent code verdict.
No new CLI/test code has been executed by darkwing in this admission check.
## C1 — resolve the advertised candidate identity mismatch
Of 35 explicit file rows checked, 34 match. Both fixture-tree manifest hashes and
counts match (185 bundles; 19 raw files). The demo file
scripts/foundation/fixtures/demo/prop-message-is-not-authority.json differs from
the report's advertised digest:
- Report: f1c6bd523cdff161e51da156fd00cfaa652d193f41541686548fc023378fd8ab
- Measured: f1c6bd523cdff161e51da156fd00cfaa652d193f41541686548cf023378fd8ab
Confirm whether this is a transcription error or unexpected file drift. Do not
silently regenerate/overwrite evidence to make a hash match. Return a corrected,
complete per-file machine-readable manifest for the next candidate, including modes.
The initial manifest-verification attempt stopped at this mismatch; it did not
produce a completed coordinator manifest. A subsequent table audit confirmed the
single mismatch above and both matching aggregate tree manifests.
## C2 — differential verification cannot silently waive disagreements
verify-schema.py:427435 accepts six KNOWN_DIVERGENCES and fails if they disappear.
The charter incorporates a required oracle where disagreements fail, separating
schema verdict from legitimate strict-profile limitations. No six-exception waiver
was requested or approved. Reporting those reproduced mismatches as PASS is not
satisfaction of that gate. The report itself identifies years 00010999 accepted
by Node but rejected by the pinned format checker, plus trailing-newline cases.
Make the shape validator and oracle faithful to the pinned contract, with strict
input/profile behavior independently verified. Do not relax safe input handling
merely to turn counts green. If a charter/source-format conflict requires a policy
choice, return a precise proposed amendment and witness; do not implement your own
waiver or change the pinned schema/checker. A finite corpus remains limited even
when it has no unapproved disagreements.
## C3 — serialized output adds a field outside the closed charter
Charter §7 lists the closed emitted result fields, with no exit field. CLI
renderJson(r) serializes the result directly; renderText(r) emits an exit line;
main uses result.exit. The report calls the result closed but describes RESULT_KEYS
from the implementation, not a check against the independent charter field list.
Keep process exit metadata separate from the serialized result, or return a proposed
charter amendment instead of changing the external contract implicitly. Add tests
whose expected output keys come from the approved contract, not solely from an
implementation-exported key list.
## C4 — before/after demo evidence must preserve the original digest
Report §9 step 2 recomputes hashes independently inside each process substitution;
both checks compare files to their own current values. That cannot establish
unchanged bytes across the operation. Preserve a before manifest in a separate
scratch location, execute the preview, then verify against that SAME manifest.
Existing suite observations may remain useful; correct the owner-demo receipt.
## C5 — report/code flag discrepancy
The report says the open flags are O_RDONLY|O_NOFOLLOW only. Actual reviewed CLI
readBundleBytes includes O_NONBLOCK and checks its numeric availability. Correct
the report; do not remove the required flag to match its prose. This finding is
about receipt accuracy, not evidence that a FIFO actually blocked.
## Authorized correction and return
First reconcile C1, then fix C2C5 only under the existing FI-ROCKO-3 source/test
allowlist. Preserve the original report; new allowed report/manifest paths are:
- docs/plans/reviews/2026-09-06_foundation-inspector-rocko-build-r2.md
- docs/plans/reviews/2026-09-06_foundation-inspector-rocko-build-manifest-r2.json
Return FI-ROCKO-4 with per-finding dispositions, exact hashes, all required tests
and any unresolved specification decision. Freeze the resulting candidate for
Filbert. No staging, commit, push, new runtime dependencies, live environment,
credential or native/sync work. The shared index remains outside this assignment.
Do not edit charter, existing schemas, prior verdicts or coordinator records.
Transport (2026-09-06 18:17 UTC): FI-ROCKO-4 sent once to =rocko/mosaic-fleet;
exit 0, delivered. Await corrected manifest/test receipts or spec blocker.
Follow-up darkwing; no timer or automatic acceptance.
@@ -0,0 +1,270 @@
# Foundation synthetic inspector — frozen charter candidate 2
Issue: #53. Author/integrator: darkwing. Feasibility contributor: rocko.
Independent reviewer: filbert, pending exact-candidate review.
Status: proposed implementation contract, NOT permission to implement.
Jason authorized continuation of planning after accepting the reviewed map.
No source changes, migration, publication, push or live fleet activity authorized.
## 1. Bound inputs and interpretation
Accepted map/handoff: commit 7345f330fc6bfae5aa1d896c78cfb7cbe62efbae.
Source/plan baseline: d4696d09eb1b5dcf1028f30db2cd63735f51cb16.
Map verdict: FM-FILBERT-1, SHA-256
6b08c6fac0718d3db527cf9ffbfab49407e7b289d09782f5d1d0e26493eaabb3.
That approval does not cover this new charter.
Detailed incorporated specification: sections 513 of
reviews/2026-09-06_foundation-inspector-rocko-feasibility-r2.md,
SHA-256 f2f47fcfe22dca79f10f885b83d87a2f846fdb560425a4e20705c40ce4a123e1.
The explicit corrections/decisions below override that note. Its other sections
are contributor rationale/history, not normative repository facts. Original r1
and the FI-ROCKO-2 corrections remain history, not alternate specifications.
Any ambiguity or contradiction discovered at implementation is a charter defect
to resolve, not permission for a coder to guess or weaken refusal rules.
Candidate records.schema.json SHA-256:
05774aaf6943cb69c113e39ff1c29676a2a230ca7bf665c50dbcaa8049672af6.
Candidate check.py SHA-256:
82564a7d3200afcdda0850a9454cac6e6cd6a76687d2162c13cf214d7eac4607.
Both resolve under docs/plans/foundation-v1-candidate at d4696d09.
## 2. Deliverable and non-goals
One local CLI over an explicitly supplied synthetic bundle, with deterministic
text and JSON previews of selected agent/project/workspace permission. No cwd
inference of scope, live registry, config bootstrap, account lookup, engine launch,
assignment mutation or real permission grant. Every result, including parser/I/O
failures, says SYNTHETIC PREVIEW — NO LIVE EFFECTS and authentication: not-modelled.
Implemented operations: work.read (null target), file.read/file.change (logical
workspace-relative target), and assignment.change as a negative/unresolved check
only. The other 25 known catalog names return unsupported-capability, exit 2.
Unknown names return invalid-request, exit 2. No assignment-change success path.
No execution.stop operation is invented; the catalog contains execution.control.
No general RPC, sandbox, authentication, command audit, stopping, durability,
legacy adoption, OAuth refresh or extension integration is delivered.
Operator supplies synthetic files only. The CLI reads just that explicit input,
never discovers credentials/config. It cannot know whether arbitrary operator-
selected file bytes contain secrets before reading them; this is not a general
credential-read prevention boundary. Never pass credentials or live records to it.
Tests and agents are not authorized to access such files.
## 3. Input, identity and graph rules
Use the closed bundle/selection/registry/artifact/authorization shapes in r2 §5,
subject to the proposal and output overrides below. All fields shown there are
required except message. proposal is explicitly null outside assignment.change;
assignment.change requires non-null proposal and null operation.target. The
subjectAssignmentRef must exactly equal selection.assignmentRef; selection agent,
project and workspace must match that assignment. Never infer a different subject.
Eight supported record kinds: agent-definition, project, workspace, registration,
mission, task, assignment and decision. Other candidate kinds refuse unsupported-
kind. Candidate record shapes remain unchanged; simulation-specific fields exist
only in the enclosing bundle, never appended to accepted records.
Record references are kind/id/scope/revision, WITHOUT digest. Registry references
include registry/id/revision/digest. Artifact references and authorization IDs
match declared simulation inputs; their presence proves neither publication
permission, authentication, authentic evidence nor current real-world authority.
Decision approvals are evaluated as synthetic fixture facts, not verified signatures.
Missing declarations refuse; no flag can turn them into actual authenticated facts.
Reject duplicate record identities, duplicate registry identities even with different
digests, duplicate artifact identities (runId/artifactId) even with different digests,
and duplicate authorization IDs. Do not choose one of ambiguous registrations:
more than one current active registration for the same agent/scope refuses ambiguity.
Revision rules: complete contiguous history from 1, or a single revision-1 record.
Structural references on every revision must resolve. Apply head/current-admission
checks only to head records used for this calculation and their consulted chain;
historical records do not fail merely because their then-current refs are now old.
Explicit historical supersedes/decision subject references may name existing old
revisions. Current selected intent/task/mission/registration/delegation/proposal
refs must name heads; no invented predecessor, repair or fallback.
Cycle checks cover task.dependencies, mission.parentMissionRef and supersedes as
separate edge relations. Before tests are counted, show that each fixture reaches
the intended rule rather than failing an earlier shape error. Workspace ownership,
mission parent scope and registration parent match the accepted schema/README.
Dependencies grant no ownership/access. A selected task's same-project dependencies
must be accepted to permit file.change; another project's dependency never lends
permission. Broader dependency execution semantics are unsupported in this slice.
## 4. Mandatory policy and assignment calculation
Adopt r2 §7 L1L9: enabled agent ceiling, both active registrations each bounded by
its mandatory scope-role ceiling, required project and workspace policy, exact
assignment/task/intent checks, applicable task/mission narrowing and an explicit
simulation execution layer. Workspace policy never falls back to a scope role.
Null optional restrictions mean no additional narrowing; missing required ceiling
never means unrestricted. Empty operations/path grants mean none. Exactly one
selected assignment contributes; no union across assignments.
Selected project/workspace must be active. Assignment is selected, belongs to the
selected agent and workspace, and binds the selected task. Task is ready/active,
with approved current plan-approval intent whose subjects include that exact task.
Assignment intent is an approved current plan-approval, delegation or assignment-
change decision covering the task/assignment. An unrelated approved acceptance
or owner-checkpoint decision is not a substitute. Mission chain must be active.
Taskless work.read/file.read skips assignment/task/mission only when assignmentRef
is explicitly null. Supplying an invalid assignment never falls back to taskless.
Paths use logical workspace roots and component-prefix intersection, never raw
string prefixes or physical filesystem traversal. Network restrictions are parsed
and intersected but no network operation is implemented or performed.
## 5. Reassignment negative check — tightened requester context
Extend r2 §5 proposal with required requesterContexts, a closed object:
- original: {assignmentRef, execution}
- target: {assignmentRef, execution}
Each assignmentRef is non-null recordRef; execution uses the same mandatory
selection.execution shape. No extra keys. Original scope derives from the subject
assignment; target scope derives from targetTaskRef. Both requester contexts belong
to requesterAgentId and the corresponding scope, not the subject agent.
Apply L1L9 to the requester in BOTH scopes for assignment.change, using those
contexts. Role membership alone is insufficient; task/mission/intent and execution
limits also narrow the request. Require original subject and target task current
intent/status checks. Apply r2 §8 recipient/subject-bounded delegation and recorded
change checks, with approved outcomes and exact current references. Artifact basis
is evidence only. Unmodelled delegation chains refuse unsupported-capability.
No message authorizes a change. Missing delegation with a message yields the
message-is-not-authority rule once structural validation succeeds. Other failures
use fixed deterministic original-scope, target-scope, delegation, change, intent
ordering. If all simulation checks pass, return unresolved/unknown-effects with
runtime-reconciliation-required, NOT allowed. No supplied runtime observations
field exists. Echo the original selection unchanged on every admitted proposal.
This is a negative preview, not a real assignment engine or proof of stopping.
## 6. Canonicalization and precise limits
Adopt separately named inspector-content-digest/1 for mock registry content only:
sorted keys, compact encoding, ASCII string domain, safe integer values, array order
preserved. No launch fingerprint or full JCS claim. V1V3 in r2 were independently
recomputed and match. Use 1.5 (not 1.0) for the nonintegral-number V4 test: JavaScript
cannot distinguish numeric 1.0 from 1 after parsing. Reject negative zero and unsafe
integer values. Strict bundle number tokens use integer notation only: reject
fraction/exponent forms and negative zero, bound integer tokens exactly before
Number conversion. This prevents precision loss from hiding unsupported values.
This lexical restriction is an inspector profile rule, not a change to candidate
JSON Schema integer semantics; the differential record validator tests shapes
separately from this strict-input profile.
Non-ASCII mock content refuses unsupported-capability; candidate record and target
paths still use the candidate Unicode/path formats. Validation tests separate schema
validity from the stricter inspector input/canonicalization domain.
Bounds: file <=1 MiB; each top-level inventory <=256; arrays <=1024; nesting <=32;
strings <=4096 UTF-8 bytes subject to stricter candidate limits. Duplicate JSON keys,
malformed UTF-8, invalid calendar dates, forbidden path characters/segments and
unknown fields refuse. Parser object construction must not invoke prototype setters;
__proto__/constructor keys are ordinary unknown keys, never executable behavior.
Never normalize an invalid path into a permitted one.
Linux input open: require available O_RDONLY, O_NOFOLLOW and O_NONBLOCK; open the
final component without following its symlink, fstat regular type and bounded size,
read within limit with an extra-byte/truncation check, close in finally. Parent-path
containment is NOT claimed. Missing/symlink/FIFO/nonregular input refuses exit 4.
Do not OR an undefined O_CLOEXEC constant: host Node v26.8.1 exposes none (measured).
No child spawning or close-on-exec guarantee is claimed. The CLI itself never spawns;
verification harness processes are separate test effects. Same-size concurrent file
mutation is not ruled out by size checks: operator/test inputs must remain quiescent.
## 7. Output and exits — replaces r2 §9 shape
Closed result fields, emitted on every outcome:
- disclaimer: fixed SYNTHETIC PREVIEW — NO LIVE EFFECTS
- preview: fixed preview: no live registrations or permission grants
- bundleVersion: 1
- authentication: fixed not-modelled
- declarations: fixed unverified-simulation
- result: allowed | refused | unresolved | invalid
- reason: allowed | invalid-request | missing-state | stale-revision |
not-authorized | unsupported-capability | unsupported-kind | unknown-effects | io-failure
- rule: fixed documented rule identifier or null; never input-derived prose
- selection: null before safe structural validation, otherwise exactly the selected
{agentId, projectId, workspaceId, assignmentRef} supplied by the caller
- operation: null before safe validation, otherwise the validated {name, target}
- proposal: null outside a valid assignment.change input, otherwise
{result, reason, rule, selectedAssignmentRef}, with no allowed result
- diagnostic: null or {byteOffset, inputPath}, each member nullable; offset only for
parse failure, original argv path only for I/O failure, never file contents
No consulted inventory, global counts, unrelated identities/payloads or raw parser
messages. Text and JSON derive from the same result. JSON is ordinary valid JSON
with the disclaimer field, not a non-JSON preamble. Text escapes control characters
in echoed arguments/targets so diagnostics cannot inject terminal controls.
No time/random data. No output claims authentic publication or real grants.
Exits: 0 permitted permission preview; 2 malformed/structurally incoherent or
unsupported input; 3 simulated permission refusal or unresolved admission; 4 I/O.
Missing required JSON keys (including execution) are structural: 2 invalid-request.
Absent referenced ordinary records are incoherent: 2 missing-state. Absent declared
mandatory policy/artifact/authorization inputs: 3 missing-state. Existing historical
reference used for current admission: 3 stale-revision. Cycles/duplicates: 2 invalid-
request. These override inconsistent example exits in r2. Refusal is never repaired.
## 8. Physical paths, toolchain and verification
Proposed implementation allowlist only:
- scripts/foundation-inspect.mjs (CLI; eventual packages/mosaic)
- scripts/foundation/{strict-json,canonical,resolve}.mjs (pure; eventual packages/config)
- scripts/foundation/validate-record.mjs (test-only differential bridge)
- scripts/foundation/verify-schema.py (verification only)
- scripts/foundation/*.test.mjs and scripts/foundation/fixtures/**
- scripts/test-foundation.sh
This is not yet a code-write authorization. No root/package-manager files, packages/
scaffolds, duplicate runtime sources, .pi/extensions, Dewey scripts, roles or config
changes. Pure modules never import live config, filesystem/process/network APIs or
read environment/clock. CLI handles input/output only, with no ambient config lookup.
Node ESM, zero new runtime dependencies. Record exact tested Node version; proposed
minimum 22 is not evidence of testing every supported version. Host measured 26.8.1;
container source uses node:24-bookworm-slim, not the first CLI's test environment.
No new repository engines pin is inferred. No automatic installation.
Mandatory verification uses existing explicitly selected Python/jsonschema 4.26.0,
checking pinned schema/checker hashes first. Missing dependency fails, never skips.
The differential bridge compares field-level validation over supported candidate
fixtures plus deterministic mutations, not invocation of check.py as a library.
Keep record-schema verdict distinct from unsupported-kind/profile/graph refusal.
Use calendar/path format semantics from the pinned checker, not string-only tests.
Unit/CLI tests cover r2 §12 with these overrides. Separate observed fixture/home/cwd/
data-root roots from harness output. Compare before/after path/type/size/mode/owner/
inode/content inventories; canaries and static import checks are bounded evidence,
not a sandbox or proof of no reads. No native synchronization or live fleet tests.
Required five repository suites and foundation author checks must remain green.
## 9. Acceptance and gates
A1. Positive read and assigned file.change permission previews with coherent records;
deterministic text/JSON, explicit disclaimers and no effects.
A2. Unregistered second workspace/cross-project selection refuses without fallback
or unrelated payload disclosure.
A3. Ownership/reference/duplicate/revision/cycle negatives hit the intended rules.
A4. Required role ceilings and all applicable layers narrow; empty/missing authority,
cross-assignment union and unassigned change refuse.
A5. Encoding, duplicate keys, calendar, path, bounds and unknown-field tests refuse
safely with the documented schema/profile distinction.
A6. Input/observed roots unchanged; no bootstrap, ambient config/credential lookup,
engine, network, installation or migration action.
A7. Cross-lane proposal preserves original selection; requester limits in both
scopes enforced; even fully supplied mock evidence cannot yield allowed.
A8. All output/exit combinations match the closed result contract, including parse
and I/O failure. No raw contents, unrelated metadata or terminal injection.
A9. Jason runs the positive and negative demo and understands the limitation before
any dependent live-registry/runtime increment begins.
First: Filbert independently reviews the frozen charter and incorporated note at
exact hashes without authorship or edits. Resolve substantive findings as a new
candidate. Then present the reviewed build scope to Jason for implementation
approval; prior map acceptance does not supply it. After authorized implementation,
retain separate author/reviewer roles, serialize shared index use, run all required
checks and obtain owner demo acceptance before dependent work. No automatic push,
issue closure, implementation or next-phase advancement follows from this charter.
@@ -0,0 +1,65 @@
# Synthetic inspector code-review and owner-demo gates
Coordinator: darkwing. Code writer: rocko. Independent reviewer: filbert.
Task: FI-ROCKO-3. Status: checklist prepared; no code candidate received or approved.
Charter identity: 19b6721128a627a2032ffdb95ece2d50abe69a8f6d521e9eff8bbdaff22798b6.
This is verification preparation under the authorized build, not another specification.
## Candidate admission
- Receive exact path list, file hashes, integration HEAD and test receipts.
- Verify charter/note/schema identities and compare every changed path with the
approved allowlist. Preserve Dewey's changes; never blanket-stage or reset.
- Inspect source and test commands before executing the new code. No native/sync,
credential, live-state or network experiments. A temporary HOME alone is not an
OS sandbox; apply the charter's explicit bounded-evidence qualifications.
- Freeze a content-hash manifest for the full code/fixture/test candidate. Do not
call moving work independently reviewed. Recheck Filbert's assignment compatibility
and non-authorship before the full review request.
## Required review evidence by acceptance group
| Group | Evidence required, not just a green aggregate |
|---|---|
| A1 | Coherent positive read and assigned-change previews; exact text/JSON outputs, disclaimers, no physical change |
| A2 | Missing workspace registration and cross-project selection refusals; no fallback or unrelated payload output |
| A3 | Named first-failure results for duplicate/reference/ownership/revision/cycle fixtures; detector and CLI coverage distinct |
| A4 | All mandatory ceilings and optional restrictions; role/issuer/delegated-operation narrowing; no cross-assignment union |
| A5 | Strict parser and separate schema/profile corpus: duplicate keys, numeric tokens, type/null/bounds/Unicode/calendar/path cases |
| A6 | Static import/I/O inspection, descriptor checks, fixture/observed-root inventory comparison, no ambient bootstrap or live lookup |
| A7 | Both requester contexts and intent/delegation checks; direct-assumption limits; original selection preserved; allowed reassignment unreachable |
| A8 | Every output/exit class including pre-validation and I/O errors; body-free diagnostics, escaped terminal data, stable ordering |
Oracle verification must be mandatory, version-recorded and pinned to the accepted
schema/checker. Missing dependency is a blocker, never a skip. Compare schema shape
validity separately from profile/unsupported-kind/graph/admission outcomes.
Run the foundation checker and all five repository suites against the measured
integration candidate, reporting unrelated concurrent changes separately. Existing
charter-review shape probes are not code tests. No raw test counts substitute for
coverage of the named failure paths. Finite tests do not prove complete schema
conformance, absence of all reads, containment, authentic delegation or crash safety.
## Independent verdict
Filbert must receive the exact candidate manifest, source baseline, charter/note
hashes, writer receipts and this checklist. He returns an independent verdict with
findings, actual commands/results and untested limits. Darkwing reconciles findings;
Rocko alone fixes owned code, then a newly hashed candidate is re-reviewed.
Neither writer nor coordinator substitutes for the independent verdict.
## Owner demo (A9), only after verified code
Use only the delivered coherent synthetic examples and actual verified CLI syntax:
1. Show the selected agent/project/workspace and a permitted read preview.
2. Show an assigned file-change permission preview; demonstrate no file was changed.
3. Select the unregistered workspace and show a refusal without fallback.
4. Preview cross-lane reassignment: the original assignment remains selected and
even fully supplied mock declarations cannot produce a real change or allowed result.
5. Ask Jason whether the selection/refusal display and no-live-effects disclaimer
are clear, and whether he accepts this increment. Record his answer separately.
Do not invent demo commands before the writer returns the implemented interface.
No dependent live-registry/runtime increment starts before Jason's acceptance.
No push, migration or issue closure follows automatically. Shared-index/commit
coordination remains separate from code delivery and reviewer approval.
@@ -0,0 +1,83 @@
# FI-FILBERT-6 — full independent inspector CODE review
Owner authorized Rocko's implementation, Filbert's independent code review and a
later owner demo. Author: rocko. Coordinator/follow-up: darkwing. Reviewer: filbert.
Check current assignment compatibility and confirm no code authorship; do not
replace another owner assignment. Earlier charter/addendum review is not code review.
## Exact frozen candidate
Repository: /home/jwoltje/src/mosaic-stack-dev-test
Integration HEAD: 9a5fbdbda74b16adf488fe28138b2ba69ea5e669
Pinned source/schema baseline: d4696d09eb1b5dcf1028f30db2cd63735f51cb16
Accepted map: 7345f330fc6bfae5aa1d896c78cfb7cbe62efbae
Code is uncommitted and bound by the machine-generated manifest, not falsely
claimed to exist at the integration HEAD:
- docs/plans/reviews/2026-09-06_foundation-inspector-rocko-build-manifest-r3.json
SHA-256 3c2253b6c9f31e448c77aaac53977d41baecfb30e15845dcfffd8dc694428547
- docs/plans/reviews/2026-09-06_foundation-inspector-rocko-build-r3.md
SHA-256 ec0444c94c9caf16472fdba1ff3fbc767dffd1a798b9a2da837598c9f4b25508
Coordinator verified all 294 files, exact allowlist/no extra implementation files,
file modes/sizes/hashes, aggregates, pinned inputs and measured HEAD. This is identity
verification, not independent execution of the writer's tests.
Governing charter: docs/plans/2026-09-06_foundation-inspector-charter.md
SHA-256 19b6721128a627a2032ffdb95ece2d50abe69a8f6d521e9eff8bbdaff22798b6
Reviewed addendum: reviews/2026-09-06_foundation-inspector-pattern-profile-addendum.md
SHA-256 afe2980be2f91e701dae5af3018831ac5c300474f52bcc06e740ce5b5cc68ca5
Its verdict: reviews/2026-09-06_foundation-inspector-pattern-profile-verdict.md
SHA-256 03c979b77cc6b03b6685ba51ed1ce24c3f1d7b274ce8f772263a103670050da7
Incorporated Rocko r2 feasibility hash: f2f47fcfe22dca79f10f885b83d87a2f846fdb560425a4e20705c40ce4a123e1.
Review gates: docs/plans/reviews/2026-09-06_foundation-inspector-code-review-gates.md.
## Required scope
Review ALL implementation/CLI/parser/canonicalizer/validator/resolver paths and
the oracle, generators, tests and evidence—not only the last regex fix. Compare
against the independent charter/addendum, not just code-exported constants or
writer-selected fixture expectations. Verify A1A8 and §§10.110.5. Challenge
claim/reference/history/scoped registration/issuer/task/mission/intent/execution
intersections, proposal branches and identity/privacy handling.
Specifically verify genuine schema compatibility and strict production profile
before graph admission, with zero schema disagreements and no waiver/normalization.
Check all typed occurrences, positive free-text controls and pre-validation nulls.
Confirm no reassignment success branch, extra serialized fields or tautological
before/after evidence checks. Revisit prior admission findings C1C5 against r3,
not the earlier red candidates. Their original reports remain historical.
Inspect source/test commands before executing new code. Run relevant checks in a
disposable isolated export containing only pinned required baseline inputs, exact
candidate files and bound planning inputs; hash those copies before execution.
Do not run fixture regeneration against the frozen shared tree. Use synthetic
HOME/cwd/data only. A temporary HOME alone is not OS containment; report actual
limits. No credentials, live data, native/sync/installation or ~/.mosaic tests.
No dependency installation or implicit network. Stop rather than improvise around
an unavailable verification dependency or suspicious out-of-scope effect.
Writer reports: 63 Node tests, 43 selftest checks, oracle 1539-record corpus with
zero schema disagreements and independent profile refusals, foundation checker and
five repository suites green. These are writer receipts until independently rerun.
Record your actual commands, versions, exit codes, output and unexecuted limits.
## Verdict and write boundary
Only allowed repository write:
docs/plans/reviews/2026-09-06_foundation-inspector-code-verdict.md.
Do not fix/co-author code, mutate fixtures/charter, edit shared logs/CURRENT, stage,
commit, checkout/reset or push. Any test/reproduction scratch must remain isolated.
Return FI-FILBERT-6 APPROVED/NOT APPROVED for the exact manifest and contract hashes,
with numbered blocking/nonblocking findings, source locations, concrete witnesses,
required corrections, acceptance dispositions and independently measured limits.
Include verdict SHA-256. Recheck candidate identities before verdict; drift blocks
approval. If assignment compatibility fails, return a blocker instead of retasking.
No owner-demo, runtime security, real permission grant or full Archify acceptance
is implied by code review. No dependent work starts automatically. Direct tagged
reply is the return mechanism; follow-up darkwing; no deadline or automatic timer.
Transport (2026-09-06 21:30 UTC): FI-FILBERT-6 sent once to =filbert/default, exit 2,
unconfirmed. Follow-up darkwing; reconcile the declared verdict artifact and direct
reply on next invocation. No timer, blind retry or automatic approval.
@@ -0,0 +1,311 @@
# FI-FILBERT-6 — independent CODE verdict: NOT APPROVED
Reviewer: filbert. Author: rocko. Coordinator/follow-up: darkwing.
Date: 2026-09-06. Authority: the exact FI-FILBERT-6 request under Jason's authorization.
No competing assignment is known. I have not authored the implementation. This is
review of the full frozen inspector candidate, not just the regex correction.
The supplied tests pass, but independent adversarial CLI witnesses expose failures
of reference completeness, work-access narrowing, revision handling and specified
first-failure ordering. No real permission grant or runtime exploit is claimed.
## 1. Exact subject and admission
| Input | SHA-256 / commit |
|---|---|
| `2026-09-06_foundation-inspector-rocko-build-manifest-r3.json` | `3c2253b6c9f31e448c77aaac53977d41baecfb30e15845dcfffd8dc694428547` |
| `2026-09-06_foundation-inspector-rocko-build-r3.md` | `ec0444c94c9caf16472fdba1ff3fbc767dffd1a798b9a2da837598c9f4b25508` |
| Charter candidate 3 | `19b6721128a627a2032ffdb95ece2d50abe69a8f6d521e9eff8bbdaff22798b6` |
| Incorporated feasibility r2, §§513 subject to overrides | `f2f47fcfe22dca79f10f885b83d87a2f846fdb560425a4e20705c40ce4a123e1` |
| Pattern/profile addendum | `afe2980be2f91e701dae5af3018831ac5c300474f52bcc06e740ce5b5cc68ca5` |
| Addendum verdict | `03c979b77cc6b03b6685ba51ed1ce24c3f1d7b274ce8f772263a103670050da7` |
| `records.schema.json` | `05774aaf6943cb69c113e39ff1c29676a2a230ca7bf665c50dbcaa8049672af6` |
| `check.py` | `82564a7d3200afcdda0850a9454cac6e6cd6a76687d2162c13cf214d7eac4607` |
| Source/schema baseline | `d4696d09eb1b5dcf1028f30db2cd63735f51cb16` |
| Accepted map | `7345f330fc6bfae5aa1d896c78cfb7cbe62efbae` |
| Measured integration HEAD | `9a5fbdbda74b16adf488fe28138b2ba69ea5e669` |
Report/manifest paths above are under `docs/plans/reviews/`. Code is uncommitted;
HEAD alone is not its identity. I independently verified all 294 distinct regular
files, modes, sizes, hashes, the exact implementation allowlist with no extras,
all six aggregates and every pinned input before execution. Source baseline
package bytes were exported from the committed baseline, not mutable extensions.
Final recheck at **2026-09-06T21:49:22Z** verified the same identities in both the
shared tree and isolated export, and the same HEAD. No candidate drift found.
The all-candidate aggregate is
`e5f9039cf4614e8acc3f6c6a71f0a03dbc1c29002703029180d1ccef5757979c`.
## 2. Numbered findings and required dispositions
All source locations below refer to the frozen `scripts/foundation/resolve.mjs`
(SHA-256 `eaa4a419618328915cd470ba192a88b8d313ee8fa48f600289ffe39df15280b2`)
unless another file is named. Witnesses use copies of the frozen demos; no shared
fixture was edited. `B` means `fixtures/demo/demo-file-change-src.json`; `P` means
`fixtures/demo/demo-change-w1.json`, under `scripts/foundation/`.
### F1 — BLOCKING / high: referenced declarations are incompletely enforced
Locations: `checkStructuralReferences`, lines 10431083; `computeContext`,
13241347 and 14031407; declaration helpers at 1213 onward.
Contract: charter §3 and incorporated r2 §6.2 require exact registry-reference
resolution and declared authorization inputs; charter §§7/10.4 preserve the
special admission-stage missing-declaration exits.
Two independent witnesses:
- From B, remove registry declarations whose registry is `harness`, `settings`
or `context-content`, leaving the agent's references intact. Actual: **exit 0,
allowed**. These references are shape-checked but never resolved.
- From B, set `task-w1-dep.authorizationRef` to the undeclared, well-formed UUID
`00000000-0000-4000-8000-000000000099`. Actual: **exit 0, allowed**. The dependency
is consulted and its accepted status used, but its authorization is not checked.
Required result is a missing-state refusal, not an allowed preview; the
authorization case has the charter's exit-3 admission exception.
Required correction: enforce the applicable exact declaration checks, including
consulted dependencies, without turning missing declarations into unrestricted
facts or swallowing their documented admission exits. Add independent negatives
for absence and mismatched references, not just missing policy ceilings.
### F2 — BLOCKING / high: task-only contexts evade required `work.read`
Locations: `computeContext` lines 13541356, 13851417;
`checkWorkAccess` lines 14261434.
Contract: charter §10.2 requires work.read for consulted task references within
the supported workspace/project relation, in the full applicable intersection.
- From B, clear the selected task's `missionRef` and `dependencies`. Set execution
restrictions to operations `["file.change"]`, readPaths `[]`, writePaths
`[{"root":"workspace","path":null}]`, network `none`, endpointRefs `[]`.
Actual: **exit 0, allowed**, despite consulting the assigned task without
work.read. The boolean `consultedWork` is set only for missions/dependencies,
not the task bound by the assignment.
- From P, clear every task's mission/dependency references and set both requester
execution restrictions to operations `["assignment.change"]`, empty paths,
network `none`, no endpoints. Actual: **exit 3, unresolved /
runtime-reconciliation-required**, rather than consulted-work-not-readable.
`checkWorkAccess` similarly conditions work.read on the task having other refs.
Required correction: distinguish genuinely taskless reads from calculations
which consult a task. Require work.read for the latter, including proposal
subject/target work, even when that task has no mission or dependency.
### F3 — BLOCKING / high: proposal issuer narrowing does not recheck work access
Locations: `evaluateProposal`, lines 15041535 and 15551563.
Contract: charter §10.1 says the explicit delegation issuer's restrictions
additionally narrow the requester calculations in **both** scopes; §10.2 requires
work.read in that full intersection.
From P, change only `delegationInputs[0].issuerCeiling.operations` to
`["assignment.change"]`. Its delegated operation remains within the issuer ceiling,
but the resulting intersection excludes work.read. Original subject work includes
mission/dependency references, so this case does not depend on F2's task-only edge.
Actual: **exit 3, unresolved / runtime-reconciliation-required**.
The code checks work access before applying the issuer, then checks only
assignment.change against the narrowed layers. Required correction: enforce all
applicable access conditions against the issuer-narrowed contexts, with coherent
negative coverage in both scopes. An unresolved preview must not falsely claim
that all modeled checks passed.
### F4 — BLOCKING / medium: cycle construction merges distinct historical revisions
Location: `checkCycles`, lines 10871109.
Contract: exact four-field references, contiguous history, and separate edge
relations in charter §3 / §10.4 and incorporated r2 §6.26.3.
The dependency graph keys tasks by identity **without revision** and unions edges
from every historical record. Independent witness:
- Keep B's revision-1 history: T1 (`task-w1`) depends on D1 (`task-w1-dep`).
- Add contiguous T2 with no dependencies, and D2 depending on T2.
- Add revision 2 of the selected assignment and the two relevant plan decisions;
bind the assignment/selection and plan subjects to the new exact revisions.
Each new record supersedes its own revision 1. All old references still exist.
All records pass the pinned schema/formats. Independent exact-reference DFS finds
**no cycle** in dependencies, mission parents or supersedes, and independently
asserts contiguous histories. The selected current task T2 has no dependencies.
Actual CLI: **exit 2, invalid-request / dependency-cycle** because the implementation
constructs the different graph T→D→T by discarding revision distinctions.
Required correction: do not infer cycles by unioning temporally distinct edges.
Preserve the approved exact-reference/history semantics and required cycle-before-
continuity precedence. If a stronger, identity-wide historical prohibition is
intended, obtain an explicit contract ruling instead of silently adding it.
### F5 — BLOCKING / medium: specified first-failure ordering is not preserved
Locations: `validateBundleShapeScoped`, approximately 719733 (before Model's
record sort at 988); `evaluateProposal`, 15041541.
Contract: charter §10.4 requires stable kind/id/scope/revision/field ordering within
a stage, not inventory input order; §5 gives missing delegation plus message its
named rule after structural validation.
1. From B, set `agent-a.payload.status` to an invalid enum and add an unknown
`extra` field to `agent-b.payload`. Forward record inventory yields
**exit 2 / shape-enum-mismatch**. Reverse only the top-level record array:
**exit 2 / shape-unknown-field**. Both identities remain well-formed. Validation
returns the first array member's error before the later stable sorting applies.
2. From P, set delegationRef null, supply a synthetic message, and restrict original
requester execution to work.read only. Structural validation succeeds. Actual:
**exit 3 / operation-not-permitted**, proposal rule
`requester-lacks-original-scope-authority`, rather than `message-is-not-authority`.
The special message check is deferred until after requester admission.
Required correction: implement the frozen first-failure contract and add independent
multi-failure/permutation tests. If message precedence is meant differently, darkwing
must reconcile the explicit §5 exception; the writer must not guess an override.
### F6 — NONBLOCKING evidence improvement: writer inventories omit ownership
`cli.test.mjs:3139` and `test-foundation.sh:123` inventory path/type/size/mode/
inode/mtime/content, but omit UID/GID despite charter §8 naming ownership.
My separate 15-run inventory includes UID/GID and passes (see §4), so this is not
an observed owner change or an additional code rejection. Preserve ownership
coverage in the maintained regression harness rather than relying on this review's
one-off receipt.
## 3. Acceptance and historical-finding dispositions
| Gate | Independent disposition |
|---|---|
| A1 | Positive text/JSON read and assigned-change demos pass exact-output tests; disclaimers present; bounded no-effect observation passes. Does not rescue F1/F2's additional false-positive cases. |
| A2 | Named missing-workspace-registration/cross-project fixtures pass; no fallback or unrelated payload emission observed. |
| A3 | Supplied duplicate/reference/ownership/revision/cycle negatives pass, including separate detector and CLI-precedence tests. **Not satisfied generally: F1/F4.** |
| A4 | Supplied role, mandatory policy, optional task/mission/execution, registration-delegation, path-prefix and no-assignment-union tests pass. **Not satisfied: F1F3.** |
| A5 | Strict-parser, bounded canonical domain, separate pinned schema/profile oracle and production LF refusals pass the tested finite domains. |
| A6 | Static runtime import/I/O review and independent descriptor/non-effect tests pass within stated limits; see F6. No OS-containment claim. |
| A7 | No allowed reassignment branch found; original selection is preserved and supplied requester negatives pass. **Not satisfied: F2/F3 and F5's proposal ordering.** |
| A8 | Closed fields, exits 0/2/3/4, parser/I/O diagnostics, escaping and body-free outputs pass supplied tests. **Not fully satisfied: F5.** |
| Required integration verification | Foundation checker independently green. **Five repository suites not independently rerun; writer receipts only. Gate remains uncleared.** |
| A9 | Not performed; Jason's demo/acceptance remains separate and cannot proceed as an accepted-code gate from this verdict. |
Prior admission findings against the older candidates:
- **C1 closed for r3 identity.** The corrected message-demo digest is
`f1c6bd523cdff161e51da156fd00cfaa652d193f41541686548cf023378fd8ab`;
manifest and demo-copy equality verify. I do not independently attest the writer's
historical scratch timestamps or reconstruct authorship of the original typo.
- **C2 closed for the tested r3 corpus/profile implementation.** The actual Node
schema column agrees with pinned Python; no disagreement waiver or copied oracle
answer supplies the Node result. Strict production validation remains separate,
rejects rather than normalizes identities, and precedes graph admission.
Original four LF witnesses remain, as do the low-year calendar witnesses.
- **C3 closed.** Exactly the twelve charter result fields; process exit is separate.
Contract-derived assertions and spawned outputs pass, including pre-validation.
- **C4 closed as bounded evidence.** Before inventories are captured before runs
and compared afterwards, not regenerated as the expected baseline. My separate
ownership-inclusive observation confirms the measured result.
- **C5 closed.** Actual CLI requires O_RDONLY/O_NOFOLLOW/O_NONBLOCK, including the
valid zero-valued O_RDONLY; FIFO refusal passes. No O_CLOEXEC claim is made.
## 4. Independent commands, receipts and reproducibility
Isolated candidate export: `/tmp/fi-filbert-6.42ru903e`.
Separate harness/evidence root: `/tmp/fi-filbert-6.42ru903e-evidence`.
Source/test commands were inspected before execution. Candidate fixture generation
ran only into the suite's disposable scratch, never the shared frozen tree.
Measured toolchain: Node **v26.8.1**, Python **3.12.8**, jsonschema **4.26.0**.
The pinned low-year platform witness is `strftime('%Y', year 999) == '999'`.
From the isolated export, the following commands each exited **0**, under `env -i`
with PATH `/home/jwoltje/.pyenv/versions/3.12.8/bin:/usr/bin:/bin`, synthetic HOME
and TMPDIR beneath the evidence root, `PYTHONDONTWRITEBYTECODE=1`, `NO_COLOR=1`:
| Command | Actual result |
|---|---|
| `node --test scripts/foundation/` | 63 tests, 63 pass, 0 fail, 0 skipped |
| `python3 scripts/foundation/verify-schema.py` | 3 pins match; 38 pinned fixtures; 1539 corpus records; 519 agree-valid / 983 agree-invalid / **0 disagreements**; 27 parser-only; 10 unsupported-kind unassessed; 489 profile-valid / 30 profile-invalid among schema-valid records; 73 named probes verified |
| `bash scripts/test-foundation.sh` | 43 passed, 0 failed; scratch regeneration equality, suites/oracle, goldens, I/O and non-effect checks |
| `python3 docs/plans/foundation-v1-candidate/check.py` | Exit 0: command 38+5, records 38, paths 16, restricted fingerprints 7, runtime/artifact 155+5, synthetic semantic model 35; not runtime enforcement |
Additional independent harnesses in the evidence root:
- `python3 reproduce.py` and `python3 additional-probes.py`: exact CLI witnesses
described above, plus the allowed B positive control. Captured result JSON and
input hashes are in `witnesses/`; all CLI stderr was empty.
- `python3 witness-validation.py`: 390 record-shape checks across exploratory and
finding witnesses pass using the pinned schema and independently redeclared
checker formats. The intentional shape-order negatives are excluded. Also checks
exact graph acyclicity and complete histories for F4; exit 0.
- `python3 profile-probes.py`: **831** independently enumerated typed-identity
occurrences/probes across B/P and a non-null agent execution-ID control. Each
single-final-LF mutation gives exit 2, invalid-request/profile-pattern-mismatch,
with selection/operation/proposal/diagnostic all null. A multiline mission
objective remains allowed. This extends, not replaces, the supplied record oracle.
- `python3 non-effect.py`: 15 independent text/JSON, parser, missing-file,
final-symlink, FIFO and usage runs. All expected exits pass. **16 inventory
entries unchanged**, including path/type/size/mode/UID/GID/inode/mtime-ns and
content or symlink target, with fixture/home/cwd/data roots separated from logs.
Absolute Node executable, PATH `/nonexistent`, synthetic HOME/config canaries;
no canary output. Exit 0.
- `python3 recheck.py`: final shared-tree/export identities and HEAD pass, exit 0.
Selected evidence hashes (paths relative to the evidence root):
| Artifact | SHA-256 |
|---|---|
| `node-tests.log` | `36c59ae491eec2d97909912f3fe4141b44e6473f0640b2141c460e2089a8a1df` |
| `oracle.log` | `18774c031f6e2bea64c45112fc23e29984db4923a74b365eaafed912746481ad` |
| `selftest.log` | `fafe1f016eaa8d150119902f2bec5ca2a83a78ccaf06501dbc5db9e9b0979a05` |
| `foundation-check.log` | `42ddd578b4f2be0c0b7b5b78a95de3a94e7d372661f634eb6f5209aa55e0c60a` |
| `profile-probe-receipts.json` | `6c067bcd6c4d88482b410e4e91f228ae5ef293156670b32c13d88544bcba463a` |
| `witnesses/receipts.json` | `db77081d5f0acf6f9f2744c48ea208a5363a688ec363db19a8767c32ef02b773` |
| `witnesses/additional-receipts.json` | `04c3945df8de33e0ed7b44a760703c19cb9d1a27dcc1e31b5678be1d630a7df1` |
| `inventory-before.json` and `inventory-after.json` (identical) | `78d5da15db9f0ae1501f7a24dccb14208eb9ba8b80c6e96d243fb850daced47c` |
| `recheck.log` | `66a96b5d044180515a717551a26ec75adaa109d0765eeb3a74ef3081b43c7d37` |
Witness input SHA-256s, for exact reproduction/audit:
| Witness basename under `witnesses/` | SHA-256 |
|---|---|
| `missing-agent-registry-declarations.json` | `78efd6fb46960079423eacc5cc9f469f0856a945137b03808e64b98add50bf56` |
| `consulted-dependency-undeclared-authorization.json` | `cc78be2811d49e6d56d67a009cac532e559a901e9a960834f64121d154e75299` |
| `assigned-change-without-work-read.json` | `35ee45e648387b9a8b0aa81b201b4eff61eb5a15bdc6eea30ecbfacecae77bd9` |
| `proposal-task-only-contexts-without-work-read.json` | `e1a9cd887f1bc64a8abdd8a0a1326df21b1ac0406ead978d2e6fc26e4eb0d683` |
| `proposal-issuer-denies-work-read.json` | `34d1ed805d3d42098052be2b928404947bd2d3b7b4c1af0edd3ec344aaec88f2` |
| `acyclic-versioned-history-false-cycle.json` | `e3dd1cd34e24c4d9ba0354203b7754c9e045966f0503d28ae1912e4e89eb2d15` |
| `shape-order-forward.json` | `689f9aa9713e53d7b10f9a9e263d16a2ff7e83d3056060c37c79c4e30bd11d6c` |
| `shape-order-reversed.json` | `d14fca5e43632c3283f1bcda772f9940dcd234afdfa43fe19bf5faa336eff062` |
| `message-priority-after-structural-validation.json` | `9e2ec77b87fb99fa602876fb5ffd52bbcd2142a4f7224cf1cdf7ec223a89d6fe` |
Scratch paths are local, disposable evidence, not durable repository artifacts.
The mutation recipes above and the frozen demo identities permit reconstruction.
## 5. Limits, corrections and handoff
- The five legacy repository suites were **not independently rerun**. Their green
results remain Rocko's receipts. Inspection found Docker/live branches in legacy
task/release tests and git mutation fixtures in the conductor test; I did not
widen this already-failing review into those activities or invent a skip/stub
and call the integration gate green. That required gate still needs an explicitly
authorized, isolated, non-live verification run before approval.
- Exploratory scratch receipts also contain blocked-subject-task, unrelated
subject-task-intent and blocked-target-mission probes reaching unresolved.
**Correction to their provisional expected-from-contract labels and my early
progress wording:** these are not counted as established violations here.
§5 specifically names subject-assignment and target-task checks; I do not infer
an additional full subject/target L1L9 calculation from those experiments.
- An exploratory Unicode probe agreed (both rejected U+13439); no Unicode
disagreement is claimed. Exhaustive comparison of the host Python/Node
Cc/Cf/Cs category sets found the same 2283 code points. This does not establish
general equivalence of their Unicode or schema implementations.
- Finite tests, static import review and unchanged inventories do not prove absence
of every read, complete schema equivalence, OS containment, authentic delegation,
crash safety, parent-path containment or resistance to same-size concurrent
input mutation. Only Node v26.8.1 was executed; no Node 22/24 portability claim.
- No shared implementation, fixture, charter, log, CURRENT or index edits; no
installation, staging/commit/checkout/reset/push, engine/network/native/sync or
live-data work. Synthetic canary files used by tests are not real credentials;
the operator's actual HOME/credentials/`~/.mosaic` were not investigated.
This verdict is the only repository write for FI-FILBERT-6.
**Return to darkwing:** reconcile F1F5 with the frozen contract, let Rocko alone
make any authorized corrections, then supply a newly hashed frozen candidate and
complete verification receipts for independent re-review. No implementation,
reassignment, acceptance, owner demo, push, issue closure or next phase follows
automatically. No timer or deadline is set.
@@ -0,0 +1,72 @@
# FI-FILBERT-3 — charter candidate 3 resubmission
Owner continuation authority unchanged. Reviewer: filbert, non-author; recheck
assignment compatibility if changed. Author/integrator and follow-up: darkwing.
Written-charter review only, not code or runtime approval.
## Exact inputs
Repository /home/jwoltje/src/mosaic-stack-dev-test
- docs/plans/2026-09-06_foundation-inspector-charter.md, candidate 3
SHA-256 19b6721128a627a2032ffdb95ece2d50abe69a8f6d521e9eff8bbdaff22798b6
- Incorporated Rocko r2 note sections 513, subject to charter overrides:
docs/plans/reviews/2026-09-06_foundation-inspector-rocko-feasibility-r2.md
SHA-256 f2f47fcfe22dca79f10f885b83d87a2f846fdb560425a4e20705c40ce4a123e1
These are frozen, uncommitted planning inputs. Map/source commits remain
7345f330fc6bfae5aa1d896c78cfb7cbe62efbae / d4696d09eb1b5dcf1028f30db2cd63735f51cb16.
Candidate 2 archived byte-for-byte as
reviews/2026-09-06_foundation-inspector-charter-candidate2.md, hash cbd0487a…;
your FI-FILBERT-2 verdict remains unchanged, full hash
2f3858c81d32b1305cb7fd49b0d8860153d8d592ac62df2c45dd25d30af7a722.
## Finding disposition for re-review
1. Charter §10.1 defines null owner-origin assumptions, approved current delegation,
exact recipient/registration/scope bounds, rejected/newer-rejected behavior,
required mock issuer ceilings, and intersections with role/narrowing. New closed
delegationInputs wrapper data is simulation-only; no accepted record changed.
Verify both ordinary registration and proposal use, not just the positive example.
2. §10.2 replaces selected-project global graph interpretation with per-record
ownership. Same-workspace/parent-project consulted work requires work.read in
applicable context. Other-workspace/project consulted refs return explicit
unsupported-capability even if separately registered; no silent readiness skip.
Unselected P2 inventory is not coerced into P1. Test outcomes specified.
3. §10.3 withdraws hidden-chain detection. Only direct-declared assumptions exist;
unknown parent fields/modes are structural errors, not chain detection. Artifact
bodies are never inferred; direct assertions cannot prove absence of chaining.
4. §10.4 fixes graph order: cycles precede continuity/parent-scope semantics, with
detector and CLI-precedence tests distinguished. O_RDONLY=0 check also corrected.
5. §10.5 expands differential type/null/bounds/uniqueness/Unicode corpus and preserves
schema-versus-profile separation and finite-test limitations.
All original substantive requests and exact-hash review boundaries still apply.
Please challenge new ambiguity, contradictions or unnecessary scope growth rather
than treating this disposition as proof. No implementation exists to test.
## Return and scope
Return FI-FILBERT-3 APPROVED/NOT APPROVED for exact identities, with per-finding
closure/reopening, new numbered findings, evidence and actual measurement limits.
Only allowed repository write:
docs/plans/reviews/2026-09-06_foundation-inspector-filbert-verdict-r3.md.
Do not edit the candidate, prior verdict or shared files. No code, dependency
installation, checkout/reset, commit/push, native/sync/live/credential tests or
separate ~/.mosaic investigation. No deadline or automatic phase advancement.
Direct reply is the return mechanism; follow-up darkwing.
Transport (2026-09-06 08:58 UTC): FI-FILBERT-3 sent once to =filbert/default; exit 2,
unconfirmed. Await direct verdict/blocker; no timer, retry or automatic approval.
## Inspector charter independently approved (2026-09-06 09:03 UTC)
FI-FILBERT-3 APPROVED received and full verdict read. Verified verdict SHA-256
15f3d04cb74a7296be6a1a26f2c0907b9dd2b08fdd1eb0ef51c95c7a52ff0399, exact
charter 19b6721128a627a2032ffdb95ece2d50abe69a8f6d521e9eff8bbdaff22798b6
and incorporated r2 f2f47fcfe22dca79f10f885b83d87a2f846fdb560425a4e20705c40ce4a123e1.
All five prior findings closed at specification level; four informational limits
retained. Reviewer reports 14 in-memory schema probes, hash checks and Node
constants measurements, not CLI/runtime/security or owner-demo acceptance.
Closeout delivered to Filbert (exit 0), no further work requested. Candidate and
prior verdicts unchanged. Await Jason's build authorization. No code, commit,
push or live changes; shared index left with Dewey per MS58-DW-1.
@@ -0,0 +1,71 @@
# FI-FILBERT-2 — frozen inspector charter review
Jason authorized continued planning with Filbert and Rocko. FI-FILBERT-1 confirmed
availability/non-authorship; recheck if current assignments changed, without
reprioritizing owner work. Author/integrator: darkwing; contributor: rocko.
Review requester/follow-up owner: darkwing. Reviewer: filbert.
## Exact candidate
Repository: /home/jwoltje/src/mosaic-stack-dev-test
1. docs/plans/2026-09-06_foundation-inspector-charter.md, candidate 2
SHA-256 cbd0487a2ab699722924e2f91367bf556facb015752ce3b5a76ad474977df791
2. Incorporated sections 513 of
docs/plans/reviews/2026-09-06_foundation-inspector-rocko-feasibility-r2.md
SHA-256 f2f47fcfe22dca79f10f885b83d87a2f846fdb560425a4e20705c40ce4a123e1
Charter overrides the note explicitly. These are frozen uncommitted planning
inputs, not falsely attributed to an earlier Git commit. No edits during review.
Accepted map commit 7345f330fc6bfae5aa1d896c78cfb7cbe62efbae;
accepted source/plan baseline d4696d09eb1b5dcf1028f30db2cd63735f51cb16.
Use committed bytes for those sources, not Dewey's mutable extension work.
## Review questions
- Is this bounded build contract coherent, implementable and faithful to the
accepted map, or does it need further design before code authorization?
- Validate exact reference types, graph/current-versus-historical handling, record
subset, required role/policy/execution layers and optional narrowing semantics.
- Challenge requester contexts in both reassignment scopes, intent/delegation
checks and the deliberately unreachable success path. Do not mistake declared
authorizations/artifacts for authentication or trusted evidence.
- Check privacy-safe output on every failure stage, closed shape/nullability,
precedence, rule/exit distinctions, number/Unicode domains and differential
test separation. Identify contradictory requirements or untestable acceptance.
- Check proposed filesystem open/read boundaries, no-live-effect limits and
static/test evidence limits. Node does not expose O_CLOEXEC on the measured host;
the charter explicitly corrects the note rather than claiming unsupported flags.
- Check that mandatory schema differential verification actually addresses validator
drift, that fixtures can reach intended rules, and that the proposed first slice
stays small enough to test before dependent runtime work.
This is a written implementation-charter review, not code, runtime, full Archify
or owner acceptance. No runtime implementation exists to test. Do not run native,
sync, live fleet, credential or installation checks. Static/helper calculations on
synthetic data in temporary space are allowed; report what you actually measured.
No dependency installation, shared checkout/reset, commits or pushes.
## History, not alternate specifications
Rocko r1 was useful but had nine coordinator correction groups; r2 accepted all.
The charter further fixes numeric 1.0 versus 1.5, unsupported-operation exit 2,
O_CLOEXEC availability, requester policy contexts, error output, input profile,
registration ambiguity and historical-reference admission. Re-evaluate these
changes independently; Rocko did not approve the integrated charter.
## Return
Reply FI-FILBERT-2 with APPROVED or NOT APPROVED for these exact input hashes,
numbered blocking/nonblocking findings, evidence and required corrections, review
question dispositions and measurement limits. Do not fix or co-author the candidate.
Only allowed repository write:
docs/plans/reviews/2026-09-06_foundation-inspector-filbert-verdict.md.
Provide its SHA-256. If assignment compatibility fails, return a blocker instead.
No implementation, source moves, role changes, fleet investigation or phase advance.
No deadline, automatic timeout or automatic acceptance. Direct reply is the return
mechanism; darkwing owns follow-up. No separate ~/.mosaic activity is requested.
Transport (2026-09-06 08:42 UTC): sent FI-FILBERT-2 once to =filbert on default socket;
exit 2, submission unconfirmed, not acknowledged. Await direct admission/verdict
or blocker. No timer or retry. Follow-up owner darkwing.
@@ -0,0 +1,195 @@
# FI-FILBERT-3 — independent charter candidate 3 verdict
Reviewer: filbert. Author/integrator and follow-up owner: darkwing.
Contributor: rocko. Date: 2026-09-06.
## Admission and exact verdict
**APPROVED for the written implementation charter at the exact identities below.**
All five FI-FILBERT-2 findings are closed at specification level. No new blocking
charter defect found. Implementation authorization remains Jason's separate gate;
this is neither implementation approval nor runtime/security/owner-demo acceptance.
No competing current personal owner-authorized assignment appeared. I remain a
non-author of the charter and incorporated feasibility note. I reviewed the complete
candidate, its changes from candidate 2, the incorporated rules and their interactions;
Rocko's contribution was not treated as approval of the integrated charter.
Independently verified identities:
| Input | SHA-256 |
|---|---|
| `docs/plans/2026-09-06_foundation-inspector-charter.md`, candidate 3 | `19b6721128a627a2032ffdb95ece2d50abe69a8f6d521e9eff8bbdaff22798b6` |
| `docs/plans/reviews/2026-09-06_foundation-inspector-rocko-feasibility-r2.md` | `f2f47fcfe22dca79f10f885b83d87a2f846fdb560425a4e20705c40ce4a123e1` |
| Archived `docs/plans/reviews/2026-09-06_foundation-inspector-charter-candidate2.md` | `cbd0487a2ab699722924e2f91367bf556facb015752ce3b5a76ad474977df791` |
| Preserved `docs/plans/reviews/2026-09-06_foundation-inspector-filbert-verdict.md` | `2f3858c81d32b1305cb7fd49b0d8860153d8d592ac62df2c45dd25d30af7a722` |
Map commit: `7345f330fc6bfae5aa1d896c78cfb7cbe62efbae`.
Source/plan baseline: `d4696d09eb1b5dcf1028f30db2cd63735f51cb16`.
Candidate and incorporated note remain frozen uncommitted planning inputs. Sections
10.110.5 explicitly override earlier shorthand, including the incorporated note.
The earlier NOT APPROVED remains an accurate historical verdict on candidate 2.
## Per-finding disposition
### 1. CLOSED — registration delegation semantics and issuer limits
Evidence: charter §10.1 supplies the missing ordinary L2/L3 checks: current active
registration, approved current delegation, exact registration scope, exact current
agent/registration subject pair, and explicit missing/stale/rejected/bounds outcomes.
Null delegation is expressly an unverified owner-origin fixture assumption, not an
unrestricted grant. A newer rejected head cannot be bypassed with an old approved
reference. Current consulted policy registries also have an explicit head rule.
The new closed `delegationInputs` wrapper does not mutate accepted records. Its
issuerCeiling and delegated operations narrow, rather than replace, mandatory role,
registration, project/workspace, task/mission and execution restrictions. Required
issuer input and subset checks apply to proposal delegation too; issuer restrictions
additionally narrow both requester contexts. This closes the previous ordinary
registration gap without treating a declaration as authenticated authority.
Independent shape/identity probes confirmed that same-scope approved decisions with
exact agent/registration subjects, and rejected successor decisions plus registration
successors, can be represented by the unchanged candidate schema. In a rejected
decision fixture, delegatedOperations must be empty to reach the intended semantic
rejection rather than fail its earlier schema conditional. This is a fixture detail,
not a new field or authority mechanism.
### 2. CLOSED — per-record ownership and consulted work access
Evidence: §10.2 replaces global selected-project graph interpretation with each
record's own project. It distinguishes structural existence from consulted access.
Unselected P2 task/mission inventory is no longer coerced into the P1 selection.
Consulted work supports only the current workspace or its parent project. Another
workspace/project receives the specified unsupported-capability refusal, even if a
separate registration exists. Thus no extra visibility context, cross-assignment
union or permission borrowing is silently introduced. Supported consulted work
requires work.read in the caller's full applicable intersection in addition to the
requested operation. Dependencies cannot be skipped when their scope is unsupported;
accepted status is required for file.change and proposal requester authority.
The subject and target proposal checks explicitly use original and target requester
contexts respectively. Taskless read does not traverse unrelated work. These are
bounded conservative limitations, consistent with baseline README:5771,124136;
they are not a promise to implement all future cross-scope dependency behavior.
### 3. CLOSED — hidden-chain detection claim withdrawn
Evidence: §§5 and 10.3 now expressly deny detection of a chain hidden behind opaque
artifacts, declarations or omitted records. The only wrapper mode is direct-declared.
Unknown parent fields and modes are structural invalid-request failures, not claimed
chain detections. A subject reference to a decision is not invented into a parent
edge. Artifact bodies remain unread and their presence remains unauthenticated.
This resolves the unobservable-predicate defect honestly. A valid direct declaration
can pass synthetic checks without proving absence of chaining. It still cannot
produce an allowed reassignment result: the final proposal branch is unresolved /
unknown-effects / runtime-reconciliation-required.
### 4. CLOSED — graph sub-order and fixture reachability
Evidence: §10.4 orders ordinary structural reference checks, then task/mission/
supersedes cycle checks, then revision continuity and ownership/parent-scope checks.
It also separates admission-time missing declarations from ordinary missing records.
The cycle order is no longer inferred from unordered requirements.
Independent schema probes confirmed a workspace mission self-parent and a revision-2
self-supersedes are shape-valid. Their references can resolve to themselves, allowing
the now-earlier cycle stage to run before parent-scope/continuity rejection. Detector
unit coverage and CLI first-failure coverage remain explicitly distinct. Stable
identity/field ordering, rather than inventory order, governs within-stage traversal.
### 5. CLOSED — differential corpus and platform boundaries
Evidence: §10.5 adds scalar types, null/absence, integer bounds and booleans, 1.0,
object-key-order-insensitive uniqueness, BMP/non-BMP lengths, byte-path limits and
escaped surrogates. Schema and strict input-profile verdicts occupy separate expected
columns; finite-corpus success is explicitly not a complete equivalence proof.
Independent probes confirmed representative distinctions: boolean revision invalid;
1.0 valid as a schema integer; maximum safe revision valid and the next integer
invalid; 128 non-BMP display-name code points valid and 129 invalid; duplicate path
objects invalid despite key-order reversal. A lone surrogate in an unformatted
schema string can be shape-valid while the strict inspector profile must refuse it.
O_RDONLY's zero value is now correctly handled with presence/type checks.
## New interaction findings and limits
1. **Informational / nonblocking — declaration authority remains an assumption.**
Location: §§3,7,10.1,10.3. An issuerCeiling is caller-supplied synthetic data;
its addition does not authenticate an issuer or model a real delegation chain.
The unconditional not-modelled/unverified-simulation output and the no-success
proposal endpoint preserve that distinction. No correction required. Code review
must ensure no diagnostic or positive preview upgrades this assumption into a
real authorization claim.
2. **Informational / nonblocking — added work.read is an intentional additional guard.**
Location: §§4,5,10.2. An assigned operation permitted by file.change alone must
still refuse when the context lacks work.read for consulted work. Taskless
file.read does not acquire an unrelated assignment/mission layer. Proposal
original/target contexts retain their own assignments and execution limits;
one context cannot supply another's missing permission. No correction required;
positive and negative tests must distinguish these cases.
3. **Informational / nonblocking — bounded scope, but substantial validator work.**
Location: §§6,8,10.110.5. The new inventory is capped at 256, graph/profile limits
remain finite, and no live source lookup, artifact-body loading, chain traversal,
runtime observer or publication component has been added. This remains feasible
as an offline increment, not a trivial schema wrapper. The mandatory differential
oracle, coherent fixtures and independent code review remain necessary. No
implementation-size or completion-time estimate was measured.
4. **Informational / nonblocking — testability is not implemented enforcement.**
Location: §§6,89. Descriptor flags, byte limits, Unicode handling, immutable
observed roots, privacy-safe outputs and fail-closed exits are obligations for
later code/tests. This review did not execute those mechanisms. No correction
required; do not promote schema probes or constants inspection into a security,
no-read, complete-mediation or crash-durability receipt.
## Full review-question dispositions
| Area | Disposition |
|---|---|
| Coherence/feasibility/faithfulness | Approved as a bounded written charter; prior substantive gaps are resolved without a runtime implementation or implicit phase advance. |
| Types, subset, history and mandatory layers | Closed wrapper addition, unchanged eight supported record shapes, complete histories versus consulted heads, explicit role/policy/execution ceilings and optional narrowing remain coherent. |
| Requester/subject/target, intent and delegation | Both requester scopes retain full contexts; ordinary/proposal delegation now has explicit bounded synthetic checks; subject selection is preserved; proposal success remains unreachable by specification. |
| Privacy/output/exits/profile | Closed body-free output, safe pre-validation nulls, fixed disclaimers, escaped text, documented refusal exceptions and separate number/Unicode profile remain intact. |
| Filesystem/no-live-effects | Proposed Linux descriptor boundary and its parent-path/concurrent-write/read-observation limitations remain explicit. No unsupported O_CLOEXEC or O_RDONLY truthiness assumption remains. |
| Differential verification/reachability | Mandatory pinned oracle, expanded corpus and explicit cycle precedence are adequate charter requirements; their implementation and actual coverage remain unverified. |
| First slice and owner gates | No implementation, live grants, source moves, package scaffolds, credentials, native integration or runtime security mechanisms added. Jason's build authorization and later demo acceptance remain separate. |
## Independent receipts for this FI-FILBERT-3 cycle
- `sha256sum` verified all four planning/history identities listed above.
- `diff -u <archived-candidate2> <candidate3>` showed the title change, replacement
of the hidden-chain claim in §5, and addition of normative §10. Exit 1 denotes
these expected differences, not a failed verification command.
- `git show d4696d09:<path>` read committed schema/checker and relevant accepted
README rules. Independent hashes again matched:
- records.schema.json: `05774aaf6943cb69c113e39ff1c29676a2a230ca7bf665c50dbcaa8049672af6`
- check.py: `82564a7d3200afcdda0850a9454cac6e6cd6a76687d2162c13cf214d7eac4607`
- Inline Python read committed records fixtures/schema with `git show`, made only
in-memory synthetic mutations, and ran **14 asserted schema probes: all passed,
exit 0**, using Python 3.12.8 and existing jsonschema 4.26.0. Four probes covered
direct delegation/registration and rejected successors, two covered cycle shapes,
four covered revision type/bounds, two covered non-BMP length, one lone-surrogate
schema string, and one object-order-independent uniqueItems check. Identity
assertions also distinguished the old approved reference from the rejected head.
These are shape/identity witnesses, not a complete coherent bundle or an inspector
implementation. Custom calendar/path formats were not exercised in this run.
- `node -e` independently observed Node v26.8.1; O_RDONLY=0 with numeric presence,
O_NOFOLLOW=131072, O_NONBLOCK=2048, and no exposed O_CLOEXEC. No descriptor was
opened for a filesystem behavior test.
No proposed CLI/differential harness, five repository suites, author checker,
canonicalizer implementation, symlink/FIFO tests, native/sync tests or live runtime
ran in this cycle. Earlier receipts are not relabelled as current execution. No
new dependencies or helper implementation files were installed/written; schema
calculations were inline and in memory. No credential contents or separate
~/.mosaic environment were accessed.
Only this offered verdict path was written in the repository. Candidate, incorporated
note, prior verdict, source, logs, policies, installations and shared index were not
edited. No checkout/reset, commit or push occurred. Follow-up remains darkwing;
this approval does not automatically authorize code or advance the phase.
@@ -0,0 +1,215 @@
# FI-FILBERT-2 — independent frozen-charter review
Reviewer: filbert. Author/integrator: darkwing. Contributor: rocko.
Follow-up owner: darkwing. Date: 2026-09-06.
## Admission and verdict
**NOT APPROVED for implementation-charter readiness.** The bounded inspector is
plausibly implementable without a new dependency or live runtime, but the frozen
algorithm needs the three substantive clarifications below before code authorization.
This is a written specification verdict, not a reproduced implementation failure.
Admission remains compatible: no competing current personal owner-authorized
assignment appeared. I did not author/co-author either input. I treated Rocko's
note as contributor material, not his approval of darkwing's integration. Charter
corrections take precedence over incorporated note sections 513.
Exact inputs independently hashed:
- `docs/plans/2026-09-06_foundation-inspector-charter.md`, candidate 2:
`cbd0487a2ab699722924e2f91367bf556facb015752ce3b5a76ad474977df791`
- `docs/plans/reviews/2026-09-06_foundation-inspector-rocko-feasibility-r2.md`:
`f2f47fcfe22dca79f10f885b83d87a2f846fdb560425a4e20705c40ce4a123e1`
- Accepted map: `7345f330fc6bfae5aa1d896c78cfb7cbe62efbae`.
- Source/plan baseline: `d4696d09eb1b5dcf1028f30db2cd63735f51cb16`.
The first two are frozen uncommitted files, not blobs falsely attributed to the
source baseline. Source comparisons used `git show` at the specified commits.
## Numbered findings
### 1. Blocking / high — consulted registration delegation has no semantic gate
**Locations:** charter §§34, especially current registration/delegation references
and adoption of L1L9; incorporated r2 §§6.26.3 and §7 L2/L3. Baseline candidate
README:7378,128136; records.schema.json `$defs/registrationPayload` and
`$defs/decisionPayload`.
The registration's `delegationRef` may be non-null. The specified rules require
that it resolve, name a head, and have the record kind `decision`. L2/L3 then check
registration status, role ceiling and narrowing. They do not say that the referenced
decision must be an approved, applicable delegation, or what a rejected/revoked or
unrelated decision does to the registration's simulated admission.
Concrete witness to specify: an otherwise valid active registration points to a
current rejected delegation decision, or to a current plan-approval/acceptance
about unrelated work. All its role/policy layers permit file.read. Exact reference
resolution and active registration status alone do not reject these cases under
the listed algorithm. They must not silently become a permitted preview of current
authority. Charter §5's proposal delegation checks do not cover ordinary L2/L3
registration use.
**Independent evidence:** a baseline valid registration mutated to reference the
valid fixture's non-delegation decision remains JSON-Schema-valid. This was an
isolated shape probe, not an executed inspector or complete graph demonstration.
It establishes that the schema cannot supply the missing semantic check.
**Required correction:** define the simulation semantics of non-null registration
delegation references, including applicable kind/outcome/recipient/scope bounds and
revocation/current-decision behavior. Keep null/owner-origin registration assumptions
explicit. Add coherent positive and rejected/unrelated/current-revoked negatives
that reach that semantic gate. No actual authentication or signature verification
is requested for this offline slice.
### 2. Blocking / high — cross-scope work-reference admission is underspecified
**Locations:** charter §3:8895 and §4; incorporated r2 §6.2:222227 and §7 L8.
Accepted map:250269; baseline candidate README:5771.
The baseline requires task mission/dependency references to resolve to **permitted
work**, with cross-scope access distinct from membership and execution authority.
The incorporated graph rule only says a task's mission resolves in the “selected
project.” The charter adds accepted status for same-project dependencies before
file.change, but does not define access checks for work in another workspace of
that project. “Dependencies grant no ownership/access” is not an algorithm for
checking whether the referenced work is permitted.
Concrete witnesses:
- Agent A is registered only in W1. Its selected W1 task names an active mission,
or an accepted dependency task, in W2 of the same project. All named records and
declarations exist. The listed same-project/status checks can succeed without
any check of A's permission to use that W2 work reference.
- An unselected historical/current task in P2 has a legitimate P2 mission while
selection names P1. If “selected project” is a global structural graph constraint,
this legitimate separate project is rejected. If it means each task's owning
project/context, the specification should say so. This matters to a bundle with
multiple projects and the new original/target requester contexts.
- A dependency in another project is said not to lend permission and broader
execution semantics are unsupported, but the exact admission result for that
reference is not stated. It must not simply be omitted from readiness checks.
**Independent evidence:** a valid baseline task mutated to name a mission in a
different workspace of the same project remains JSON-Schema-valid. No cross-scope
permission resolver was run or claimed; this is a missing specified semantic rule.
**Required correction:** distinguish per-record structural ownership from per-caller
consulted-reference access. Define the supported mission/dependency scope relations,
visibility/admission checks, and refusal for out-of-slice references, with exact
rule/exit outcomes. Add coherent same-project-unregistered-workspace and unrelated-P2
inventory tests. Resolve this within the bounded model, not by implementing real
authentication or expanding into a runtime dependency engine.
### 3. Blocking / medium — delegation-chain refusal lacks an observable predicate
**Locations:** charter §3 declaration limits and §5:133135; incorporated r2
§§5.2,6.2,8; baseline decisionPayload and artifactRef definitions.
The charter promises “Unmodelled delegation chains refuse unsupported-capability.”
The closed proposal supplies one delegationRef. A decision has subjectRefs and an
artifact basis, but no typed parent-delegation field. Declared artifacts contain only
runId/artifactId/digest; the inspector never reads their bodies. The specification
does not define a subjectRef to another decision as a delegation-parent relation
(subject references otherwise explicitly support history).
Consequently an implementation cannot determine that an otherwise well-shaped
delegation relies on a chain hidden behind its declared basis. Adding an arbitrary
parent field would instead fail the unknown-field structural rule, not reach the
promised unsupported-capability gate. Treating every referenced decision as a parent
would invent a relation and can misclassify historical subjects.
**Required correction:** state exactly what observable input denotes an unsupported
chain and its precedence, or explicitly delimit the model to direct declared
delegation assumptions and withdraw any claim to detect hidden chains. Define tests
for the chosen supported/unsupported distinction. Do not infer trust from artifact
presence or add an undocumented parent relationship during coding.
### 4. Nonblocking / medium — cycle fixtures need explicit within-graph precedence
**Locations:** charter §3:8890 and A3; incorporated r2 §§6.26.3,12.3,13.
The global stages are ordered, but ownership/parent-scope/continuity checks versus
cycle checks within the graph stage are not. A mission cycle necessarily violates
the permitted workspace-to-project parent structure; a supersedes cycle necessarily
violates the immediately preceding revision rule. Either can therefore be caught
by another semantic guard before the cycle detector.
**Independent evidence:** a workspace mission with a self-parent and a revision-2
task with self-supersedes both pass the record schema. Thus cycle tests can reach
a semantic detector if it precedes the other graph guards; they are not inherently
impossible. After successful parent-scope/continuity checks, those cycle cases cannot
reach a distinct cycle outcome.
**Disposition / requested clarification:** freeze the graph sub-order or document
which guard is the intended outcome for each fixture. Use separate detector-unit
and CLI-precedence tests where appropriate. Do not count an earlier wrong-owner or
bad-predecessor refusal as demonstrated cycle-detector coverage. This does not by
itself require a larger implementation scope.
### 5. Nonblocking / low — strengthen differential coverage beyond the listed mutations
**Locations:** charter §8; incorporated r2 §12.1; pinned checker/schema.
The mandatory independent Python oracle, pinned hashes, no-skip rule, and separation
of schema verdict from inspector-profile/unsupported-kind/graph verdict are valuable
and address drift. The listed mutations do not systematically cover scalar type
substitution, all null/absence branches, numeric bounds/boolean-versus-integer cases,
object-order-insensitive uniqueness, or non-BMP character-count boundaries.
**Disposition / recommendation:** include those boundaries in the deterministic
corpus, particularly because the Node validator is handwritten. Numeric 1.0 is a
valid schema integer but forbidden as an inspector input token; retain separate
entry paths for those tests. A passing finite corpus is compatibility evidence,
not proof that all candidate-schema behavior has been implemented.
## Review-question dispositions
| Question | Disposition |
|---|---|
| Coherent, implementable, faithful, ready for code authorization? | Not yet: findings 13 require design resolution. The dependency-free offline architecture itself is feasible in principle. |
| Exact types, subset, history, mandatory/optional layers | Reference types, eight-kind subset, explicit execution layer and null narrowing are sound. Complete-history versus consulted-head distinction is materially improved. Registration delegation and cross-scope reference semantics remain incomplete. |
| Requester contexts and reassignment | Both requester contexts correctly apply all L1L9 rather than just memberships. Subject/selection binding, approved task intent and no reassignment success are clear. Delegation-chain behavior needs finding 3 resolved. No mock basis/auth ID is treated here as authentic evidence. |
| Privacy, output, exits, number/Unicode domains | Revised closed output removes inventory/count disclosure; null pre-validation fields, fixed prose, JSON disclaimer field and escaped text are sensible. Numeric lexical profile is distinct from schema semantics. Clarify cycle precedence per finding 4 and test those output rules rather than just exit codes. |
| Filesystem and no-effect limits | Proposed descriptor-based Linux boundary is implementable; final-component symlink protection is not parent containment. O_CLOEXEC correction, quiescent-input limitation and no proof-of-no-reads caveats are honest. No descriptor behavior was tested in this review. |
| Differential verification and fixture reachability | Mandatory oracle/hashes and separated validation layers are sound. Findings 45 qualify reachability and coverage. Existing fixtures are shapes, not a coherent permission graph. |
| Small first slice / gates | Still offline and bounded, but already includes a full historical graph and substantial handwritten validation. Resolve the above rather than having the coder invent semantics. Written approval, implementation authority, code review and Jason's demo remain separate gates. |
## Independently measured receipts and limits
1. `sha256sum` of both frozen files matched the exact requested hashes.
2. `git show d4696d09:<candidate path>` read schema/fixtures/checker. Independent
SHA-256 matched records.schema.json
`05774aaf6943cb69c113e39ff1c29676a2a230ca7bf665c50dbcaa8049672af6`
and check.py
`82564a7d3200afcdda0850a9454cac6e6cd6a76687d2162c13cf214d7eac4607`.
Temporary copies: `/tmp/fi-filbert-2.XdSfM8/`.
3. Inline Python using existing jsonschema 4.26.0 ran five schema-shape probes from
copied committed fixtures: cross-workspace mission reference; mission self-cycle;
revision-2 self-supersedes; registration pointing to non-delegation decision;
numeric revision 1.0. **All five schema-valid, assertions passed, exit 0.** These
deliberately show where separate semantics/profile checks are required. Custom
calendar/path format callbacks were not exercised by these probes; their existing
fixture dates/paths were unchanged. No complete bundle or inspector execution is
claimed.
4. Inline Python `json.dumps(sort_keys=True,separators=(',',':'))` plus SHA-256
independently recomputed V1V3: all matched, exit 0:
- V1 `0bc44e14fd8354a8a85be879306a54881da7a0cb4d3dcf1f88bc4bc08a40dc9c`
- V2 `63817bffc57803ca6ac5df971aa0a160d4be73646394b3bc536578bd66c82660`
- V3 `d538c865808cfe7665956615fb48f69819baa0833626d1ef6e1cb3614acbc7da`
5. `node -e` read Node constants and parsed synthetic numeric strings. Observed
**Node v26.8.1**, O_RDONLY=0, O_NOFOLLOW=131072, O_NONBLOCK=2048,
O_CLOEXEC absent. `1.0` parses as 1, `-0` preserves negative zero, and
`9007199254740993` rounds to `9007199254740992`. This supports exact lexical
checking before Number conversion. O_RDONLY availability must not be tested by
truthiness because its valid value is zero. No file-open/symlink/FIFO behavior
was measured; constants alone are not enforcement evidence.
No proposed code exists to test. I did not run the proposed differential bridge,
CLI, non-effect harness, five repository suites or foundation author checker in
this FI-FILBERT-2 cycle. Earlier FM-FILBERT-1 receipts are not relabelled as new
execution. No dependencies, native/sync tests, engines, live runtime, credentials,
installations, commits, pushes, source changes or ~/.mosaic investigation occurred.
Only this offered verdict path was written in the repository. No charter fix or
co-authorship was performed. Follow-up and any revised candidate remain darkwing's;
this verdict authorizes no implementation or phase advancement.
@@ -0,0 +1,84 @@
# FI-C2-1 — proposed schema/profile clarification
Author: darkwing. Status: frozen proposal for independent review, not yet approved
or authority to edit code. Scope: resolve FI-ROCKO-4 C2 without a mismatch waiver or
weaker CLI admission. No live permissions, new dependencies or source-schema changes.
## Bound context
Charter candidate 3 SHA-256:
19b6721128a627a2032ffdb95ece2d50abe69a8f6d521e9eff8bbdaff22798b6.
Pinned schema/checker baseline: d4696d09eb1b5dcf1028f30db2cd63735f51cb16.
Rocko r2 report SHA-256:
0dabd82fffdc3a56ebf9a1d8b851832c3acee2cb9332892bde9dbb13151d5e19.
Frozen r2 manifest SHA-256:
2e8b5f1998a3be6cc7fcc3fba308724d2a29ca166c08f005e1bca88ddbc14196.
The coordinator verified all 239 file identities/modes/sizes, aggregates and pinned
inputs. This establishes the candidate identity, not functional acceptance.
## Problem
Python re's end anchor permits matching immediately before a final LF; the
inspector's ECMAScript patterns reject it. Four shape-oracle cases therefore
currently disagree. The earlier waiver was removed and the gate correctly fails.
The choice is not limited to permitting unsafe identifiers or waiving disagreements:
the charter already distinguishes schema-only verdicts from strict input profiles.
## Proposed normative clarification
1. Keep the pinned Python/jsonschema oracle and schema/checker bytes unchanged.
The Node schema-only validator must reproduce the pinned shape verdict,
including its pattern semantics. Every schema-column disagreement still fails;
no named exceptions, suppressed mutations or green artifact-difference class.
2. Define an explicit stricter inspector profile for values using candidate
$defs/id, $defs/runtimeId and $defs/digest: the entire string must satisfy the
declared grammar under strict end-of-string semantics. A final LF must fail the
profile even if the schema-only oracle accepts it. This covers all occurrences
of those types, including scopes, actors, record/registry/artifact references,
authorizations and simulation wrapper fields—not merely the four current probes.
3. Preserve the original value throughout both checks. Do not trim, normalize,
silently substitute or create an identity index from a newline-stripped value.
No schema-only pass can bypass the profile before graph/admission evaluation.
4. A well-decoded, schema-valid but profile-invalid value returns process exit 2,
invalid-request, a fixed documented profile-pattern-mismatch rule, and safe
pre-admission output. No newline-bearing identifier/authority/digest reaches
a permitted preview. Existing closed output fields/disclaimers remain unchanged.
5. The test bridge exposes schema and profile verdicts independently. For the four
reported cases: Python schema true, Node schema true, inspector profile false,
actual CLI refusal. These are schema AGREEMENTS plus tested profile refusals,
not allowed schema disagreements under another label. Other stricter documented
lexical/byte/Unicode profile rules retain their separate expected columns.
6. Implement schema-pattern compatibility as real bounded validator behavior, not
case-name/path whitelisting or a harness-only answer adjustment. A copied oracle
answer is not an independent Node shape verdict. The production admission path
must actually enforce the profile, not rely on a test-only wrapper to reject it.
This clarification changes validation-layer classification, not the CLI's accepted
identity grammar. It does not introduce a broader accepted record profile, change
a runtime policy, or require Jason to adjudicate regex dialect details. Independent
review must confirm that this remains within the authorized offline build scope.
## Required evidence
- Preserve all four existing disagreement witnesses; do not delete/rename them out
of coverage. Test valid values, one/two final LF, CRLF, interior LF and relevant
Unicode line separators across every affected type family, with independent
expected shape/profile/CLI outcomes. Do not assume all separators share semantics.
- Include both records and wrapper/reference inventories, including unselected
records and declared inputs. Reject before identity lookup or permission result;
tests must distinguish profile refusal from a later missing-reference mismatch.
- Ordinary free-form text that legitimately permits escaped newlines must not be
blanket-rejected by this targeted identifier profile. Path/time custom formats
keep their existing semantics and separate tests.
- Differential oracle has zero unapproved schema disagreements; strict-only/profile
refusals are visibly counted and asserted. All other mandatory tests remain green.
- No normalization, extra output fields, dependency install, modified pinned inputs
or exceptions to required gates. Retain actual toolchain/platform receipts.
## Gate
Filbert reviews this exact proposal as a non-author. Rocko keeps code frozen pending
that verdict and coordinator instruction. If approved, record it as an explicit
addendum to the unchanged charter, update bound test identities deliberately, then
implement only within existing source/test paths and return a new frozen candidate.
Full independent CODE review and Jason's demo remain subsequent separate gates.
@@ -0,0 +1,109 @@
# FI-FILBERT-5 — independent pattern/profile addendum verdict
Reviewer: filbert. Author/follow-up owner: darkwing. Date: 2026-09-06.
## Admission and exact verdict
**APPROVED for the written addendum only.** The proposed separation preserves
strict CLI admission while requiring genuine Node/Python schema agreement. It is
not a whitelist or permission to waive the red differential gate.
No competing current personal owner-authorized assignment appeared. I did not
author/co-author this proposal. This narrow review does not start or replace the
later frozen implementation review.
Reviewed file:
`docs/plans/reviews/2026-09-06_foundation-inspector-pattern-profile-addendum.md`
Independently verified SHA-256:
`afe2980be2f91e701dae5af3018831ac5c300474f52bcc06e740ce5b5cc68ca5`
Unchanged charter candidate 3 SHA-256 independently verified:
`19b6721128a627a2032ffdb95ece2d50abe69a8f6d521e9eff8bbdaff22798b6`
Pinned source baseline:
`d4696d09eb1b5dcf1028f30db2cd63735f51cb16`.
## Numbered findings and dispositions
1. **Confirmed / no blocking defect — the mismatch premise is reproducible.**
For the pinned id, runtimeId and digest definitions, Python/jsonschema accepts
a valid value followed by exactly one final LF, whereas the measured Node
ECMAScript patterns reject it. Two final LF, CRLF, CR, interior LF, U+2028 and
U+2029 did not share that acceptance. The proposal correctly requires independent
outcomes instead of treating every line separator alike. No correction required.
2. **Confirmed / no blocking defect — no weaker admitted identity grammar.**
Normative points 24 require strict whole-string matching for every occurrence
of the affected types, including unselected records and declared wrapper inputs,
before indexing or admission. Original strings are preserved; no trimming or
newline-stripped identity can enter the graph. Thus reproducing the oracle's
schema-only acceptance does not enlarge the CLI's accepted identifier language:
the additional profile still rejects the final-LF cases with exit 2,
invalid-request/profile-pattern-mismatch and safe pre-admission output.
This fits the charter's existing schema/profile separation. No correction required.
3. **Confirmed / no blocking defect — the proposed gate is not an oracle whitelist.**
Points 1,5,6 require an actual independent Node shape verdict, zero schema-column
disagreements, independently asserted profile verdicts and real CLI refusals.
They prohibit named exceptions, deleted witnesses, copied oracle answers,
harness-only answer adjustment and test-only rejection wrappers. Green must mean
schema agreement AND production profile enforcement, not relabelling an ongoing
discrepancy. No correction required; code review must verify these obligations.
4. **Confirmed / bounded scope — targeted profile, not blanket newline rejection.**
The proposal leaves legitimate free-form multiline text and existing path/time
formats separate. I independently confirmed an escaped-newline mission objective
remains valid under the pinned record schema. This supports the required negative
control: an implementation that bans every decoded newline would violate this
addendum. Pinned schemas/checker, dependencies, output fields and allowed source
paths remain unchanged. No new runtime capability or grant is introduced.
5. **Informational / unverified implementation gate — written approval does not turn the build green.**
I did not inspect the moving implementation, independently validate the reported
239-file manifest, identify/re-execute its four particular witnesses, or run its
differential bridge/CLI. Those remain reported context, not my receipts. The new
frozen code candidate must preserve those witnesses, pass every mandatory check,
and receive full independent code review. No correction to the written proposal
is required; no functional acceptance is issued here.
## Independent measurements in this review cycle
1. `sha256sum` verified the exact addendum and unchanged charter hashes above.
2. Read `records.schema.json` using `git show` at d4696d09 and independently checked
SHA-256 `05774aaf6943cb69c113e39ff1c29676a2a230ca7bf665c50dbcaa8049672af6`.
3. Inline Python using Python 3.12.8/jsonschema 4.26.0 validated three pinned type
definitions over eight variants each. An inline Node v26.8.1 subprocess evaluated
their actual ECMAScript patterns and a strict-end helper on the same original
values. **All 24 expected matrix rows asserted successfully; exit 0.**
| Value variant, for each of id/runtimeId/digest | Python schema | Node pattern | Strict-end helper |
|---|---|---|---|
| Valid value | true | true | true |
| One final LF | true | false | false |
| Two final LF | false | false | false |
| CRLF | false | false | false |
| CR | false | false | false |
| U+2028 | false | false | false |
| U+2029 | false | false | false |
| Interior LF | false | false | false |
The helper is only a regex measurement, not the proposed schema compatibility
implementation, profile traversal, differential bridge or CLI.
4. A separate in-memory mutation of the committed valid mission fixture inserted
an escaped newline into its free-form objective. **Pinned record-schema verdict
true, assertion passed, exit 0.** Custom path/calendar formats were not exercised
by that unchanged-field shape probe.
No dependency installation, implementation edit, helper implementation file,
staging, commit, push, native/sync/live runtime, credential read or ~/.mosaic work
occurred. Calculations used synthetic strings and committed schemas in memory.
Only this offered verdict path was written in the repository.
## Return boundary
Approval permits treating this exact proposal as the reviewed written addendum,
not treating Rocko's current red build as accepted. Coordinator instruction and
deliberate binding of updated test identities remain necessary before code resumes.
A green frozen implementation, independent CODE review and Jason's demo remain
separate subsequent gates. Follow-up stays with darkwing; no automatic advancement.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,305 @@
# Foundation inspector — rocko build report r2 (FI-ROCKO-4 dispositions)
Author: rocko (Claude Fable 5.1). Coordinator: darkwing. Task: FI-ROCKO-4.
Written 2026-09-06 18:35 UTC. Supersedes nothing: the original report
`docs/plans/reviews/2026-09-06_foundation-inspector-rocko-build.md` is preserved
unedited (sha256 `857470d97af6aeae4e7d7942c2a1d8455bfcda74ff68b8e1dc4ba8d066521fa4`,
unchanged since delivery); this revision records the admission findings, what
changed, and the new frozen candidate.
Inputs bound to this revision:
| Input | sha256 |
|---|---|
| Admission findings `2026-09-06_foundation-inspector-build-admission-findings.md` (as received, 18:04Z) | `59233c6126c2355df5a367f0e61df7798e6cccfaa682454992fcd0d0df39c82c` |
| Same file now (darkwing's "Transport (2026-09-06 18:17 UTC)" footnote appended; no other change) | `8d9f7aab3b3bdf79345a07ba3595b966982b7667714ac7e3f669d65e328ca3d5` |
| Charter candidate 3 `docs/plans/2026-09-06_foundation-inspector-charter.md` | `19b6721128a627a2032ffdb95ece2d50abe69a8f6d521e9eff8bbdaff22798b6` |
| `records.schema.json` / `check.py` / `records.fixtures.json` | `05774aaf…72af6` / `82564a7d…4607` / `d433d06d…da85` (full values re-verified by the oracle gate 1 and listed in the manifest) |
| Build request `2026-09-06_foundation-inspector-rocko-build-request.md` (now, transport footnote included) | `90a1f329e859152d4ce8e157cbd6c56e6bcced16b4ed757822d2309514fa9a15` |
| Integration HEAD (unchanged, nothing staged) | `9a5fbdbda74b16adf488fe28138b2ba69ea5e669` |
| Machine-generated manifest `2026-09-06_foundation-inspector-rocko-build-manifest-r2.json` | `2e8b5f1998a3be6cc7fcc3fba308724d2a29ca166c08f005e1bca88ddbc14196` |
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. Per-finding dispositions
### C1 — demo hash mismatch: transcription error, no drift
Disposition: **typo in the original report, not evidence drift.** Corrected;
no evidence was regenerated to make anything match.
- Advertised (report line 96): `…548fc023…`; measured then and now:
`f1c6bd523cdff161e51da156fd00cfaa652d193f41541686548cf023378fd8ab`.
The only difference is the transposition `fc``cf` at positions 5152; the
other 62 hex characters are identical.
- Evidence the file never changed: my scratch hash listing taken at 18:03:52 UTC
(before the report was written) already contains the measured value for
`demo/prop-message-is-not-authority.json`; the file's mtime is 17:52:58 UTC,
earlier than that listing; the demo copy is byte-identical to
`bundles/prop-message-is-not-authority.json` (same hash, 49,975 bytes; asserted
by `fixtures.test.mjs` "demo copy drifted"); and both aggregate manifests
reproduce the original report's values with the original method:
bundles 185 files 9,235,245 bytes `a804e4ab253839ba2bb8ad7475d27512b2ef88e70a9779f9093fee5478de4823`,
raw 19 files 1,336,985 bytes `508ad85208f4b69676f3d041faa4ff4cd4a2f8de74b7bde9b0b89123a8485cc4`.
- Root cause: the original §3 tables were hand-transcribed. The r2 manifest is
written by a script (`manifest-r2.json`: path, mode, size, sha256 for all 239
candidate files, aggregates, HEAD, toolchain, pinned inputs). No hash in this
report or in the manifest is typed by hand except where a value is quoted from
the original report to show the error.
### C2 — oracle divergences were waived: waiver removed, one class remains as a spec blocker
Disposition: **fixed for the calendar class; precise blocker for the pattern
class.** The oracle no longer has a `KNOWN_DIVERGENCES` list; every
schema-column disagreement is a problem and the oracle FAILS.
Calendar class (2 cases, fixed): the pinned checker refuses years 00010999 on
this platform because `strftime("%Y")` is unpadded below 1000, so its
strptime/strftime round-trip fails. The inspector now refuses them identically
(`isValidTime`: year < 1000 refused; charter §8 "calendar semantics from the
pinned checker"). Witness:
`python3 -c 'from datetime import datetime; print(datetime(999,1,1).strftime("%Y"))'``999`.
The oracle asserts this witness as gate 3 before comparing and fails with an
explicit "platform boundary" message on a platform that pads. Cases
`calendar-year-0001`, `calendar-year-0999`, `calendar-year-0100` now agree
(both refuse). `resolve.test.mjs` adds the three boundary vectors.
Pattern class (4 cases, blocker, unchanged verdicts): the pinned checker
evaluates `pattern` through Python `re.search`, whose `$` also matches
immediately before a trailing `\n`; ECMAScript `$` does not. Consequently the
pinned checker ACCEPTS `id`, `scope.projectId`, `authorizationRef` (runtimeId
pattern) and `policyRef.digest` values that carry a trailing newline, and the
inspector REFUSES them (`shape-pattern-mismatch`). Witnesses:
```
python3 -c 'import re; print(bool(re.search(r"^[a-z0-9][a-z0-9._-]{0,63}$", "abc\n")))' # True
node -e 'console.log(/^[a-z0-9][a-z0-9._-]{0,63}$/.test("abc\n"))' # false
```
Current oracle output (verbatim, exit 1):
```
platform witness: strftime('%Y') for year 999 -> '999' (pinned checker refuses years 0001..0999)
node v26.8.1; corpus 1432 records (38 pinned fixtures, 410 unique bundle records, 984 typeCase/mutation/lexical cases)
schema column: agree-valid 476, agree-invalid 915, DISAGREEMENTS 4; strict-only (parser-bound) cases: 27; unsupported-kind records not schema-assessed by the inspector: 10
profile column (schema-valid records only): profile-valid 476, profile-invalid 0
problem: DISAGREEMENT pattern-authorization-ref-trailing-newline: pinned-checker schema True / inspector schema False (inspector profile False, rule shape-pattern-mismatch)
problem: DISAGREEMENT pattern-digest-trailing-newline: pinned-checker schema True / inspector schema False (inspector profile False, rule shape-pattern-mismatch)
problem: DISAGREEMENT pattern-id-trailing-newline: pinned-checker schema True / inspector schema False (inspector profile False, rule shape-pattern-mismatch)
problem: DISAGREEMENT pattern-scope-project-id-trailing-newline: pinned-checker schema True / inspector schema False (inspector profile False, rule shape-pattern-mismatch)
FAIL: 4 differential problems
```
Why I did not resolve it myself: the findings forbid implementing a waiver or
changing the pinned schema/checker, and the charter forbids weakening safe
input handling. Making the inspector accept an identifier with an embedded
newline would relax input handling merely to turn the count green (the newline
would then be carried into `selection.projectId` and the text rendering, and a
`scope.projectId` of `p1\n` would be a distinct identity from `p1` that renders
almost identically). The schema-column comparison is therefore left honestly
red, and the suite reports `selftest: 36 passed, 1 failed` until this is ruled.
Proposed amendment (for darkwing/Jason; I implement nothing until ruled):
- (a) **Recommended.** Add to charter §8 (or the incorporated notes) a
"checker-dialect artifact" clause: "The pinned checker's `pattern` semantics
are Python `re.search`; its `$` accepts one trailing newline. This is a
dialect artifact, not an intended grammar. The inspector applies the pattern
with anchored (ECMAScript) semantics and refuses a trailing newline. The
differential oracle records the cases in this class by name, with the two
witnesses above, and reports them as an expected artifact-class difference
separately from agreement counts; any other disagreement fails." Under (a) the
oracle would carry a named, witnessed artifact class with exact direction
(pinned True / inspector False) and fail on any other direction or any other
case. This is the amendment I would implement; it needs a coordinator ruling
because it is a policy choice about which side is authoritative.
- (b) Against: relax the inspector to Python semantics. Rejected for the input
handling reason above and because §8 keeps "record-schema verdict distinct
from … refusal"; the inspector would have to accept an identifier the runtime
would never mint.
- (c) Against: drop the four mutations from the corpus. Rejected: it hides a
real, reproducible difference between the two implementations.
Until ruled, the candidate's differential gate is **red by design**, and this
report does not claim oracle PASS.
### C3 — `exit` outside the closed §7 fields: removed from the serialized result
Disposition: **fixed; no charter amendment needed.** Exit status is process
metadata derived from the emitted result (`exitFor(result)`), never a field
of it and never a text line.
- `resolve.mjs`: `RESULT_KEYS` is exactly the 12 charter §7 names in charter
order; `buildResult` builds no `exit` member and throws if the requested exit
is inconsistent with the derived result/reason; new export `exitFor(result)`
(allowed→0; refused/unresolved→3; invalid+io-failure→4; other invalid→2).
`evaluate()` returns `{ result, exit, detail }` with `exit` outside `result`.
- `foundation-inspect.mjs`: `renderText` ends with the `diagnostic:` line (no
`exit:` line); `run()` returns `{ json, result, exit }`; `main()` writes the
rendering and sets `process.exitCode = exit`.
- Tests whose expected keys come from the approved contract, not from the
implementation: `resolve.test.mjs` "closed result fields equal the pinned
charter §7 list" reads the charter file, asserts its sha256 is
`19b67211…798b6`, parses the twelve `- name:` bullets under "Closed result
fields, emitted on every outcome:", and asserts they equal both an
independent literal copy in the test and the implementation's `RESULT_KEYS`;
it also asserts `exit` is absent, checks `exitFor` on all four classes, and
that `buildResult` throws for four exit/reason inconsistencies.
`cli.test.mjs` and `fixtures.test.mjs` assert `!("exit" in parsed)` for every
spawned run and derive the expected process status from the parsed result;
text renderings are asserted to end with the diagnostic line and to contain
no `exit` line for all 204 cases. `test-foundation.sh` asserts the `--json`
key list equals the twelve names literally.
- Consequence: **the ten demo goldens (`*.expected.txt`, `*.expected.json`) were
regenerated** with the README loop because the contract fix removed one line
/ one member from each; the five `*.expected.exit` files are byte-identical
to before (hashes `9a271f2a…86aa` for 0 and `1121cfcc…02a2` for 3, as in the
original table). `index.json` is unchanged (its `expect.exit` was always the
process status). Demo tree total bytes 249,096 → 248,991 (105 = 5 × (8-byte
text line + 13-byte JSON member)).
### C4 — demo step 2 could not show unchanged bytes: corrected
Disposition: **fixed.** The BEFORE manifest is saved in a separate scratch
location first, the preview runs, then `sha256sum -c` verifies against that
SAME manifest (plus an inventory of path/type/size/mode/inode/mtime and a file
count). Corrected commands are in §4; the receipt from running them is in §3.
### C5 — report omitted O_NONBLOCK: prose corrected, flag kept
Disposition: **fixed in prose only; no code change.** The CLI opens the input
with `O_RDONLY | O_NOFOLLOW | O_NONBLOCK` (`REQUIRED_FLAGS` = those three
names) and refuses with `open-flags-unavailable` (exit 4) if any is not a
number on the platform. O_CLOEXEC is not used (charter §6). The original
report's lines 142 and 270 said `O_RDONLY|O_NOFOLLOW` only; that text was wrong
and is superseded by this paragraph. The FIFO test (`cli.test.mjs` "FIFO must be
refused after O_NONBLOCK open, not read") exercises the flag.
## 2. Changed files (old → new sha256; everything else byte-identical)
All under the FI-ROCKO-3 allowlist plus the two paths offered in the findings.
Nothing else in the working tree was touched; `git status` shows the same
pre-existing modified/untracked entries as before plus the two r2 documents.
| File | Lines | Original report sha256 | r2 sha256 |
|---|---|---|---|
| `scripts/foundation-inspect.mjs` | 239→244 | `bfa1b78007c772c54fe1dab90a53e19e6bce7e4888a5adb2de0b2cfe43c5cddd` | `dad369490ca8396d3b4a7bd4a1b7fa87b677a2b8cf991bf61672d446e5aa3c93` |
| `scripts/foundation/resolve.mjs` | 1625→1646 | `9ae8b4255b5dc1f1e9b0d36549865268c12dc53f010984eb1e5616b127d1d8a2` | `aa842898ebb0bb2a911406314c4c3a2c4079b46bfd674c4ffba0176a1e32766c` |
| `scripts/foundation/verify-schema.py` | 453→467 | `7e3098655b2e5f261391d788c2112a6ffb055895e357b427bc68e5f2fa7b52d7` | `b61031b6c2cea126133afda70894e7f2429b08bf2cd50fc766ec6b99f348c966` |
| `scripts/foundation/resolve.test.mjs` | 294→333 | `05f27aa6c8a1b8ff2ee45e5de03a9aea5ed13cf011b2464c5865022dc9781449` | `6bb6d40fa6ec90fb52db658f77ca9fd27cc3eb8673f040f52fc126e67983a571` |
| `scripts/foundation/cli.test.mjs` | 279→281 | `b7e9a13c11e3e6f487ada2779c892cdf848526de1ef8b21387d15d4a461ddb62` | `ccec06c266e03d878c1ecd9e8c20ee3f1fb82f478daead25efa4661b7090d83f` |
| `scripts/foundation/fixtures.test.mjs` | 93→98 | `2827de36214c8014471fed3478c42bf48eddb3fbdbff82cac9e27851646b15d2` | `94e7508717efcafd11585a288a5d791e1e48a993794e2d470c6097f904befdb3` |
| `scripts/test-foundation.sh` | 132 | `76fb7ba9da4345271b6ba93228a9da69c7e55c4e44b9f4033e84a8f4b430e8ec` | `fdfa13ce247bc9ad8f3617e248913aef384029198924685ada3431006ffdf114` |
| `fixtures/demo/demo-read-w1.expected.txt` | | `8bfff519ce8275cfe59562efd04647c242c328a09b301b91d70491f030cf1600` | `8ba4bbe92819ac8912c72e7c635730e99eac7916c0d924fc81b75115b5939b53` |
| `fixtures/demo/demo-read-w1.expected.json` | | `55e10c1693787cd8e39d3a66841d30e2336080d2ae4450a806a7ae8373db476b` | `42055bda71075ba5c710f011f83d470228f18097d93ac5585ba1b534cba0ef2a` |
| `fixtures/demo/demo-file-change-src.expected.txt` | | `f5387217ca0a41d437468af33b7d87d06c0c5535ab5490b568f9866a13b2732e` | `2cdd6d4e162fa904b03e8f8a88553a03065ac7fb646baabf21625d4f5962a79b` |
| `fixtures/demo/demo-file-change-src.expected.json` | | `88c7793c6af17ca255525451a499d9f8bb165155e50d2ee936bd68ba82a876a7` | `7ea412916404ec948c94e929cc7b2ce120b394944c66c7bfcc811d0721dd82db` |
| `fixtures/demo/demo-change-w1.expected.txt` | | `2a1090e5f5ad08e2175830943a7c81928de970470893e803b1e440843152c348` | `0e2807ab56d15670c51c8ad4a43f33b36c5672799937561f39e20c6e93be1dda` |
| `fixtures/demo/demo-change-w1.expected.json` | | `36c287cba327070f7ff3dd9846421bee3ebd0dd52e9c602b68e84fa620ef4fc5` | `ecf8313993ca27450d1753c6178be1a063fb0637f14be8f091de923b8b722516` |
| `fixtures/demo/adm-registration-revoked.expected.txt` | | `624c9e5991597d59fc3379343b16e7eab9cb6434f054da3a4df7518742e3b36c` | `c2fd118d44d21cbd709d30a2c2be2603740a81e628aa9d32f95d6eaf06d3a9a6` |
| `fixtures/demo/adm-registration-revoked.expected.json` | | `b966d939e0d2851ef731462a0fda932e75f53b9aac406216ad440f781e036d0f` | `c44b0935ed329c1a381f986997b1bc4be702fc4229166d8a0b49e4e80f9b2fa8` |
| `fixtures/demo/prop-message-is-not-authority.expected.txt` | | `e7b0e9fa64abe0c0f8c91fbc9aa565988ce76cb3967672bfacafab350e20d8be` | `388983ad6e4e31db6f5a688773ff2bf07d44d7ffe530eb7870e729a0f546278d` |
| `fixtures/demo/prop-message-is-not-authority.expected.json` | | `53884bfdea21185141b9a06d52aa1c0fe8e7bfae6627b465929403521f9bc4d8` | `742e479ddbb4cf2138d49ec0ac40cd038b6c20f8b9c0e2daffc5a859db9f4145` |
| `fixtures/demo/prop-message-is-not-authority.json` | | (report typo `…548fc023…`) | `f1c6bd523cdff161e51da156fd00cfaa652d193f41541686548cf023378fd8ab` (file unchanged) |
Unchanged (same hash as the original table): `strict-json.mjs`, `canonical.mjs`,
`validate-record.mjs`, `strict-json.test.mjs`, `canonical.test.mjs`,
`build-fixtures.mjs`, `index.json`, `fixtures/README.md`, all five
`*.expected.exit`, all five demo `*.json` bundles, all 185 bundles and 19 raw
fixtures (aggregates above). Full per-file listing with modes: `manifest-r2.json`.
Aggregates (r2 manifest method: sha256 of the LC_ALL=C sorted `sha256sum`
listing with repo-relative paths): `scripts/foundation/fixtures/` 227 files
`36d99b91065ed7af03f17b7b9cc309b3f7805ca5e3a337ddb5f3536f2ccaa563`;
`scripts/foundation/` 237 files `6c111ad1165e0da219d566f919e25005af47fa004257a11e7e2750a4010b9ecb`;
all 239 candidate files `e0fe89d9cc5245031ce484e9e0fe15b93319dd2cdf040800c52555a26fb1c1a6`.
Original-method demo aggregate (run in `scripts/foundation/fixtures/`,
`sha256sum demo/* | sha256sum`): `7000fdd9b2a5e92256429e148240541fab3f93d2ef009e47b08baddcbcef5216`.
Source changes in words: `resolve.mjs` (isValidTime year ≥ 1000; `exitFor`;
`RESULT_KEYS` without exit; `buildResult` consistency guard; `evaluate` returns
exit beside result). `foundation-inspect.mjs` (no exit line; `withExit`; exit via
`process.exitCode` only). `verify-schema.py` (waiver list and waiver comparison
deleted; gate 3 platform witness; trailing-newline cases renamed
`pattern-*-trailing-newline` and kept; calendar boundary cases; separate
schema/profile column summary; every disagreement is a problem).
`test-foundation.sh` (JSON key-list assertion; oracle summary grep lines).
Tests as described under C3 and C2. No new dependency, no new file outside the
allowlist, no `__pycache__` (verified absent after all runs).
## 3. Receipts (all run 2026-09-06 18:2x18:30 UTC at HEAD 9a5fbdbd)
| Check | Result |
|---|---|
| `node --check` on all 10 `.mjs` files; `ast.parse` on `verify-schema.py` | OK |
| `node --test scripts/foundation/` | 58 tests, 58 pass, 0 fail (was 57; +1 charter-derived field test) |
| `python3 scripts/foundation/verify-schema.py` | **FAIL, exit 1: exactly the 4 `pattern-*-trailing-newline` disagreements** (output quoted under C2); gates 13 PASS; 38 pinned fixtures agree |
| `NO_COLOR=1 scripts/test-foundation.sh` | **`selftest: 36 passed, 1 failed`**; the one failure is the oracle gate above; all other checks OK (syntax, fixture regeneration equality, node tests, demo exits 0/0/3/3/3, usage 2, I/O 4 ×3, oversize 2, disclaimer, JSON key list, golden byte-match, sandboxed inventory unchanged, canaries never printed) |
| `python3 docs/plans/foundation-v1-candidate/check.py` | exit 0 |
| `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 |
| `git rev-parse HEAD`; `git status` | `9a5fbdbd…`; nothing staged; only the pre-existing entries plus the two r2 documents |
| `scripts/foundation/__pycache__`, `docs/plans/foundation-v1-candidate/__pycache__` | absent |
Owner-demo receipt (corrected C4 procedure, verbatim outcome lines):
```
step 1 demo-read-w1.json → result: allowed … operation: work.read target null rc=0
step 2 before manifest: 227 files, sha256 cf2eed27c5e5b311d40e5346af89fbc5fdc7781488bf8ea9d663e66e7dd50d59
demo-file-change-src.json → result: allowed … operation: file.change target workspace:src/main.mjs rc=0
sha256sum -c against saved BEFORE manifest: all 227 OK
inventory (path/type/size/mode/inode/mtime) unchanged
file count unchanged: no file added
step 3 adm-workspace-registration-missing.json → refused / not-authorized / workspace-registration-missing, assignment null rc=3
step 4 demo-change-w1.json → unresolved / unknown-effects / runtime-reconciliation-required; selection keeps asg-a-w1 rev 1 rc=3
prop-all-pass-restricted-contexts.json → unresolved / unknown-effects / runtime-reconciliation-required rc=3
extra adm-registration-revoked → refused/registration-revoked rc=3; prop-message-is-not-authority → refused/message-is-not-authority rc=3
json keys = [disclaimer, preview, bundleVersion, authentication, declarations, result, reason, rule, selection, operation, proposal, diagnostic] rc=0
```
Every text rendering begins `SYNTHETIC PREVIEW — NO LIVE EFFECTS` and ends with
the `diagnostic:` line. These are bounded evidence (finite tests, inventory
comparison), not an OS-sandbox proof; the original report's §8 qualifications
stand.
## 4. Corrected owner-demo commands (A9; replaces original §9 step 2)
```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 preview (exit 0); prove no fixture file changed:
# save the BEFORE manifest elsewhere first, run, then verify against that SAME manifest
BEFORE="$(mktemp)"
( cd scripts/foundation/fixtures && find . -type f | LC_ALL=C sort | xargs sha256sum ) > "$BEFORE"
node scripts/foundation-inspect.mjs scripts/foundation/fixtures/demo/demo-file-change-src.json
( cd scripts/foundation/fixtures && sha256sum -c --quiet "$BEFORE" ) && echo "all $(wc -l < "$BEFORE") files unchanged"
[ "$(cd scripts/foundation/fixtures && find . -type f | wc -l)" = "$(wc -l < "$BEFORE")" ] && echo "no file added"
# 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; even fully
# supplied mock declarations 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
# machine-readable form; process exit status is the only exit signal
node scripts/foundation-inspect.mjs --json scripts/foundation/fixtures/demo/demo-read-w1.json; echo "exit $?"
```
Step 5 (Jason's answer on clarity and acceptance) is darkwing's to record; this
report claims no acceptance.
## 5. Open item and freeze
Open: the C2 pattern-class ruling (§1 C2, options a/b/c). Until ruled the
oracle and therefore `test-foundation.sh` are red on exactly those four named
cases; I have not weakened, waived or removed them.
Frozen at the r2 manifest (`manifest-r2.json`, sha256 `2e8b5f19…4196`; 239
files) for independent review. Rocko changes nothing under the allowlist until
darkwing returns a ruling or reconciled findings. No staging, commit,
checkout/reset, push, charter/schema/verdict/coordinator-record edit, live or
native/sync work, credential or `~/.mosaic` read, network access or engine
launch occurred. C1 (Archify rev 3) remains HELD; no lane action taken.
@@ -0,0 +1,180 @@
# 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:0x21: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.
@@ -0,0 +1,80 @@
# FI-ROCKO-3 — authorized synthetic inspector build
Jason explicitly answered yes to Rocko building the offline synthetic inspector,
Filbert independently reviewing the code, and darkwing bringing an owner demo.
No push, live registration/permission changes, migration or fleet work authorized.
Requester/integration owner: darkwing. Sole implementation writer: rocko.
Independent reviewer: filbert (not yet dispatched to code review).
Issue: #53. Recheck current assignment compatibility; do not displace held owner work.
## Exact build contract
Repository: /home/jwoltje/src/mosaic-stack-dev-test
Charter: docs/plans/2026-09-06_foundation-inspector-charter.md, candidate 3
SHA-256 19b6721128a627a2032ffdb95ece2d50abe69a8f6d521e9eff8bbdaff22798b6
Incorporated r2 sections 513, overridden by charter (especially §10):
docs/plans/reviews/2026-09-06_foundation-inspector-rocko-feasibility-r2.md
SHA-256 f2f47fcfe22dca79f10f885b83d87a2f846fdb560425a4e20705c40ce4a123e1
Independent charter verdict: reviews/2026-09-06_foundation-inspector-filbert-verdict-r3.md
SHA-256 15f3d04cb74a7296be6a1a26f2c0907b9dd2b08fdd1eb0ef51c95c7a52ff0399
Source/schema baseline d4696d09eb1b5dcf1028f30db2cd63735f51cb16;
accepted map 7345f330fc6bfae5aa1d896c78cfb7cbe62efbae.
## Only authorized implementation paths
- scripts/foundation-inspect.mjs
- scripts/foundation/strict-json.mjs
- scripts/foundation/canonical.mjs
- scripts/foundation/resolve.mjs
- scripts/foundation/validate-record.mjs (test-only bridge)
- scripts/foundation/verify-schema.py (verification only)
- scripts/foundation/*.test.mjs
- scripts/foundation/fixtures/**
- scripts/test-foundation.sh
- Your build report only: docs/plans/reviews/2026-09-06_foundation-inspector-rocko-build.md
No edits to charter, incorporated notes, verdicts, CURRENT, shared logs, root/package
files, existing schemas, extension/native files, policies, runtime data or installations.
If another helper/path or specification decision is necessary, return a concrete
proposal rather than improvise outside the allowlist. Work only in these initially
unclaimed implementation paths; report any conflicting existing work before editing.
## Implementation and verification obligations
Implement the approved charter, not the superseded r1/r2 shorthand. Four supported
operations only; assignment.change has no allowed branch. All output is simulation-
labelled; no source of mock data becomes authenticated authority. Preserve exact
role/issuer/assignment/execution narrowing, supported-work scope, history/current
semantics, output privacy, closed shapes and lexical-versus-schema distinction.
Build coherent fixtures plus positive/negative tests for A1A8 and §§10.110.5.
Prepare simple commands for Jason's later A9 demo; do not claim owner acceptance.
Required verification: pinned schema/checker hashes; mandatory differential oracle
with existing explicit Python/jsonschema 4.26.0 (no installation or silent skip);
unit and isolated CLI/non-effect/privacy tests; syntax and diff checks; foundation
checker and all five repository suites. Report exact commands/toolchain/results.
Do not run native/sync tests against Dewey's installation. Use disposable synthetic
HOME/cwd/fixtures/data-root for new CLI tests. No credential, live-data or ~/.mosaic
reads/experiments, network access or engine launches. Tests may spawn test subprocesses;
the inspector must not. Do not report static flags or finite tests as sandbox proof.
## Shared Git and review handoff
Dewey owns the shared index per MS58-DW-1. NO staging, commit, checkout/reset or push.
Read-only git inspection is allowed. Other source changes may occur concurrently;
keep pinned contract inputs distinct from the measured integration HEAD.
Return FI-ROCKO-3 admission/blocker, then completion with exact changed-file list,
SHA-256 per file, baseline/integration HEAD, test receipts, A1A8 coverage, known
limitations and owner-demo commands. Freeze code/fixtures while Filbert reviews;
a delivered build is a review candidate, not accepted work. If blocked, report the
specific unmet gate; do not switch assignments or silently weaken tests.
Direct tagged reply is the return mechanism. Follow-up darkwing. No deadline or
automatic timer/approval. Implementation authorization does not authorize dependent
live-registry/runtime increments, source migration, issue closure or publication.
Transport (2026-09-06 17:02 UTC): FI-ROCKO-3 sent once to =rocko/mosaic-fleet;
exit 0, delivered. Await admission/blocker and then frozen build/test manifest.
FI-FILBERT-4 availability-only send to =filbert/default returned exit 2, unconfirmed.
No blind retry. Direct reply/manual steering is the return condition; no timer.
@@ -0,0 +1,320 @@
# 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 V1V5):
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 §§35, §7, §10.110.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. A1A8 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.110.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 00010999 in `time` fields (python refuses because glibc `%Y` is unpadded
so its round-trip fails; the inspector accepts calendar-valid years 19999).
- 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.
@@ -0,0 +1,98 @@
# FI-ROCKO-2 — feasibility reconciliation before charter freeze
Coordinator: darkwing. FI-ROCKO-1 admitted; original note SHA-256 verified as
92fa7b3de2591ba24fb184ed8edbabedd30c54498fdaf101649e36aaebabe9b9.
Its measured charter hash fdcdf4df8bf30b9fbfff960f9b1d4160ce7e6bbc4b8bb601a93cda13b56c8996
also matches. These are author/contributor checks, not independent approval.
Please return a corrected, self-contained recommendation at only
`docs/plans/reviews/2026-09-06_foundation-inspector-rocko-feasibility-r2.md`.
Preserve the original note. No implementation or other edits authorized.
## Required corrections and decisions
F1. The named accepted-map path is the foundation requirements document, not
2026-09-06_foundation-technical-map.md. Correct all affected citations against
actual committed bytes, including map lines 275/278 and proposal section.
`d4696d09:docs/plans/foundation-v1-candidate/FINDINGS.md` does not exist (git
cat-file check fails). Withdraw the AJV/fast-uri audit rationale unless supported
by an in-scope, exact source. No external fleet investigation to repair it.
package.json has no Node engines pin; distinguish measured host version from a
repository pin or a newly proposed inspector test baseline.
F2. records.schema.json/$defs/recordRef has kind/id/scope/revision, no digest.
Registry references have registry/id/revision/digest. decisionPayload.basisRef
is artifactRef, NOT a reference to a delegation decision. envelope.authorizationRef
is runtimeId, not recordRef. Workspace parent comes from scope, not payload.
createdAt has the candidate time validation, not arbitrary string acceptance.
The charter's initial generic reference/digest sentence needs the same distinction;
darkwing will correct it during integration. Specify how simulation declares any
external authorization/artifact inputs and their limits; do not silently treat
missing referenced evidence as valid or claim real authentication.
F3. Do not sort instruction arrays while claiming the accepted fingerprint rule:
README:268-285 explicitly preserves instruction order and check.py:115 sorts only
skills for those vectors. A new registry-content digest is a separately specified
restricted algorithm, not an established record-fingerprint rule. Prefer keeping
all input array order for the new mock content digest; distinguish structural
uniqueness and set intersection from serialization. Propose exact vectors.
F4. Workspace policyRef is required and must be project-policy. There is no fallback
to the registration role. Each registration's scopeRoleRef must resolve and bound
its optional registration restrictions: using restrictions alone omits the reviewed
role ceiling. Nullable registration restrictions mean no additional narrowing,
not absent mandatory role/policy authority. Likewise nullable mission/task narrowing
must not erase required intent/status/scope checks. Assignment has no restrictions
field. Explicit empty arrays remain denial. Distinguish missing required launch
policy from an explicitly modelled unrestricted narrowing layer; do not default
missing launchRestrictions to null and silently skip required policy.
F5. Define authority in both affected original and target scopes for reassignment,
not just target project membership. Approved decision outcome, actual delegation
recipient/subject bounds, reviewed ceilings and current original/target intent
must be checked or explicitly unsupported. A basis artifact is not automatically
an authorization decision. Caller-supplied runtime observations cannot establish
actual stopping/reconciliation. Prefer refusal/unresolved for all assignment-change
success paths in this first slice; useful negative previews need not implement an
authoritative change engine. Original selection always remains unchanged.
F6. Limit implemented preview operations explicitly: recommend work.read, file.read,
file.change permission previews plus a bounded assignment.change negative check.
Other recognized catalog operations should return unsupported-capability, never
exit 0 as if executable. Do not invent execution.stop in the 29-operation enum
(it is not there; the catalog contains execution.control). Align the closed output
schema with every emitted field (the note adds scope without defining it).
F7. Optional schema cross-check is insufficient for a hand-written validator.
check.py does not accept arbitrary bundle records as a validation API. Define a
required verification-only harness using the pinned candidate JSON Schema and
existing explicitly selected Python/jsonschema, with no dependency installation.
It must compare supported records/negative mutations, calendar/path boundaries,
conditionals and typed references. Runtime stays dependency-free if selected;
missing test dependency blocks verification rather than silently passing.
F8. find -newer alone is not a no-effect proof and output captures themselves write.
Separate harness artifacts from observed roots; compare bounded before/after path,
type, content and relevant metadata inventories, plus static import/I/O boundaries.
State that canaries do not prove absence of all reads or OS containment. Regular-file
opening must refuse symlinks/FIFOs before blocking or following unsafe targets;
specify Linux descriptor-based checks/size bounds without introducing live tests.
F9. Settle revision-history handling without inconsistent head-only/missing-predecessor
rules. Historical predecessor/decision references cannot all be treated as forbidden
stale active heads. Distinguish historical resolution from current-intent admission.
An explicit small revision-1-only supported subset is acceptable if later revisions
refuse unsupported-capability and the limitation/negative case is clear. Preserve
exact scope and duplicate/cycle checks; never silently invent the missing history.
## Return
Resolve D-A..D-J and F1..F9 into a concrete bounded recommendation, or identify the
remaining design choice precisely. No external investigation, code, dependencies,
commits, installation changes or contacts to Filbert. Do not displace the held
Archify assignment. Return FI-ROCKO-2 with corrected note hash and disposition per
finding. Darkwing owns integration; Filbert remains the later non-author reviewer.
Transport (2026-09-06 08:25 UTC): one FI-ROCKO-2 send to =rocko on mosaic-fleet;
exit 0, delivered. Await direct corrected-note/hash/disposition or blocker.
No deadline/timer or automatic acceptance. Follow-up darkwing.
@@ -0,0 +1,496 @@
# FI-ROCKO-2 — Foundation synthetic inspector: corrected feasibility note (r2)
Author: rocko (Claude Fable 5.1, Archify lane author seat). Requested by darkwing
(FI-ROCKO-2, 2026-09-06), reconciling the FI-ROCKO-1 note against darkwing's
coordinator source check. Issue: #53. Status: planning evidence only. This note
proposes; it does not approve, implement, or bind. It supersedes the r1 note for
every point where the two differ; r1 is preserved unchanged as history.
## 0. Admission and scope
**FI-ROCKO-2 is admitted. No blocker.** My held owner goal (Archify C1 rev 3,
awaiting Jason's rulings) is not displaced. This file is the only repository
write. No implementation, dependency, commit, push, checkout, live test,
credential read, fleet investigation, or contact with filbert occurred. Every
citation below was re-read from committed bytes with `git show` during this
task; the only unpinned inputs are the untracked charter draft and darkwing's
corrections note.
## 1. Pinned inputs
| Input | Identity |
|---|---|
| Technical map `docs/plans/2026-09-06_foundation-technical-map.md` (the accepted map) and `docs/plans/2026-09-06_foundation-map-handoff.md` | commit `7345f330fc6bfae5aa1d896c78cfb7cbe62efbae` |
| Requirements document `docs/plans/2026-09-06_agent-project-workspace-foundation.md` (R1R34), candidate `docs/plans/foundation-v1-candidate/{README.md, REVIEW.md, RUNTIME.md, records.schema.json, records.fixtures.json, fingerprint-vectors.json, check.py, semantic-model.py}`, `docs/plans/2026-09-06_foundation-phase2-contract.md`, `docs/plans/ROADMAP.md` | commit `d4696d09eb1b5dcf1028f30db2cd63735f51cb16` |
| Charter draft 1 `docs/plans/2026-09-06_foundation-inspector-charter.md` | untracked, SHA-256 `fdcdf4df8bf30b9fbfff960f9b1d4160ce7e6bbc4b8bb601a93cda13b56c8996` (unchanged since r1) |
| Corrections `docs/plans/reviews/2026-09-06_foundation-inspector-rocko-corrections.md` | untracked, SHA-256 `fe672fd6f0b745b5f64042a094f31463064ca436aeaeba956f9c15228df5f716` |
| r1 note `docs/plans/reviews/2026-09-06_foundation-inspector-rocko-feasibility.md` | untracked, SHA-256 `92fa7b3de2591ba24fb184ed8edbabedd30c54498fdaf101649e36aaebabe9b9` |
Citation form: `commit:path:line`. `cand/` abbreviates
`docs/plans/foundation-v1-candidate/`; `map` abbreviates
`7345f33:docs/plans/2026-09-06_foundation-technical-map.md`.
## 2. Disposition of F1F9
| Finding | Disposition | Where resolved |
|---|---|---|
| F1 wrong map path, nonexistent FINDINGS.md, phantom Node pin | **Accepted in full.** Citations corrected; AJV/fast-uri rationale withdrawn; measured host version separated from a proposed test baseline | §3, §4 |
| F2 reference shapes (recordRef no digest, basisRef artifactRef, authorizationRef runtimeId, workspace parent from scope, createdAt calendar rule) | **Accepted in full.** Bundle gains declared `artifacts` and `authorizations` simulation inputs; resolver rules rewritten against the schema | §5, §6 |
| F3 instruction-order digest | **Accepted.** New digest is named separately, preserves all array order, never claims the README 6.1 fingerprint rule; exact vectors supplied | §6.1 |
| F4 mandatory role/policy layers, assignment has no restrictions, no launch default | **Accepted in full.** Layer table rebuilt; role ceilings mandatory; execution layer must be explicitly modelled | §7 |
| F5 reassignment authority in both scopes; no success path | **Accepted.** Proposal mode yields only refused or unresolved; caller-supplied observations removed | §8 |
| F6 bounded operations, no `execution.stop`, closed output | **Accepted.** Four supported operations; `execution.stop` withdrawn (catalog has `execution.control`); output schema enumerates every field | §9, §10 |
| F7 required differential schema verification | **Accepted.** Mandatory Python/jsonschema harness; missing dependency fails, never skips | §12.1 |
| F8 honest non-effect tests, descriptor-based open | **Accepted.** Inventory diff on separated roots, static import boundary, `O_NOFOLLOW|O_NONBLOCK` open then `fstat` | §12.2, §5.3 |
| F9 revision handling | **Accepted.** Contiguous full history or nothing per identity; historical vs current-admission resolution classes | §6.3 |
No finding is disputed. Two places where I go slightly beyond the finding are
flagged inline (§9 exit class for unsupported operations; §6.1 ASCII limit on
mock-content paths).
## 3. Corrected repository facts (F1)
- The accepted map is the technical map at 7345f33. Its recommended increment
is `map:244-283`; exit classes `map:275-276`; "No npm/Turbo change is needed"
`map:278`; the inspector-must-not-bootstrap disposition `map:240`; the
cross-lane retasking scenario `map:290-314` with the adversarial acceptance
case at `map:305-314`. The document I cited in r1 under the map's name is the
requirements document (R1R34) at d4696d09; R-number citations stay valid
against that file, the map citations did not. Corrected throughout.
- `d4696d09:cand/FINDINGS.md` does not exist (`git cat-file -e` fails) and no
file in the pinned tree or in `docs/plans/*.md` mentions `ajv` or
`fast-uri`. **The audit rationale is withdrawn.** The dependency-free
recommendation now rests only on in-scope facts: `package.json` declares one
dependency (pi 0.84.4), the map forbids an npm change for this boundary
(`map:278`), and the candidate's own checker states it "never installs
dependencies" (`d4696d09:cand/check.py:4`).
- There is no repository Node pin: no `engines` field, no `.nvmrc`,
`.node-version`, or `.tool-versions`, and no Node image pin in the build
scripts. The **measured host** runtime is Node v26.8.1, Python 3.12.8,
jsonschema 4.26.0. These are measurements, not pins.
- Proposed inspector test baseline (a new charter decision, not an existing
pin): the suite records `node --version` in its header and refuses to run
below a stated minimum. The features used (`node:test`, `node:crypto`,
`TextDecoder` with `fatal: true`, `fs.constants.O_NOFOLLOW`) are all present
in Node 22 LTS; I recommend the charter state "Node ≥ 22, measured on
v26.8.1" and that no `engines` field be added by this increment.
## 4. Language and dependency recommendation (D-A resolved)
Node ESM, zero new runtime dependencies, hand-rolled closed validation derived
field-by-field from `d4696d09:cand/records.schema.json`, **verified
differentially by a mandatory Python/jsonschema harness** (§12.1). The
Python-stdlib runtime alternative is closed: the candidate's `check.py` is a
script that executes assertions on import, not a validation API
(`d4696d09:cand/check.py:66-96` run at module level), so neither language
gets a free validator; Node keeps the CLI surface consistent with `scripts/`.
## 5. Bundle contract (exact fields, proposed to freeze)
Closed objects throughout; unknown keys refuse; duplicate JSON keys refuse at
parse time; identifiers follow `$defs/id` (`^[a-z0-9][a-z0-9._-]{0,63}$`).
```
{
"bundleVersion": 1,
"kind": "foundation-inspector-bundle",
"simulation": true, // literal true or refuse
"records": [ <envelope record>, ... ], // ≤256, supported kinds only (§10)
"registries": [ <registryEntry>, ... ], // ≤256
"artifacts": [ {runId, artifactId, digest}, ... ], // ≤256, declared only
"authorizations": [ <runtimeId>, ... ], // ≤256, declared only
"selection": {
"agentId": <id>, "projectId": <id>, "workspaceId": <id>,
"assignmentRef": <recordRef> | null,
"execution": { "kind": "unrestricted-simulation" }
| { "kind": "restrictions", "restrictions": <restrictions> }
},
"operation": { "name": <supported operation>, "target": <target> | null },
"proposal": null | {
"kind": "assignment-change",
"requesterAgentId": <id>,
"subjectAssignmentRef": <recordRef>,
"targetTaskRef": <recordRef>,
"delegationRef": <recordRef> | null,
"changeDecisionRef": <recordRef> | null,
"message": <string, ≤4000> | absent // informational, never authority
}
}
```
### 5.1 Type corrections (F2)
- `<envelope record>` is exactly `$defs/envelope`: `authorizationRef` is a
`runtimeId` (UUID v4 pattern), not a recordRef; `supersedes` is `null` at
revision 1 and a recordRef otherwise (schema `allOf`); `createdAt` is
`$defs/time` (`YYYY-MM-DDTHH:MM:SS.mmmZ`) **and** must be a real calendar
instant with the same round-trip rule as `check.py:36-44` (2026-02-30
refuses). It still takes no part in calculations.
- `<recordRef>` = `{kind, id, scope, revision}`. **No digest.** Record identity
is exact-match on those four fields; record content integrity is not
digest-checked in increment 1 (stated as a limitation in output docs).
- `<registryRef>` = `{registry, id, revision, digest}`; `<artifactRef>` =
`{runId, artifactId, digest}`. `decision.basisRef` and `evidenceRefs` are
artifactRefs and are **evidence pointers, not authority**.
- Workspace ownership comes from `scope`: a workspace record has
`scope.kind = workspace`, `scope.projectId` names the owning project, and
`id` must equal `scope.workspaceId`; a project's `id` must equal
`scope.projectId` (`d4696d09:cand/README.md:64`). Registrations carry
project or workspace scope per the schema's conditional.
### 5.2 Simulation-only external inputs (F2)
`artifacts` and `authorizations` are the only way the bundle can satisfy an
`artifactRef` or `authorizationRef`. They are **declared, not verified**: the
inspector checks presence and exact match only, never content, signature, or
liveness, and the output labels them `declared-simulation-inputs`. A missing
declaration refuses `missing-state`; it is never treated as valid. Nothing in
the bundle asserts authentication; the inspector emits
`"authentication": "not-modelled"` in every result.
### 5.3 Bounds and file handling (F8)
| Bound | Value |
|---|---|
| File size | ≤ 1 MiB, checked from `fstat` **before** reading |
| `records`, `registries`, `artifacts`, `authorizations` | ≤ 256 each |
| Any array | ≤ 1024 (`d4696d09:docs/plans/2026-09-06_foundation-phase2-contract.md:116`) |
| Nesting depth | ≤ 32 |
| Strings | ≤ 4096 bytes; relative paths per `$defs/relativePath` and the `mosaic-relative-path` format (≤4096 UTF-8 bytes, no Cc/Cf/Cs, no backslash, no empty/`.`/`..` segment; `check.py:47-64`) |
Open sequence (Linux, descriptor-based): `fs.openSync(path, O_RDONLY |
O_NOFOLLOW | O_NONBLOCK | O_CLOEXEC)`; a symlink fails at open with `ELOOP`
and a FIFO cannot block; then `fstatSync(fd)` must report a regular file and a
size within bound; then read exactly `size` bytes from the descriptor and
refuse if more arrive. Any failure is exit 4 `io-failure` naming only the path
as given on argv. This is a design statement; no live test was run.
## 6. Digest and reference algorithms
### 6.1 Mock-content digest (F3): `inspector-content-digest/1`
This is a **new, separately named** restricted algorithm for content-bearing
registry entries only. It is not the README 6.1 launch-fingerprint projection,
which preserves instruction order and ID-sorts skills
(`d4696d09:cand/README.md:268-285`, `check.py:115`); the inspector computes no
launch fingerprint in increment 1.
Rule: domain = objects, arrays, ASCII strings, booleans, null, safe integers;
anything else refuses `unsupported-capability`. Object keys sorted by code
unit; compact separators; **all array order preserved**; digest =
`"sha256:" + hex(SHA-256(UTF-8 bytes))`. Structural uniqueness (`uniqueItems`)
and set intersection operate on parsed values and are independent of
serialization. Consequence flagged: pathGrant paths inside mock content must be
ASCII in increment 1, while record and target paths may be non-ASCII per the
candidate regex (which accepts `é/x`); the charter should state this asymmetry.
Exact vectors (computed with Python stdlib `json.dumps(sort_keys=True,
separators=(",",":"))`, the same primitives as `check.py:116`):
| Vector | Content | Canonical | Digest |
|---|---|---|---|
| V1 | `{"restrictions":{"operations":["work.read","file.read"],"readPaths":[{"root":"workspace","path":null}],"writePaths":[],"network":"none","endpointRefs":[]}}` | `{"restrictions":{"endpointRefs":[],"network":"none","operations":["work.read","file.read"],"readPaths":[{"path":null,"root":"workspace"}],"writePaths":[]}}` | `sha256:0bc44e14fd8354a8a85be879306a54881da7a0cb4d3dcf1f88bc4bc08a40dc9c` |
| V2 | V1 with `operations` reversed | `…"operations":["file.read","work.read"]…` | `sha256:63817bffc57803ca6ac5df971aa0a160d4be73646394b3bc536578bd66c82660` (differs from V1: order is significant) |
| V3 | V1 plus `file.change` and `writePaths:[{"root":"workspace","path":"docs"}]` | `{"restrictions":{"endpointRefs":[],"network":"none","operations":["work.read","file.read","file.change"],"readPaths":[{"path":null,"root":"workspace"}],"writePaths":[{"path":"docs","root":"workspace"}]}}` | `sha256:d538c865808cfe7665956615fb48f69819baa0833626d1ef6e1cb3614acbc7da` |
| V4 | V1 with a float `1.0` anywhere | refuse | `unsupported-capability` |
| V5 | V1 with a non-ASCII string | refuse | `unsupported-capability` |
Registry entry shapes: declared `{registry, id, revision, digest}` for harness,
settings, context-content, endpoint; content-bearing
`{registry, id, revision, digest, content:{restrictions}}` for scope-role,
agent-policy, project-policy, where `digest` must equal the V-rule digest of
`content` or the bundle refuses `invalid-request`. The candidate defines no
registry content shapes; `{restrictions}` is a simulation-only stand-in (D-E).
### 6.2 Reference resolution
Index on `(kind, id, scope)`; duplicate `(kind, id, scope, revision)` refuses
`invalid-request`. Every recordRef resolves by exact four-field match; every
registryRef by exact four-field match including digest; every artifactRef and
authorizationRef by exact match against the declared lists (§5.2). Absent →
`missing-state`; kind mismatch against the schema's `const` constraints (for
example `policyRef` not `agent-policy`) → `invalid-request`.
Graph rules (all refuse without repair, naming the rule):
- Project `id` = `scope.projectId`; workspace `id` = `scope.workspaceId`; the
workspace's `scope.projectId` must resolve to an active project.
- A workspace registration's `projectRegistrationRef` must resolve to an
**active** project registration in the workspace's owning project for the
same `agentId` (`README:65`).
- A workspace mission's `parentMissionRef` must be a project mission in that
project; project missions have no parent (`README:66-68`).
- A task's `missionRef` resolves in the selected project; `dependencies` are
tasks; cycle checks run over exactly three edge sets, independently:
`task.dependencies`, `mission.parentMissionRef`, `supersedes`. Excluded from
cycle checks: `intentRef`, `subjectRefs`, `projectRegistrationRef`,
`delegationRef`, all registryRefs and artifactRefs.
- Cross-project execution selection refuses (`README:71`).
### 6.3 Revision history (F9, D-J resolved)
Per identity `(kind, id, scope)` the bundle carries either **exactly one
record at revision 1** or a **complete contiguous chain** 1..n where each
revision r > 1 has `supersedes = {kind, id, scope, revision: r-1}`. A chain with
a missing predecessor, a skipped number, or two records superseding the same
predecessor refuses `invalid-request`; the inspector never invents history.
Head = highest revision.
Two resolution classes:
- **Current-admission references** must name the head: `selection.*`,
`assignment.taskRef`, `assignment.intentRef`, `task.intentRef`,
`task.missionRef`, `task.dependencies`, `mission.parentMissionRef`,
`registration.projectRegistrationRef`, `registration.delegationRef`, and every
`proposal` ref. Naming a non-head revision refuses `stale-revision`.
- **Historical references** may name any revision present in the bundle:
`supersedes` and `decision.subjectRefs`. Absent → `missing-state`.
This satisfies charter A3's stale-reference case with a real fixture (task
intent pointing at decision rev 1 while rev 2 exists) without treating all
history as forbidden.
## 7. Permission algorithm (F4, D-D, D-F resolved)
Supported operations for permission preview: `work.read`, `file.read`,
`file.change` (§10). Taskless set = `{work.read, file.read}` exactly
(`d4696d09:cand/semantic-model.py:24`); `file.change` requires
`selection.assignmentRef`.
| # | Layer | Source | Mandatory? |
|---|---|---|---|
| L1 | agent ceiling | `agent-definition.policyRef``agent-policy` content | yes; `agent-definition.status` must be `enabled` |
| L2 | project registration | active registration in `projectScope(projectId)` for `agentId`: **`scopeRoleRef``scope-role` content is the ceiling**; `restrictions` (nullable) narrows it further | yes (`README:99-101`) |
| L3 | workspace registration | active registration in `workspaceScope(projectId, workspaceId)` for `agentId`, `projectRegistrationRef` = L2's exact record; `scopeRoleRef` ceiling; `restrictions` nullable narrowing | yes |
| L4 | project policy | `project.policyRef``project-policy` content | yes |
| L5 | workspace policy | `workspace.policyRef``project-policy` content (schema `const`) | yes; **no fallback to L3's role** |
| L6 | assignment binding | one `assignment` = `selection.assignmentRef`; `status: selected`, `agentId` = selected agent, `taskRef` head in the selected workspace scope, `intentRef` → approved decision (head) whose `subjectRefs` include the task | required for non-taskless operations; contributes checks only, **it has no restrictions field** |
| L7 | task | `task.restrictions` (nullable = no narrowing); independently `task.status ∈ {ready, active}` and `task.intentRef` → approved head decision | status/intent checks mandatory whenever L6 applies |
| L8 | mission chain | each mission from `task.missionRef` up the parent chain: `restrictions` (nullable = no narrowing); `status: active` mandatory | as L7 |
| L9 | execution | `selection.execution`: `restrictions` narrows; `unrestricted-simulation` is an explicit no-narrowing marker | yes; absent or null refuses `missing-state` (`README:132`, `semantic-model.py:21`) |
Intersection: operations as set intersection; explicit empty array = none
(`README:101`); `restrictions: null` on L2/L3/L7/L8 = no additional narrowing
(`README:100`) but never satisfies a mandatory ceiling or status/intent check.
Path grants: `path: null` = whole root (`README:102`); component-prefix
matching on parsed segments (`semantic-model.py:30-34`); the intersection of
two grant lists keeps, for each pair where one grant is a segment-prefix of
the other, the narrower. Network: `none` dominates; `approved-endpoints`
intersect by exact endpoint registryRef. No union across assignments
(`contract:172`); exactly one assignment consulted (`README:134`).
Refusal precedence: parse/shape/bounds (exit 2) → graph incoherence (exit 2)
→ unsupported operation or kind (exit 2) → mandatory layer or declaration
missing (exit 3, `missing-state`) → registration/role absent or revoked
(exit 3, `not-authorized`) → status/intent not current (exit 3,
`not-authorized`, rule named) → operation or target outside the intersection
(exit 3, `not-authorized`). First failure ends evaluation.
## 8. Proposal mode: assignment-change negative check (F5, D-G, D-I resolved)
Increment 1 implements **no success path**. The evaluation order is fixed and
every branch ends in `refused` or `unresolved`; `allowed` is unreachable by
construction, and a unit test asserts that.
1. Original scope authority: the requester holds an active L2/L3 registration
in the subject assignment's workspace whose role ceiling ∩ restrictions
include `assignment.change`. Else `not-authorized` /
`requester-lacks-original-scope-authority`.
2. Target scope authority: the same in the target task's project and
workspace. Else `not-authorized` / `requester-lacks-target-scope-authority`.
3. Delegation: `delegationRef` → head decision, `decisionKind: delegation`,
`outcome: approved`, `delegatedOperations ∋ assignment.change`,
`subjectRefs` include the requester's agent-definition **and** the subject
assignment or its task (recipient and subject bounds). Else `not-authorized`
/ `delegation-not-applicable`. A `message` with no delegation refuses with
rule `message-is-not-authority` (`map:310`).
4. Recorded change: `changeDecisionRef` → head decision,
`decisionKind: assignment-change`, `outcome: approved`, `subjectRefs` include
the subject assignment and the target task; its `basisRef` must be a
declared artifact but **is not itself authorization**. Else
`not-authorized` / `change-not-recorded`.
5. Current intent: the subject assignment's `intentRef` and the target task's
`intentRef` resolve to approved head decisions. Else `stale-revision` or
`not-authorized` as applicable.
6. If 15 pass: result `unresolved`, reason `unknown-effects`, rule
`runtime-reconciliation-required`. Stopping and reconciliation are runtime
facts (`map:311-314`); the bundle has no field to assert them and the r1
`runtimeObservations` field is withdrawn.
In every branch the output echoes `selection.assignmentRef` unchanged as
`selectedAssignmentRef` and the bundle bytes are untouched. Requester model is
agent-only in increment 1 (D-G); delegation chains are not modelled (D-I).
## 9. Output and exit classes (F6)
Closed result schema; every emitted field is listed here and nothing else is
emitted:
```
{
"disclaimer": "SYNTHETIC PREVIEW — NO LIVE EFFECTS",
"preview": "preview: no live registrations or permission grants", // REVIEW.md:126
"bundleVersion": 1,
"authentication": "not-modelled",
"declaredSimulationInputs": { "artifacts": <count>, "authorizations": <count> },
"result": "allowed" | "refused" | "unresolved" | "invalid",
"reason": <reason code>,
"rule": <rule name> | null,
"selection": { "agentId", "projectId", "workspaceId", "assignmentRef" },
"operation": { "name", "target" },
"consulted": [ <recordRef | registryRef>, ... ], // identities only, sorted
"proposal": null | { "result", "reason", "rule", "selectedAssignmentRef" }
}
```
Text output is a pure rendering of this object; both begin with the
disclaimer, on every exit class. No payload bodies, no parser input bytes
(byte offset and error class only), no timestamps, no random ids, keys sorted.
Reason codes: the RUNTIME closed set (`d4696d09:cand/RUNTIME.md:97`) plus
inspector-only `unsupported-kind` and `io-failure`, documented as not runtime
API codes. Exit classes (`map:275-276`, charter): 0 allowed; 2 malformed,
graph-incoherent, unsupported kind or operation; 3 refused or unresolved; 4
I/O failure. Flag: I place unsupported operations in exit 2 with reason
`unsupported-capability` because they are not simulated permission refusals;
if darkwing prefers exit 3 for them, nothing else in this note changes (D-C).
## 10. Supported kinds and operations (F6)
Record kinds: `agent-definition`, `project`, `workspace`, `registration`,
`mission`, `task`, `assignment`, `decision`. `session`, `context-source`,
`adapter-capability` present in `records` refuse `unsupported-kind`.
Operations (from the 29-name catalog, `d4696d09:cand/records.schema.json`
`$defs/operation`): permission previews for `work.read` (target `null`),
`file.read` and `file.change` (target `{root:"workspace", path}`); proposal
negative check for `assignment.change` (§8). The other 25 catalog names are
recognized and refuse `unsupported-capability`; never exit 0. `execution.stop`
does not exist in the catalog (`execution.control` does); the r1 remark is
withdrawn. Names outside the catalog refuse `invalid-request`.
## 11. Physical paths (D-B, D-H resolved)
Unchanged from r1: `scripts/foundation-inspect.mjs` (CLI, future
`packages/mosaic`); `scripts/foundation/{strict-json,canonical,resolve}.mjs`
(pure, future `packages/config`; import only each other and `node:crypto`);
`scripts/foundation/fixtures/`; `scripts/foundation/*.test.mjs`;
`scripts/test-foundation.sh`; plus the new verification harness
`scripts/foundation/verify-schema.py` (§12.1). No `packages/` scaffolding, no
root file, no `.sh` shim, nothing imported from `scripts/mosaic-config.mjs`
(`map:240`). Layout follows the ROADMAP M20 doctrine
(`d4696d09:docs/plans/ROADMAP.md:142-159`).
## 12. Test plan
### 12.1 Required differential schema verification (F7)
`scripts/foundation/verify-schema.py`: Python 3 stdlib plus the already
installed `jsonschema` (measured 4.26.0); **no installation**. If `import
jsonschema` fails the suite exits non-zero with `verification dependency
missing`; it never skips. The harness re-declares the two format checkers
exactly as `check.py:36-64` (calendar round-trip `date-time`,
`mosaic-relative-path`), loads the pinned `cand/records.schema.json` from the
tree, and compares, for every document in a corpus, the jsonschema verdict with
the Node validator's verdict (obtained by running
`node scripts/foundation/validate-record.mjs` over the corpus and reading its
JSON verdict list). Any disagreement fails.
Corpus: every fixture record; the candidate's own `records.fixtures.json`
cases (schema-valid and invalid) for the eight supported kinds; and a mutation
set generated deterministically from each valid record: drop each required
field; add one unknown key at each object level; `createdAt` = 2026-02-30 and
2028-02-29; paths `../x`, `a//b`, `a/./b`, `/abs`, backslash, a control
character, 4097 bytes, `é/x` (must be **accepted** by both); revision 1 with
non-null `supersedes`; revision 2 with null `supersedes`; approved delegation
with empty `delegatedOperations`; non-delegation with non-empty
`delegatedOperations`; `network: none` with an endpoint; `approved-endpoints`
with none; `status: ended` with null `endReason` and vice versa; each typed
reference with the wrong `kind`/`registry`. The runtime remains
dependency-free; only verification needs Python.
### 12.2 Non-effect and privacy observations (F8)
- Roots are separated: observed roots `$SANDBOX/home`, `$SANDBOX/cwd`,
`$SANDBOX/fixtures`, `$SANDBOX/data-root`; harness writes go only to
`$SANDBOX/harness`. The CLI runs with `env -i PATH=… HOME=$SANDBOX/home
NO_COLOR=1`, cwd `$SANDBOX/cwd`, `MOSAIC_CONFIG` unset.
- Inventory before and after every invocation over each observed root:
`find -printf '%p %y %s %m %U %i\n' | sort` plus SHA-256 of every regular
file; compared exactly. A canary config path under `home/.config/mosaic-dev`
is asserted absent after a missing-file run (no bootstrap, A8).
- Static boundary: a unit test reads the three pure modules and asserts their
import specifiers are exactly the allowed set and that `process`, `fs`, and
`Date` do not appear; a second asserts the CLI imports no `mosaic-config`.
- Canaries (`CANARY-DO-NOT-PRINT-n` in every unrelated payload and in the
second workspace's records) are grepped from all captured output. Stated
limit: canaries and inventories demonstrate this tool's bounded behaviour on
these inputs; they do not prove absence of all reads or OS-level
containment (charter test-plan paragraph).
- Determinism: each fixture runs twice, byte-identical; `--json` and text agree
on `result`/`reason`/`rule`; golden files compared exactly.
### 12.3 Units (`node --test`)
Canonicalizer V1V5; strict JSON (duplicate key, depth, size, fatal UTF-8);
each graph rule in §6.26.3; each layer in §7 including "null restrictions do
not satisfy a mandatory ceiling", "empty array is none", "no union across
assignments", "missing execution layer refuses"; §8 steps 16 and the
`allowed`-is-unreachable assertion.
## 13. Fixtures and the first demonstration
`demo.bundle.json`: project P1 with workspaces W1 and W2; project P2; agent A
enabled, registered in P1 and W1 only, with scope-role V1 (reader) at W1;
one active mission and one ready task in W1 with approved plan-approval
intents; one selected assignment for A; agent B registered in P2 with a
delegation decision that does not cover `assignment.change`; all revisions 1;
a second variant carries decision rev 1→2 for the stale case.
| Fixture | Expected |
|---|---|
| `demo-read-w1` | 0 allowed `file.read docs/notes.md` |
| `demo-change-w1-refused` | 3 not-authorized, role ceiling V1 lacks `file.change` |
| `demo-read-w2` | 3 not-authorized, `workspace-registration-missing`, no W2 payload text |
| `demo-cross-project` | 3 not-authorized, cross-project selection |
| `demo-reassign-message-only` | 3 not-authorized, `message-is-not-authority`, selection unchanged |
| `demo-reassign-fully-recorded` | 3 unresolved, `unknown-effects`, `runtime-reconciliation-required` |
| `neg-stale-intent` | 3 stale-revision (intent names decision rev 1, rev 2 present) |
| `neg-missing-predecessor`, `neg-fork`, `neg-duplicate-identity`, `neg-cycle-{task,mission,supersedes}`, `neg-wrong-owner` | 2 invalid-request, rule named |
| `neg-no-execution-layer`, `neg-missing-role-content`, `neg-undeclared-artifact` | 3 missing-state |
| `neg-empty-ops`, `neg-two-assignments` | 3 not-authorized |
| `neg-unsupported-op-execution.control`, `neg-unsupported-kind-session` | 2 unsupported-capability / unsupported-kind |
| `neg-unknown-key`, `neg-dup-json-key`, `neg-bad-utf8.bin`, `neg-bad-path`, `neg-bad-calendar` | 2 invalid-request |
| symlink, FIFO, missing file | 4 io-failure, no bootstrap |
## 14. Resolved decisions D-A..D-J
| Id | Resolution |
|---|---|
| D-A | Node ESM, zero runtime deps; Python/jsonschema for mandatory verification only (§4, §12.1) |
| D-B | `scripts/foundation/` with M20 owner headers; no `packages/` (§11) |
| D-C | Graph incoherence and unsupported kind/operation → exit 2; permission refusal/unresolved → 3. Only open sub-choice: exit class for `unsupported-capability` operations (§9 flag) |
| D-D | Taskless = `{work.read, file.read}`; `work.propose` is not implemented at all in increment 1 (§10) |
| D-E | Registry content = `{restrictions}` simulation stand-in, digest per §6.1 |
| D-F | `selection.execution` is mandatory and explicit; no null default (§7 L9) |
| D-G | Requester is an agent with registrations in both scopes (§8) |
| D-H | `scripts/foundation-inspect.mjs`, no `.sh` shim |
| D-I | Delegation: recipient and subject bounds checked; no chains (§8 step 3) |
| D-J | Revision-1-only or complete contiguous chain; historical vs current-admission classes (§6.3) |
Remaining design choice for darkwing, stated precisely: whether unsupported
catalog operations exit 2 or 3 (§9). Everything else in this note is a
concrete recommendation with no open alternative.
## 15. Feasibility verdict
Still feasible as a bounded, dependency-free increment. The corrections
increase scope in three places: mandatory role ceilings and execution layer
(§7), the full-history resolver with two reference classes (§6.3), and the
required differential verification harness (§12.1). None requires an npm
change, a package move, live state, or runtime coupling. The largest new risk
is the differential harness itself drifting from the candidate checker's
format semantics; re-declaring the two format checkers verbatim from
`check.py:36-64` and asserting the same four sentinel cases (`check.py:66-69`)
is the mitigation.
This note is evidence for darkwing's charter. It is not approval, and it
authorizes no implementation.
@@ -0,0 +1,466 @@
# FI-ROCKO-1 — Foundation synthetic inspector: measured feasibility note
Author: rocko (Claude Fable 5.1, Archify lane author seat). Requested by: darkwing
(FI-ROCKO-1, 2026-09-06). Issue: #53. Status: planning evidence only. This note
proposes; it does not approve, implement, or bind. Every choice below is a
recommendation for darkwing to accept, alter, or reject in the frozen charter.
## 0. Admission
**FI-ROCKO-1 is admitted. No blocker.**
- Compatibility: my current owner goal (Archify C1 rev 3, HELD for Jason's
T2/T3 rulings) is a waiting state with no lane action due; this note displaces
nothing. I take no supervisory authority over darkwing, filbert, or Jason's
queue; Jason may veto or discard this note at any time.
- Authority basis observed, not assumed: `docs/plans/CURRENT.md` (working tree)
records Jason's acceptance of the map and "continue with filbert/rocko"; the
charter draft restates it. I did not verify this with Jason directly.
- Scope honoured: this file is the only repository write. No commit, push,
checkout, reset, live/runtime test, credential read, or `~/.mosaic`
investigation was performed. Dewey's `extensions/**`, `.pi/**`, and scripts
were not touched. Filbert's verdict files were not opened for editing.
## 1. Pinned inputs
| Input | Identity | How read |
|---|---|---|
| Accepted map `docs/plans/2026-09-06_agent-project-workspace-foundation.md` | commit `7345f330fc6bfae5aa1d896c78cfb7cbe62efbae` | `git show 7345f33:…` |
| Source/plan baseline (candidate schema, semantic-model.py, check.py, README, REVIEW, RUNTIME, phase-2 contract, ROADMAP, foundation plan) | commit `d4696d09eb1b5dcf1028f30db2cd63735f51cb16` | `git show d4696d09:…` |
| Charter draft 1 `docs/plans/2026-09-06_foundation-inspector-charter.md` | untracked; SHA-256 `fdcdf4df8bf30b9fbfff960f9b1d4160ce7e6bbc4b8bb601a93cda13b56c8996` at write time | working tree |
| Filbert map verdict (FM-FILBERT-1) | SHA-256 `6b08c6fac0718d3db527cf9ffbfab49407e7b289d09782f5d1d0e26493eaabb3` (as cited in the charter) | read only |
The charter is a moving draft: an earlier read in this session hashed to
`9c065ef1…`. Recommendations below target the `fdcdf4df…` text. If the frozen
charter differs materially, this note must be re-checked, not assumed valid.
Citations use `commit:path:line`. `cand/` abbreviates
`docs/plans/foundation-v1-candidate/`.
## 2. Repository facts that constrain the design
- Host toolchain: Node v26.8.1 with `node:test` available; Python 3.12.8 with
`jsonschema` 4.26.0 importable. `package.json` declares one dependency
(pi 0.84.4); no `node_modules` is present in the tree. `RELEASE` = 0.0.12.
- `scripts/` is flat; no `packages/` tree exists yet. ROADMAP places the
package layout under M20 (`d4696d09:docs/plans/ROADMAP.md:114`) with the
layout doctrine and phase-1 sequencing at `:142-145` and the target tree at
`:152-159` (`packages/config` at `:159`).
- The map's recommended increment forbids npm or Turbo changes
(`7345f33:docs/plans/2026-09-06_agent-project-workspace-foundation.md:278`)
and proposes exit classes 0/2/3/4 (`:275`).
- Existing validation idiom is hand-rolled and closed: `scripts/mosaic-task.mjs`
(`rejectUnknownKeys`, `fail(2, …)`). `scripts/mosaic-config.mjs` reads
`$MOSAIC_CONFIG` (`:42-43`) and refuses symlinks (`:54`); importing it runs
config resolution, which the charter forbids for the inspector.
- Existing suite style: `scripts/test-config.sh` uses a `mktemp` sandbox,
`check`/`expect_exit` helpers, and `NO_COLOR`.
- `cand/FINDINGS.md` records an `ajv`/`fast-uri` audit concern; the candidate's
own checker uses Python `jsonschema` (`cand/check.py`).
- The candidate's fingerprint rule is restricted-domain canonicalization, not
full RFC 8785 (`d4696d09:cand/README.md:265-288`, ASCII-only vectors
`:281-282`; `check.py` sorts keys, uses compact separators, ASCII-only,
sorts skills by id, digest = `"sha256:" + hex(SHA-256(UTF-8))`).
## 3. Language and dependency pin (recommendation)
**Recommend: Node ESM (`.mjs`), zero new dependencies, hand-rolled closed
validation.** Pin: the repository's existing Node engine (v26.8.1 on host); no
`package.json` change; no `ajv`, no `jsonschema` at runtime.
Why:
- Matches the map (`:278`, no npm/Turbo change) and the repo's validation idiom.
- Avoids the `ajv`/`fast-uri` audit issue and avoids adding a runtime dependency
for a preview tool that must be reproducible offline.
- Node gives `TextDecoder('utf-8', { fatal: true })` for malformed-UTF-8
refusal, `node:crypto` for SHA-256, and `node:test` for units, all built in.
- A hand-rolled closed validator is smaller than the candidate schema but must
be **derived from** `cand/records.schema.json` field-by-field. To keep it
honest, the test suite should run the Python candidate checker over every
fixture bundle's records as a cross-check when `python3 -c "import jsonschema"`
succeeds, and skip with a visible notice otherwise (see §9).
Alternative (viable, not preferred): Python 3.12 stdlib only, reusing
`check.py`'s canonicalizer verbatim. Rejected because the CLI surface of the
stack is Node/bash and because the charter says not to promote the author-only
Python model into the inspector. This is unresolved decision D-A.
Explicitly not recommended: JSON Schema at runtime via `ajv` (audit issue,
dependency) or via Python `jsonschema` in a Node CLI (two runtimes).
## 4. Physical source paths (recommendation, M20-consistent)
No `packages/` scaffolding in this increment. Files land in `scripts/`, which
is the existing flat layout, with a comment header naming the logical owner so
M20 phase 1 can move them without rewriting.
| Path | Logical owner (M20 target) | Contents |
|---|---|---|
| `scripts/foundation-inspect.mjs` | `packages/mosaic` (CLI presentation) | argv parsing, file read, output rendering, exit classes |
| `scripts/foundation/strict-json.mjs` | `packages/config` | strict JSON reader: fatal UTF-8, duplicate-key refusal, depth/size limits, byte-offset-only errors |
| `scripts/foundation/canonical.mjs` | `packages/config` | restricted-domain canonicalizer + `sha256:` digest, out-of-domain refusal |
| `scripts/foundation/resolve.mjs` | `packages/config` | bundle validation, reference resolution, graph checks, permission intersection, proposal evaluation. Pure: no I/O, no env, no clock |
| `scripts/foundation/fixtures/*.json` | test data | demo bundle plus negative fixtures |
| `scripts/test-foundation.sh` | suite | sandboxed CLI/privacy/non-effect suite, invokes `node --test scripts/foundation/*.test.mjs` |
| `scripts/foundation/*.test.mjs` | unit tests | `node:test` units for the three pure modules |
Rules:
- `resolve.mjs`, `canonical.mjs`, `strict-json.mjs` import only each other and
`node:crypto`. Never `mosaic-config.mjs`, never `process.env`, never `Date`.
- `foundation-inspect.mjs` is the only file that touches `process.argv`,
`fs`, `stdout`, `stderr`, and `process.exit`. It reads `process.env` only to
honour `NO_COLOR`; it never reads `MOSAIC_CONFIG`, `HOME`, or the data root.
- Root stays bootstrap-only (AGENTS.md invariant 1): nothing is added to root.
- The command name `mosaic foundation inspect <bundle.json>` from REVIEW
(`d4696d09:cand/REVIEW.md:123`) is the eventual `packages/mosaic` surface.
In this increment the wrapper is `scripts/foundation-inspect.mjs`; a
`foundation-inspect.sh` shim is unnecessary. Naming is decision D-H.
## 5. Bundle contract (exact fields, proposed to freeze)
One file, one closed object. Every object is closed: unknown keys refuse.
Duplicate keys refuse at parse time. All strings must be ASCII printable when
they participate in digests (§6); identifiers are `^[a-z0-9][a-z0-9-]{0,63}$`.
```
{
"bundleVersion": 1,
"kind": "foundation-inspector-bundle",
"simulation": true, // must be literally true; anything else refuses
"records": [ <record>, ... ], // candidate envelope records, ≤256
"registries": [ <registryEntry>, ... ], // ≤256
"selection": {
"agentId": "<id>",
"projectId": "<id>",
"workspaceId": "<id>",
"assignmentRef": <recordRef> | null,
"launchRestrictions": <restrictions> | null // simulated execution layer, D-F
},
"operation": { "name": "<one of the 29 operation names>", "target": <target> | null },
"proposal": null | {
"kind": "assignment-change",
"requesterAgentId": "<id>",
"subjectAssignmentRef": <recordRef>,
"targetTaskRef": <recordRef>,
"delegationRef": <recordRef> | null, // decision, decisionKind delegation
"changeDecisionRef": <recordRef> | null, // decision, decisionKind assignment-change
"message": "<string>" | absent, // informational only; never authority
"runtimeObservations": {
"originalExecutionStopped": true|false|null,
"effectsReconciled": true|false|null
}
}
}
```
`<record>` is exactly the candidate envelope (`d4696d09:cand/records.schema.json`):
`{schemaVersion:1, kind, id, scope, revision, createdAt, createdBy, supersedes,
authorizationRef, payload}`, closed. `createdAt` is carried and validated as a
string but never used in calculations (charter: no timestamps in results).
`<recordRef>` = `{kind, id, scope, revision}`; `<registryRef>` =
`{registry, id, revision, digest}`; `<restrictions>` = `{operations[],
readPaths[], writePaths[], network, endpointRefs[]}` with `pathGrant`
`{root:"workspace", path|null}`; all as defined in the candidate schema.
`<target>` for file operations: `{root:"workspace", path:"<relative>"}`. For
record operations: a `<recordRef>`. For operations that take no target: `null`.
An operation whose target shape does not match its name refuses `invalid-request`.
`<registryEntry>` has two shapes:
- Declared: `{registry, id, revision, digest}` for harness, settings,
context-content, endpoint. Existence and exact-match only.
- Content-bearing: `{registry, id, revision, digest, content}` for
`scope-role`, `agent-policy`, `project-policy`. `content` is
`{restrictions: <restrictions>}`; `digest` must equal the canonical digest of
`content` (§6) or the bundle refuses `invalid-request`. These are the
"separately identified mock policy inputs" the charter requires. The candidate
does not define registry content shapes; this is decision D-E.
Bounds (refuse `invalid-request` before any calculation):
| Bound | Value |
|---|---|
| File size | ≤ 1 MiB (aligns with RUNTIME frame limit `d4696d09:cand/RUNTIME.md:41` and contract `…phase2-contract.md:116`) |
| `records` | ≤ 256 |
| `registries` | ≤ 256 |
| Any array | ≤ 1024 items (contract `:116`) |
| Nesting depth | ≤ 32 |
| Any string | ≤ 4096 bytes; path strings ≤ 4096 bytes |
| Input file | regular file only; symlink, directory, FIFO, device refuse `invalid-request` (matches `mosaic-config.mjs:54` doctrine) |
| Path argument | exactly one positional bundle path; relative paths resolved against cwd but never searched; no defaults |
Explicitly absent by design: no `$ref`, no includes, no URLs, no `env`, no
`credentials`, no `authenticated`/`authorized` booleans anywhere. Presence of
any of those keys is an unknown-key refusal, not a warning.
## 6. Reference and digest algorithm
### 6.1 Canonical digest (restricted domain)
Implement `canonical.mjs` as the candidate's rule, not JCS:
1. Domain: objects, arrays, strings, booleans, null, and integers within
`Number.isSafeInteger`. Floats, `-0`, non-ASCII strings, control characters
other than those JSON must escape, and values outside the domain **refuse**
with `unsupported-capability`. This is stricter than JCS and is the documented
restricted domain (`d4696d09:cand/README.md:265-288`).
2. Object keys sorted by UTF-16 code unit order (same as `sort_keys=True` on
ASCII keys), compact separators, no whitespace.
3. Set-valued arrays are sorted by a stable key before serialization:
`skillRefs` by `id`, `instructionRefs` by `id`, `operations` lexically,
`readPaths`/`writePaths` by `path` with `null` first, `endpointRefs` by `id`.
Sequence-valued arrays (`dependencies`, `subjectRefs`, `evidenceRefs`) keep
order. The list of set-valued fields is enumerated in code and in the frozen
charter; anything not listed is a sequence.
4. Digest = `"sha256:" + lowercase hex SHA-256 of the UTF-8 bytes`.
5. Test vectors: reproduce the README's vectors (`:281-282`) and add one
out-of-domain vector per rejected class.
No claim of RFC 8785 conformance is made in code, docs, or output.
### 6.2 Reference resolution (bounded resolver, `resolve.mjs`)
Index build:
- Key `(kind, id, scope)` → list of revisions. Two records with the same
`(kind, id, scope, revision)` refuse `invalid-request` (duplicate identity, A3).
- `supersedes` chains must be contiguous from revision 1: revision *n* must
supersede exactly `(kind, id, scope, n-1)`; gaps, forks (two records
superseding the same predecessor), or a supersedes pointing outside the
identity refuse `invalid-request`. The bundle may carry only the head
revision if it carries no history at all for that identity (D-J).
- `id` must agree with `scope` per README `:64`; mismatch refuses.
Reference check (every `recordRef` and `registryRef` in every payload):
- Exact match on all fields; `digest` compared byte-for-byte after §6.1
recomputation for content-bearing entries. A ref to a superseded revision
refuses `stale-revision`. A ref to an absent identity refuses `missing-state`.
Kind mismatch (e.g. `policyRef` not pointing at `agent-policy`) refuses
`invalid-request`.
Graph rules (all refuse without repair; the violated rule name is emitted):
- `workspace.payload` must reference exactly one active `project` (README `:65`;
charter "exactly one project owns a workspace").
- A workspace `registration` for agent X must reference, via
`projectRegistrationRef`, an **active** project `registration` for the same
agent X in the owning project (README `:65`). Missing or revoked → refuse.
- `mission.parentMissionRef` must resolve to a mission in the same project;
a task's `missionRef` must resolve to a mission in the selected project.
- `assignment` must bind one task and one agent; `intentRef` must resolve to a
`decision` with `decisionKind ∈ {plan-approval, delegation, assignment-change}`
whose `subjectRefs` include the task. Otherwise `not-authorized`.
- Cycle checks (A3, "document which edges participate"): DFS over exactly three
edge sets, evaluated independently: (i) `task.dependencies`, (ii)
`mission.parentMissionRef`, (iii) `supersedes`. A cycle in any of them
refuses `invalid-request`. Edges deliberately excluded from cycle checks:
`intentRef`, `authorizationRef`, `evidenceRefs`, `subjectRefs`, all
`registryRef`s (they point outside the record graph).
- Cross-project execution selection refuses (README `:71`).
## 7. Permission algorithm
Inputs: the resolved graph, `selection`, `operation`. Output: `allowed` or
`refused` + reason code + violated rule + the identities consulted. Never the
payload bodies.
Taskless set: `{work.read, file.read}` (from `semantic-model.py`). Every other
operation requires `selection.assignmentRef` to be non-null (D-D asks whether
`work.propose` belongs in the taskless set; recommendation: no, keep the
candidate's set).
Layers, in fixed order, each producing a `<restrictions>` view or a refusal:
| # | Layer | Source | Missing → |
|---|---|---|---|
| L1 | agent policy | `agent-definition.policyRef` → registry `agent-policy.content.restrictions` | refuse `missing-state` |
| L2 | project registration | active `registration` for agent in `projectId`, `restrictions` | refuse `not-authorized` (A2) |
| L3 | workspace registration | active `registration` for agent in `workspaceId` whose `projectRegistrationRef` is L2's record | refuse `not-authorized` (A2) |
| L4 | project policy | `project.policyRef` → registry `project-policy` | refuse `missing-state` |
| L5 | workspace policy | `workspace.policyRef` if present in candidate payload; else scope-role of L3 | refuse `missing-state` |
| L6 | assignment | `selection.assignmentRef`; must be `status: selected`, agent = `agentId`, task in `projectId` | non-taskless op → refuse `not-authorized` |
| L7 | task | `task.restrictions` | null = no narrowing |
| L8 | mission chain | each mission up the `parentMissionRef` chain, `restrictions` | null = no narrowing |
| L9 | simulated execution layer | `selection.launchRestrictions` | null = no narrowing; when present, narrows only (D-F) |
Intersection semantics (README `:96-142`, contract `:158-193`):
- `operations`: set intersection. An explicit empty array is **none** (`:101`).
A `null` restrictions object at L7L9 means "no narrowing"; at L1L5 a
`null` refuses (required layer, `:133`).
- `readPaths`/`writePaths`: a grant `{root:"workspace", path:null}` is the whole
root (`:102`). Intersection of two grant lists = the set of pairs where one
is a component-prefix of the other, keeping the narrower. Component-prefix
means path segments, not string prefix (`a/b` covers `a/b/c`, not `a/bc`).
Target paths must be relative, normalized, contain no `..`, no empty
segment, no leading `/`, no `\`, no NUL; otherwise refuse `invalid-request`
before any permission result (A5).
- `network`: `none` ∧ anything = `none`; `approved-endpoints`
`approved-endpoints` = intersection of `endpointRefs` by exact ref.
- Never union across assignments (contract `:172`); exactly one assignment is
consulted (README `:134`). A second `selected` assignment for the same
agent+task in the bundle is not an error, but only the selected one is used.
- Result for the operation: allowed iff `operation.name ∈ operations` and,
for file operations, the target path is covered by the corresponding
`readPaths`/`writePaths` after intersection, and for network operations the
endpoint is covered.
Refusal precedence (deterministic): parse/shape errors (exit 2) → graph
incoherence (exit 2, D-C) → missing required layer (exit 3, `missing-state`)
→ registration absent (exit 3, `not-authorized`) → operation not in
intersection (exit 3, `not-authorized`). The first failing check ends
evaluation; the output names only that rule.
## 8. Proposal mode (cross-lane reassignment, map `:290-314`)
Evaluated only when `proposal !== null`, after the base permission result:
1. `requesterAgentId` must hold an active registration in the target task's
project (authority in target scope) — else refuse `not-authorized`.
2. `delegationRef` must resolve to a `decision` with `decisionKind: delegation`,
outcome approved, `delegatedOperations` including `assignment.change`, and
`subjectRefs` covering the subject assignment or its task — else refuse
`not-authorized`. A `message` with no delegation refuses with the same code
and the violated rule "message-is-not-authority" (A7).
3. `changeDecisionRef` must resolve to a `decision` with
`decisionKind: assignment-change` whose `subjectRefs` include both the
subject assignment and the target task and whose `basisRef` is the
delegation decision — else refuse `not-authorized`.
4. `runtimeObservations`: if either field is `null`, result is **unresolved**
with reason `unknown-effects` (charter: report reconciliation-required
rather than simulate success). If `originalExecutionStopped` is `false`
or `effectsReconciled` is `false`, refuse `unsafe-replacement`.
5. On any outcome, the output's `selection.assignmentRef` is echoed unchanged
and the bundle bytes are never written (A6, A7).
Exit class for unresolved: 3 (it is a refusal to affirm), with
`result: "unresolved"` in JSON and text so it cannot be read as a permission
refusal. Requester model in increment 1 is agent-only (D-G).
## 9. Output and exit classes
- Text (default) and `--json` must be generated from the same result object;
the text renderer is a pure function of the JSON. First line of both, always:
`SYNTHETIC PREVIEW — NO LIVE EFFECTS` (text) / `"disclaimer": "SYNTHETIC
PREVIEW — NO LIVE EFFECTS"` (JSON), including on every refusal and on
exit 2/4. REVIEW's phrasing "preview: no live registrations or permission
grants" (`d4696d09:cand/REVIEW.md:126`) is emitted as the second line.
- JSON result shape (closed): `{disclaimer, bundleVersion, result: allowed |
refused | unresolved, reason: <code>, rule: <rule-name>, selection: {agentId,
projectId, workspaceId, assignmentRef}, operation, consulted: [<recordRef |
registryRef>], proposal: null | {result, reason, rule, selectedAssignmentRef}}`.
No payload bodies, no paths other than the requested target, no input
snippets, no timestamps, no random ids, keys sorted.
- Reason codes: the RUNTIME closed set (`d4696d09:cand/RUNTIME.md:97`:
allowed, invalid-request, not-authorized, stale-revision, missing-state,
already-active, control-conflict, retired, unsupported-capability,
audit-unavailable, unknown-effects, unsafe-replacement, request-id-conflict,
expired) plus inspector-only codes `unsupported-kind`, `unresolved`,
`io-failure`. Inspector-only codes are documented as not being runtime API
codes (charter).
- Exit classes: 0 allowed; 2 malformed input (parse, shape, bounds, graph
incoherence, unsupported kind/operation); 3 simulated refusal or unresolved;
4 I/O failure (missing file, unreadable, not a regular file). Exit 4 output
names the path as given on argv and nothing else; no bootstrap, no config
read, no directory creation (A8).
- Errors from `strict-json.mjs` report byte offset and error class only, never
the surrounding bytes.
## 10. Supported record kinds and operations
Supported kinds in increment 1: `agent-definition`, `project`, `workspace`,
`registration`, `mission`, `task`, `assignment`, `decision`. The remaining
candidate kinds refuse `unsupported-kind` (exit 2) when present in `records`,
rather than being ignored. Operation vocabulary is the candidate's 29-name enum
(`d4696d09:cand/RUNTIME.md:55`); a name outside it refuses `invalid-request`.
Operations whose semantics need runtime state the inspector cannot model
(stop, durability, audit) are accepted as names for permission intersection
only; the output states `"scope": "permission-only"` for them so a `0` is not
read as an executability claim.
## 11. Fixtures and the first demonstration
`scripts/foundation/fixtures/demo.bundle.json` implements the charter's
scenario: project P1 with workspaces W1 and W2; project P2; agent A registered
in P1 and W1 only; one mission, one task in W1, one selected assignment for A;
agent B registered in P2 with a delegation decision that does **not** cover
`assignment.change`. Derived bundles (same records, different selection or
proposal) cover:
| Fixture | Expectation |
|---|---|
| `demo-read-w1` | exit 0, allowed, `file.read` on `docs/notes.md` |
| `demo-read-w2` | exit 3, not-authorized, rule workspace-registration-missing, no W2 payloads in output |
| `demo-cross-project-exec` | exit 3, not-authorized, cross-project selection |
| `demo-reassign-message-only` | exit 3, not-authorized, message-is-not-authority, selection unchanged |
| `demo-reassign-no-observations` | exit 3, unresolved, unknown-effects |
| `neg-duplicate-identity`, `neg-stale-ref`, `neg-missing-parent`, `neg-cycle-task`, `neg-cycle-mission`, `neg-fork-supersedes` | exit 2, named rule |
| `neg-unknown-key`, `neg-dup-json-key`, `neg-bad-utf8.bin`, `neg-bad-path` | exit 2, before any permission text |
| `neg-empty-ops-layer` | exit 3, explicit empty = none |
| `neg-union-two-assignments` | exit 3, second assignment does not widen |
Fixture digests are generated by a checked-in helper
(`node scripts/foundation/canonical.mjs --digest <file>`) and the suite fails
if a stored digest disagrees with a recomputed one, so fixtures cannot drift
silently.
## 12. Test harness (isolated, non-effect, privacy)
`scripts/test-foundation.sh`, same shape as `scripts/test-config.sh`:
- Runs under `env -i PATH=… HOME=<mktemp> NO_COLOR=1 node …`; `MOSAIC_CONFIG`
unset; no `~/.config/mosaic-dev` or data root exists in the sandbox. A
canary `HOME/.config/mosaic-dev/config.json` is **absent** and the test
asserts it stays absent (no bootstrap on missing input, A8).
- Non-effect: before and after every CLI invocation, `find <sandbox> -newer
<stamp>` must be empty and `sha256sum` of each bundle must be unchanged (A6).
Also asserts no `.pi`, `roles`, or `state` directory appears under the sandbox.
- Privacy: fixture payloads contain a canary string
(`CANARY-DO-NOT-PRINT-<n>`) in every unrelated record body and in W2's
payload; every stdout/stderr capture is grepped for it and must be clean
(A2, charter diagnostics rule). Exit-2 parse errors are checked for absence of
any input bytes beyond the byte offset.
- Determinism: each fixture runs twice; outputs must be byte-identical;
`--json` and text must agree on `result`/`reason`/`rule` (A8).
- Golden files: `scripts/foundation/fixtures/expected/<name>.{txt,json}`,
compared exactly.
- Units (`node --test scripts/foundation/*.test.mjs`): canonicalizer vectors
and out-of-domain refusals; strict-json duplicate key, depth, size, fatal
UTF-8; resolver graph rules one per test; permission intersection tables
(empty=none, null=whole root, component-prefix, no union); proposal rules.
- Cross-check (optional, skipped visibly when Python `jsonschema` is absent):
`python3 cand/check.py` over each fixture's `records` to confirm the
hand-rolled validator has not drifted from the candidate schema.
- The suite does not touch Dewey's extension installation, `~/.mosaic`, the
network, or any engine/process launch. It states this in its header. The
existing required suites remain untouched and must stay green.
## 13. Unresolved decisions for the frozen charter
| Id | Decision | Recommendation |
|---|---|---|
| D-A | Language: Node ESM vs Python stdlib | Node ESM, zero deps (§3) |
| D-B | Directory layout before M20 | `scripts/foundation/` with owner headers, no `packages/` (§4) |
| D-C | Exit class for graph incoherence (cycle, stale, duplicate) | 2 (malformed input), not 3, so it cannot be mistaken for a policy refusal |
| D-D | Taskless operation set | `{work.read, file.read}` exactly; `work.propose` stays assigned-only |
| D-E | Registry content shapes for scope-role / agent-policy / project-policy | `{restrictions}` only, declared simulation-only in the charter; candidate schema does not define these |
| D-F | Simulated execution layer | `selection.launchRestrictions`, narrowing-only, default null |
| D-G | Requester model in proposal mode | agent-only (agentId + registration); no human/operator principal in increment 1 |
| D-H | Wrapper naming | `scripts/foundation-inspect.mjs`, no `.sh` shim |
| D-I | Delegation enforcement depth | require `delegatedOperations ∋ assignment.change` and subject coverage; do not model delegation chains |
| D-J | Whether bundles carry revision history | permit either head-only or contiguous full history per identity; forbid partial history |
One further point the charter should settle explicitly: whether a `0` result
for stop/durability/audit-class operations is acceptable at all in increment 1,
or whether those names should refuse `unsupported-capability` outright. My
recommendation is the latter for `execution.stop`-class names, to keep A9's
"understands the limitation" honest.
## 14. Feasibility verdict
Feasible as a bounded increment with no new dependencies, no package
migration, and no runtime coupling. Estimated size: three pure modules of a
few hundred lines each, one CLI wrapper, roughly twenty fixtures, one bash
suite, and unit tests. The main risk is drift between the hand-rolled validator
and the candidate schema; the Python cross-check in §12 and the enumerated
set-valued field list in §6.1 are the mitigations. Nothing here weakens the
accepted semantics; where the candidate is silent (D-E, D-F), the proposal is
narrowing-only and simulation-labelled.
This note is evidence for darkwing's charter. It is not approval, and it
authorizes no implementation.
@@ -0,0 +1,118 @@
# FM-FILBERT-1 — independent written-map review request
Owner authority: Jason explicitly said “You can have filbert review the map.”
Requester/follow-up owner: dragon-lin:darkwing.
Reviewer requested: dragon-lin:filbert, default tmux server.
Status: request prepared; transport and acknowledgement recorded separately below.
## Admission before work
Confirm you did not author/co-author the map and that this bounded review is
compatible with your existing owner-authorized assignments and scope. If not,
return a blocker; do not replace another goal, assume a new supervisory role,
or silently abandon current work. This request authorizes only this review.
## Exact candidate
Repository: /home/jwoltje/src/mosaic-stack-dev-test
Mapping commit: 7345f330fc6bfae5aa1d896c78cfb7cbe62efbae
Source/accepted-plan baseline: d4696d09eb1b5dcf1028f30db2cd63735f51cb16
Foundation parent: 44f257cb06484feda3412d9382e3587393796353
- docs/plans/2026-09-06_foundation-technical-map.md
SHA-256: 772f9e61cb9fb7a31ce8187b12cdf1c4a5fb714ad517a9c12928901171a37db1
- docs/plans/2026-09-06_foundation-map-handoff.md (MAP-HANDOFF-2)
SHA-256: 1fd1a89f982a31bb9db21b852df78be954323aa1668ab9752be34de853ee4999
Use git show at these commits, not mutable working-tree source. The handoff lists
69 SHA-256-pinned inputs. Subsequent uncommitted quiet-wait extension work belongs
to Dewey and is explicitly outside this historical candidate.
## Scope and verdict
Review the written current-versus-planned technical/component map, not a rendered
Archify deliverable. There is no architecture JSON, HTML, renderer receipt, visual
check or preview supplied. Do not certify those missing gates or label this full
Archify acceptance. Identify any limitation that prevents substantive review.
1. Open every source/plan citation at the named baseline and verify every claimed
boundary/hop, reuse/change classification and gap. Mark each confirmed, wrong
or unsupported; external behavior without measurement must remain a hypothesis.
2. Check R1-R34 coverage against requirement meaning, not table counts, including
owner intent, reassignment, cross-scope messages and independent acceptance.
3. Check pure policy versus effectful publication, package versus process authority,
current extensions/** versus future packages/*, and single runtime/adapter owners.
4. Check the small synthetic inspector's dependencies, acceptance cases and clear
separation from live grants, session control and runtime security guarantees.
5. Check identity hashes and source/plan versus mapping-commit distinctions.
6. Run relevant author/repository checks in an isolated temporary export if needed.
Do not checkout/reset this shared tree or run synchronization/native tests against
Dewey's changing installation. Report commands, baseline and measured results;
do not treat previously reported tests as your independent execution.
Return APPROVED or NOT APPROVED for the written map at the exact candidate hashes,
with per-item dispositions and numbered findings (severity, location, evidence,
required correction), test receipts and any unverified limits. A written-map
approval is neither owner acceptance nor a runtime/renderer verdict.
## Boundaries and return
Do not fix/edit the map, CURRENT, shared logs, source, policies or installations.
No commit, push, implementation, source moves, live workers or fleet investigation.
Never read credential contents. Jason's ~/.mosaic failure is only a reported negative
scenario; do not inspect or intervene in that environment.
Reply directly tagged FM-FILBERT-1 to darkwing. If a durable detailed verdict is
needed, you may create only docs/plans/reviews/2026-09-06_foundation-map-filbert-verdict.md
in this repository; report its SHA-256 and reviewed candidate hashes. No commit
is requested. No automatic timer, deadline, retry or approval is assumed.
## Transport receipt (2026-09-06 07:52 UTC)
One tools/tmux/agent-send.sh invocation targeted =filbert on the default server.
Exit 2: submission could not be confirmed. Receipt is unconfirmed, not delivered
or acknowledged. No retry or private-pane poll. Await direct FM-FILBERT-1
reply or manual owner steering; darkwing owns follow-up.
## Admission clarification (2026-09-06 08:00 UTC)
Filbert replied FM-FILBERT-1, resolving the original delivery uncertainty. He
verified candidate hashes, all 69 baseline inputs and foundation parent, but
stopped before substantive review/tests because assignment compatibility was
unestablished. His NOT APPROVED means incomplete review, not technical rejection.
He identified d4696d09's historical CURRENT.md as the uncertainty, not evidence
of an actual current competing personal assignment.
Sent FM-FILBERT-1-C1 once: source baseline is not current assignment authority;
7345f33 CURRENT.md:8-25 names the mapping review gate, subsequently authorized
by Jason's explicit request for Filbert. Asked him to establish compatibility
from his own current instructions, or return the concrete conflict/uncertainty
for Jason to resolve. No permission to cancel, inspect other agents, or reprioritize.
Clarification delivery unconfirmed (exit 2); no retry. Candidate remains unchanged.
Await FM-FILBERT-1-C1 admission/blocker; darkwing owns follow-up.
## FM-FILBERT-1 completed review (2026-09-06 08:06 UTC)
Filbert confirmed non-authorship and no competing current assignment, withdrew
the historical-CURRENT blocker and returned APPROVED for the exact written map
at 7345f33 against d4696d09. Verified verdict SHA-256
6b08c6fac0718d3db527cf9ffbfab49407e7b289d09782f5d1d0e26493eaabb3 and both
candidate hashes against committed/current map bytes. No blocking defect; five
informational findings/limits, 20 source-row and R1-R34 semantic dispositions.
Independent checks reported: 69 hashes, nine legacy identities, foundation checker,
config 24/24, syntax and mapping whitespace. Other full runtime/native/render
suites were explicitly not run by this reviewer. Earlier incomplete NOT APPROVED
is superseded, not rewritten. Owner acceptance and implementation remain gated.
Sent one non-actionable closeout; delivery unconfirmed, no reply obligation or
retry. Exact verdict remains unchanged. No commit, push or implementation.
## Owner acceptance of reviewed technical map (2026-09-06 08:07 UTC)
Jason answered "yes" to accepting the independently reviewed written map as the
technical planning baseline. Accepted mapping: 7345f330fc6bfae5aa1d896c78cfb7cbe62efbae;
source/plan baseline: d4696d09eb1b5dcf1028f30db2cd63735f51cb16.
Verified map/handoff and Filbert verdict identities unchanged. Verdict SHA-256:
6b08c6fac0718d3db527cf9ffbfab49407e7b289d09782f5d1d0e26493eaabb3.
Acceptance covers planning, not runtime/security/render proof, implementation,
migration, push or issue closure. Recommended next step: separately authorized
charter for the bounded synthetic inspector. No new phase started or commit made.
@@ -0,0 +1,223 @@
# FM-FILBERT-1 — independent written-map verdict
Reviewer: filbert. Follow-up owner: darkwing. Date: 2026-09-06.
## Admission and verdict
**APPROVED for the bounded written technical map at the exact identities below.**
No blocking technical-map defect found. This is not full Archify acceptance,
owner acceptance, phase advancement, an implementation charter, or a runtime verdict.
I did not author/co-author this candidate in my available session history. My
current instructions contain no competing personal owner-authorized assignment.
FM-FILBERT-1-C1 resolved my earlier mistaken use of the source baseline's historical
CURRENT.md as current task authority. That admission blocker and the resulting
incomplete NOT APPROVED are superseded by this completed review, not erased.
Mapping-commit CURRENT.md:8-25 records the later review gate; Jason's separately
communicated authorization admits only this bounded review.
- Mapping commit: `7345f330fc6bfae5aa1d896c78cfb7cbe62efbae`
- Source/plan baseline: `d4696d09eb1b5dcf1028f30db2cd63735f51cb16`
- Foundation parent: `44f257cb06484feda3412d9382e3587393796353`
- Map: `docs/plans/2026-09-06_foundation-technical-map.md`
SHA-256 `772f9e61cb9fb7a31ce8187b12cdf1c4a5fb714ad517a9c12928901171a37db1`
- Handoff: `docs/plans/2026-09-06_foundation-map-handoff.md`
SHA-256 `1fd1a89f982a31bb9db21b852df78be954323aa1668ab9752be34de853ee4999`
Both document hashes matched independent computation from `git show`. All 69
handoff input hashes matched the source baseline. The mapping commit's parent is
the source baseline, whose parent is the foundation parent. The mapping commit
changes only map, handoff and CURRENT. All nine inspected legacy source files
are byte-identical to 69d1bb3 and to the isolated baseline export.
## Numbered findings and limits
1. **Informational / confirmed — legacy launch is not managed admission.**
Locations: map launch/mount/context trace tables; baseline `compose.yaml:38-43`,
`scripts/agent.sh:121-138,181-199`, `src/run-agent.sh:37-41`,
`src/load-contracts.sh:40-41,68-97`, `adapters/pi/adapter.sh:29-44,81-96`.
Evidence: broad writable data-root mount, shared SOUL/mission/prompt destinations,
fixed `.partial`, blanket user Markdown discovery, directory-nonempty continuation,
and native/print invocation are present. These support the proposed replacement
boundaries; a named workspace is not isolation. Required correction: none.
Limit: no race reproduction, engine discovery measurement or containment test.
2. **Informational / confirmed — evidence and lifecycle reuse is correctly narrow.**
Locations: map evidence/lifecycle tables and ordering constraints; baseline
`scripts/mosaic-task.mjs:295-302,442-466,548-641`, `scripts/reset.sh:16-48`.
Evidence: exclusive-create writes lack fsync in the helper; retry starts a new
run without reconciliation; prune deletes before appending its receipt and
treats directory-read exceptions as an empty inventory; reset lacks foundation
claim/reference protection. Map preserves useful conventions without calling
them crash durability or recovery. Required correction: none. Limit: static
ordering inspection is not a measured crash/failure-injection result.
3. **Informational / confirmed — policy, packaging and process privilege remain distinct.**
Locations: map component/placement matrices and integrated ownership section;
baseline ROADMAP:127-166, #55 layout plan, candidate README sections 2-3/6,
RUNTIME sections 1/4/7. Pure calculation belongs to proposed packages/config;
publication and process authority do not. CLI presentation does not own policy.
Runtime/adapter logic has one proposed packages/agent owner, with only unavoidable
retained src shims. Current extensions/** and generated .pi installation do not
replace the future packages/* decision. A shared package is explicitly not a
shared process privilege grant. Required correction: none. #55's historical
native-test/reviewer receipts were read as reports, not independently rerun or
recertified here; Dewey's current work is excluded.
4. **Informational / confirmed with implementation limits — the inspector is appropriately bounded.**
Locations: map recommended-increment section and cross-lane scenario; candidate
REVIEW first-increment proposal, README sections 2-3/8, RUNTIME sections 2/5.
Coherent synthetic graph, explicit selection, required policy refusal,
least-privilege intersection, no assignment-union grants, deterministic preview,
no live writes and owner test gate are stated. The cross-lane case preserves the
original assignment unless a properly authorized, recorded change within owner
intent is reconciled. A message does not itself confer delegation or acceptance.
Required correction: none for this recommendation. A later charter must specify
executable graph/operation inputs and tests for those rules; the current small
model is not a real graph resolver, authenticator or reassignment implementation.
5. **Informational / review limit — source flags and reported external behavior are not runtime proof.**
Locations: map adapter row, authority/coordination history and owner-reported
cross-lane scenario; handoff collaboration section. I confirm adapter flags and
command construction, not the pinned engine's complete discovery, exact-session,
fork-preservation or security behavior. Future reuse remains conditional on the
admission tests already required by the plan. Collaboration delivery, native
acceptance and the separate-environment incident are reported context, not
independently observed facts in this review. Required correction: none; preserve
those qualifications in downstream maps and charters. No external incident
diagnosis or investigation was performed.
## Request-item dispositions
| Item | Disposition | Independent basis |
|---|---|---|
| 1. Source/plan boundaries, hops, reuse and gaps | Confirmed at the written map's explicitly limited inventory level | All direct source-locator rows opened in the committed baseline; dispositions below. New responsibilities are proposals, not repository-wide absence claims. |
| 2. R1-R34 meaning | Confirmed as responsibility mapping, not a replacement specification | Each requirement checked against the foundation table, owner interview and accepted phase-2 rules; per-R dispositions below. |
| 3. Policy/effects, package/process, source/install, single owners | Confirmed | Placement matrix and integrated qualifications agree with ROADMAP, #55 and RUNTIME trust boundaries. |
| 4. Synthetic inspector | Confirmed as a recommendation | Seven core acceptance cases plus cross-lane case preserve the no-live-grants boundary; execution and enforcement unimplemented. |
| 5. Identity/commit distinction | Confirmed mechanically | Exact map/handoff hashes, 69 input hashes, both parent links and nine legacy identities verified. |
| 6. Independent checks | Passed within stated limits | Contract checker, config suite, syntax and mapping whitespace checks below; no native/synchronization/security suites claimed. |
## Direct source-row dispositions
Every row is **confirmed as a static source finding and justified reuse/change
recommendation**, subject to findings 1-5. No row is certified as external runtime
behavior. Paths/lines here resolve at d4696d09.
| Map source row | Verified meaning / disposition |
|---|---|
| agent.sh:78-130 | Reads seat defaults, copies canonical SOUL to shared agent path, conditionally writes seat record. Reuse identity concept; change snapshot materialization. |
| agent.sh:132-170 | Global agent session default and role-tool narrowing. Replace scoped selection; retain narrowing principle only. |
| agent.sh:181-199 | Shared mission copy, name-default workspace, Compose TUI launch. Change orchestration and inputs. |
| adapter.sh:23-50 | cwd, fork/persistent/ephemeral flags and nonempty-directory `-c`; explicit tools/no-tools. Exact scoped binding remains new. |
| adapter.sh:63-96 | Native/print modes and explicit suppression/provider/model/prompt arguments. New mediated gateway remains required; engine behavior not exercised. |
| mosaic-task.mjs:252-273,670-676 | Closed role keys, filename identity, known unique tools, network enum and emitted metadata. Not network enforcement or scope RBAC. |
| mosaic-task.mjs:362-378 | Requested task tools intersect mission tools when both exist; empty intersection is tool-free. Absent task tools can inherit mission tools: this is narrower legacy semantics, not the new full policy resolver. |
| mosaic-task.mjs:295-325 | Exclusive-create snapshots/helper, no fsync in helper. Reuse intent, replace durable publisher. |
| mosaic-task.mjs:442-466 | Final response/provenance/process result fields, followed by writeOnce. Not invocation-level managed audit. |
| compose.yaml:38-43 | Writable whole-root mount and separate read-only auth mount. New managed isolation/credential boundary needed. |
| run-agent.sh:20-41 | Adapter path checks and shared generated prompt before dispatch. Retain dispatch validation, change context publication. |
| load-contracts.sh:18-58 | Required governance sources, optional seat SOUL and fixed staging file. Snapshot/publication changes warranted. |
| load-contracts.sh:68-77,81-98 | Blanket user Markdown selection precedes mission, contrary to header order. Replace discovery with authorized classified selection. |
| reset.sh:16-48 | Configured target, symlink/realpath/marker checks, recursive delete; no claim/reference/receipt integration. |
| mosaic-task.mjs:548-595 | Retry redirects relative mission references to snapshot and replays as a new run. Not uncertainty recovery. |
| mosaic-task.mjs:598-641 | Count-based preview/apply, caught directory errors, delete then receipt. Protected retention requires changes. |
| mosaic-config.mjs:39-61,76-174 | MOSAIC_CONFIG override, strict shape/file/root validation and lstat errors treated as missing. Sole-config reconciliation is explicitly required, not silently approved. |
| mosaic-config.mjs:194-239 | Exclusive bootstrap creation, existing-config validation and quoted env output. Synthetic inspector must not invoke bootstrap/live resolution. |
| auth.sh:19-96 | Config-backed account reporting; status parses credential JSON and parser diagnostics. Static source read only; no redaction guarantee or credential read performed by reviewer. |
| agent.sh:28-64 | Named auth account refusal checks and mount-source export; no project-selection parser. Future #50 binding must replace flat selection. |
The nine files were read completely. Plan inputs read: foundation requirements,
workspace/schema interview, phase-2 contract, candidate README/REVIEW/RUNTIME,
ROADMAP, #55 layout, #54 native-development plan and #50 auth/provider registry.
Also read candidate check.py and semantic-model.py, extension/.pi READMEs,
Containerfile and adapter contract. The 69-entry identity audit is a byte audit,
not a claim of independent line-by-line review of every extension/schema fixture.
The schema/fixture inventory was additionally consumed by the author checker.
## R1-R34 semantic dispositions
C = confirmed responsibility allocation and planned gap, not implemented behavior.
The map's concise index is read with its named accepted-plan input; it does not
need to restate every normative clause to be a faithful responsibility map.
| Requirement | Disposition and meaning checked |
|---|---|
| R1 | C — reusable definition retained; execution-specific identity binding changes. |
| R2 | C — project registration and bounded delegation require new resolver, not tool names. |
| R3 | C — exactly one project parent, explicit workspace membership; dependencies do not grant access. |
| R4 | C — one identity across scopes with distinct scoped sessions, replacing global default. |
| R5 | C — explicit agent/project/workspace selection, not cwd or seat-name inference. |
| R6 | C — reusable instructions, selected scoped work context and authorized snapshots. |
| R7 | C — exact Resume/Fresh/genuine-first-use distinction; damaged history is not first use. |
| R8 | C — assignment-only Abandon and explicit authorized prerequisite/selection transitions. |
| R9 | C — authorized human/service launch and recovery from checked work records. |
| R10 | C — claim key is scoped, not session-only; tuning/budgets/scaling are not implemented by the map. |
| R11 | C — shared client operations/work truth; no separate interface task list. |
| R12 | C — explicit scoped messaging, no identity-based conversation mixing; cross-lane text is not authority. |
| R13 | C — whole-root mount is not containment; actual enforcement remains a proof gate. |
| R14 | C — legacy provenance is useful but lacks trusted classified per-action evidence. |
| R15 | C — owner phase/user-test gates retained; independent written approval is not owner acceptance. |
| R16 | C — canonical SOUL retained, current approved launch revision snapshotted; no silent live reload. |
| R17 | C — comparable base hash and cross-interface notices are new, distinct from full launch identity. |
| R18 | C — single-owner mission/parent graph and exact references, not duplicated project truth. |
| R19 | C — bounded within-plan decomposition and authorized non-author acceptance; coordinator title is insufficient. |
| R20 | C — taskless permitted read/chat is distinct from recorded assigned changes. |
| R21 | C — active conflict plus explicitly authorized connection, not automatic attach/replacement. |
| R22 | C — transcript visibility/handoff is separate from work-record read and automatic context loading. |
| R23 | C — revoke affected scope, stop/fence and reconcile effects; independent other-scope authority survives. |
| R24 | C — one controller, separately authorized observers and explicit generation-fenced transfer. |
| R25 | C — controlled Fresh replacement requires stopping/safety evidence, not timeout/idle alone. |
| R26 | C — non-destructive authorized investigation, no blind replay or invented success. |
| R27 | C — audit failure closes affected admission; preauthorized fail-safe stop is not unaudited recovery. |
| R28 | C — classified relevant user context replaces blanket global Markdown discovery. |
| R29 | C — retirement/reopen preserves evidence, distinct from deletion and protected retention. |
| R30 | C — reviewed legacy adoption preserves originals; no inferred membership. |
| R31 | C — current approved intent pauses affected work for reconciliation; messages cannot silently retask it. |
| R32 | C — standard nonhierarchical scope roles narrow reviewed ceilings, not redefine identity. |
| R33 | C — invocation evidence plus actually enforced limits; no claim to enumerate every internal effect. |
| R34 | C — Mosaic-controlled client with Pi behind the single reviewed adapter; no native parity waiver of safety. |
Owner-intent/reassignment was checked particularly against R8/R19/R23/R31/R32,
README reference/permission/lifecycle rules and RUNTIME assignment/message rules.
Independent acceptance uses actual author provenance and current reviewer authority,
not a fresh session of the same author or a message saying approved. The small
synthetic model cannot prove that enforcement; the map does not claim it does.
## Independent test receipts
Measured 2026-09-06 around 08:01 UTC. Isolated source export:
`/tmp/fm-filbert-1.6Acnih`, created with
`git archive d4696d09eb1b5dcf1028f30db2cd63735f51cb16 | tar -x -C <export>`.
No shared-tree checkout/reset, dependency install or live runtime was used.
1. Python/subprocess `git show <commit>:<path>` plus `hashlib.sha256`:
both candidate hashes matched; 69/69 inventory matched; 9/9 legacy files matched
69d1bb3 and the export. `git rev-list --parents -n 1` confirmed both parent links.
2. From export, with clean environment, temporary HOME and bytecode writes disabled:
`/home/jwoltje/.pyenv/versions/3.12.8/bin/python3 docs/plans/foundation-v1-candidate/check.py`.
**Exit 0:** 38 command shapes, 38 record shapes, 16 paths, 7 restricted-domain hash
vectors, 155 runtime/artifact shapes, 35 synthetic model cases; 5+5 deliberately
shape-valid semantic forgeries remain shape-valid. Python 3.12.8/jsonschema 4.26.0.
Initial attempt using `env -i PATH=/usr/bin:/bin ... python3` failed exit 1 because
that interpreter lacked jsonschema. No dependency was installed; the existing
explicit interpreter above supplied the documented dependency for the successful run.
3. From export: `env -i PATH=/usr/bin:/bin HOME=/tmp/fm-filbert-1.6Acnih-review-home bash scripts/test-config.sh`.
**Exit 0: 24 passed, 0 failed.** Suite uses its own temporary synthetic config/data.
4. `bash -n` for scripts/agent.sh, auth.sh, reset.sh; `sh -n` for
adapters/pi/adapter.sh, src/run-agent.sh, src/load-contracts.sh;
`node --check` for scripts/mosaic-config.mjs and scripts/mosaic-task.mjs.
**All exit 0.** Observed default Node v26.8.1; syntax checking is not pinned-runtime testing.
5. `git diff-tree --check 7345f330^ 7345f330`: **exit 0**.
No test-task full suite, release/conductor/auth runtime suites, verify.sh, Docker,
native extension, sync/package, renderer, browser, process-stopping, sandbox,
credential separation, crash-durability or full JCS/Unicode enforcement tests ran.
In particular the author checker is independently executed author test code, not
an independent implementation of its validator and not proof of real authorization.
No architecture JSON/HTML, render receipt or visual preview was supplied or accepted.
Only this offered verdict path was written in the repository. No shared logs,
CURRENT, source, policies, installations, commits or pushes were changed. No
credential contents, live worker state or separate ~/.mosaic environment were read.
No implementation or automatic next increment is authorized by this verdict.
@@ -0,0 +1,45 @@
# FI-FILBERT-8 — r6 re-review after Unicode ordering correction
Owner demo/build/review authority and FI-FILBERT-7 scope remain unchanged.
Reviewer filbert; sole code writer rocko; coordinator/follow-up darkwing.
Recheck assignment compatibility/non-authorship. No displacement of owner work.
Repository /home/jwoltje/src/mosaic-stack-dev-test.
Frozen candidate report:
docs/plans/reviews/2026-09-07_foundation-inspector-rocko-build-r6.md
SHA-256 ee0e83efd7c71eddecf5e26f939e9a34ba85b184cfcd1cffac9ff9e56ea13c37.
Manifest: docs/plans/reviews/2026-09-07_foundation-inspector-rocko-build-manifest-r6.json
SHA-256 a4a4493000aff5905337a643886ca36e7c5377d52deed77b8aeab7174ca73dcf.
Coordinator verified both identities, 382 file hashes/modes/sizes and pinned inputs;
this is not independent execution of writer tests. Recheck exact scope/aggregates.
Charter/addendum and owner test-gate decision are unchanged, with exact identities
in the manifest and FI-FILBERT-7 request. Prior NOT APPROVED verdict remains preserved
at hash 154e7b5d804c059d6fec4c936c78e4ae33bb7fc273ba3a5eec7b00d0a9ce1e59.
Reproduce all six R5-1 Unicode pairs, inspect orderingForm over the actual strict-
JSON domain, and test malformed/equal-key cases beyond writer examples. Verify no
normalization, Unicode ban, digest-domain expansion, precedence/privacy change or
semantic-array reordering. Distinguish structural equality from byte-identical
serialization when assessing the writer's index-fallback claim. Retain original
F1F6/C1C5 closure and A1A8 coverage; independently run authorized checks.
Use isolated copies of exact candidate and required committed baseline dependencies.
Writer reports unrelated working-tree modifications to scripts/agent.sh and
docs/TOOLS.md: do not include or test them as though part of this frozen inspector.
If integration HEAD or relevant source identities changed, identify that boundary
explicitly rather than silently reviewing another session's work.
As Jason ruled, test-task.sh and test-release.sh are NOT RUN / DEFERRED for this
offline demo. All other inspector/oracle/foundation/non-live checks remain required;
conductor fixture Git mutations allowed only in disposable test repos. No live model,
engine/container, native/sync, credential, install or ~/.mosaic activity. No shared
index, checkout/reset, staging, commit or push. Inspect commands before running.
Only allowed repository write:
docs/plans/reviews/2026-09-07_foundation-inspector-code-verdict-r6.md.
Return FI-FILBERT-8 APPROVED/NOT APPROVED for exact candidate and bounded offline-demo
gate, per-finding dispositions, actual measurements, new findings and deferred limits.
Do not fix/co-author code or edit existing records. Owner A9 acceptance remains a
subsequent gate. Direct reply plus declared verdict are return paths; follow-up
darkwing; no deadline or automatic approval.
@@ -0,0 +1,57 @@
# FI-FILBERT-7 — independent r5 code re-review for offline demo
Owner authorized build, independent code review and demo. Recheck current assignment
compatibility/non-authorship; no displacement of other work. Writer rocko; coordinator
and follow-up darkwing. All FI-FILBERT-6 review boundaries remain except the explicit
test-gate adjustment below.
Repository /home/jwoltje/src/mosaic-stack-dev-test.
Frozen r5 manifest: docs/plans/reviews/2026-09-07_foundation-inspector-rocko-build-manifest-r5.json
SHA-256 a63bb103e4cfe51bbd8a42cd95545f935ac83c1da51cf469298375cf94ced135.
Report: docs/plans/reviews/2026-09-07_foundation-inspector-rocko-build-r5.md
SHA-256 17c67427dfdf1bc5dac491c4d0223928e87fdfc67a26175ac239eb2b2f7b7dec.
Coordinator verified report/manifest identities, 369 file hashes/modes/sizes and all
pinned inputs. This is not independent test execution. Recheck exact scope/no extras,
aggregates, copies and candidate identity before/after review yourself.
Charter 19b6721128a627a2032ffdb95ece2d50abe69a8f6d521e9eff8bbdaff22798b6 and
addendum afe2980be2f91e701dae5af3018831ac5c300474f52bcc06e740ce5b5cc68ca5 remain
unchanged; full paths and all earlier identities are in the FI-FILBERT-6 request.
Source baseline d4696d09; integration HEAD reported 9a5fbdb, not a commit of this code.
## Re-review scope
Reproduce/reconstruct all F1F5 witnesses from your original verdict, confirm F6
ownership coverage and independently examine the fixes/interactions for regressions.
Do not accept writer CLOSED labels as your verdict. R4 fixed declarations/work.read/
issuer narrowing/exact-revision cycles; r5 completes deterministic declaration
inventory traversal beyond records. Confirm new registry-declaration-missing rule
and admission stage/exit semantics against the charter. Inspect stableOrder and
malformed-entry/content tie-breaking, profile/digest/duplicate/reference precedence,
permutation coverage and unchanged semantic sequence arrays. Retain full A1A8
coverage and prior C1C5 closure; expand adversarial probes where useful.
## Explicit owner test-gate adjustment
Read docs/plans/reviews/2026-09-07_foundation-inspector-demo-test-gate-decision.md.
Jason authorized test-task.sh and test-release.sh to be NOT RUN / DEFERRED for this
OFFLINE DEMO only. Do not execute their live branches, simulate a full pass or hide
the missing coverage. Full deployment testing remains a later gate.
Independently run inspector/oracle/foundation and authorized non-live config/auth/
conductor verification in disposable copies. Conductor's fixture Git mutations
are authorized ONLY inside its disposable test repositories, never shared source
or index. No provider calls, engine/container launches, native/sync tests, credential
access, package installs or ~/.mosaic activity. Inspect commands first; report any
additional unsafe branch/blocker rather than broadening permission.
## Exact return
Only authorized repository write:
docs/plans/reviews/2026-09-07_foundation-inspector-code-verdict-r5.md.
Return FI-FILBERT-7 APPROVED/NOT APPROVED for the bounded offline-demo code gate,
exact manifest/contract identities, per-finding closure/reopening, new findings,
A1A8 dispositions, commands/toolchain/results and explicitly deferred coverage.
Owner A9 acceptance remains separate. Preserve prior rejected verdict and evidence.
Do not fix/co-author code, change fixtures/charter, stage, commit, push or mutate the
shared index. Direct reply and declared verdict path are return mechanisms; follow-up
darkwing. No deadline, automatic approval or dependent runtime work.
@@ -0,0 +1,236 @@
# FI-FILBERT-7 — r5 independent CODE verdict: NOT APPROVED
Scope: **bounded offline-demo code gate**, not deployment or owner acceptance.
Reviewer: filbert. Sole code author: rocko. Coordinator/follow-up: darkwing.
Date: 2026-09-07. No competing assignment is known; no implementation authorship.
All nine original F1F5 witness inputs now produce corrected results. All executed
required suites pass. **F5 nevertheless remains open:** the new content tie-break
collapses distinct Unicode entries to the same fallback and again makes the emitted
first failure depend on inventory order. Six independent reversed-order witness
pairs demonstrate this. This is a deterministic-refusal defect, not a real permission
grant or demonstrated runtime-security exploit.
## 1. Exact candidate, authority and identity checks
| Input | SHA-256 / commit |
|---|---|
| r5 manifest `docs/plans/reviews/2026-09-07_foundation-inspector-rocko-build-manifest-r5.json` | `a63bb103e4cfe51bbd8a42cd95545f935ac83c1da51cf469298375cf94ced135` |
| r5 report `docs/plans/reviews/2026-09-07_foundation-inspector-rocko-build-r5.md` | `17c67427dfdf1bc5dac491c4d0223928e87fdfc67a26175ac239eb2b2f7b7dec` |
| Charter candidate 3 | `19b6721128a627a2032ffdb95ece2d50abe69a8f6d521e9eff8bbdaff22798b6` |
| Incorporated feasibility r2, §§513 subject to charter overrides | `f2f47fcfe22dca79f10f885b83d87a2f846fdb560425a4e20705c40ce4a123e1` |
| Pattern/profile addendum | `afe2980be2f91e701dae5af3018831ac5c300474f52bcc06e740ce5b5cc68ca5` |
| Pinned record schema | `05774aaf6943cb69c113e39ff1c29676a2a230ca7bf665c50dbcaa8049672af6` |
| Pinned checker | `82564a7d3200afcdda0850a9454cac6e6cd6a76687d2162c13cf214d7eac4607` |
| Owner demo test-gate decision | `62cea74bea59e69f29c8a29a9c0311fdc6feffa2c337bc6a141db55149204898` |
| Source/schema baseline | `d4696d09eb1b5dcf1028f30db2cd63735f51cb16` |
| Measured integration HEAD | `9a5fbdbda74b16adf488fe28138b2ba69ea5e669` |
I independently verified **369 distinct regular candidate files**, sizes, modes,
SHA-256s, exact allowlist/no extras, all six aggregates, report/manifest hashes and
every manifest-pinned input. Copies were hash-verified before execution. Final
shared-tree/export recheck at **2026-09-07T15:15:57Z** passed with the same HEAD.
The code is uncommitted: HEAD is not falsely presented as its code identity.
Export: `/tmp/fi-filbert-7.239u2bco`.
Separate evidence/harness root: `/tmp/fi-filbert-7.239u2bco-evidence`.
Required baseline bytes came from the committed source baseline, not moving owner
work. The non-live integration scripts and their relevant baseline dependencies
are unchanged between that baseline and measured HEAD. Five unrelated native/fleet/
goal scripts differ between those commits; they were not executed or independently
reviewed here. No shared index or owner extension work was used as test scratch.
## 2. Numbered finding
### R5-1 / F5 reopened — BLOCKING, medium: partial canonicalizer is not a total ordering tie-break
Sources in the frozen candidate:
- `scripts/foundation/resolve.mjs:730751`, especially `734735` and `750`;
SHA-256 `892f95ab8a971d93060353e43d53cb6988e7e61f2a5bae71f6f2aaf2b7c1f09f`.
- `scripts/foundation/canonical.mjs:2943`: the mock-content canonicalizer rejects
non-ASCII strings, as required for its separately bounded digest domain.
- New ordering tests: `scripts/foundation/resolve.test.mjs:548712` exercise ASCII
tie-breaks and readable differing keys, but miss the colliding Unicode fallbacks.
Contract: charter §10.4 and the pinned ordering follow-up require stable within-stage
ordering, including deterministic content tie-breaking for malformed entries. The
r5 report's assertion that only indistinguishable duplicates fall back to input index
is not true for this implementation.
`stableOrder` catches a `CanonicalError` and assigns canonical content `""`. Two
**different** entries containing non-ASCII strings therefore compare equal whenever
their typed keys are equal or both unreadable. The final `a.i - b.i` makes input order
choose the first shape failure. This affects emitted CLI rules, not just internal
locators.
#### Independent concrete witnesses
Start with a copy of the frozen
`scripts/foundation/fixtures/demo/demo-file-change-src.json`.
1. Replace `registries` with `[{"extra":"é"}, "é"]`. CLI `--json` returns
**exit 2 / invalid-request / shape-unknown-field**. Reverse only that array:
**exit 2 / invalid-request / shape-type-mismatch**. Both entries have unreadable
identity keys and both fail the ASCII canonicalizer.
2. The identical substitution/reversal independently produces the same differing
rules in **records, artifacts and delegationInputs**: four affected families.
3. For readable equal keys, duplicate `agent-a` at the same kind/id/scope/revision.
Give both copies the legitimate displayName `Café`; make the first copy's status
an invalid enum and give the other an unknown payload field. Forward/reversed
inventory gives **shape-enum-mismatch / shape-unknown-field**, both exit 2.
4. Duplicate `agent-policy/ap-full` with identical registry/id/revision/digest keys.
Both copies have readPaths `[{"root":"workspace","path":"café"}]`; give one
an invalid network enum and the other an unknown restrictions field. Reversal
again changes **shape-enum-mismatch / shape-unknown-field**, both exit 2, before
the later digest/duplicate stages.
All six pairs were executed through the real exported CLI. Four matched ASCII-only
malformed-entry controls are stable under reversal. Separate valid Unicode displayName
and logical-path controls remain **allowed**, as the contract requires. All observed
shape failures remain privacy-safe; no body disclosure is alleged.
Required correction: provide a deterministic tie-break over the relevant full
strict-JSON input domain without treating distinct unsupported canonical values as
identical. Preserve the ASCII-only **mock digest** domain, permitted Unicode record/
path values, semantic sequence order, stage precedence and body-free diagnostics.
Do not fix this by blanket-rejecting Unicode or changing the charter. Add equal-key
and unreadable-key multi-failure Unicode permutation regressions. Rocko alone owns
any authorized implementation correction; none was made in this review.
Exact equal-key record witness input hashes:
| File under evidence `witnesses/` | SHA-256 |
|---|---|
| `equal-key-unicode-records-forward.json` | `372c5bf1fc0d600ed5d348dc3638c2206d9c6aa43b869f35b0699b7c836e63cf` |
| `equal-key-unicode-records-reversed.json` | `22ed3d21bc95b950af49f37b5c8f33b6be7db52ec4342542a04690696ed95134` |
No additional numbered code finding is asserted. Finite passing tests are not a
claim that every other possible interaction is correct.
## 3. Original findings and acceptance dispositions
Original witness files were preserved byte-for-byte from FI-FILBERT-6; their hashes
match the prior verdict's listed inputs. Actual r5 CLI dispositions:
| Finding | Independent result / disposition |
|---|---|
| F1 missing referenced declarations | Both original cases now refuse: exit 3 / missing-state / registry-declaration-missing; exit 3 / missing-state / authorization-undeclared. **Closed for reviewed consulted-declaration paths.** |
| F2 task-only work access | Assigned change and task-only proposal both refuse exit 3 / consulted-work-not-readable; proposal identifies original requester context. Taskless positives remain allowed. **Closed.** |
| F3 issuer narrowing | Original issuer-denies-work.read case now refuses exit 3 / consulted-work-not-readable, original requester context. Source rechecks the narrowed layers in both scopes. **Closed for reviewed narrowing behavior.** |
| F4 revision-collapsed cycles | Original acyclic exact-reference history now returns exit 0 / allowed. A further stale-selection mutation reaches assignment-stale, not a fabricated cycle. Real-cycle and cycle-before-continuity fixtures pass. **Closed.** |
| F5 ordering/message priority | Original forward/reversed shape cases both yield shape-enum-mismatch; original message case now yields message-is-not-authority. These witnesses close, but **F5 overall remains OPEN via R5-1**. |
| F6 ownership inventory | Both maintained inventories now include UID/GID; maintained and independent before/after tests pass. **Closed.** |
The fixed `registry-declaration-missing` diagnostic is consistent with the pinned
coordinator ruling and the declaration/admission distinction: it is an exit-3
missing-state refusal for a missing consulted external declaration, not the exit-2
ordinary-record reference rule. I independently combined missing declarations with
structural missing records, duplicates, invalid typed profiles and unsupported
operations: each earlier gate still wins with its specified exit/rule. Registry
lookups remain exact in registry/id/revision/digest; no live authority is inferred.
| Gate | r5 disposition |
|---|---|
| A1 | Tested positive read/assigned-change text and JSON outputs, goldens, disclaimers and no-effect observations pass. |
| A2 | Missing registration/cross-project selection and privacy/no-fallback fixtures pass. |
| A3 | Reference, ownership, duplicate, history and genuine-cycle detector/CLI tests pass; exact revision fix independently reproduced. |
| A4 | Tested role/policy/task/mission/execution/issuer intersections, path bounds and no-assignment-union cases pass; F1F3 witnesses corrected. |
| A5 | Strict parser and separate schema/profile oracle pass tested domains; 831 independent typed-LF probes refuse before admission. Unicode/free-text positives remain valid. |
| A6 | Static runtime I/O/import review retained; descriptor, ownership-inclusive inventory and canary checks pass within bounded evidence limits. |
| A7 | Both requester contexts/narrowing checked in source/tests; original selection retained; no allowed reassignment branch. Original F2/F3/message witnesses corrected. |
| A8 | Closed fields, exits 0/2/3/4, escaping and body-free errors pass tested cases. **Not satisfied overall: R5-1 violates stable first-failure ordering.** |
| Offline-demo integration prerequisite | Inspector, oracle, checker, config/auth/conductor independently pass. Task/release **NOT RUN / DEFERRED**, not green. |
| A9 | Not performed. Jason's separate demo acceptance remains required and is not implied by this review. |
Prior C1C5 closures remain supported by r5 identity and rerun tests: corrected demo
digest/copy equality; genuine zero-waiver schema comparison plus strict production
profile; twelve closed result fields with process exit separate; saved-before versus
after comparisons; and required O_RDONLY/O_NOFOLLOW/O_NONBLOCK with FIFO refusal.
The calendar platform witness and original LF witnesses remain. No trimming or
normalized identity lookup replaces production refusal.
## 4. Executed commands and independent receipts
Commands were inspected before execution. From the isolated export, using `env -i`,
synthetic HOME/TMPDIR, `PYTHONDONTWRITEBYTECODE=1`, `NO_COLOR=1` and PATH
`/home/jwoltje/.pyenv/versions/3.12.8/bin:/usr/bin:/bin`:
| Command | Exit and actual result |
|---|---|
| `node --test scripts/foundation/` | 0; **77 pass, 0 fail, 0 skipped** |
| `bash scripts/test-foundation.sh` | 0; **43 pass, 0 fail**, including scratch-only fixture regeneration equality |
| `python3 scripts/foundation/verify-schema.py` | 0; **1563 records**, 539 agree-valid / 987 agree-invalid / **0 disagreements**; 27 parser-bound unassessed, 10 unsupported-kind unassessed; 509 profile-valid / 30 profile-invalid; 73 named probes verified |
| `python3 docs/plans/foundation-v1-candidate/check.py` | 0; all pinned author checks pass, including 38 record shapes, 16 paths, 7 restricted fingerprints, 155 runtime/artifact shapes and 35 synthetic model cases; not runtime enforcement |
Measured versions: **Node v26.8.1, Python 3.12.8, jsonschema 4.26.0**. The year-999
`strftime('%Y')` witness is `999`, as required by the pinned checker on this platform.
Non-live integration ran via `python3 integration.py` in the separate disposable
`<evidence>/integration-fixture` copy. It seeded a **disposable test Git repository**
so the conductor suite could clone/commit/reset only its own test fixtures. Git
system/global configuration was disabled, HOME/TMPDIR synthetic, and no shared Git
mutation occurred. Commands `bash scripts/test-config.sh`, `bash scripts/test-auth.sh`
and `bash scripts/test-conductor.sh` each exited **0**, respectively **24/0, 15/0,
17/0 passed/failed**. Auth inputs were fabricated test canaries, never real credentials.
Failing guards for docker/podman/curl/wget/ssh were installed ahead of PATH and were
**never invoked**; they did not simulate services or supply passing branch results.
Additional independent harnesses, all under the evidence root:
- `python3 review-probes.py`: exit 0 verifies the nine corrected original witnesses,
**six remaining Unicode ordering counterexamples**, and four stable ASCII control
pairs (29 CLI executions). Exit 0 here means the recorded findings were reproduced,
**not** that the candidate passes the counterexamples.
- `python3 interactions.py`: exit 0; eight independently constructed stage-order,
message/issuer, history/currentness and Unicode-positive interactions pass.
- `python3 profile-probes.py`: exit 0; **831** typed-identity single-final-LF mutations
produce exit 2 / profile-pattern-mismatch with selection/operation/proposal/diagnostic
all null; a multiline mission objective remains allowed.
- `python3 non-effect.py`: exit 0; **15** text/JSON/parser/I/O/usage executions, **16**
unchanged inventory entries including path/type/size/mode/UID/GID/inode/mtime-ns/
content-or-symlink-target; observed fixture/home/cwd/data roots separate from logs.
- `python3 recheck.py`: exit 0; final shared/export candidate identities and HEAD pass.
Selected hashes, relative to the evidence root:
| Artifact | SHA-256 |
|---|---|
| `node-tests.log` | `9cf6f45864e50b7c81e50c31e88d76bf41e6c046d54284205ea21f14f2bc7654` |
| `selftest.log` | `a9eacfc0f8679cd0a6688d2dd3f705528f5b0c1299cf822e61e7be33f578af1e` |
| `oracle.log` | `7bffe6dc27383ee65d2a6b39443aafccab24d2e9247982de2719d29411d929fb` |
| `integration-receipts.json` | `9f576d011b598fab9ac03c56ee68bf0d1ba5eba902d15a22a4742ebe06e8afcb` |
| `review-probe-receipts.json` | `4c46cd6ebd0fc6cb560172e9364f9a6e34a8182b1b869c58ab70f3b76de9ba91` |
| `review-probes.py` | `aa8132dd0a32878d3c94e0475bd34a2348d452af33538ee990a81283f53af107` |
| `profile-probe-receipts.json` | `6c067bcd6c4d88482b410e4e91f228ae5ef293156670b32c13d88544bcba463a` |
| `interaction-receipts.json` | `3e27aee6492ee121f88f28cc00e20af0f2c63d086772210a3030d054784301c6` |
| `inventory-before.json` and `inventory-after.json` (identical) | `5a4feeb061565506317b81dcc3af9bda310674bf0b8aa6ad0972286771ceda59` |
| `recheck.log` | `edad63227d0c0f7ef8fc08869334fd19dc8a2f0e5a1dba5298b4e907367775ed` |
Scratch is local/disposable evidence, not a durable repository receipt. The minimal
recipes and frozen demo identity above permit reconstruction without modifying
shared fixtures.
## 5. Deferred coverage, limits and handoff
**`scripts/test-task.sh` and `scripts/test-release.sh`: NOT RUN / DEFERRED** under
Jason's 2026-09-07 offline-demo decision. They are not passed, skipped-as-green or
fully covered. Full deployment/integration testing remains a later gate before
dependent live runtime work. The recorded correction that r3 ran live branches
stands; the new decision neither retroactively authorizes nor relabels that history.
No such branches were executed in this review.
Finite tests and inventories are not OS containment, proof of no reads, full schema
or Unicode equivalence, authentic delegation, crash safety, same-size-race defense
or parent-path containment. Only Node v26.8.1 was executed. No installation,
provider/engine/container/network/native/sync/live-data work or investigation of the
operator's actual credentials/HOME/`~/.mosaic` occurred. Git mutations were confined
to the explicitly authorized disposable conductor fixtures. No shared index,
implementation, fixture, charter, prior verdict, log or CURRENT changes; this verdict
is the only repository write for FI-FILBERT-7.
**Return to darkwing:** reconcile R5-1/F5, authorize Rocko alone to correct owned
code if appropriate, then provide a newly hashed frozen candidate for re-review.
The offline-demo code gate is **NOT APPROVED**. No automatic implementation,
owner acceptance, demo completion, push, issue closure or dependent phase advance;
no deadline or timer is set.
@@ -0,0 +1,248 @@
# FI-FILBERT-8 — r6 independent CODE verdict: APPROVED
**APPROVED for the bounded offline-demo code gate only.**
Reviewer: filbert. Sole implementation author: rocko. Coordinator/follow-up: darkwing.
Date: 2026-09-07. No competing assignment is known; I have not authored or fixed the
implementation. Owner A9/demo acceptance remains a separate subsequent gate.
R5-1 is closed: all six exact prior Unicode witness pairs now have stable first
failures. Independent broader-domain and interaction checks support the correction.
No blocking inspector-code finding remains in this review. Two nonblocking
qualifications below correct the byte-identity claim and preserve an auxiliary
native-parser observation without mislabeling it as a passing check.
## 1. Exact reviewed identities and source boundary
| Input | SHA-256 / commit |
|---|---|
| `docs/plans/reviews/2026-09-07_foundation-inspector-rocko-build-manifest-r6.json` | `a4a4493000aff5905337a643886ca36e7c5377d52deed77b8aeab7174ca73dcf` |
| `docs/plans/reviews/2026-09-07_foundation-inspector-rocko-build-r6.md` | `ee0e83efd7c71eddecf5e26f939e9a34ba85b184cfcd1cffac9ff9e56ea13c37` |
| Charter candidate 3 | `19b6721128a627a2032ffdb95ece2d50abe69a8f6d521e9eff8bbdaff22798b6` |
| Incorporated feasibility r2 §§513, subject to charter overrides | `f2f47fcfe22dca79f10f885b83d87a2f846fdb560425a4e20705c40ce4a123e1` |
| Pattern/profile addendum | `afe2980be2f91e701dae5af3018831ac5c300474f52bcc06e740ce5b5cc68ca5` |
| Pinned record schema | `05774aaf6943cb69c113e39ff1c29676a2a230ca7bf665c50dbcaa8049672af6` |
| Pinned checker | `82564a7d3200afcdda0850a9454cac6e6cd6a76687d2162c13cf214d7eac4607` |
| Owner offline-demo test-gate decision | `62cea74bea59e69f29c8a29a9c0311fdc6feffa2c337bc6a141db55149204898` |
| Preserved r5 NOT APPROVED verdict | `154e7b5d804c059d6fec4c936c78e4ae33bb7fc273ba3a5eec7b00d0a9ce1e59` |
| Source/schema baseline | `d4696d09eb1b5dcf1028f30db2cd63735f51cb16` |
| Measured integration HEAD | `9a5fbdbda74b16adf488fe28138b2ba69ea5e669` |
Independently verified before execution and rechecked at **2026-09-07T15:48:19Z**:
382 distinct regular candidate files, exact allowlist/no extras, sizes, modes,
SHA-256s, all six aggregates, report/manifest hashes and every pinned input. Both
shared candidate and exported copies pass. HEAD remains unchanged. This uncommitted
code is bound by the manifest, not falsely claimed to be committed at that HEAD.
Export: `/tmp/fi-filbert-8.ehrv19oo`.
Separate harness/evidence: `/tmp/fi-filbert-8.ehrv19oo-evidence`.
Compared with r5: five candidate files changed, thirteen fixtures added, none removed.
The CLI, strict parser, mock canonicalizer, oracle and other unchanged implementation
paths retain their verified prior identities; changed source/tests/generator were
inspected before execution.
The working-tree `scripts/agent.sh` and `docs/TOOLS.md` modifications were excluded.
Required integration dependencies were exported from the committed baseline. The
relevant agent/common/auth/config/conductor scripts, three authorized legacy tests,
package/RELEASE/policy/README dependencies have no committed difference between that
baseline and measured HEAD. Approval does not cover unrelated working-tree or
native/fleet/goal changes, nor a deployment of the entire current working tree.
## 2. Findings and dispositions
### 1. R5-1 / F5 — CLOSED: total ordering tie-break
Frozen `scripts/foundation/resolve.mjs` SHA-256:
`c4951014828080caf9a5038845104afdac02465af10e94a2fddd3558b29621a3`.
`orderingForm` at approximately lines 730739 replaces the partial ASCII
canonicalizer in `stableOrder`'s tie-break at approximately 755770.
Over the actual strict-parser domain, it preserves scalar distinctions, Unicode
strings, array order and object members while sorting object keys by UTF-16 code
unit. Safe integer bounds, paired surrogates, dense arrays and bounded acyclic objects
are supplied by the parser; arbitrary JavaScript objects/nonfinite numbers/getters
are not claimed as supported inputs to this helper. The former exception-to-empty-
string collapse is gone. No normalization, case folding or new Unicode ban appears.
The ordering form is internal, not a digest or emitted record body.
I reran the **exact twelve prior Unicode witness files**, checking their input hashes
against the prior review receipts. All four unkeyed-family pairs now return exit 2 /
shape-type-mismatch; both equal-key pairs return exit 2 / shape-unknown-field in both
orders. The four prior ASCII control pairs also remain stable.
Independent extension beyond writer examples:
- **2,540 strict-parser values**, including safe-integer extrema, all JSON types,
NFC/NFD/case distinctions, BMP/non-BMP strings and keys, escaped controls, prototype-
named keys, numeric-looking keys, maximum-length strings, 1024-member arrays/objects
and depth-32 structures. Forms matched an independently implemented Python
UTF-16-key-sorted reference for every value; **1,663 distinct structural values/forms**
had no collisions. Strict-parser round trips and input immutability passed.
- **120 evaluations**: all 24 permutations of four further malformed entries in each
of the five inventory families; emitted first outcomes remained stable.
- **Ten additional equal-key malformed-record pairs / twenty CLI runs** spanning
Unicode and escaped control display names. Competing enum/missing-field failures
matched the first entry independently predicted by Python's ordering reference;
all pre-admission nulls remained intact.
These are finite compatibility/regression measurements, not exhaustive proof.
### 2. NONBLOCKING — “byte-identical” should say structurally equal parsed values
The report §§2.2/3(a), `stableOrder` comment and test wording overstate the final
index fallback. For example, raw `{"é":1,"a":2}` and
`{"a":2,"\u00e9":1}` have different bytes and insertion orders but the same
ordering form. I independently asserted this distinction and the index tie.
That is correct for JSON object structural equality: member order, whitespace and
escape spelling do not create different values. Array order and distinct string
values remain significant. Thus this is a prose qualification, **not a reopened code
ordering defect**. Future reports/comments should use “structurally equal parsed
values,” not claim byte identity or general JCS conformance. No file was fixed here.
### 3. NONBLOCKING, scoped verification observation — native JSON.parse round trips
An auxiliary warm-run test initially failed a native `JSON.parse`/deep-equality
round-trip comparison. With all anomalies retained, **19 of the 2,540 comparisons**
showed native reparse discrepancies involving object keys. For the initial case,
Python confirmed the raw input, strict-parser serialization and ordering form were
structurally equal; a separate cold native probe did not reproduce that discrepancy.
The full rerun independently verified **every ordering form against Python**, and
strict-parser round trips passed. Detailed raw/form/native-reparse evidence is saved
in `domain-native-disagreements.json`; underlying native-runtime cause is not claimed
as diagnosed or fixed.
This is **not** relabeled as a passing native-parser test or a waived schema mismatch.
The required pinned record oracle was unmodified and independently reported zero
schema disagreements. Production inspector/strict-parser/resolver/canonicalizer
paths do not call native `JSON.parse`; their inspected parsing path uses `parseStrict`.
The observed auxiliary native-reparse behavior therefore does not demonstrate an
inspector-code defect or invalidate the independent form/reference comparison.
Approval remains limited to the tested offline inspector, not general native JSON
parsing, the platform or a live runtime. Preserve this evidence for separately
scoped follow-up rather than asserting universal parser equivalence.
## 3. Retained original findings and A1A8
The original nine F1F5 witness inputs were also rerun unchanged. Actual outcomes:
| Finding | r6 disposition |
|---|---|
| F1 declarations | Missing agent registry declarations: exit 3 / missing-state / registry-declaration-missing. Undeclared dependency authorization: exit 3 / missing-state / authorization-undeclared. **Closed.** |
| F2 work.read | Assigned task-only change and task-only proposal refuse consulted-work-not-readable; taskless positives preserved. **Closed.** |
| F3 issuer narrowing | Original issuer-denies-work.read witness refuses consulted-work-not-readable in original requester context; both narrowed contexts remain checked. **Closed.** |
| F4 exact-revision cycles | Original acyclic history allowed; stale selection subsequently reaches assignment-stale. Genuine-cycle/precedence fixtures pass. **Closed.** |
| F5 ordering/message | Original shape-order pair and message priority corrected; all R5-1 pairs now corrected with broader coverage above. **Closed**, subject to structural-equality wording qualification. |
| F6 ownership evidence | Maintained UID/GID checks and independent ownership-inclusive inventories pass. **Closed.** |
The new fixed registry-declaration-missing diagnostic retains the reviewed admission-
stage exit-3 missing-state semantics. Eight independently rerun interactions preserve
structural/duplicate/profile/unsupported-operation precedence ahead of missing
external declarations, message priority, history/currentness and Unicode positives.
| Acceptance group | Independent disposition within tested scope |
|---|---|
| A1 | Positive read/assigned-change previews, exact text/JSON goldens, disclaimers and bounded no-effects checks pass. |
| A2 | Missing registration/cross-project selection refusals, no fallback and body-free privacy checks pass. |
| A3 | Reference, duplicate, ownership, continuity and revision-exact cycle tests pass; detector and CLI precedence remain distinct. |
| A4 | Mandatory and optional policy layers, role/issuer/task/mission/execution narrowing, paths and no-assignment union tests pass; original F1F3 witnesses corrected. |
| A5 | Parser/format/bounds negatives, zero-waiver record oracle, strict production identity profile and permitted Unicode/free-text controls pass tested domains. |
| A6 | Static I/O/import limits, descriptor tests, canaries and unchanged ownership-inclusive inventories pass; no containment/no-reads proof claimed. |
| A7 | Both requester contexts, issuer rechecks, original-selection retention and negative/unresolved-only reassignment tests pass; no allowed reassignment branch. |
| A8 | Closed output/exit classes, escaped diagnostics, pre-admission nulls and stable first-failure tests pass, with equality wording and auxiliary native-parser limits above. |
C1C5 remain closed for the reviewed candidate: corrected demo identity/copy equality;
genuine pinned schema agreement plus separate production profile; exactly twelve
serialized fields and process exit separate; saved-before versus after inventories;
required O_RDONLY/O_NOFOLLOW/O_NONBLOCK and FIFO refusal. No O_CLOEXEC, authentic
permission, runtime reconciliation or complete schema-equivalence claim is added.
## 4. Actual commands, results and evidence
Commands inspected first; all candidate executions used the isolated export.
Measured versions: **Node v26.8.1, Python 3.12.8, jsonschema 4.26.0**.
The pinned year-999 `strftime('%Y')` witness remains `999`.
From the export, with `env -i`, synthetic HOME/TMPDIR,
`PYTHONDONTWRITEBYTECODE=1`, `NO_COLOR=1`, and PATH
`/home/jwoltje/.pyenv/versions/3.12.8/bin:/usr/bin:/bin`:
| Command | Actual result |
|---|---|
| `node --test scripts/foundation/` | Exit 0; **80 passed, 0 failed, 0 skipped** |
| `bash scripts/test-foundation.sh` | Exit 0; **43 passed, 0 failed**; fixture regeneration only in disposable scratch |
| `python3 scripts/foundation/verify-schema.py` | Exit 0; **1568 records**; 540 agree-valid, 991 agree-invalid, **0 disagreements**; 27 parser-bound and 10 unsupported-kind unassessed; 510 profile-valid/30 profile-invalid; 73 named probes verified |
| `python3 docs/plans/foundation-v1-candidate/check.py` | Exit 0; all pinned author checks pass, including 38 record shapes, 16 paths, 7 restricted fingerprints, 155 runtime/artifact shapes and 35 synthetic model cases; not runtime enforcement |
`python3 integration.py` independently ran the committed non-live tests in a separate
`<evidence>/integration-fixture` copy: `bash scripts/test-config.sh` **24/0**,
`bash scripts/test-auth.sh` **15/0**, `bash scripts/test-conductor.sh` **17/0**
passed/failed, each exit 0. The authorized seed/clone/commit/reset operations occurred
only inside disposable conductor test repositories. Git global/system configuration
was disabled; HOME/TMPDIR were synthetic. Engine/network-command guards were never
invoked and did not substitute simulated successes. Auth data were fabricated test
canaries, not actual credentials.
Additional scratch commands and receipts:
- `python3 reproduce.py`: exit 0; 29 exact prior inputs, covering nine original
findings, six Unicode pairs and four ASCII pairs; preserved hashes checked.
- `python3 domain-probes.py`: initial auxiliary native-round-trip assertion failed;
preserved in `domain-probes.log`. The instrumented rerun, logged separately in
`domain-probes-rerun.log`, exited 0 after recording all native anomalies and
independently checking all 2,540 forms with Python and strict-parser round trips.
No candidate code or mandatory oracle was changed.
- `python3 equal-key-probes.py`: twenty final CLI checks pass, exit 0. The first
reviewer harness expected type-mismatch for numeric status; the established enum
checker emits enum-mismatch. That **reviewer expectation** was corrected and the
original failed log preserved; the candidate was unchanged.
- `python3 profile-probes.py`: exit 0; **831** typed single-final-LF probes refuse
exit 2 / profile-pattern-mismatch with selection/operation/proposal/diagnostic null;
multiline objective remains allowed.
- `python3 interactions.py`: exit 0; eight independent interactions pass.
- `python3 non-effect.py`: exit 0; fifteen text/JSON/parser/I/O/usage runs; sixteen
unchanged path/type/size/mode/UID/GID/inode/mtime-ns/content-or-symlink-target entries.
Observed roots and harness output are separate; no synthetic canary output.
- `python3 recheck.py`: exit 0; final shared/export identities, all pins and HEAD pass.
Selected hashes, relative to `/tmp/fi-filbert-8.ehrv19oo-evidence`:
| Artifact | SHA-256 |
|---|---|
| `node-tests.log` | `ca295bd80df32558d8d75d48c336ca6cc68bc74edb754ca4e5875247f8015c8d` |
| `selftest.log` | `e856f3fd68bcca7442f809e7a53af4aa674fd6483486120d429917688c4216a2` |
| `oracle.log` | `40e7311b1aed62c12aaba4ad4dd9eca3d43b46b2785f1abc4263be9d85e93653` |
| `integration-receipts.json` | `9f576d011b598fab9ac03c56ee68bf0d1ba5eba902d15a22a4742ebe06e8afcb` |
| `reproduction-receipts.json` | `a2677c32068ee62bd4bbdda89f44432252eeabfb6e433c97fccc28ff71d6b258` |
| `domain-summary.json` | `edd9c1f7f03d8c9249bf2c3627cd1c7c706c6cd90aefc24f67da7f655ccaa8cf` |
| `domain-native-disagreements.json` | `395ae878a3edfe481b22511d720d00e20064c5806f44cf95e597e8324fb3a254` |
| `equal-key-receipts.json` | `22f257f9145de8852255a547b14d79115d080f38bfbbcfde30c024c4afeb5ff3` |
| `profile-probe-receipts.json` | `6c067bcd6c4d88482b410e4e91f228ae5ef293156670b32c13d88544bcba463a` |
| `inventory-before.json` and `inventory-after.json` (identical) | `494f2dbf66a48d3aba5c6731508859b05414c80a52a855708a2859dc5f5df57c` |
| `recheck.log` | `c121172527c5ccb47e4ca6f9d5fb820a1d3580610bba2d34fb61aca9247d3f44` |
Scratch is local/disposable evidence, not durable repository publication.
## 5. Deferrals, limits and return
**test-task.sh and test-release.sh: NOT RUN / DEFERRED** under Jason's offline-demo
ruling. They are not green or fully covered. Full deployment/integration testing
remains a later gate before dependent live runtime work. The historical correction
that r3 ran live branches remains in force; this decision does not retroactively
authorize or relabel those actions. No live branches were executed here.
Finite tests/static review/inventories do not prove OS containment, absence of every
read, complete schema/native-parser equivalence, authentic delegation, crash safety,
parent-path containment or protection against same-size concurrent mutation. Only
Node v26.8.1 was executed. Approval covers no generalized JavaScript-call domain
outside strict-parser-produced values and no runtime permission engine.
No code fixes/co-authorship, dependency installation, shared staging/index/commit/
checkout/reset/push, provider/engine/container/network/native/sync/live-data work or
actual credential/HOME/`~/.mosaic` investigation occurred. Git mutations were solely
the authorized disposable conductor fixtures. This verdict is the only repository
write for FI-FILBERT-8; prior evidence and unrelated owner modifications are preserved.
**Return to darkwing: APPROVED at the exact r6 manifest for the bounded offline-demo
code gate.** Carry the nonblocking qualifications and deferred tests into the handoff.
Jason's separate A9 acceptance is still required. No automatic demo acceptance, push,
issue closure, live/dependent implementation, reassignment, timer or deadline follows.
@@ -0,0 +1,54 @@
# FI-ROCKO-6 — independent code findings to demo readiness
Jason directed: “Let's get this to demo.” Existing build/review authority continues;
it does not waive the independent approval or owner acceptance gates.
Sole code writer: rocko. Reviewer: filbert. Integration/follow-up: darkwing.
Recheck compatibility; no displacement of other owner work.
## Exact rejected candidate and evidence
Repository /home/jwoltje/src/mosaic-stack-dev-test.
R3 manifest SHA-256 3c2253b6c9f31e448c77aaac53977d41baecfb30e15845dcfffd8dc694428547.
Full verdict: docs/plans/reviews/2026-09-06_foundation-inspector-code-verdict.md
SHA-256 e4cc5970aab20240e6ea3a9a1513ef942ff167fefbb03356b9a32c89999adb3d.
Charter/addendum remain unchanged at 19b67211… / afe2980b…; use their full hashes
in the existing build/review requests. No specification relaxation is authorized.
## Required corrections
Read the FULL verdict and implement F1F5, plus maintained ownership coverage F6:
1. Enforce exact referenced registry declarations and consulted dependency
authorization declarations, preserving the documented missing-state stages/exits.
2. Require work.read whenever a context consults its assigned task or proposal
subject/target, even without mission/dependency references. Preserve taskless reads.
3. Recheck applicable work access after proposal issuer narrowing in BOTH scopes.
4. Preserve exact reference revisions in cycle graphs; never union different
historical revisions into an invented cycle. Preserve cycle-before-continuity order.
5. Stable within-stage shape failure order independent of record inventory order;
message-without-delegation priority after structural validation as specified.
6. Include UID/GID in maintained before/after inventory checks.
Use the review's concrete witness recipes as regression tests, checking intended
first failures and positive controls. If declared scratch evidence still exists,
verify its listed hashes before relying on it; otherwise reconstruct from frozen
demos and recipes. Do not inspect unrelated reviewer/fleet files. Do not edit the
verdict or claim a new rule where the contract is unclear: return a precise blocker.
## Allowed work and freeze
Original FI-ROCKO-3 code/test path allowlist ONLY. Additionally allowed new receipts:
- docs/plans/reviews/2026-09-07_foundation-inspector-rocko-build-r4.md
- docs/plans/reviews/2026-09-07_foundation-inspector-rocko-build-manifest-r4.json
Preserve all previous reports, manifests, charter, addendum and verdicts. No staging,
commit, checkout/reset, push, installs, native/sync/live/credential work or ~/.mosaic
investigation. Isolated synthetic tests only. Do not silently run legacy live branches
or substitute stubs/skips to claim integration green; report any test-authorization
blocker. Darkwing owns arranging the independent isolated integration gate identified
in the review, without broadening live-operation authority.
Return FI-ROCKO-6 admission/blocker, then exact full manifest, per-finding closure,
new witness receipts and all authorized required test results. Freeze the corrected
candidate for Filbert re-review. No owner-demo acceptance or dependent work is inferred.
Direct reply and declared report paths are the return mechanism; darkwing owns follow-up.
No timer, deadline or automatic approval.
@@ -0,0 +1,55 @@
{
"manifestSha256": "a4a4493000aff5905337a643886ca36e7c5377d52deed77b8aeab7174ca73dcf",
"verdictSha256": "ab9dd5e5c3cad5c9263e873ff82cac444da2d36040e907e4798b208fa1c08b13",
"isolatedRoot": "/tmp/foundation-owner-demo-r6.sje97ajy",
"node": "v26.8.1",
"observedRootsUnchanged": true,
"sharedCandidateHashesUnchanged": true,
"ownerAcceptance": "pending",
"cases": [
{
"case": "Permitted read",
"command": [
"/usr/bin/node",
"scripts/foundation-inspect.mjs",
"scripts/foundation/fixtures/demo/demo-read-w1.json"
],
"exit": 0,
"stdout": "SYNTHETIC PREVIEW \u2014 NO LIVE EFFECTS\npreview: no live registrations or permission grants\nauthentication: not-modelled; declarations: unverified-simulation\nresult: allowed\nreason: allowed\nrule: null\nselection: agent agent-a, project p1, workspace w1, assignment assignment asg-a-w1 @workspace:p1/w1 rev 1\noperation: work.read target null\nproposal: null\ndiagnostic: null\n",
"stderr": ""
},
{
"case": "Assigned change preview",
"command": [
"/usr/bin/node",
"scripts/foundation-inspect.mjs",
"scripts/foundation/fixtures/demo/demo-file-change-src.json"
],
"exit": 0,
"stdout": "SYNTHETIC PREVIEW \u2014 NO LIVE EFFECTS\npreview: no live registrations or permission grants\nauthentication: not-modelled; declarations: unverified-simulation\nresult: allowed\nreason: allowed\nrule: null\nselection: agent agent-a, project p1, workspace w1, assignment assignment asg-a-w1 @workspace:p1/w1 rev 1\noperation: file.change target workspace:src/main.mjs\nproposal: null\ndiagnostic: null\n",
"stderr": ""
},
{
"case": "Unregistered workspace",
"command": [
"/usr/bin/node",
"scripts/foundation-inspect.mjs",
"scripts/foundation/fixtures/bundles/adm-workspace-registration-missing.json"
],
"exit": 3,
"stdout": "SYNTHETIC PREVIEW \u2014 NO LIVE EFFECTS\npreview: no live registrations or permission grants\nauthentication: not-modelled; declarations: unverified-simulation\nresult: refused\nreason: not-authorized\nrule: workspace-registration-missing\nselection: agent agent-a, project p1, workspace w1, assignment null\noperation: work.read target null\nproposal: null\ndiagnostic: null\n",
"stderr": ""
},
{
"case": "Reassignment cannot execute",
"command": [
"/usr/bin/node",
"scripts/foundation-inspect.mjs",
"scripts/foundation/fixtures/bundles/prop-all-pass-restricted-contexts.json"
],
"exit": 3,
"stdout": "SYNTHETIC PREVIEW \u2014 NO LIVE EFFECTS\npreview: no live registrations or permission grants\nauthentication: not-modelled; declarations: unverified-simulation\nresult: unresolved\nreason: unknown-effects\nrule: runtime-reconciliation-required\nselection: agent agent-a, project p1, workspace w1, assignment assignment asg-a-w1 @workspace:p1/w1 rev 1\noperation: assignment.change target null\nproposal: unresolved (unknown-effects; runtime-reconciliation-required) selected assignment assignment asg-a-w1 @workspace:p1/w1 rev 1\ndiagnostic: null\n",
"stderr": ""
}
]
}
@@ -0,0 +1,24 @@
# Owner decision — bounded offline-demo test gate
2026-09-07 14:47 UTC. Jason explicitly answered yes after clarification:
defer the two older mixed live suites for this offline inspector demo.
Deferred: scripts/test-task.sh and scripts/test-release.sh. Report them as NOT RUN /
DEFERRED under this owner decision, never passed or fully covered. This changes only
the test prerequisite for the bounded offline demo. It does not authorize live model
calls, deployment actions, weaker inspector behavior or permanent removal of tests.
Still required: all inspector unit/CLI/privacy/non-effect/differential checks,
foundation checker, authorized isolated non-live integration checks, Filbert's
independent code approval, and Jason's separate synthetic demo acceptance.
Disposable Git mutations required by conductor tests are confined to test copies,
never the shared index/repository. No credential/native/sync/live environment work.
Full deployment/integration testing remains a later gate before dependent live
runtime work. Record exact tested versions, hashes, executed checks and deferred
coverage in the next build report, review verdict and demo handoff. Preserve the
historical correction that r3 did execute live branches; this decision does not
retroactively authorize or relabel that execution.
FI-ROCKO-7 ordering corrections continue. No staging, commit, push, implementation
scope expansion, independent-review waiver or automatic owner acceptance follows.
@@ -0,0 +1,64 @@
# Inspector r6 — owner demo
Independent code verdict: APPROVED for the bounded offline demo (FI-FILBERT-8).
Code manifest: a4a4493000aff5905337a643886ca36e7c5377d52deed77b8aeab7174ca73dcf.
Verdict: ab9dd5e5c3cad5c9263e873ff82cac444da2d36040e907e4798b208fa1c08b13.
Coordinator ran all four examples in an isolated verified copy: expected outcomes
passed, observed copy/HOME unchanged, shared candidate hashes unchanged. Receipt:
2026-09-07_foundation-inspector-demo-receipt.json. This is not owner acceptance.
## Try it
From /home/jwoltje/src/mosaic-stack-dev-test, using the tested Node v26.8.1:
```sh
# Helper only shortens these four commands; it does not install anything.
inspect_demo() {
node scripts/foundation-inspect.mjs "scripts/foundation/fixtures/$1"
}
# 1. Permitted work-record read: allowed, exit 0.
inspect_demo demo/demo-read-w1.json
# 2. Assigned change of src/main.mjs: allowed PREVIEW, exit 0; no file is changed.
inspect_demo demo/demo-file-change-src.json
# 3. Workspace registration missing in this fixture: refused, exit 3.
inspect_demo bundles/adm-workspace-registration-missing.json
# 4. Even fully supplied mock reassignment evidence: unresolved, exit 3.
inspect_demo bundles/prop-all-pass-restricted-contexts.json
```
Run individually or together without `set -e`/`&&`: exits 3 for the negative
examples are expected, not crashes. Each bundle is an independent synthetic
scenario, not successive edits to live state. The third fixture removes w1's
registration; it does not claim to switch selection to w2.
Look for:
- The same explicit agent/project/workspace and selected assignment where applicable.
- `allowed` only as a hypothetical permission calculation, never an actual grant.
- `workspace-registration-missing` rather than a fallback to another workspace.
- `runtime-reconciliation-required` with the original assignment still selected.
- `SYNTHETIC PREVIEW — NO LIVE EFFECTS` on every result.
Optional: add `--json` immediately after scripts/foundation-inspect.mjs; inspecting
JSON is not required for acceptance. Do not pass credentials or actual work records.
## Your acceptance question
Are the selected scope, refusals and no-live-effects limitation clear, and does
this meet your expectations for this first offline inspector increment?
Report confusing output or unexpected behavior; do not certify security.
## Boundaries retained
Two legacy suites (task/release) are NOT RUN / DEFERRED by owner decision, not green.
Other required offline checks passed independently. No live registration, sandbox,
authentication, durable runtime, restart recovery, deployment or federation is proved.
Reviewer qualifications remain: ordering equality means structurally equal parsed
values, not raw byte identity; auxiliary native-parser warm-run anomalies remain
unresolved separate evidence, not a passed universal parser-equivalence test.
No code/comment fixes were made after approval. No commit, push or dependent runtime
work is authorized by this demo. Jason's A9 answer must be recorded separately.
@@ -0,0 +1,41 @@
# Inspector integration verification boundary — measured planning gate
Coordinator: darkwing. Date: 2026-09-07.
Status: source inspection, not test execution or a waiver of required coverage.
## Measured boundaries
- scripts/test-task.sh:408458 contains real marker and session/fork launches via
run-task.sh when docker info succeeds. Missing Docker skips these cases; that is
incomplete coverage, not a full green integration gate.
- scripts/test-release.sh:1015 backs up/restores RELEASE; :4752 deliberately
changes/removes it. Run only in a disposable repository copy, never the frozen
shared source. :5899 exercises activation/rollback against synthetic data when
Docker is available. Activation is health-gated; do not assume this is a purely
static test or harmless just because the release pointer is synthetic.
- scripts/test-conductor.sh:4051 clones into its temporary sandbox; later commands
stage/commit/reset there. Those fixture mutations are different from staging the
shared index, but require an explicitly permitted disposable Git test context.
An archive without Git history alone is insufficient for this suite.
## Required verification plan before full approval
1. Verify the corrected candidate and reviewed contract hashes before execution.
2. Prepare a disposable repository/test context with the necessary baseline history
and exact candidate bytes. No shared checkout, RELEASE mutation or index use.
3. Select a verification mode explicitly: complete suites with separately authorized
Docker/provider/session effects and runtime-only auth, or accurately limited
non-live coverage. Do not label skips, substitutes or stubs as the full suites.
4. If complete live-provider testing is authorized, constrain it to synthetic tasks,
temporary data/config/session roots, bounded requests and existing pinned images.
No production pointer, actual work/session adoption, credential-content reading,
provider-account mutation, image installation or separate fleet intervention.
Obtain the necessary explicit permission before executing these branches.
5. Record executed/skipped/failed cases and independent versus writer receipts.
The code reviewer must see the scope and exact candidate tested.
No new authorization is issued by this document. Current code fixes can proceed
independently under FI-ROCKO-6. At the 2026-09-07 14:28 UTC check, the declared r4
build report had not returned. Do not poll private panes or retry the delivered task.
Owner/test-scope direction and Rocko's exact corrected candidate are the concrete
conditions needed to finish the corresponding remaining gates.
@@ -0,0 +1,38 @@
# FI-ROCKO-7 — finish F5 across declaration inventories
Owner-authorized build corrections continue. Coordinator: darkwing; sole writer:
rocko. No new feature, live test, staging, commit or push authority.
Verified r4 report dff9f676ad0a97f6333a59d527e02ed55e7bcdca986fe9c1488280b84d4e677f
and manifest 2a2e885f9df3dd626a09fe5db6e28af67c289e54660872031c18f8aa40cb0826,
including all 331 file hashes/modes/sizes. Fixes remain author claims pending review.
F5 is not yet closed in full. Your disclosure says registries/artifacts/
authorizations/delegationInputs are still shape-validated in input order. Charter
§10.4 applies stable within-stage ordering, not just to the records array. Source
inspection also finds input-order registry digest-profile traversal at resolve.mjs:831.
Complete stable traversal across the applicable declaration inventories/stages using
appropriate typed identity keys and deterministic content tie-breaking for malformed
entries. Preserve stage/field precedence, original values and error privacy. Do not
change semantically ordered arrays such as instruction lists or canonical content.
Add multi-failure permutation tests for all declaration families, including differing
shape errors and competing profile/digest failures; demonstrate intended first-rule
stability rather than only a consistent nonzero exit. Do not mutate frozen input files
or invent an exception for declaration lists.
The new registry-declaration-missing rule is acceptable as a fixed diagnostic name
under existing missing-state refusal semantics; this is not an authority expansion.
Filbert must still confirm its application and stage/exit correctness in code review.
Allowed correction paths remain FI-ROCKO-3's implementation/test allowlist. New receipts:
- docs/plans/reviews/2026-09-07_foundation-inspector-rocko-build-r5.md
- docs/plans/reviews/2026-09-07_foundation-inspector-rocko-build-manifest-r5.json
Preserve r4 and prior evidence. Return FI-ROCKO-7 exact hashes, per-family tests and
all authorized required receipts; freeze for independent re-review. If the contract
is ambiguous, report a precise blocker rather than narrowing it silently.
Continue to withhold task/release live branches. Jason is being asked about deferring
those two mixed suites for this offline-only demo; no ruling exists yet. No fake full
suite pass, new waiver, credential access or live execution is permitted. The report's
correction that r3 included live branches must remain visible in history.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,319 @@
# Foundation inspector — rocko build report r4 (FI-ROCKO-6: corrections for FI-FILBERT-6 findings F1F6)
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 r1r3 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-missing` is 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 to
`authorization-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.** `shapeValidationOrder`
applies to `bundle.records` only; `registries`, `artifacts`, `authorizations` and
`delegationInputs` remain 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.read` the original scope has already failed first. The target branch is covered
by the `intersectLayers` algebra 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-stale` currentness check.
- (f) Agent declaration checks run after the agent-status check and before the policy
ceiling; a disabled agent therefore still refuses as `agent-disabled` first.
- (g) **Correction to r3 §6.** r3 stated "no engine launch". That was true of the
inspector work, but the r3 `test-task.sh` receipt (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:2x14: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 F1F5 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.sh` gates two sections on `docker info`: the adapter-seam mock
cases (container launches, no provider) and the live cases (`run-task.sh run` with
the real engine, provider credentials, session forks and onboarding recall). In this
session `docker info` returns 0, so an unmodified run executes both sections.
- `scripts/test-release.sh` gates its state-machine cases on `docker 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 empty `PATH`) would print the suites' own "skip … (docker unavailable)"
lines and additionally fail `test-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.
@@ -0,0 +1,259 @@
# 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 r3
`test-task.sh` 90/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.json` expectation 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 730767): the generic stable
traversal. `keyOf` returns a typed key (array of `string | integer | null`
components) or `null` when the item has no readable identity. Order: keyed items
before unkeyed; keys component-wise (a `null` component 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; `detail` remains internal).
- `ORDER_KEYS` (exported, 801807), 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 → `null` component);
`shapeValidationOrder` now delegates to `stableOrder`, behaviour-preserving (all
r4 F5 tests and fixtures unchanged);
- registries: `[registry, id, revision, digest]`; unkeyed unless `registry` and
`id` are strings;
- artifacts: `[runId, artifactId, digest]`; unkeyed unless `runId`/`artifactId` are strings;
- authorizations: `[runtimeId]`; unkeyed unless a string;
- delegationInputs: the `decisionRef` kind/id/scope/revision key; unkeyed unless
the ref is readable.
- `checkInventory(v, path, itemCheck, keyOf)` (813818): bounds first
(`shape-type-mismatch`, `shape-bound-exceeded` at the array path, as before), then
each item in stable order with its input-index path. Used for the four declared
inventories in `validateBundleShapeScoped` (821823 and 857864). 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 (871884): content-digest traversal iterates
`stableOrder(b.registries, ORDER_KEYS.registries)`; rules, reasons and paths unchanged.
- `Model` constructor (10841089): computes `this.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 authorization `Set`, `delegationInputs.find`)
are order-independent once duplicates are rejected and are untouched.
- **Semantic sequence arrays are not reordered.** `checkArray` is unchanged and still
used, in input order, for `operations`, `readPaths`, `writePaths`, `endpointRefs`,
instruction/skill/context-content lists, `dependencies`, `subjectRefs`,
`evidenceRefs` and every other ordered array; canonical content is never
reordered; `evaluate` does 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` 10761230; tests in `resolve.test.mjs` 548712)
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 FisherYates 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-unsupported` share 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-missing` semantics.** 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
(23 entries). The helper's own ordering is asserted directly on hand-built lists.
- (e) **Locator (`detail`) remains internal.** The tests read it through `evaluate`
only; `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.
@@ -0,0 +1,225 @@
# Foundation inspector — rocko build report r6 (FI-ROCKO-8: R5-1 total tie-break over the strict-JSON domain)
Author: rocko (Claude Fable 5.1). Coordinator: darkwing. Reviewer: filbert. Task: FI-ROCKO-8.
Written 2026-09-07 15:35 UTC. Supersedes nothing: the original report, the r2r5
reports and manifests, the charter, the addendum, all verdicts, the corrections
request, the ordering follow-up and the demo test-gate decision are preserved unedited.
This revision corrects exactly the FI-FILBERT-7 finding R5-1 (verdict
`docs/plans/reviews/2026-09-07_foundation-inspector-code-verdict-r5.md`, sha256
`154e7b5d804c059d6fec4c936c78e4ae33bb7fc273ba3a5eec7b00d0a9ce1e59`), records what
changed r5 → r6, the new Unicode permutation regressions, and the frozen candidate for
independent re-review.
## 0. Admission, compatibility and blockers
FI-ROCKO-8 is **admitted and compatible** with the standing chain, the FI-ROCKO-3 build
request, the corrections request, the ordering follow-up, the demo test-gate decision
and the FI-FILBERT-7 verdict; the work stays inside the original source/test allowlist
plus the two r6 receipt paths named in the task. C1 (Archify rev 3) remains HELD with no
lane action. **No open blocker.** `scripts/test-task.sh` and `scripts/test-release.sh`
remain **NOT RUN / DEFERRED** under the owner decision (§7); no live test authority is
claimed.
Inputs bound to this revision (all hashes machine-read; full list in the r6 manifest
`pinnedInputs`, which adds the r5 report, the r5 manifest and the FI-FILBERT-7 verdict
to the r5 list):
| Input | sha256 |
|---|---|
| charter `docs/plans/2026-09-06_foundation-inspector-charter.md` | `19b6721128a627a2032ffdb95ece2d50abe69a8f6d521e9eff8bbdaff22798b6` |
| addendum FI-C2-1 | `afe2980be2f91e701dae5af3018831ac5c300474f52bcc06e740ce5b5cc68ca5` |
| code verdict FI-FILBERT-6 | `e4cc5970aab20240e6ea3a9a1513ef942ff167fefbb03356b9a32c89999adb3d` |
| code verdict FI-FILBERT-7 (r5, NOT APPROVED, R5-1) | `154e7b5d804c059d6fec4c936c78e4ae33bb7fc273ba3a5eec7b00d0a9ce1e59` |
| corrections request | `35c237f5c001832a0cfed23b03ff7530ffa78443612ffe11130fe456b968bd61` |
| ordering follow-up | `e93a65b94fd4df8bd6e74c2f38afaf02e0f86b36632ff5a820fd8ac464c22101` |
| demo test-gate decision | `62cea74bea59e69f29c8a29a9c0311fdc6feffa2c337bc6a141db55149204898` |
| r5 report | `17c67427dfdf1bc5dac491c4d0223928e87fdfc67a26175ac239eb2b2f7b7dec` |
| r5 manifest (369 files) | `a63bb103e4cfe51bbd8a42cd95545f935ac83c1da51cf469298375cf94ced135` |
| pinned schema / checker / fixtures | `05774aaf…2af6` / `82564a7d…4607` / `d433d06d…da85` |
Git: HEAD `9a5fbdbda74b16adf488fe28138b2ba69ea5e669` (main), unchanged throughout;
nothing staged. Tracked modifications present in the worktree: the pre-existing
`BUILD-LOG.md`, `docs/SESSIONS.md`, `docs/plans/CURRENT.md`, plus `docs/TOOLS.md` and
`scripts/agent.sh`, which were modified by another session at 15:04 UTC (outside the
allowlist; not touched, not inspected beyond `git status`, reported here only). 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
- r5 report and manifest: unedited, hashes above re-verified after the r6 build. The
r5 §3(a) claim that "two entries with equal typed key and equal canonical content are
indistinguishable" was **wrong** for non-ASCII entries (R5-1); it is corrected here
(§2), not by editing r5.
- r4 report/manifest, r3 report (`ec0444c9…5508`) and manifest (`3c2253b6…8547`):
unedited. **The r4 §3(g) correction stands and is repeated so it stays visible:** the
r3 `test-task.sh` 90/0 receipt did execute the suite's Docker and live branches,
contradicting r3 §6 "no engine launch". r3 is not relabeled; those actions were not
repeated in r4, r5 or r6 (§7).
- Charter, addendum, both verdicts, corrections request, follow-up, decision doc,
pinned schema/checker/fixtures, `canonical.mjs` (`a7760882…0172`, the mock-digest
canonicalizer): unedited.
- Every pre-existing fixture bundle, raw case, demo copy and golden is byte-identical
to r5 (manifest diff r5 → r6: 5 files changed, 13 bundles added, 0 removed; §4).
Every prior `index.json` expectation is unchanged; only 13 cases were appended.
## 2. Correction of R5-1
### 2.1 The defect
r5 `stableOrder` broke equal-key and unkeyed ties on `canonicalize()`, the ASCII-only
mock content-digest canonicalizer, and mapped its `CanonicalError` to the empty string.
Every entry containing a non-ASCII string therefore had the same tie-break form, and
two *distinct* such entries with equal typed keys (duplicates) or no readable key fell
through to the input index, restoring input-order-dependent first failures — exactly
filbert's six reversed-pair witnesses. The defect was a wrong choice of domain: the
mock digest domain is deliberately narrower than the strict-JSON input domain (Unicode
record values and logical paths are permitted input), so a digest canonicalizer can
never be a total order over inputs.
### 2.2 Implementation (`scripts/foundation/resolve.mjs`, r6 lines 719771)
- `orderingForm(value)` (exported, new): a total ordering form over the strict-JSON
parser's output domain (`null`, booleans, safe integers, any well-formed Unicode
string, arrays, objects): literals as JSON literals, strings and keys as
`JSON.stringify` literals, arrays in order, objects with keys sorted by UTF-16 code
unit, compact separators, no normalization or case folding, no length or depth
limit beyond the parser's own bounds. Every parser-producible value has exactly one
form and distinct values have distinct forms (injective), so the index fallback in
`stableOrder` now decides only between byte-identical entries. It throws a plain
`Error` only for non-JSON values, which `parseStrict` never yields; there is no
`CanonicalError` path. It is **not** a digest, is never emitted or compared with
a declared digest, and is not a validity judgement: `canonical.mjs` and the
`inspector-content-digest/1` domain are untouched and `mock-content-unsupported`
semantics are unchanged.
- `stableOrder(items, keyOf)`: unchanged except that the memoized tie-break calls
`orderingForm(items[i])` instead of the `canonicalize`/`CanonicalError` fallback.
Typed keys, keyed-before-unkeyed, component comparison and the input-index locator
are exactly r5. `ORDER_KEYS`, `checkInventory`, `shapeValidationOrder`, the
digest/identity/structural traversals and `Model.order` are unchanged.
- Nothing else changed: no blanket Unicode rejection (the Unicode positive controls
stay `allowed`), semantic sequence arrays are still never reordered, family and
stage precedence are unchanged, `detail` remains internal and no value is echoed,
the closed rule/reason/exit vocabulary is unchanged, no new dependency.
### 2.3 Regressions (fixtures in `build-fixtures.mjs` 12311266; tests in `resolve.test.mjs` 723801)
The fixtures rebuild filbert's witnesses from the base bundle. Each pair carries two
different shape failures on two distinct entries with a legitimate non-ASCII value,
forward and reversed; the expected first rule is the same in both orders and in every
permutation (`assertPermutationStable`, all permutations for ≤ 4 entries, the fixed
deterministic family beyond that).
| Case | Content | Expected first rule (both orders) |
|---|---|---|
| `shape-order-unkeyed-unicode-{records,registries,artifacts,delegation-inputs}-{forward,reversed}` (shape) | `[{"extra":"é"}, "é"]` as the whole inventory: two unreadable-key entries | `shape-type-mismatch` at the string entry (form `"…` sorts before `{…`); r5 flipped to `shape-unknown-field`/`shape-missing-field` in one order |
| `shape-order-equal-key-unicode-records-{forward,reversed}` (shape) | two `agent-definition/agent-a/system/1` copies, both `displayName: "Café"`, one `status: "invalid-status"`, the other an unknown `payload.extra` | `shape-unknown-field` at `.payload.extra` (the copy with the extra key sorts first: `"extra"` < `"harnessRef"`); removing the extra key yields `shape-enum-mismatch` (the pair really carries two errors) |
| `shape-order-equal-key-unicode-registries-{forward,reversed}` (shape) | two `agent-policy/ap-full/1/<same digest>` copies, `readPaths[0].path: "café"`, one `network: "everything"`, the other an unknown `restrictions.extra` | `shape-unknown-field` at `.content.restrictions.extra`; removing the extra key yields `shape-enum-mismatch` |
| `positive-unicode-display-name-allowed` (positive) | `displayName: "Café 😀"` on agent-a | `allowed` |
Unit tests: "R5-1: the ordering form is total and injective…" (37 hand-built values
covering every parser type, NFC/NFD and case-distinct strings, NBSP/U+2028, escapes,
nested arrays/objects, Unicode keys and values: 37 distinct forms; 12 of them (test bound ≥ 12)
are refused by `canonicalize()` with `CanonicalError`, proving the domains differ; key
order independent of insertion order and by code unit; array order semantic; string
form equals `JSON.stringify`; `stableOrder` on the unkeyed and equal-key Unicode pairs
in both input orders for all four families; only a `structuredClone` duplicate falls
back to the index), "R5-1: unkeyed Unicode entries…" (per family: permutation-stable
`shape-type-mismatch` with a null locator key, the two fixtures are exact reversals,
and the located entry is the string in both), "R5-1: equal-key Unicode entries…"
(permutation-stable `shape-unknown-field` with the asserted agent-a key and
`.payload.extra` / `.content.restrictions.extra` tails, the sibling enum error is
reachable, the Unicode positive stays allowed). The existing `stableOrder` unit test
keeps its r5 expectations (`"not-an-entry"` still precedes `{registry: 7}`).
Filbert's own witness files (`/tmp/fi-filbert-7.239u2bco-evidence/witnesses/`, read
only) through the r6 inspector: all six Unicode pairs now report the same rule in
both orders (`shape-type-mismatch` for the four unkeyed pairs, `shape-unknown-field`
for the two equal-key pairs).
Mutation witness (scratchpad copy only, discarded): with the r5 tie-break
(`canonicalize` + `CanonicalError → ""`) restored in the r6 tree, the three R5-1 unit
tests and the "evaluate over every bundle fixture" index check fail (the 13 new
`index.json` expectations flip), while all 34 other resolve tests pass; the r6
regressions therefore detect the r5 behaviour.
## 3. Disclosures for the reviewer
- (a) **Index fallback.** `a.i - b.i` remains as the final comparator and now decides
only between byte-identical entries (equal forms ⇒ equal values). The r5 §3(a)
wording was wrong for non-ASCII entries; the corrected claim is asserted by the
injectivity test and the equal-key fixtures.
- (b) **Ordering form vs. canonical digest.** Two different serializations now exist
in `resolve.mjs`/`canonical.mjs` on purpose: the digest form is the frozen mock
domain (ASCII, `CanonicalError` for everything else, unchanged); the ordering form
is total. They agree on the shared ASCII domain up to representation but are never
compared with each other. The ordering form is never written to output.
- (c) **Cost.** The form is computed at most once per entry per `stableOrder` call
(memoized) and only for ties; inputs are already bounded by the strict parser
(MAX_ITEMS/MAX_DEPTH/MAX_STRING_BYTES), so no new resource bound is introduced.
- (d) `registry-declaration-missing` semantics: unchanged; the FI-FILBERT-7 verdict
confirms them as consistent.
- (e) Permutation family for large inventories remains the fixed deterministic subset
(r5 §3(d)); the new unkeyed pairs have two entries (all permutations); the equal-key
records pair sits in the 36-record inventory (35 base records plus the copy) (deterministic family).
- (f) r3 live-branch correction (r4 §3(g)) remains in force and unrelabeled (§1, §7).
## 4. Changed files (r5 → r6 sha256; everything else byte-identical, 13 fixtures added, 0 removed)
| File | r6 sha256 | Change |
|---|---|---|
| `scripts/foundation/resolve.mjs` | `c4951014828080caf9a5038845104afdac02465af10e94a2fddd3558b29621a3` | `orderingForm`; `stableOrder` tie-break (§2.2) |
| `scripts/foundation/resolve.test.mjs` | `dca397f268cfd39feffae3839f57afc61fe74ca324645dd1d916219f38d4b15b` | three R5-1 tests; `orderingForm`/`canonicalize` imports; two comment/title words |
| `scripts/foundation/fixtures/build-fixtures.mjs` | `ea5a54028b75cc6f3fbce1666f6fad04b3df774a137b0fd281da0a1abb0d0cab` | 13 FI-ROCKO-8 cases (§2.3) |
| `scripts/foundation/fixtures/index.json` | `e5b2cf8d6ad0bab6aa232edf80492ca58dae260940f52cf87e34525b166b459a` | 347 cases (was 334) |
| `scripts/foundation/fixtures/README.md` | `c69c64a15b0a20105c46d6b8e04e32a80d8c9b025f9f47aa9e18679a69da8ed2` | tie-break wording; FI-ROCKO-8 paragraph |
| `scripts/foundation/fixtures/bundles/*` | 13 added (manifest) | none modified |
Group counts (`index.json`): admission 62, continuity 2, cycle 6, identity 7, lexical
19, operation 7, ownership 10, positive 22 (+1), profile 47, proposal 48,
registration-delegation 13, shape 97 (+12), structure 7.
## 5. Receipts (run 2026-09-07 15:2x 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 |
| `node --test scripts/foundation/` | 80 tests, 80 pass, 0 fail (was 77) |
| `python3 scripts/foundation/verify-schema.py` (jsonschema 4.26.0, pinned hashes) | PASS; corpus 1568 records; schema column agree-valid 540, agree-invalid 991, DISAGREEMENTS 0; profile refusals asserted 30 |
| `python3 docs/plans/foundation-v1-candidate/check.py` | PASS |
| `scripts/test-config.sh` / `test-conductor.sh` / `test-auth.sh` | 24/0, 17/0, 15/0 |
| `scripts/test-task.sh`, `scripts/test-release.sh` | **NOT RUN / DEFERRED** (owner decision, §7) |
| every new fixture through the CLI (`env -i`, `PATH=/nonexistent`, `HOME=/nonexistent`) | 13/13 match `index.json`; every pre-existing case unchanged; fresh generation equals the checked-in tree |
| filbert's six Unicode witness pairs through the r6 CLI | same rule in both orders for all six (§2.3) |
| git | HEAD unchanged, nothing staged, no candidate file tracked; no `__pycache__` created |
## 6. Constraints honoured
No edit to charter, addendum, verdicts, corrections request, follow-up, decision doc,
pinned schema/checker/fixtures, `canonical.mjs`, prior reports or manifests, CURRENT,
shared logs, root/package files, policies or runtime data. No blanket Unicode
rejection. 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 or 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, unchanged)
Per `2026-09-07_foundation-inspector-demo-test-gate-decision.md` (Jason, 2026-09-07
14:47 UTC): `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; no live model calls, deployment actions, weaker inspector behaviour or
permanent removal of tests are authorized. 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. The r3 execution of the
live branches (r4 §3(g)) is neither authorized nor relabeled.
## 8. Freeze
Frozen at the r6 manifest (`docs/plans/reviews/2026-09-07_foundation-inspector-rocko-build-manifest-r6.json`,
sha256 `a4a4493000aff5905337a643886ca36e7c5377d52deed77b8aeab7174ca73dcf`; 382 files:
source 6, tests 5, suite 1, fixtures-meta 3, bundles 328, raw 19, demo 20; aggregate
`scripts/foundation/` 380 files `e9d406b3…3dff`) 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.
@@ -0,0 +1,34 @@
{
"timestamp": "2026-09-07T17:33:50.274903+00:00",
"commit": "127a54fdff1fe6ae56c3197edddf957481465db4",
"conductorPassed": 17,
"conductorFailed": 0,
"conductorLog": "/mnt/storage/src/.mosaic-stack-conversion-20260907T172430Z/verification-postcommit/conductor.log",
"conductorLogSha256": "e1206366f07f3d9029530dcdcb55c0282d3f052adc60fc7fd51642d5d4ec3600",
"demoCases": [
{
"fixture": "demo/demo-read-w1.json",
"exit": 0,
"result": "allowed"
},
{
"fixture": "demo/demo-file-change-src.json",
"exit": 0,
"result": "allowed"
},
{
"fixture": "bundles/adm-workspace-registration-missing.json",
"exit": 3,
"result": "refused"
},
{
"fixture": "bundles/prop-all-pass-restricted-contexts.json",
"exit": 3,
"result": "unresolved"
}
],
"candidateHashesUnchanged": true,
"aliasAndCanonicalSameRootAndCommit": true,
"forbiddenGuardsInvoked": false,
"ownerDemoAcceptance": "pending"
}