Files
TORCH/docs/ARCHITECTURE_DECISIONS.md
thePR0M3TH3AN 6fdb88ea20 docs: specify proposed candidate attempt store
TASK-6e4ff870-a386-4a11-a59c-444ebc23732e
2026-10-01 09:20:52 -04:00

42 KiB

TORCH architecture decisions

Status date: 2026-09-27

This ledger resolves the implementation decisions identified by PORTABLE_AGENT_FLEET_SPEC.md section 31. A decision marked accepted is the current portable-core contract. A decision marked gated identifies a feature boundary TORCH must not cross until a follow-up decision and acceptance evidence exist.

ADR-001: SQLite state and retention

Status: accepted.

Machine-local structured state uses one SQLite database per installed project, with WAL, foreign keys, and a bounded busy timeout. Messages, acknowledgements, audit records, presence, leases, check receipts, integration requests, context samples, schedule runs, and Fleet changes share the project identity but remain separate tables. TORCH performs no automatic history deletion. Retention or compaction must be an explicit, owner-authorized operation added with recovery tests; until then, durable records are append-preserving.

ADR-002: Control-plane transport

Status: accepted.

The service layer is an in-process API. The agent-facing transport is MCP over stdio and the non-MCP fallback is the structured CLI. The Fleet Console exposes a read-only loopback HTTP observation projection, plus only specifically approved local owner actions documented in separate decisions. There is no required daemon, Unix socket, network message queue, or hosted database. A future socket transport must preserve identity binding and cannot become the data model.

ADR-003: Project identity and repository moves

Status: accepted for the first release; moves are gated.

Installation creates an opaque project UUID stored in tracked configuration, the ownership manifest, and machine-local metadata. All three must agree. Machine-local state also records the canonical absolute repository root, and a different root fails closed. Moving a managed repository therefore requires a future explicit migration command that verifies identity and rewrites only the local root binding; TORCH must not infer a move from a matching directory name.

ADR-004: Runtime process supervision

Status: accepted.

Runtime adapters own process-specific creation, resume, status, capture, and stop behavior and declare every capability. TORCH persists stable Fleet identity and runtime session IDs but does not require a resident supervisor. Unsupported controls fail explicitly and durable messages remain available. The optional system-schedule launcher uses user systemd on Linux; macOS and Windows launchers are separate adapters and are not claimed by this release.

ADR-005: Configuration and generated files

Status: accepted.

.torch/torch.yaml, approved decisions, and tracked backlog records are authoritative. roster.yaml and prompts are reviewable materializations of an approved organization. The ownership manifest records their exact hashes; doctor reports drift, and generated prose never overrides configuration. Changing organization requires the Fleet-change workflow rather than editing a generated prompt and treating it as policy.

ADR-006: Runtime capability negotiation

Status: accepted.

Every adapter implements the common operation surface and declares support for each operation. Startup validates the declaration before planning a launch. The minimum useful adapter can create or resume a session and exchange durable messages through CLI/MCP; live steering, hooks, listing, and stopping may be reported unsupported. TORCH never substitutes an unsupported native feature silently.

ADR-007: Check invalidation

Status: accepted for the first release.

A check pass is reusable only for the exact Git commit and the exact hash of its configured definition. A dirty or changing worktree produces no transferable pass. Additional non-Git inputs require a future declared input-fingerprint schema; until then projects must encode them in the check definition or rerun the check. Branch names alone never validate a receipt.

ADR-008: Local canonical remote naming

Status: accepted.

The local bare canonical remote is named torch-canonical, never origin, and lives under machine-local project state as remote.git. Creation refuses an existing path, remote-name collision, or dirty checkout. The configured remote and path are recorded in tracked configuration and the ownership manifest.

ADR-009: Multi-machine security

Status: gated.

The first release is single-machine and exposes no network control-plane write surface. Multi-machine transport is prohibited until a separate decision defines mutual authentication, encryption, project isolation, replay defense, revocation, and recovery, with adversarial acceptance tests. A forge remote is not a substitute for control-plane authentication.

ADR-010: Distribution and update signing

Status: gated.

Local candidate builds use exact tree hashing, versioned compatibility metadata, isolated state, and atomic activation/rollback. They are not signed. Publishing a package or enabling unattended remote updates is blocked until a follow-up decision selects artifact signing, trusted-key rotation, provenance, and offline rollback verification. Local npm pack qualification does not claim supply-chain authenticity.

