paperclip/doc/execution-semantics.md

101 KiB
Raw Permalink Blame History

Execution Semantics

Status: Current implementation guide Date: 2026-08-18 Audience: Product and engineering

This document explains how Paperclip interprets issue assignment, issue status, execution runs, wakeups, parent/sub-issue structure, and blocker relationships.

doc/SPEC-implementation.md remains the V1 contract. This document is the detailed execution model behind that contract.

1. Core Model

Paperclip separates four concepts that are easy to blur together:

  1. structure: parent/sub-issue relationships
  2. dependency: blocker relationships
  3. ownership: who is responsible for the issue now
  4. execution: whether the control plane currently has a live path to move the issue forward

The system works best when those are kept separate.

2. Assignee Semantics

An issue has at most one assignee.

  • assigneeAgentId means the issue is owned by an agent
  • assigneeUserId means the issue is owned by a human board user
  • both cannot be set at the same time

This is a hard invariant. Paperclip is single-assignee by design.

3. Status Semantics

Paperclip issue statuses are not just UI labels. They imply different expectations about ownership and execution.

backlog

The issue is not ready for active work.

  • no execution expectation
  • no pickup expectation
  • safe resting state for future work

todo

The issue is actionable but not actively claimed.

  • it may be assigned or unassigned
  • no checkout/execution lock is required yet
  • for agent-assigned work, Paperclip may still need a wake path to ensure the assignee actually sees it

in_progress

The issue is actively owned work.

  • requires an assignee
  • for agent-owned issues, this is a strict execution-backed state
  • for user-owned issues, this is a human ownership state and is not backed by heartbeat execution

For agent-owned issues, in_progress should not be allowed to become a silent dead state.

blocked

The issue cannot proceed until something external changes.

This is the right state for:

  • waiting on another issue
  • waiting on a human decision
  • waiting on an external dependency or system when Paperclip does not own a scheduled re-check
  • work that automatic recovery could not safely continue

Entering blocked requires a routable waiting path. An issue may transition into blocked only with at least one of:

  • first-class blockers (blockedByIssueIds)
  • a pending issue-thread interaction or linked approval that names the responder
  • a structured unblock descriptor naming {owner, action}, where owner is an agent id, user id, or the board, and action is the concrete step that unblocks the issue

When a structured unblock descriptor is the waiting path, Paperclip immediately notifies the named owner: an agent owner gets a wake, a user or board owner gets an inbox notification. Prose-only blocked — free-text that names an owner or action in a comment without any of the paths above — routes to nobody. It is rejected at the API or auto-classified as needs_attention with a board notification, never silently accepted as a healthy waiting state.

A permission denial is not, by itself, a blocker. If an instructed step is denied at an authorization boundary but the issue's own deliverable is complete, the right disposition is done, not blocked (see the review-delegation rules in §6).

This requirement is prospective-only on rollout: it applies to transitions into blocked made after the feature ships, gated on the blocked-transition timestamp against the rollout marker, not on issue createdAt. Issues already blocked at upgrade time are untouched — no backfilled notifications, no retroactive validation, no needs_attention storm on deploy. Triage of pre-existing prose-blocked issues is a one-time opt-in digest, not a default.

in_review

Execution work is paused because the next move belongs to a reviewer or approver, not the current executor.

An external review service can also be a valid review path when the issue keeps an agent assignee and has an active one-shot monitor that will wake that assignee to check the service later.

done

The work is complete and terminal.

cancelled

The work will not continue and is terminal.

4. Agent-Owned vs User-Owned Execution

The execution model differs depending on assignee type.

Agent-owned issues

Agent-owned issues are part of the control plane's execution loop.

  • Paperclip can wake the assignee
  • Paperclip can track runs linked to the issue
  • Paperclip can recover some lost execution state after crashes/restarts

User-owned issues

User-owned issues are not executed by the heartbeat scheduler.

  • Paperclip can track the ownership and status
  • Paperclip cannot rely on heartbeat/run semantics to keep them moving
  • stranded-work reconciliation does not apply to them

This is why in_progress can be strict for agents without forcing the same runtime rules onto human-held work.

5. Checkout and Active Execution

Checkout is the bridge from issue ownership to active agent execution.

  • checkout is required to move an issue into agent-owned in_progress
  • checkoutRunId represents issue-ownership lock for the current agent run
  • executionRunId represents the currently active execution path for the issue

These are related but not identical:

  • checkoutRunId answers who currently owns execution rights for the issue
  • executionRunId answers which run is actually live right now

Paperclip already clears stale execution locks and can adopt some stale checkout locks when the original run is gone.

The active-lock lifecycle is part of the checkout contract:

  • a run owns checkoutRunId only while that run is non-terminal
  • when a run reaches succeeded, failed, cancelled, or timed_out, finalization must compare-and-clear lock columns that still point at that run
  • finalization must not clear a lock already reacquired by a successor run
  • process-loss retry handoff must not leave checkoutRunId pinned to the failed run when executionRunId moves to the retry run
  • checkout and checkout-owner checks may self-heal lock columns that point at terminal or missing runs before evaluating conflicts
  • the recovery sweeper may clear rows whose checkout and execution locks all point at terminal or missing runs

Stale-lock recovery is crash recovery, not a retry loop. Paperclip must not clear or adopt locks held by non-terminal runs. After stale cleanup, a checkout 409 should mean a real live owner, status/assignee mismatch, unresolved blocker, or active gate still prevents checkout. Agents must treat that 409 as an ownership conflict and stop rather than retrying the same checkout.

Known execution waits at admission

A known execution hold is a waiting condition, not a new execution attempt. Every issue wake must read the current effective reconciliation hold under the issue admission lock before creating a run. Resolved recovery bookkeeping can still carry a no-replay hold; only clearing the effective hold makes admission eligible again. The final dispatch gate remains required for changes after admission.

Repeated automatic signals for an unchanged gate share one durable skipped-wake diagnostic, scoped to company, agent, issue, gate code, and condition identity. The diagnostic retains the first request and counts later observations. This applies to execution reconciliation, dependencies, pause holds, company and agent availability, budget blocks, and disabled heartbeats. These diagnostics do not consume provider attempts and are never proof that a future wake was delivered. All current gates are checked again on the next wake, including the periodic dependency reconciliation sweep. Clearing one gate does not bypass another.

New comments received during an execution hold retain their individual deferred receipts and ordered comment ids. Release cannot drain those receipts while replay remains blocked; the next eligible wake can adopt them. Authorized external-chat requests also remain deferred with their exact durable receipt. They must use normal promotion and current authorization; a generic wake cannot adopt only their comment ids and discard their actor or session contract. A wait does not authorize replay, reset an incident retry budget, or bypass an interaction's delivery rules.

The conversation groups repeated empty pre-start reconciliation cancellations into a neutral waiting notice. Started runs, actual startup failures, and run history remain inspectable. No historical run records are deleted.

Workspace contention (workspace_busy) displays Waiting for workspace and continues automatically when the workspace is available. Internal scheduling attempts remain in the run log without conversation cancellation markers, cancellation toasts, or manual Retry controls. Users can keep sending instructions.

The legacy remote ACP process-session relay runs on the control-plane host. Its launch command uses the host's absolute Node executable even when the adapter's launch environment is sanitized for a remote sandbox; the sandbox PATH remains owned by the sandbox image.

Pre-dispatch configuration validation

Pre-dispatch configuration validation is a distinct gate that runs after ownership and checkout are resolved but before the control plane actually dispatches a run.

Before a run is dispatched, required secret/env bindings are validated; missing bindings produce a surfaced configuration-incomplete blocker, not a dispatched run.

A configuration-incomplete result is a gate outcome, not a runtime failure. It is one of the active gates that a checkout-time or dispatch-time check can surface instead of starting a run, and it leaves the issue in an explicit waiting state that names the missing binding. Surfacing the blocker keeps the issue healthy under the liveness contract while preventing a run that is guaranteed to fail once it cannot resolve its required secret/env bindings. A dispatched-then-failed run is the wrong shape for missing configuration: the missing binding is a known pre-dispatch condition, so the control plane must surface it as a configuration-incomplete blocker rather than letting the run start and then fail.

An unresolved workspace base ref is another configuration-incomplete condition. A git_worktree workspace bases a fresh worktree on a configured base ref. Paperclip first fetches a remote-only ref before dispatch: it maps an unqualified name (for example fix/foo) or a remote-tracking name (for example origin/fix/foo) to origin/<branch>, runs the authenticated fetch, and re-checks the commit. A ref that resolves lets work continue on the resolved commit. A ref that is still unresolvable after the fetch produces a configuration-incomplete blocker that names the requested ref, rather than a dispatched-then-failed run. Because the adapter never started, Paperclip queues no missing-comment retry. The recovery action dedupes by the canonical remote ref (origin/<branch>), not the operator spelling. Two equivalent spellings of one remote branch, for example fix/foo and origin/fix/foo, share one recovery identity, so a repeated failure reuses the active action and does not reset the attempt count or post a second notice. A different remote branch is a distinct blocker. Paperclip resolves the prior recovery action, creates a new action for the new ref, and notifies the operator with the new ref instead of overwriting the active action of the prior ref.

6. Parent/Sub-Issue vs Blockers

Paperclip uses two different relationships for different jobs.

Parent/Sub-Issue (parentId)

This is structural.

Use it for:

  • work breakdown
  • rollup context
  • explaining why a child issue exists
  • waking the parent assignee when all direct children become terminal

Do not treat parentId as execution dependency by itself.

Blockers (blockedByIssueIds)

This is dependency semantics.

Use it for:

  • "this issue cannot continue until that issue changes state"
  • explicit waiting relationships
  • automatic wakeups when all blockers resolve

Blocked issues should stay idle while blockers remain unresolved. Paperclip should not create a queued heartbeat run for that issue until the final blocker is done and the issue_blockers_resolved wake can start real work.

