24 KiB
Mediated runtime contract — phase-2 review candidate
Status: proposed technical contract after Jason's Q28 A ruling. No component below has been installed. Pi remains the engine. A Mosaic-controlled terminal is acceptable; native Pi screen/shortcut parity is not an initial requirement. The same authorized operations are intended for later desktop/web clients.
This file completes the operation and evidence rules alongside the package
rules and runtime shapes. Closed JSON shapes
are necessary, not sufficient. check.py checks synthetic examples, not a live
permission system. Fixtures are independent shape cases, not one valid run graph.
1. Components and authority
| Component | Owns | Must not do |
|---|---|---|
| Mosaic client | Scope display, user interaction, authenticated requests, authorized rendering | Hold client-private task truth, set trusted actor/producer, bypass the broker |
| Control broker | Authentication binding, policy intersection, current claims/controllers, admission, routing | Treat agent text or engine events as approval, fall back to another scope/account |
| Trusted publisher | Serialized immutable records, artifact index, receipts, recoverable projections | Accept a worker's producer label as proof, acknowledge an undurable commit |
| Engine adapter | Exact Pi instance/session, pinned configuration, reviewed tool bridge | Expose raw engine control channels, discover ambient extensions/context |
| Command gateway and supervisor | Enforced command limits, process cohort identity, observations and stopping | Mount credentials, host control endpoints, private engine home, or shared evidence into command jobs |
The broker/publisher/supervisor are runtime infrastructure, not a new autonomous conductor agent. Git, credentials and shared policy retain conductor/owner authority. This design does not add a background goal scheduler.
Initial ingress proposal: a local owner client over a private, ownership-checked local channel. Bind owner identity through OS credentials and reviewed bootstrap policy, not a JSON principal ID. Sandboxed engines/jobs must not reach that owner control endpoint. Agent/service ingress uses a distinct, execution/delegation-bound channel with narrower operations. Provider API credentials are never control-plane credentials. Remote ingress is refused until an authenticated mapping is approved and tested; a future web interface is not permission to trust HTTP actor headers. A compromised host owner/root is outside the sandbox boundary, not something this contract claims to contain.
2. Wire, operations, and receipts
The proposed control transport uses bounded UTF-8 JSON frames. Reject duplicate keys, non-finite numbers, unknown fields, bad encodings and metadata frames over 1 MiB before admission. No shell expansion, URL fetching or host-path resolution is implied by an argument. Sidecar body ingestion is authenticated, private, bounded by the selected operation/profile, and correlated to the request. It cannot publish work or grant authority independently. Validate content and digest before replacing a staging handle with a trusted artifact reference.
controlRequest defines request ID, target scope, expected record references,
optional assignment reference, exact operation and closed parameters. Actor,
producer, authorization and outcome come from the service. Public ingress validates
only its request sub-schema; a valid runtime-record or response object is never
accepted as a client request. command.execute
retains its separate command request shape. inputRequest is exclusively for
prompt, stop and approved dialog replies, with execution/connection generations.
All 29 permission names have a request contract: 28 control operations and the separate command request. Descriptive CLI commands are wrappers, never another permission system. JSON stdin/file forms submit the same request; they do not allow arbitrary engine JSON. No new command described here exists today.
| Family | Required interpretation beyond shape |
|---|---|
| Project/workspace create/change | Proposed ID/payload is not a published envelope. Validate exact record-kind payload, owning scope, lifecycle and reserved/delegated target IDs; publisher supplies envelope/authorization. Workspace creation needs an existing exact project. |
| Mission/task create/change | Preserve single-parent ownership, mission policy intersection, dependency acyclicity and current approved intent. A proposed accepted status cannot bypass acceptance. |
| Assignment change | Null current reference explicitly requests creation; otherwise exact current ID/revision must match. New assignment does not abandon existing assignments. |
| Registration manage | Explicit creation/update; grantee identity, parent ceilings, allowed role and delegation must resolve. Never infer membership from creation or dependency. |
| Work read | records returns authorized work records; execution-status returns safe execution metadata; configuration runs the shared hash check. No transcript, account secret or private launch-input dump. |
| File read/change | Only the bound workspace, permitted path components and current limits. Contents/entries are distinct views. Put with null expected digest requires absence; delete requires an existing matching digest. No root deletion. |
| Work propose/result submit | A proposal is not approved work; a submitted result is not acceptance. File/work changes require a recorded assignment. |
| Task/mission accept | Exact subject/criteria revisions, independently authorized reviewer, verified evidence and current approval authority. |
| Decision issue | Validate decision-kind basis and issuing authority. Creation uses a new ID; revision/revocation requires the exact current decision in expectedRefs and the same immutable identity/scope. A model cannot issue owner approval because it can write prose or name the owner. |
| Conversation read/observe | Check separate conversation grants on each page/stream. Record visibility never auto-loads a transcript. |
| Execution launch/control/transfer | Apply sections 3-4, not native engine launch/attach semantics. |
| Workspace retire/reopen | Stop admission immediately; finalize retirement only after safe stop/reconciliation. Retain files/history. Reopen does not restore revoked grants or restart work. |
| Message send | Apply section 5 at both send and delivery. No automatic work assignment or acceptance. |
| Audit read | Resolve classified artifacts with the caller's own rights; knowing a reference is not permission. |
| Session adopt | Explicit reviewed decision plus preserved legacy snapshot; no filename-derived membership or in-place historical conversion. |
New creation/change/acceptance/adoption operation names are separate explicit
grants, not implicit additions to Reader/Contributor/Reviewer/Coordinator.
In particular mission.accept does not follow automatically from task.accept.
System-scoped registration delegation requires reviewed ceiling authority and
an approved delegation-basis: grantee, allowed operations, existing scopes,
preallocated new target IDs, parent decision, expiry and finite use limit. The
parent's limits still intersect it. A scope role cannot redefine shared policy.
Bootstrap creation uses explicit owner authority and an auditable bootstrap
assignment/bundle; ordinary agents cannot select a bootstrap bypass. Once work
exists, changing actions bind to their recorded assignment. Taskless discussion
and inspection never silently become file changes.
controlResponse distinguishes succeeded, accepted, already-active, refused and
unknown. Accepted means durable admission only. Success/acceptance needs a receipt.
An already-active response exposes identity only after authorization. Pre-admission
invalid/unauthorized requests may receive an unreceipted refusal; an audit outage
or uncertain action is never represented as success. Unknown effects require
recovery, not a retry under a new ID. Outcome data is a classified reference.
Reason codes are closed: 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. Client copy must distinguish these without leaking private state.
Request identity is bound to authenticated principal, instance/epoch and canonical request digest, including referenced input digests. A matching retry returns its existing receipt/state. Different content under the same ID refuses. Private bodies are not copied into a public request log. After a reset/lost index, old channels/claims cannot authorize replay: recover the authoritative namespace or require explicit reinitialization and new intent. Do not silently recreate it.
3. Launch, claims, sessions, and configuration
- Authenticate, resolve exact identities/revisions and current policy. Closed or ambiguous scope, bad config, missing evidence or unsupported adapter refuses.
- Resolve work selection. Continue is the default; select/abandon name exact assignments. Abandon changes only those assignments after authorization. None permits conversation/inspection, not arbitrary changes.
- Reserve the single
(agent, project, workspace)claim in a serialized durable transaction. Concurrency initially remains one per tuple; unsupported higher tuning refuses rather than being silently ignored. - Resume selects the recorded current session or an explicit same-scope session. Genuine first use creates and announces an initial conversation. Once history or initialization is recorded, missing state is an error, not new first use. Resume pins an immutable pre-load snapshot and selected leaf (null only for a verified empty history). Verify the engine loads that history/branch; unsupported selection refuses. These private hashes are not part of the comparable base.
- Fresh creates a new conversation with no old chat/automatic summary. Metadata may retain predecessor references; they are not transcript loading authority. If an execution is active, an explicit replacement binding/generation and authority are required. Stop admission, verify old engine and command cohorts stopped, reconcile effects, then release its claim. Idle/abort/EOF is not proof.
- Bootstrap the selected pinned engine in a private instance with inference and tool admission closed. Obtain/verify native session identity and effective settings. If the adapter cannot establish this before effects, it is unsupported. Do not guess the latest file or invent an engine session header.
- Publish the session binding and full launch manifest, verify snapshot digests, then open only the approved capabilities. Record started state and actual process identity. Incomplete bootstrap enters recovery, not automatic replay.
A manifest includes exact agent/session/settings/capability references, image
identity, comparable base projection, context snapshots, policy references and
selected assignments. agentConfigHash hashes the normalized base projection;
launchManifestHash hashes normalized inputs, not its own hash or timestamps.
Preserve ordered inputs. Normalize the skill set before JCS serialization.
Credentials and credential hashes are absent. Account selection is non-secret
identity metadata, resolved through #50 without fallback or in-session swapping.
Private/personal/project/work context appears only in authorized launch inputs. Designated shared general preferences need their classification record; when they serve as shared behavior instructions, include their content digest in the base instruction projection. Do not omit a shared instruction merely because its source is named USER. Context selection verifies source kind, classification, audience and scope; a supplied category is not proof. Work context is a structured projection of R6's approved records, preserving proposed/unverified labels.
Canonical approved configuration publication triggers a comparison for affected executions. Also compare on client connection/reconnection and on demand. Publish matching/changed/unknown and checked time. Missing current sources yields unknown, not matching. Deduplicate notices by execution/old-hash/new-hash/status, retain the current status badge, and deliver on reconnect using the recorded cursor. A local UI toast acknowledgement changes no canonical state. No periodic model polling or silent reload is required. These are event-triggered comparisons, not proof of continuous live memory equality. Permission revocation acts immediately even though ordinary configuration drift is a non-blocking Fresh recommendation.
4. Control and the Pi adapter boundary
A connection is observe or control. Both need their own visibility grants; control is not implicit transcript access. There is one current controlling connection and generation per execution. Check both execution and controller generations on admission. Transfer is explicit, targets an authorized connection, and invalidates old queued input before admitting new-controller input. Previously admitted work keeps its true causal actor; transfer does not retroactively rename it.
A client disconnect does not release an execution claim or prove work stopped. Recovery replacement without the current controller requires an explicit qualified owner/delegation decision; knowing the current generation is not a grant. Revocation closes affected ingress/streams and fences new unsafe actions. It also stops affected running work, recording uncertainty until actual stopping is proven. Unrelated independently authorized/recordable work can continue.
Proposed Pi integration: a broker-owned RPC process with a reviewed, pinned tool bridge, no builtin tool escape, no ambient packages/extensions/templates/context, and no raw RPC endpoint exposed to clients. The bridge requests gateway actions; it does not execute arbitrary project commands inside the credential-bearing engine process. Engine events report observations, never permission decisions. This architecture is proposed, not a claim that the current adapter does it.
Initial prompt body is bounded text. Stop means fence admission and request safe cancellation; only supervisor proof closes the execution. Dialog replies match an outstanding approved dialog, connection, execution and generation. Unsupported engine commands/dialogs fail visibly; no pass-through of bash, session switching, model changes, login, package installation or reload. Additional reviewed mappings must preserve the same contracts. Display engine text as untrusted data: no terminal control/clipboard escape execution or web markup privileges.
5. Messages, queues, and late results
A message has sender, source scope, recipient agent/scope, routing mode, class, private body reference, subject references, expiry, reply correlation and trusted authorization. Sender identity comes from the channel. Record admission before publishing to the queue. Delivery rechecks current sender delegation, receiver membership, body visibility, expiry and exact target binding.
- Current-scoped-session is for permitted ordinary notices. Resolve at delivery within that exact agent/workspace, never a global newest session. Missing or inactive recipient can remain queued until expiry; it does not auto-launch.
- Exact-session never follows Fresh. Exact-execution requires both session and execution identity. Results/interactive approvals use exact-execution routing.
- An approval message only references a separately valid decision. Match pending request ID/digest, intent revision, scope and execution; text saying approved confers nothing. Late results remain evidence for their original execution.
- Delivered means an attributable receiver acknowledgement, not task success or acceptance. Lost acknowledgement gives unknown, not safe permission to resend.
- Retries reuse identity/content. Receiver deduplication precedes processing. Do not claim exactly-once delivery across an unproved crash boundary.
Expiry is explicit and checked against trusted service time and policy bounds; there is no hidden default TTL or automatic approval on timeout. Current-schema calendar validation does not establish clock correctness.
6. Command limits and concrete evidence
command-spec contains reviewed command-profile/parameter-schema identities,
classified parameter/input references and workspace-relative cwd (null explicitly
means workspace root). No raw argv/environment appears in public metadata. The
reviewed profile fixes executable identity and parameter grammar; it is not an
agent-supplied shell wrapper. The parameter-schema reference must equal the
profile's registered schema; callers cannot substitute a weaker schema. Profile/schema bodies are immutable reviewed contract
assets identified by commit/content, not per-workspace copies of authority.
sandbox-limits records the selected sandbox profile, workspace grants, permitted
endpoint identities, wall-time/memory/process ceilings, and the explicit absence
of credential/host-control access. Workspace paths supplement the reviewed image,
scratch and system-filesystem rules in the profile; they do not pretend to list
all internal reads. Resolve current policy and take the least-privilege limits.
The profile must actually enforce filesystem and network boundaries, including
symlinks, mounts, /proc access, endpoint redirects/DNS and child processes.
A declaration, Pi tool allowlist or --offline flag alone is insufficient.
Initial file-effect concurrency proposal: a workspace read/write lease. Writers are exclusive; read-only commands may share a read lease. Hold a write lease until its cohort ends and effects are accounted for. An uncertain writer blocks affected access, not unrelated workspaces or control-plane recovery. Finer concurrency is a later reviewed optimization. Metadata publication uses its separate serialized revision guard. File put uses verified content/destination and durable atomic publication; crashes never turn absence of a result into permission to replay.
Evidence bodies now include process observations, termination proof, decision basis and delegation basis. The publisher verifies their producer and meaning:
| Body | Required additional truth check |
|---|---|
| Process observation | Exact backend object/cohort from admitted launch, pinned image, observation attributable to supervisor; PID/name alone is insufficient |
| Termination proof | Admission is fenced and original cohort/descendants are gone. Never-started proof also establishes no start was admitted and no old producer can start it later. Absence or idle alone supplies neither proof. |
| Decision basis | Subject/criteria/evidence revisions resolve; authors derived from delivery provenance; reviewer is authorized and not an author; request-bound approvals match digest/binding |
| Delegation basis | Issuer/parent authority, target allocations, operations, expiry/use limit and ceilings all hold at use time |
| Command result | Resolve outcomeEventId to the actual command finished/recovered event with matching command/binding. There is no second outcome/signal vocabulary. Classified stdout/stderr/output references and truncation remain distinct from work acceptance. |
Artifact indexes disclose kind, scope, digest, byte length, media type, visibility, publisher and authorization, not absolute storage paths. Index and referenced body must agree. Metadata reads do not authorize body reads. Output capture is bounded/classified by profile; truncation must be explicit in the result evidence, never silently presented as full output. Credentials are allowed in neither metadata nor evidence; do not rely on a generic secret-pattern regex as proof.
The trusted journal publishes intent before effects, started after attributable creation, and outcome only after observed completion. Failure after effects blocks that execution and preserves unknown state. Recovery first proves stopping and reconciles actual files/results, then appends a new observation; it never edits an old receipt or blindly repeats the invocation.
Launch authorization must preauthorize the supervisor's specific fail-safe fencing and stopping of its own bound cohort when required recording fails. Attempt that stop even if a new stop event cannot be written; do not start exploratory recovery commands through an unaudited fallback. Signal the outage without sensitive content and retain unknown state until recording recovers and stopping/effects are verified. A later observed-at time records the later observation, not a fabricated stop time.
7. Storage, retention, and implementation admission
Use the storage ownership/publication rules in README sections 2 and 6. Mutable indexes are rebuildable projections, not the authority. The recorded runtime namespace/epoch and exact scope must survive restart or be declared unavailable. No metadata search may infer scope from an engine filename or host working path. Legacy sessions remain separate until reviewed adoption preserves the original. Adoption rollback before activation discards only unpublished staging and appends its failure receipt. After activation, safely stop affected work, explicitly revise/revoke the adoption approval, and preserve all original/new history and work effects. A now-invalid current mapping causes refusal; it does not silently select another conversation or become first use. A separately authorized explicit Resume/Fresh can establish the next valid mapping. Reversing work effects requires its own reconciliation/assignment, never an automatic historical rewrite.
No new retention duration is implied: retain records and history by default. Workspace retirement is not deletion. Evidence needed for current state, active claims, unresolved effects, live references or required recovery cannot be pruned without satisfying its protection/receipt rules. A pruned reference is explicitly pruned, not current verifiable evidence. Existing reset/prune scripts have not acquired these protections; reconcile and test them before enabling this mode.
The first mediated adapter is admitted only after an implementation charter and proof of: complete mediation; narrow mounts/egress/credential separation; exact session/config binding; crash-safe writer/idempotency; cohort stopping; revocation and stale-controller fencing; context/output privacy; protected retention; closure of legacy broad-mount/unmediated entrypoints into the protected namespace; and #50 account/materialization compatibility. Unsupported capability fails closed. Pinned Pi documentation is not a passing admission test.
| Capability | Evidence available now | Still required before managed execution |
|---|---|---|
| Native/print launch | Current source inspected; earlier owner launch/resume example | New mediated launch implementation and negative tests |
| Exact selection and RPC events | Pinned 0.84.4 documentation read | Verify exact bootstrap/resume identity and cancelled/error cases |
| Pre-action mediation | Architecture and typed requests only | Reviewed bridge/gateway and bypass/failure tests |
| Sandbox | Pinned Pi documentation says no builtin sandbox; current Compose broad mount inspected | Actual filesystem/network/credential boundary tests |
| Stop/replace/control | Typed records and synthetic traces | Real process-cohort, crash, concurrent-client and revocation tests |
| Audit/publication/recovery | Existing writeOnce source plus candidate rules/models | Durable failure-injection and trusted-producer tests |
| Context/config/privacy | Source risks identified; hashes and candidate classifications | Admission/loading/output tests on actual adapter |
| OAuth refresh | #50 boundary read; gate 7 still open | Separately authorized provider/materializer proof |
These are explicit implementation acceptance gates, not missing permissions that an agent may improvise around. No runtime feature claim follows from this draft.