Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/patch-work-queue-obsolete-contracts.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

97 changes: 51 additions & 46 deletions .github/aw/work-queue.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ description: Git-backed work queue agent instructions.

`tools.work-queue` schedules DAGs and Claim-scoped effects.
`work-queue.jsonl` is authoritative; V3 omits storage selectors. Issues/PRs are dependencies.
For issue-backed WorkQueueOps: [WorkQueueOps](../../docs/src/content/docs/patterns/workqueue-ops.md).
For issue-backed WorkQueueOps: [deployment](../../docs/src/content/docs/patterns/workqueue-ops.md).

## Select the role

- **Observer:** explain only; never submit, dispatch or finish Work.
- **Producer/dispatcher:** submit trusted plans/request bounded pool work;
queue authority grants no arbitrary resource writes.
- **Producer/dispatcher:** submit trusted, bounded plans/request pool work;
no arbitrary resource writes.
- **Worker:** require compiler-supplied version-3 `claims`; never override
reserved `work_queue_assignment` or caller context.

Trust roles, not snapshots: AW authenticates run/workflow/revision;
AW authenticates run/workflow/revision;
reruns cannot inherit attempt 1. Absent branches are empty;
reject malformed/unsupported logs.

Expand All @@ -34,32 +34,31 @@ Dispatchers require `tools.work-queue: true`, a worker allowlist, bounded
native runs; ignore moved `target-ref`.