cancelled is terminal for the blocker issue itself, but it does not satisfy the dependency. A cancelled blocker edge remains unresolved until the edge is removed or replaced, and Paperclip must surface blocker attention on the dependent regardless of whether that dependent is currently displayed as blocked, todo, backlog, or another non-terminal agent-owned status.

If a parent is truly waiting on a child, model that with blockers. Do not rely on the parent/child relationship alone.

Child→Parent Reporting

Run-scoped write authorization is subtree-scoped: a run may mutate its checked-out issue and that issue's descendants. Delegated child work still has to report upward, so the platform provides exactly three canonical report channels. Nothing else crosses the boundary.

  1. Completion signal (always on). When a child that blocks its parent reaches done, the issue_blockers_resolved wake engages the parent's assignee, who can read the child thread. Completion needs no report comment: the child's own thread is the deliverable record, and relaying done as prose would duplicate the first-class wake.
  2. Direct-parent report comment (trust-gated). The write boundary widens exactly one hop upward: a run checked out on a child issue may POST comments on the child's direct parent — comments only (no status, field, assignment, or document writes), the direct parent only (never grandparents or siblings, never lateral). This is gated per trust preset: on for standard, off by default for low_trust_review and other review-contained presets, whose input is untrusted content (diffs, external tickets) and whose report comment would be a prompt-injection carrier into higher-trust context.
  3. Stop-only relay (fallback where the report comment is off). For presets with direct-parent commenting disabled, the platform delivers a system-attributed relay comment to the direct parent when the child transitions into blocked or cancelled — never on done or in_review. Stopping is the event the parent must hear about; completion already has the first-class signal above. A relay is a comment, not a disposition transition, so it can never trigger another relay (depth-1 by construction), and relays dedupe per (child, target status) so status flapping cannot spam the parent.

Review Delegation

Review tasks — security reviews, code reviews, QA verdicts — must instruct the delegate to post findings on their own review issue and mark it done. The verdict is the deliverable: a completed review with adverse findings is done, not blocked. The parent's owner is engaged by issue_blockers_resolved (plus the direct-parent report comment where the reviewer's preset allows it) and owns any follow-up fixes.

Never instruct a low-trust delegate to comment on the parent issue. That instruction is guaranteed to be denied at the authorization boundary, and a reviewer that converts the denial into a blocked disposition with a prose-only owner strands the whole tree indefinitely.

The Courier Pattern (Lateral Coordination)

The direct-parent report comment intentionally does not open lateral comment access: no writes into sibling subtrees or other agents' boundaries. The sanctioned lateral channel is the courier pattern: create a new issue assigned to the target agent that carries the complete instructions and context in its description (company-scoped issue-CREATE is permitted from any run). The courier issue wakes the target agent through normal assignment, keeps the coordination auditable, and avoids widening comment access into another agent's boundary. Because the target agent's run may not be able to read your issues, the courier description must be self-contained — do not rely on links back into your own subtree for essential instructions.

7. Accepted-Plan Execution and Optional Decomposition

An accepted plan confirmation authorizes execution of one specific accepted plan revision. Acceptance does not choose the issue topology. A planning source transitions atomically to standard; a source that is already standard stays standard. The continuation starts a fresh default-execution session on that same issue and carries the accepted document id, revision id/number, and approved Markdown.

The default is to implement on the source issue. The run-scoped paperclip-converting-plans-to-tasks guidance decides whether a minimum child graph is justified by an ownership, parallelism, dependency, review, or lifecycle boundary. A child must not be created merely because a plan was accepted, and the source must not be blocked merely because children exist.

create_task and set_dependencies are ordinary authorized standard-run capabilities. create_task creates a standard child under the active issue, with durable idempotency scoped by source issue and caller key; blocker-free children start todo, children with unresolved blockers start blocked, and only assigned dependency-ready children wake. set_dependencies changes the active source issue's first-class blockers and is used only when the source genuinely waits for delegated results.

The accepted-plan decomposition API and records remain as an optional compatibility surface. When that API is explicitly used, Paperclip treats it as an exact-once control-plane primitive, not as the runner's ordinary child-creation binding.

Exact-once fingerprint

The canonical decomposition fingerprint is:

  • (sourceIssueId, acceptedPlanRevisionId)

Where:

  • sourceIssueId is the issue whose plan document revision was accepted
  • acceptedPlanRevisionId is the accepted plan document revision

For the compatibility decomposition API, this remains the product contract because the accepted revision is the thing being decomposed. Re-accepting, re-waking, or re-reading the same accepted revision must not authorize a second child tree through that API. A later accepted revision on the same source issue is a new fingerprint and may produce a different decomposition result.

An implementation may also store the accepted interaction id, acceptance run id, or other evidence, but those values must collapse onto the same uniqueness guarantee. They must not allow a second decomposition claim for the same (sourceIssueId, acceptedPlanRevisionId) pair.

Durable compatibility claim and result

Before creating child issues, the first decomposition attempt must create or reuse a durable record for the fingerprint.

That durable record must be able to answer, without reconstructing the thread from comments or transcripts:

  • whether decomposition for the fingerprint is in_flight or completed
  • which run or owner currently holds the in-flight claim
  • which child issues, if any, have already been created under that fingerprint
  • which final child issue ids belong to the completed result

Paperclip does not need to mandate a specific storage shape in this document. The record may live in a dedicated table, source-issue execution state, interaction metadata, or another durable product surface. What matters is the contract:

  • the claim is durable before fan-out starts
  • partial progress is durable while fan-out is underway
  • the completed child result set is durable after fan-out finishes

If a run creates some children and then dies, retries must continue from the same fingerprint and reuse the already-recorded partial result. They must not restart decomposition as if nothing happened.

Source live path while optional decomposition is in flight

While decomposition for an accepted fingerprint is incomplete, the source issue must expose an explicit live path for that same fingerprint.

The accepted interaction by itself is only evidence that the plan was approved. It is not a sufficient live path once decomposition begins. The source issue must make it clear what moves the fingerprint forward next, such as:

  • the active decomposition run
  • a queued continuation wake for the same assignee
  • a monitor or explicit recovery action tied to the same decomposition claim
  • a blocked state that names the real blocker for finishing that claimed decomposition

If the live run disappears, Paperclip must repair, resume, or visibly block the existing claim. It must not leave the source issue in a state where a second run can interpret the same acceptance as fresh permission to create sibling issues again.

When the source retains implementation, integration, or verification responsibility and genuinely must wait for children, it must hold a first-class blocker path rather than relying on parentId rollup. If it can continue independently, it stays open without child blockers. If its sole deliverable was planning and all remaining work is fully delegated, it may finish after verifying the graph.

Concurrent and repeat attempts

Every later caller of the compatibility decomposition API for the same accepted-plan fingerprint must consult the durable claim/result before creating children.

  • If no claim exists, the run may atomically create the claim and become the decomposition owner.
  • If a claim exists and is in_flight, the later run must reuse that claim. It may resume the same decomposition if it is the valid continuation owner, or it may exit after observing that another run already owns the work.
  • If a claim exists and is completed, the later run must reuse the recorded child result and must not create new sibling issues.
  • If the prior attempt ended after partial child creation, the retry must continue under the same fingerprint and preserve the already-created child ids.

Concurrent compatibility decomposition attempts are therefore idempotent relative to the fingerprint. Creating multiple child trees through that API for the same (sourceIssueId, acceptedPlanRevisionId) pair is a product bug.

8. Non-Terminal Issue Liveness Contract

For agent-owned, non-terminal issues, Paperclip should never leave work in a state where nobody is responsible for the next move and nothing will wake or surface it.

This is a visibility contract, not an auto-completion contract. If Paperclip cannot safely infer the next action, it should surface the ambiguity with a blocked state, a visible notice, or an explicit recovery action. It must not silently mark work done from prose comments or guess that a dependency is complete.

An issue is healthy when the product can answer "what moves this forward next?" without requiring a human to reconstruct intent from the whole thread. An issue is stalled when it is non-terminal but has no live execution path, no explicit waiting path, and no recovery path.

The valid action-path primitives are:

  • an active run linked to the issue
  • a queued wake or continuation that can be delivered to the responsible agent
  • a typed execution-policy participant, such as executionState.currentParticipant
  • a pending issue-thread interaction or linked approval that is waiting for a specific responder
  • a one-shot issue monitor (executionPolicy.monitor.nextCheckAt) that will wake the assignee for a future check
  • a human owner via assigneeUserId
  • a first-class blocker chain whose unresolved leaf issues are themselves healthy
  • an open explicit recovery action that names the owner and action needed to restore liveness

Durable external waits and heartbeat finalization

An external wait counts as a live or waiting path only when the next move survives the current heartbeat and is represented in Paperclip's durable control-plane state. Valid external-wait shapes are:

  • a one-shot issue monitor or other persisted scheduled wake that names the responsible assignee, next check time, and bounded timeout/attempt policy
  • a first-class blocker or blocked disposition that names the external owner and concrete action required to unblock the issue
  • a delegated child issue with a responsible owner and its own healthy action path, plus a blocker edge when the source issue must wait for that child; parentId alone is not a dependency

A one-shot issue monitor consumes its persisted nextCheckAt when it dispatches the assignee wake. If that monitor-consuming run is lost before it records a new disposition or future monitor, Paperclip restores exactly one bounded continuation using the existing process-loss retry limit; if that continuation is also lost, the normal recovery-action escalation owns the next step instead of creating another monitor loop.

An unmanaged local process is not a durable action path. Shell jobs started with &, nohup, local polling loops, detached PTY sessions, adapter child processes, or similar background watchers do not keep an issue live unless Paperclip persists them as a run or pairs a managed runtime service with a monitor, scheduled wake, blocker, or delegated issue that owns the next check. A PID, session id, log file, comment, or promise to check later is evidence only. The process may be killed when the adapter invocation or heartbeat exits and cannot be assumed observable or recoverable by another worker.

