Proposed workflow specification
Status: historical implementation design. The current service implements the workflow using the contracts and routes listed in implementation status; some design-stage names and state shapes below differ from that implementation. This chapter preserves the reasoning beneath the confirmed product choices in PLAN.md. Projects can permit automatic integration or require human authorization, and can delegate binding-rule changes to agents. The service stores bounded logs/reports; source checkpoints remain in Git remotes.
Task outcome and available work
A task represents an outcome. Its kind is code, general, objective,
agent_review, human_review, or integration. Agents normally create code or
general tasks. An objective groups required children. Review and integration
tasks are linked workflow activities, created transactionally from a submission
and the applicable project policy, with stable identities preventing duplicates.
A revert is a code task that undoes one published integration result on an
integrator-owned project; its task view carries a revert target and the
original task’s view names it in reverted_by. While the integrator computes
its candidate nobody claims or unblocks it, and a review that requests
changes on that candidate cancels the revert (see the API contract,
“Reverts”).
Persist a task lifecycle of planned, open, done, canceled, or superseded.
Expose a derived work status alongside it, so agents do not have to infer
readiness from raw records:
Human operators may cancel unowned planned or open tasks, archive tasks for
separate browsing, and restore archived tasks to the ordinary task listing.
Archiving preserves lifecycle and history. The default task endpoint excludes
archived and soft-deleted tasks before pagination; /tasks/archived is a
separate project-scoped listing. Deletion is soft and limited to canceled or
planned tasks with no attempt, dependency, objective, or workflow history.
Canceling a task also retires it from the queue: a task with no attempt,
dependency, objective, or workflow history, and no replacement, is soft-deleted;
any other canceled task is archived instead, so its history stays browsable. The
cancel response reports which with deleted or archived. Active attempts and
review/integration workflows block lifecycle changes.
| Work status | Meaning and next action |
|---|---|
planned | Outcome is recorded but not admitted to the work queue |
ready | The task can be claimed; a candidate listing grants no ownership |
in_progress | A current unexpired attempt owns this task |
waiting_review | A submitted candidate needs one or more linked reviews |
waiting_integration | Review requirements are satisfied; the linked integration task is pending |
integrating | The linked integration attempt is preparing or publishing a result |
validating | The integrated result is being checked; the deliverable is still incomplete |
blocked | An explicit dependency, decision, capability, resource, or verification issue prevents the next action |
recovery_required | An expired owner or uncertain external effect requires reconciliation |
done | This task kind’s required outcome is accepted |
canceled | Work was deliberately stopped; this does not satisfy a dependency |
superseded | A replacement/duplicate relationship closes the record; the replacement is explicit |
The response also includes structured blockers, current attempt, submission, linked activities, and exact next actions. It never uses a status string as a substitute for these facts. These statuses describe the selected task: a code task can be waiting for review while its linked review task is in progress.
Task records also carry a read-only processing object that says whether
anyone is acting on the status right now, so a list can tell a queued review
from a claimed one without opening the task. It is null unless the task is
in_progress, waiting_review or, as described below, an integrator-owned
waiting_integration. Its stage is in_progress (a live,
authorized, unexpired attempt owns the task), in_review (a required review
activity is claimed under a live lease), awaiting_reviewer (every pending
review is queued and unclaimed) or review_lease_expired (a claimed review’s
lease lapsed and needs recovery). active is true only for the first two.
holders lists the lease holder’s name, harness, workstation and
lease_expires_at; a value the service did not record is null, never a
guess. A live lease proves a claim, not that the holder’s process is running.
The dashboard animates a status icon only while active is true, labels every
stage in text, and shows holders in a tooltip that opens on hover and focus.
On a project whose integration_owner is integrator, a task that is
waiting_integration carries processing.kind integration: an additive
indicator that leaves work_status and its filters unchanged and creates no
owner, lease, claim or policy change (holders is always empty). The service
derives it from the current code submission’s newest integration result for its
exact candidate_revision; a result for another candidate, a superseded
submission or a different revision is ignored, so old evidence never makes the
task look active. Its stage is awaiting_checks (a result is pinned and no
check was reported), verification_queued (the integrator reported required
checks that are queued and none is running), verifying (at least one required
check is running), checks_passed (every required check passed and the result
awaits publication), checks_failed (a required check’s deciding run did not
pass and no newer run is going), verification_unknown (the report of queued or
running checks, or the integrator heartbeat, is more than three minutes old),
publishing (push authority is outstanding and unexpired) or
publication_unconfirmed (push authority expired before the integrator
observed the target). active is true only for verifying and publishing.
Publication ends, and the indicator disappears, when the integrator’s
observation completes the task or returns it to review. The object also names
submission_id, candidate_revision, result_id, result_revision,
result_created_at, observed_at (the integrator’s last progress report),
authority_expires_at, checks (total, passed, failed, running,
queued, pending) and up to 25 check_runs (check_name, state,
run_id, run_attempt, conclusion, started_at). A task that is blocked,
done, ready again or superseded, a legacy agent-owned integration, and a
task with no result for its current candidate have processing null; their
existing statuses (integrating, validating, recovery_required) are
unchanged. The integrator feeds the queued and running state through
POST …/integrator/check-progress; completed runs and publication come from
receipts and push authority as before.
Status is derived from authoritative records, including server-time lease
validity. The database must not rely on a periodic job to change in_progress
to recovery_required before refusing a stale update. Transactional projections
may speed dashboards but cannot grant authority or hide expired ownership.
The API does not accept arbitrary writes to derived status.
An expired current attempt or unresolved external outcome takes precedence over
ready. A task waiting for an active linked review/integration displays that
phase and retains any blockers as separate fields. No task becomes complete
merely because all owners have released their attempts.
Admission and task selection
Task admission requires a title, concrete outcome, acceptance criteria, kind, project, priority, source/provenance, and any required capabilities or resources. A code task also needs its repository/target binding. Use a checklist of explicit criteria; do not require the service to interpret arbitrary prose as executable tests. Planned tasks can hold incomplete drafts.
Admission is also budgeted. Every task records its origin: human or agent
from the principal that created it, or service when the service created it
(reverts, integrator follow-ups, re-lands and internal review/integration
tasks). A task may carry an admission_class (revert, fix_target,
deflake or refusal_fix) that marks a fix; fixes are always admitted and do
not use the budget. An agent-created task without a class is admitted only
while fewer than N agent-originated tasks were admitted in the current ISO week
(UTC, Monday 00:00 to the next Monday) in the task’s own project; the budget
is per project, and tasks of other projects do not count against it. The
6th such task in a week is still created, but as planned, and the creation
response carries an admission object with held: true and the reason; the
digest lists it under held_agent_tasks. A human releases it by editing it to
planned: false; an agent cannot, even with a task-definition grant. Human
tasks, tasks with a class and tasks an agent itself created as planned are
never held and do not use a place. N defaults to 14 and is the service setting
--agent-task-weekly-budget (COORDINATOR_AGENT_TASK_WEEKLY_BUDGET, 0 through
10000; 0 holds every unclassed agent task). The week rolls over with the clock:
the first agent task of a new ISO week is admitted again.
The fix classes (revert, fix_target, deflake, refusal_fix) skip the budget,
so an agent cannot grant one to its own task. Who may set each class:
| Class | Human or service | Agent |
|---|---|---|
revert | always | admission_evidence.result_id naming a project integration result that landed (published, already contained, or published after reopen) |
fix_target | always | result_id naming a project result with a failed check receipt (optionally narrowed by check_name), or report_id naming a fix_target integrator report of the project |
deflake | always | report_id naming a flaky integrator report of the project |
refusal_fix | always | no record to verify: only a designated principal |
canary | refused | only a designated canary principal |
An agent the operator names with --fix-class-principals
(COORDINATOR_FIX_CLASS_PRINCIPALS; empty by default) may set any fix class
without evidence. Otherwise an unbacked class is refused with a 403 and no
task is created; the agent can file the task without a class, and the budget
counts it.
The end-to-end canary (one task per host and harness per day, seven or more a
week) would otherwise use the whole budget and hold genuine agent work, so it
has its own route: the request-only admission_class canary. It is accepted
only from an agent principal the operator designates with
--canary-principals (COORDINATOR_CANARY_PRINCIPALS); any other creator is
refused with a 403 and no task. A canary task is always admitted and is not
counted against the budget, and the same principal’s tasks without the class
are budgeted normally. The canary asks for priority 0 (urgent, the highest the
service accepts), so selection hands it out before every task of priority 1 to 3.
Default priorities are urgent, high, normal, and low. Within a project, selection filters eligibility and requested task kinds/capabilities, then orders by priority, oldest-ready time, and stable ID. Ready time resets only when work actually becomes eligible again, not on a heartbeat or cosmetic edit. There is no agent-vendor preference or required scheduling model.
Agents search existing and recently closed tasks before creating new work. An optional stable external source key is unique within its declared source namespace. Similar titles produce suggestions, not automatic task identity. The service can prevent duplicate claims and repeated source imports; it cannot guarantee that separately worded outcomes never overlap.
Normal dependency edges require the prerequisite task to be done. Cancellation
and supersession produce an explicit blocker and replacement reference; they do
not silently satisfy the old edge. Authorized dependency edits retain
history. Objectives cannot complete until required children and their own
acceptance criteria are satisfied. Reject parent and dependency cycles, including
concurrent edits that would create a cycle only when combined.
Attempts and checkpoints
Each attempt belongs to one task, authenticated session, workstation, and
ownership generation. Its state is active, submitted, released, blocked,
expired, or canceled. Only an active, current, unexpired attempt can perform
ownership-dependent mutations. Historical attempts are retained.
For code work, claim first, then prepare/register the separate worktree and checkpoint the starting repository state before editing. A preparation failure releases or blocks the attempt with a reason; it does not leave an unreported reservation. Lease renewal can continue during preparation.
A checkpoint includes a short summary, current action, progress since the last checkpoint, next step, blockers, and current branch/revision/job references when relevant. Heartbeat requests need not fabricate a new progress summary. Save health time and progress time independently.
Explicit relinquishment records a final checkpoint and an outcome. A request to cancel an active task revokes service authority but retains jobs/resource holds until their actual disposition is known. Operators see the distinction between canceled work and a still-running external job.
Submission, review, and completion
Submitting a code attempt creates an immutable candidate containing the task revision, policy revision, repository/base/candidate revisions, result summary, acceptance evidence, handoff, and linked/new lessons. Artifact references include their accessibility. The submission ends the implementation attempt and admits the required review activities atomically.
Reviews become eligible from this candidate, not from the code task’s done
state. This avoids a dependency cycle. Review tasks use their own ownership,
candidate binding, and attribution. A completed review task means a decision
was recorded; its decision may be approval or changes requested. The code task
uses the decision as a guard, not merely the review task’s terminal state.
The review modes are none, agent, human, and both, with agent as the
selected default. Propose one required approval of each enabled type initially.
Human decisions require human authentication; agent review uses the separation
rules in the coordination contract.
A changes-requested decision makes a revision attempt eligible, subject to the project’s retry/escalation rules. It does not reopen the completed review task. A new code submission supersedes the old candidate and creates its own required activities; old approvals never transfer automatically. Pending obsolete activities are canceled, while active ones lose authority and retain history.
After the required approvals, a linked integration task becomes eligible under the selected integration-authorization policy. It reserves the canonical target, records the observed target and candidate, and prepares the intended result. Conflicts, a moved target, incomplete checks, and uncertain publication outcomes have distinct blockers and recovery instructions.
The integration result records its base, resulting commit/tree, publication observation, verification roster, check outcomes, and reporting actor. Required checks must apply to the exact integrated tree and configured environment. Pre-publication testing can count when tree equivalence is verified; checks whose semantics require a published/deployed state must actually run there.
The final transaction verifies the current candidate and required policy, applicable approvals, integration evidence, required checks, and ownership. It completes the integration activity and code task together, records the final handoff, and reevaluates downstream readiness. Publishing code without satisfying these checks leaves visible incomplete work. It does not automatically revert the target or authorize deployment.
General tasks complete from their own acceptance evidence and configured review, without artificial Git requirements. Objectives complete from their required children and criteria. They have no implementation worktree of their own.
Recovery and late information
Recovery is an attempt mode on the affected task, not permission to overwrite the old attempt. Claiming recovery is atomic and uses a new generation. In manual projects, an operator must release the recovery hold first. Inspection can read all retained evidence but cannot bypass reservations held by uncertain jobs.
Record one recovery disposition: resume accessible work, reconcile an already delivered result, restart with an explanation, or remain blocked. Reconciliation must satisfy the same completion guards as normal work. A commit found in Git does not itself establish passed review or verification.
Support append-only late notes and job observations from their authorized reporters after an attempt expires. They are clearly historical/unaccepted and cannot renew ownership, approve the current candidate, release another owner’s resources, or complete the task. A current recovery owner may explicitly adopt applicable evidence after verification.
Changes to requirements or policy during work
Descriptions, acceptance criteria, dependency sets, and project policy use revision checks. Cosmetic changes preserve acceptance applicability when marked as such; substantive changes require explicit reconciliation. An agent cannot erase or weaken acceptance criteria to make its own submission pass.
A project may explicitly authorize agents to change binding project rules without human approval. Each change checks the existing delegation, requires the expected policy revision, and records rationale and actor. Delegation and service credential administration are separate from editable rule text: changing a rule cannot grant its author a new administrative identity or fabricate human approval.
A new policy revision prevents new claims/submissions from silently following the old policy. Existing attempts receive a policy-changed next action and can checkpoint or relinquish safely; they must reconcile before taking a newly restricted action. Historical approvals remain tied to their original policy. The service records the authorized actor’s resolution instead of silently grandfathering or retroactively rewriting every in-progress task.