ADR-011: Project-specific coordination hierarchy

Status: gated.

The installed organization config now accepts a versioned role graph, and TORCH persists sustained-evidence proposals, exposes them for owner review, and prepares a read-only pilot plan. A separate owner-confirmed CLI activation now commits the approved graph, derived manager schedules, ownership-manifest hashes, and pilot record after freshness checks. It does not launch an identity or modify a system timer. Doctor reports graph roles bound to missing identities, and the read-only Console renders approved roles, identity status, reporting links, coordination links, and implementation ownership. Fresh, resumed, and on-demand identity briefs now include the current role, responsibility, authority, reporting, direct-report, coordination, and implementation-ownership context from the active graph, bound into the prompt digest. A new read-only hierarchy assessment measures recurring cross-domain backlog, coordination-request, manager-approval, and handoff events in each project's configured observation window; it recommends review but never creates or activates a role. Real-fleet measurement, roster binding across every activation path, pilot outcome measurement, adoption, and reversal remain incomplete. Do not represent the full adaptive organization as implemented or encode COMBATRIG's proposed departments as the default organization.

The target design is an owner-approved, versioned organization graph generated from each project's repository and specification. It separates implementation ownership from coordination, fleet operations, program priority, and independent review authority. The graph permits optional coordination levels, one primary owner-facing role, and direct peer communication. Reporting links do not confer worktree access, task reassignment, or release authority. One shared backlog remains authoritative; program and domain documents are summaries, not task queues.

A proposed lead must own a concrete integrated outcome. In this design, headcount alone must never trigger an added management layer. Before this ADR can be closed, TORCH still needs real fleet-pressure assessment, pilot outcome measurement, adoption, and reversal. Owner-approved pilot activation is available through the CLI and the local Console's fresh-plan, same-origin preview/confirm flow. Active tasks, branches, messages, and implementation ownership must remain preserved throughout.

ADR-012: Per-identity runtime and model portability

Status: accepted as a product requirement; implementation gated.

TORCH's policy, identity, backlog, and inter-session communication are provider-independent. Each persistent identity must be assignable an owner-reviewed runtime profile, including adapter, model identifier, optional reasoning settings, and launch policy. A single Fleet may mix Claude, Codex, Pi, other local agent CLIs, and different model tiers at once. Provider/model labels remain project configuration rather than TORCH-wide assumptions.

An adapter registry must combine built-in and explicitly installed local plugins. Plugins declare lifecycle capabilities and unsupported settings; TORCH may not silently substitute a runtime. Durable TORCH messages remain the inter-session source of truth when a runtime lacks native messaging or live steering. Runtime-profile changes preserve identity, backlog, worktree, and resume state, and remain separate from explicit process startup.

The current implementation is partial: install/config, doctor, and lifecycle startup share a capability-declaring registry; identities can select registered adapters and model/reasoning profiles; unsupported settings block launch instead of falling back. Built-in adapters include Claude, Codex, and Pi. The Pi adapter uses explicit provider/model profiles, Pi's extension API, and an identity-bound TORCH MCP server started only for individual tool calls; it runs one resumable turn per process and stores Pi transcripts outside the repository. Pi's local CLI contract and bridge are covered by regression tests, and installed Pi 0.80.3 passes an offline, no-session extension startup without a provider turn. Other Pi versions and live provider resume remain qualification gates. Custom adapter registration still requires an embedding caller for programmatic use. Profile review and changes are available through torch profile show, torch profile set, and torch profile defaults; they validate and write only project-local config and do not launch runtimes. A user-managed local plugin trust flow now pins an absolute CommonJS entrypoint to an explicitly reviewed SHA-256 outside the repository, validates it before registry loading, and lets profile changes select newly trusted adapters without editing TORCH source. Project config cannot grant plugin trust, runtimes list does not execute plugins, and revocation does not affect an already-running process. Launch policy uses a nested launchPolicy object in a runtime default (runtimes.<adapter>) and/or identity (session_manager or domains[]). Identity keys override matching default keys; omitted keys inherit. Adapters declare exact supported field/value sets. Unknown fields/values, unsafe modes, and incompatible combinations block doctor and startup planning before a runtime process is executed. Custom adapters without capabilities.launchPolicy.fields accept no overrides. torch profile show, profile set, and profile defaults expose effective policy; edits require --yes and change future plans only.

