Foundation contract candidate: schemas and semantic rules
Planning artifacts for #53 phase 2. These files are not loaded by Mosaic, installed as policy, or approved for implementation. The owner confirmed R1-R34; field spellings, role bundles, state transitions, and mechanisms here are proposals.
Parent: phase-2 contract. Behavior: foundation requirements. Decision history: schema discussion.
1. What is executable here
- Command schema: a closed command request and four event variants: intent, started, finished, and recovered.
- Record schema: closed payloads for eleven declarative record kinds, including explicit references, revisions, and optional absence.
- Command fixtures: 38 shape cases and five deliberately shape-valid forgeries requiring separate runtime rejection.
- Record fixtures: 38 record cases and 16 path cases.
- Fingerprint vectors: seven restricted-domain examples of canonical comparison, content changes, and set/order semantics.
- Runtime schema and fixtures: 155 cases for mediated control/execution, messages and artifact bodies, plus five additional shape-valid semantic forgeries.
- Rule model and fixtures: 35 synthetic reference, permission, path, acceptance and recovery cases.
- Author checker: checks all three schemas and fixtures/models using the
existing Python
jsonschemapackage, observed version 4.26.0. Installs nothing.
Run from the repository:
python3 docs/plans/foundation-v1-candidate/check.py
These are design checks, not product tests. Schema validation does not prove permissions, identity, filesystem containment, durable writes, or correct reference resolution. The ten forged/stale records intentionally pass shape validation. A future runtime must reject them for their semantic reasons.
The checker explicitly asserts UTC calendar validity and the
mosaic-relative-path format. The latter rejects paths over 4096 UTF-8 bytes,
Unicode control/format/surrogate characters, backslashes, and empty/dot/parent
components. A validator that ignores required formats must not be certified
for these contracts. String length alone counts characters, not UTF-8 bytes.
Filesystem symlinks, hard links, mounts, races, and case collisions require
separate checks at the operation boundary; this formatter does not inspect files.
2. Reference and publication rules
A registryRef identifies an exact external definition by registry, ID,
revision, and digest. It is not a new system configuration location. Harness
and settings registries must reconcile with #50; agent/scope-role authority
must resolve to reviewed repository policy. Registry absence refuses an action;
no default provider, account, role, or workspace substitution is allowed.
A recordRef resolves to exactly one record kind, ID, owning scope, and revision.
The resolver checks the authenticated caller's access before returning content.
A reference to another scope is not membership in that scope. A record revision
cannot move its owning scope or change kind/ID. supersedes must name the
immediately prior revision of the same object. Reject cycles and skipped or
competing revisions, even when each individual JSON document is valid.
Project/workspace record IDs must agree with their scope IDs. A workspace has one owning project. Workspace registration references an active project registration for the same agent/project. A workspace mission's optional parent is a project mission in that project. Project missions have no parent mission in the initial design. Task mission/dependency references must resolve to permitted work; dependency cycles and self-dependencies refuse readiness. Cross-scope dependency information is filtered by access and grants no extra execution authority. Cross-project execution selection is not introduced here.
Assignment agent, task, and workspace must match its execution binding. A task may have no mission but still has purpose, criteria, and approved intent. Its intent decision is independently authorized; neither task nor decision grants itself permission. Decision subject/basis/evidence references must resolve and be consistent with the requested decision kind. A delegation authorizer cannot grant operations outside its own reviewed delegation ceiling.
Acceptance records identify exact criteria, delivered artifact revisions, authoring identities, and an authorized non-author reviewer through the basis artifact. The decision schema's artifact pointer is not proof of these facts. The acceptance resolver must inspect and validate that basis. Owner checkpoints remain distinct from ordinary reviewer acceptance.
Context marked shared by default must be a general preference explicitly published for that purpose. An author cannot turn private content into shared preferences merely by changing an enum. Validate publisher authority, permitted scopes, relevance, and provenance. Fresh rejects transcript/automatic-summary inputs regardless of whether a caller can read the old conversation.
An adapter's verified declaration needs evidence for the exact image/package,
mode, operation set, and tested failure behavior. Evidence references alone do
not certify the adapter. Refuse required guarantees that lack matching evidence.
3. Proposed permission catalog
Operations are exact strings, not glob patterns. All are default-deny.
A scope role combines allowed operations with permitted targets; registration
restrictions can only narrow that result. restrictions:null means no additional
restriction, not a grant. An explicit empty operations array permits none.
A path grant with path:null explicitly names the whole workspace root; it
still requires the operation and all ancestor grants. No empty-string root alias.
| Proposed bundle | Operations |
|---|---|
| Reader | work.read, file.read, work.propose |
| Contributor | Reader operations plus file.change, command.execute, result.submit |
| Reviewer | work.read, file.read, audit.read, task.accept |
| Coordinator | work.read, work.propose, task.create, assignment.change |
These are review candidates, not additions to roles/. They are nonhierarchical.
Combined roles need an explicit reviewed bundle; do not union arbitrary role
labels at launch. A reviewer never accepts its own authored delivery.
The following operations need separate explicit grants: registration.manage,
conversation.read, conversation.observe, execution.launch,
execution.control, execution.transfer, workspace.retire,
workspace.reopen, message.send. audit.read exposes only evidence the
principal is entitled to see, not every referenced payload. No bundle grants
git integration, release, credential management, destructive maintenance, or
shared policy changes. Those stay under the repository's conductor/owner rules.
Control-plane operations authenticate the requesting user/service/agent and check its scope grant; the authorized runtime component performs them. An agent being launched does not need permission to launch itself. Its reviewed ceiling instead bounds the new execution's tools and actions. For assigned work, check both the originating delegation and the acting agent's current authority.
For a workspace action, resolve the reviewed agent ceiling, project registration, explicit workspace registration, applicable parent/workspace mission restrictions, task restriction, and execution restriction. Intersect operations, file targets, and network targets independently. A missing required layer refuses; never skip an unreadable policy. Bind an action to one assignment rather than borrowing permissions from other assignments. Recheck revocation and current approved intent before admission, not merely at launch.
Command network permission concerns command processes. Model-provider access
is a separate, narrowly authorized runtime channel. network:none for a command
cannot be satisfied merely by Pi's startup --offline flag. No credential file,
Docker socket, host home, or shared evidence directory belongs in the command's
writable/readable sandbox solely because it exists in the configured data root.
4. Command and audit rules
A command request supplies a proposed execution binding and immutable command specification reference. These are claims to validate, not trusted identity. The gateway resolves the authenticated channel, exact live execution/session, agent/workspace, assignment/task revision, and active generation. A client cannot supply event producer, authorization verdict, or observed outcome fields.
The command specification is controlled evidence, not raw metadata. It must identify the authorized executable/arguments or shell program, cwd, permitted input sources, output policy, and applicable constraints without containing credentials. Exact command-specification and sandbox-limit artifact schemas remain dependent work; these reference slots are not permission for arbitrary JSON payloads. Required artifacts must resolve and validate before execution.
Order of operation:
- Authenticate and validate the full request, references, permissions, current generation, approved intent, and required coverage.
- Reserve its idempotency identity and persist the authorization and command intent, including the exact enforced-limit reference, before issuing effects.
- Establish the sandbox and its process-group identity. Persist observed start separately. Start failure produces a not-started outcome, not false success.
- Record exit/signal plus proof that the command's entire admitted process group can no longer act. A shell's exit code alone does not prove descendants stopped.
- Persist the command outcome. Zero exit with proven termination can mean command success while effects remain unverified. It never means task acceptance.
- If effects or required recording are uncertain, block dependent work and use authorized non-destructive checks. Append recovery evidence with its real observation time; do not edit an earlier unknown record into success.
command.finished permits one initial terminal observation per command ID.
Later knowledge uses command.recovered, naming the prior observation and the
independent check events. Unconfirmed termination requires an unknown outcome.
A confirmed failure needs a nonzero exit or a signal. No process issued means
null exit/signal and effects not-issued. A reconciled effect claim needs evidence.
The recorder rejects duplicate event IDs, reused sequence numbers, contradictory command bindings, causal cycles, missing intents, and unauthorized producers. JSON Schema cannot enforce these cross-record rules. Per-execution sequence orders its observations; clocks do not create a global order across machines.
Neither metadata nor detailed evidence may contain credentials. Use allowlisted metadata and controlled artifact references; do not dump arguments, environment, stdout, or RPC messages into the audit stream by default. Content classification and release of evidence are separate authorized operations. An evidence pointer is not an exception to the no-secrets rule.
5. Proposed lifecycle transitions
All changes require expected revisions and authorized writers. No last-writer-wins. These transitions describe intended work, not changes to old run evidence.
| Object | Proposed transitions and guards |
|---|---|
| Project | Active to retired only by authorized administration, with owned work safely accounted for. Reopening requires revalidated policy; cascading membership restoration is forbidden. |
| Workspace | Active to retiring closes launch/action admission. Retiring to retired requires stopped executions and reconciled/explicitly blocked effects. Reopen moves retired to active without launching work or restoring revoked grants. |
| Registration | Active to revoked blocks affected work immediately. A later regrant is a new authorized revision after current policy checks, not automatic revival. |
| Mission | Proposed to active requires approved intent. Active/blocked may proceed to ready-for-review after evidence is available. Accepted requires authorized independent acceptance; cancellation needs separate authority. Child completion alone does not accept its parent. |
| Task | Proposed to ready requires criteria, approved intent, and resolved prerequisite readiness. Ready to active requires an assignment/claim. Active may block or submit for review. Reviewer accepts exact evidence; rejection returns work for correction. Cancellation is separate from assignment Abandon. |
| Assignment | Selected to paused on approved-plan change or unresolved effects; reconciliation may select it again within delegation. Ended is terminal with an explicit completed/abandoned/revoked/reassigned/canceled reason. Reassignment creates a new assignment, not a different agent under the old ID. |
| Session | Immutable identity/scope and creation lineage. Resume creates a new execution, not a new conversation record. Fresh creates a new conversation and preserves the predecessor only as lineage, not loaded chat. |
| Execution | Admission, observed start, stopping, observed termination, and uncertainty are separate immutable events. No reusable active claim until prior work is proven unable to act. |
| Connection | Observe/control admission checks transcript and operation grants. One controller generation per execution. Explicit transfer invalidates the old generation before new input is accepted. Disconnect is not permission to start another execution. |
The early discussion's candidate task state abandoned is replaced in this
proposal by assignment endReason abandoned; task cancellation stays explicit.
This follows Q8 rather than silently ending shared work.
6. Storage, retry, and crash traces
Proposed ownership remains under the sole configured data root. Shared system
configuration is still ~/.config/mosaic-dev/config.json; reviewed role authority
still lives in repository roles/. No runtime directory is created by this plan.
- Project/workspace metadata:
<dataRoot>/projects/<projectId>/, with one workspace metadata subtree per workspace ID. Immutable revisions and checked current indexes are separate. Shared agent definitions stay outside projects. - Working files:
<dataRoot>/workspaces/<workspaceStorageId>/, where an immutable workspace record resolves storage ID. Display names never construct paths. - Conversations:
<dataRoot>/sessions/<sessionStorageId>/, resolved through the scoped conversation registry, never latest-file discovery. - Evidence:
<dataRoot>/runs/<runId>/, with immutable inputs and uniquely named event/result artifacts. The trusted host recorder writes; workers cannot. - Current indexes, first-use tombstones, request decisions, and active claims:
<dataRoot>/state/foundation/. These are derived/control records, not a second system configuration. Private source content retains publisher-controlled storage and is selected into immutable launch inputs only when authorized.
A proposed host-side per-scope writer serializes admissions and checks expected revisions. Unique temporary files, flush, atomic rename, and parent-directory flush publish one durable transaction decision; referenced payloads are written before that decision. Readers accept only payloads named by a complete commit record. Indexes rebuild from committed decisions. Never infer atomicity across several independent renames. Filesystem support and process-lock behavior need failure tests before this design can be called implemented.
| Crash point | Recovery rule |
|---|---|
| Before committed intent | Do not issue the action. Uncommitted artifacts do not grant authority. |
| After intent, before observed start | Outcome is not assumed not-started. Reconcile the exact process/container identity before considering replay. |
| After start, before result | Block dependent work; inspect the recorded process group and authorized evidence. Timeout of Compose or an RPC acknowledgement alone is insufficient. |
| After result, before response | Return the existing request decision/result after reauthentication, never run the action again. |
| During claim transfer/replacement | Reject both stale input and conflicting launch until committed generation and old-process disposition are established. |
| During index publication | Rebuild from committed revisions; do not silently select another session or infer first use from absent files. |
| During plan revision | Pause affected work until its expected intent/assignment revisions reconcile; unaffected valid work can continue. |
Idempotency identity binds authenticated requester, request ID, operation, scope, and normalized request digest. The same ID with different content refuses. A repeated request reuses its existing outcome only after current visibility checks. Automatic retention cleanup is not introduced. Keep request/first-use history while the scope remains available; explicit pruning must retain enough non-secret tombstone metadata to refuse ambiguous replay or missing-session replacement. Owner-authorized data-root reset remains destructive and does not promise restoration of those indexes. Never silently adopt leftover files after reset into a newly registered scope.
Legacy adoption preserves original bytes and source identity before any format conversion. Produce a new reviewed mapping/conversion receipt. Missing lineage, ambiguous source ownership, or insufficient permission refuses adoption.
6.1 Fingerprint projection and vectors
The proposed comparable projection has exactly hashScopeVersion, agentId,
soulDigest, ordered instructions, ID-sorted skills, harness,
modelSettingsDigest, and roleConfigDigest. Instruction entries contain ID
and content digest. Skill entries contain ID, declared package version, and
content digest. Harness contains canonical ID, actual pinned package version,
and package/image content identity. Reject duplicate component IDs.
Digests represent the resolved operative content, not only a filename or an administrative revision number. Normalize operative model/role settings through their strict source schema; retain their original source revisions separately in the full launch manifest. Do not include timestamps, display labels, private user context, chat, progress, or credential bytes/hashes in this base projection. Approved account selection is a non-secret launch binding, not credential content.
Serialize the projection with RFC 8785 and hash its UTF-8 bytes using SHA-256. The seven vectors use only ASCII keys/values and safe integers. The author checker proves those examples and skill-set sorting, not a general-purpose JCS implementation. Instruction order changes the hash; skill inventory order does not. Changed SOUL, skill version, model settings, or role configuration changes it. The full launch manifest remains distinct and includes work-specific input identity. Cross-interface notification uses the same base comparison, never hash equality as proof of live process state.
6.2 Compatibility boundary with #50
The author re-read the existing auth/provider/harness plan. Its canonical harness
IDs are executable names, so registry references remain dynamic IDs such as pi,
not an enum of providers or a host executable chosen through PATH fallback.
The old examples spelling claude-code do not override its later explicit
owner ruling that the ID is claude.
Settings references point to the centrally authored settings profile. Account
references remain a provider/account pair, with each component using the ID
format; the combined slash-separated pair is not a filesystem path or an Id.
There is no independent account registry per project or workspace. Endpoint
restrictions resolve canonical provider/approved network definitions; they do
not register the provider again for each assignment.
The proposed agent-definition record is a versioned resolved representation of
reviewed identity, not a second mutable source alongside agent.json. An exact
reviewed-source binding and migration adapter are required before adopting this
schema. Likewise, schema registryRef.revision/digest are proposed identity
requirements; current #50 records do not already supply every such field.
A cached projection cannot authorize changes absent from its canonical source.
#50's per-seat generated files need reconciliation with R16's stable per-execution launch inputs before concurrent scoped launches. Central credential ownership, profile ceilings, explicit account choice, no identity fallback, and no writes to default harness homes remain binding. Credential values and their hashes stay out of these manifests. In-session account swapping remains deferred, not enabled by a controller's access to raw engine commands.
OAuth refresh gate 7 remains unresolved. No refresh/login/credential operation was performed during this reconciliation. A future launch requiring refresh must refuse until the authorized registry/materializer path meets its gate; this contract does not invent a refresh protocol or resume #50 implementation.
7. Managed interface ruling and completed candidate
The shapes and rules above do not establish how terminal input is mediated. The pinned documentation describes native Pi TUI commands and a separate RPC mode. Current Mosaic starts native TUI or print mode; it does not implement a shared authenticated control service or arbitrary attachment to a live RPC process. RPC events alone are not a pre-action permission gate.
Jason answered Q28 A: a Mosaic-controlled terminal backed by Pi is acceptable. The same operations are intended for later desktop/web clients; native screen and shortcut parity is not required initially. No runtime change follows from the ruling.
The runtime contract and runtime schema now cover execution/claim/control records, typed requests/responses, routing, launch inputs, command specifications/limits and concrete evidence bodies. The runtime fixtures include positive conditional branches and negative cases. The synthetic rule model with its fixtures checks proposed reference/permission and recovery rules, not actual observations or enforcement. The existing checker runs them together and checks catalog/projection consistency.
New project/workspace/mission/task change, mission acceptance, decision issuance and adoption operations are separate explicit grants, not silent bundle expansion. All proposals now go to owner review. No capability is admitted merely because its record passes JSON validation.
8. Owner-review and first-increment proposal
Start with the owner-review package. It traces D1-D16, separates checked proposals from unproved runtime capabilities, and requests a phase-2 verdict.
Refined first-increment recommendation: a read-only scope/permission inspector for a coherent synthetic bundle, explicitly labelled preview with no live grants. Owner tests two workspaces, exact membership, ambiguity, stale/missing references and widening refusals, with no data-root/credential/session changes. Live metadata publication is not yet the smallest safe increment: it also needs trusted writing, retention and closure of legacy broad-mount bypasses. This refines, rather than implements, the earlier metadata-registration proposal.
Phase-2 acceptance, Archify mapping, distinct-agent gap review and an implementation charter remain separate gates. Author checks are not independent approval.