Repository navigation
fix(kanban): preflight worktrees and forced skills - #104257
Open
chrisbawden wants to merge 1 commit into
Open
chrisbawden wants to merge 1 commit into
chrisbawden wants to merge 1 commit into
Conversation
PR #104257 — fix(kanban): preflight worktrees and forced skillsGood defense-in-depth: invalid worktrees and unresolvable forced skills now fail at creation/dispatch (preflight) instead of midway through a worker run. The 440-line What looks right
Non-blocking points
|
3 tasks done
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Stops two classes of Kanban tasks from ever reaching spawn when their prerequisites
cannot be satisfied, and makes every route into
runningre-validate stored forcedskills atomically.
1. Worktree tasks without a repository anchor are rejected up front. A
workspace_kind=worktreetask with no absoluteworkspace_path, no project-linkedprimary repo and no board
default_workdirused to be accepted at creation and onlyfail later at spawn (burning retries on the way). Creation and the dispatcher now
reject unanchored worktree tasks immediately; explicit absolute paths, project-linked
repos and board defaults remain valid (
hermes_cli/kanban_prerequisites.py).2. Forced skills are resolved against the assignee before the task becomes
runnable.
skills=[...]onkanban_createused to be accepted unchecked: a typo ora skill the assignee profile doesn't have surfaced only at worker spawn. Now:
create_taskvalidates the forced-skill list against the assignee's profile homebefore insertion (no secrets read).
assign_taskre-validates when a card is reassigned.recompute_ready) blocks a card whose stored skills no longerresolve, before it becomes
ready._claim_and_open_runboundary re-validates stored forced skills onevery route into
running— direct/control-plane claims, dispatcher claims, andany requeue that restored
ready/review(reclaim, stale lock, crash, timeout,spawn failure): an incompatible card is blocked (one
prerequisite_blockedevent,no run opened, no retry consumed) before the CAS can open a run.
3. Legacy invalid cards are blocked before spawn. When the dispatcher
(
_dispatch_lane_task) encounters a card whose stored prerequisites are now invalid,it atomically flips the card to
blockedwith aprerequisite_blockedevent insteadof opening a run and letting it crash-loop.
Existing API shapes are preserved: the dashboard plugin maps the new
ValueErrorrejections to HTTP 409 alongside the existing 400/409 mappings, and allpreviously valid task paths (absolute worktree paths, project links, board defaults,
valid forced skills) keep working — covered by regression tests for each.
Related open PRs (different layers, not duplicates): #103714 anchors decomposed
worktree children at decompose time; #39179 drops invalid skills at spawn instead of
blocking; #85551 gates on base-ref/required-paths. This PR validates at creation,
reassignment, promotion and claim time so nothing invalid survives to spawn.
Related Issue
No existing issue covers the crash-loop class; linking none rather than guessing.
Type of Change
Changes Made
hermes_cli/kanban_prerequisites.py(new):validate_worktree_anchor,validate_forced_skills,validate_task.hermes_cli/kanban_db.py: creation/assignment validation, promotion-time guard inrecompute_ready, atomic claim-boundary guard in_claim_and_open_run.hermes_cli/kanban_db_dispatch.py: pre-spawn validation in_dispatch_lane_taskwith atomic block +
prerequisite_blockedevent.plugins/kanban/dashboard/plugin_api.py: 409 mapping for the new rejections.tools/skills_tool.py: profile-scopedskill_is_loadablehelper.website/docs/user-guide/features/kanban.md: prerequisite behaviour documented.tests/hermes_cli/test_kanban_prerequisites.py(new, 440 lines),tests/hermes_cli/test_kanban_cli_exit_status.py,tests/hermes_cli/test_kanban_review_lifecycle.py,tests/hermes_cli/test_kanban_swarm.py,tests/plugins/test_kanban_dashboard_plugin.py,tests/tools/test_kanban_tools.py.How to Test
bash scripts/run_tests.sh tests/hermes_cli/test_kanban*.py tests/tools/test_kanban*.py tests/plugins/test_kanban*.py tests/tools/test_skills_tool.py→ 62 files, 505 passed, 0 failed, 2 Windows-only skipped.
.venv/bin/ruff checkon all 12 changed Python files → passed..venv/bin/python -m compileall -qon the 8 non-test-source files → passed..venv/bin/ty check hermes_cli/kanban_prerequisites.py tests/hermes_cli/test_kanban_prerequisites.py→ passed.git diff --check origin/main..HEAD→ clean; working tree clean.Checklist
Code
fix(kanban):…)pytest tests/ -qand all tests pass — not run: the full ~39k suite was not executed on this host; the task-scoped 505-test Kanban suite listed above was run and passedDocumentation & Housekeeping
cli-config.yaml.exampleif I added/changed config keys — or N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/AFor New Skills
N/A — no skill added.
Screenshots / Logs
Focused suite summary (local run, 4 workers):