The local Console also supports per-identity changes through a same-origin, single-use owner preview followed by explicit confirmation. Preview runs the same CLI validation path as profile edits; confirmation rechecks the exact configuration digest before writing and records an owner audit event. The UI shows current versus next-launch state and does not start or alter a running session. Only built-in and verified, explicitly user-trusted adapters are offered as available choices.

Codex supports sandbox=read-only|workspace-write|danger-full-access and approval=on-request|never|approve-for-me. approve-for-me maps only to --approve-for-me and conflicts with an explicit sandbox because the flag implies workspace-write; other approval modes map to --ask-for-approval. Fresh defaults preserve the previous invocation with approval=approve-for-me and no redundant sandbox field. The historical generated flat pair sandbox=workspace-write, approval=approve-for-me is interpreted as that same effective mode and migrated by the profile CLI before policy edits. Claude supports only permissionMode=default|acceptEdits|auto|manual|dontAsk|plan; bypassPermissions is excluded. Pi exposes no policy overrides and retains TORCH's fixed --no-approve, --no-extensions, and --no-context-files.

Remaining portability gates: supported-version Pi runtime matrix coverage and live mixed-provider resume evidence. Pi extensions execute with Pi's operating-system permissions, so only the bundled reviewed bridge is loaded for TORCH sessions; project extension discovery and project trust are disabled for these invocations.

Built-in starting profiles are Codex gpt-6-luna with high reasoning effort and Claude sonnet. These are editable defaults, not fixed policy: after install, change runtimes.codex.model / runtimes.codex.reasoning or runtimes.claude.model in .torch/torch.yaml; set model and/or reasoning on session_manager or an individual domains[] identity to override that runtime's default. Profile edits do not start, stop, or replace sessions. Codex receives the selected reasoning effort as an invocation-scoped model_reasoning_effort override, leaving the user's global Codex config untouched.

Runtime defaults and per-identity overrides are resolved consistently by startup planning, doctor, the live identity/agent interfaces, and dashboard snapshots. Agents can query their own effective profile without relying on a stale prompt copy. Owners can use torch profile show, torch profile set, and torch profile defaults to review or edit installed project-local profiles. Each write requires explicit --yes, validates the full project config, and only changes future launch plans; it never starts or reconfigures a running session.

ADR-013: Repository analysis snapshot and approval freshness

Status: accepted.

Repository analysis operates on the live working tree: tracked files plus unignored, non-symlink regular files not yet tracked. It reports tracked and untracked coverage separately and never executes project content. A domain proposal binds Git history, HEAD, external specification hashes, and a working-tree fingerprint over visible paths plus analysis-relevant source and manifest contents. Installation recomputes this fingerprint; any relevant working-tree drift invalidates approval even when the commit has not changed. Ignored files are excluded, and the fingerprint is provenance only—it is not an authorization token.

The deterministic baseline assigns a shared path to a domain only when the repository graph shows that domain importing that shared component. Other repository-level candidates remain visible for Session Architect and owner review; they are not blanket-granted as editable shared paths to every domain.

ADR-014: Local visual evidence and owner feedback

Status: accepted.

Visual review evidence is registered only against an existing backlog task owned by the publishing Fleet identity, with a full local Git commit SHA and the runtime session ID captured at publication time. TORCH accepts bounded PNG, JPEG, WebP, and GIF files from that identity's worktree, rejects symbolic-link paths, and copies image bytes into the project's private external local state. The catalog stores content hashes and exposes images only through an integrity-checking local Console route; project repositories do not gain image blobs or a second artifact ledger.

Owner comments use the durable message stream as their source of truth. A comment preview identifies the image, task, target identity, commit, and message effect before an explicit owner confirmation creates the message. The Console's loopback feedback endpoint requires a same-origin JSON request and a single-use, five-minute token bound to the exact preview; confirmation recomputes the plan, while stale, cross-origin, expired, or replayed requests fail without creating a message. The snapshot API remains GET-only, and the Console gains no general task, identity, or lifecycle write access. Private model reasoning is never exposed. Missing or changed image bytes appear unavailable, not as verified evidence.

ADR-015: Browser-local saved backlog views

