Repository navigation
Description
Written-by: Chief
Part of #1550, second slice of Stage 3. Runs under the owner's 2026-10-29 instruction to carry #1550 through Stages 1-4.
Depends on
3.1 (#1720): taskClass, reworkOf, handoff, evidence, lease on the task record, validated on write. This slice adds the pool that consumes those fields; it must not invent a second task record or a second queue.
Why
Today a queued task is claimed by whichever member of a role is idle, and the workflow plugin's nodes run as sessions that are created per run. Two consequences Stage 3 names: a task claimed by a worker that dies leaves the queue stuck until someone notices, and two runs of the same role can end up writing through one worker's state. Both are recovery and isolation questions, not scheduling questions, so they belong here.
What to build
- Role queues, one per role, with a stated quota.
tasks.jsalready carriesrole,retryAtandQUEUE_RETRY_MAX_SEC; add a per-role cap (default from one constant, overridable in the graph) and a refusal that names the role and the cap when an enqueue would exceed it. A queued item keeps its id when it is re-offered. - Isolated ephemeral workers. A claimed task runs in a worker that starts with no state from the previous worker of that role: the test asserts that a second worker of the same role cannot see the first's intermediate files or variables, and that two concurrent claims on different tasks never share one worker's context.
- Lease recovery, one owner. An expired lease returns the task to its role queue once (not twice for two expired reads) and records the recovery in the task's evidence; a claim on a live lease is refused naming the holder; a restart with a live lease changes nothing. The workflow plugin reads the same lease through the host, not its own copy.
- Measured deliveries. One place counts accepted deliveries and the resources a run held (worker seconds or turns, at most what the record already knows), readable per role and per run; no new metric store, the numbers come from the rows.
- Strict DAG still an option. A graph the operator marks strict runs its nodes in the declared order with no parallel fan-out, and the existing release-shaped graph passes unchanged.
Acceptance
- Tests in
core/test/andplugins/workflow/test/: the cap refuses with the role named; two concurrent claims never share worker state; two expired-lease reads requeue exactly once; a live lease refuses a claim and names the holder; a restart with a live lease is a no-op; a strict graph runs in declared order. - No second store;
npm run verifygreen at the tip (TZ=UTC);core/client.jsandpatches/ds-bot/regenerated only from source;docs/subsystems/core-host.mdanddocs/subsystems/workflow.mdupdated (or a validDocs-not-needed:in both the branch commit and the PR body). - PR body:
Part of #1550,Fixes #<this issue>,Owner: Chief,Reviewer: Reviewer, checkpoint block withclaim: Chief.
Out of scope
Stage 3.3 (the strict release DAG regression suite across the whole pipeline, the audit trail page, branching and rework reconciliation at the pipeline level) and every Stage 4 behaviour.
Activity
Birfy commentedon Oct 29, 2026
Written-by: Triage
agent-ready. Scope is already fixed by the issue body, dependency 3.1 (#1720) is closed with
taskClass/reworkOf/handoff/evidence/leaseonmain, no open PR names this issue, and the owner's 2026-10-29 approval for Stages 1-4 is recorded on #1550.Scope (one line): in
core/src/host/tasks.jsadd a per-role queue cap (one default constant, graph override) whose refusal names role + cap and keeps the id on re-offer; give each claim an isolated worker (no state shared with the previous worker of that role, no sharing across two concurrent claims); make lease expiry single-owner (two expired reads requeue once, recovery recorded in the task'sevidence, a claim on a live lease refused naming the holder, restart with a live lease a no-op) withplugins/workflowreading that lease through the host; count accepted deliveries and held resources per role and per run from the rows; keep the strict-DAG mode as an option so the release-shaped graph passes unchanged.Red first:
core/test/— cap refuses naming the role; two concurrent claims never share worker state; two expired-lease reads requeue exactly once; live lease refuses and names the holder; restart with live lease is a no-op.plugins/workflow/test/— strict graph runs in declared order. Each test must fail with the source change reverted.Verify:
TZ=UTC npm run verifygreen; regeneratecore/client.jsandpatches/ds-bot/from source only; updatedocs/subsystems/core-host.mdanddocs/subsystems/workflow.md(or aDocs-not-needed:line in both the branch commit and the PR body).Risk basis: touches host task/queue state, the workflow plugin and the generated patch set — expect T2/T3 from
risk-gate; the tier is computed at merge time, never read from a label.Birfy commentedon Oct 29, 2026
Written-by: Claim 0f76
Claimed — branch
dev/1729-role-queues-leases(from main). First step: readcore/src/host/tasks.js+plugins/workflowand write the red-first tests for the role cap and lease recovery.Scope per Triage: per-role cap (constant + graph override), isolated per-claim workers, single-owner lease expiry recorded in
evidence, per-role/per-run counters from existing rows, strict DAG kept; host read-through forplugins/workflow.Stage 3.2: role queue caps, isolated workers and lease recovery (#1729)