Files
stack/docs/plans/2026-09-06_foundation-phase2-contract.md
T

29 KiB

Foundation phase 2: record and operation contract candidate

Status: phase-2 planning baseline accepted by Jason on 2026-09-06 ("accept phase 2"). Not approved for mapping or implementation. Owner authorized this phase on 2026-09-06 after confirming the behavior summary. Tracking: mosaicstack/stack-v2#53.

Inputs: agreed behavior R1-R33 and decision/interview record. This file proposes common types and operation rules. The linked Schema and semantic-rule package now contains checked command/event and eleven-kind record schemas, permission bundles, reference/lifecycle/storage rules, hash vectors, and #50 compatibility notes. The runtime contract and runtime schema now cover mediated execution/control, requests, messages and artifact bodies after Q28 A. The owner-review package reconciles D1-D16 and lists unproved implementation gates. None of this is implemented runtime behavior. No new owner requirement is inferred from a technical proposal.

1. Evidence boundary

Repository baseline: 69d1bb3aa4b826218aa4cca3710f2d98c0b9d7ba. The inspected source files have no working-tree difference from that commit. Existing runtime image: mosaic-poc-agent:0.84.4-r0.0.12, image ID sha256:a72aa79f98e54c3c974f5ad08b82e1643a4aa6eff259ac891b738120ba963ca1.

A tool-free worker examined supplied, line-numbered source excerpts through scripts/run-task.sh. Task specification: tasks/foundation-phase2-source-facts.json. Run: r-20260906T024609Z-68ee7f, under <dataRoot>/runs/. result.json SHA-256: e81ac68a369a9315d827e6fc7117033f794ab7b214d2610ca07081a668045875. The run reports success, exit 0, no tools or persistent session, and 1490 whitespace-delimited response words. This is a source-analysis response, not an independent review verdict or a runtime test of the proposed controls.

Author checks qualify the worker's suggestions:

  • One supplied excerpt header says adapters/pi/adapter.sh:65-106, although the file ends at line 96. The supplied numbered text and worker's executable citations end at 96. Preserve that input as recorded; no lines 97-106 exist.
  • A recorded stdout response is not a trusted account of arbitrary side effects.
  • The exclusive active-work key must include agent/project/workspace, not a session ID that lets two different Fresh sessions evade the same-scope limit.
  • A session transcript grows. Verify identity, supported format, and accepted checkpoints; do not mistake its changing content hash for corruption.
  • --no-extensions disables discovery, not explicitly supplied -e extensions. The current adapter supplies no -e; future reviewed extensions are possible, but their enforcement and failure behavior need investigation.
  • Command receipts and complete internal file/network tracing are different guarantees. The worker's suggestions do not settle their required granularity.

1.1 Pinned Pi documentation

Host Pi is 0.85.1. Its documentation was not used as proof of 0.84.4 behavior. The author copied the 0.84.4 package's README, package metadata, docs, and examples from the existing image using docker create and docker cp. The extraction container was never started and was removed afterward. No credentials, runtime sessions, or user-context files were copied. Temporary extraction: /tmp/mosaic-foundation-pi-0844.poVO9d.

To reproduce, create an unstarted container from the exact image ID above and copy the named files under /opt/app/node_modules/@earendil-works/pi-coding-agent/. Do not substitute a newly installed host version. The temporary directory is not canonical evidence; the image ID, file paths, and hashes identify the documentation used.

Package file SHA-256
package.json db9fead11bd2ddf7a327d2c2d11b535f30d059241c251d376837d5ab638a5576
README.md f2ffe4e825ea457ecb728cabbb15b545655cda2e3bab9b5b1fc28b950a3abd08
docs/rpc.md 010811d3526435b4fff5b03ee3a40f5bcb47fa17d5034fbd6b598955f56020d7
docs/json.md 094b8d1b25aebd949334b695b18e8e7e73d934b82337439af12f6936d73aca84
docs/session-format.md c0f25475ab08fb96e244e6bf433aeaa41b69bfb5a52de5c7b01b81c900a84a54
docs/security.md 5df4b27e7b0db49f50807f0e5d8a77e6dc099c76adab6edf21c5b705ede6efab
docs/containerization.md 29ac379f744052adf301e744559cb43d0e6e84d1b04f4757f1710680991be10b

