# agent-doc Functional Specification

- With `agent_doc_per_component_convergence` explicitly enabled, the commit
  candidate uses the same exact retained expected→target ownership set as the
  terminal convergence gate. Every owned component must already equal current
  Lazily/editor authority; the candidate is then rebased onto that current cut
  so all unowned operator bytes survive. An owned mismatch blocks commit, and a
  live editor never grants authority to merge an independent disk candidate.
- A capacity-paused or otherwise detached closeout must reconcile exact pending
  editor operations before treating an on-disk document equal to the cycle base
  as evidence that no concurrent edit occurred. The on-disk bytes remain the
  compare-and-swap expectation, while the replayed operator cut is the semantic
  current document used for response merge, snapshots, and queue reconciliation.
  Replayed operations are cleared only after the reconciled document is written
  successfully (`#pauseddeletetombstone`).
- Compact Exchange derives its semantic input from the same exact base-keyed
  durable editor-op cut before parsing the exchange. It retains the originally
  observed authority bytes as its compare-and-swap base, atomically lands operator
  deletes with the compact rewrite, and consumes the op epoch only after the
  authoritative write and snapshot succeed (`#compactcachedeletetombstone`).
- Normal preflight publishes typed document observations to one
  controller-owned per-document `Computed`; short-lived preflight CLI processes
  consume that projection instead of independently rebuilding output state.
  Probe mode remains actorless and side-effect free. Effects advance only
  through `repair -> prior-cycle commit -> derived reads -> baseline checkpoint
  -> cycle-open`; exhaustive effect identities and the terminal gate make
  skipped or newly inserted steps fail closed. Cycle-open remains a durable,
  exactly-once identity rather than computed state (`#preflightreactive`).
- Hot-path authority is singular and named consistently across the binary and editor plugins: Lazily current owns the live document, and `state.db` owns intent/lifecycle coordination. Normal execution must not read, write, import, scan, or replay filesystem live-buffer, patch-inbox, queue-journal, queue-delete, continuation, capture, cycle, turn-scope, editor-op, transport-health, hook-session, or cooldown state. Snapshot/CRDT files are permitted only as cold recovery projections after the authority is unavailable; they never vote in a live merge. There is no compatibility fallback to retired sidecars.
- The Zed integration is a supplemental language server for Zed's existing
  `Markdown` language, not a second language that claims `.md`. It activates
  realtime replica behavior only while the live buffer has parseable
  frontmatter with a non-empty `agent_doc_session`; every other Markdown buffer
  is a strict no-op. Controller-to-Zed edits use `workspace/applyEdit`, and a
  delivery is acknowledged only after the matching visible-buffer hash returns
  through `didChange`. The LSP PID is registered with the controller's
  process-exit watcher so a crash cannot strand editor authority.
- The document write state machine is `IntentCaptured -> CanonicalApplied -> ReplicaAccepted -> ReplicaVisible -> DiskProjected -> Committed`. A transition may advance only one edge after its matching proof, duplicate/reordered events are idempotent, endpoint churn is a self-loop, and no recovery command may skip an edge or reconstruct intent from a projection. Queue deletion uses the same rule: the exact Lazily authority shape is the compare-and-swap base, so a missing historical queue item is deletion—not an input to union/replay.
- When a retained operation observes live editor authority that differs from
disk, its recovery owner must request the editor's typed `save_document`
transition and prove that exact authority revision on disk before settlement or
semantic replay continues. A changed revision retries from the new authority;
an unavailable, rejected, or timed-out save remains retained. Recovery never
projects those bytes directly to disk, and operator `session-check` remains a
read-only observer rather than the save-effect owner.
- A controller-derived retained-write settlement is a reactive effect receipt,
not an imperative acknowledgment request. A short-lived observer may join a
`Satisfied` receipt that differs from its turn-local semantic reconstruction
only when the receipt names the same retained intent and its settled hash equals
both the observer's live editor authority and disk observations. A different
intent, missing plane, or mismatched hash must not clear or unblock the local
retained state.
- A controller recycle invalidates relay membership even when an editor still holds a cached client. Forced editor refresh must retire that client and issue a fresh registration. Every deferred document write, including an explicitly authorized `--force-disk` projection, retains its full base and target in Lazily state so reconnect restores or component-merges the editor buffer without consulting Git HEAD. Compact Exchange must compose active captured/deferred response lineage before archiving.

- Captured-response recovery must persist both the response and its complete editor-visible baseline in Lazily `ResponseCaptured` state; hashes alone are not replay authority. A partially materialized response may be reconciled only from added nonblank lines whose multiplicities are proven by the captured baseline and response, with at least two matching lines. The reconciled target must pass through document/editor authority, retain any unrelated operator text, and then replay and commit the complete response once. A legacy hash-only capture may consult a byte-hash-matching Git `HEAD` only as a historical baseline anchor and must fortify Lazily state with the recovered content; it must never restore the working tree to `HEAD`. Template-mode raw captures must become explicit exchange patches before strict replay. An open captured cycle may cross a recovered commit boundary only when the captured response is materially present in `HEAD`.
- A recovery-capable operator session-check that applies a proven replay canonicalization must also close its exact binary-owned commit boundary before reporting `OK`. It may commit only the session document through a private index after proving `normalize(HEAD) == authority == disk`, must checkpoint and re-prove the committed bytes, and must recover that settlement across a process restart without consuming unrelated staged or working-tree content.
> Language-independent specification for the agent-doc interactive document session tool.
> This document captures the exact behavior a port must reproduce.

Individual specs are in `specs/`. This file is the index.

Notable invariants:
- Real-time document authority is operator-first. The editor-visible document
  state owns every operator-authored change, including ordinary non-prompt text,
  queue/backlog edits, frontmatter, comments, whitespace, and partial words.
  `content_ours`, snapshots, and legacy editor-content receipts are merge candidates only; they
  must never authorize a recovery, IPC patch, harness hook, or disk write that
  drops operator-visible text. Snapshots are durable backup/audit state, not
  hot-path authority; legacy snapshot-derived candidates must be narrowed and
  merged into the latest source-of-truth document. The document realtime state
  machine, source-authority projection, editor/disk epochs, owner leases, and
  in-flight apply facts belong to `agent-doc-document-realtime` and are
  lazily-rs-backed state, not turn-local sidecars. The realtime parse state
  projection is also lazily-backed: parse issues surface as realtime editor
  diagnostics and preflight repair is a crash/retry backstop, not the hot-path
  way to make live documents parse. `agent-doc-document` remains the pure
  document model/projection crate. CRDT merge and document realtime
  apply/verify do not commit; the document turn lifecycle owns commit decisions.
  An attached-document write waits for typing quiescence, rebases the agent target
  over the latest canonical CRDT cut, and applies backpressure while any prior
  delivery frontier lacks visible-replica acknowledgement. Repeated intent is
  coalesced to the latest target; an accepted CRDT replacement is never replayed
  through legacy editor IPC, and disk is only a post-acknowledgement projection
  of exact canonical text. Bounded convergence failure retains the change and
  fails closed instead of issuing a competing disk write. An editor-visible
  write acknowledgement is durable authority only when its Lazily event carries
  the full acknowledged content; hashes validate and index that content but
  cannot reconstruct it. A legacy hash-only `already_applied` receipt gets one
  bounded live-buffer publication attempt that upgrades the same patch fact. If
  no editor replica can publish, the full target is retained as a Lazily
  deferred-write intent and the cycle fails promptly without file IPC or a disk
  projection. An empty delivery target set is never convergence for an
  editor-owned write.
  Editor-selected tmux focus is likewise latest-wins per project. A stale or
  pruned actor projection cannot hide a still-running document owner when the
  latest open session log, live pane, and exact process-tree document binding
  all agree; incomplete or cross-document evidence fails closed without
  repairing the document or ownership projections.
  The normal preflight boundary also recognizes the narrowly provable legacy
  corruption shape where a structurally complete session document is repeated
  byte-for-byte two (or a power-of-two number of) times. It automatically
  coalesces that replay to one projection through the same CRDT/ACK path before
  parsing, diffing, or dispatch; the agent must never run a document-repair
  workflow for this transport artifact. Non-identical content is never eligible.
  Editor delivery must target the `editor_id` from the newest live reliable-sync
  registration when an owner lease exists; untargeted file-IPC fallback is not
  delivery proof for an editor-owned document.
  See
  [Real-Time Workflow Authority](specs/14-realtime-workflow.md)
  and [Turn Lifecycle Authority](specs/15-turn-lifecycle.md).
  Invariant: parse state projection drives editor diagnostics; preflight repair
  is not the live parse hot path.
