All three brief tasks and the nine-child Usage Monitor unit are merged and main verified green. Correct section 5: "exited with code 1 and no result" is a catch-all, not a CLI crash — max_turns (sonnet presets default to 30 because app_settings.model_presets is NULL) and the account session limit both surface through the same message.
13 KiB
Handoff — List-handler run on list "Claude do", 2026-08-05
✅ COMPLETED 2026-08-05 (follow-up session). Everything in §1 and §2 is merged and
mainverified green. Read §0 below before §1–§8 — §5's diagnosis turned out to be wrong and the rest is now history. Still nothing pushed.
Repo: C:\Private\ClaudeDo · List id: 5f973815-050a-4136-94f0-1506a5d4560a · Branch: main (nothing pushed)
0. What the follow-up session did (and what §5 got wrong)
All merged, main green after every step (Worker 811/811, Data 143/143, Ui 292/292,
Localization 16/16, builds 0 new warnings):
| Merged | Task | Merge commit |
|---|---|---|
| §1 #1 | 9e307199 revert_merge + merge-SHA persistence |
3e7126b |
| §1 #2 | 0b2fbb48 post-merge verification gate |
(conflict-resolved) |
| §1 #3 | 8c1c2130 roadblock reply box |
519ea5a |
| §2 #42 | c1df5b9a Hub surface for usage |
6e2158d |
| §2 #43 | f74b44d9 Usage pill |
7661129 |
| §2 #45 | 06068810 gate thresholds in settings |
5115cfc |
| §2 #44 | 82488d2a Usage Monitor modal |
338fc39 |
| §2 #46 | 9c8cffe0 docs |
5872666 |
| parent | 439a4daf Usage Monitor unit |
approved → Done (empty unit merge; all children already Merged) |
Plus one hand-fix on main: 677a4c1 — UsagePillViewModelTests never set Loc.Current
(defaults to a key-echo localizer) and only passed because another test class happened to
install a real Localizer first; #44's new tests changed the ordering and broke it on main.
Classic "both branches green, main red".
§5 is wrong — "exited with code 1 and no result" is NOT (only) a CLI crash
It is a catch-all hiding at least three causes. The truth is in the run log's last NDJSON
line ({"type":"result", …} → terminal_reason / errors / result):
max_turns— what actually killed #40 and #42.app_settings.model_presetsisNULL, soModelPresets.Parsefalls back to the shipping defaults, and sonnet's default is 30 turns.AppSettings.DefaultMaxTurns(100) is only the fallback for an unrecognized alias, so it never applies. Every task without an explicitmaxTurnsoverride got 30 turns. → Fix used here:set_task_config(taskId, model="sonnet", maxTurns=200)before queueing.api_error+"You've hit your session limit · resets 1pm (Europe/Berlin)"— the account's 5-hour limit, which took out #43's first attempt. Nothing to fix; wait for the reset, re-queue.- Genuine process death — the case §5 describes.
§5's operational advice still holds and is what saved #42: never reset_failed_task on one
of these; check the worktree, build/test it, then set the task Queued so the agent resumes its
own session and commits. #42's worktree held a complete green implementation (773/773).
Follow-up tasks: ca6e55c0 (surface the real failure reason) is new; the turn-budget/presets side
is already covered by the Idle task 2de2f008 (b0317ec7 fixed only the unknown-alias half).
Still open
- Visual passes (nobody has looked at these in a running app): usage pill in the footer and
the Mission Control header; Usage Monitor modal (gauges, tables, stale/blocked bands, dark/light);
the roadblock reply box; the verify-command field in the List Settings modal. See
docs/open.md. ~/.todo-app/prompts/planning.mdstill shadows the compiled default (§7.1) — unchanged.wait_for_task_changeis merged but not in the running Worker, so it isn't callable over MCP until the Worker is restarted. §3's sqlite poll was used instead.- One rough edge in the verify gate: if the verify command fails, the worktree has already been
removed and its state set
Mergedwhile the task staysWaitingForReview— re-approving is then refused. Recovery isupdate_task_status(..., "Done")oncemainis fixed.
Predecessor session ran the five-phase list handler over 11 briefed tasks and, along the way, absorbed the 9-child "Usage Monitor" unit. Phases 0–3 are complete for the brief. What is left is Phase 4 (review + merge) for three tasks, plus the Usage chain.
1. Do this first — three brief tasks sit in WaitingForReview
Merge in this order (the order was chosen with the user and matters):
| # | Task | Id | Note |
|---|---|---|---|
| 1 | Feat: Merge zurücknehmen — Merge-Commit festhalten + revert_merge |
9e307199-2eca-4eb7-9057-d2c675cc57ca |
Migration + new tool. Merge before #2 |
| 2 | Feat: Verifikations-Gate nach dem Merge | 0b2fbb48-d44c-4155-8c21-d3464c0bd5c2 |
Depends on #1's merge-SHA persistence; both edit TaskMergeService.cs |
| 3 | Feat: Antwortfeld auf der Roadblock-Karte | 8c1c213004574c4fad6beb75b84b70d7 |
UI + localization (en and de) |
For each one:
get_task_diff(taskId, stat=true), then the full diff if non-trivial. Sanity-check against the task description (they are long and precise — the acceptance criteria are the checklist).review_task(taskId, decision="approve", leaveConflictsInTree=true).- On conflict: open the files under the returned
repoPath, resolve keeping both sides' intent, thencontinue_merge(taskId). Conflicts are expected and normal here. - After every merge, verify
main(see §4). This is non-negotiable — see §5.
Expected conflicts: TaskMergeService.cs between #1 and #2; src/ClaudeDo.Worker/CLAUDE.md
and src/ClaudeDo.Data/CLAUDE.md in nearly every merge (doc bullet lists — trivial, keep both
sides' entries).
2. Then the Usage Monitor unit
Parent 439a4daf166f4ab5b0fa415693d2c80d ("Usage Monitor hinzufügen") is WaitingForChildren
and has no worktree of its own. It has 9 children. Four are merged, one is in flight, four
are Idle.
| Child | Id | State |
|---|---|---|
| #38 Data: Usage-Gate-Schwellen + Modell-Spalte | c1c999b6-b800-4b6b-a821-fbc028c15772 |
merged b1efcdc |
| #39 Worker: OAuth-Usage-Client + Poller | f657e316-ad72-4f45-8036-460841fc8997 |
merged b126a21 |
| #40 Worker: UsageGate | 06a7cc32-6ab7-4758-98f4-bee77149b2bf |
merged 1ee21b5 |
| #41 Worker: TranscriptUsageReader | 840fdb98-1c0e-4219-8062-c8769233fc14 |
merged 334cf1e |
| #42 Worker: Hub-Surface für Usage | c1df5b9a-b911-4fe8-aab4-5876d9d85793 |
re-queued, in flight — read §5 before touching |
| #43 UI: Usage-Pill | f74b44d9-7e48-4bfe-9d89-075e194d1fc9 |
Idle — queue once #42 is merged |
| #45 UI: Gate-Schwellen im Settings-Modal | 06068810-5b5c-4635-80dd-62eeba89fb8c |
Idle — queue once #42 is merged (parallel with #43) |
| #44 UI: Usage-Monitor-Modal | 82488d2a-8ff7-41b8-b791-367959a8f827 |
Idle — needs #42 and #43 merged |
| #46 Docs: Usage Monitor | 9c8cffe0-8f7b-401e-a4f0-33b937047082 |
Idle — last, after everything is merged |
The chain is strictly serial and you must respect it. Every child forks from main, and each
one's own description hard-requires the earlier ones. Queueing them all at once is exactly what
produced the original roadblock: #40 ran, found its prerequisite types only on unmerged sibling
branches, and returned Done having written zero code. So: merge a child → then queue the
next → verify main → repeat.
When the last child is merged the parent surfaces for review by itself; approve it to close the unit (it has no worktree, so it approves straight to Done).
3. Cheap status polling — important
list_tasks and batch_get_tasks return full descriptions and blow the token limit on this
list (list_tasks over 52 tasks = ~206,000 chars; that is literally one of the bugs this run
fixed). Do not poll with them. Poll the DB read-only instead:
PYTHONIOENCODING=utf-8 python - <<'EOF'
import sqlite3
c=sqlite3.connect("file:C:/Users/mika.kuns/.todo-app/todo.db?mode=ro",uri=True)
for i,s in c.execute("select id,status from tasks"):
print(s, i)
EOF
list_worktrees is also compact and safe. New this run: wait_for_task_change(taskIds, timeoutSeconds) is now merged and is the proper primitive — it returns as soon as any listed
task leaves Queued/Running (server-clamped to 170 s). Prefer it over sleeping.
4. Verify main after every merge
dotnet build src/ClaudeDo.Worker/ClaudeDo.Worker.csproj -c Release
dotnet test tests/ClaudeDo.Worker.Tests/ClaudeDo.Worker.Tests.csproj -c Release
dotnet test tests/ClaudeDo.Data.Tests/ClaudeDo.Data.Tests.csproj -c Release
For the UI/localization task (#3 above, and children #43–#45) also:
dotnet build src/ClaudeDo.App/ClaudeDo.App.csproj -c Release
dotnet test tests/ClaudeDo.Ui.Tests/ClaudeDo.Ui.Tests.csproj -c Release
dotnet test tests/ClaudeDo.Localization.Tests/ClaudeDo.Localization.Tests.csproj -c Release
.slnx needs .NET 9 — build individual csproj files, -c Release (a running Worker locks Debug).
Baseline as of this handoff: Worker 753/753, Data 143/143, build 0 warnings.
5. The trap that cost this run the most time
Two children "failed" with "Claude exited with code 1 and no result". That is a CLI crash,
not bad code. In both cases the worktree held complete work that built with 0 warnings and
passed the full suite (#40: 732/732, #42: 766/766) — the run just died before the auto-commit.
- Never
reset_failed_taskon such a task — it discards the worktree and destroys the work. - Instead:
cdinto the worktree,git status, build + test it. If green, set the taskQueued. The worktree is preserved and the agent resumes its own session (--resume), finds its work and commits it. That is how #40 was recovered. - #42 is mid-recovery right now via exactly this route. If it failed again, verify its worktree
(
C:\Private\.claudedo-worktrees\claude-do\c1df5b9a-b911-4fe8-aab4-5876d9d85793) before doing anything destructive.
Second trap: git merges cleanly and the compiler still breaks. It happened again this run —
Usage/UsageModels.cs was an add/add conflict, and src/ClaudeDo.Worker/CLAUDE.md merged
"cleanly" into a file with the Usage/ folder documented twice. Always read what a clean
merge produced, and always run §4.
6. Phase 0–3 decisions already made (do not redo)
Dedupe: four candidate pairs examined, nothing cancelled. Decisions:
05827da5↔81e37801— kept both, and05827da5was re-scoped: its "lean status query" half was removed because81e37801's wait tool covers it.05827da5now owns only the brief-description rendering. Both are merged.a76d9547↔99732497— kept both,99732497merged first. Done.0b2fbb48↔9e307199— kept both,9e307199merges first. This is item #1/#2 in §1.20c78c95↔a76d9547(b) — kept both, different actors. Done.
Phase 2: all 11 tasks carry acceptance criteria, real file+line references and out-of-scope sections. Three that were one-liners were researched and rewritten after asking the user (ConPTY fix approach, maxTurns-only scope, roadblock reply-box design).
Run config: maxParallelExecutions = 3. No list config exists, so effective max turns was
the global 100; it was raised to 200 per-task on the five heaviest via set_task_config.
0b2fbb48, 9e307199 and 8c1c2130 still carry that override.
7. Open follow-ups worth new tasks
~/.todo-app/prompts/planning.mdshadows the planning prompt.PromptFiles.EnsureExistsonly writes a default when the file is absent, and that file exists (dated Jun 2). ThemaxTurnsguidance merged in65db1cdtherefore does not reach real planning sessions until that file is updated by hand.system.mdandagent.mdare shadowed too.merge-helper-system.md/merge-helper-initial.mddo not exist, so this run's handler prompt changes are live.- MCP task DTOs expose no parent/child link. The 9-child Usage unit had to be reconstructed
from
sortOrderand creation timestamps.get_task/list_tasksshould returnparentTaskId/blockedByTaskId. - Visual verification open on: the ConPTY fix (open a tile on a task whose description
contains
->), and — once merged — the roadblock reply box and the verify-gate field in the list settings modal. "exited with code 1 and no result"is too common. Three runs died that way today, two with finished work. Worth investigating whether the auto-commit step can be made to survive a late CLI crash.- Nothing has been pushed.
mainis 22 commits ahead of8d7ba1e.
8. Rules this session operated under
- Drive merges through the MCP tools. Never raw
git merge/reset/checkout. - Hand-resolve only markers the tools left behind, then
continue_merge. When committing by hand is unavoidable, stage explicit paths — nevergit add -A: the main checkout is shared with other sessions. - For a parent/children unit merge, pass the parent id to
continue_merge/abort_merge. - Ask the user on anything ambiguous, risky, or destructive.
- Never
delete_taskto dedupe —Cancelledkeeps it visible and resettable.