README and these five documentation files were read completely. They establish documented capabilities and cautions, not measured implementation behavior. No SDK, extension, RPC client, or isolation mechanism was implemented or tested.

1.2 Findings that constrain the contract

Evidence Supported statement Design consequence, still proposed
scripts/agent.sh:132-138; adapters/pi/adapter.sh:29-44 Session default is per agent; nonempty session directory causes -c. Replace latest-file inference with a scoped conversation index and exact session binding.
Pinned README, Session options; docs/session-format.md:386-438 Pi documents exact session selection and session-manager APIs. Mosaic can investigate using an exact validated path; no need to expose partial UUID search to clients.
Pinned docs/session-format.md:19-27 Older session formats are automatically migrated when loaded. Preserve a legacy source before any reviewed adoption/conversion; do not load original historical files merely to inspect them.
scripts/agent.sh:121-123,181-185; src/run-agent.sh:37-41; src/load-contracts.sh:40-41,97 SOUL, mission, and generated prompt locations are shared by agent or data root. Resolve stable execution-specific inputs and avoid shared temporary-file names. No race reproduction is claimed.
scripts/agent.sh:144-162; scripts/mosaic-task.mjs:364-378 Interactive path intersects role tools; headless path intersects mission/task tools. One future authorization resolver must apply all applicable ceilings on both paths. Current checks are not a project/workspace RBAC system.
compose.yaml:39-43; pinned docs/security.md:31-37 Broad data-root mount; Pi explicitly has no built-in sandbox. Tool names and working directory cannot establish cross-workspace privacy or evidence protection.
scripts/mosaic-task.mjs:295-302,408-466 Exclusive-create snapshots/results and Compose process outcome, not a complete trusted action ledger. Separate invocation outcome, external effect, acceptance, and confirmed execution termination.
Pinned docs/rpc.md:43-80,905-911,1012-1060 Prompt acceptance, settled processing, and tool events are documented and distinct. Acceptance of an RPC prompt is not task acceptance; events alone are not durable pre-action authorization.
Pinned docs/rpc.md:124-184,479-550,620-642 Abort, queue clearing, direct bash, and session switching are separate commands. A session switch can be cancelled while the response says success. Do not pass arbitrary raw RPC commands through a Mosaic connection. Do not equate abort acknowledgement or idle processing with process death.
adapters/pi/adapter.sh:81-96 Mosaic currently runs plain print or native interactive mode, with no explicit extension or RPC invocation. Documented Pi integration options are not already implemented Mosaic attachment, control-transfer, or audit guarantees.

2. Proposed common record types

Plain-language rule: an ID names an object, a revision names the exact approved copy, and a scope names where it belongs. A display name is only a label. These proposed types are shared across records; they are not fields accepted by today's task runner.

