# 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 5–13 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 L1–L9: 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 L1–L9 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. V1–V3 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 1–5 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 L1–L9 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 L1–L9 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.