`aw.json` `work_queue`: concurrency, pending limits, retries, pools, fairness,
Issues. Defaults: weighted-priority, concurrency 16,
pending 4,096, singleton assignments, three attempts, 30-second backoff.
Submission initializes Policy/Work. Trusted submit/dispatch install pools/profiles;
Issues. Defaults: weighted-priority, concurrency 16, pending 4,096,
singleton assignments, three attempts, 30-second backoff.
Submission initializes Policy/Work. Only trusted submit/dispatch install pools/profiles;
workers, observers, previews and accepted-request recovery never install.
New workers require default-revision
AW source/contract verification and active registration.
New workers require default-revision AW source/contract verification and active registration.
`PoolInstall.config_ref` records provenance, not authority.
Preserve installed profiles/limits/epoch.
Standalone seeding is unsupported; AW/Actions authorize submissions.
Quiesce economic/authority changes; apply with
`policy --from-config --epoch EPOCH`. Config edits never rewrite active state.
Quiesce economic/authority changes; apply: `policy --from-config --epoch EPOCH`.
Config edits never rewrite active state.
Never expose queue-write credentials to agents or snapshot MCP. Repository access rules are GitHub's responsibility.
See [deployment](../../docs/src/content/docs/patterns/workqueue-ops.md#deploy-a-native-queue).

## Mirror admitted Work with Issues

`aw.json` `work_queue.issues: true` mirrors admitted Work with purple `work` /
`work:<status>` labels. `label` customizes both prefixes; `title_prefix` defaults
to `[work queue]`; `orphaned_after_days` defaults to 30. Titles/summaries show
12-character Work IDs; bodies use full IDs.
Protected AW hooks alone project admissions/Claims. Immutable `backing_issue`
binds one Work per Issue. Agents never write mirrors; human edits never establish
`aw.json` `work_queue.issues: true` mirrors admitted Work: purple `work` /
`work:<status>` labels. `label` customizes both prefixes. Defaults: `title_prefix` =
`[work queue]`, `orphaned_after_days` = 30. Titles/summaries: 12-character Work IDs;
bodies: full IDs.
Only protected AW hooks project admissions/Claims. Immutable `backing_issue`
binds one Work/Issue. Agents never write mirrors; human edits never establish
Results. Pre-existing Issues require exact installed `backing_issues` grants.
Only admission-time `completion_policy` closes verified non-PR results.
Maintenance reconciles at most 256 same-repository mirrors/run from the checked
ledger and flags aged orphan Issues for review, leaving them open. Keep uncertain
ledger; flag aged orphan Issues for review without closing. Keep uncertain
writes pending; never recreate mirrors or repair untracked Issues. Recovery:
`work-queue sync-issues --request-id ID`.
Upgrade closed-schema readers. See
Expand All @@ -71,68 +70,74 @@ events; disabling removes it.

- Read immutable snapshots; stale predictions cannot override Policy.
Submit bounded, secret-free plans within scheduling limits.
- Request a pool prefix with `work_queue_dispatch_next` (`pool`, `max_claims`,
- Request prefixes: `work_queue_dispatch_next` (`pool`, `max_claims`,
`max_dispatches`). Never choose winners/targets or use scalar dispatch.
- Trusted processing refreshes the ledger and commits a compatible fair prefix.
- Trusted processing refreshes the ledger and commits a fair compatible prefix.
CAS losers discard tentative choices/charges and recompute.

ESLint/daily-report/conformance agents only explain staged plans.
Trusted controls validate batches; empty dispatcher intents fail.
Unassigned dispatchers cannot emit `noop` or `report_incomplete`.

## Execute original Claims
## Execute Claims

- Process only the assignment's original Claims and stored plans. Scope every
safe output and finish intent to one original Claim.
- Process only assigned original Claims/stored plans. Scope every safe output
and finish intent to one original Claim.
- Omit `claim_handle` only for an originally single-Claim assignment.
Multi-Claim assignments require it on every message even after others
Multi-Claim assignments require it on every message even after siblings
close. Reject malformed, null, foreign or conflicting selectors.
- Finish members with `work_queue_claim_finish`, using
`outcome: "completed"` or `"cancelled"`. Missing finish authorizes no effects;
valid siblings settle independently.
- Retain Work with `outcome: "completed", keep_open: true` (default: false;
- Retain Work: `outcome: "completed", keep_open: true` (default: false;
invalid with cancellation). Preserve both on retries. Verified delivery permits
another fair Claim, not successor release/backing Issue closure.
another fair Claim, never successor release/backing Issue closure.
Pending/failed delivery blocks Claims; never rerun uncertain effects.
- Default to one Claim; batch compatible Work with reusable setup. Native
- Default: one Claim; batch compatible Work with reusable setup. Native
batch conclusions are not per-Work Results.
- Treat finish as an intent: trusted processing publishes Completion before
- Finish is an intent: trusted processing publishes Completion before
scoped effects and Result only after independently verified delivery.
- Beyond built-in safe outputs, declare `safe-outputs.claim-adapters`
- Beyond built-ins, declare `safe-outputs.claim-adapters`
([reference](safe-outputs-runtime.md)); each adapter binds one effect-type to
an independently verified result, never job success alone.
independently verified results, never job success alone.

`<mcp-clis>` takes one JSON argument. `uninitialized` plus null SHA is empty.
Policyless ledgers fail; workers require Policy; `status: "staged"` is no grant.
`<mcp-clis>` takes one JSON argument. `uninitialized` + null SHA is empty.
Policyless ledgers fail; workers require Policy; `status: "staged"` grants nothing.

## Dependencies and recovery

Require fresh Issue completed-state/PR merge evidence. Predecessors consume no
Claims; successors wait for predecessor Results.
Claims; successors await predecessor Results.

Lost responses, dispatcher cancellation/deadlines never prove nonlaunch/termination.
Retain reservations until exact evidence. Never rerun uncertain effects after
Completion; bounded verification yields Result/DeliveryFailure. Compatible
Lost responses, cancellation or deadlines never prove nonlaunch/termination.
Retain reservations until exact evidence; never rerun uncertain effects after
Completion. Bounded verification yields Result/DeliveryFailure. Compatible
deployments preserve obligations, debt, Results, frozen assignments and explicit
`execution_ref` pins. Unavailable/incompatible workers pause affected Work only.
`execution_ref` pins. Unavailable workers pause affected Work only. Scheduled
maintenance terminally cancels unclaimed, unpinned Work with admission/approved-active-worker
contract mismatch: `WorkCancellation`, operation `version: 1`, reason
`worker_contract_obsolete`. Current-time expiration excludes elapsed Work;
publication rechecks eligibility. Preserve delivery-barrier Work. Version-3
history lacking operation version retains reason-only semantics, including
compatible/pinned cancellations.
Quiesce economic Policy changes. Reject unsupported protocols/scalar assignments.
Retries/checkpoints preserve submission identity; never delete queues to retry admission.

## Load details only when needed

- Operator commands, TUI and diagnostic artifacts:
- Commands, TUI, diagnostics:
[queue reference](../../docs/src/content/docs/reference/work-queue.md).
Cancellation terminates Work, not workers; reconcile separately.
`gh aw work-queue --repo OWNER/REPO stats --json`. `dispatch-next` grants
reservations, never launches; use the authorized dispatcher.
reservations, never launches; use authorized dispatchers.
- Destructive: `gh aw work-queue clear --reason CODE [--dry-run | --hard]`
requires repo maintain/admin, forbids CI, and requires interactive confirmation
of the exact snapshot preview; no bypass. `--hard` replaces the ledger,
forgetting Work/Claim identities, retry history and fairness debt. Admission/grants
must already be paused, without open Claims/pending deliveries.
requires repo maintain/admin, forbids CI, requires interactive confirmation
of exact snapshot previews; no bypass. `--hard` replaces the ledger,
forgetting Work/Claim identities, retries and fairness debt. Pause admission/grants
first, without open Claims/pending deliveries.
See [hard reset](../../docs/src/content/docs/reference/work-queue.md#hard-reset).
- Daily report rotation and Claims:
- Daily-report rotation/Claims:
[portfolio example](../../docs/src/content/docs/gallery/daily-report-portfolio.md)
and [shared worker instructions](../workflows/shared/daily-report-worker.md).
and [worker instructions](../workflows/shared/daily-report-worker.md).
- Contracts: [specification](../../docs/src/content/docs/specs/work-queue-specification.md#91-implementation-coverage-and-remaining-requirements).
- Models/fixtures/bounded verification: [formal reference](../../specs/work-queue/README.md).
- [Formal reference](../../specs/work-queue/README.md).
13 changes: 12 additions & 1 deletion actions/setup/js/reconcile_work_queue_run.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const { lifecycleEvidence, releaseAssignment, reconcileQueue } = require("./work
const { isStagedMode } = require("./safe_output_helpers.cjs");
const { readQueueMetadata } = require("./work_queue_read_retry.cjs");
const { ERR_WORK_QUEUE_RECONCILIATION } = require("./error_codes.cjs");
const deploymentControl = require("./work_queue_deployment_control.cjs");

const reconciliationError = message => {
const error = new Error(`${ERR_VALIDATION}: ${message}`);
Expand Down Expand Up @@ -113,6 +114,16 @@ async function main(options = {}) {

async function maintenance(options = {}) {
const configured = { ...options, context: options.context || global.context, githubClient: options.githubClient || global.github, core: options.core || global.core };
let obsolete;
let obsoleteFailed = false;
try {
obsolete = await deploymentControl.reconcileObsoleteWork(configured);
log.diagnostic("maintenance.obsolete.complete", { cancelled: obsolete.cancelled });
} catch (error) {
obsoleteFailed = true;
log.failure("maintenance.obsolete.failed", error, true);
configured.core?.warning("Work queue obsolete-work reconciliation failed; core recovery will continue. Inspect safe API diagnostics and the checked ledger before retrying maintenance.");
}
const result = await reconcileQueue({ ...configured, requestCancellation: false, expireUnverified: true });
const released = result.results.filter(entry => entry.released).length;
const unresolved = result.results.filter(entry => ["launch_unresolved", "run_binding_conflict"].includes(entry.state) || Object.values(entry.delivery?.claims || {}).some(claim => claim.reason === "verification_unresolved")).length;
Expand All @@ -135,7 +146,7 @@ async function maintenance(options = {}) {
log.diagnostic("maintenance.projection.complete", { pending: pending.length });
if (unresolved) throw reconciliationError("work_queue_maintenance_reconciliation_unresolved");
if (pending.length && !options.deferIssueWarning) configured.core?.warning("Work queue transitions are committed; Issue synchronization remains pending. Recover the exact terminal requests with work-queue sync-issues --request-id.");
return { ...result, issue_sync_pending: pending };
return { ...result, obsolete_work_cancelled: obsolete?.cancelled ?? null, obsolete_work_reconciliation_failed: obsoleteFailed, issue_sync_pending: pending };
}

module.exports = { main, maintenance };
Loading
Loading