Before a heartbeat finalizes, its issue disposition must therefore be evaluated from durable Paperclip state, not from processes still visible only to that heartbeat. An agent-owned issue may remain in_progress after the heartbeat only when another valid action-path primitive already exists. If the only claimed continuation is a local/background watcher, finalization treats the issue as having no live path even when the process has not yet been observed exiting.

If useful deliverable work can continue without the external result, the agent should continue that work or delegate it rather than parking the issue. Use blocked only for a real dependency that prevents productive progress. Use a monitor when the assignee owns a bounded future check, and use delegated child work when another owner can make progress independently.

Recovery from an invalid external wait is bounded and idempotent:

  1. Record bounded evidence that the completed heartbeat left no durable action path, including the terminal run and any reported local watcher metadata without treating that metadata as liveness.
  2. Queue at most one normal-model continuation for the same source state and recovery fingerprint so the assignee can inspect the external result, replace the watcher with a durable wait, continue productive work, or choose a valid disposition.
  3. If that continuation also exits without creating a durable path, do not queue another equivalent continuation. Move the issue to blocked only when a real external dependency can be named; otherwise open or update an explicit recovery action with a named owner and concrete repair/escalation action.
  4. New durable source activity may produce a new recovery fingerprint, but unchanged killed/local-watcher evidence must not create an infinite wake/recovery loop.

This rule is intentionally conservative: local watcher evidence can help the recovery owner decide what happened, but only persisted control-plane state can prove that the work will move again.

Comment and document activity wake sources

Issue-thread comments and document-scoped comments have different wake semantics.

A top-level issue comment created by a board user or other user on an agent-assigned, non-terminal issue may wake that issue's assignee. This is the normal "the owner should see new issue-thread feedback" path, and the wake payload should identify the issue comment that caused the wake when possible.

Issue document comments, document annotation comments, and document review comments do not wake the issue assignee by default. They remain visible as document activity and should be discoverable from the issue's document/review surfaces, but document activity is not itself an issue execution path. A document comment can provide evidence or context for the next run, but it must not be treated as a queued wake, monitor, approval, interaction response, blocker, or terminal disposition.

Document-scoped activity may still route work when it is converted into an explicit action-path primitive. Valid routing exceptions include:

  • an issue mention or structured agent mention that intentionally wakes or assigns a named participant
  • a document-review assignment that names a reviewer or assignee for the review state
  • a response to an issue-thread interaction, such as request_confirmation, ask_user_questions, or suggest_tasks
  • intentional board routing that assigns or reassigns the issue, opens a first-class blocker, creates delegated follow-up work, or queues a typed wake

Freeform document approval text is not auto-acceptance. Plan approval, implementation approval, or review acceptance must flow through the explicit interaction, approval, execution-policy, assignment, or blocker primitives that define who owns the next move.

Comment interrupts and ownership handoffs

A board comment can be an interrupt, an ownership change, both, or neither. Paperclip must keep those concepts separate in the product contract.

An interrupt stops the current live execution path for the issue. It does not, by itself, select the next owner. If an active run is interrupted by the board, the run may still terminate with the underlying cancelled status, but the issue activity and wake context should make the operator intent visible as an interruption rather than an unexplained runtime failure.

For legacy runners, Interrupt on a queued message stops the active run and explicitly continues the pending queue after execution cleanup. It validates the queue revision and target run, then dispatches the requested queues current message bodies in their saved order. Other actors queues cannot consume that interrupt. The persisted interrupt intent is retried by the scheduler after a promotion error or server restart until that queue is dispatched or discarded. Edits and discards remain authoritative until dispatch; deleting the final message must not create an empty continuation. Pending messages remain visible after a run stops. Cancelling only the run preserves the queue for a later explicit wake; pausing the task retains its separate queue-cancellation behavior. Native same-turn steering keeps its separate acknowledgement protocol. Legacy Codex uses Ctrl-C to stop its tool sessions and cannot retry a missing-session fallback after the provider has confirmed that the session started.

An ownership change selects who owns the issue after the comment is committed:

  • setting assigneeAgentId makes the named agent the owner
  • setting assigneeUserId, or clearing assigneeAgentId, makes the issue human-owned or unassigned
  • leaving assignee fields unchanged preserves the current owner

A wake is the delivery path for a selected agent owner. If an interrupting update also assigns a non-terminal, non-backlog issue to an agent, Paperclip should enqueue one wake for the new assignee and include the interrupting comment and interrupted run id in the wake payload/context when available. Stale scheduled retries for the previous owner must not run after ownership changes away from that owner.

If the committed update assigns the issue to a user, clears the agent assignee, or leaves the issue without an agent owner, Paperclip must not imply that an agent handoff happened. The issue is then waiting on the human owner or on a future explicit assignment, blocker, approval, interaction, monitor, or recovery action.

Plain text is not assignment. Writing an agent's name, role, or team label in a comment does not change ownership and does not create an agent wake. Agent routing from comment text requires a structured agent mention that resolves inside the company, an explicit assigneeAgentId mutation, or an existing current agent assignee receiving normal issue-thread feedback.

Pause and tree-control previews should make the same distinction visible. They should report whether the affected subtree contains live running work, queued wakes, agent-owned work, or only human-owned/static issues, so a pause after a handoff does not look like it interrupted agent execution when no agent execution path existed.

Adapter-backed workspace coherence

For adapter-backed execution, an active run or queued wake counts as a live path only when Paperclip can also prove that the selected workspace is coherent for that adapter invocation. A wake that cannot start in the intended workspace is only a failed delivery attempt, not a healthy liveness path.

A workspace-coherent adapter path means:

  • the selected executionWorkspaceId, projectWorkspaceId, projectId, source issue, and company all refer to the same company-scoped work context
  • any projectWorkspaceId is accompanied by the owning projectId, and that project relationship is unambiguous
  • the adapter will receive the same effective workspace/cwd that Paperclip resolved for the run, including the same workspace ids and PAPERCLIP_WORKSPACE_* environment values
  • the effective cwd exists or is provider-reachable, according to the workspace provider
  • when the adapter or workspace strategy relies on git state, the cwd is git-valid for the selected workspace: it resolves to the expected repository root, required base refs or branch metadata can be resolved, and runtime-created worktrees are still registered or explicitly recoverable

Adapter-backed liveness also requires control-plane reachability from the agent's actual mutation surface, not just from the host adapter process. If the agent is expected to use Bash, shell tools, runtime helpers, or in-sandbox command execution to update issues, create comments, upload artifacts, or submit review decisions, the PAPERCLIP_API_URL and PAPERCLIP_API_KEY visible to that surface must route to Paperclip successfully.

For sandbox-backed local adapters, Paperclip may satisfy that contract with a run-scoped in-sandbox bridge. The host adapter keeps the real run JWT on the host side, injects only the bridge URL/token into the sandbox tool environment, and forwards allowed Paperclip API requests with the run id attached. The bridge credentials are execution plumbing, not user-facing context: they must not be written into prompts, visible comments, issue documents, restored workspace files, or durable logs. Agents and skills must use the env vars available in Bash/curl rather than assuming that the host's localhost API URL is reachable from browser or web-extraction tools inside the sandbox.

The state projectWorkspaceId plus executionWorkspaceId without projectId is invalid for project-scoped execution. Paperclip may treat it as recoverable only when it can derive exactly one owning project from the execution workspace, project workspace, or source issue in the same company and then repair the persisted state before delivery. If the owning project is missing, ambiguous, or cross-company, the queued adapter run must not be counted as a live path.

Workspace incoherence feeds into the same non-terminal liveness and stranded assigned-work model as a disappeared run. The recovery path should first fail or reject the incoherent wake, then either repair and requeue one bounded continuation for the same assignee or surface an explicit recovery action. It must not leave an agent-owned in_progress issue healthy solely because a wake record exists that would invoke the adapter in the wrong cwd, a non-git directory where git is required, an unrelated project workspace, or an unrecoverable missing worktree.

For runtime-created git_worktree execution workspaces, branch coherence is part of workspace coherence. The persisted execution workspace branch is the recorded branch for future dispatch. Reusing that workspace must verify that the worktree is still registered and that HEAD is on the recorded branch. Successful run finalization must perform the same check before recording workspace_finalize=succeeded. If the run switched to a publishing/PR branch without updating the execution workspace record, finalization may auto-restore the recorded branch only when the worktree is clean, still registered, and the recorded branch points at the current HEAD; the repair is recorded as a workspace operation before the successful finalize row. If that safe repair cannot be proven, finalization records a failed workspace finalize and the run fails with bounded evidence for the expected and actual branch. A branch change is sanctioned when a control-plane path updates the execution workspace record before finalization, when publishing work happens in a separate worktree and the managed issue worktree remains on its recorded branch, or when the finalizer performs this clean same-commit restoration.

ACP startup handshake bound

An adapter-backed live path also requires that the ACP startup handshake itself cannot hang forever. The engine bounds the handshake with a fixed startup deadline and a poll of the duplex control-channel disposition. Either condition ends the handshake and reports a closed, typed code, so the issue can reach a settled disposition instead of staying in_progress with no observable next action.

The handshake failure code is distinct from a session-identity mismatch. A timeout or a duplex-channel loss during startup must not be reported as the same code as a failed session resume, because the two need different operator responses.

Explicit recovery actions

An explicit recovery action is a typed liveness repair path for a source issue. It is the recovery primitive; the action can be rendered directly on the source issue or backed by a separate recovery issue when the repair needs its own work item.