Status: accepted.

Named Console views are bounded, schema-versioned browser preferences scoped by stable project identity. A view stores only a name and filters over fields already present in the authoritative backlog snapshot. It does not duplicate tasks, statuses, ownership, or queue ordering, and it never calls a write API. Storage errors or malformed data fall back to the unfiltered backlog with an explanatory status. View edits are explicit: owners may save a new view, update the selected one, or delete it; each action affects only this browser's saved presentation preferences.

ADR-016: Backlog-derived feature and milestone progress

Status: accepted.

Backlog tasks may carry optional bounded feature and milestone labels. The Session Manager may set labels at task creation or update them with a revision-checked, reasoned classification action; task-local history and the control-plane audit record preserve the change. Labels never change task state, owner, dependencies, evidence, or queue order. The Console derives group status and completion from the same task records and does not create initiative records, another task ledger, or inferred project taxonomy. Canceled work is reported but omitted from the completion denominator. Test, integration, release, deployment, and live-verification gates remain distinct evidence and cannot be inferred from progress percentages.

ADR-017: Preview-confirmed owner priority changes

Status: accepted.

The loopback Console may expose one bounded owner control: change a task's priority. Every change requires a same-origin loopback request, an explicit reason, a revision-bound single-use preview, and separate confirmation. The service records the owner, reason, prior/new values, timestamp, revision, and audit event. The action cannot change state, ownership, evidence, dependencies, integration, or release status. The snapshot endpoint remains GET-only and no general-purpose Console mutation API is introduced.

ADR-018: Preview-confirmed owner task proposals

Status: accepted.

The loopback Console may let the configured project owner propose one new backlog task through an exact, same-origin, five-minute preview and a separate confirmation. Confirmation creates the task as proposed and unassigned; selected domains are routing suggestions only. The Session Manager retains triage, readiness, dependency, and assignment authority. Creation records an owner audit event and is idempotent for a repeated confirmation token. It does not start, stop, or steer any runtime. The task remains in the existing authoritative backlog and the observation endpoint remains GET-only.

ADR-019: Serialized canonical integration

Status: accepted.

TORCH owns one serialized landing authority per project. Landing acquires a cross-process project-state write lock before revalidating the request, target branch, exact check receipts, authorization, and fast-forward eligibility. The lock remains held through the canonical Git ref update and durable result record. A competing lander fails closed with a retryable busy result and must recompute its plan; after target advancement, stale candidates converge and rerun required checks on the exact resulting commit. Authorized requests are drainable in durable insertion order through one explicit torch integrate drain invocation. After each landing, later requests are re-evaluated; sibling tips that omit the new target become needs_convergence until their owner merges the current target and records fresh exact-commit checks. The drain is one-shot by default, requires explicit confirmation, and is not installed as a daemon or timer. An owner may separately define an exact-config system schedule to invoke the same drain no more frequently than once per minute; each ticket still needs its own landing-authority authorization and fresh exact-commit receipts. The schedule cannot merge/converge worktrees, push remotes, or start AI runtimes. Specialists do not push directly to the canonical branch. External forge credentials can bypass this local queue, so branch protection/credential isolation remains optional defense in depth rather than a false claim of local enforcement.

ADR-020: Current instruction rehydration on every resume

Status: accepted.

Every fresh start and resume composes a digest-addressed instruction bundle from the canonical project checkout. TORCH delivers that current bundle through the selected adapter's supported resume mechanism and exposes the same text and digest in the Fleet brief. Current instructions override historical conversation content, and agents re-read the current brief before each new work item. The bundle is never sourced from a potentially stale specialist worktree. If an adapter cannot apply the bundle, TORCH must disclose or block rather than claim the resumed agent has current instructions.

ADR-021: Hierarchy-aware manager check-ins

Status: accepted; organization-aware inspection, durable queue, typed system-schedule dispatch, default Session Manager cadence, and an opt-in adapter-mediated wake with an atomic project-wide daily invocation ceiling are implemented. Installing a persistent timer and live provider qualification remain gated.

