docs(explore-notes): reflect claim-before-create ordering in worker-task-pipeline
Bumps the verified-against commit to 774f9d3 (the RunNow/picker
double-dispatch race fix) and documents the new claim-before-create
ordering and the RunCancellationRegistry double-registration guard.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
> **Explore-note — verify before trusting.** Distilled map of a subsystem, not authoritative.
|
||||
> Last verified against commit `896d4b5` (2026-07-23).
|
||||
> Drift check: `git log --oneline 896d4b5..HEAD -- src/ClaudeDo.Worker`
|
||||
> Last verified against commit `774f9d3` (2026-08-06).
|
||||
> Drift check: `git log --oneline 774f9d3..HEAD -- src/ClaudeDo.Worker`
|
||||
> Stable structure only (no line numbers). See docs/explore-notes/README.md.
|
||||
|
||||
# Worker: Task Execution Pipeline
|
||||
@@ -28,9 +28,11 @@ How a task moves Queued → Running → terminal, across `src/ClaudeDo.Worker`
|
||||
|
||||
5. **Run Preparation** — `TaskRunner.RunAsync()` (Runner/TaskRunner.cs)
|
||||
- Loads task, list config, subtasks, attachments from the DB.
|
||||
- `StartRunningAsync()` (only if not pre-claimed): atomic claim to Running, **before any
|
||||
resource is created**. A rejected claim (task already Running) bails out immediately —
|
||||
no worktree, no MCP token file. Broadcasts TaskStarted.
|
||||
- `PrepareRunDirectoryAsync()`: worktree (via WorktreeManager) if the list has a WorkingDir,
|
||||
else sandbox. Generates a per-run MCP token, writes MCP config to disk.
|
||||
- `StartRunningAsync()` (only if not pre-claimed): atomic Queued → Running. Broadcasts TaskStarted.
|
||||
|
||||
6. **Claude Execution** — `TaskRunner.RunOnceAsync()` (Runner/TaskRunner.cs)
|
||||
- Creates a TaskRunEntity, points the task at the run's log path.
|
||||
@@ -148,6 +150,15 @@ Program.cs (DI setup)
|
||||
- **Slot limit** — respects MaxParallelExecutions; a backstop timer wakes even if a Wake() is missed.
|
||||
- **Pre-claimed tasks** — the dispatcher pre-claims via the picker; the override slot
|
||||
(RunNow/ContinueTask) must call StartRunningAsync if a task is not pre-claimed.
|
||||
- **Claim before create** — `TaskRunner.RunAsync`'s unclaimed path calls `StartRunningAsync`
|
||||
*before* `PrepareRunDirectoryAsync`. RunNow racing the picker for the same Queued row used to
|
||||
create the worktree first and only claim afterwards, so the losing dispatch could hit
|
||||
WorktreeManager's branch-collision self-heal and force-remove the winner's live worktree
|
||||
mid-run. `OverrideSlotService.RunNow` also fast-rejects a task already Running in the DB
|
||||
(defense in depth; the picker's atomic SQL claim is the real arbiter either way).
|
||||
`RunCancellationRegistry.Register` refuses (and logs) a second registration for the same task
|
||||
id instead of silently overwriting the first, so a losing dispatch's cleanup can't unregister
|
||||
the winner's CTS out from under it.
|
||||
- **Terminal writes** — use `CancellationToken.None`; a task is never left Running after crash/cancel.
|
||||
- **Per-run MCP tokens** — each run gets a unique token scoping tool access; unregistered on end.
|
||||
- **Auto-retry** — one automatic retry if a session exists and the first run failed.
|
||||
|
||||
Reference in New Issue
Block a user