The work-item spine: repository, validation, service and routes for Task, plus its verdicts and append-only transition log. Transitions are compare-and-swap. The expected current state is part of the WHERE clause and the affected-row count is the answer, so two agents racing to advance the same task cannot both win — a read-then-write would let both "succeed" and silently lose one. Losing the race is a 409 naming the state the task is actually in, not a 500, because on a shared board that is a normal outcome the caller retries. Same idiom as InferenceTaskRepository's claim. QA / Security / SRE are stages inside the task's own loop, not post-submit reviewers, so each can bounce straight back to in_progress — that is what "feedback" means here. A failed build likewise goes backward, not forward. `merged` allows only `reopened`, so a merged task cannot be quietly edited; post-merge failure is the one way back in. The gate on `done` scales with risk instead of running a fixed pipeline: trivial needs nothing, normal needs a passing QA verdict, high needs QA + Security + SRE. Forcing a one-line docs fix through security review is how a process gets routed around, so the cost has to match the risk. A FAILING verdict does not clear a gate — a recorded failure is evidence the gate was tried and did not hold. The 400 names which gates are still missing. The human accept gate is a task-level yes/no on a resolved outcome, not per-tool approval: accept fires the merge and stores the comment, reject sends it back to in_progress and REQUIRES a comment, because the comment is the direction the agent works from. GET /tasks/:id returns `legalTransitions` so no client has to hardcode the table. Tests: 25 service tests — full happy path, every stage's bounce-back, illegal and no-op transitions, the CAS race (including that no event is written when the race is lost), the complete risk matrix including failing-verdict-does-not- count, and the accept/reject gate. Local: build clean, workspace 2400 passed (+25), db 128 passed (same 4 pre-existing Secret failures), lint unchanged at 869. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N4wNHWf7xSwnZCWpJcyv9p
326 KiB
326 KiB