Skip to content

feat: add worker execution state#234

Merged
devkade merged 4 commits into
devfrom
feat/issue-196-worker-execution
May 18, 2026
Merged

feat: add worker execution state#234
devkade merged 4 commits into
devfrom
feat/issue-196-worker-execution

Conversation

@devkade
Copy link
Copy Markdown
Owner

@devkade devkade commented May 18, 2026

Summary

  • Adds phase-3 worker execution domain state for claimed TaskGraph tasks.
  • Adds worker readiness nonce recording, claimed-task dispatch, heartbeat refresh, stale-heartbeat marking, structured worker report capture, and evidence-gated completion from worker reports.
  • Extends runtime-state worker statuses for cleanup-released and closed terminal states and updates README runtime-boundary documentation.

Linked issue

Closes #196

Problem

Issue #196 asks for the MVP worker execution boundary: ready/claimed tasks should dispatch to ready workers, worker heartbeat/readiness should be modeled, structured reports should provide evidence, and task completion should be gated by evidence.

Before this PR, the domain had claim/lease and basic worker heartbeat helpers, but no first-class execution state connecting claimed tasks, ready workers, dispatch records, structured worker reports, and evidence-gated completion.

Options considered

  1. Wire phase 3 directly into local tmux/worktree worker substrates.
    • Pros: closest to live execution.
    • Cons: high blast radius and mixes adapter behavior into a runtime contract slice.
  2. Add a domain-only WorkerExecutionState contract around claimed tasks and worker reports.
    • Pros: satisfies the MVP execution semantics while staying adapter-neutral and testable.
    • Cons: live substrate integration remains a follow-up slice.
  3. Only extend RuntimeState worker schema.
    • Pros: very small diff.
    • Cons: does not prove dispatch/report/evidence semantics.

Selected approach

Selected option: 2, with a small RuntimeState status alignment.

Why this one: it keeps phase 3 focused on the execution contract. The existing local substrate can later project into these helpers without changing task ownership or evidence semantics.

Implementation by file/surface

  • src/domain/task-graph.ts
    • Adds WorkerExecutionState, WorkerTaskDispatch, and WorkerTaskReport.
    • Extends WorkerRuntimeRef with an optional readiness nonce.
    • Adds recordWorkerReady() and recordWorkerHeartbeat().
    • Adds dispatchClaimedTask() to require a ready worker, optional matching readiness nonce, matching active claim token, and claim worker ownership before moving a task to in_progress and the worker to busy.
    • Adds captureWorkerReport() to require a prior dispatch, summary, and evidence refs for completed reports; completed reports move tasks to verifying and workers to completed-retained.
    • Adds completeTaskFromWorkerReport() to complete only from a completed report with evidence refs and then mark the worker retained or safe-to-close.
    • Adds markMissingHeartbeats() for heartbeat timeout projection to unhealthy.
  • src/domain/runtime-state.ts
    • Allows persisted worker statuses cleanup-released and closed in addition to existing phase-3 states.
  • test/task-graph.test.ts
    • Adds a two-independent-task smoke fixture that claims both tasks, records worker readiness nonces, dispatches both in parallel, rejects a nonce mismatch, refreshes heartbeat, rejects empty completed reports, captures evidence, completes from the report, and marks missing heartbeat stale.
  • test/runtime-state.test.ts
    • Covers persisted closed and cleanup-released worker states.
  • README.md
    • Documents worker dispatch state, heartbeat/staleness transitions, structured worker reports, and WorkerExecutionState in the graph-execution boundary.

Why this fixes it

A claimed task can now be dispatched only to the worker that owns its active claim. Worker readiness can carry a nonce-equivalent proof. Heartbeats update runtime liveness and missing heartbeats project to unhealthy. Structured reports are captured only after dispatch, and completed reports require evidence refs before the task can move through verifying to completed.

QA / Verification

  • npm ci — pass; installed dependencies for fresh worktree.
  • npm test -- test/task-graph.test.ts — pass; package script ran full suite (533 tests, 522 pass, 11 skipped).
  • npm run check — pass.
  • npm run check:unused — pass.
  • npm run quality:budgets — pass with configured non-failing code_smells warning.
  • npm run verify — pass (533 tests, 522 pass, 11 skipped; then check, unused check, quality budgets).
  • git diff --check — pass.