The task thread exposes the existing guarded Retry action for failed or timed-out legacy conversation runs. Where the server supports an explicit new attempt after a stopped legacy conversation, the thread must not hide that action solely because the old run still has a recovery-needed projection. Native and process recovery holds, pending decisions, active execution, and other retry gates remain in force. When a gate hides Retry, the thread says the message is preserved instead of promising an unavailable action. This presentation change does not rewrite historical outcomes or certify prior actions.

A valid recovery action must name:

  • the source issue and company
  • the recovery kind and idempotency fingerprint
  • the recovery owner, plus previous or return owner when ownership may temporarily shift
  • the cause, bounded evidence, and next action
  • the wake, monitor, timeout, retry, or escalation policy that will move the action forward
  • the resolution outcome when closed, such as restored, delegated, false positive, blocked, escalated, or cancelled

A source-scoped recovery action is the default form. Use it when the next safe move is to repair the source issue's liveness directly: move the source issue back to todo so it can be retried, clarify disposition, re-establish a monitor, record a false positive, or delegate real follow-up work from the source issue.

Recovery-action ownership and source-task ownership are separate contracts. Assigning a manager or board owner to a recovery action authorizes that owner to repair or route the recovery action; it does not write that owner into the source issue's assigneeAgentId. Automatic retry and escalation preserve the source assignee. Reassignment requires an explicit source-task decision or a policy-defined serious-failure path, with the normal company, authorization, budget, checkout, active-run-lock, governed-action, and activity-log checks.

Use an issue-backed recovery action only when the recovery is genuinely independent work or when source-scoped handling would be unsafe or unclear. Examples include:

  • long or cross-agent repair work with its own assignee, subtasks, or blockers
  • real delegated follow-up that should block the source issue as a first-class dependency
  • active-run watchdog work that must observe a still-running source process without interfering with it
  • recovery that needs separate review, approval, security handling, or escalation ownership
  • cases where source issue ownership cannot be changed or restored safely

A comment or system notice can be evidence for a recovery action, but it is not a recovery action by itself. Comment-only recovery is not a healthy liveness path because it does not define a typed owner, wake or monitor policy, retry bound, timeout, escalation path, or resolution outcome.

Recovery action freshness

Source-scoped recovery actions are snapshots of the source issue's liveness state at the time the action was opened. They must be revalidated after newer durable source activity, including source issue status changes, assignee changes, blocker changes, execution policy or monitor changes, document or work-product updates that define a valid waiting path, and structured resume or disposition updates.

When newer source activity restores a valid live or waiting path, the recovery action is stale and should be folded through the explicit recovery lifecycle instead of being hidden or deleted. Folding means resolving or cancelling the recovery action with a resolution outcome and note that preserve the audit trail.

Plain comments alone do not make a recovery action stale. A comment can provide evidence, but the recovery action should remain visible when the source issue is still stalled and the comment does not create a valid action-path primitive such as a wake, monitor, interaction, approval, blocker, human owner, execution participant, terminal disposition, or delegated follow-up.

Agent-assigned todo

This is dispatch state: ready to start, not yet actively claimed.

A healthy dispatch state means at least one of these is true:

  • the issue already has a queued wake path
  • the issue is intentionally resting in todo after a completed agent heartbeat, with no interrupted dispatch evidence
  • the issue has been explicitly surfaced as stranded through a visible blocked/recovery path

An assigned todo issue is stalled when dispatch was interrupted, no wake remains queued or running, and no recovery path has been opened.

Agent-assigned backlog

This is parked state, not dispatch state.

Assigning an issue normally implies executable intent. When create APIs receive an assignee and no explicit status, Paperclip defaults the issue to todo so the assignee has a wake path instead of silently inheriting the unassigned backlog default.

An explicit assigned backlog issue remains valid when the creator is deliberately parking the work. It must not wake the assignee just because it has an assignee. Paperclip should make that choice visible in activity and UI so operators can distinguish intentional parking from a missed handoff.

An assigned backlog issue becomes a liveness problem when another issue is blocked on it and there is no explicit waiting path such as a human owner, active run, queued wake, pending interaction or approval, monitor, or open recovery action. In that case the blocked parent should surface "blocked by parked work" rather than treating the dependency chain as healthy.

Agent-assigned in_progress

This is active-work state.

A healthy active-work state means at least one of these is true:

  • there is an active run for the issue
  • there is already a queued continuation wake
  • there is an active one-shot monitor that will wake the assignee for a future check
  • there is an open explicit recovery action for the lost execution path

An agent-owned in_progress issue is stalled when it has no active run, no queued continuation, no persisted monitor, and no explicit recovery surface. An unmanaged local/background watcher does not satisfy any of those conditions. A Paperclip-tracked run that is still running but silent is not automatically stalled; it is handled by the active-run watchdog contract.

in_review

This is review/approval state: execution is paused because the next move belongs to a reviewer, approver, board user, or recovery owner.

A healthy in_review issue has at least one valid action path:

  • a typed execution-policy participant who can approve or request changes
  • a pending issue-thread interaction or linked approval waiting for a named responder
  • a human owner via assigneeUserId
  • an active run or queued wake that is expected to process the review state
  • an active one-shot monitor for an external service or async review loop that the assignee owns
  • an open explicit recovery action for an ambiguous review handoff

Agent-assigned in_review with no typed participant is only healthy when one of the other paths exists. Assignment to the same agent that produced the handoff is not, by itself, a review path.

An in_review issue is stalled when it has no typed participant, no pending interaction or approval, no user owner, no active monitor, no active run, no queued wake, and no explicit recovery action. Paperclip should surface that state as recovery work rather than silently completing the issue or leaving blocker chains parked indefinitely.

When an execution-policy review stage has a pending agent participant, the participant's run is part of the review path only while it is live or queued. If that participant run reaches a terminal state while executionState.status remains pending, no decision has been recorded. After a successful run with no review decision, Paperclip should queue one bounded normal-model recovery wake for the same participant when the agent is invokable and no other review path exists. A failed participant instead follows the provider-continuity rules below: local conversational adapters can start a bounded continuation turn, while native sessions use validated resume/replacement. Other adapters retain their action-recovery gates. The original assignee stays unchanged. If that recovery run also finishes while the stage remains pending, or the participant cannot be invoked, Paperclip must move the source issue to an explicit blocked/recovery path instead of leaving in_review to drift silently.

Issue monitors

An issue monitor is a one-shot deferred action path for agent-owned issues in in_progress or in_review.

Use a monitor when the current assignee owns a future check against an async system or external service. Examples include Greptile review loops, GitHub checks, Vercel deployments, or provider jobs where the agent should come back later and decide what happens next.

Monitor policy lives under executionPolicy.monitor and includes:

  • nextCheckAt: when Paperclip should wake the assignee
  • notes: non-secret instructions for what the assignee should check
  • serviceName: optional non-secret external-service context
  • externalRef: optional external-service reference input; Paperclip treats it as secret-adjacent, redacts it before persistence/visibility, and omits it from activity and wake payloads
  • timeoutAt, maxAttempts, and recoveryPolicy: optional recovery hints for bounded waits

Monitors are not recurring intervals. When a monitor fires, Paperclip clears the scheduled monitor and queues an issue_monitor_due wake for the assignee. If the external service is still pending, the assignee must explicitly re-arm the monitor with a new nextCheckAt. If the issue moves to done, cancelled, an invalid status, or a human/unassigned owner, the monitor is cleared.

The task's waiting banner and composer countdown also display automatic retries while their run is scheduled_retry. Once a retry is queued or running, its retained scheduledRetryAt is historical and must not produce a waiting or overdue warning. A separately scheduled monitor remains visible. Completed and cancelled tasks hide both waiting surfaces even if a stale schedule remains in the response.

Because serviceName and notes remain visible in issue activity and wake context, operators should keep them short and non-secret. Put enough context for the assignee to know what to inspect, but do not include signed URLs, bearer tokens, customer secrets, tenant-private identifiers, or provider links with embedded credentials.

Monitor bounds are enforced. Paperclip rejects attempts to re-arm a monitor whose timeoutAt or maxAttempts is already exhausted. When a scheduled monitor reaches an exhausted bound at trigger time, Paperclip clears it and follows recoveryPolicy: wake_owner queues a bounded recovery wake for the assignee, create_recovery_issue opens visible issue-backed recovery work, and escalate_to_board records a board-visible escalation comment/activity.

Use blocked instead of a monitor when no Paperclip assignee owns a responsible polling path. In that case, name the external owner/action or create first-class recovery/blocker work.

blocked

This is explicit waiting state.

A healthy blocked issue has an explicit waiting path:

  • first-class blockers exist, and each unresolved leaf has a valid action path under this contract
  • the issue has an explicit recovery action that itself has a live or waiting path
  • the issue is waiting on a pending interaction, linked approval, human owner, or clearly named external owner/action

A blocker chain is covered only when its unresolved leaf is live or explicitly waiting. An intermediate blocked issue does not make the chain healthy by itself.

A blocked issue is stalled when the unresolved blocker leaf has no active run, queued wake, typed participant, pending interaction or approval, user owner, external owner/action, or recovery action. In that case the parent should show the first stalled leaf instead of presenting the dependency as calmly covered.

9. Crash and Restart Recovery

Paperclip now treats crash/restart recovery as a stranded-assigned-work problem, not just a stranded-run problem.

There are two distinct failure modes.

9.1 Stranded assigned todo

Example:

  • issue is assigned to an agent
  • status is todo
  • the original wake/run died during or after dispatch
  • after restart there is no queued wake and nothing picks the issue back up

Recovery rule:

  • if the latest issue-linked run failed/timed out/cancelled and no live execution path remains, Paperclip queues one automatic assignment recovery wake
  • if that recovery wake also finishes and the issue is still stranded, Paperclip moves the issue to blocked and opens or updates a board-owned recovery action without changing the source assignee or waking a substitute agent; the visible comment is evidence, not the recovery path by itself

This is a dispatch recovery, not a continuation recovery.