- `agent-doc commit` remains snapshot-selective. It may repair narrowly-classified missed agent-owned drift before staging, but it must not absorb free-form user prompts from the working tree. Already-committed historical response drift may repair the snapshot only when the working tree matches `HEAD` modulo transient boundary / `(HEAD)` markers. On an already-current no-op closeout, a stale agent-owned exchange collapse (committed `### Re:` heading missing from the working exchange, with only committed exchange lines remaining and a duplicated queue-prompt blockquote proving the missing response id) is restored from `HEAD`; independent local queue/backlog/prompt drift outside `agent:exchange` remains visible and uncommitted.
- When the snapshot already matches `HEAD`, post-commit local drift classification must reuse the canonical prompt-bearing diff classifier. Queue/backlog directive edits that preflight would surface as prompt targets are `user_follow_up` drift, not anomalous `working_tree_edits`; inline content corrections remain working-tree edits.
- `agent-doc prompt --all` must normalize OpenCode horizontal permission prompts for any external prompt consumer. When the OpenCode pane exposes option controls but no explicit `← ...` question line, the reported question is the neutral `Permission required`; earlier shell command text, including ANSI-literal `printf` prompt fixtures, must never become a user-facing prompt label. First-party JetBrains and VS Code plugins do not consume this polling surface.
- `agent-doc memory index/search` must use the shared `tsift-memory` library crate to index/search agent-doc session surfaces (`agent:backlog`, `agent:review`, `agent:done`, `agent:icebox`, and live `agent:exchange` responses) in `.tsift/memory.db`. It must not invoke or embed the heavy tsift CLI codebase index on the per-cycle hot path. `preflight` and `plan` may reuse that shared library path to emit advisory `semantic_completion_match` candidates when open backlog/review items or free-text queue prompts are highly similar to done-state memory events; those advisories are proposals only and do not mark work done without a deterministic closeout path.
- Managed supervisor sessions own both the child PTY and a terminal-state model for that PTY. Filtered child output must be fed into an `alacritty_terminal` viewport, and readiness/help/protected-prompt checks must prefer that current screen text before falling back to the raw byte ring, so cursor rewrites and line clears are not interpreted as append-only tmux scrollback. In managed OpenCode sessions, the supervisor stdin forwarder must translate legacy arrow-key escape sequences to Tab/BackTab only while the current child output is an OpenCode horizontal permission prompt (`Allow once` / `Allow always` / `Reject`). Normal OpenCode composer arrow editing must pass through unchanged, and permission-prompt arrows must not leak literal `^[[C` / `^[[D` text into the TUI.
- When `agent-doc commit` sees a `HEAD`-current snapshot plus a later user follow-up prompt, it must leave that prompt uncommitted for the next response cycle and log `post_commit_user_follow_up`; that safe follow-up shape must not be reported as `prior_patchback_without_response_body` or `out_of_band_write`. If the persisted cycle is already terminal, this is a prompt handoff only: it must not re-emit `commit_noop` / `commit_already_current`, rewrite committed cycle state, or describe the prompt handoff as another closeout.
- Extreme snapshot/file drift does not relax that rule for tracked documents. Wholesale snapshot re-sync from the live file is reserved for bootstrap scaffold snapshots on files with no `HEAD` entry yet; tracked documents stay selective so unanswered prompts cannot be committed during preflight.
- Post-commit cleanup keeps the committed blob, snapshot, and user-facing document state in the same clean boundary shape. Transient ` (HEAD)` / boundary-only churn must be collapsed after commit instead of being left as post-success working-tree dirtiness, and that cleanup must preserve comment-only user notes that live outside the committed response.
- If post-commit cleanup proves the working tree lost committed `HEAD` content and added no carry-forward user directive, `agent-doc` must restore the file to the committed `HEAD` blob and push that committed content to a live JetBrains editor buffer through a guarded `refresh_content` socket message. The editor may apply the refresh only when the live buffer still matches the stale content hash/length; any changed buffer must reject the refresh so legitimate carry-forward edits are not clobbered. With a live editor listener, the working-tree disk write may be skipped only after that editor refresh is acked; a no-ack/error refresh must fall back to the authoritative `HEAD` disk write and log `transport=disk_after_failed_editor_refresh`.
- Post-commit cleanup must also fail closed against stale editor buffers that resurrect completed queue prompts. If `HEAD` contains a completed `agent:queue` row and the working/editor buffer contains an active row with the same prompt text, cleanup must restore the committed completed row before any generic editor-buffer flush can persist the stale active copy. This applies to pinned/id-backed queue heads and answered free-text rows, preserves unrelated new queue work, and is directional: a newly struck editor-owned row when `HEAD` still has it active remains editor-owned queue state.
- Queue-head closeout consumption must require proof for the exact active head. Id-backed queue heads require an explicit same-id closeout signal such as `--done`, `--backlog-gate`, `--review-resolve`, or `--backlog-edit`; free-text heads require an explicit current-response target such as the `> **Queue prompt:**` echo for that head. A free-text head's in-progress marker proves selection only and is never answer evidence. Generic repair/no-op responses and unrelated exchange answers must keep the head runnable.
- Before that cleanup runs, newly patchbacked `### Re:` headings in append-mode exchange content must surface as transient ` (HEAD)` markers in the working tree/editor buffer so the user can distinguish the fresh uncommitted response from already-committed transcript history. The write path, FFI/editor patch paths, and fallback patchers must all preserve that temporary marker until the post-commit cleanup removes it.
- Final responses and their complete editor-visible baselines are durably captured as `ResponseCaptured` facts in `state.db` before canonical application. Interrupted-cycle replay uses only that ledger intent and rebases its semantic cell on Lazily current; recovery projections and Git history cannot synthesize or supersede the response.
- Cycle-state lifecycle transitions append stable, idempotent state-backbone facts and advance the formal write phase only after matching proof. No JSON cycle/capture file participates in normal execution.
- Git closeout appends a `CommitObserved` fact carrying the exact `HEAD` SHA after a successful real commit or already-current no-op closeout.
- `session-check` and `preflight` read the state-backbone projection as the only open/terminal lifecycle authority. Projection-only open cycles fail closed; missing/corrupt ledger state is an explicit recovery condition, never permission to import a sidecar.
- `agent-doc preflight` must surface `warnings[].code = "stuck_captured_cycle"` when persisted cycle state says `committed` but the matching durable capture's materialized response body is absent from `HEAD`. Detection must match the active cycle/capture id and response hash, ignore discarded captures, tolerate template patch materialization and prompt-prefix stripping, and stay quiet when `HEAD` already contains the response.
- Every recovery-capable document turn stage that can observe the LIVE controller/supervisor — preflight, generation, stream, finalize/write, commit, compact, and closeout evidence — must detect when its recorded launch `controller_binary` no longer matches `current_binary_identity` and write an idempotent per-document recycle request. The request is mandatory for proven staleness even when proactive auto-recycle is disabled, checkpoints CRDT state first, and is honored only at the supervisor's safe idle boundary so it cannot sever an open closeout. Preflight emits `warnings[].code = "supervisor_binary_stale"`; operator `session-check` emits `[session-check] WARNING:` but remains status-only and does not request the recycle. No stage may insert an operator-facing stale marker into document content. Detection remains fail-open when status or identity evidence is unavailable.
- Quiescent idle-queue observation must be lazily invalidated. With live editor authority, the supervisor compares a compact canonical CRDT state vector plus replica liveness/convergence state before materializing canonical markdown; with disk authority or an intentionally suppressed controller probe, it compares file metadata. Full-text hashing, serialization, and queue parsing run only when that revision changes, when the compact probe fails, or on a bounded safety reconciliation. Installed-binary staleness remains a prompt local probe outside this throttle.
- A reliably-open editor authority with zero registered relay replicas is also stale at every observable turn stage, even when the supervisor binary inode is current. The complete write target remains in CRDT/Lazily state, agent-doc requests the same owner-scoped safe recycle automatically, and recovery retries the binary-owned finalize transaction after reconnect; it must not require response repair or an implicit force-disk write.
- Stale-controller replacement must be directional. The caller stamps its full binary identity on controller RPC requests; a replacement shutdown is accepted only when that identity proves a newer release or a newer same-version build timestamp than the controller bootstrap identity. An older caller must adopt the newer live controller rather than tear it down. This proof applies before every stage-level recycle request so a stale controller cannot refuse a genuinely newer install merely because its own process-local executable still matches its bootstrap record.
- Supervisor recycle in-flight state is a lazily-backed project-controller projection, not a `.agent-doc/` marker authority. Recycle starts publish `StateFact::SupervisorRecycleStarted` and settle paths publish `StateFact::SupervisorRecycleSettled`; callers inspect `SupervisorRecyclePhase::{InFlight,Settled}` through controller RPC helpers. Route/direct/dispatch-only callers must wait through `wait_for_supervisor_recycle_settle_for_file` before injecting prompt text so triggers are not dropped across supervisor `execve`. The old recycle-in-flight marker sidecar is retired.
- Installing the cdylib must apply an explicit per-adapter reload policy after the versioned symlink swap and controller/supervisor auto-recycle. The controller enumerates Lazily registrations, deduplicates by project/PID/editor identity, and sends the shared `reload_library` intent through the PID-scoped endpoint only to adapters explicitly known to support safe hot reload. VS Code and Linux JetBrains are hot-reload capable; unknown or unproved host registrations are restart-required. JetBrains must marshal native calls onto a bounded generation-owned worker pool, keep document replica operations FIFO through per-document workers and per-replica native locks, distinguish queue-wait timeouts from running-call timeouts, stop and join every old-generation CRDT/listener worker, drain calls, quiesce native replicas, terminate every owner thread, close the old JNA handle, and prove the old mapping is absent before loading a replacement and re-registering open projects. A queued timeout retains the generation; only a call that actually runs beyond its lease poisons it. Controller launch from an embedded cdylib must use a short-lived external helper rather than a controller-lifetime reaper thread. The reloadable cdylib must not own the reliable-sync SQLite outbox; durable enqueue/replay belongs to the project controller. Any failed thread, mapping, or ABI proof must load no replacement and require restart. The JetBrains Kotlin package still declares `require-restart="true"` because the native handoff does not replace plugin classes. The operation is best-effort and reports projects, endpoints, deliveries, restart requirements, and failures. No filesystem broadcast or compatibility watcher exists. Running controllers/supervisors still recycle onto the new binary at their idle boundary.
- A stale controller endpoint or zero-replica observation retains the exact canonical revision in the per-document Lazily graph. Registration and canonical-projection delivery wake that same graph; no ACK-replay, force-refresh, full-state request, or editor text-adopt recovery event exists. JetBrains, VS Code, and Zed all open replicas from the controller bootstrap and project it downstream.
- A retained Base → Target transition must pin the response continuation that produced it when durable events are projected. Recovery, its final effect fence, its supervisor wake projection, and the supervisor's resumed operation key/body may not consult a later current-cycle capture after checkpoint, abandonment, or supervisor recycling; replay reconstructs the owning continuation from event order without a sidecar or imperative acknowledgement. The published-effect frontier advances only after successful transition publication, never after a failed attempt.
- When exact retained convergence makes that pinned continuation runnable while its originating foreground finalize still owns the same open cycle, closeout ownership transitions atomically from the foreground owner to the exact captured continuation. The continuation must not wait for owner-process exit, lease expiry, an idle timer, polling, or an editor acknowledgement. An ordinary response-captured wake, a stale cycle/capture/response identity, or a different recovery role cannot authorize this transition.
- The relay must retain recognized editor replica identity metadata with membership and, when a replacement registers, retire prior memberships only when their encoded editor process is provably dead. This pruning occurs on registration and update-driven reattachment rather than idle polling, precedes replacement bootstrap/convergence, and must never infer liveness or ownership for opaque identities. A crashed or restarted editor therefore cannot leave an unreachable pending-delivery member blocking `write --commit`, while independent live replicas remain protected.
- Controller restart recovery must push one targeted rebuild signal to every registration missing from the process-local replica hub, even when the editor advertises peer-pull support. A handoff replacement hydrates durable registrations while private but defers rebuild effects until its exact pid and generation are observed as stable through the public controller socket; otherwise the editor can rebuild into the predecessor generation and promotion can discard the replica. Peer pull is a complementary startup/transport-recovery mechanism because a transparent controller restart may not trip an editor transport-loss hook. An idle watcher that observes an explicit attached-missing-replica or sync-pending state requests one bounded current observation before entering the existing 30-second backoff. High-frequency liveness predicates must not append success or uncertainty events on every controller reconciliation.
- The binary must detect a stale editor plugin and warn (`#stale-plugin-detect`). Each plugin reports its release version in its live Lazily registration; preflight compares that registration against the build-time expected JetBrains/VS Code version and emits one non-blocking `stale_plugin` warning per distinct kind+version. No live-buffer file is written or consulted. Version comparison is dotted-numeric with leading `v` and prerelease/build suffixes ignored; unparseable versions and source-absent packaged builds fail open.
- Supervisor recycle/restart decisions must not sever an open agent-doc closeout cycle. While a cycle is open, stale auto-recycle, explicit admin recycle, editor write-wedge recycle, and failed-reexec escalation all defer. If the cycle never closes past the bounded deferral threshold, the forced recycle preserves the open durable checkpoint rather than abandoning it; the fresh supervisor boot then adopts a surviving child or re-dispatches the interrupted turn exactly once. Stalled-cycle abandonment may clear only old, no-IPC cycles at a true harness turn boundary, never a long active turn mid-closeout.
- A managed supervisor owns one document and must never use a process-global harness-history selector to replace its child. Claude `--continue`, Codex `resume --last`, and OpenCode `--continue` can select another document's most-recent conversation even while CP actor/registry ownership remains correct. Replacement launches therefore start fresh and re-submit the owning document's trigger unless a future implementation has durable, exact document-to-harness-session proof.
- Binary installation is an atomic promotion and ordered handoff boundary. Local install paths must build a complete executable, copy it to a same-directory staging path, preserve executable permissions, and rename it over the installed binary; they must never unlink the live path before the replacement is complete. Background supervisor auto-install must defer while the source checkout is dirty, suppress nested generic recycle-on-install fanout, durably mark route-owned supervisors before controllers, and issue exactly one fleet recycle wave. Live child PTYs remain owned across the in-place supervisor exec; a failed handoff must keep the prior process/binary serving rather than reap the pane.
- Recycle-yield for self-driving queue loops uses the same controller projection, not a sidecar file. The supervisor idle watch records `stale_binary_drain` or `state_flush_drain` as a `SupervisorRecycleStarted` reason; preflight, session-check, and queue continuation detection suppress in-session looping while `supervisor_recycle_yield_pending_for_file` reports the projection in flight, and they surface `queue_recycle_yield=true` / `RECYCLE_YIELD_GUIDANCE` so the harness yields one boundary and restarts on the fresh supervisor. Clearing a recycle-yield settles only those yield reasons and must not clear real admin/auto-install in-flight recycle state.
- Queue drain-stall continuation-pending state is a lazily-backed project-controller projection, not a `.agent-doc/` marker authority. A clean closeout that still requires queue continuation publishes `StateFact::QueueDrainStallContinuationRecorded`; the next preflight classifies `#qstallguard` facts and publishes `StateFact::QueueDrainStallContinuationCleared` after every reconciliation outcome. Supervisor idle-watch drain progress also clears the same projection so an actively progressing supervisor drain cannot false-fire `queue_stall_detected` in the next agent preflight.
- Streaming agent paths must also save durable partial-response checkpoints while generation is still in progress. The first non-empty partial response and then changed partial output at most once every 30 seconds are appended as cycle-scoped recovery facts in `state.db` for diagnostics/manual recovery, without advancing the cycle to `response_captured`. Once the persisted cycle changes, commits, or is abandoned, the writer must stop instead of updating the retired cycle's ledger projection.
- Partial model output must never be written into the authoritative session document. Streaming and orchestration buffer generation outside the document, may update only the `state.db` recovery ledger, and submit exactly one complete final response to the write+commit boundary. Bare/non-committing `agent-doc write` on a session document fails before stdin, capture creation, document mutation, queue consumption, or lifecycle advancement.
- Outside fenced code examples, a session exchange may contain at most one `agent:boundary` marker and it must occupy a standalone line. Final placement removes every prior boundary before appending the singleton at exchange end; duplicate or inline markers fail the mandatory integrity gate. Explicit repair may normalize historical partial-patchback artifacts, but ordinary preflight/finalize/compact/session-check must never launder them into a new baseline.
- Every repair mutation must compare-and-swap against the exact realtime authoritative document image from which the repair was computed. After the write, repair must prove both the realtime authority and the disk projection are byte-identical to the intended repaired image before it may save a snapshot, commit, or report success. A concurrent/stale projection mismatch fails closed and must never be merged back as operator content, because doing so can resurrect fragmented response bodies and duplicate boundaries. If the CAS target was durably retained but the editor owner has zero registered replicas, explicit repair may use the audited force-disk authority to project only that exact retained target; ordinary writes remain deferred, and repair must preserve force-disk reconnect lineage after exact disk proof so a stale editor buffer cannot overwrite the repair when it returns.
- If a repair crosses a detached write boundary and an editor registers with the exact pre-repair authority after the repaired bytes reach disk, settlement must wait a bounded interval for that editor to acknowledge the target. If the interval expires, the original expected-to-target compare-and-swap lineage must remain durably resumable; the already-applied repair must not be reported as an unretained terminal failure. Any different/newer editor cut remains a concurrent-authority mismatch and fails closed.
- Multi-stage repair must settle every superseded deferred target after exact authority/disk proof and retain at most the newest reconnect target, using the original editor cut as its content-bearing merge base. Settling the newest delivery must not reveal an older intermediate marker, boundary, or fragmented response image.
- When a newer response target already equals live CP authority, it supersedes any older deferred response target instead of merging that stale assistant tail back into the document. Reconnect lineage rebases on the exact superseded target: an unchanged failed-ACK editor cut receives the newer target directly, while later operator prompt nodes are preserved through semantic response-tail reconciliation with one terminal boundary.
- When recovery resumes a newer durable capture while the deferred journal still points at a prior-cycle reconnect target, that stale target must not block or overwrite the newer capture. If rebasing the retained target over exact current authority cannot materialize the newer captured response, recovery skips that stale rebase and CAS-replays only the newer response cell over the same authority cut; it clears the deferred lineage only after editor/canonical/disk convergence proves the resulting bytes.
- Every deferred-write composition and settled-operator rebase must canonicalize boundary control state from the newest target branch: outside fenced examples the result retains exactly that branch's singleton `agent:boundary` marker at exchange end. A forced editor refresh is not a reconnect merge or delivery operation: it captures the exact visible editor bytes, validates them, and register/swaps the replacement replica from that same baseline under a generation fence. It never preinstalls or saves a deferred target. Retained mutations replay afterward through the ordered document-cell/CRDT path, so a refresh cannot overwrite a prompt or resurrect deleted queue state.
- Before the generic integrity gate, recovery may collapse a replica-refresh suffix only when the retained prefix is already structurally sound, the appended bytes are an exact suffix of that prefix beginning at any UTF-8 character boundary (including a mid-line or mid-token cut), and the suffix contains agent-doc component scaffolding. This repair removes one duplicated partial component tail without interpreting repeated operator prose as binary-owned state; non-exact or prose-only tails fail closed.
- Session-check publishes that proof-bearing replica-refresh repair through an exact-current authority compare-and-swap. It must not route the repaired projection through the ordinary semantic component merge against the structurally invalid editor generation, because that merge can recreate the duplicate tail it is repairing.
- Terminal `session-check` success additionally requires byte-for-byte equality between current canonical document authority and disk. The operator-facing command is status-only: a mismatch fails closed and records both hashes without requesting recovery, replaying a capture, settling a retained write, or mutating document content. Finalize/write/preflight and the supervisor own those transitions. Its sole self-heal is metadata-only repair of an already-committed historical snapshot whose exact `HEAD` content is proven; substantive post-commit operator edits are never eligible.
- When `session-check` collides with a foreground closeout owner for the same durable capture, it must subscribe to that exact cycle's controller projection and continue as soon as the cycle becomes terminal or the request-scoped owner guard releases. A long-lived supervisor PID is not proof that an individual closeout request is still active. Recovery retries once after owner release, controller reconnect, or a bounded 30-second crashed-owner fallback; the foreground lease is a safety stopgap, never the normal wait mechanism. A timer may schedule a wake at the lease boundary, but it may only observe the resulting clock edge into controller-owned Lazily state; the shared Computed closeout gate, derived from cycle, owner, and observed-clock sources, owns the blocking/released decision.
- Connected and managed clients must not run a second agent-invoked session check after strict finalize succeeds (`#sessioncheckturnreactive`). `agent_doc_finalize` returns the terminal binary-owned closeout report plus queue-continuation fields; managed orchestration consumes the same strict finalize boundary directly. The next turn's admit/preflight resolves the current document and evaluates the open-cycle, prompt-only-tail, and bypassed-response guards before opening new work. A `PreflightStarted` fact for cycle N+1 clears cycle N's closeout owner in the live projection immediately, so a superseded diagnostic cannot retain a lease. The explicit `session-check` command remains available for direct-exec harness distrust checks and debugging.
- Response placement, answered queue-head removal, backlog/review/done mutations, snapshot publication, and commit form one final-response transaction. A validation or convergence failure leaves none of those effects authoritative. `AlreadyApplied` can advance that transaction only when the visible document contains the exact complete final payload expected by the same transaction; a response prefix, partial checkpoint, prior-cycle body, or heading-only match is insufficient.
- Every appended response must cross a commit boundary in the document turn lifecycle unless the user explicitly asks to leave it uncommitted. The normal happy path is `agent-doc finalize <file>`; the documented repair path for an already-present prompt is `agent-doc write --commit <file>`. CRDT merge/realtime convergence may provide the verified document state for closeout, but it must not run the commit as a side effect.
- Strict `write --commit` with empty stdin may only commit when it first recovers an agent-doc-owned visible response or applies explicit backlog/review/icebox mutations. A live editor/CRDT projection is harness-neutral authority for this recovery: even when cycle state is already `Committed` and the snapshot/`HEAD` image is compacted or stale, a response delta proven in the editor buffer must be adopted into the snapshot and carried through the normal commit/session-check boundary exactly once. The binary must never recommend restoring the editor buffer to `HEAD` for that state. Empty stdin with no recoverable response and no tracked-work mutation must fail before commit so live prompt drift remains unresolved for the next cycle.
- Once a closeout cycle reaches `Committed`, a delayed editor intent for that cycle is rejected by its state-ledger phase and generation fence. No alternate delivery transport exists. Active delivery timeout retains the same intent in `state.db`, performs no direct write for an attached document, and resumes from the recorded phase. Terminal lifecycle updates are idempotent.
- Explicit `--force-disk` closeout is the operator-controlled direct-write escape hatch for stale/wedged editor listeners. When used with strict `write --commit` / `finalize`, the force flag must apply to the whole binary-owned closeout path: response placement, pending-maintenance reap, queue consumption, done-id marking, and free-text queue strike. Ordinary preflight/route maintenance still fails closed under active listeners unless the caller explicitly selected this force-disk recovery path, and force-disk maintenance writes must remain attributable in `ops.log`. A live editor buffer that diverges from disk because the operator has unsaved edits is a **valid state, not a wedge** (`#unsaved-buffer-divergence-valid`): the `retry after typing stops` / `visible_write_deferred_live_buffer_changed` / `live_prompt_drift` deferral is the guard working as designed. Harnesses must not chain `make install` + `agent-doc admin recycle` + `--force-disk` to force a closeout through it, and must escalate to the stale-binary recycle path only when the drift is actually traced to a `stale_install` / recycle-yield projection; once the response already reached `committed` in `HEAD` with `session-check` OK, state-only leftovers left in the working tree reconcile on save and must not be force-disked. See [runbooks/commit.md](runbooks/commit.md) `#unsaved-buffer-divergence-valid`.
- Every `agent:exchange` write emits `exchange_write_diagnostic` with the transaction id, writer identity, named intent, expected/current Lazily generations, affected semantic nodes, before/after canonical hashes, rebase/conflict result, and receipt phases. All template, queue, compact, normalization, and repair mutations use node/component-scoped socket intents; `fullContent`, file IPC, degraded attached-editor disk fallback, and compatibility payloads do not exist. The plugin validates target-node preconditions immediately before apply, and the state machine advances only from typed Lazily accepted/visible receipts. Duplicate-prompt repair is response-block aware and operates on the verified canonical result before disk projection; it never adopts post-preflight operator scratch text into an agent-owned snapshot candidate.
- `agent-doc route` defaults to a bounded 500ms quiescence gate before it inserts a missing session id, scrubs duplicate prompt comments, or submits a managed/dispatch-only reopen. The route gate must observe both filesystem mtime idle and the shared editor typing indicator idle for the debounce window; if either remains active through the bounded wait, route fails closed before document mutation or pane input. Editor integrations may pass `--debounce 0` only after they have saved the focused document themselves; the JetBrains `Run Agent Doc` path uses that focused-save fast path so dispatch is not delayed by a second debounce.
- Direct-pane route submit acceptance must not treat a single empty pane capture as proof that the harness received the prompt. Empty captures must remain stable before acceptance, visible drafted triggers still get a bounded submit-key retry, and Codex accepted-without-dispatch-start proof must attempt one late Enter retry when the same routed prompt is visibly sitting in the input. Once the full trigger transport succeeds, absence of dispatch-start proof never authorizes another full-payload send; post-send recovery may send only a bare submit key while the exact routed draft remains visibly present.
- When `route --dispatch-only` queues a prompt-bearing editor rerun behind a busy actor in `agent:queue`, the rerun must be inserted **ahead of queued active-loop items** (priority preempt, `#jb-run-preempt-autoloop-priority`): a manual `Run Agent Doc` preempts the loop instead of landing at the tail. Route-owned queue writes must never add `auto`; when they touch a legacy `agent:queue auto` tag they strip `auto` while preserving other attributes. A bare slash-command line such as `/clear` in an exchange diff is prompt-bearing even without a `❯` prefix, and route must short-circuit it into `agent:queue` for the idle supervisor instead of submitting it as a normal agent-doc turn. The priority insert lands after any leading queue directive (preset / start fence) and must not supersede a lone active-loop prompt, so the queued item is preserved (manual prompt first, then the queued item) rather than replaced. If an explicit editor run finds no new prompt-bearing diff but the document already has a startable inactive queue head (`queue_active: true`, a start fence, or legacy `auto`), route must promote that head to `queue_active: true`, sync the snapshot, and let the supervisor idle-queue watch drain it after the busy pane returns to idle. The idle-queue watch must treat the hook-owned turn-active marker as authoritative over renderer prompt heuristics: queued work, slash-command heads, and automatic context-reset clears may run only after the full turn reaches the Stop/idle boundary. Queued `/clear` / `/new` heads and context reset clears must use the supervisor's clear submit path, not generic prompt dispatch, so they are recovery controls and remain gate-exempt while still submitting Enter to the owner pane. A non-interrupting `session clear` on a busy active auto-queue must publish exactly one deferred `QueueContextClearDeferred` projection for the supervisor's next proven idle boundary; repeat clears while that deferred projection is pending must report "already deferred" and must not refresh the projection or inject another `/clear` into the active turn. After the idle-watch submits the deferred clear, it promotes the projection to `QueueContextClearStarted` until the cleared pane settles. A synthetic active queue head that consists only of a slash command, ignoring surrounding whitespace, is command-only for preflight, plan, and direct run: it must not open `preflight_started`, must not become prompt targets/repo actions, and must stay live in `agent:queue` for supervisor idle submission.
- A managed owned pane must not remain indefinitely split between authoritative ready state and stale busy renderer state. When actor state, supervisor actor state, and controller lease are all `ready` but the live pane probe still reports `alive-busy`/`prompt_ready=false` from a recoverable stale queued-draft cue, route-owned completion and the idle-queue watch debounce that ready/busy conflict for the same four-poll window used by stale-busy idle repair, emit `owned_pane_ready_busy_conflict`, and then let queued work proceed. Genuine active-turn, permission, hook-review, shell-search, help, and clean-exit blockers remain protected. `agent-doc session status` must make the ready/busy conflict explicit and prefer bounded reconcile/clear guidance over pane restart.
- A plain `route --dispatch-only --plain-trigger` reopen (the editor `Run Agent Doc` contract) always submits the bare `agent-doc <FILE>` trigger to a live `ready`, `busy`, or `waiting_input` authoritative actor. It must not derive prompt-bearing queue work from the document diff, mutate `agent:queue`, or require retained editor-delivery proof before dispatch. This is the single replacement/steering boundary: an interrupted turn whose actor projection still reads busy receives the same plain trigger as a fresh run, and a Run click made with selected text or a live document diff follows the same route instead of a separate supervisor-steering RPC. Legacy `selected_text` / `steering_id` payload fields are accepted only as compatibility metadata and are normalized onto this plain-trigger route. Protected interactive substates and non-turn surfaces such as the Claude artifact picker still fail closed, and a still-booting `starting` pane retains the bounded readiness guard.
- Once route admission classifies `managed_reopen` or `dispatch_only_reopen` as an explicit operator reopen, a stale same-generation in-flight dispatch receipt must not coalesce that controller dispatch. Automatic/non-operator re-dispatches retain durable in-flight backpressure, and the JetBrains action layer may still coalesce duplicate clicks while the same bounded `editor_route` request is alive; those are separate dedupe boundaries.
- Template write paths must fail closed when a response contains patch/replace markers outside code blocks but no closed patch blocks parse. Such malformed patchbacks must log `template_patchback_parse_shape` and `template_patchback_malformed_rejected` with response hash, marker count, patch count, exchange patch count, unmatched length, and source before returning an error; they must never be synthesized into `agent:exchange` as raw unmatched content. Strict template, stream, and IPC closeout routes share the same marker and response-heading validation before durable response capture, even when replacing a pending response. Binary-owned replay may transiently normalize the retired `agent:patch:*` wrapper only for an already-durable, complete, marker-only exchange response; it must not mutate the stored capture or session document during migration. Socket IPC attempts must also log `ipc_socket_attempt` plus lazily visible-write receipt hashes/lengths so corruption reports can distinguish malformed payload parsing, editor projection drift, and stale fallback writers.
- When an `agent-doc` turn also includes ordinary repo `commit + push`, manual git commits must exclude the active session document. Agents may commit the non-session repo files first, but the session document still closes through `agent-doc finalize <file>` / `write --commit <file>`, and the push happens after that binary-owned closeout commit lands.
- Narrowed/path-scoped manual repo commits must fail closed on staging drift. The agent must resolve the exact intended non-session path set first, run stage commands only for that set, stop immediately if any stage step fails, prove the staged diff still matches the intended set before `git commit`, and use an explicit pathspec commit or equivalent isolated-index strategy so unrelated pre-staged entries cannot leak into the commit.
- `session-check` must warn on likely partial manual staging closeouts: if the latest repo commit (or dirty submodule repo surfaced by the owning worktree) changes relevant source/test paths and tracked dirty or staged companion changes remain with overlapping changed string literals, the closeout is suspect because local verification may have run against the dirty worktree while CI sees only the committed tree.
- `agent-doc finalize <file>` is the binary-owned happy path for session responses: it must fail before mutating non-git documents, run the normal write pipeline, invoke commit, and refuse success unless the cycle closes in `committed`. If the active prompt is a synthesized active `agent:queue` head and the captured response heading targets that queue item or its `#id`, finalize consumes the queue head even when the visible document had no queue-head diff; unrelated baseline prompts must not consume it.
- A semantic response-cell closeout must not commit ahead of visible convergence. `ResponseCellAdded` proves durable idempotence only; finalize must apply normal typing/ACK backpressure, materialize the acknowledged canonical cut to disk even when an attached authority currently has zero live relay members, and only then snapshot and commit. Materialization proof is semantic across transient ` (HEAD)` and boundary annotations. Before adding the latest complete response, the operation anchors at the last unchanged committed response in `HEAD`, removes only later uncommitted assistant-response nodes, preserves all operator prompts, and emits one terminal boundary; interrupted partial/full variants must not accumulate or require repair. The committed blob and working-tree projection must therefore begin closeout byte-identical instead of relying on later repair.
- Inter-queue-item dispatch is convergence-gated (`#fullboundary`): item N+1 must not dispatch until item N proves a quiescent close — cycle `committed`, the retained editor-delivery settlement no longer blocks a new cycle, this document's editor-IPC inflight count drained to 0, and the authoritative actor idle (dispatch-ready prompt, no active turn). The delivery proof is purpose-scoped Lazily state, not whole-document equality with Git `HEAD`: queue control and newly appended operator queue rows are legitimate next-cycle input and must not retroactively make a completed response look unconverged. A genuinely `Unsettled` retained write blocks; `NoRetainedIntent`, `Satisfied`, and the new-cycle fail-open `Unobserved` verdicts do not. The decision core is the pure `convergence_gate::convergence_gate_decision(ConvergenceFacts)` returning `Dispatch` (all four proofs), `Defer { unmet }` (not yet quiescent, within the bounded timeout), or `Blocked { unmet }` (bounded timeout exceeded while unconverged). A blocked boundary is an ERROR condition and persists a replayable operation-playback artifact (`convergence_playback::ConvergencePlayback`) to `.agent-doc/playback/<doc-hash>/<cycle-id>.json` capturing the ordered IPC attempt sequence (patch_id/transport/receipt/inflight), snapshot/baseline/HEAD hashes, candidate vs `content_ours` lengths/hashes, cycle/run/actor/supervisor identity, and the closeout state-machine transitions, so a recovering agent can root-cause the wedge without guessing. The live supervisor inter-item dispatch (idle-queue watch / drain) is the consumer of this gate and composes with the drain-owner lease (`#kp5z`, dispatch ownership) and `queue_continuation` drainability.
- The `live_prompt_drift` editor-convergence recovery is component-merge-aware (`#qpcwcmerge`). After the editor applies the convergence patches, the recovered editor buffer is accepted even when it is NOT byte-identical to `content_ours`, provided every divergence lives strictly INSIDE a component OTHER than the agent's response component (`exchange`) — the editor's live queue/backlog/review/status and any plugin-defined component, while the response component, the document's non-component regions (preamble/frontmatter/interstitial), and the component structure all match (normalized). In that case the editor buffer is the correct merged state (the operator's live queue + same-cycle auto-strikes + the response), so committing it makes `HEAD` equal the editor buffer and eliminates the recurring `#pcwc` post-commit worktree drift instead of falling back to the `content_ours` disk write that drops the editor's components (editor-wins, `#queue-user-edit-overwrite`). The discriminator is AST-structure-driven and component-name-agnostic (it keys off `component::parse`, never an allowlist), so a plugin that defines a new component is reconciled identically to the built-in queue. Conservative: any out-of-response divergence, a structural component add/remove, or a parse failure fails closed to the existing block/`content_ours` path.
- `preflight` IPC-truncation recovery may ask the active editor to flush its visible buffer through typed `save_document`, but only through the matching PID-scoped editor socket and with a Lazily receipt. JetBrains and VS Code implement the same intent, record editor-surface outcomes through `agent_doc_record_editor_surface_event`, and never use a file signal or editor-local log formatter. If save proof is absent or the published buffer no longer preserves the committed exchange, recovery fails closed with the operator-visible Lazily cut authoritative.
- Component patch and recovery writes may target an editor only when its live Lazily registration, editor identity, PID, and PID-scoped endpoint agree. With no live registration the document is detached and may project to disk; disagreement fails closed before payload delivery, leaving captured intent retryable.
- The editor-sync barrier observes the retained Lazily projection and live replica frontier. Timeout is a bounded absence of convergence; it never sends a republish, re-registration, save, or ACK request to the editor.
- A durable retained transition is one typed state machine over durable Base → Target facts, current editor/CRDT delivery, and controller generation. Its exhaustive states are no projection, idle, awaiting controller, awaiting delivery, awaiting live editor, awaiting convergence, apply target, target visible, reconcile materialized capture, and typed conflict. One derived optional Effect observes the current delivery projection, compare-and-projects Target, or resumes closeout; waiting and conflict states have no effect. The controller listener must be bound before restored liveness publishes missing-replica targets so the resulting full projection cannot be lost during controller startup. This is reactive Source propagation, not an editor request/ACK protocol.
- When preflight/current-document resolution observes live editor membership but the relay model is missing, it schedules the controller-owned canonical projection and returns the typed retained/pending observation. It never asks the editor to publish its current buffer, never seeds authority from disk while attached, and never blocks the foreground command behind an editor recovery barrier.
- The `#yzer` reconnect-reread is editor-agnostic and lives in the binary FFI (`agent_doc_reconnect_buffer_decision`, owning the disk==HEAD vs buffer==prior-commit staleness decision); both the JetBrains plugin (`reconcileStaleBuffersOnReconnect`) and the VS Code plugin (`PatchWatcher.reconcileStaleBuffersOnReconnect`, run on activation) are thin callers that only re-read disk into a buffer the FFI proves stale, so genuine unsynced user edits are never clobbered (editor wins, `#editorbufwin`). The two plugins must stay behavior-matched through that shared FFI.
- Operator-authored queue prompt order is position-locked by stable identity, not by mutating visible prompt text. During preflight, queue prompts absent from the snapshot and not appended by backlog sync form an operator-authored identity set; priority and auto-DAG queue sorting anchors those identities like operator pins while leaving the line marker-free, including id-backed `do [#id]` heads. Binary-synced backlog mirrors still use append-stable ordering, explicit operator pins still anchor normally, and dependency edges may still outrank an anchor when holding the slot would violate the edge (`#qauthorderpin`).
- Free-text queue heads are struck when answered, regardless of position (`#ftstrike`). The normal leading-head consume only strikes a contiguous leading run and stops at an id-backed head, so a free-text report sitting BEHIND an unfinished `do [#id]` head was never struck even after the response addressed it. On closeout, after the leading-head consume, a position-independent pass (`strike_answered_free_text_queue_heads`) strikes every non-struck free-text head whose text the committed response answers — matched conservatively by requiring the head text (priority-markers stripped, normalized to lowercase alphanumeric words) to appear inside the response's `>` quoted-prompt blockquote region, with a minimum four-significant-word guard. A head merely mentioned in prose (not quoted as a prompt) is NOT struck, so an unaddressed operator report is never silently dropped. The pass is also conservative about in-flight operator edits (`#qstrikeexplain`): a free-text head is struck only when it was already present in the stable pre-turn baseline (the preflight baseline). A head that first appeared in the live buffer during this turn — a line the operator is still typing — is never same-cycle struck even if it fuzzy-matches a quoted prompt; it defers to the cycle that actually answers it (editor-wins, consistent with `#queue-user-edit-overwrite`). A missing baseline (rare; preflight writes it each cycle) skips the gate, preserving legacy strike behavior. The pass runs independent of the leading-head `queue_consumption_allowed` decision, strikes the document and snapshot in sync, and is best-effort (a missed strike never fails an otherwise-clean closeout). This mirrors how `strike_done_queue_head_prompts` strikes id-backed heads regardless of position.
- Short free-text heads such as `deploy` count as answered only when the response contains an explicit labeled `> **Queue prompt:**` echo for that exact head (`#qheadresidue`), never from a bare prose mention. `session-check` must fail closed when an active free-text queue row is still present even though exchange history contains that labeled echo, because the row is completed queue residue and would re-run stale work.
- Queue convergence also auto-strikes a LIVE free-text queue head when it is already complete OR a backlog item already addresses it, even if no exchange answer echoes it (`#qftbklgstrike`). During preflight queue maintenance, after the `#qheadresidue` exchange-answer strike, a deterministic (no-LLM) lexical scorer (`memory_cmd::semantic_queue_strike_matches`, the strike sibling of the existing `semantic_completion_match` *warning*) scores every non-struck free-text head (no `#id`) against BOTH the completed `agent:done` archive and the active `agent:backlog` items. A head that clears the conservative `QUEUE_STRIKE_THRESHOLD` (1.6 — strictly above the warning's 0.8 floor, set above the scorer's `+1.0` substring-contains bonus so only a near-restatement of a tracked item can reach it) is struck in place and annotated: a done match renders `- ~~<original> — auto-struck: completed by #<id> (#qftbklgstrike)~~`, a backlog match renders `- ~~<original> — auto-struck: tracked by backlog #<id> (#qftbklgstrike)~~` (the reason is baked INSIDE the strikethrough so the line round-trips as a stable `Completed` entry). The head is struck, never deleted. The same committed-snapshot in-flight-edit gate as `#qheadresidue` applies, so an operator line convergence just added is never struck; id-backed heads are skipped (they have their own done-strike); the operator-authored position-lock (`#qauthorder` / `#queue-operator-pin-position-lock`) and existing `#ftstrike` exchange-answer strike are preserved. The conservative threshold is the false-strike safety margin: an unrelated operator prompt that is not a near restatement of a tracked item can never reach 1.6, so an unanswered operator prompt is never silently buried.
- Queue parser/drainability must treat operator prose followed by a `---` separator as one multiline free-text prompt (`#qfreetext-sep`). In a preset-bearing queue, a prose bug report followed by fenced diagnostics is drainable work: the preset supplies the directive and the prose lead is the object. Pure log/evidence blocks with no prose lead remain predicate-proven noise and may be removed by `queue prune-noise`; prose+diagnostic reports must instead be answered and then struck/consumed by closeout.
- Paused-queue supervisor fallback must not use a supervisor-owned drain-owner lease as proof that a self-driving in-session loop owns the drain (`#qstallguard-failsafe-lease`). The transactional drain-owner row gates only real `/loop` owners; `owner=supervisor-failsafe` rows are ignored by the pause gate, stale-recycle-yield gate, and stall classifier.
- Done-id collection uses each item's OWN id, never prose citations (`#donemirrorreap`). The preflight already-done-mirror reap removes an active `agent:backlog`/`agent:review` item whose id appears in `agent:done` (or the external `archive=` file). That done-id set must be collected per item via `extract_done_item_own_ids` — the FIRST `[#id]` on each list-item line — NOT via a whole-text scan that harvests every bracketed id. Otherwise a `[#other]` cited inside one done entry's prose (e.g. "behind do `[#fullboundary]`" inside the `#ftstrike` entry) is wrongly treated as done and falsely reaps a still-open `#other` review/backlog mirror. An item's identity is its leading id, never a citation in its description.
- `agent-doc mcp serve [--project-root DIR]` is a stdio MCP transport into the same binary-owned document APIs. With no `--project-root` it walks up from its working directory to the nearest project root, so the installed Codex config carries no absolute install-machine path (`#skillinstallconfigpath`); outside any project it stays in the working directory. It exposes read/preflight/plan/session-check/finalize tools for Codex or other MCP clients, but finalize must still call the normal strict write/commit/session-check machinery instead of creating a harness-specific patchback path. Its result includes any queue continuation and is terminal for the managed turn; the session-check tool is an explicit diagnostic, not a required companion call.
- `agent-doc <file>` and `agent-doc run <file>` are the same mode-aware entrypoint. Document mode comes from frontmatter via `resolve_mode()`, with template as the default when no explicit format is present.
- After `run` pre-commits user edits and opens its response `preflight_started` cycle, the agent child wait is bounded by `AGENT_DOC_RUN_AGENT_TIMEOUT_SECS` (default 1800s). While waiting, `run` emits parent-visible heartbeat stderr every `AGENT_DOC_RUN_HEARTBEAT_SECS` (default 30s) and records the heartbeat as open-cycle progress by updating the cycle state's `updated_at` and `last_event`; that gives Codex/direct harnesses phase/cycle evidence that a long child wait is still progressing. When `run` is invoked with terminal stderr inside a tmux pane owned by a Codex/OpenCode parent harness, routine run/diff/commit stderr is redirected to `.agent-doc/logs/run-stderr.log` unless verbose input diagnostics are enabled, so progress output cannot paint over the foreground TUI after a restart. If the child times out, or if a Codex harness tries to run `agent-doc <file>` from the same tmux pane that already owns that document, the command must fail closed, leave the cycle in `preflight_started` with a timeout/blocking `last_event`, and surface cycle id, phase, pane, actor generation/state, and retry/restart guidance.
- If the pre-commit repair for `run` closes an already-committed missed patchback and the post-repair diff is empty, `run` must fail before child-agent dispatch. The diagnostic must say no new assistant response body was supplied and name `agent-doc write --commit <FILE>` as the missed-response repair path.
- `agent-doc start <file>` must preserve the one-live-pane-per-session invariant by failing closed when another alive pane is already bound to that document. Normal `start` may not reuse, restart, supersede, or silently replace that pane. The error must include concrete tmux inspect/capture/kill commands so the user can decide which pane to keep. `--force` remains the explicit escape hatch for deliberate repair work.
- Route-created `start` panes carry an explicit lifecycle policy. Editor-origin Run Agent Doc requests and editor-layout/focus reconciliation create interactive `keep-alive` document sessions so a successful commit cannot be misclassified as a crash and later recreated solely because the selected document became unfocusable. Controller/watchdog recovery retains `auto` one-shot behavior: after a new cycle reaches `committed`, it may stop and reap only when the supervisor actor is in stable `ready` prompt state or direct live-pane evidence shows the child is back at an idle harness prompt, and the document has no liveness signals. Explicit blocking prompt states such as queued drafts, permission prompts, hook-review prompts, history search, and clean-exit restart prompts keep the pane alive. If a one-shot fresh trigger is accepted but no cycle starts, route must record startup-miss provenance and reap the just-created pane instead of preserving an idle registered owner indefinitely.
- Route must re-check legacy associated-pane evidence immediately before normal-path auto-start. If stale registered-pane cleanup clears the old binding and only then a live associated pane becomes provable from session-log / `registry_rebind` / same-file evidence, the binary must fail closed with explicit claim/repair guidance instead of cold-starting around that ambiguity or silently promoting the legacy pane back to authority.
- Startup-miss supersession follows the current registered file owner, not the stale marker's original `session_id`. Once a later pane/session is registered for the same document, `start`, `route`, `sync`, and `session-check` may clear the old pane's `startup_miss` marker only when the current owner's session log proves a newer `session_start` on that registered pane.
- `agent-doc gc` prunes stale operational artifacts without hiding fresh diagnostics: Codex blocked-stop payload records age out after seven days, and `starting` actor records older than one hour close unless a live supervisor PID still has a fresh supervisor heartbeat for that generation. A live but non-heartbeating `agent-doc start` process is not enough to pin `starting` indefinitely. Actor cleanup mutates the controller SQLite store transactionally. The lightweight stale-`starting` actor cleanup also runs every normal `preflight`, `start`, and `sync` cycle; the full orphan-file GC is bounded by a coordination throttle in `.agent-doc/state.db`.
- `agent-doc run <file>` must advance the cycle to `write_applied` once the final response (and any `resume` update) is on disk, before attempting the post-write commit. In git-backed runs, it must then pass through the same strict post-write closeout helper used by `finalize`, `write --commit`, `repair`, and the Codex Stop-hook: commit, prove the cycle is closed, retry once if the snapshot still differs from `HEAD`, and finish with `session-check`. Preflight/recover then finish from the recorded `write_applied` state instead of a stale `response_captured` phase.
- Codex Stop-hook, direct template writes, and `repair` replay must validate captured assistant payload shape before writing whenever an exchange patch is mixed with unmatched text. Transcript-shaped or full-document component dumps fail closed into diagnostics, while known replay guard comments such as `<!-- no-pending-capture -->` may wrap an otherwise valid patch response. Safe plain progress commentary before the first patch is stripped, and the sanitized patch payload is what the write path applies.
- The per-session log at `.agent-doc/logs/<session>.log` must capture document closeout boundaries in the same timeline as harness/supervisor events. When a session document crosses `preflight_started`, `response_captured`, `write_applied`, `committed`, or `abandoned`, the corresponding `document_cycle phase=... cycle=... event=...` entry must be appended to that session log so crash forensics do not have to infer the closeout boundary from separate state files.
- `agent-doc preflight` treats `preflight_started`, `response_captured`, and `write_applied` as open cycle states. It auto-attempts recovery+commit for `response_captured` / `write_applied`; a stale `preflight_started` lock auto-clears when `recover` can prove the recorded snapshot/file hashes still match exactly, when safe historical `HEAD` proof shows the patchback is already committed, or when an otherwise-empty `preflight_started` cycle has no capture and has been stale past the bounded timeout. If the JetBrains File Cache Conflict Cancel branch leaves the response already visible in the working tree and snapshot while `HEAD` lacks it, preflight must classify both `write_applied` and already-marked `committed` variants as `jb_cache_conflict_cancel` and close the missing commit boundary instead of requiring manual `agent-doc write --commit`. If `route --dispatch-only` leaves a busy-actor queued dispatch in the snapshot (`queue_active: true`, `agent:queue`) while `HEAD` lacks it, preflight must commit that route-owned snapshot before diffing; any later visible prompt edit remains uncommitted for the fresh cycle. If that stale empty cycle still has unresolved prompt-bearing drift, `recover` marks the cycle `abandoned` instead of committing a placeholder response, leaving the prompt in the live document for the next fresh preflight cycle. Recent empty prompt-bearing cycles still fail closed so active concurrent work is not stolen. Outside those cases, `preflight_started` still only auto-closes when `recover` replays a pending/captured response first. If neither path applies, preflight fails closed before diffing. Pure agent-owned boundary churn (`(HEAD)` attribution and boundary-id-only diffs) is normalized back to `no_changes` / already-committed closeout instead of opening a new user-visible cycle, so transient post-commit markers do not leak a stale `preflight_started` lock. It emits non-blocking `warnings[]`; when frontmatter `agent:` is set and differs from the detected active harness after alias normalization, preflight emits `code: "harness_mismatch"` so the skill can surface the mismatch while still using active-harness attribution and closeout behavior. It also emits the tier/attribution contract the skill consumes: `effective_tier`, `required_tier`, `suggested_tier`, `model_switch`, `model_switch_tier`, `agent_model`, and `session_accretion` when local exchange/log heuristics detect churn-heavy growth or restart-heavy reopen patterns. Those heuristics are advisory only; preflight does not auto-compact the document.
- Inline prompt-preset references are prompt-preset requests, not only standalone `preset <name>` directives. `preflight.prompt_presets_requested`, backlog-capture guards, and `plan` classification must recognize user prompt text such as `Please analyze failed orders and bot traffic. #next-steps`, while ignoring YAML `prompt_presets:` definition lines. Stale empty preflight cycles and post-compact follow-up prompts that contain `#next-steps` must reopen a fresh actionable `prompt_target` cycle with backlog capture still required; step-2 commit recovery must classify that drift as `post_commit_user_follow_up` instead of absorbing it into the snapshot or HEAD.
- `agent-doc plan` may surface accretion guidance through normal prompt context. Exchange-size accretion and repeated `commit_noop` closeout churn remain advisory; the plan must not suppress normal repo work/finalize or require a compact/restart handoff unless the prompt or document explicitly requests compaction. Claude skill auto-update also defaults to restart, not `/compact`; compact reload requires explicit `agent_doc_auto_compact` opt-in in document frontmatter or project `.agent-doc/config.toml`. After a real Codex skill-version update, the installed Codex instructions must re-read the installed skill completely and continue the active turn in place; they must not request a supervisor restart or stop the turn (`#codex-skill-reload-in-place`).
- `agent-doc plan` must recognize both `do #id` and `do [#id]` directives as executable repo actions. When the id matches an open backlog or icebox item, the emitted normal finalize command must carry `--done <id>` so the binary-owned closeout records the resolved tracked-work item in the same cycle.
- If an ancestor `.tsift/graph.db` is materialized, `agent-doc plan` and `agent-doc orchestrate` should try to collect graph evidence for queued `do #id` / `do [#id]` work before dispatch: `graph-db status`, `graph-db refresh`, per-target `graph-db evidence`, `conflict-matrix`, and `dispatch-trace`. Any tsift collection failure, including stale/fail-closed graph freshness, non-current status, missing evidence targets, command timeout, bad JSON, or missing graph orchestration contract fields, is advisory at the agent-doc turn boundary: `plan` must emit a soft warning plus `manual_packet_only: true`, `orchestrate` must warn and continue without graph evidence, and `jobs create` must still be able to write parent-reviewed manual packets. When graph evidence is successfully collected, evidence packets must be `graph-db-evidence-v1` with `packet_id`, `projection_hash`, `replay_commands`, and `repair_commands`; conflict matrices must be `conflict-matrix-v1`; dispatch traces must be `dispatch-trace-v1` with projection freshness/hashes, evidence packet ids, worker feedback, graph nodes/edges, replay commands, and repair commands; worker prompt packets must be `worker-prompt-packet-v1` with `packet_id`, `projection_hash`, `token_budget`, and explicit fail-closed prompt text. A successfully collected conflict matrix can still block parallel dispatch when it explicitly reports unsafe ownership (`can_parallel=false` or `fail_closed=true`). Prompt targets and orchestration job prompts with available evidence must carry compact graph handles/evidence packet ids plus a normalized lower-agent job packet preserving owned files, read-only context, forbidden files, expected tests, expansion commands, token budgets, fail-closed instructions, and dispatch-trace audit context; child prompt context must not be injected into the session document itself. Successful graph-backed orchestrate child closeouts must append a tsift-projectable `worker_result` line with status, target id, touched files, tests, and follow-up ids before `finalize` so later graph projections can close the feedback loop without scraping CLI output.
- `agent-doc plan` must also emit lower-agent routing fields for job-packet workflows: `dispatch_candidate`, `task_class`, `risk`, `parallelizable`, parent/model tier, context and job-packet token budgets, `write_scope`, `required_proof`, `dispatch_mode`, `manual_packet_only`, `warnings`, and `tsift_context`. `agent_doc_dispatch: off` disables the candidate flag; `agent_doc_dispatch: auto` records opt-in for future automatic dispatch. These fields are structural hints for packet generation and never replace parent review or verification. `agent-doc jobs create <FILE>` writes `agent-doc-job-packet-v1` markdown packets under `.agent-doc/jobs/<cycle>/`, expands compound `do [#a] [#b]` directives into one packet per target, derives target-specific `write_scope` from explicit path references in backlog text, optionally writes an operation note, and records tsift context sidecars when `tsift status --json` / `tsift context-pack --json` succeed. When a tsift graph projection is usable, create dogfoods graph-db evidence, conflict-matrix, dispatch-trace, worker prompt packet, worker_result feedback, replay, and repair command contracts before attaching graph acceptance evidence; when `manual_packet_only` is true, the job index and packet body must preserve the warning and omit graph acceptance evidence so parent review remains explicit. `agent-doc jobs list/status/collect` inspect generated packets and `agent-doc-worker-result-v1` result envelopes only; collection validates required changed path, command/test, touched-file, expected-test, follow-up, proof, and attention fields but does not apply patches, resolve backlog items, or bypass the normal parent-owned `finalize` closeout.
- `agent-doc orchestrate <FILE> --mode dag --from-queue` owns the auto-DAG queue path. It reads all active queue prompts plus queue-level presets, expands compound `do [#a] [#b]` items into per-target nodes, parses explicit dependency metadata and natural dependency phrases, computes deterministic antichain batches, persists `agent-doc-auto-dag-schedule-v1` JSON under `.agent-doc/schedules/`, and writes schedule-backed job packets under `.agent-doc/jobs/<schedule-id>/` before dispatch. `--resume-schedule <ID>` must reload the durable schedule, skip complete nodes, preserve attempt counts, and fail closed if a blocked/failed node would otherwise unblock downstream work. When graph evidence is present, auto-DAG treats stale graph status, missing target evidence, ambiguous ownership packets, or unsafe conflict-matrix antichain dispatch as blockers before launch. Recent ops-log/session-review families are scheduler input: prompt-budget/cache-resend gates to compact-first, restart-loop gates to restart/repair-first, and repeated noop-closeout gates to fixture-fix-first. The schedule record must preserve the guard action, replay commands, repair commands, node state, and attempt count for interrupted run recovery.
- Repeated `--backlog-add` flags in a single `write` or `finalize` command must preserve caller order as a batch at the top of the backlog: the first backlog-add flag becomes the first new backlog item, followed by later backlog-add flags, followed by the pre-existing backlog. Legacy `--pending-add` remains an alias.
- `finalize` / `write --commit` must expose `--no-followups` (with `--no-pending-capture` as an alias) as the first-class declaration that the response creates no actionable follow-up work. The runtime must encode the declaration into captured response evidence before pending-capture guards run, preserve it across idempotent closeout retries, and strip its transient marker from visible and committed document text.
- A `#next-steps` closeout that captures multiple follow-up backlog items must preserve declaration/priority order through the same repeated `--backlog-add` path, and any generated `Top backlog item: #id.` status sentence must name the first inserted live backlog item.
- In an explicit go-mode queue backed by an `agent:backlog queue` component, add and ungate mutations that make ids actionable must mirror those exact ids into `agent:queue` in the same closeout transaction (`#backlogqueuepopulation`). The binary records mutation-scoped actionable ids separately from new-add proof, performs an insert-only queue update after current-head consumption, and orders the new block by hard `after=#id` dependencies before priority. It must not sweep every open backlog id during closeout, because that would resurrect unrelated queue entries the operator intentionally deleted.
- `--backlog-add-to <file> <text>` is the binary-owned path for explicit cross-document backlog capture. Legacy `--pending-add-to` remains an alias. It must fail when the target file is missing or lacks an `agent:backlog`/legacy `agent:pending` component, and `agent-doc plan` must expose explicit backlog target files so skills do not satisfy a target-specific prompt by adding to the current document. Closeout guards must still check explicit targets even when the current document recorded unrelated tracked-work mutations. When a prompt chain contains multiple `#agent-doc-bug` declarations, `agent-doc plan` must preserve declaration order in its expected add mutations and emitted placeholder flags; intentional priority overrides must be visible in response text or explicit mutation metadata, not produced by accidental LIFO insertion.
- `--icebox-add`, `--icebox-add-after`, `--icebox-add-before`, and `--icebox-add-back` are granular tracked-work mutations for parked work in `agent:icebox`. They use the same stable-id, checkbox, collision, same-cycle metadata, and operator-preserving writeback rules as backlog adds, but they must not mirror new items into runnable `agent:queue`.
- `agent-doc boundary` prepares a transient working-tree insertion marker and may signal the editor, but it must not update the saved snapshot or create a git commit. A later preflight/commit may normalize marker-only working-tree churn as already-committed drift, but a standalone boundary marker is never the committed snapshot basis.
- Full and partial exchange compact with a trailing unresolved prompt after the boundary must preserve that prompt in the live editor/working tree while leaving it out of the saved snapshot/commit. The compact closeout may archive old response sections and commit the compacted history, but the next `agent-doc` cycle must still see the prompt as live user drift. Compact therefore carries distinct live and committed targets through the transaction: editor save/relay convergence uses the live target, Git stages and verifies the committed target, and an already-converged live relay must never be reset to the committed-only projection. A stale zero-editor relay fallback may be repaired, but it must be repaired to the live target.
- When warn/block session-accretion prompt packing is active, the bounded exchange context must anchor each prompt target to its actual `exchange` position: include the enclosing `### Re:` block for inline prompt edits, or the immediately previous `### Re:` block for tail follow-ups. The pack must also expose a lightweight live+archive response TOC plus a targeted retrieval surface (`response-fetch`) so agents can request exact neighboring sections on demand instead of relying only on a fixed recent-turn slice. If no clean anchor can be found, the pack may still fall back to the latest bounded recent-turn slice.
- When `sync` discovers that a previously registered pane disappeared while the document's cycle state is still `response_captured` or `write_applied`, it must attempt the same binary-owned recovery path immediately instead of only logging pane loss. `response_captured` must replay from durable capture through the normal write/commit closeout, and `write_applied` must finish the missing commit boundary if the live file/snapshot already prove the response landed. If either recovery attempt fails, the failure must be logged alongside the pane-loss provenance and the durable capture must remain available for later `preflight` / `repair`.
- During tmux layout reconciliation, `sync` must not evict an unwanted pane whose owning document still has an open `preflight_started`, `response_captured`, or `write_applied` cycle. In that shape the binary warns and preserves the pane instead of stashing it mid-closeout.
- `finalize --done <id>` is a tracked-work resolution and must satisfy pending-capture closeout requirements for `do #id` turns in the same way as adding new backlog work. If the item was already reaped into canonical `agent:done`, into the repo-relative external `.done.md` archive named by `agent:done archive=...`, or recorded as resolved in the active cycle, the flag is an idempotent no-op warning, not a fatal "id not found" error. Legacy `agent:backlog-done` and `agent:pending-done` markdown components are migration inputs only, not accepted completed archives at runtime; run `agent-doc migrate` to rewrite them.
- During preflight maintenance, active `agent:backlog` or `agent:review` mirror items whose ids already appear in inline `agent:done` or the configured external `agent:done archive=...` are stale and must be removed from the active tracked-work surface without writing duplicate done archive entries. Active backlog/review items may also be auto-completed when their item text carries an explicit completion marker (`DONE`, `SHIPPED`, `IMPLEMENTED`, `COMPLETE`, or `COMPLETED`) plus deterministic commit or successful-CI proof, but blocker language such as partial, remaining, reopened, deferred, false-closeout, or follow-up work keeps the item active. That auto-completion must not fire on a false positive where the marker only describes already-landed dependency work: for an open (non-gated) item the completion marker must be the item's own leading status verb (the status prefix before the first clause break), not a marker buried in a cited-dependency clause such as "the predicate already shipped in abc1234"; gated `[/]` items keep the marker-anywhere behavior because the agent deliberately code-completed them. Auto-completion must also never reap an item on the same cycle it is added — a brand-new add is absent from the cycle-start snapshot and must be closed explicitly rather than archived the moment it appears. Queue maintenance must also treat those ids as resolved: backlog-to-queue sync excludes them, and existing live queue prompts for them are struck before dispatch.
- `agent:review` is the canonical review-pending tracked-work component. `--backlog-gate <id>` moves backlog work into review as `[/]`; `--backlog-ungate <id>` moves review work back to backlog as `[ ]`; legacy `--pending-gate` / `--pending-ungate` remain aliases. `--done <id>` accepts backlog, review, or icebox sources. `review_done_guard` defaults to `off`; with `warn` or `strict`/`error`, direct `--done` outside review is surfaced or blocked. `agent-doc migrate` moves legacy `[/]` backlog items into `agent:review`, and preflight warns with `legacy_gated_in_backlog` until that migration lands.
- `auto_done: true` in frontmatter, or `[guards] auto_done = true` in `.agent-doc/config.toml`, opts a document into automatic tracked-work resolution for clear completion signals. Explicit inline prompts such as `mark #id done`, `#id done`, `done #id`, `complete #id`, and `resolved #id` must make `agent-doc plan` emit a `ResolveExisting` / `--done <id>` mutation even without `auto_done`; a bare `done`/`complete`/`resolved` prompt may auto-resolve only when `auto_done` is enabled and exactly one open `agent:review` item is the contextual target. When `auto_done` resolves a response-completion guard hit during `finalize` / `write --commit`, it must record the same cycle-state pending-done ids as an explicit `--done`. If the target still lives in `agent:backlog`, the auto path gates it into `agent:review` before marking it done.
- Generated status text that includes `Top backlog item: #id.` must stay consistent with the live `agent:backlog` head. Pending maintenance, reap repair, explicit backlog reap, and exchange compaction must reconcile that sentence to the current open backlog head or clear it to `No open backlog items.` when the backlog is empty; unrelated free-form status text remains user-owned.
- Editor-triggered `sync` serialization must be bounded. A stuck prior full sync may delay a later sync only up to the configured contention budget; safe-passive editor sync may wait only the `sync_lock_wait` latency budget. Immediate editor focus is handled by the separate Project Controller focus command; sync itself does not move focus before acquiring this lock. On safe-passive contention, the binary must emit a visible `[sync] safe_passive_sync_lock_contention_retry ... phase=sync_lock_wait ... status=over_budget ... coalesced=skipped_stale` marker and return without further auto-start, tmux reconciliation, or post-lock hidden-pane focus changes so the editor can retry the latest superseding selection instead of waiting the full lock budget. Lock acquisition blocks in the kernel on `flock(2)` with no userspace polling, and `flock(2)` is released automatically when the holding process exits (fd close), so a dead or orphaned owner can never wedge the lock — there is no `/proc` stale-orphan reap and no manual process cleanup.
- Editor plugins must treat that safe-passive contention marker as deferred, not applied: the stale command must leave the last-applied selection state unchanged, and only the newest superseding tab/layout request may be retried. Editor-side guards must not self-contend by acquiring their local sync guard and then calling a helper that reacquires it before starting the CLI process.
- Editor-selected document focus is operator-first while its latest-wins focus command crosses the Project Controller. The editor plugin must hold a short focus-intent lease that suppresses tmux-to-editor recall of the previously active pane, acknowledge the intended pane without reopening the editor, and restore normal tmux-to-editor following after a bounded expiry if the command never converges. This prevents the two directions from creating a self-sustaining cross-document focus loop.
- Controller-owned safe-passive sync must use the live authoritative SQLite actor row as local ownership proof, allowing an exact-visible editor selection to swap an already-running hidden document pane into view. A standalone safe-passive CLI remains forbidden from issuing a nested Project Controller actor-binding RPC; it may proceed only from non-RPC ownership evidence.
- Editor tab selection performs its immediate focus handoff through the separate latest-wins Project Controller `focus_document_pane` command, resolved from the focused document's own project root rather than the one root chosen to span a mixed-root editor layout. The following safe-passive sync must not steal focus before acquiring its sync lock; it owns guarded exact-visible reconciliation, including the hidden-pane swap after controller-local actor proof.
- One JetBrains editor surface may retain a desired-layout projection through only one Project Controller root at a time. When a mixed-root editor selection successfully republishes that surface through a different root, the plugin must generation-fenced-forget the prior root; a failed forget remains retryable. Component-focus events are selection-only and must not republish unchanged structural layout. This prevents two healthy controllers from reconciling one tmux window from incompatible retained surfaces.
- Plain `agent-doc focus <FILE>` without an explicit pane uses that same Project Controller command and its typed `resume_latest` missing-pane policy. A closed/missing actor projection with a known durable session must reach the resume transition rather than fail at the earlier focusability guard. The focus transition uses typed `ProvisionOnly` startup policy so pane creation/start/selection returns within the short focus RPC; harness readiness and layout reconciliation remain asynchronous. Explicit `--pane` and `--blocking` retain their direct/operator behavior.
- Safe passive sync must also fail safe before attach-first reconciliation would expand the visible `agent-doc` window around those protected panes. If a requested file is not currently visible and satisfying it would require attaching another pane while some already-visible unwanted pane is still protected by an open cycle, `sync --no-autostart` preserves the current visible layout and warns instead of creating a visible 3+/4+ pane mix it already knows cannot detach cleanly. That preserve-layout fast path must still reselect the requested pane when the focused file is already visible in the kept window.
- Session-check must not treat plain `content_edit` drift as proof that an already-committed response bypassed closeout. Only new prompt targets, response patchback markers, hidden snapshot-vs-HEAD closeout drift, or open cycle states should force another closeout boundary.
- Session-check must also fail closed when the live `agent:exchange` tail itself ends in a prompt-looking block with no later assistant response, even when that prompt already matches the committed snapshot. This catches direct/manual closeouts where implementation commits completed but the final response patchback never landed.
- Explicit-baseline `finalize` / `write --commit` must classify concurrent live-file drift against the pre-response baseline. A prompt added after preflight but before write-back remains outside the committed closeout snapshot, and the required post-commit `session-check` must interrupt on that unresolved `prompt_target`.
- For strict template/CRDT append-mode `agent:exchange` writes, an explicit baseline that is missing exchange content already committed in `HEAD` is stale for patch application. `finalize` / strict `write --commit` must apply the response on top of `HEAD` before producing `content_ours`, IPC snapshots, or commit-staged snapshots, while still leaving later live user drift for the next cycle. The repair path must log `explicit_baseline_rebased_to_head`.
- Typed-baseline closeout must survive session-document path moves after preflight. Rename migration transactionally rekeys the ledger events and embedded fact hashes, so `finalize` / `write --commit` resolves the baseline under the current document identity without reading a baseline sidecar.
- Filesystem snapshot sidecars are write-only crash state written by effects after typed `state.db` facts commit; they never override or supplement Lazily current text or typed state. A missing, corrupt, or stale sidecar has no closeout meaning. `reset --from-current` rebuilds typed recovery state from Lazily current markdown; no CRDT, capture, pending, baseline, snapshot, or live-buffer file is imported.
- Cross-process state exchange uses generic `state_plane_publish`/`state_plane_subscribe` transport RPC around canonical Lazily `Snapshot`/`Delta` messages. Producers publish keyed state projections; RPC handlers must not translate those publications into imperative plugin-owned effect retries. Covering snapshots may replace a prior producer, deltas require the exact producer/base epoch, duplicate delivery is idempotent, and subscribers resume from a monotonic controller plane version.
- Pane layout is the first state-plane domain. Editor plugins publish desired columns/window/focus, while the controller derives typed desired/actor-binding/observed/effect status and owns retained tmux reconciliation. A tmux attempt is keyed by the exact desired generation plus actor-binding projection. Convergence retires it; a retryable failure derives stable `retry_pending` while the same latest-wins effect worker retains ownership, waits with bounded backoff, and retries until convergence or supersession. A newer desired-layout or actor-authority fact interrupts that wait and wakes the retained worker immediately. The controller must not synchronously poll tmux from its IPC accept loop or create a detached periodic retry timer. Columns and focus are one product projection: convergence requires both matching observed columns and, when focus is requested, a typed receipt proving the final input-revision-fenced pane-selection consequence. Desired layout is committed to `state.db` before tmux effects, so controller restart recovery does not depend on controller-lifetime message history.
- A pane-layout observation must independently compare the model-owned file-to-pane assignment in desired column order with tmux's physical left-to-right pane order; matching document labels alone cannot prove convergence. A live same-window actor outside the desired surface is diagnostic, not terminal ownership: reconciliation may move its pane to `stash` without killing or interrupting the actor, and the generation remains `retry_pending` until the visible pane count and order converge. A missing requested surface document likewise remains `retry_pending`. Focus continues to resolve the requested document through the file-to-pane assignment and must never index directly into physical pane order.
- A foreground editor `Run Agent Doc` route must treat its `--col` / `--focus` payload as one exact-visible desired-layout Source and await that controller projection before dispatching to the routed pane. Before publication, the controller canonicalizes editor-relative paths and requires the routed document in the converged columns. If focus is absent from the columns, the controller may materialize it only into one unique explicit empty-column placeholder; zero or multiple candidates fail closed before desired-state publication or dispatch.
- Pane-layout status `phase` and `reason_code` are wire-stable enums; optional `reason_detail` is diagnostic only. Version 1 uses Lazily's canonical JSON envelope and typed JSON node payloads. Protobuf may be added as a node payload codec for additional language runtimes, but it is not required by or embedded into the Lazily state-plane core.
- A pane-layout effect receipt is a source fact, while its applicability is a computed join of desired state, actor-binding state, and receipt state. The exact file-to-pane assignment returned by the effect remains attached to that desired-generation/actor-binding pair and takes precedence over actor-store or process-tree inference during observation. A receipt or observation from a superseded generation or actor binding cannot prove convergence or select a pane for newer editor navigation. This controller-owned rule is editor-neutral and therefore applies equally to JetBrains, VS Code, and Zed publishers.
- `install-full` removes repository-owned compilation outputs only after the binary, native library, and editor plugins have been installed successfully. It preserves Cargo's global dependency caches and supports `AGENT_DOC_CLEAN_BUILD_ARTIFACTS=0` when an operator intentionally wants to retain incremental outputs.
- Exchange prompt-prefix normalization must preserve exchange prompt-prefix state already committed in `HEAD` in both directions: previously prefixed user-prompt lines must keep `❯ `, and previously unprefixed agent response lines must stay bare. A `content_ours` fallback may add `❯ ` to newly typed prompts, including every nonblank line in a blank-separated multi-line prompt run after a stale inserted response block, but it must not add that prefix to prior agent response lines simply because the snapshot/baseline pair is stale. Inserted assistant response blocks stay assistant-owned until an explicit `❯` line, component/boundary marker, or canonical prompt-target diff opens a new prompt run; prompt-shaped assistant prose such as questions is not enough by itself. When IPC sidecar verification rejects a plugin-side normalization result and computes a `content_ours` fallback, that fallback must first merge current disk edits against the explicit pre-response baseline, then deliver the normalized repair through narrow editor IPC. If editor delivery is skipped or unproven, the write must fail closed before saving a snapshot, CRDT state, commit, or direct working-tree repair. Concurrent user edits outside `agent:exchange`, including deletions of scratch HTML comments, must remain editor-owned and must not be restored by normalization retry. Post-commit prefix repair must not propagate historical bad prefixes from assistant evidence labels such as `Commit / push:` into later assistant responses, and patch/content prefix application must still refuse to prefix those assistant labels if a stale target list includes them, even when a historical stale target list contains `Commit / push:` and a later response has a fresh bare `Commit / push:` label. A temporarily prefixed response heading such as `❯ ### Re:` is still an assistant response boundary; prefix repair must not treat matching response-body lines after that heading as prompt targets. Prompt-prefix overrun protection logs and passes through when more than `MAX_NORMALIZE_USER_LINES` prefixes would be applied; it must not force-commit from inside normalization now that typed repair decisions own disk/snapshot/editor recovery.
- Sync live-owner recovery must rank file-specific evidence by freshness: path/supervisor provenance first, then the latest open session-log owner, and only then generic same-file process-tree matches. An older pane that still has a same-file harness process must not steal authority back from a newer pane that already recorded the latest `session_start`.
- Sync must also treat the latest alive `session_end origin=registry_rebind ... next_pane=...` successor as authoritative live-owner evidence before generic same-file process-tree fallback. A pane handoff proven by tmux/session-log provenance must not fail just because the supervisor PID or foreground process tree changed afterward.
- When `route --dispatch-only` reuses a live pane through direct tmux input, startup-window reroutes must first observe a harness-specific dispatch-ready prompt in that pane. A Codex status/footer line such as `gpt-5.5 high · ... · Context ...` is not a prompt by itself. OpenCode startup-window prompt probes must use the longer OpenCode redraw budget, including the same harness-specific recovery wait used for starting actors, because the idle splash can become dispatch-ready after the short Codex-style boot probe. During that startup prompt-ready wait, route owns the pane input window and must publish controller-backed `RouteSubmitStarted` / `RouteSubmitSettled` facts before any supervisor idle-queue context reset can enqueue or submit `/clear` / `/new`; pending `QueueContextClearDeferred` / `QueueContextClearStarted` projections and orphan visible clear drafts must wait while the route-submit projection is pending. Accepted-without-dispatch-start proof records `RouteSubmitBlocked` for the bounded blocked window. Dispatch proof must separate pane-input acceptance from dispatch-start evidence. Accepted shared text+`Enter` delivery is a successful dispatch-only result for Claude Code, Codex, and OpenCode, and logs `proof=accepted proof_scope=accepted_only` when dispatch-start proof is absent. Codex hook proof and OpenCode pane-state proof are still logged as stronger `dispatch_start` evidence when available, but missing stronger proof does not make the editor action fail. Editor-triggered JetBrains routes must propagate the durable Run Agent Doc attempt id into the binary process, and route/tmux diagnostics must include that id on the input-delivery and proof lines so a live click can be correlated across `.agent-doc/state/editor-route-attempts/`, `ops.log`, and preserved route-submit pane snapshots without replacing tmux-router reconciliation.
- Claude readiness treats a bare `⧉ <label>` line as an attached-artifact composer chip and continues scanning for the real idle `❯`/permissions prompt; `<label>` is arbitrary session content and must never be hard-coded. Only the complete picker shape (`Enter to open` plus a `claude.ai/code/artifact/...` URL) is an operator-owned dispatch blocker.
- Safe passive mixed-root sync must preserve the current visible `agent-doc` window layout whenever any visible file stays blocked under `sync --no-autostart`. In that shape the binary warns and skips tmux-router reconciliation instead of collapsing the remaining foreign pane set into a new authoritative layout, but it still reselects an already-visible requested focus pane inside the preserved window.
- Full/manual `agent-doc sync` is the binary repair path behind editor `Sync Tmux Layout`: before reconciling the editor pane projection, it must invoke the same file-scoped doctor repair used by `agent-doc session doctor <FILE> --repair` when a focused/session document is available. That repair must close recoverable `jb_cache_conflict_cancel` commit-boundary drift (visible document and snapshot already contain the response while `HEAD` does not) before pane liveness can short-circuit, and must normalize the inferred tmux session to `0:agent-doc`, `1:stash`, and adjacent overflow `N:stash` windows, renaming `stash-*` aliases back to `stash`, even when the editor supplied a stale `stash` window target or sync starts while the active window is named `stash`. Passive `sync --no-autostart` remains non-destructive and does not run that repair step.
- A full/manual sync that provisions a missing document pane owns one terminal create-and-route boundary: resolve the intended tmux session, create and register the pane there, wait for the harness to become dispatch-ready, and submit the document reopen before returning success. The Project Controller receipt records that this strict path was selected. Automatic/passive editor sync remains admission-oriented and must not wait on or claim this manual route boundary.
- Safe passive editor sync must optimize for the fast pane handoff path before it owns the bounded sync lock when a local projection or no-record provisioning miss is cheap, then converge through the existing locked path. Safe-passive prune may still remove stale registry rows and retained dead non-stash panes, but it must skip expensive stash-window and stash-pane cleanup before tmux-router reconciliation so extra visible panes are detached before orphaned stash scans spend the selection budget. If no live actor binding exists after the pre-lock handoff, reuse the latest matching pane when one is known, otherwise fall back to an alive exclusive registered pane rooted to the same document, and only then cold-start a new pane. The slower supervisor/process-tree recovery still applies to non-passive paths and non-happy-path recovery.
- Automatic editor syncs that have a complete visible markdown projection must pass `--exact-visible` with `--no-autostart`; the binary must then treat a single `--col` as authoritative and skip remembered focus-only sibling expansion, so stale panes do not reappear after the editor switches away from a document.
- `resync --fix` orphan-agent cleanup must prove a pane is unowned across project roots before killing it. A non-stash agent pane that is absent from the current registry but registered in its pane-local project root, still proves a live owner there, or hosts a live supervisor from that root is preserved instead of being reaped as a parent-project orphan.
- Safe passive focus-only editor sync must not collapse a multi-column `agent-doc` tmux layout to one pane. When a single focused markdown column arrives while the last recorded layout has sibling columns, sync should first prefer the remembered or currently visible column that already owns the focused document; only true replacements should infer the editor side from the currently active tmux pane in the target `agent-doc` window. It must replace only that column with the focused document and keep the sibling columns visible until a full editor-layout sync supersedes it. If no recorded layout exists, sync must derive the same sibling projection from the registered panes currently visible in the target `agent-doc` window before reconciling.
- `agent-doc preflight` must also fail closed before diffing when the live snapshot/file pair already looks like an uncommitted assistant closeout with no open/recoverable cycle left to explain it. That includes a visible bypassed `### Re:` block and the hidden `snapshot != HEAD` shape where the file now matches the snapshot but tracked side-effect edits are still only in the working tree. The failure must name `agent-doc write --commit <FILE>` as the repair path.
- `agent-doc commit <FILE>` may close an already-committed historical response as a no-op while leaving later user follow-up prompt edits for the next turn only when an open/recoverable cycle still needs that terminal transition. If the most recent cycle is already terminal, a later user follow-up prompt is not a closeout at all; the command must return without lifecycle no-op bookkeeping and say to rerun `agent-doc <FILE>` or pipe the missing response through `agent-doc write --commit <FILE>`.
- When the document diff is empty, direct harness prompt text or an active queue head item may still open a real cycle. The binary strips the leading `agent-doc <file>` invocation from the current harness prompt (Codex hook state or explicit `AGENT_DOC_HARNESS_PROMPT`) or reads the active `agent:queue` head prompt, synthesizes an in-memory added-lines diff from that body, and feeds it through the normal prompt-target / prompt-preset / backlog-contract classifiers. Bare `agent-doc <file>` with no trailing body and no active queue still remains `no_changes`.
- Consuming (striking) the active `agent:queue` head requires an explicit completion signal for `do [#id]` directive heads, never an inferred one (`#queue-strike-on-halt`); synthetic/preset heads have an exact-id exception (`#queue-head-consume-on-topic-id-regression`). On the CLI `finalize` / `write --commit` path, consuming a `do [#id]` head requires a closeout flag — `--done <id>`, `--backlog-gate <id>`, or `--backlog-edit "<id>=..."` — that names the head id, or a genuine fresh operator prompt-target / `do queue` trigger in the cycle diff. A `### Re:` heading that merely names a `do [#id]` head is not a completion signal, because a halt/refusal response names the head to explain why it is not being done. For a synthetic/preset head (a natural-language prompt carrying a trailing `#preset` id, not a bare `do [#id]` directive), the CLI path additionally consumes when the response heading topic resolves to exactly the head id (`### Re: #spec-test-build-install-commit-push`). An operator-pinned bare id head (`[#id]` / `#id`, with or without a `:pushpin:` / `:round_pushpin:` priority pin) whose id names a tracked `agent:backlog` / `agent:review` item is an id-backed directive, not a synthetic/preset head: it follows the same explicit-flag rule and must not be struck by a `### Re: #id` log-check/halt heading (`#zwn5`), so an operator-drive live-verify item the agent can only log-check stays pinned for an explicit close. A registered prompt-preset id is not a tracked backlog/review item, so it remains synthetic and still consumes on a matching heading. The Codex Stop-hook auto-close path, which has no closeout CLI flags, consumes from a response heading on an exact topic match to the head prompt (`### Re: do [#id]`) or a topic that resolves to exactly the head id (`### Re: #id` for head `do #id`) — never on a heading with trailing modifiers such as `### Re: #id halt` / `### Re: #id deferred`.
- When recovery reopens a closeout from durable capture or Codex `last_assistant_message`, an `AlreadyApplied` dedup outcome is still allowed to advance the snapshot and `write_applied` phase when the live document already contains the response but the snapshot does not. That keeps the subsequent commit boundary binary-owned instead of downgrading the turn to post-commit local drift.
- The same adopt-current closeout path must also work when no pending/capture artifact survives but the live document already contains a fresh visible response block absent from the snapshot. `repair` and the Codex Stop hook may synthesize that visible response back into the normal dedup/write-applied/commit pipeline, but they must not leave the response as plain working-tree drift that still needs a separate manual commit.
- Explicit `agent-doc repair` must also fail closed when the no-pending recovery pass still leaves a `session-check` interruption behind. A committed historical patchback may self-heal the snapshot from `HEAD`, but if later prompt-bearing user drift remains after that repair, `repair` must surface the same interruption instead of reporting `No pending response found`.
- Fresh route-triggered starts must not treat prompt detection or pane-input consumption as sufficient success. After the initial trigger injection, the route path must observe a new per-document cycle state for that file before considering the start successful; otherwise it fails closed as a missed startup rather than silently idling. Harness-readiness detection should key off the real harness prompt shapes, not a generic shell `>` echo.
- When route has already created a fresh pane for a document, a concurrent same-session registry rebind is not authority by itself. Fresh-start dispatch must stay on the new pane unless the new pane is invalid for that file, so layout/sync churn cannot supersede the just-created pane out of the visible `agent-doc` window.
- When a Codex child exits after a stdin-forwarded `Ctrl-D`/stdin EOF or a terminating stdin-forwarded `Ctrl+C`, the supervisor must always route that clean exit through the restart-or-quit prompt, even if the run already recorded a committed `document_cycle`. Operator quit keys must never auto-restart Codex directly.
- Supervisor stdin forwarding has one runtime implementation (`#af88`): on Unix it reads the raw stdin fd only after `poll()` selects it and watches a sibling stop pipe, so child exit can interrupt and join the forwarder before any restart/quit prompt reads stdin. `PtySession` must not expose a second blocking `stdin.lock()` forwarding path. Editor IPC connections are likewise bounded at both edges: callers time out a wedged `connect_sync`, and listener handlers close half-open clients that never deliver a complete request line.
- When Codex definitively reports `No saved session found with ID <id>`, the supervisor must remove `resume` only if the current document still names that exact ID, then immediately launch and trigger a fresh session. If the current editor cut contains safely provable replay duplication, cleanup must normalize that structure and remove the matching pointer in the same expected-current authority write so malformed scaffolding cannot retain the dead ID. Before retrying cached resume launch arguments, the supervisor must also honor an operator removal already visible in document authority and relaunch fresh. It must not repeatedly back off and retry the stale ID. Ctrl+C during any crash-backoff interval must stop the supervisor even though no child currently owns stdin and the terminal is raw.
- When a fresh/fresh-restart Codex child clean-exits before it ever surfaces an idle prompt and no forwarded operator quit key was observed, the supervisor must restart fresh instead of prompting the user. That exit is failed startup provenance, not an intentional quit.
- When a routed Codex fresh-restart retry never regains a dispatch-ready prompt after the supervisor bounce, the binary must keep the optimistic fallback explicit: record the resulting `startup_miss` on the original routed pane, preserve the canonical absolute document path for later recovery, and avoid silently redirecting that retry through a replacement pane that never proved ready.
- Route dispatches into an already-running pane must enforce the same fail-closed contract whenever the document already has unresolved prompt-bearing drift on top of a closed cycle. A consumed routed trigger is not enough; route must observe a newer per-document cycle state for that file before returning success, or fail closed instead of silently re-entering the stale pane.
- When the baseline cycle is already `committed`, route/fresh-start acknowledgment must require a genuinely newer cycle id for that document. Same-cycle `commit_already_current` / other committed-state mutations do not count as proof that a new closeout cycle started.
- Template writes and `compact exchange` must keep conversation content inside `agent:exchange`: a safe escaped `## User` / `## Assistant` / `### Re:` tail is repaired automatically before snapshot/write, and the same repair path must also pull prompt-target blocks back inside exchange when they were typed after `<!-- /agent:exchange -->` but before sibling markdown section breaks such as `###` / `## Pending`. Ambiguous mixed trailing structure still fails closed instead of being committed malformed. Comment-only or scratch-note content without escaped conversation headings stays outside `agent:exchange`; ordinary multiline HTML comment bodies (`<!-- ... -->`), including transiently unterminated comment tails while the user is typing, are ignored by escaped-tail scanners and prompt-bearing drift checks even when the comment text looks like a prompt. During final template reconciliation, complete post-exchange HTML comments remain user-owned scratch containers; duplicate or near-duplicate prompt text inside those comments is scrubbed while preserving the shell only when the duplicate line was not already present in the pre-response baseline/snapshot. After that safe scrub, any remaining duplicate prompt residue in freeform post-exchange Markdown outside tracked components is an invalid closeout/route state and must fail closed instead of being silently committed or dispatched.
- Template exchange appends must keep response headings block-separated from the previous response body. When the appended `agent:exchange` content starts with `### Re:`, both boundary replacement and fallback append paths must insert a blank line after non-empty prior exchange content so Markdown renderers never join the new H3 heading to the previous paragraph.
- Template/CRDT closeout must also clean up answered raw prompt-target lines that were typed inside `agent:backlog` / legacy `agent:pending`: after the response is merged into `agent:exchange`, only the newly-added prompt-target lines are removed from the backlog component. Normal tracked backlog additions and backlog/review state changes remain part of the closeout.
- That template-write repair path must also handle duplicated-close failure shapes: if a merged document still contains the real `<!-- agent:exchange ... -->` opener but later hits a second `<!-- /agent:exchange -->` after safe escaped response content, the binary must move that escaped content back inside the real exchange block and drop the stray duplicate close before the final guard/commit boundary. If the text between close markers is only a duplicated template scaffold, that scaffold is dropped. If the duplicated scaffold is mixed with live prompt text, closeout fails closed with a typed `flow::document_mutation` event, and editor-visible normalization also rejects the shape, instead of moving or deduplicating that live text automatically. Ambiguous duplicate-close suffixes still fail closed.
- When the user-added diff explicitly requests `compact exchange`, template/CRDT write-back must force `agent:exchange` replacement semantics for that turn instead of inheriting the component's normal append mode. A compaction checkpoint summary must replace the superseded exchange body, not layer on top of it.
- `agent-doc compact <file> --component exchange --commit` computes against Lazily current state and submits one expected-current canonical intent. An attached document is updated only through its PID-scoped editor endpoint; a detached document may project directly to disk. If the editor-visible and disk projections lag, compact persists the exact live/committed targets as a durable continuation; the controller completes snapshot/commit after the matching authority+disk projection clears the retained write. One plane, a stale or divergent projection, and replay of an already-consumed exact projection cannot commit or duplicate the identity-fenced completion Effect. The initiating command does not poll or request an editor save/ACK. Reposition is the shared `reposition` intent, never a queued file patch. VCS refresh is observational and cannot invalidate an already-durable compact commit.
- Editor refresh and reload work is bounded by the affected document. The typed `refresh_vcs` payload includes its absolute file path; JetBrains dirties that file only and VS Code refreshes only its containing repository, with no workspace-wide VFS/VCS refresh fallback. JetBrains installs one split-tree-filtered AWT layout listener rather than recursively attaching container listeners, discovers nested native endpoints only when a Markdown file from that root is open, and stops inbound native callbacks before disposing CRDT managers. Callback threads must never block indefinitely waiting for an IntelliJ read permit: editor-owned objects are captured on the EDT without blocking the caller, then native/CRDT work continues on pooled executors.
- Reconciliation distinguishes operator edits from remote CRDT application using Lazily operation provenance in the same document lineage. There is no live-buffer digest sidecar and no older-plugin compatibility branch; a plugin lacking the required registration, intent, and receipt capabilities is rejected as incompatible.
- A bare `compact exchange` directive in the current diff must not complete through the normal response write path. `run`, `write`, and `finalize` fail closed with a binary-compaction handoff (`agent-doc compact <file> --commit`) unless the turn is already using that compaction path.
- The direct-exec Codex/OpenCode instruction path must run `agent-doc session-check <file>` after final response persistence (`finalize` or manual `write --commit`) and fail closed when the check reports an open cycle, unresolved prompt-bearing user edits with no newer cycle start, or a likely direct assistant patchback that bypassed the binary write path. The only self-heal exception is already-committed historical snapshot drift proven by `HEAD`. Connected clients use the terminal finalize report instead of invoking this companion command.
- Closeout lifecycle, capture, prompt, and coordination state is read from `state.db`, not optional files. Logs are diagnostic and snapshot/CRDT files are recovery projections; their absence cannot create lifecycle proof. An unavailable ledger fails closed.
- Harness-native `agent-doc` entrypoints (`/agent-doc <FILE>` in Claude Code, `agent-doc <FILE>` in Codex/OpenCode/direct-exec, and equivalent direct entry forms in other harnesses) must be treated as the start of the binary-owned response cycle rather than as a generic document-editing request. A turn started that way must not be reported successful until it crosses `finalize` or `write --commit`, and "not committed" is only valid when the user explicitly asked to leave it uncommitted.
- When `session-check` fails on an uncommitted closeout (`snapshot != HEAD`, committed-cycle exchange drift with a newly appended assistant response marker, or a direct response patchback with no matching cycle), the diagnostic must include any tracked side-effect files and the explicit follow-through command `agent-doc write --commit <FILE>`.
- Session-document closeout owns backlog consistency too: when a response clearly completes an existing `#id` backlog item, the same closeout cycle must record the matching `--done <id>` mutation or fail before commit. The done guard must scan the response body, including `### Re: do [#id]` headings with later completion evidence, but it must exclude ids explicitly kept open by same-cycle backlog mutations such as `--backlog-edit`, `--backlog-gate`, `--backlog-ungate`, `--backlog-reorder`, or gate-type edits. Warn-only post-commit stale-backlog states are not acceptable as the default for real session docs.
- When the active prompt contract requests backlog capture directly or through prompt-preset expansion (for example `#code-review` chaining into `#follow-up-backlog`), the same closeout cycle must either record backlog mutations, explicitly state that there were no actionable follow-up items to capture, or fail before commit. Findings-only review prose must not silently commit against an unchanged backlog.
- The pending-capture heuristic (`heuristics.rs`) must detect unconditional follow-up work — quantified remaining items (e.g., "18 remaining"), outstanding work, unfinished tasks, and unresolved current bugs/issues that the response frames as still needing follow-up — even when the response frames continuation as mutually exclusive options or blocked-with-choices. A single high-confidence unconditional follow-up indicator (confidence >= 0.7) is sufficient to trigger the guard at count=1; the count >= 2 threshold only applies to lower-confidence patterns.
- The Codex install surface writes repo-local `.codex/hooks.json` and `.codex/config.toml`; `UserPromptSubmit` / `Stop` session tracking is stored in each relevant project `state.db`, never mirrored into ambient ancestor roots or filesystem session files. The single installed `UserPromptSubmit` command must durably track the session before running preflight for a valid harness-native `agent-doc <FILE>` invocation, despite injected preambles, and must emit the cycle contract plus its final success marker as Codex turn context. Ordinary prompts emit no context; tracking or preflight failures must not emit the success marker. Latest-prompt lookup skips malformed ledger rows. `Stop` may finish an open cycle only from a validated single-assistant closeout; transcript-shaped or empty tool-only payloads remain diagnostic blockers and cannot count as response completion.
- Non-streaming Codex child runs must persist only the final assistant closeout for the active turn. If `codex exec --json` emits multiple `item.completed` `agent_message` events, `agent-doc` selects the last assistant message before `turn.completed` as the durable response body; if multiple assistant messages arrive without a `turn.completed` boundary, the run fails closed instead of committing progress/status chatter as a transcript-shaped patchback.
- The shared instruction surface must treat MCP auth / OAuth tool flows as sub-steps inside the current `agent-doc` turn. A browser/authenticate step may pause the turn, but it does not satisfy the response boundary; the same turn still must finish through connected `agent_doc_finalize` or, on direct exec, `finalize` / `write --commit` plus `session-check`, or fail closed.
- When that replayable Codex Stop payload contains a safe `patch:backlog` mutation, the backlog normalization must run before the payload is saved to the pending/capture ledger. Recovery must replay only the stripped exchange-safe payload, not the raw backlog patch, so later closeout recovery cannot fail just because the live backlog has interleaved section headers or other preserved non-item structure.
- The atomic CRDT response-cell fast path is valid only when the entire exchange patch parses as canonical assistant-only response nodes. Template-compatible legacy heading depths such as `## Re:` and mixed response/prompt patches must bypass that fast path and continue through compatibility patchback without issuing a controller `response_cell_add`; a deterministic response-cell parser rejection must not wedge a retained `response_captured` cycle into identical recovery retries.
- The instruction surface must also preserve response-ordering: requested implementation / verification / build-install work completes before final response persistence, and once `finalize` / `write --commit` returns, only a required direct-exec distrust check, failure recovery, and final reporting remain for that turn.
- The shared instruction surface must treat imperative user edits inside the document as executable directives for the underlying repo work. That includes explicit command-like lines (`do #id`, `run tests`, `build + install`, `commit + push`) and actionable pending-item prose that begins with an imperative verb (for example `[#n8q4] Fix the cross-repo ...`). For path-scoped `commit + push` work it must also require an explicit fail-closed staging contract: resolve the intended non-session path set, stop on any stage failure, verify the staged diff still matches that set, and commit only that validated set. It must not require the user to repeat those directives in chat, and it must not append "starting/continuing" status prose when the requested work has not actually happened. The binary `run` / `write` / `finalize` path must reject status-only or meta-only replies to those directive diffs unless the response contains either concrete execution evidence or a concrete blocker.
- The project controller surface owns route/start/sync authority. `agent-doc controller status --ensure` lazily launches one project-local controller through `.agent-doc/controller.sock`, guarded by `.agent-doc/locks/controller-launch.lock`. Bootstrap epoch, launch mode, generation, handoff state, prior PID, and binary identity live transactionally in the `.agent-doc/state.db` `controller_bootstrap` row; there is no controller-state compatibility file. Controller launch skips a stale removed executable and falls back to the invoked command or `agent-doc` on `PATH`. RPC reads are bounded, an idle client cannot block unrelated clients, and stale-binary replacement promotes a private-socket generation before reaping verified same-project duplicates. Start, route, sync, and controller-backed admin operations use typed generation-CAS requests and receipts. Queue pause/drain and backpressure are durable SQLite state; explicit operator reopen bypasses a deliberate auto-drain pause once, while stale-supervisor churn-stop still forces recovery first.
- A quiescent supervisor must not replay the full idle reconciliation pipeline on every 500 ms watch tick. Once queue state has been observed and the actor is ready, the tick retains only local installed-binary and historical-zombie liveness probes; pane inspection, full CRDT text/controller reads, and stable blocked-head retries are throttled to a five-second liveness pass. Busy work, in-flight clear settling, and installed-binary staleness bypass the throttle immediately. A stale supervisor must `execve` onto the installed binary at the first checkpoint with no supervisor IPC receipt handler in flight, regardless of harness turn/prompt stage or an open durable agent-doc cycle; the live harness child and cycle checkpoint survive the exec.
- A detached controller is scoped to the exact project-root directory incarnation that requested it. On Unix, startup retains an open handle to the original directory until its final incarnation check so deletion cannot make that inode immediately reusable by a same-path replacement. If the directory disappears or is replaced between spawn, bootstrap creation, and socket publication, startup fails closed and removes its socket instead of recreating a deleted temporary root. Supervisors that survive an in-place `execve` must also reap already-exited historical `agent-doc` controller children without consuming the live harness child's exit status.
- The project controller actor store writes `.agent-doc/state.db` as the sole persistence boundary. The `documents`, `actor_transitions`, and registry tables carry session actor and pane-binding state; no actor or registry JSON projection participates in runtime resolution. Sync column memory lives only in `layout_states` rows; there is no legacy layout import or compatibility file projection.
- The project controller Phase C supervisor path is controller-owned: `agent-doc start` must lazy-launch/connect to the project controller, register the starting actor generation and supervisor lease, and report prompt-ready, busy dispatch, waiting-input, blocked, and closed lifecycle facts through controller IPC. Lifecycle reports include session id, pane id, and generation; stale reports fail closed before mutating the authoritative actor record. When `session_id` and `pane_id` both match the current actor record, a stale `expected_generation` is allowed through: the generation bump was from a same-owner rebinding (compact/restart/route), and the transition proceeds using the current generation rather than rejecting the legitimate owner. Supervisor state probes include the actor session id, pane id, and generation so `session status` / `doctor` can refresh the controller lease heartbeat and `runtime_state` from a live matching supervisor without adding a duplicate actor transition. Route readiness waits for a `starting` authoritative actor must stop immediately when the supervisor refreshes that actor to `closed` or `blocked`; those terminal states are the actionable diagnostic and must not be reported as a startup-ready timeout.
- `agent-doc session status <FILE>` must include direct live-pane evidence beside projected actor/controller state: pane id, evidence source, pane current command, recent meaningful output tail, and an `alive-idle` / `alive-busy` / `closed-clean` / `projection-stale` classification. If direct evidence is `alive-idle` while actor, supervisor, or controller lease projection still says `busy`, the session operator path reconciles the actor/lease back to `ready` before printing status or clearing. For Codex operator status/clear, direct evidence that contains only Codex status/footer chrome, such as the model/cwd/context line, and no prompt input or busy cue is `alive-idle`; a bottom Codex model/cwd/context footer is also idle evidence even when older visible transcript text remains above it, as long as there is no protected composer state or busy cue. Codex idle placeholder prompts such as `› Ask Codex to do anything`, `› Explain this codebase`, and safe generated placeholders ending in `in @filename`, `for @filename`, or `on my current changes` are also prompt-ready evidence when the pane does not show an active `Working (... esc to interrupt)` cue. Dynamic Codex composer suggestions rendered with SGR-2 are likewise idle placeholders even when their text is not in the static phrase list, so supervisor readiness and auto-trigger verification must preserve ANSI until classification; the same undecorated text remains protected drafted input. Route dispatch still requires a real dispatch-ready prompt before injecting a reopen; a Codex footer alone never proves dispatch readiness. File-scoped `session restart-supervisor <FILE>` must fail closed when direct pane evidence is `alive-busy` or when the actor is still `starting` and the document changed after the last committed cycle; those refusals must point operators to `--force`. File-scoped `session restart-supervisor <FILE> --force` is the explicit discard path and may interrupt a busy live pane or bypass the starting-actor guard before requesting the supervisor restart. File-scoped `session clear <FILE>` is an explicit operator clear request and must not run the starting-actor readiness guard: it must not fail solely because a pane is classified `alive-busy`, because `pane_current_command` is an agent wrapper such as `agent-doc`, because the actor projection still says `starting`, or because the document has prompt-only drift after the last committed cycle. Clear may refuse protected prompt-input states such as a permission prompt, queued draft, shell search, drafted user input, or clean-exit restart prompt, and may block explicit busy cues such as an active Codex turn, hook-review prompt, or help/usage screen; those refusals must point operators to `agent-doc session interrupt-clear <FILE>` for the explicit discard path. Codex placeholder text rendered dim by the TUI is idle chrome, not drafted user input, even when the plain text is not in the built-in placeholder phrase allow-list. If `session interrupt-clear` times out after that explicit discard path, its ops event and user-facing error must report the final blocking live-pane state, evidence source, prompt-ready value, current command, and recent pane tail instead of collapsing to a generic timeout.
- The project controller Phase D route path is controller-owned: before route submits a managed or dispatch-only reopen to an actor-owned pane, it must record a controller `dispatch` attempt for the current session id, pane id, generation, and command kind. Stale session, pane, or generation requests fail closed before tmux/supervisor input is submitted. A `starting` actor is not dispatchable until it refreshes to `ready`; route may promote a healthy starting actor to `ready` only after the current generation's live pane shows a harness-specific dispatch-ready prompt, and if it remains `starting` after the bounded route wait, route must fail closed before tmux or supervisor input is submitted. If the same pane/generation later shows dispatch-ready prompt proof after route has marked it blocked for `starting_actor_timeout`, route may clear that timeout and promote the actor to `ready` before submitting. Startup wait failures must persist a single typed diagnostic with elapsed time, pane id, generation, actor state, supervisor health/runtime state, prompt-ready status, and last lifecycle transition so the editor route error points at the exact failed phase. The current-generation ready-prompt barrier must also accept an `idle_pane_reconcile` transition as ready proof (`#monster60stimeout`): the supervisor's idle-watch only records that reason after `supervisor_pane_has_busy_cue` returns `Some(false)` (direct pane evidence that the pane is not busy), so the route must not wait the full 60s timeout when the edge-triggered pty redraw missed re-emitting a recognized prompt shape but the supervisor already proved the pane idle.
- When a document explicitly changes `agent:` to another harness, a healthy authoritative actor record for the old harness must not hard-fail future `Run Agent Doc` routes with "bound to harness X, not Y" (`#actor-switch-rebind`, `#harnesshotrebind`). Route treats that explicit frontmatter change as a typed boundary handoff: it accepts the operator request without dispatching any prompt bytes into the old harness, preserves an active old-harness turn, and lets the supervisor idle watch spawn the newly resolved harness at the first safe `prompt_visible && !turn_active` boundary and auto-trigger the owning document exactly once. Repeated routes coalesce with an in-flight handoff. A paused queue holds the accepted handoff until queue resume and must not require a supervisor restart. The supervisor IPC `state` payload reports `current_harness`; when the live runtime has already switched but the actor record is stale, route repairs that record and proceeds instead of starting another handoff. For an old-harness actor that is **not a live authority** (closed/blocked, or its pane is no longer dispatch-ready), route falls back to the normal create/rebind path. A healthy live authority is never cold-replaced (`mismatched_authoritative_actor_can_be_replaced` remains false), and `agent_change_restart: false` remains an explicit fail-closed policy. Without an explicit document harness change, a healthy ready actor from another harness also remains fail-closed.
- Resumed agent prompts must restate the changed exchange tail as ordered user-authored prompt-bearing changes. The canonical subtypes are `prompt_target`, `content_edit`, `recovery_artifact`, and `boundary_artifact`. The turn-completeness contract is oldest-first: do not anchor only on the newest question, do not treat the turn as complete until each `prompt_target` item is answered or explicitly grouped into one response, and treat `content_edit` items as source-of-truth corrections while artifact items route to normalization/repair instead of ordinary conversation.
- Prompt-cache replay metadata is part of direct-run prompt assembly. Only durable response contracts, harness-neutral instructions, turn-payload reading rules, cache-control metadata, and provider replay-key material may live above the cache boundary. File paths, queue heads, diffs, current document excerpts, status text, prompt-bearing change sections, compaction/accretion diagnostics, bounded context packs, session ids, and recovery markers must stay in the volatile suffix after the boundary. The provider cache key must include the agent-doc key version, routing-affinity hash, and stable-prefix SHA-256; the volatile suffix must never contribute to that key. The stable prefix SHA-256, provider cache key, cache-control policy, and routing affinity must remain identical across consecutive resumed agent-doc turns whose changes are only volatile session churn such as no-op closeout diagnostics, status edits, queue-head/list churn, boundary markers, diffs, or bounded context packs. Durable response-contract/instruction changes must change the stable-prefix fingerprint and provider cache key, even when the routing affinity is held constant.
- Prompt-cache session-cost diagnostics must make cache misses explainable without raw JSON analysis. Given two cost samples, miss ranking compares stable-prefix fingerprint, adapter state, routing affinity, cached-input token delta, and creation-token spike, then reports ranked causes with the highest-impact invalidation cause first. When no prior sample is available, the diagnostic must still print the current fingerprint, adapter state, routing affinity, unknown token deltas, and an explicit `baseline_required` rank state so later history persistence can feed the same ranking path. The token/performance gate persists prompt-cache effectiveness samples as JSONL records keyed by provider, harness, and real transcript id (for example Codex/OpenAI and Claude/Anthropic transcripts). Trend checks must compare the current sample with the latest matching workload history and fail with an operator-readable summary that includes provider, harness, transcript id, previous observation time, cached-input delta, creation-token spike, thresholds, and the same ranked miss causes used by the session-cost diagnostic.
- Prompt-prefix preservation is part of that same contract: append-mode exchange canonicalization must derive required `❯ ` transcript prefixes from the prompt-bearing classifier (not a separate ad hoc heuristic). That invariant still applies when `repair` dedups an already-present template response: `AlreadyApplied` is a canonicalization-capable outcome, not proof that transcript normalization can be skipped. Prefix repair must remain structurally scoped to prompt runs: once a `### Re:` / `❯ ### Re:` / `## Assistant` response block starts, assistant prose and verification/list bullets must not become `❯ ` targets merely because their trimmed text matches a `normalize_prefix_lines` entry; targeted repair may leave the response block only when the line matches the explicit target set and also starts a prompt run, or when a boundary/component marker has already closed the response. `session-check` must fail closed when a bypassed response leaves bare prompt-target lines in the changed exchange tail, and when prompt-bearing user edits exist without any newer cycle start at all.
- The prompt-bearing classifier itself must suppress stale-boundary prompt runs that are already visibly answered by a later response in the same changed tail, including raw assistant completion prose without a formal `### Re:` heading. `preflight`, `plan`, routed admission projection gating, prompt-prefix normalization, and write-path snapshot decisions must all consume that same filtered actionable list instead of re-deriving their own stale-tail heuristics.
- Unstarted exchange-prompt detection must not be snapshot-gated on a fresh session (`#codex-exchange-prompt-no-dispatch`). The queue path activates independently of any cycle snapshot, so a queue write dispatches `Run Agent Doc` even before the first snapshot exists; the exchange path keys off the snapshot↔file diff. When no snapshot exists yet, `first_unstarted_prompt_bearing_change` must fall back to the committed `HEAD` blob (then to an empty baseline for untracked docs) so a freshly typed exchange tail prompt is still detected and routed, instead of leaving exchange writes inert while the same text in `agent:queue` starts a turn. The HEAD fallback stays exchange-scoped — queue components remain stripped from this diff and keep their own activation path.
- Component/comment parsing must never panic on valid UTF-8 document content. Ordinary HTML comments near multibyte glyphs such as `❯` must either parse normally or be ignored as prose; malformed agent markers still surface as structured parse errors instead of byte-boundary crashes.
- The state backbone is the Cycle State Machine plus typed event-sourced projections, not one global FSM for every subsystem. The cycle FSM owns only turn closeout phases. Queue, document, transport, supervisor, route, and proof state must be represented as typed append-only facts reduced into deterministic projections, with live mutation guarded by owner actors, epochs, and leases. Local FSMs are allowed for small closed subdomains, coroutines may express linear protocols, and behavior-tree-style logic may be used only as policy over projections; GOAP/MPC-style planning is not the durable state model for correctness-critical closeout.
- FlowCore is the typed ownership layer for the direct session cycle, routed reopen, closeout, document mutation, operator clear, and orchestration batch hot paths. The first phase is mirror-mode: existing commands still execute behavior, but high-risk branches emit `flow_event` ops lines with `flow`, `stage`, `outcome`, and tokenized `reason`, and `agent-doc ops summary` groups failures by flow stage. The same summary must also emit ranked bug clusters that correlate closeout/captured-response drift, route/start replay gaps, Codex warning storms, SQLite counts, cross-harness markers, session-review guardrails, and working-tree drift by file/session/cycle/thread keys. Closeout/document-mutation guard reasons, including pre-write/pre-commit pending capture blocks, patchback parse shapes, repair recovery boundaries, committed-cycle late fallback rejection, and disabled full-content decisions, must use FlowCore enums or document-mutation decision helpers instead of adding more free-form proof strings. New tactical fixes in these hot paths should prefer FlowCore enums and pure decision helpers over adding more free-form proof strings.
- The FlowCore regression gate must remain executable, not only documented. Routed-reopen prompt-ready and dispatch-start failure reasons are represented by `RoutedReopenGuardReason`, and the hot-path source-token budget test must fail when route/write/preflight/session-check/orchestrate/git/repair add unaudited `guard_`, `proof=`, `proof_scope=`, `reason=`, `flow_reason=`, or `accepted_only` tokens. A failing budget is resolved by promoting the new branch into the owning FlowCore enum/event or by updating the budget with the FlowCore audit complete.
- Agent harnesses, not git hooks, own full-suite verification after changes. The shared instruction surface must require explicit full-project verification before final response persistence whenever code, tests, build logic, or instruction surfaces changed.
- Test-bearing harness turns must review the live tmux CI leg with `gh run list --workflow CI --limit 1`. The expected local reproduction command is `make tmux-ci` when the CI leg fails after runner startup; any failure fix should include deterministic SimWorld coverage for the regression class when feasible, so the default suite can catch modeled failures before relying on live tmux. Queued or in-progress CI runs are recorded but do not block turn closeout unless the user explicitly asks the agent to wait. Empty-step Actions jobs with no logs because GitHub never allocated a runner, such as billing/spending-limit exhaustion, are external CI-start blockers rather than tmux/code regressions; closeout should record the CI annotation and the local verification evidence.
- A failing full-suite verification run must not be waived off as "unrelated" or "flaky". If the suite is red, the turn must either fix the failing tests or report a concrete blocker and capture the follow-up work in backlog before closeout.
- `make test` should use a parallel test runner when available. `cargo-nextest` is preferred because it runs test binaries concurrently while preserving Cargo's integration-test environment, with a doctest pass afterward. Plain `cargo test --all-targets` remains the fallback when the parallel runner is unavailable.
- `CycleContext`/`ActorContext` are the lazily-backed read cache boundary for per-run global configuration and transactional document/project registry snapshots. Long-lived actors must explicitly invalidate those slots on controller events. Read-only route/sync/resync/gc lookups may reuse those snapshots for a single logical operation, but every registry read-modify-write path must still execute through the state-store transaction boundary.
- Harness-specific launch controls are explicit: `agent_args` is generic, `claude_args` applies only to Claude, `codex_args` applies only to Codex, `opencode_args` applies only to OpenCode, and `codex_network_access` controls whether agent-doc preserves, removes, or forces `CODEX_SANDBOX_NETWORK_DISABLED` for Codex child sessions. `claude_model: opus`, `/model opus`, and the built-in Claude Code high tier are deferred to Claude Code: agent-doc emits `--model opus` so Claude Code resolves its current latest opus, and attribution is self-stamped by the running agent instead of a pinned version (agent-doc stores no concrete opus version, so launch and attribution can never lag a release). Explicit non-alias model ids (e.g. `claude-opus-4-8`) pass through unchanged. `opencode_model` / `opencode_args` allow managed OpenCode panes to launch as `opencode --model <provider/model>` with OpenCode-specific flags, while direct `agent-doc run --agent opencode` uses `opencode run`. Managed Codex capability proof is off unless document frontmatter sets `managed_proof: true`. When opted in, `codex_network_access: enabled` must prove host DNS plus a bounded `codex exec --json` child DNS/HTTPS command under the same launch args before route may trust the pane as network-capable; managed OpenCode startup uses a bounded `opencode run --format json` child probe for network checks. Opted-in Codex proof children use `--ephemeral`, `--ignore-rules`, and low reasoning effort, and combine network plus writable-root checks in one child when both are required. Managed OpenCode startup also records `opencode_capability_proof` for documents with `required_ssh_targets`, and that proof must run an isolated SSH check inside the OpenCode child before auto-trigger, supervisor injection, managed route, or dispatch-only route may submit prompt work. Successful proof events must include per-phase `timings_ms` for network, SSH, writable-root, and total proof time. Successful and failed managed proof summaries must be surfaced as tmux status messages through `display-message` on the owned pane, not written into the child pane transcript; the full proof event remains in the session log. For OpenCode, an otherwise chrome-only `context ... % used` status footer counts as an idle composer even when no standalone `>` prompt line is captured after proof completion. When Codex writable roots are required, successful proof events must also include a normalized `writable_root_contract` fingerprint, and route/session-status may treat a Codex proof as current only when that fingerprint matches the active document's resolved `--add-dir` set after the latest `session_start`. When a Claude/Codex document lives in a submodule, harness launches must also auto-add any writable roots outside the submodule that the session lifecycle may need: the superproject working tree for parent-repo document patchbacks plus the external git metadata directories (`.git/modules/...` for the submodule and the superproject `.git` for pointer updates). If a resumed Codex `exec resume <id>` turn reports the local-browser/CDP EPERM signature (`Operation not permitted` on `127.0.0.1:9222` / `localhost:9222`), agent-doc must treat that as stale resumed-session capability drift, retry once with a fresh `codex exec`, and let the successful fresh thread replace the saved `resume` id instead of trusting the poisoned resume state again. Because `codex exec resume` cannot accept new `--add-dir` roots, a direct resumed Codex backend turn whose current launch args require writable roots must fresh-start with the full root set instead of attempting resume. Required SSH metadata may come from document frontmatter (`required_ssh_targets` or `required_ssh_profile`) or from project-local `.agent-doc/config.toml` mappings for known ops docs. If a configured SSH-dependent document cannot resolve any targets, preflight/startup must fail closed before launch. Those pre-launch SSH capability probes must run in isolated mode (`ControlMaster=no`, `ControlPath=none`, `ClearAllForwardings=yes`, `PermitLocalCommand=no`) so they cannot create or reuse shared SSH multiplexing state that would affect later operator shells. When a document resolves required SSH targets, that same resumed-session recovery must also treat bare `socket: Operation not permitted` command output as required-SSH capability drift when the `command_execution` event proves SSH command context for one of the required targets, while still excluding the localhost/CDP drift family and historical capture/log grep output from the SSH path. For resumed required-SSH streaming turns, early assistant chunks from the resumed session must stay buffered until required SSH is proven safe or the turn completes successfully, so a fresh retry can discard stale prelude text instead of leaking it into the final response. A transient capability-proof failure must not permanently disable the session: the proof retries with bounded exponential back-off (configurable via `managed_proof_max_attempts`, `managed_proof_retry_backoff_secs`, and `managed_proof_probe_timeout_secs` in frontmatter or `.agent-doc/config.toml`; defaults 3 / 2s / 45s), keeping the gate `Pending` between attempts and only committing to `Failed` after the budget is exhausted. Operator recovery is gate-exempt: only real prompt dispatch (`Inject`, auto-trigger, auto-queue) is gated, while the supervisor control methods (`Clear`, `Stop`, `Restart`) and read-only methods (`State`, `Pid`) bypass the gate, so `agent-doc session clear` / `session interrupt-clear` can stop or clear a proof-`Failed` session without `kill -9` (`#codex-capability-proof-unrecoverable`).
- `### Re:` response headers must use the resolved model short name for attribution (for example `gpt-5`, `opus-4-7`), never the harness label (`codex`, `claude`).
- Bundled skill/install content is part of the external contract: Claude/Codex/OpenCode hot-path instructions must render from one shared source surface, with differences limited to harness-specific invocation wording and frontmatter description. Harness installs must write trigger-scoped managed skill files (`.claude/skills/agent-doc/SKILL.md`, `.codex/skills/agent-doc/SKILL.md`, `.opencode/skills/agent-doc/SKILL.md`) and must retire old generated root `AGENTS.md` / `.codex/AGENTS.md` copies instead of refreshing them as always-on mirrors. `audit-docs` must fail generated managed skill surfaces that carry agent-doc managed frontmatter but no longer match the running binary, and must fail retired generated `AGENTS.md` surfaces until `agent-doc skill install` migrates them away. `audit-docs` must also compare every installed runbook bundle to the running binary: a stale runbook, a missing runbook, unbundled Markdown in a managed harness runbook directory, a surviving retired `.codex/runbooks/` mirror, and drift in a directory listed under `skill_runbook_mirrors` are all release-blocking. `make check` runs `audit-docs`, because the release process runs `make check` and an audit only reachable from `precommit` cannot gate a release. Without an explicit `--root`, submodule-local audits check both the git superproject install root used by normal release installs and the submodule checkout itself — `skill install` resolves to the superproject, so submodule-local copies are otherwise touched only by `release-version` and never content-checked; explicit `--root DIR` checks generated surfaces under `DIR` exactly. `release-version` projects the version into bundled skill *sources* only; installed copies are the installer's output, refreshed by `skill install` (`--root DIR` targets an explicit root). Custom root instruction files that do not look agent-doc-managed remain user-owned. Filesystem mtime freshness is advisory for agent-doc audits; source-only timestamp changes may be reported, but generated instruction surfaces are release-blocking only when the rendered content differs. The shared Claude/Codex/OpenCode manual-repair instructions must distinguish adding a missing user prompt from repairing a missed assistant response, use `agent-doc write --commit <file>` for the missed-response path, and not stop after bare `agent-doc write`. The repo-local Codex plugin manifest must stay schema-valid: it must not point `skills` at Claude install paths such as `.claude/skills`; if it exposes Codex skills, the manifest path must resolve to a real plugin-root `./skills/` tree.
- The optional `skill-harness` integration is owned by the focused `agent-doc-skill-harness` crate, never by `agent-doc-core` or by `skill-harness` itself. Its `AgentDocSkillHarnessPlugin` detects the supervised `AGENT_DOC_SESSION` marker at priority 100, resolves `<name>` to `.agent-doc/plugins/<name>/SKILL.md`, and is installed into a consumer registry through `register_agent_doc_plugin` (or `registry_with_agent_doc`). This path is distinct from Agent Doc's own harness bootstrap skill paths.
- Reusable authoring runbooks and OKF concept bundles shipped by `skill install` are part of that same contract. If `runbooks/split-spec-files.md` or `okf/index.md` is referenced from the shared instruction surfaces, it must be bundled into installed harness resources and its ownership rule must stay harness-agnostic across agent-doc-managed surfaces while leaving custom root instruction files opt-in unless they still match the generated baseline.
- Route readiness/trigger acceptance is a binary responsibility: pane prompt detection must be robust to shell startup noise and must wait for actual prompt state rather than treating echoed command text as readiness.
- Route progress/status diagnostics must also be binary-safe: when `route.rs` trims captured tmux lines for stderr/status output, it must preserve UTF-8 char boundaries so multibyte glyphs in prompt/status lines cannot panic the reroute path.
- Route trigger commands must use absolute file paths (resolved against the invoker's CWD) to prevent submodule CWD-dependent misrouting. That invariant applies to every routed reopen attempt, including post-restart retries after an admission projection stays unchanged; once route has resolved the canonical path, later retries must not fall back to `file.display()` or other caller-relative renderings. When a tmux pane's CWD is narrowed to a submodule root and the same relative path exists in both the main repo and the submodule, a relative path would resolve to the wrong file.

| # | File | Description |
|---|------|-------------|
| 1 | [Overview](specs/01-overview.md) | What agent-doc does and how sessions work |
| 2 | [Document Format](specs/02-document-format.md) | Frontmatter fields, components, and template structure |
| 3 | [Snapshot System](specs/03-snapshot-system.md) | Snapshot storage, lifecycle, and diff baseline |
| 4 | [Diff Computation](specs/04-diff-computation.md) | Line-level unified diff and comment stripping |
| 5 | [Agent Backend](specs/05-agent-backend.md) | Agent trait, resolution order, Claude backend |
| 6 | [Config](specs/06-config.md) | Global/project config, IPC, document state model |
| 7 | [Commands](specs/07-commands.md) | Command-spec index with split sibling specs for core, tmux/session, closeout, and orchestration behavior |
| 8 | [Session Routing](specs/08-session-routing.md) | Registry, claim semantics, stash routing, binding invariant |
| 9 | [Git Integration](specs/09-git-integration.md) | Commit/branch/squash and hook system |
| 10 | [Security](specs/10-security.md) | Threat model, known risks, recommendations |
| 11 | [Debounce](specs/11-debounce.md) | Debounce system gaps, limitations, and improvements |
| 12 | [Deterministic Simulation Testing](specs/12-deterministic-simulation.md) | Fast seeded workflow simulation for closeout edge cases |
| 13 | [State Backbone](specs/13-state-backbone.md) | Cycle FSM boundary, typed event ledger, projections, and actor ownership |
| 14 | [Real-Time Workflow Authority](specs/14-realtime-workflow.md) | Operator-first source-of-truth and live mutation invariants |
| 15 | [Turn Lifecycle Authority](specs/15-turn-lifecycle.md) | Turn/closeout state machine, realtime handoff, and commit ownership |
| 16 | [Codex Support](specs/codex-support.md) | Harness-specific differences for Codex vs Claude Code |

Command sub-specs:
- [Core Commands](specs/07-core-commands.md)
- [Session And Tmux Commands](specs/07-session-tmux-commands.md)
- [Closeout Commands](specs/07-closeout-commands.md)
- [Orchestration Commands](specs/07-orchestration-commands.md)

Session-routing supplements:
- [Session Actor Contract](specs/08a-session-actor-contract.md)
- [Single Process Control Plane Contract](specs/08b-single-process-control-plane.md)