Type Exact proposed representation and validation
Id String matching ^[a-z0-9][a-z0-9._-]{0,63}$. New runtime IDs use lowercase UUID v4; reject collisions with exclusive allocation. Existing definition IDs require explicit resolution, not a guessed alias.
Revision Integer from 1 through 9007199254740991. A create request expects revision 0 to mean absent; 0 is never a persisted revision.
UtcTime A valid UTC instant encoded as YYYY-MM-DDTHH:mm:ss.sssZ. Validate calendar/time values as well as shape. Wall-clock time is not proof of causal order.
Digest String sha256: followed by exactly 64 lowercase hexadecimal characters. A digest detects content change; it is not a signature or access grant.
Scope Discriminated object: {kind:"system"}, {kind:"project",projectId:Id}, or {kind:"workspace",projectId:Id,workspaceId:Id}. No omitted or extra fields; workspace ownership must match its project.
RecordRef {kind:RecordKind,id:Id,scope:Scope,revision:Revision}. Resolve exactly; a reference never means latest or grants access. RecordKind is the closed catalog in section 3.
ActorRef `{kind:"human"
FileTarget {workspace:Scope,relativePath:string} where scope must be workspace kind. Nonempty slash-separated relative path, at most 4096 UTF-8 bytes; reject NUL, control characters, empty components, ./.., backslashes and absolute paths. Validate filesystem containment and symlinks at use time, not merely through a string prefix check.

Unknown fields/versions fail validation. Required fields cannot be omitted. Use explicit null only where the type permits it; an empty list means none, not unrestricted. Permissions and source-reference lists contain no duplicates. Proposed generic list limit is 1024 items and record size limit is 1 MiB of UTF-8 JSON, with detailed evidence stored separately. Limits need workload review before becoming an implementation contract. Reject oversize input; never silently truncate authority, dependencies, or recovery context.

Common envelope for declarative records: schemaVersion:1, kind:RecordKind, id:Id, scope:Scope, revision:Revision, createdAt:UtcTime, createdBy:ActorRef, supersedes:RecordRef|null, and authorizationRef:Id. authorizationRef resolves a trusted authorization event, not a recursive grant from the record being created. System bootstrap authority resolves to reviewed policy and the authenticated owner; no record may authorize its own creation.

The first revision has null supersedes. Later revisions reference the exact previous revision of the same object and immutable owning scope. A mutable current index is a rebuildable view, not the authoritative history.

3. Record catalog and ownership

The catalog names proposed types, not approved role or directory additions. Fields below supplement the common envelope. Complete per-kind field types, conditional requirements, and transition validation are still being drafted. There is deliberately no unrestricted metadata or permissions:any field.

RecordKind Payload to define Authorized writer
agent-definition Display name, reusable type, harness reference, canonical SOUL/instruction/skill references, reviewed role ceiling and configuration references. Reviewed configuration author, not a workspace worker.
project Display name, policy reference and lifecycle. Authorized project administration.
workspace Display name, parent project via scope, policy reference, lifecycle and logical working-file root. Authorized workspace administration.
registration Agent ID, scope role reference, narrowing restriction set, active/revoked status and delegation reference. Project and workspace registrations are separate records. Actor with bounded registration authority.
mission Objective, criteria, lifecycle, optional parent project-mission reference and policy restrictions. Project missions have no workspace parent. Authorized work owner.
task Purpose, criteria, optional mission reference, approved intent reference, dependencies and lifecycle. An ad-hoc task still needs purpose/criteria and explicit authorization. Authorized work owner/coordinator.
assignment Exact task reference, agent ID, lifecycle, assigned policy/work revisions and coordinator decision. Authorized coordinator; progress does not grant assignment authority.
decision Decision kind, approved intent/evidence references, affected records, delegation bounds and decision outcome. Authorized decision maker. Acceptance checks authorship independence separately.
session Agent ID, immutable project/workspace scope, creation mode, predecessor reference and exact harness identity binding. Launch resolver; lifecycle observations are separate events.
context-source Content reference, revision/digest, owner, permitted scopes, context category and explicit sharing designation. Authorized context publisher. Relevance cannot invent a grant.
adapter-capability Adapter/package identity, supported operations, observable and enforceable action classes, tested coverage references and limitations. Reviewed adapter authority. A worker cannot self-certify coverage.

Execution, active claim, connection, message, context manifest, and audit event are runtime evidence types, not mutable declarative records. Their complete envelopes remain a dependent drafting task. Do not force them into a common mutable status record or rewrite a run to update its progress.

4. Permission resolution

Proposed operations are distinct from tool names. A read tool grant does not imply permission to read another conversation, credential, or audit payload.

An action must satisfy both the requester's authority to request it and the performer's authority to execute it. The performer is bounded by reviewed agent policy, project registration, explicit workspace registration, applicable parent/workspace mission policy, task policy, and launch restrictions. Resolve all required references before taking the intersection. Missing/invalid required policy is an error, not an empty policy to skip. An optional absent restriction adds no grant and does not remove any ancestor ceiling.

Each layer checks operations and their targets. Project participation alone never admits a workspace action. Multiple assignments do not produce a union that lets an action borrow another task's wider grant. Bind a changing action to one explicit assignment and current intent revision. Tool availability is only a coarse filter before per-action authorization.

Proposed standard role catalog for later review:

  • Reader: permitted work records and scoped file inspection.
  • Contributor: permitted inspection plus assigned file changes and result submission, with command execution subject to Q27's invocation-audit ruling and verified permission, containment, and evidence checks.
  • Reviewer: permitted evidence inspection and independent routine acceptance.
  • Coordinator: permitted within-plan decomposition and assignment changes.

These roles are not a rank hierarchy. Coordinator does not automatically mean file writer, reviewer, membership administrator, or credential administrator. Separate explicit grants govern registration, conversation reading/observation, control transfer, retirement/reopening, and protected operations. Exact operation sets and any combined standard roles need review. Shared role authority still changes only through reviewed commits under roles/; no live role-policy file was added or modified during this phase.

5. Proposed command contract

Use the target mosaic command family already proposed by #50. These spellings are candidate interface decisions, not commands to run today. Terminal, desktop, web, and service clients submit the same authorized operations.

Candidate command Operation/result rule
mosaic agent resume <agent> --project <id> --workspace <id> [--session <id>] Default launch operation. Use exact session if provided; otherwise use the authoritative current scoped session. Genuine first use creates and announces initial conversation. Missing established history refuses.
mosaic agent fresh <agent> --project <id> --workspace <id> New conversation, no old chat/automatic summary. During active work, request controlled replacement; do not overlap executions.
Work flags for Resume/Fresh: `--work continue select
`mosaic execution connect --mode control observe`
mosaic execution transfer <id> --to-connection <id> --expected-generation <n> Explicit authorized transfer; old generation stops admitting control input. Being an observer is not permission to take control.
mosaic execution config-check <id> Return matching/changed/unknown, launch/current references and check time. Automatic non-blocking notices use the same comparison record.
mosaic workspace retire <id> --project <id> Stop admitting new work, safely stop/reconcile active work, retain files/history. Report retirement pending if safety is unresolved.
mosaic workspace reopen <id> --project <id> Revalidate current policy and membership; no automatic restoration of revoked access or launch. Exact assignment reactivation rules need review.