Recovery hand-back is covered by the same liveness guarantee:

  • an issue_recovery_action_restored wake requested while the resolving recovery run is still active is persisted as a follow-up and dispatched only after that run exits, so it cannot be coalesced into the run that requested it
  • if that follow-up is nevertheless lost, the stranded-work backstop treats an assigned todo issue with a resolved handed_back recovery action from during or after its latest successful run as stranded and queues the bounded assignment recovery wake; the successful resolving run is not, by itself, evidence that the handed-back source work is live

9.2 Stranded assigned in_progress

Example:

  • issue is assigned to an agent
  • status is in_progress
  • the live run disappeared
  • after restart there is no active run and no queued continuation

Recovery rule:

  • Paperclip queues one automatic continuation wake
  • if that continuation wake also finishes and the issue is still stranded, Paperclip moves the issue to blocked and opens or updates a board-owned recovery action without changing the source assignee or waking a substitute agent; the visible comment is evidence, not the recovery path by itself

This is an active-work continuity recovery.

After a productive successful run, recovery checks that the issue is still in_progress and assigned to the same agent under the enqueue transaction's issue lock. The sweep's earlier snapshot cannot authorize a continuation after completion, cancellation, reassignment, or a move to another status. A mismatch records a skipped wake receipt without creating a run. An empty queued continuation cancelled because the issue became terminal is omitted from task chat; its cancellation remains in the run log. Runs that actually started still show their stop state.

The same bounded rule applies when the previous heartbeat reported waiting on a local/background watcher and that watcher was killed, disappeared, or was never represented by a durable Paperclip primitive. Paperclip queues at most one continuation for the same recovery fingerprint. If the continuation also leaves only local watcher evidence, Paperclip must surface a real blocker or explicit recovery action instead of repeating continuation recovery. A new monitor, scheduled wake, healthy delegated blocker issue, or other durable source mutation resolves that recovery fingerprint normally.

Deliberate wait is not a lost run

A continuation that the staleness gate cancelled with issue_continuation_waiting_on_review is a deliberate park, not a disappeared execution path. The latest run reported that the issue is waiting for review/approval (for example, an umbrella issue whose work was just decomposed into sub-tasks). Treating that park as a stranded run would retry it, then escalate it to blocked with a recovery action and an operator-facing failure notice — even though nothing failed and there is nothing for a human to do.

Recovery rule for a parked-for-review continuation:

  • if the issue has a real waiting target — open (non-terminal) sub-tasks or existing unresolved blockers — Paperclip converts the deliberate wait into a first-class dependency wait: it sets the issue blocked by those issues, keeps the original assignee, and posts a plain-language comment explaining that the task will resume automatically when its dependencies finish. The issue then self-resumes through the normal issue_blockers_resolved path; no recovery action or escalation owner is involved
  • if the issue has no current typed waiting target and the original owner is invokable, Paperclip classifies it as deliberate_wait_without_target and gives that owner five normal-model disposition-repair attempts: immediate, then after 60, 120, 240, and 480 seconds, with up to 10 percent jitter on delayed attempts
  • before every attempt, Paperclip revalidates unresolved blockers and children, interactions, linked approvals, monitors, execution stages, queued wakes, active runs, work products, owner invokability, and budget or governance gates. Any real live or waiting path suppresses the retry
  • the retry bound is keyed by an idempotent durable source-state fingerprint. Comments, repeated parked summaries, and equivalent prose do not reset it. Durable changes such as source status or assignee changes, dependency or interaction changes, approval or execution-policy changes, monitor changes, or work-product changes may create a new fingerprint
  • on upgrade, consecutive historical issue_continuation_waiting_on_review cancellations for the same accepted interaction and still-unchanged durable source state seed this same counter. Five applicable pre-upgrade parks therefore exhaust the ceiling immediately; the absence of a historical deliberate_wait_without_target recovery-action row does not grant five new attempts
  • the action persists the unchanged fingerprint, source-attempt count, due time, source owner, and return owner. Startup and periodic reconciliation reuse that state, fold the action when a current typed wait appears, and reschedule or escalate an expired attempt that has no live scheduled run. Idempotency keys prevent a restart from creating duplicate wakes or scheduled runs
  • after five attempts with the same fingerprint, Paperclip opens one board-owned source-scoped recovery action. The source assignee remains unchanged, no manager/creator/executive substitute is woken, and the board chooses whether to repair, retry the original owner, explicitly reassign, or resolve
  • a recovery action is a healthy wait only while its owner has a live run, queued wake, scheduled retry, typed wait, or explicit board escalation. Source liveness and every blocker-chain projection use that same nested result

An accepted interaction supersedes a continuation park recorded before that acceptance. A queued continuation carrying a parseable interactionResolvedAt must not be cancelled solely because an older continuation summary says to wait for review or approval. Interaction-continuation recovery is bounded: after three consecutive continuation wakes are cancelled without a run starting, recovery converts a real dependency wait when one exists or escalates the missing execution path visibly instead of requeueing forever.

This keeps the post-decomposition umbrella (§7) on a real waiting path instead of relying on parentId rollup, which §6 does not treat as a dependency.

9.3 Recovery work classes

Status-only operational recovery can update task liveness, clear bad status, record a disposition, or ask for human or manager intervention. Those wakes must carry guard context such as allowDeliverableWork: false, allowDocumentUpdates: false, and resumeRequiresNormalModel: true. The recovery work class does not select or change the agent model.

Automatic retries that can continue source work use the agent's configured model. This includes failed source-work retries, process-loss retries, transient or scheduled retries, max-turn continuations, source-assignee continuations, assigned-todo dispatch recovery, and any run that can update repo files, task documents, plans, work products, or attachments. When status-only recovery determines that actual work remains, it must hand back to a worker run before source work or persistent deliverable updates resume.

10. Startup and Periodic Reconciliation

Startup recovery and periodic recovery are different from normal wakeup delivery.

On startup and on the periodic recovery loop, Paperclip performs the following recovery passes:

  1. reap orphaned running runs
  2. resume persisted queued runs
  3. reconcile stranded assigned work
  4. scan silent active runs only for source-aware terminal folding and legacy cleanup; API reads classify ordinary output silence for the board UI

The stranded-work pass closes the gap where issue state survives a crash but the wake/run path does not. The silent-run scan covers the separate case where a live process exists but has stopped producing observable output.

Automatic productivity reviews are retired. Run counts, missing comments, and elapsed task time do not create review tasks or impose continuation holds. Bounded continuation, provider recovery, budget limits, explicit blockers, and normal review/approval stages remain in force. Existing productivity-review tasks, comments, assignments, and dependencies remain unchanged and readable; their historical origins still identify them as recovery work for recursion suppression.

Issue-thread interaction resolution

Every issue-thread interaction kind inherits resolver policy anyone when the creator omits a policy. anyone includes the creator agent and creating run. Callers opt into independent review with not_creator or human resolution with human_only; a named addressee and company cap may narrow the effective audience. The legacy input aliases board_or_agents and board_only normalize to anyone and human_only for new writes.

Resolver policy is snapshotted with explicit/inherited provenance and an effective source (requested, company_cap, or governed_action). Existing ambiguous legacy rows are marked legacy_inherited_restriction and retain their old restriction: board_or_agents becomes not_creator, not anyone, while board_only becomes human_only. Pending cards are never silently widened.

Resolution is exact-once and requires issue access in the same company. Agent resolution also requires valid run attribution and remains subject to low-trust and task-bridge containment. Target freshness and supersession are checked before the outcome commits. Resolution records an answer; every continuation, task creation, tool/provider call, execution-policy transition, spend, deployment, or other effect independently re-runs its own authorization and approval gates.

11. Task Watchdog for Issue Trees

A task watchdog watches a configured issue subtree after that subtree has stopped moving. It is a product-level verification and recovery mechanism for selected work, not a process monitor.

Keep the three watchdog/recovery concepts separate:

  • task watchdog: watches a configured source issue plus non-watchdog descendants and asks whether the stopped subtree is legitimate
  • silent active-run watchdog: watches a still-running process that has stopped producing output
  • liveness recovery: repairs stranded control-plane paths when a non-terminal issue has no live, waiting, or recovery path

Configuration and scan scope

A source issue may have at most one active task watchdog configuration. The configuration names a same-company, invokable watchdog agent and optional custom instructions.

The scan scope is:

  • the source issue
  • descendants reached through parentId
  • excluding every issue whose originKind is task_watchdog
  • excluding every descendant below an excluded task-watchdog issue

The reusable watchdog issue is a child of the watched source issue for audit and navigation, but it is excluded from the watched work subtree. This prevents recursive watchdog loops.

Stopped-subtree evaluation

Task watchdog evaluation is conservative. If any included issue has a live run, queued wake, or scheduled retry that should fire without intervention, the subtree is live and the task watchdog does not run.

If no included issue has a live path, Paperclip computes a stop fingerprint from durable subtree state, including at least:

  • included leaf issue ids, statuses, assignees, and latest durable update timestamps
  • first-class blockers and unresolved blocker leaf summaries
  • pending interactions and approvals that define waiting paths
  • active monitors and scheduled retries
  • terminal or cancelled leaf evidence
  • the watchdog configuration revision, including watchdog agent and instructions changes

If the fingerprint equals the watchdog's last reviewed fingerprint, Paperclip suppresses another watchdog wake. If the fingerprint is new, Paperclip creates or reopens the reusable watchdog issue and wakes the configured watchdog agent with the source issue, watchdog config, stop fingerprint, leaf summary, default mandate, custom instructions, and server-derived capability metadata that names the allowed operations, denied operations, reusable watchdog issue, and non-watchdog target scope.

Changing the watchdog agent or custom instructions invalidates the reviewed fingerprint and forces a fresh evaluation even if the subtree state did not otherwise change.

Live path created by watchdog work