Periodic check-ins derive each manager's direct reports from the active organization graph. They inspect durable presence/task state, unacknowledged coordination messages, and explicit approval waits; uncertain natural-language summaries are not treated as approval facts. Approval requests persist with a named requester and approver, task/evidence context, state, revision, and decision metadata. Named AI approvers receive durable inbox messages and may decide only their own requests; the configured owner decides through explicit CLI confirmation. Decisions are audited and returned durably to the requester. Manager check-ins classify direct-report requests by whether the manager, a peer AI, or the owner must act; they route but never decide on another approver's behalf. The check-in creates a durable, bounded request for the manager to inspect and advance its reports. It never approves, reassigns, edits backlog state, creates identities, or starts provider sessions by default. If the manager is offline, the event remains queued. An optional adapter-mediated wake is disabled by default; owner-reviewed schedule configuration plus a project-wide budget can enable it with an atomic maximum invocation count shared across manager schedules per UTC day. TORCH uses the configured identity adapter/profile and skips active managers. This count ceiling is not equivalent to a USD spend ceiling. No persistent timer is installed without owner approval. New deterministic project proposals include one 15-minute system schedule for the Session Manager. Additional manager identities require their own explicitly configured check-in schedule; project configuration validation rejects an explicit hierarchy that leaves a manager identity without one. Automatic schedule generation follows hierarchy planning and activation; activation surfaces schedule additions and obsolete candidates but does not install or reconcile a system timer.

ADR-022: Explicit fast-forward-only forge publication

Status: accepted.

Integration and forge publication are separate operations. Specialists submit verified commits to TORCH's local FIFO integration queue; the landing authority updates local canonical main. Publishing that landed canonical commit to an attached forge requires a separate owner-confirmed torch forge sync --yes after a read-only torch forge sync plan. TORCH pushes only the exact current canonical commit with normal Git fast-forward semantics and records the owner's action and observed result. It never force-pushes, fetches/merges implicitly, or publishes from the integration drain or its timer. A remote-ahead or divergent result blocks and requires explicit owner convergence. The remote's compare-and-update semantics reject a race that advances its ref after planning. Local integration remains available during forge outages.

ADR-023: Organization-aware lifecycle ordering

Status: accepted.

Startup is topologically ordered by the active reporting graph after role relationships are projected onto persistent Fleet identities. Managers start before direct reports. Wind-down reverses that identity order and routes each active identity's final status to its direct manager identities, preserving bottom-up reporting as the fleet grows. An identity-level cycle or missing manager blocks both plans; an acyclic role graph is not sufficient if multiple roles collapse into a cyclic identity graph. A partial startup leaves already started managers available for coordination and reports the exact identities that did start; TORCH does not silently stop them or continue launching after a failure. Planning alone never invokes a provider. Legacy session_manager.start_last: true remains accepted in existing configs but is ignored in favor of the active organization graph.

ADR-024: Runtime reservation schema compatibility

Status: accepted.

Runtime reservation leases require control-plane schema version 3 or later. An engine may migrate state that predates reservations, but it must refuse a reservation-bearing database relabelled by an older engine and must refuse a database with a newer schema. Runtime and Release must keep the reservation- capable engine active for any project that has reservation state; rollback to an older launcher is unsupported until an explicit, recovery-tested migration exists. This is a compatibility boundary, not permission to install, activate, or start a runtime.

ADR-025: Reviewed reservation-state recovery and writer isolation

Status: proposed; design-only pending independent QA and Session Manager review.

This decision records the recovery design required by TASK-125dd886-6859-4e3c-a0c7-abbfde9eac24. It does not authorize an installation change, a runtime start, a database mutation, a migration retry, or another qualification gate.

Observed writer inventory

The clean candidate be1ae9511e74e3c4c7d8f3d3a5f1212b25c24cc2 has the only reservation-aware initializer: src/control-plane/service.mjs declares schema version 3, defines the twelve-column runtime_launch_reservations table, and creates both its active-identity and unique-attempt indexes. Its CLI (src/cli.mjs), MCP server (src/mcp/server.mjs), and Console server (src/console/server.mjs) all open that control-plane service.

The current canonical checkout and installed active runtime are incompatible writers. Canonical src/control-plane/service.mjs and active ~/.local/share/torch/runtime/active (a link to versions/0.1.0-alpha.2) unconditionally execute PRAGMA user_version = 2 after their shared-table initializer. The installed torch launcher resolves to that active alpha.2 runtime. Its CLI, MCP server, and Console server also open their version-2 control-plane service. Any of those writers can relabel a reservation-bearing database after the candidate has initialized it. A reservation-aware candidate alone therefore cannot safely repair the state.