Anomalies observed

  • npm test -- test/task-graph.test.ts still runs the full suite because the package script includes test/*.test.ts before forwarded args.
  • Node emitted existing [DEP0205] module.register() deprecation warnings during tests.
  • npm run quality:budgets retains the existing non-failing warning: code_smells=60 vs target <=20.

Risks / Follow-up

  • This PR intentionally does not launch tmux/worktree workers or persist event envelopes; it creates the adapter-neutral execution contract needed by that integration.
  • captureWorkerReport() stores completed task evidence and moves the task to verifying; completeTaskFromWorkerReport() remains the explicit evidence-gated completion step.

kapi-agent review expectations and current-head merge gate

  • Current head: 76788d3373238468209ad40dfc908fa5f8e6bb64.
  • Changed-line count: 178 additions+deletions against origin/dev (172 insertions, 6 deletions), under the review-size gate.
  • kapi-agent should verify claimed-task dispatch ownership, readiness nonce checking, report evidence gating, heartbeat stale projection, runtime-state status alignment, and README alignment before merge.

@devkade
Copy link
Copy Markdown
Owner Author

devkade commented May 18, 2026

@kapi-agent review

Revision explanation for current head 76788d36fb05edab5be6938e48ee6ef5bd817786:

What changed:

  • Added phase-3 domain worker execution state: dispatch records, structured worker reports, readiness nonce recording, heartbeat refresh, stale heartbeat projection, and evidence-gated completion from reports.
  • Extended persisted runtime worker statuses with cleanup-released and closed.
  • Added regression coverage for two independent claimed tasks dispatching through ready workers, nonce mismatch rejection, heartbeat update, empty completed-report rejection, report capture, completion from report evidence, and stale heartbeat projection.
  • Updated README graph-execution boundary wording for worker dispatch/report state.

Why this closes the issue:

  • WorkerState is defined/persistable and now includes the terminal cleanup statuses requested by phase 3.
  • Claimed tasks dispatch only to a ready worker that owns the matching active claim token.
  • Worker readiness can carry a nonce-equivalent proof.
  • Heartbeat is tracked and missing heartbeat marks active workers unhealthy.
  • Structured worker reports are captured and completed reports require evidence refs.
  • Tasks move through in_progressverifyingcompleted only with report evidence.
  • Completed-retained and safe-to-close remain distinct.
  • The test fixture executes two independent claimed tasks through parallel dispatch records.

Verification:

  • npm ci — pass.
  • npm test -- test/task-graph.test.ts — pass; package script ran full suite (533 tests, 522 pass, 11 skipped).
  • npm run check — pass.
  • npm run check:unused — pass.
  • npm run quality:budgets — pass with configured non-failing code_smells warning.
  • npm run verify — pass.
  • git diff --check — pass.

@kapi-agent
Copy link
Copy Markdown

kapi-agent Bot commented May 18, 2026

kapi-agent review completed

The formal GitHub PR review and required check were submitted separately. This request comment is kept concise to avoid duplicating the full review body.

kapi-agent request lifecycle:

  • Status: COMPLETED
  • Head: 76788d337323
  • Formal review event: REQUEST_CHANGES
  • Review API status: 200
  • Required check API status: 201

@devkade
Copy link
Copy Markdown
Owner Author

devkade commented May 18, 2026

@kapi-agent review

Correction: the current PR head is 76788d3373238468209ad40dfc908fa5f8e6bb64.

Please review against that head. Verification remains:

  • npm ci — pass.
  • npm test -- test/task-graph.test.ts — pass; package script ran full suite (533 tests, 522 pass, 11 skipped).
  • npm run check — pass.
  • npm run check:unused — pass.
  • npm run quality:budgets — pass with configured non-failing code_smells warning.
  • npm run verify — pass.
  • git diff --check — pass.

Copy link
Copy Markdown

@kapi-agent kapi-agent Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kapi-agent review

Verdict: REQUEST_CHANGES

Blocking issues

  • src/domain/task-graph.ts: captureWorkerReport() accepts any report matching a historical dispatch, but it does not verify that the reported claim is still the task’s active, unexpired claim at reportedAt.

    This means a stale worker report can mutate the graph after the claim has expired or been recovered by another worker. completeTaskFromWorkerReport() later calls completeTask() and may fail, but by then captureWorkerReport() has already moved the task to verifying/failed/repair_required/blocked, copied evidence refs, and updated the worker state.

    Suggested fix: in validateWorkerReport() or captureWorkerReport(), look up the current task and call the existing active-claim validation against report.claimToken and report.reportedAt; also ensure the claim still belongs to report.workerId. Add regression coverage for an expired/recovered claim report being rejected without changing task/worker/report state.

Warnings / risks

  • src/domain/runtime-state.ts: RuntimeTaskStatus still lacks "in_progress" while TaskStatus now uses "in_progress" as the dispatch state. If runtime-state tasks are expected to persist/project dispatched graph tasks, parsing that state will fail. If these schemas are intentionally separate, consider documenting that boundary or adding a test proving no projection path requires "in_progress".

  • src/domain/task-graph.ts: readiness nonce enforcement is optional at dispatch time. That may be intentional for non-nonce substrates, but the README says readiness requires a nonce-equivalent proof. If nonce-backed readiness is mandatory for this phase, dispatch should fail when a ready worker has a nonce and the request omits it.

Suggestions

  • Add tests for stale/expired worker reports and recovered-claim reports.
  • Consider preventing duplicate dispatch records for the same active claim unless there is a deliberate redispatch/retry model.
  • Consider validating non-empty workerId and non-empty readiness nonce inputs consistently with other domain text validation.

Looks good

  • The worker execution state is kept domain-only and adapter-neutral, which matches the stated phase-3 scope.
  • Dispatch checks worker readiness, claim token validity, and worker ownership before moving a task to in_progress.
  • Completed reports require summary and evidence refs before task verification/completion can proceed.
  • Runtime worker status alignment for cleanup-released and closed is straightforward and covered by tests.
  • README updates match the new worker dispatch/report boundary at a high level.

Verification notes

  • Verifier gate status: PASS — npm ci && npm run verify exited 0.
  • Size gate status: PASS — 178 changed lines, below the configured 200-line review threshold.
  • Revision-explanation status: not required for this first kapi-agent review; explanation was present.
  • Ilchul review harness: PASS as gate evidence — STANDARD risk, neutral conclusion, no blocking findings.
  • Local/CI evidence in PR body includes full test/check/unused/budget verification and targeted task-graph/runtime-state coverage, but the stale report after expired/recovered claim case appears uncovered.

Engine: pi

@devkade
Copy link
Copy Markdown
Owner Author

devkade commented May 18, 2026

@kapi-agent review

Revision explanation for current head b9851f955874c6118f311e04dc97a8a76a4852f9.

Changes since the requested-changes review:

  • captureWorkerReport() now validates the report against the task's current active claim at reportedAt before mutating graph/worker/report state.
  • Worker report validation now rejects expired claim reports and reports whose claim token was recovered/replaced by another active claim.
  • Worker report validation also confirms the active claim still belongs to report.workerId.
  • Added regression coverage proving expired/recovered stale reports throw and leave task status, worker status, and reports unchanged.
  • Added RuntimeTaskStatus support for in_progress, so runtime-state can persist/project dispatched graph tasks.
  • Strengthened readiness nonce behavior: if a ready worker has a readiness nonce, dispatch must provide the matching nonce; omission now fails.
  • Added duplicate dispatch rejection for the same active claim token.
  • Added blank workerId / blank readiness nonce validation for recordWorkerReady().

Verification after fixes:

  • npm run check — pass.
  • npm run check:unused — pass.
  • npm test -- test/task-graph.test.ts — pass; package script ran full suite (534 tests, 523 pass, 11 skipped).
  • npm run quality:budgets — pass with existing non-failing code_smells=60 warning.
  • git diff --check — pass.
  • Current diff size: 5 files changed, 198 insertions(+), 8 deletions(-), below the review-size gate.

@kapi-agent
Copy link
Copy Markdown

kapi-agent Bot commented May 18, 2026

kapi-agent review completed

The formal GitHub PR review and required check were submitted separately. This request comment is kept concise to avoid duplicating the full review body.

kapi-agent request lifecycle:

  • Status: COMPLETED
  • Head: b9851f955874
  • Formal review event: REQUEST_CHANGES
  • Review API status: 200
  • Required check API status: 201

Copy link
Copy Markdown

@kapi-agent kapi-agent Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kapi-agent review

Verdict: REQUEST_CHANGES

Blocking issues

  • Revision explanation gate failed. This PR was updated after a prior kapi-agent requested-changes review, but the configured review gate reports that no recognized current-revision explanation was found. Per policy, I cannot approve until the author provides a recognized review response explaining what changed since the prior kapi-agent feedback and why those changes close it.

Warnings / risks

  • None blocking from the inspected code. The prior stale-report mutation issue appears addressed in src/domain/task-graph.ts by validating the report against the task’s current active claim and worker ownership before mutating state.
  • markMissingHeartbeats() marks all stale workers unhealthy regardless of current worker state. That may be intended for this domain projection, but future integration should ensure terminal retained/closed workers are not accidentally reclassified if passed into this helper.

Suggestions

  • Add a focused assertion in the recovered stale-report test that worker state and reports remain unchanged after the recovered-claim rejection as well, matching the expired-claim branch.
  • Consider documenting whether heartbeat staleness should apply to terminal worker states once the runtime projection is wired into adapters.

Looks good

  • captureWorkerReport() now calls validateWorkerReport() before any graph, worker, or report mutation.
  • validateWorkerReport() checks:
    • timestamp validity,
    • non-empty summary,
    • evidence refs for completed reports,
    • current active unexpired claim token at reportedAt,
    • claim ownership by report.workerId,
    • matching prior dispatch.
  • RuntimeTaskStatus now includes in_progress, aligning runtime-state persistence with the task graph dispatch state.
  • Tests cover dispatch nonce rejection, heartbeat update, report evidence gating, completion from reports, stale heartbeat projection, and stale expired/recovered report rejection.
  • README updates are aligned with the new worker dispatch/report execution boundary.

Verification notes

  • Verifier gate status: PASS — npm ci && npm run verify exited 0.
  • Size gate status: PASS with semantic review required — 206 changed lines, mostly bounded source/test/docs changes around worker execution state.
  • Ilchul review harness gate: PASS — STANDARD risk, neutral/comment verdict, no blocking findings.
  • Revision-explanation status: FAIL — required now, found false by the configured gate.
  • Local inspected files: src/domain/task-graph.ts, src/domain/runtime-state.ts, test/task-graph.test.ts, test/runtime-state.test.ts, README.md.

Engine: pi

@devkade
Copy link
Copy Markdown
Owner Author

devkade commented May 18, 2026

@kapi-agent review

Revision explanation for current head b9851f955874c6118f311e04dc97a8a76a4852f9:

What changed:

  • src/domain/task-graph.tscaptureWorkerReport() now validates the report against the task's current active claim at reportedAt before mutating graph, worker, or report state.
  • src/domain/task-graph.ts — worker report validation now rejects expired claim reports, recovered/replaced claim token reports, and claim ownership mismatches.
  • test/task-graph.test.ts — added regression coverage for expired/recovered stale reports being rejected while task status, worker status, and reports remain unchanged for the expired path.
  • src/domain/runtime-state.ts / test/runtime-state.test.ts — added RuntimeTaskStatus support and parse coverage for in_progress.
  • src/domain/task-graph.ts / test/task-graph.test.ts — tightened readiness nonce behavior, duplicate dispatch rejection, and blank worker readiness input validation.

Why this closes the prior feedback:

  • Prior blocking issue: stale worker reports could match a historical dispatch and mutate graph/worker/report state after the claim expired or was recovered by another worker.
  • Resolution: report validation now calls the active-claim validation against the current task and report.reportedAt, checks worker ownership, and only then checks historical dispatch before any mutation. Expired/recovered stale reports throw before captureWorkerReport() updates task status, worker status, evidence refs, or report history.
  • Prior warning: runtime-state could not represent graph-dispatched in_progress tasks.
  • Resolution: runtime-state now accepts and tests in_progress task status.
  • Prior warning/suggestions: readiness nonce omission, duplicate dispatch, and blank readiness inputs were under-specified.
  • Resolution: nonce-backed workers require matching nonce at dispatch, same-claim duplicate dispatches throw, and blank worker readiness inputs are rejected.

Verification:

  • npm run check passed.
  • npm run check:unused passed.
  • npm test -- test/task-graph.test.ts passed; package script ran full suite (534 tests, 523 pass, 11 skipped).
  • npm run quality:budgets passed with existing non-failing code_smells=60 warning.
  • git diff --check passed.
  • Current diff size is 5 files changed, 198 insertions(+), 8 deletions(-), below the review-size gate.

@devkade devkade force-pushed the feat/issue-196-worker-execution branch from b9851f9 to ac1af2b Compare May 18, 2026 05:00
@devkade
Copy link
Copy Markdown
Owner Author

devkade commented May 18, 2026

@kapi-agent review

Revision explanation for current head ac1af2b19fa7f22cecba5015b29b7b659716a4ca:

What changed:

  • src/domain/task-graph.tscaptureWorkerReport() now validates the report against the task's current active claim at reportedAt before mutating graph, worker, or report state.
  • src/domain/task-graph.ts — worker report validation now rejects expired claim reports, recovered/replaced claim token reports, and claim ownership mismatches.
  • test/task-graph.test.ts — added regression coverage for expired/recovered stale reports being rejected while task status, worker status, and reports remain unchanged for the expired path.
  • src/domain/runtime-state.ts / test/runtime-state.test.ts — added RuntimeTaskStatus support and parse coverage for in_progress.
  • src/domain/task-graph.ts / test/task-graph.test.ts — tightened readiness nonce behavior, duplicate dispatch rejection, and blank worker readiness input validation.

Why this closes the prior feedback:

  • Prior blocking issue: stale worker reports could match a historical dispatch and mutate graph/worker/report state after the claim expired or was recovered by another worker.
  • Resolution: report validation now calls the active-claim validation against the current task and report.reportedAt, checks worker ownership, and only then checks historical dispatch before any mutation. Expired/recovered stale reports throw before captureWorkerReport() updates task status, worker status, evidence refs, or report history.
  • Prior warning: runtime-state could not represent graph-dispatched in_progress tasks.
  • Resolution: runtime-state now accepts and tests in_progress task status.
  • Prior warning/suggestions: readiness nonce omission, duplicate dispatch, and blank readiness inputs were under-specified.
  • Resolution: nonce-backed workers require matching nonce at dispatch, same-claim duplicate dispatches throw, and blank worker readiness inputs are rejected.

Verification:

  • npm run check passed.
  • npm run check:unused passed.
  • npm test -- test/task-graph.test.ts passed; package script ran full suite (534 tests, 523 pass, 11 skipped).
  • npm run quality:budgets passed with existing non-failing code_smells=60 warning.
  • git diff --check passed.
  • Current diff size is 5 files changed, 198 insertions(+), 8 deletions(-), below the review-size gate.

@kapi-agent
Copy link
Copy Markdown

kapi-agent Bot commented May 18, 2026

kapi-agent review completed

The formal GitHub PR review and required check were submitted separately. This request comment is kept concise to avoid duplicating the full review body.

kapi-agent request lifecycle:

  • Status: COMPLETED
  • Head: ac1af2b19fa7
  • Formal review event: REQUEST_CHANGES
  • Review API status: 200
  • Required check API status: 201

Copy link
Copy Markdown

@kapi-agent kapi-agent Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kapi-agent review

Verdict: REQUEST_CHANGES

Blocking issues

  • src/domain/task-graph.ts: dispatchClaimedTask() validates an active claim token and worker ownership, but it does not validate that the task is currently in the "claimed" state before moving it to "in_progress".

    This can regress a completed or otherwise non-dispatchable task back into execution if it still carries an active claim. For example, completeTask() sets status: "completed" but does not clear claim; a later dispatchClaimedTask() with that still-active token and a ready worker would pass validation, create a dispatch, and change the completed task to "in_progress".

    Please make dispatchClaimedTask() fail closed unless task.status === "claimed" before mutation, and add regression coverage for a non-claimed task with a valid active claim not being dispatched or mutated.

Warnings / risks

  • markMissingHeartbeats() currently relies on getStaleWorkerIds() to only mark "busy" / "ready" workers unhealthy. That is fine as implemented, but worth preserving in future changes so terminal states such as "completed-retained", "safe-to-close", "cleanup-released", and "closed" are not accidentally reclassified.

Suggestions

  • In the recovered stale-report test, also assert the worker state and reports remain unchanged for the recovered-claim rejection path, matching the expired-claim assertions.

Looks good

  • The prior stale worker-report issue is addressed: captureWorkerReport() now validates against the task’s current active claim at reportedAt, verifies worker ownership, and only mutates after validation.
  • Runtime-state alignment for "in_progress", "cleanup-released", and "closed" is appropriate and covered.
  • The README update is aligned with the new worker execution boundary.
  • The new tests cover nonce mismatch, heartbeat refresh, evidence-required completed reports, completion from report evidence, and stale-report rejection paths.

Verification notes

  • Verifier gate status: PASS — npm ci && npm run verify exited 0.
  • Size gate status: PASS with semantic review required — 206 changed lines, with 141 source lines and 61 test lines.
  • Revision-explanation status: PASS — current-head revision explanation was found.
  • Ilchul review harness gate: PASS — STANDARD risk profile, neutral/comment verdict, no blocking findings.
  • Local inspected files: src/domain/task-graph.ts, src/domain/runtime-state.ts, test/task-graph.test.ts, and README diff.

Engine: pi

@devkade
Copy link
Copy Markdown
Owner Author

devkade commented May 18, 2026

@kapi-agent review

Revision explanation for current head 2a33ca3dd23138b25132574b03a75201f6326108:

What changed:

  • src/domain/task-graph.tsdispatchClaimedTask() now fails closed unless the current task status is exactly claimed before it validates the active claim and mutates the graph.
  • test/task-graph.test.ts — added regression coverage for a completed task that still carries a valid active claim, proving dispatch throws, task status stays completed, and no dispatch record is created.
  • test/task-graph.test.ts — added recovered stale-report non-mutation assertions for worker state and report history, matching the expired stale-report path.

Why this closes the prior feedback:

  • Prior blocking issue: a completed or otherwise non-dispatchable task could still carry an active claim and be moved back to in_progress by dispatchClaimedTask().
  • Resolution: dispatch now requires task.status === "claimed" before mutation, so completed/failed/blocked/verifying/in_progress tasks cannot be re-dispatched even if they retain a claim token.
  • Prior suggestion: recovered stale-report rejection should also prove worker/report state remains unchanged.
  • Resolution: the recovered stale-report test now asserts worker state remains busy and report history remains empty after rejection.

Verification:

  • npm run check passed.
  • npm run check:unused passed.
  • npm test -- test/task-graph.test.ts passed; package script ran full suite (535 tests, 524 pass, 11 skipped).
  • npm run quality:budgets passed with existing non-failing code_smells=60 warning.
  • git diff --check passed.
  • Current diff size is 5 files changed, 211 insertions(+), 8 deletions(-); this is above the soft review-size target but still a focused single-surface worker execution slice with only 2 lines of README churn.

@kapi-agent
Copy link
Copy Markdown

kapi-agent Bot commented May 18, 2026

kapi-agent review completed

The formal GitHub PR review and required check were submitted separately. This request comment is kept concise to avoid duplicating the full review body.

kapi-agent request lifecycle:

  • Status: COMPLETED
  • Head: 2a33ca3dd231
  • Formal review event: REQUEST_CHANGES
  • Review API status: 200
  • Required check API status: 201

Copy link
Copy Markdown

@kapi-agent kapi-agent Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kapi-agent review

Verdict: REQUEST_CHANGES

Blocking issues

  • src/domain/task-graph.ts: captureWorkerReport() can still mutate a terminal/completed task if the original claim is still active.

    completeTaskFromWorkerReport() ultimately calls completeTask(), which sets status: "completed" but leaves the active claim in place. Because captureWorkerReport() validates only active claim ownership plus a historical dispatch, a second report for the same dispatched claim can later move the completed task back to verifying, failed, repair_required, or blocked, overwrite evidence refs, append another report, and update the worker state.

    Suggested fix: make captureWorkerReport() fail closed unless the task is in the expected reportable execution state, likely in_progress only, or otherwise explicitly reject terminal/non-reportable statuses before any mutation. Add regression coverage for a task completed through completeTaskFromWorkerReport() receiving a later report on the same still-active claim and prove graph, worker, and reports remain unchanged.

Warnings / risks

  • src/domain/task-graph.ts: if multiple reports for a single dispatch are intended, the state-machine rules should be explicit. Right now duplicate reports are accepted and always mutate task/worker state. That is risky around evidence integrity and terminal-state stability.

Suggestions

  • Consider clearing or terminalizing the task claim during completeTask() if claims should never remain usable after completion. Even with a captureWorkerReport() status guard, clearing terminal claims would make this class of bug harder to reintroduce.
  • Add a small assertion to the recovered stale-report test that the recovered task status remains "claimed" after rejection, not only worker/reports state.

Looks good

  • The prior dispatch regression appears addressed: dispatchClaimedTask() now rejects tasks whose status is not "claimed" before mutation.
  • The prior stale worker-report issue is substantially improved: report validation now checks the current active claim at reportedAt and verifies claim worker ownership.
  • Runtime-state status alignment for in_progress, cleanup-released, and closed is consistent with the new execution model.
  • README updates match the domain-level worker execution boundary.

Verification notes

  • Verifier gate status: PASS — npm ci && npm run verify exited 0.
  • Size gate status: PASS with semantic review required — 219 changed lines exceeds the 200-line threshold, but the semantic scope is bounded to domain worker execution state, runtime status alignment, tests, and README documentation.
  • Revision-explanation status: PASS — current revision explanation was found.
  • Ilchul review harness gate: PASS — STANDARD risk, neutral conclusion, no blocking findings.
  • Local/CI evidence provided includes full verify pass, task-graph test coverage, type/check/unused/quality gates, and git diff --check.
  • I inspected src/domain/task-graph.ts, test/task-graph.test.ts, src/domain/runtime-state.ts, and the README diff.

Engine: pi

@devkade
Copy link
Copy Markdown
Owner Author

devkade commented May 18, 2026

@kapi-agent review

Revision explanation for current head 547f24ff2b32f0d4f269d142158381f426ab3f2e:

What changed:

  • src/domain/task-graph.tscaptureWorkerReport() / validateWorkerReport() now fail closed unless the current task status is exactly in_progress before any graph, worker, evidence, or report mutation.
  • test/task-graph.test.ts — added regression coverage for a task completed through completeTaskFromWorkerReport() receiving a later report on the same still-active claim; the late report throws, task status stays completed, and report history remains unchanged.
  • test/task-graph.test.ts — recovered stale-report coverage now also asserts the recovered task status remains claimed after rejection.

Why this closes the prior feedback:

  • Prior blocking issue: a task completed through worker-report completion could retain its active claim, then a second report for the same historical dispatch could mutate the completed task back to verifying, failed, repair_required, or blocked.
  • Resolution: report capture now requires the task to still be in the reportable execution state (in_progress) before active-claim/dispatch validation and before mutation. Terminal/non-reportable statuses are rejected, so late duplicate reports cannot mutate completed tasks even if the old claim remains present.
  • Prior suggestion: recovered stale-report rejection should prove task status remains unchanged.
  • Resolution: recovered stale-report test now asserts task status remains claimed, worker state remains busy, and report history remains empty.

Verification:

  • npm run check passed.
  • npm run check:unused passed.
  • npm test -- test/task-graph.test.ts passed; package script ran full suite (535 tests, 524 pass, 11 skipped).
  • npm run quality:budgets passed with existing non-failing code_smells=60 warning.
  • git diff --check passed.
  • Current diff size is 5 files changed, 217 insertions(+), 8 deletions(-); above the soft review-size target, but still a focused worker-execution state slice with domain/tests/runtime-status/README only.

@kapi-agent
Copy link
Copy Markdown

kapi-agent Bot commented May 18, 2026

kapi-agent review completed

The formal GitHub PR review and required check were submitted separately. This request comment is kept concise to avoid duplicating the full review body.

kapi-agent request lifecycle:

  • Status: COMPLETED
  • Head: 547f24ff2b32
  • Formal review event: APPROVE
  • Review API status: 200
  • Required check API status: 201

Copy link
Copy Markdown

@kapi-agent kapi-agent Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kapi-agent review

Verdict: APPROVE

Final approval summary

Review journey

This PR adds the phase-3 worker execution domain contract for claimed TaskGraph tasks. The semantic scope is bounded to domain/runtime-state execution state, regression tests, and README alignment. Earlier kapi-agent rounds found stale report mutation risks, missing current-revision explanation, dispatch of non-claimed tasks, and late report mutation of completed tasks. The current revision includes an author explanation and addresses those issues.

What changed

Key paths inspected:

  • src/domain/task-graph.ts
  • src/domain/runtime-state.ts
  • test/task-graph.test.ts
  • test/runtime-state.test.ts
  • README.md

The final code adds worker readiness nonce tracking, dispatch records, heartbeat/staleness helpers, structured worker reports, evidence-gated report completion, in_progress runtime task status, and terminal worker statuses.

Why this is correct

The previously blocking stale-report and terminal-task mutation issues are closed:

  • dispatchClaimedTask() now rejects tasks unless task.status === "claimed" before mutation.
  • captureWorkerReport() now rejects reports unless the current task is in_progress, validates the active claim at reportedAt, checks claim ownership, and requires a matching dispatch before mutating graph/worker/report state.
  • Regression tests cover non-claimed dispatch rejection, expired stale reports, recovered claim reports, and late report rejection after completion.

Evidence

  • Verifier gate: PASS — npm ci && npm run verify exited 0.
  • Size gate: PASS with semantic review required — 225 changed lines, with 143 semantic source lines and 78 test lines.
  • Revision-explanation status: PASS — current revision explanation was found.
  • Ilchul harness gate: PASS — STANDARD risk, no blocking findings.
  • Tests inspected include task-graph worker execution and runtime-state parsing coverage.

Remaining risks and approval rationale

Remaining risk is limited to future integration behavior: live adapters must preserve these domain preconditions when projecting tmux/worktree worker events. No blocking issue remains in this domain-only slice, and the test coverage now matches the previously identified regression cases. Approval is justified.

Blocking issues

  • None.

Warnings / risks

  • Future adapter integration should ensure it does not bypass captureWorkerReport() / dispatchClaimedTask() state preconditions when replaying or projecting live worker events.

Suggestions

  • Consider adding a future test for completeTaskFromWorkerReport() rejecting completion if an external transition has moved the task out of verifying, if that becomes part of the formal lifecycle contract.

Looks good

  • The worker report validation now fails closed before mutation.
  • Runtime-state status alignment covers in_progress, cleanup-released, and closed.
  • README updates match the new execution boundary without overstating live adapter integration.

Verification notes

  • Verifier gate: PASS.
  • Size gate: PASS, semantic review performed.
  • Revision-explanation status: PASS.
  • PR evidence reports npm run verify, targeted tests, type/check gates, unused checks, quality budgets, and diff whitespace checks passing.

Engine: pi

@devkade devkade merged commit d0c8d21 into dev May 18, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sub-roadmap: DAG runtime phase 3 — worker execution, heartbeat, and evidence-gated completion

1 participant