An active watchdog issue or queued watchdog wake can be the visible recovery path for a stopped watched subtree, but it is not proof that the original deliverable work is complete. It means the next action is watchdog verification.

When the source issue is non-terminal and has no other live path, the product should expose the watchdog issue or source-scoped recovery action as the reason the subtree is covered. When correctness requires the source issue to wait on watchdog review, the source issue should be blocked on the reusable watchdog issue or an equivalent explicit recovery action. Do not rely on parent/child structure alone.

Watchdog authority during execution

The watchdog agent acts in a scoped capacity, not as the original deliverable worker and not as the board. The server must enforce the authority contract in doc/SPEC-implementation.md from persisted watchdog context. Prompt text and custom instructions may guide the watchdog's judgment, but they cannot grant authority outside the watched subtree or widen an interaction's ordinary effective audience.

Watchdogs must not create visible probe issues, comments, or throwaway tasks to discover capability boundaries. They should rely on the wake capability metadata and explicit API denials, then record any denied operation as evidence in the reusable watchdog issue.

The watchdog should verify stopped leaves against comments, documents, work products, tests, screenshots, blockers, review state, and run context. It should not accept "I could not" or "waiting for approval" as sufficient by itself.

When work should continue, the watchdog restores a live path inside the watched subtree: reopen or reassign stuck work, create follow-up issues, repair blockers, set a monitor, or resolve an interaction that its ordinary agent audience permits. When the stopped state is legitimate, the watchdog records why and leaves the subtree with a valid terminal, waiting, blocked, review, or explicit recovery path.

Atomic recovery batch

Restoration is often more than one write — reopen the dead-end leaf and explain it on the parent. A watchdog run may submit a small atomic recovery batch: at most 3 mutations from the allowed-mutation list, validated against the stop fingerprint the run observed. The server applies the batch all-or-nothing and aborts the remainder if the subtree fingerprint changed mid-batch because work went live concurrently.

This preserves the stale-guard's purpose — never keep mutating a subtree that just went live under the watchdog's feet — while removing the failure mode where spending the only permitted write on an informational comment forfeits the state-restoring mutation the recovery actually needed.

Interaction decisions

A task watchdog is an ordinary agent for interaction resolution. Its watchdog context provides no special audience, plan-purpose marker, or kind allowlist, and it is not a categorical denial. The normal evaluator checks the effective policy, named addressee, company and issue scope, run attribution, low-trust/task-bridge containment, target freshness, and exact-once state.

This does not give a watchdog downstream authority. Linked/formal approvals remain separate, execution-policy decisions still require the typed participant, and an accepted interaction cannot authorize spend, hiring, secrets, deployment, destructive data changes, cross-company work, or any mutation the watchdog scope otherwise forbids.

Completion and fingerprint updates

The watchdog's reviewed fingerprint should update only after the watchdog issue reaches a valid disposition:

  • done with evidence that the stopped state is acceptable
  • in_review with a real reviewer, approval, interaction, user owner, monitor, or recovery path
  • blocked with first-class blockers or a named external owner/action
  • a watchdog mutation that restores live work, where the subsequent source-subtree mutation naturally changes the stop fingerprint

If the watchdog moved work forward, Paperclip should not mark the old fingerprint as permanently acceptable just because the watchdog issue completed. The next scan should observe the changed subtree state and either suppress because work is live or compute a new stopped fingerprint later.

Restoration verification and escalation

A reviewed fingerprint suppresses re-fire only when the watchdog's recorded disposition was "this stopped state is legitimate." A "live path restored" disposition does not earn permanent suppression; it arms a bounded verification instead.

The stop fingerprint must be computed from durable subtree state such that a restoration which changes nothing observable is detectable as a failed restoration. In particular, activity on intermediate (non-leaf) nodes — comments, wakes delivered to an intermediate issue's assignee, runs that end without mutating any stopped leaf — must feed the fingerprint or the attempt lineage; a fingerprint derived from stopped leaves alone makes a failed intermediate-node restoration byte-identical to a reviewed-and-acceptable stop, which silences the watchdog forever.

Verification and escalation semantics:

  • if, after a "live path restored" disposition, the subtree is observed stopped again with a fingerprint equal to the one the watchdog claimed to have fixed, the restoration failed and the watchdog re-fires with an incremented attempt count
  • attempt lineage is durable watchdog state: attempt number, the fingerprint each attempt claimed to fix, and the restoration actions taken
  • after N attempts (N = 23) on the same fingerprint lineage, the platform stops re-firing and escalates to a human — the watchdog owner or a board notification — carrying the attempt history

This bounds both failure modes: a failed restoration retries instead of going silent (liveness), and the attempt bound plus human escalation prevents an infinite fire loop (no runaway watchdog). Legitimate stops still suppress exactly as before.

Task watchdogs must not silently mark source work done from prose comments, must not duplicate child trees for the same accepted plan revision, and must not create another task-watchdog issue for the same source issue.

12. Silent Active-Run Watchdog

An active run can still be unhealthy even when its process is running. Paperclip treats prolonged output silence as a watchdog signal, not as proof that the run is failed.

The recovery service owns this contract:

  • classify active-run output silence as ok, suspicious, critical, snoozed, or not_applicable
  • honor active snooze and continue decisions on the run
  • permanently suppress the signal for a run after a dismissed_false_positive decision
  • build the outputSilence summary shown by live-run and active-run API responses
  • retain links to open legacy stale_active_run_evaluation issues without refreshing or changing them

Suspicious and critical silence are informational board UI signals. They do not create an issue or recovery action. They do not comment on or block the source issue. They do not change an assignment, wake an agent, cancel the active process, or change the run. The board uses the existing run controls when it decides that intervention is necessary.

Watchdog decisions are explicit board decisions stored against the run:

  • snooze records an operator-chosen future quiet-until time and hides the signal during that window
  • continue records that the current evidence is acceptable, does not cancel or mutate the active run, and sets a 30-minute default re-arm window before the watchdog evaluates the still-silent run again
  • dismissed_false_positive records why the signal was not actionable and suppresses it permanently for that run

Operators should prefer snooze for known time-bounded quiet periods. continue is only a short acknowledgement of the current evidence. If the run remains silent after the re-arm window, the UI signal appears again.

The signal reappears in the UI after a snooze or continue window expires. No review work is created when it reappears. The board can record decisions without an evaluation issue. For compatibility, the assigned owner of an open legacy evaluation issue can also record a decision that is bound to that issue and run. Other agents cannot.

Source-aware watchdog folding

The active-run cleanup scan is source-aware. It re-reads the linked source issue and decides whether a still-running handle represents productive source work or stale run/process bookkeeping. It does not create reviewer work.

Fold watchdog work when all of these are true:

  • the run is linked to a source issue in the same company
  • the source issue is terminal (done or cancelled)
  • durable source activity from the same run proves the source issue reached that terminal disposition after the stale-run or output-silence evidence point
  • there is no independent evidence that the still-running or detached process is doing harmful work, still owns external cleanup that needs an operator decision, or needs a separate security/ownership review

Folding means finalizing the stale run and resolving any legacy watchdog recovery action or issue-backed evaluation through the explicit recovery lifecycle. It must preserve the run id, source issue, detected silence or detached-process evidence, terminal source activity, decision reason, and best-effort process cleanup result. It must be idempotent for the (companyId, runId, sourceIssueId) signal and must not recursively recover a watchdog evaluation issue itself.

Do not fold a run only because it is quiet. Keep the informational signal visible when:

  • the source issue is still todo or in_progress, because productive work may still be happening or stuck
  • the source issue remains in_progress after a successful run with no valid disposition, because the successful-run handoff path owns that bounded correction
  • the run terminated or disappeared while the source issue remains in_progress without a live path, because stranded assigned recovery owns that continuity repair
  • the source issue is terminal but there is no durable same-run terminal activity after the stale evidence point
  • there is independent evidence that the process may still be mutating external state, leaking resources, crossing company or ownership boundaries, or otherwise needs an operator decision

In the normal non-terminal case, critical silence remains a UI signal and does not block the source issue. In the source-resolved case, a completed source issue does not acquire a new review or blocker merely because an old run handle stayed active. Only real unresolved work should block work.

Source-resolved watchdog folding concerns stale active-run bookkeeping after a valid terminal disposition. It does not infer productivity from run counts, comment frequency, or elapsed task time.

Detached process cleanup is operational hygiene, not source issue liveness. Cleanup should be best-effort and auditable. If cleanup fails but the source issue is already terminal with same-run durable evidence, Paperclip should preserve the cleanup failure on the run/watchdog audit trail and route only the cleanup concern to bounded recovery when a real owner/action remains.

13. Auto-Recover vs Explicit Recovery vs Human Escalation

Paperclip uses three different recovery outcomes, depending on how much it can safely infer.

Auto-Recover

Auto-recovery is allowed when ownership is clear and the control plane only lost execution continuity.

Examples:

  • requeue one dispatch wake for an assigned todo issue whose latest run failed, timed out, or was cancelled under the bounded conversation or provider-continuity rules below
  • requeue one continuation wake for an assigned in_progress issue whose live execution path disappeared under the bounded conversation or provider-continuity rules below
  • assign an orphan blocker back to its creator when that blocker is already preventing other work

Auto-recovery preserves the existing owner. It does not choose a replacement agent.

Completion tools and final answers

A completion tool such as paperclip_finish reports task disposition; it does not end the provider turn. Paperclip continues persisting and displaying provider events until an authoritative turn terminal arrives. The completion report starts no interruption timer. Existing execution timeouts, cancellation, governed waits, and active-goal rules still apply. A later failed or cancelled terminal remains failed or cancelled even when the agent already reported completed work.

The final assistant message is the visible task response. Response selection runs after preceding event persistence completes; the completion summary cannot replace an available final answer. Existing fallback and explicit-comment precedence still apply. Stream closure without a turn terminal is not proof of success. Event replay uses the existing source receipts and never repeats provider work merely to recover recorded output.

