Conversation
Kernel-enforced verdicts are the right place for this invariant, and the TOCTOU recheck inside the write transaction (with its own regression test) is exactly how a race like this should be closed. Test coverage is excellent — CLI, tool surface, dashboard PATCH/bulk, blocked-escalation, stale-run, and concurrency paths. Notes:
No blocking issues found. |
3266d69 to
6c2edfd
Compare
|
Thanks — I audited each point and updated the PR.
The branch was rebased onto current |
|
Closing due to age and conflicts (15 files, thousands of commits behind current The review-verdict invariant is still needed (#67132), but this patch no longer rebases cleanly and I am not picking that fight in this form. If I return to it, it will be a new PR against current |
What does this PR do?
A first-class Kanban review task can currently transition to
donethrough the DB, CLI, model tool, or dashboard even when its completion metadata is missing a verdict or explicitly records a rejected/conditional verdict. Becausedonesatisfies ordinary dependency edges, that false terminal state can immediately promote downstream work.This PR makes review approval a DB-level invariant:
metadata.verdictis a string that normalizes viastrip().upper()to exactPASS;FAIL, and conditional verdicts fail closed without changing task state or promoting dependents;blockedretain review identity, so leaving the literalreviewstatus cannot bypass the gate;expected_run_idare re-read inside the final SQLite write transaction, closing the completion time-of-check/time-of-use race;completion_blocked_nonpassing_verdictevent while leaving the task in flight;Ordinary completion keeps the existing free-form metadata contract, including a caller-defined
metadata.verdict; exactPASSis enforced only when durable task context identifies review work.Compatibility:
complete_tasknow raisesNonPassingVerdictErrorfor a semantic review rejection after committing its audit event. All four first-party production callers handle that domain error; direct Python/plugin callers that complete review work should handle it as well. Ineligible, stale, and non-review completion paths retain their existing boolean behavior.Related Issue
Related to #67132, but intentionally does not claim to close it. That issue asks for typed approval dependency edges, mixed fan-in, and remediation fan-out semantics. This PR instead enforces the narrower first-class review-task invariant before the parent can become terminal.
Overlap review:
donewithout approval.metadata.gateproposal with additional unrelated scope; this PR does not supersede it.Type of Change
Changes Made
hermes_cli/kanban_db.py— normalize review verdicts, identify durable review context, revalidate insidewrite_txn, commit structured rejection events before raising, preserve ordinary free-form metadata, and keep task/dependency state unchanged on rejection.hermes_cli/kanban.py,tools/kanban_tools.py,plugins/kanban/dashboard/plugin_api.py— return actionable completion errors consistently across CLI, model-tool, and dashboard surfaces.agent/prompt_builder.py,skills/devops/sdlc-review/SKILL.md— teach reviewers to approve only withmetadata={"verdict": "PASS"}and route correctable findings throughkanban_request_changes.website/docs/user-guide/features/kanban-tutorial.md,website/docs/user-guide/features/kanban-worker-lanes.md, and the corresponding zh-Hans tutorial — document the enforced verdict contract.tests/hermes_cli/test_kanban_verdict_gate.pyplus existing lifecycle/tool/dashboard/skill suites — cover missing, malformed, conditional, stale-run, claimed-review, blocked-review, ordinary free-form metadata, transactional review races, durable rejection events, and dashboard race UX.How to Test
Run the focused regression and surface suites:
Result:
138 passed.Run Ruff on all touched Python files. Result:
All checks passed!.Run
git diff --check upstream/main...HEAD. Result: clean.The regression suite verifies that rejected completion leaves the review task in flight and its dependent child held, while normalized exact
PASScompletes the task and promotes the child.Checklist
Code
pytest tests/ -qand all tests pass — the focused 138-test affected suite passes; the full repository suite was not runDocumentation & Housekeeping
cli-config.yaml.example— N/A; no configuration keys changedCONTRIBUTING.mdorAGENTS.md— N/A; no repository architecture/workflow convention changedScreenshots / Logs
N/A — this is a lifecycle invariant and structured error-path change with automated coverage.