Staged qualification without production-state migration

There is no non-circular native qualification path today. Every normal candidate-CLI check opens the registered production state root before executing its check, so it correctly stops at the downgrade guard. That failure must not be bypassed to create a real-project receipt.

The first implementation phase is therefore limited to an isolated fixture: it uses a unique XDG_DATA_HOME, a fixture installation and state root, and a candidate-source executable. It may construct version-2 and version-3 fixture databases and exercise the recovery planner/backup verifier there. Its outputs are scoped source evidence only; they cannot be stored as, substituted for, or promoted into any receipt for this project. The existing test fixtures already support a distinct XDG_DATA_HOME; the registered manifest/state-root checks ensure that such a fixture is not the production installation.

Only after independent QA accepts that isolated implementation may Release propose a separately reviewed reservation-aware runtime installation and writer fence. That activation is not authorized by this ADR. Once the fence is live, the real project may take a fresh read-only plan, a separately authorized consistent backup, and—only after another review—an apply. Full native gates remain unavailable until that real state has been safely recovered; this sequence reports the circular dependency instead of hiding it.

Required read-only preflight and backup contract

The future recovery planner must first emit a digest-bound, read-only plan. It must record the project manifest and project.json identities, repository and runtime source hashes, active-launcher target, candidate commit, database file and WAL/SHM hashes, and the exact observed writer set. It must reject an unresolved or untrusted writer rather than infer that a process is absent. A plan does not create a backup or change the database.

The plan must validate all of the following before it can name a database recoverable:

  • PRAGMA integrity_check succeeds and PRAGMA foreign_key_check is empty.
  • The reservation table SQL, all twelve columns, and both expected indexes exactly match the schema-3 contract; a missing, extra, or substituted object is an incomplete-schema refusal.
  • The recorded schema version is 2, the table is present, and every reservation-state count is zero. Any starting, held, succeeded, failed, or otherwise unrecognized row refuses recovery; held rows are never cleared or reclassified.
  • Project identity, local-state path, and database provenance bind to the requested installation. A copied, forged, newer-than-supported, or cross-project database refuses recovery.
  • The plan identifies the external backup destination and the source files to fingerprint, but does not copy them. A later backup phase must produce a consistent snapshot and immutable hash manifest before any future mutation. Backup success is necessary but never itself an authorization to apply recovery.

Writer isolation is a separate, independently verified prerequisite. The future recovery implementation must verify a reservation-aware installed engine and refuse while any alpha.2/canonical version-2 CLI, MCP, Console, or arbiter-owned service can write this state root. A caller-supplied boolean or free-text claim that executors are stopped is insufficient. Runtime/version activation remains a separately owned and reviewed operation.

The required attestation is a Release-owned, installation-bound recovery fence, not a process-list observation. Its verifier must bind the project and state root, the approved reservation-aware runtime digest, retired writer digests, the active launcher target, and an exclusive fence token. The fence begins before plan-hash recheck, remains held through online backup and the apply transaction, and remains enforced afterwards so an old writer cannot restart and relabel the database. BEGIN IMMEDIATE protects the short database transaction but is not a substitute for that lifetime fence. The apply phase recomputes the source state.db/WAL/SHM hashes while the fence is held and refuses if they differ from the plan. It then verifies a fresh immutable snapshot rather than trusting volatile live file copies.

No such verifier or enforceable lifetime fence exists in the current alpha.2 installation. A state-root lock that the version-2 writers do not honor, a stopped PID, or an unsigned attestation is not sufficient. Consequently, live backup and live apply are deliberately unsupported until Release supplies and independently validates this boundary.

Proposed future interface (not implemented or invoked)

The supported path should be two explicit commands implemented only after review:

torch control-plane reservation-recovery plan --area project-kernel --target-schema 3 --json
torch control-plane reservation-recovery backup --plan <plan-digest> \
  --writer-attestation <trusted-fence> --destination <external-path> --yes --json
torch control-plane reservation-recovery apply --plan <plan-digest> \
  --backup-manifest <backup-digest> --writer-attestation <trusted-fence> --yes --json