The runtime schema now fixes requestVersion:1, requestId:RuntimeId, operation, scope, expectedRefs:RecordRef[], assignmentRef and closed parameters. Input and command requests have their own narrower shapes. The service supplies authenticated actor and authorization; clients cannot submit trusted producer/outcome records.

The runtime schema defines the common response: version, request ID, outcome, reason code, optional execution ID and classified receipt/data references. Accepted means durable admission, not completion. Success/acceptance cannot have null receipts. Invalid/unauthorized pre-admission refusals and audit failures are not success receipts. Already-active identity requires authorization; wrappers never silently connect or Fresh.

The linked runtime contract supplies all 29 operation names, request coverage, error codes, JSON stdin/file semantics, message routing and #50 boundaries. CLI presentation/aliases in a later charter must map to these same operations.

6. Ordering and recovery obligations

  1. Authenticate and validate before resolving private state for a caller.
  2. Resolve exact record revisions, scope, permission, and expected audit coverage.
  3. Serialize active-work admission by agent/project/workspace. Default limit is one, independent of session ID. Validate history before claiming first use.
  4. Commit authorization and intent to trusted durable storage before effects. Proposed durability requires file flush plus parent-directory flush and atomic publication on a supported local filesystem; unsupported storage refuses. Crash-order and multi-record commit mechanics still need design.
  5. Resolve exact immutable launch inputs and record the manifest. A successful spawn is not a confirmed session binding; require adapter identity evidence.
  6. Serialize controller changes separately by execution ID and generation. Reject stale generations for new input even if an old connection still lives.
  7. Before managed actions, recheck policy, assignment/plan revisions, active claim generation and required recording. A changed approved plan pauses affected work; a shared base-configuration notice alone does not.
  8. For replacement/revocation/retirement, close admission first, account for queued requests, settle or identify outstanding effects, and confirm the execution can no longer act before admitting conflicting new work.
  9. Append observations and recovery decisions. A timeout, abort acknowledgement, or Pi agent_settled event alone does not prove container/process termination.

