13 KiB
Native status arbitration
Native runner results do not directly mutate an issue's status. The model may report that work is done, blocked, ready for review, or yielded, but Paperclip's server remains the authority that decides and commits the resulting workflow state.
The native status pipeline is:
structured runner result
|
v
schema and terminal validation
|
v
evidence classification
|
v
pure status arbitration
|
v
transactional decision commit
|
+--> issue status/version
+--> durable side effects
+--> audit and recovery records
This separation prevents model prose from acting as a privileged status command, protects newer issue state from stale runs, and makes every decision replayable and auditable.
Inputs to finalization
The runner returns a paperclip.run_result.v1 result and a matching terminal
record. Important result fields include:
reportedWorkDisposition:done,blocked,needs_review, oryielded;completionClaim, including the contract revision, criterion claims, and remaining work;verificationclaims;- evidence references;
- an optional blocker; and
- an optional continuation.
The server also owns facts the runner cannot choose:
- the persisted completion contract;
- the run's actual terminal state;
- whether workspace finalization succeeded;
- the issue's current status and status version;
- pending approvals, interactions, and execution-policy stages; and
- the completion-authority policy recorded on the contract.
Evidence classification
classifyNativeEvidence() compares model claims with durable Paperclip
records. It recognizes these evidence families:
- run events with an authoritative control-plane evidence verdict;
- issue work products;
- approvals;
- issue-thread interactions; and
- attachments.
Each evidence reference becomes one of:
| Outcome | Meaning |
|---|---|
accepted |
A matching durable record exists and authoritatively supports the claim. |
missing |
The required claim or referenced record does not exist or is still pending. |
rejected |
The record or claim explicitly contradicts completion. |
unverifiable |
A record exists, or a string was supplied, but it is not authoritative evidence. |
For example, a model-authored reference such as task-response is not trusted
merely because it looks descriptive. Likewise, the model's own
run.result.proposed event is a claim, not independent proof.
The classifier produces a NativeEvidenceAssessment containing:
- contract-revision validity;
- criterion claim and evidence outcomes;
- verification claim and evidence outcomes;
- accepted, missing, rejected, and unverifiable references;
- blocking remaining work;
- normalized blocker or continuation data; and
- pending attention requests.
The classifier does not update the issue.
Completion authority
The persisted completion contract controls how a done claim may be accepted.
Durable-evidence completion
The strongest completion path requires all of the following:
- the runner reports
done; - the objective is satisfied;
- every contract criterion has accepted durable evidence;
- every verification has accepted durable evidence; and
- no remaining work blocks completion.
This produces completion_contract_satisfied.
Low-risk claim-policy completion
Ordinary issue completion changes Paperclip workflow state, but it does not by
itself authorize deployments, spending, secret access, approvals, or arbitrary
API calls. Default native completion contracts therefore use low-risk
agent_claim_policy authority.
Under that policy, a result can complete the issue when:
- it reports
done; - its contract revision matches;
- every contract criterion is claimed
satisfied; - every verification is claimed
passed; and - no remaining work blocks completion.
This produces completion_claim_policy_accepted. Independently governed tools
and effects still enforce their own authorization and approval rules.
Decision order
arbitrateNativeStatus() is a pure function. It evaluates higher-authority
conditions before model disposition:
| Condition | Status decision | Important effects/reason |
|---|---|---|
Issue is already done or cancelled |
Preserve | terminal_status_preserved |
| Workspace finalization failed | Preserve | Record a retryable finalization error |
| Run was cancelled | Preserve | Release run resources |
| Run failed | Preserve | Schedule recovery |
| Approval, interaction, or execution stage is pending | in_review |
Materialize/bind the governance gate and notify its owner |
| Completion satisfies its authority policy | done |
Release checkout |
| Runner reports a concrete attention request with a reviewer and decision | in_review |
Bind the requested reviewer |
Runner reports needs_review without a decision, or an incomplete completion claim |
Keep work with the agent | No automatic human approval; at most one corrective continuation, then a visible recovery action |
| Runner reports a task-wide blocker | blocked |
Persist blocker owner and unblock action |
| Runner reports a current-track blocker | in_progress |
Enqueue another productive track |
Runner reports yielded with a valid continuation |
in_progress |
Enqueue the declared continuation |
| Completion evidence is incomplete and continuation is forbidden | Preserve | Record a finalization error and named next action |
| Completion evidence is otherwise incomplete | in_progress |
Enqueue a bounded, idempotent continuation |
The output is a NativeStatusDecision containing:
- the arbiter policy version;
statusActionandtoStatus;- a stable reason code;
- an optional unblock descriptor; and
- declarative side effects.
The pure arbiter performs no database or network writes.
Transactional decision commit
commitNativeStatusDecision() applies the decision against authoritative issue
state. It uses the issue's prior status, status version, and prior decision ID
as compare-and-swap inputs. If another actor changed the issue first, the commit
raises NativeStatusRaceError; finalization reloads current state, reassesses,
and retries a bounded number of times.
Within the transaction, the committer:
- validates that the assessment and issue bindings still match;
- records the status decision and reason;
- updates the issue status and increments its version when required;
- materializes declared effects;
- writes an effect ledger with deterministic idempotency keys;
- updates the native-finalization coordinator; and
- persists audit activity.
After commit, activity publications are emitted. Reconciliation may redeliver a pending effect, but it resumes the recorded ledger decision; it does not ask the model or arbiter to invent a new decision.
Durable side effects
Depending on the decision, materialized effects may include:
- an idempotent agent wake request;
- an issue-thread interaction;
- a reviewer binding or owner notification;
- a persisted blocker and unblock action;
- a scheduled retry or recovery action;
- a delegated child issue;
- checkout/resource release; or
- finalization/reconciliation records.
Effect rows bind company, issue, decision, target, ordinal, delivery state, and idempotency key. This is what makes a status transition with follow-up work recoverable after a process crash.
Governance precedence
A model cannot bypass a pending governance gate by reporting done. Before
completion is considered, finalization checks:
- an active execution-policy stage;
- a pending issue-thread interaction; and
- a pending or revision-requested approval linked to the issue.
If one exists, the issue goes to in_review and the durable gate remains the
path forward.
Failure and recovery behavior
Status finalization is coordinated by native_run_finalizations. Important
phases include observation, workspace finalization, assessment, arbitration,
commit, and retryable or terminal failure.
Examples:
- a workspace-finalization failure preserves the claim and records a retryable error rather than falsely completing the issue;
- a failed provider run preserves partial evidence and schedules recovery;
- a status-version race causes bounded reassessment against current issue state; and
- a materialization failure records the failed phase and next retry time rather than silently dropping the side effect.
Policy upgrades
The policy version on an assessment is audit metadata. New runs use the current rules. A version change alone does not reassess an old run, change task status, or ask a person to review completion. New evidence and explicit status changes still use the existing reconciliation paths.
Reconciliation also withdraws pending review cards created solely by the old policy-version check. It restores the previous status only if that exact decision and status version are still current and no other review gate is pending. A later user or agent decision takes precedence. The old assessments and decisions remain in the audit history; cleanup does not accept or reject the agent's work.
Diagnosing an unexpected status
Start with the terminal heartbeat run and inspect:
resultJson.nativeResult.reportedWorkDisposition;- completion-claim contract revision and criterion statuses;
- verification statuses and evidence references;
resultJson.assessmentIdanddecisionId;resultJson.authoritativeDecision;resultJson.issueStatusBeforeandissueStatusAfter;finalizationPhaseandworkspaceFinalizeStatus; and- pending approvals, interactions, execution stages, blockers, or continuations on the issue.
Common patterns:
doneclaim +in_progressdecision: evidence/claim policy did not accept completion, or blocking work remained;doneclaim +in_review: a governance gate took precedence;- successful run + unchanged status + retryable finalization: workspace or status-effect commit failed;
- repeated
issue_continuation_neededruns: the issue remains open without a converging completion or durable wait path; and - terminal issue unchanged by a stale run: terminal-state preservation or status-version race protection worked as designed.
Primary implementation locations
server/src/services/native-runtime/evidence-classifier.ts— validates claims against durable records.server/src/services/native-runtime/status-arbiter.ts— pure policy and decision table.server/src/services/native-runtime/status-decision-committer.ts— CAS commit, effect materialization, ledger, and audit.server/src/services/native-runtime/native-run-finalizer.ts— orchestrates assessment, governance checks, arbitration, bounded race retry, and result projection.server/src/services/native-runtime/completion-contracts.ts— creates and versions default native completion contracts.server/src/services/native-runtime/native-finalization-reconciler.ts— resumes interrupted finalization without re-inventing committed decisions.server/src/services/recovery/service.ts— repairs open issues that finish without a live or durable wait path.
See also
durable-continuation-scheduler.md for
the scheduler and recovery behavior that follows an in_progress decision.
Explicit completion reviews
Ordinary task completion uses the agent's structured done claim under the
contract's low-risk claim policy. Unknown evidence references remain diagnostic
information; they do not create human approval requirements. Cancellation,
newer task state, unresolved dependencies, and explicit governance still win.
Paperclip no longer creates a generic "Native completion review" because a
report is incomplete, verification failed, or the agent says needs_review.
A new review interaction requires an explicit attention request naming the
reviewer's responsibility and the decision. The card displays that request.
Waiting for CI remains agent work, not a human completion approval.
The native runner returns current approval/dependency constraints to the agent
when it calls paperclip_finish. An empty needs_review report without an
existing gate is rejected with instructions to correct it. The final reply must
explain any required user action and link to the relevant task or approval.
The tool acknowledges receipt, not a premature status commit: final status is
committed only after the provider turn and workspace finalization settle.
On upgrade, bounded cleanup withdraws only unanswered, system-created fallback cards proven by their decision/effect ledger, original prompt/target, empty attention request list, and low-risk claim policy. Explicit or answered reviews and stronger completion policies are preserved. Withdrawal has audit history and retires chat actions. Reconciliation reassesses only the current successful run's result, with the same task status/version and completion contract and no newer execution owner. It applies normal governance and dependency checks and appends a decision; it never marks every affected task done blindly. A persisted withdrawal marker makes restart between cleanup and reassessment retryable.