plan is read-only. backup is a separate, explicit mutation: while the trusted fence is held it must use Node's node:sqlite online backup() API to write an external snapshot, then create an immutable manifest over the backup and the fenced source inventory. Independent file copies of live state.db/WAL/SHM are prohibited. apply must be unavailable until the plan, immutable backup manifest, and a verifier-backed writer attestation all match current state. In one immediate write transaction it must repeat every validation, record an audit event, and only then advance the version label from 2 to 3. It must never create a missing reservation table, drop/rebuild an index, delete a row, clear a lease, or accept a different schema shape as a recovery shortcut. A changed hash, concurrent writer, or transaction contention aborts without a partial relabel.

Required deterministic scenarios before any implementation

  • Empty, exact twelve-column version-2 reservation state plus a trusted reservation-aware writer produces a plan, backup manifest, and one atomic relabel only after a separately reviewed apply.
  • A held row, active row, unknown state, nonzero data count, forged table SQL, missing/altered index, newer schema, or version-3 state missing its table refuses with no database change.
  • A v2 writer attempt racing the plan/apply boundary invalidates the writer attestation or transaction precondition; recovery does not relabel and no duplicate runtime reservation is created.
  • A forged caller evidence record cannot stand in for trusted writer isolation or a verified backup manifest.
  • Candidate-source recovery tooling operating under an isolated fixture state root yields scoped evidence only; a normal candidate CLI pointed at the real manifest remains blocked until a separately reviewed fence and live recovery exist.

These scenarios are additive future QA work under the existing strict consent; they do not relax ADR-024's fail-closed guard or change existing assertions.

Consequences

These decisions keep the first usable release local-first and provider- independent. They also make current boundaries explicit: repository moves, multi-machine control, non-Linux persistent launchers, published update channels, and measurement/adoption of live multi-level organization pilots remain unavailable or owner-gated rather than silently approximated.

ADR-026: Proposed candidate-source qualification contexts and receipt authority

Status: proposed, nonnormative design contribution pending Work, Release, QA, and owner review. This ADR makes no implementation, policy, gate, schema, or receipt-validity change.

Context

Candidate checks must be able to qualify a clean, unlanded source commit without initializing a live control plane. A single engine digest is not enough to establish what was checked, whether it may write a receipt, or whether the result describes candidate source versus an installed operational runtime. Conversely, the schema-2-to-schema-3 refusal protects live registered state and must not be bypassed by fixtures, alternate roots, or a source runner.

Proposed direction

A future versioned result would bind three independent axes. Engine provenance (E) is the exact engine source commit, module path, dependency-resolution and source-tree digests, runtime/build bytes, and interface version. Subject scope (S) is a tagged union: candidate-source contains an authenticator-derived clean managed product commit and root, while operational-runtime has its own authenticated runtime/install identity and never uses a candidate-commit placeholder. Each has immutable subjectProductStorageSchemaDigest (or explicit null) as subject metadata. Receipt authority (A) is the adapter identity/digest/interface, declared compatible registered receipt schemas, registeredReceiptSchemaVersion, and observedControlPlaneSchemaVersion. E is independently recorded and is not presumed to equal S's product commit. The exact tuple would also include protocol version, registered project/install identity, frozen definition and input snapshot digests, guard/resource binding, durable attempt identity, sealed artifact-manifest digest, and actual terminal outcome. Product-storage schema metadata is not a registered receipt/control-plane schema change.

The proposed CandidateAttemptStore/v1 is registered control-plane receipt storage, not product storage. AttemptRecord would bind id, protocol and tuple digests, issued|executing|sealed|finalized state, authenticated project and area, E/S/A sets, frozen definition/input digests, guard and lease bindings, artifact-manifest digest, observed terminal, process fence, and timestamps. ResultRecord would bind attemptId, PASS|FAIL|INCOMPLETE, attributable outcome proof, seal digest, and optional receiptId; UNKNOWN has no ResultRecord and remains nonfinalized guarded evidence. A separately reviewed and owner-authorized Kernel provisioner—not a source check, candidate engine, or adapter—would have to create the store under a qualified registered receipt schema. Until then, missing or incompatible storage refuses; it is not silently created, migrated, or activated. ReceiptAdapter/v1 opens an already-compatible registered schema and performs DML only.