A scoped conversation index must retain initial-creation history and missing/ pruned-session tombstones. A missing index is not proof of first use. Retrying a request must resolve its prior durable decision; a timeout or missing response must not replay an external action. Request identity binds authenticated actor, operation, scope, and normalized arguments. Reuse with different arguments is an error. Tombstone retention and post-prune retry behavior remain unresolved.

The enforcing runtime component is not an autonomous conductor agent. It has only its reviewed operation authority; changing a task's state cannot change policy. Required audit failure blocks affected actions, including recovery checks that cannot meet their own recording requirements.

7. Storage and evidence

Keep immutable execution evidence under <dataRoot>/runs/. A proposed new execution record uses its run directory as the evidence owner; projects and workspaces reference it instead of maintaining competing result copies. Existing v1 records are never rewritten or silently reinterpreted as v2 evidence.

Keep conversation bytes under <dataRoot>/sessions/, but resolve them through explicit scoped metadata rather than directory naming. Do not mount all sessions, all runs, all user context, or the whole data root into a worker's tool-accessible filesystem. Only the necessary approved inputs and working paths are exposed. A trusted recorder must be outside worker write permissions. OS ownership and mount tests must verify these boundaries before any isolation claim.

Proposed metadata ownership: project/workspace records in their dedicated runtime metadata namespace; current indexes under a derived system state namespace. No actual directory choice or second configuration file is installed. Exact paths, per-directory writers/readers, export, retention, prune/reset references, and rollback must be specified before schema approval.

Legacy adoption makes a new mapping receipt. Preserve the original source and its identity before adapter conversion. Pi's documented automatic format migration is a reason to inspect metadata without opening a legacy session in Pi. Fresh does not load an adopted transcript just because it is accessible.

8. Configuration fingerprints

Proposed algorithm: SHA-256 over a versioned canonical JSON manifest using RFC 8785 serialization. Hash exact instruction/SOUL bytes as referenced content; normalize structured settings through their strict schema first. Preserve instruction order; sort set-valued permissions and source inventories by their explicit stable keys. Publish test vectors before implementing the comparator.

Comparable base configuration covers canonical SOUL/shared instructions, applicable enabled skills and their dependency content, canonical harness/model settings, and reviewed role configuration. Exclude timestamps, display labels, chat, task progress, private user context, and credentials. Content changes must be detected even if a path stays the same. Do not hash unrelated skills merely because they are installed.

The full launch manifest separately binds execution identity, selected approved context, effective restrictions, session choice, adapter/image identity, and non-secret credential-account reference where authorized. Its hash naturally differs between launches. Never compare full launch hashes as the base-config change test. Private context source references/digests remain access-controlled.

Exact included JSON keys, skill dependency inventory rules, configuration revision races, approved launch overrides, and notification transport still need D10/D16 design and #50 reconciliation. A launch fingerprint is not continuous proof of live process state, and a changed role grant may require immediate revocation rather than waiting for Fresh.

9. Owner decision after investigation

Q27: command-level evidence or internal-effect evidence

A command such as npm test can invoke other processes, read/write many files, and attempt network access. Pinned Pi documents tool invocation/result events; it explicitly does not provide a sandbox. Mosaic's current adapter does not capture those events as a trusted per-action ledger.

