claude-failover/internal
Ubuntu 5cfb58c202 feat(dispatcher): enforce depends_on with .blocked marker (Phase 2/G2)
Before claiming a session for a task, the dispatcher now:
1. Parses the task's frontmatter
2. If `depends_on: [project:task_id]` is non-empty, checks each entry
   against `<projectsDir>/<project>/.agent-queue/done/<task_id>.md`
3. If any dep is unresolved -> skip the task and write
   `<task>.md.blocked` next to it. The watchdog (G1) will resolve
   this marker on its next tick.

The `.blocked` marker is idempotent: re-running the dispatcher does not
refresh its mtime, so the watchdog can compute the blocked-since
timestamp from the FIRST detection (timeout precision).

Path-traversal hardening: project / task_id segments must match
`[A-Za-z0-9._-]+` and cannot be `.` or `..`. A malicious frontmatter
like `depends_on: ../../tmp:foo` is rejected before any filesystem
lookup.

assignNextTask (the doneChan path) applies the same gate so that a
session freed mid-cycle cannot bypass enforcement.

Tests (-race clean):
- DependsOnUnresolved -> .blocked marker, no dispatch
- DependsOnResolved -> normal dispatch, no marker
- PartialResolution -> stay blocked
- RejectPathTraversal -> blocked, not dispatched
- BlockedMarker idempotent (mtime stable across passes)
- NoDependsOn regression guard
2026-04-16 20:30:17 +00:00
..
api feat: SessionLifecycleManager — auto-detect and repair dead tmux sessions 2026-04-14 18:02:25 +00:00
config feat(pool): add start_index so manual and auto pools can coexist 2026-04-15 20:39:57 +00:00
dispatcher feat(dispatcher): enforce depends_on with .blocked marker (Phase 2/G2) 2026-04-16 20:30:17 +00:00
janitor feat: Phase 2.7+3 — full integration, config update, systemd unit 2026-04-15 00:15:06 +00:00
lifecycle feat(lifecycle): validate shared symlinks at daemon startup (A2) 2026-04-16 19:03:43 +00:00
notify feat(notify): Phase 2.5 — Notifier Telegram + Resend email 2026-04-14 20:28:46 +00:00
quota fix(dispatcher): send a lone Enter after the task paste to submit it 2026-04-15 20:49:59 +00:00
state fix(quota): add cooldown + 2-poll confirmation to prevent swap ping-pong 2026-04-15 19:18:27 +00:00
switcher fix(switcher+symlinks): rollback on ensure failure (Bug #1) + requiredShared contract test (Bug #10) 2026-04-16 19:53:48 +00:00
symlinks fix(switcher+symlinks): rollback on ensure failure (Bug #1) + requiredShared contract test (Bug #10) 2026-04-16 19:53:48 +00:00
tmux fix(dispatcher): send a lone Enter after the task paste to submit it 2026-04-15 20:49:59 +00:00
watcher fix(dispatcher+watcher): never auto-dispatch into dedicated sessions 2026-04-16 13:30:26 +00:00