The Kernel would derive a native candidate context from the registered manifest/root, registered area, and exact clean managed candidate, rather than accepting caller paths, manifests, database handles, receipt adapters, commits, or an initial expected commit as authority. The proposed candidate engine would not initialize ControlPlane. A separately versioned registered adapter would validate the tuple and compatible schema before performing receipt DML; the adapter would not perform DDL, migration, schema relabel, or root redirection. A future product-schema-3 subject can be considered with genuinely pure, schema-agnostic engine bytes and an authenticated schema-2-compatible adapter only when the reviewed tuple explicitly supports it. The observed Project Kernel reservation candidate be1ae951 actually initializes ControlPlane, requires schema 3, and must continue to refuse against registered schema 2; it does not imply every candidate CLI is schema-3-bound. This is tuple-specific: valid schema-2 legacy source receipts remain valid under their recorded compatible adapter contract and are not retroactively invalidated or promoted.

Fixture execution would use a separately authenticated fixture identity, manifest/root, and XDG state. It may return a permanently nonpromotable SourceAttestation/v1, never a registered receipt. It cannot be copied or relabeled into registered receipt storage, and Integration, Backlog, and Delivery would not consume it as a gate result.

That fixture nonpromotion does not make every source subject unusable. A future explicitly reviewed candidate-source result may satisfy a prelanding integration requirement for its exact unlanded subject; requiring an independently authenticated post-landing operational subject for that same prelanding condition would be circular. Operational gates still require their own independently authenticated operational-runtime subject.

The proposed worker transport is an adapter-created opaque fresh single-use attempt with a dedicated artifact directory. The worker would receive only a verified immutable snapshot, frozen definition, bounded arguments, an explicit environment allowlist, and per-attempt HOME, TMPDIR, and XDG homes; it would receive neither registered root/manifest/database locations nor provider credential variables. It would receive no registered root, manifest, database, adapter identity, writable receipt path, or migration capability. A process fence would record direct-child and process-group observation; cancellation alone is UNKNOWN. The adapter-created attempt directory would yield only a write-once ArtifactManifestV1: canonical sorted relative paths, SHA-256, and byte lengths for regular files. Links, traversal, special files, overwrite, or post-seal digest drift would refuse.

FinalizeV1 would require exact tuple, active guard/lease bindings, process-fence evidence, and sealed ArtifactManifestV1. One BEGIN IMMEDIATE compare-and-swap transaction would finalize only the matching sealed open attempt, insert ResultRecord, and insert a PASS receipt in that same transaction only for PASS. Duplicate, wrong-tuple, inactive-binding, nonsealed, or finalized attempts fail closed; no durable finalization exists without its PASS receipt or non-PASS result record.

PASS, FAIL, and proven INCOMPLETE remain distinct terminal evidence; non-PASS is durable observable evidence but cannot pass a gate. Error, signal, timeout, ENOBUFS, malformed transport, drift, and zero-exit mutation are INCOMPLETE only when proven. Unproven interruption, cancellation, ambiguous commit, or uncertain persistence is UNKNOWN: no terminal ResultRecord, no receipt, no replay/retry/release, and retained evidence, guards, leases, and resources for exact-identity reconciliation. A proven FAIL or INCOMPLETE with durable attribution and no live descendants may take only existing-policy scoped cleanup, separately recorded from receipt eligibility; it never becomes PASS.

These withheld capabilities are an authority boundary, not an OS filesystem sandbox. They stop the proposed interfaces from granting registered-root or receipt-writing authority, but do not independently contain same-user code that can discover ambient host state.

Unresolved decisions

  • The initial CLI subject rule is constrained: derive registered area and clean managed subject internally; accept no caller selector or initial expected-commit. A future reviewed expected-commit value could only reject a mismatch against that derived subject. Release still must decide command naming, presentation/refusal surface, and the primary src/cli.mjs boundary.
  • QA must approve strict candidate, native, fixture-nonpromotion, schema-incompatibility, single-use, replay, no-DDL, terminal-outcome, and unknown-interruption scenarios before implementation.
  • Durable store choice, guard/fence ownership, process isolation, environment exceptions, artifact sealing/transport, credential treatment, cancellation/recovery behavior, replay implementation, and adapter support for historical receipt layouts remain unselected.

Consequences

This proposal preserves ADR-024's fail-closed schema compatibility and ADR-025's recovery boundaries. It does not authorize live recovery, a schema change, an installation change, a provider start, automatic wake activation, or an integration decision.