Choices presented to the owner; Jason selected A on 2026-09-06:

  • A: for the initial managed command facility, record the authorized command invocation, actor/scope/assignment, enforced filesystem/network limits, start/end, outcome, and controlled evidence references. Be explicit that this does not separately enumerate every internal file read/write or network call.
  • B: require separately attributable internal file/network effects before enabling command execution. Keep commands unavailable until that stronger coverage is designed and verified.

Owner ruling: A, with real sandbox enforcement and honest coverage labels. This keeps test/build commands practical while preserving accountable invocation and fail-closed admission. Use typed, allowlisted command metadata. Neither events nor detailed evidence may contain credentials; unfiltered argument, environment, and output capture is not approved. The ruling does not waive workspace isolation, credential protection, action recording, revocation, or uncertainty recovery. A command whose effects cannot stay within the authorized boundary must still refuse.

This ruling settles D11's command-audit granularity, not a specific sandbox, RPC/SDK choice, product UI replacement, or implementation increment. It does not grant shell access to any current research worker.

10. Phase-2 exit gate remains open

Q27 and Q28 are answered; R34 records the managed-terminal ruling. Runtime, control/input, command artifacts, permission/routing/recovery rules and the D1-D16 reconciliation now form an owner-review candidate. Jason's specific phase-2 acceptance is now recorded. Implementation must prove the listed mechanisms; any change to owner behavior returns for a new decision.

Candidate acceptance evidence must include negative schema fixtures, reference and permission checks, representative lifecycle/crash traces, hash test vectors, and a capability matrix that distinguishes documented, code-inspected, and runtime-tested support. Current evidence is source/document inspection and author schema/hash/synthetic-model checks only. No runtime feature or security guarantee, independent verdict, whole-schema approval, or readiness for mapping follows from this draft.

11. Continuing goal task record

Goal: issue-53-phase2. Owner: Jason. Assigned author: darkwing in the explicit repository working directory. The repeated /goal request resumes this existing assignment; it does not create a second authority record. CURRENT owns live control state; BUILD-LOG and SESSIONS hold append-only history.

Task Criterion and dependencies Status and evidence
P2-1 Recover Q1-Q27 requirements and pre-reboot work. Done for author recovery; R1-R33 and preserved source/run evidence.
P2-2 Repair command/record/path schemas and fixtures after P2-1. Author checks pass: 38 command cases, 38 record cases, 16 path cases, plus 5 deliberately shape-valid forgeries. Runtime semantics remain separate.
P2-3 Define permission/reference/lifecycle/storage rules after P2-2. Review proposals in schema package sections 2-6; no live policy installed.
P2-4 Define comparable fingerprints and reconcile #50 boundaries. Seven restricted-domain vectors pass; package sections 6.1-6.2 retain the unresolved OAuth gate.
P2-5 Choose managed terminal requirement and finalize affected execution/control/artifact schemas. Author checkpoint complete after Jason's Q28 A. Runtime schema, fixtures and RUNTIME.md provide the review candidate; no runtime capability is claimed.
P2-6 Assemble exact-candidate review package, trace D1-D16, and recommend one testable increment. Depends on P2-5. Owner package in REVIEW.md; 155 runtime cases and 35 synthetic rule-model cases supplement earlier checks. First recommendation refined to a read-only synthetic scope/permission inspector, not live registration.
P2-7 Obtain Jason's specific phase-2 acceptance after P2-6. Done: Jason said "accept phase 2" after clarification that this accepts the planning baseline, not security certification or implementation. Goal satisfied; later mapping/implementation still require separate authority.

Jason clarified that /goal belongs to the separate ~/.mosaic deployment, not this environment. Continue through existing file-based records. No extension installation, active --wait-timeout 60, or automatic follow-up was requested for this phase-2 session. Separate #54 native-extension work is not part of this goal; this session has not migrated its goal state or configured that extension. Owner waits are manual and never expire into approval. No numeric work budget was supplied; aggregate usage is unavailable, not reset on resumption.