Routine task completion and human-input requests must work under Conservative runner permissions. The isolated Claude runtime grants only the narrow task tools on the runner-owned bridge; it does not change general tool permissions. Questions must be created as durable interactions before the agent claims to be waiting. A direct Board comment reopening completed work has the same passive response-wait semantics as a comment on an open task, subject to the same source, identity, and governance checks. An automatic continuation is not a user reply.

Provider-turn identity separates recovery responses from earlier assistant output. A recovery turn cannot overwrite a delivered answer. File attachments and work products refresh in the visible conversation when delivered. Composer delivery uncertainty is reconciled by the exact durable client request ID; another comment cannot settle it, and newer draft text must be preserved.

The composer Stop action cancels the current response and verifies termination; it does not create a pause hold. An acknowledged intentional cancellation remains neutral even if teardown releases the run lease or returns no semantic result. Pause work separately controls future execution. A crash preventing progress is Blocked; In Review requires a concrete human decision.

Provider continuity and bounded finalization

A permanently unusable native runner session may be replaced only with evidence that its predecessor is stopped and fenced, completed results and workspace state are preserved, required task history is available, and pending effects have been reconciled. A provider-native shell command or external write without a reliable outcome receipt is unknown. Unknown effects, integrity failures, and unverified process ownership never authorize speculative replay. Once automatic recovery is ruled out, Paperclip selects a conservative default: preserve recorded work, stop the affected task, and retain a durable no-replay hold. Unknown action outcomes remain unknown. No reconciliation form or user diagnosis is required.

Local Codex crash replacement can use a complete interrupted-turn inventory, authenticated process-stop evidence, and unchanged retained-state fingerprints. Only text and an exactly receipted task-completion call qualify for this path; unknown operations or partial transcripts do not. Replacement uses a fresh session and retires only the exact predecessor's obsolete recovery hold while recording the proof and successor lineage. Retained provider files are not edited.

Bootstrap retries, exact-checkpoint resumes, and fresh replacement sessions share three total provider attempts, including the original attempt. Linked run IDs, controller restarts, and duplicate wakes do not reset this budget. Automatic attempts retain the 30-second delay. Replacement scheduling and predecessor lineage commit together, with one successor per predecessor and admission through the normal task locks, authorization, pause, approval, and budget gates.

Provider execution and control-plane finalization have different clocks. A healthy provider can think or execute a long tool without output. Once execution settles, recovery and finalization control steps have a 60-second deadline, checked on startup and every 15 seconds. With a healthy database and scheduler, an abandoned transition must be repaired or surfaced within 90 seconds. Terminal persistence must not wait on provider cleanup or publication; a late finalizer cannot change a reassigned or closed task or release another run's locks. Historical ambiguous runs are never automatically replayed after an upgrade.

Every continuation carries the triggering request, ordered user direction, interaction outcomes, completed work, and explicit history coverage. A delivered message remains part of the task's request after its connection or approval resolves. The original title is background; a completed Notion read does not satisfy a later Gmail request. Author and source-trust boundaries survive rendering into both native and legacy prompts. Missing required history must be fetched before dispatch rather than described as complete.

Interrupted conversation continuation

Before provider dispatch, chat-control admission retries transient database lock contention with up to 50 waits of 100 ms. Each attempt starts a new transaction and rechecks the current run and committed conversation-close evidence. No lock is held between attempts, and no provider call is retried. Queue claims remain nonblocking. Persistent contention retains the bounded admission failure, with an explicit database-lock error; missing or invalid source evidence still stops the run without retrying the admission check.

An interrupted conversation does not permanently block its task. For local conversational adapters, Paperclip starts a new bounded turn with the existing session when compatible, or the full task conversation when the session is unavailable. The prompt says: “Your previous run was interrupted. Continue from where you left off.” The agent decides what remains from the history and latest user request. Paperclip never automatically replays recorded tool calls. Unknown past action outcomes are not a task-wide execution gate, and no action-reconciliation questionnaire is required.

Shutdown, process loss, and provider failure use the existing durable failure retry counter and delay. Ordinary failure recovery permits at most two automatic retries in a failure chain. Accepted-interaction infrastructure recovery retains its existing bounded policy. Repeated scheduler visits reuse the same successor; restarting the server does not reset the counter. After exhaustion, automatic attempts stop. A new explicit user message can start a fresh run and failure budget. Productive max-turn continuation and confirmed workspace waits keep their separate existing semantics.

Real gates still apply: company and task ownership, active provider ownership, budget limits, agent availability, dependencies, pending approval/review paths, and explicit pause holds. Native runner reattachment and finalization retain their existing ownership protocol. Process, HTTP, and gateway adapters retain their recovery rules because invoking those adapters can itself repeat an external action rather than start a conversation turn.

An operator Stop waits for provider termination. Remote sandbox providers may return a stopped/deleted receipt after their control-plane operation completes. Paperclip binds that receipt to the company, run, and exact lease; successful file cleanup, a terminal run row, or an in-sandbox shutdown event is not sufficient. Legacy conversational runs receive their cancellation acknowledgement after all remote leases have confirmed termination. Stop alone never creates a continuation. A user message queued during remote cleanup is reconsidered when the provider confirms termination; it still passes normal admission and adopts pending comment IDs in order. Once stopped, the next explicit wake uses the same queue. A compatible saved ACP session can resume, and an unavailable or incompatible session can start fresh with the full task context. Run credentials and scratch paths remain scoped to the new run. A subtree pause requires Resume; a message does not bypass it.

For native conversations, an authenticated user message sent after the previous run finishes can retire its execution recovery holds and start a fresh turn. Hold retirement and the new run are atomic. The previous transcript, tool outcomes, and recovery history remain intact. This starts a new conversation; it does not replay tool calls with unknown outcomes.

Local recovery records a server-authored stop receipt before it clears a verified absent process identity. A new execution request invalidates that receipt before any process can spawn; recording a new process identity also invalidates it. Missing process IDs without a receipt still block admission. Remote execution continues to require termination receipts for every lease.

If cleanup or another execution gate is still pending, the message stays in its existing queue receipt. Startup and periodic scheduling reconsider up to 50 due receipts per pass, at most once per 30 seconds per receipt, without calling a model or resetting recovery attempts. Cleanup callbacks use the same admission path. The issue lock prevents concurrent workers from delivering an adopted or discarded receipt again. The queued-message area shows the current wait reason. Pauses, approvals, budgets, ownership, and external chat authorization remain enforced. A message sent before the run finished does not grant new post-stop authority.

Historical legacy interruption holds for conversational adapters no longer block new messages or Resume. Automatic classification uses the server-owned adapter identity saved atomically at run claim, the saved adapter invocation, or the continuation policy, never the agents current adapter settings. Missing historical adapter evidence retains the automatic hold; an explicit user continuation can retire it after proving the predecessor stopped. A terminal row with a live predecessor process, an unreleased environment lease, or failed/pending cleanup still blocks actual admission and Resume; a release timestamp alone does not prove cleanup succeeded. Retry scheduling can happen before cleanup, but grants no execution authority. Recovery folds their obsolete no-replay bookkeeping without changing task ownership, status, or automatically waking old work. The audit trail remains readable. Native integrity and ownership holds, and non-conversational adapter holds, remain enforced.

The server projection remains available for diagnostics. Normal working, finishing, and interaction waits add no badges or cards to task lists or feeds. Active transcript headers keep saying Working during automatic retry and execution confirmation; attempts, causes, and recovery decisions belong in the run log. Recovery uses the existing transcript and run log rather than adding a reconciliation form. A cancelled run that never started says “Couldn't start” instead of implying that the agent answered.

Codex startup and provider state

Paperclip trusts the server-selected startup execution root in the isolated Codex configuration. Resolve that root on the execution host, including the main repository trust key for Git worktrees. Start the provider in that same root. This does not change sandbox permissions, tool authorization, secret access, or Codex's separate per-hook trust policy.

Codex retains the model conversation. Paperclip resumes with excludeTurns: true, reads lightweight thread state, and fetches paginated turn metadata or specific turn items only when execution reconciliation needs them. Unsupported or incomplete history is an explicit error, not evidence of idle execution.

The root-thread usage snapshot sent during resume belongs to its reported completed turn. Retain a bounded local diagnostic and use cumulative totals as a baseline; do not emit a warning or charge its historical last usage to the new run. Preserve the baseline across recovery of the same run and start a new delta when attaching a new run. Other stale-event and authority checks remain.

Explicit user continuation after execution failure

An execution recovery hold blocks automatic replay. A new authenticated user comment or exact failed-run Retry can authorize a fresh native or legacy conversation turn after the predecessor's execution is confirmed stopped. This is a new request, not another automatic attempt in the failed incident. The old attempt count and unknown action outcomes remain unchanged. Known non-conversation adapter evidence still requires its original reconciliation flow even if the agent's current settings change. Pre-upgrade runs with no adapter evidence may receive a new explicit user turn only after termination is proven; their old adapter and action outcomes remain unknown, and they do not gain automatic replay eligibility.

Admission validates the persisted comment's author, task, and time against every held predecessor. Retry validates the selected failed run's company, task, and agent and preserves that run's identity through admission and history loading. Duplicate Retry requests adopt the same successor. An agent-authored comment, an old queued request, or a generic system wake cannot release a hold. The source task keeps its assignee. Process ownership, active controllers, cleanup leases, pause, approval, budget, and normal execution gates still apply. Dependency-blocked interaction mode remains limited to its existing answer/triage contract.

The hold retirement, audit record, and new run commit together under the task lock. The new turn uses a fresh provider session and retains the latest user request, task history, completed work, and the interruption notice. It receives no instruction to repeat old tool calls. Later messages cannot reset the old incident's retry budget or create another automatic replacement for it.

Explicit continuation verifies local process identities for local runs. Remote runs instead require a provider termination receipt for every lease, with successful cleanup and no active ownership. This applies to both per-turn and warm native runners. A stop receipt retires only the settled cleanup owner for that exact company, run, provider, and sandbox resource, without changing its checkpoint or recorded action outcomes. Independent remote sandboxes have separate cleanup gates, including when one run owns multiple sandboxes. Successful pending-cleanup retries persist the same receipt and reconsider deferred user messages; a delivery failure never reverts successful provider cleanup. A failed checkpoint does not prevent destruction of a terminal run's isolated sandbox; busy ownership still prevents it. Missing receipts and failed cleanup retain the hold. Older providers that return no receipt remain supported but cannot authorize remote continuation. A terminal database status or a PID check on the wrong host is insufficient. No historical task is automatically awakened by this change.

Startup waits for provider plugin initialization before remote recovery and lease cleanup. The task's blocked notice offers Retry, and a refused retry shows the actual recovery hold. Each explicit user Retry can make one scoped cleanup attempt for its failed run even after automatic cleanup is exhausted. If that attempt fails, a later user Retry may try again after the provider recovers. The failed cleanup keeps the execution hold in place. Retry does not reset the automatic limit or clean up another task's leases. Provider shutdown must still be confirmed before a new conversation is admitted.

Explicit Recovery Action

Paperclip opens an explicit recovery action when the system can identify a problem but cannot safely complete the work itself.

Examples:

  • automatic stranded-work retry was already exhausted
  • a dependency graph has an invalid/uninvokable owner, unassigned blocker, or invalid review participant

The recovery action stays source-scoped by default. Stranded-task escalation is board-owned and records the cause, evidence, next action, source and return owner, routingPolicy: board_escalation_no_takeover_v1, and wake or monitor policy in the source thread/detail surface.

The board owns the recovery decision, not the source deliverable. Automatic recovery must preserve both source assignee fields. Only an explicit operator decision or applicable serious-failure policy may transfer the deliverable.

An upgrade may encounter an already-active agent-owned recovery action. Paperclip keeps that record readable and resolvable for compatibility, but periodic reconciliation does not enqueue another takeover wake from it.

Create an issue-backed recovery action only when a separate issue is the right execution object. In that fallback form, the source issue remains visible and is blocked on the recovery issue when blocking is necessary for correctness. The recovery owner must restore a live path, resolve the source issue manually, delegate real follow-up work, or record the reason the signal is a false positive.

Human Escalation

Human escalation is required when the next safe action depends on board judgment, budget/approval policy, or information unavailable to the control plane.

Examples:

  • the original owner is paused, terminated, pending approval, or budget-blocked
  • the issue is human-owned rather than agent-owned
  • the run is intentionally quiet but needs an operator decision before cancellation or continuation

In these cases Paperclip should leave a visible issue/comment trail instead of silently retrying.

14. What This Does Not Mean

These semantics do not change V1 into an auto-reassignment system.

Paperclip still does not:

  • automatically reassign work to a different agent
  • infer dependency semantics from parentId alone
  • treat human-held work as heartbeat-managed execution

The recovery model is intentionally conservative:

  • preserve ownership
  • use the cause-specific bound when the control plane lost execution continuity; deliberate waits without a target use five fingerprinted original-owner disposition repairs
  • open a board-owned recovery action when the original-owner bound is exhausted or unsafe
  • escalate visibly when the system cannot safely keep going

15. Practical Interpretation

For a board operator, the intended meaning is:

  • agent-owned in_progress should mean "this is live work or clearly surfaced as a problem"
  • agent-owned todo should not stay assigned forever after a crash with no remaining wake path
  • parent/sub-issue explains structure
  • blockers explain waiting

That is the execution contract Paperclip should present to operators.

Cancellation during native startup

Cancellation records a preparation fence while holding the run row lock. Native runtime selection checks that fence, the running status, and the current startup controller lease in the same transaction that creates the native coordinator. The native executor rechecks cancellation and terminal status when claiming the coordinator, before starting or attaching a provider.

A cancelled startup can continue from a newer authenticated user message after cleanup. The server requires either its explicit before-selection fence or an unclaimed native coordinator (zero attempts and controller generations, no controller, lease, or result). It also checks for contradictory launch/process evidence and verifies local cleanup or exact remote termination receipts. The preparer must have finished or its startup lease must have expired. A missing PID alone does not establish this proof.

The existing bounded saved-message worker rechecks this proof after restart. Admission atomically settles an unclaimed coordinator and admits one fresh turn, preserving history, unknown action outcomes, and attempt counts. Pauses, approvals, budgets, task ownership, and terminal task status still gate admission. No automatic provider replay is authorized by a cancelled startup.

Delivering queued messages after a legacy run stops

The legacy queued-message Interrupt action accepts a null targetRunId when there is no active turn. It validates the queue identity and revision under the task lock and records durable board intent to send the saved queue. A run that stops between the queue read and the click is also accepted. The server never redirects interruption to an unrelated active run. Intentional interruption does not show the global cancelled/failed run toast; the queue control supplies its own delivery feedback.

This click can authorize a fresh conversation for messages written before the prior run stopped. It preserves the original message content and authors, and retains process/lease stop proofs, task ownership, pauses, approvals, and budget checks. Queue edits and discards remain authoritative until dispatch. Dispatch revalidates the consumed queue receipt against the operator, task, agent, message, and successor run; the operator need not be the message author. Repeated delivery attempts cannot create another successor after the queue is consumed. Native same-turn steering retains its active-target contract.

Legacy finalization retries deferred input after adapter and lease cleanup. The scheduler also revisits bounded batches of stranded queues after restart or a late enqueue. Both use normal admission; an existing queued successor owns the next turn even before it acquires the task execution lock. A recovery hold does not block an undelivered user message in a durable queue. The server validates the saved comment and its author, even if the queue began as a system wake. It can then start a fresh legacy conversation after proving the old process stopped. It preserves unknown action outcomes and does not replay comments already delivered to the failed run. A plain operator Stop still requires a new user action. The successor guard is scoped to the same agent so another agent's review participation keeps its independent recovery path.

An explicit queued-message Interrupt also grants one scoped cleanup retry for the stopped run. Old ephemeral leases whose cleanup predates provider stop receipts are rechecked through the recorded provider teardown path. Retained resources and sandboxes owned by another lease are not rechecked this way. Delivery still requires the provider's verified stop receipt. Periodic queue retries do not gain extra cleanup attempts, and the queue displays the server's waiting reason while cleanup remains unresolved.

The legacy task recovery notice shows “Automatic recovery of this task stopped.” in a bordered container with Retry for a failed or timed-out run. A failed Retry shows its error in the same container. New user messages and saved undelivered messages pass normal admission independently of automatic recovery exhaustion.

Operator identity and permission for manual dispatch

A legacy queued-message Interrupt is a new instruction from the user who clicks it. The new run uses that user's execution identity, including when someone else wrote the queued messages. Message bodies and historical authors stay unchanged. The task page and pipeline conversations both permit Interrupt after the target run stops and submit the queue's current revision. Startup validates the consumed queue receipt against the new run, company, agent, task, clicking user, and delivered message IDs. Automatic retries inherit the resulting execution identity through the ordinary run identity history.

Starting an existing agent requires agent:wake, which active non-viewer board members have within their company. Both wake endpoints use this action instead of agents:create. An exact task retry also checks issue:comment on the task from the stored failed run and verifies that its assigned agent has not changed. External chat retries retain their additional conversation authorization. Ordinary board wake requests also persist the clicking user's identity, so adopting another author's queued message cannot change their execution authority. If that wake merges into an older deferred request, the same transaction updates the request's execution requester to the clicking user. Manual wake requests wait for their own run and execution identity. They do not merge into an agent's active run, with or without a task. Private agent conversations retain their owner-only wake and retry checks.

These actions do not grant permission to hire agents or change their settings. Each action during execution still checks the agent's authority and the responsible user's authority. A denied retry returns before dispatch; it does not create a new failed run or change the task's state.

Native controller restart ownership

The controller persists a newly spawned runner's process identity before waiting for provider startup. An abrupt controller exit during session opening can then recover through the same exact process-identity checks as an active turn.

Both graceful and hot restarts detach the old controller from native sessions. If shutdown begins while a provider session is opening, its eventual publication honors the pending detachment before dispatching a turn. Once detached, an old execution finalizer cannot suspend or signal the durable runner: the next controller must recover it through the authenticated ownership checks. This preserves active work and queued messages without treating a server restart as user cancellation.

Before either shutdown path exits, idle warm sessions close through their normal suspend-and-checkpoint path. Remote sessions therefore leave verified backup authority for the next controller even though their last run is already complete. Busy sessions use active-run adoption while they remain active; if a turn finishes during shutdown, its release checkpoints the session before returning instead of leaving a new idle owner behind. If checkpointing fails, the retained state continues to block unverified reuse.

Warm sandbox continuity

A warm sandbox's shared workspace binding persists independently of the experimental isolated-workspaces UI. Ordinary workspace updates remain gated; the runtime can bind only a validated shared workspace in the issue's company and project. Follow-ups can therefore reuse the same sandbox and provider session. A staged provider package is reused only after the complete expected manifest and artifact hashes verify. A missing, changed, or incompatible package must be replaced and verified before launch.

Safe native replacement may clear a Blocked status only with a durable receipt that the same failed run projected that exact status version. Explicitly reasserting Blocked or changing its blockers advances the status version, even when the displayed status is unchanged. Adding a queued comment does not change that authority. A later block also suppresses replacement at scheduled, queued, and final dispatch gates. Queued and final native replacement dispatch also re-read dependency readiness, since new dependencies need not change the displayed task status. Old blocked rows without a receipt remain held; no historical status backfill is performed.