Files
ClaudeDo/docs/open.md
T
mika kuns b5a8d58e62 docs(open): re-verify the 2026-07-24 findings and drop the fixed ones
Ten of the twelve listed bugs/nits are fixed in the code (outcome JSON,
subtask terminology, live child rows, AskUser in the detail island, Icon.Plus,
gear glyph, rename display, TurnsText, conflict Continue gate, ConPTY resume)
and the blocked-approve silent fail is handled by the WorkerHub throw. Adds the
open verification block for the planning-resume fix.
2026-08-06 09:10:50 +02:00

16 KiB
Raw Blame History

ClaudeDo — Offene Punkte

Stand: 2026-08-06. Der Findings-Block von 2026-07-24 wurde am 2026-08-06 gegen den Code nachverifiziert (statisch, nicht in der laufenden App); alles, was inzwischen gefixt ist, ist hier entfernt — Erledigtes steht in den Commits/im Code, nicht hier. Die alte Verifikations- Checkliste lebt in docs/verification-handoff.md.


UX / Nits (offen)

  • Planning-aktiver Parent zeigt weiter „Idle": Parent in planning_phase=active hat Status=Idle (korrekt im Modell), aber TaskRowViewModel.StatusLabel (Zeile 132) kennt nur HasInteractiveSession/IsParked als Overrides — der PlanningBadge ersetzt den Chip nicht sichtbar → liest sich wie ein normaler Idle-Task. Wunsch: klarer „Planning/Draft aktiv"-Zustand, der Idle überschreibt. (Kinder zeigen korrekt „Draft".)
  • Blocked-by-Kette nicht sichtbar: Nach Finalize ist die sequentielle Kette korrekt gesetzt (child[i] blocked-by child[i-1]), aber die UI stellt Reihenfolge/Abhängigkeit nicht dar — es gibt nur den „waiting"-Chip. Wunsch: Kette visualisieren (z.B. „wartet auf <Vorgänger>").
  • Dequeue-„X" fehlt auf wartenden (blockierten) Kettengliedern: CanRemoveFromQueue = IsQueued || HasQueuedSubtasks (TaskRowViewModel.cs:99), IsQueued verlangt leeres blocked_by. Ein gequeuetes, aber blockiertes Kind (IsWaiting) bekommt daher kein Remove-from-queue-X — nur Parent + erstes (entsperrtes) Kind.
  • Session-Skills-Tab hat keinen Empty-State: Bei 0 installierten Skills zeigt der Skills-Tab (Settings) nur eine nackte leere Fläche unter der Install-Zeile — kein erklärender Hinweis (z.B. „Noch keine Skills installiert — GitHub-URL oben einfügen"). Im sessionSkillsTab-Locale-Namespace (en.json:674) gibt es keinen empty-Key.
  • Conflict-Resolver: mehrere Konfliktdateien schlecht erkennbar: Beim 2-Datei-Konflikt schwer zu sehen, dass zwei Dateien betroffen sind (File-Switcher/Anzahl zu unauffällig). Prominentere Datei-Liste / „x von y Dateien".
  • Attachments: erster Drag&Drop der Session schlug einmalig fehl („An error occurred"): Beim allerersten Drop-to-attach einer UI-Session zeigte die DropStatus-Zeile inline einen generischen Fehler und es wurde nichts persistiert (kein File, keine DB-Row); alle folgenden Drops derselben Session + der „Add file…"-Picker + Remove funktionierten fehlerfrei. Nicht reproduzierbar nach dem ersten Mal. Kandidaten: transiente SQLite-Contention (der UI-Prozess schreibt todo.db direkt via new TaskAttachmentRepository, während der Worker dieselbe DB hält) ODER ein Fehler im Drop-Stream-Pfad (IStorageFile.OpenReadAsync im Code-Behind, außerhalb des try in AddFilesAsync). Falls es erneut auftritt: AddFilesAsync/OnDrop mit robusterem Error-Logging versehen.

Feature-Wünsche

  • Conflict-Resolver: farbliches Hervorheben eingefügter Zeilen im Result-Pane (grüner „flow" der übernommenen Zeilen).

Design-Entscheidungen (27.07.-Batch, Sichtprüfung am 2026-08-06 abgeschlossen)

Der Sichtprüfungs-Block dieses Batches (Ctrl+K/#, Titel-Edit, ConPTY-/Refine-Spinner, Interactive-Chip, Diff-Viewer-Abstände, Manual-Tasks, Vorgaben-pro-Modell-Tabelle) ist von Mika verifiziert und deshalb hier entfernt. Es bleiben die Entscheidungen, die daran hängen:

  • Interaktive ConPTY-Sessions bekommen --effort, aber kein --model — die Session läuft weiter unter dem Modell aus Mikas Claude-Config, der Effort kommt aus dem Preset des Modells, das ClaudeDo für die Task auflösen würde. Falls ClaudeDo auch interaktiv das Modell erzwingen soll, ist das ein Folge-Task.
  • AppSettings.DefaultMaxTurns ist jetzt tatsächlich verdrahtet (ModelPresets.For(..., global.DefaultMaxTurns) in TaskRunner.ResolveConfigAsync): reiner Fallback für ein Modell, das auch nach ModelRegistry.TryNormalizeAlias auf keine Preset-Zeile trifft — vorher war das Feld tot (hartkodierte 30). Hat weiterhin keinen eigenen Editor mehr (nur die Preset-Tabelle pro Modell); Spalte könnte später entfallen, falls das nie zutrifft.

Beobachtung (offen — Entscheidung Mika)

  • --permission-mode auto + Modell haiku → Writes werden denied: Kontrolliert verifiziert (CLI 2.1.207): unter dem Default-Mode auto bekommt sonnet Writes auto-approved (permission_denials:[]), haiku wird denied (permission_denials:[Write], keine Datei) — eine haiku-Task macht unter auto still nichts und landet ohne Änderung in WaitingForReview. Normalbetrieb (Default = sonnet) nicht betroffen. KEINE CLI-Regression, sondern modellabhängiges auto-Verhalten. Optionen falls es nervt: haiku aus der Auswahl nehmen, ODER Runner auf acceptEdits/bypassPermissions (modell-unabhängig). Mika: erstmal beobachten. Siehe Memory auto_permission_haiku_footgun.
  • QueueServiceTests.UsageGate_TransitionLogging_FiresOncePerChange ist zeitbasiert flaky, unabhängig von dieser Session: Schlägt reproduzierbar fehl (Expected 1, Actual 0 Warn-Log-Aufrufe), sowohl solo (--filter) als auch im Vollauf, auf einem sauberen git worktree add gegen main (bdee731) — also kein durch diese Abschluss-Session verursachter Regress (die Session hat keine .cs-Datei angefasst). Ursache: der Test verlässt sich auf einen festen Task.Delay(200), um mehrere 50-ms-Backstop-Ticks abzuwarten (Kommentar im Test: „Several backstop ticks (50ms interval) all observe the same blocked state"); auf einer stark ausgelasteten Maschine (hier: viele parallele ClaudeDo-Worktrees/Builds) reicht das Fenster nicht immer. Zum Vergleich: derselbe Test lief in einer zweiten, isolierten Verifikation (Scratch-Merge für den Environment-Checks-Task) sauber durch (876/876). Fix wäre ein Poll-basiertes Warten statt fixem Sleep — aber außerhalb des Scopes dieser Doku/Verifikations-Session (keine Code-Änderung angefasst).

Offene Verifikation (2026-07-27)

  • List handler (2026-07-27) — visual pass: the Broom button is gone from the lists footer, the context-menu item appears only on lists with a working dir, and the selection dialog has no LIST column. (Der real-Claude-Smoke-Run der fünf Phasen ist am 2026-07-29 gelaufen — 6/6 sauber gemerged; nur die Sichtprüfung ist noch offen.)

Offene Verifikation (2026-08-05)

  • List handler owns a task (2026-08-05) — build + unit tests all green, but not visually verified: start "Let Claude handle it" on a list, confirm exactly one new task appears in that list (Idle, MANUAL badge, title "List handler: "), the Mission Control tile is task-based (Submit for review button present), Submit for review flips it to WaitingForReview, and the detail pane's diff/merge card shows the full range of everything the run merged to main (via the new HandlerBaseCommit/HandlerHeadCommit fallback — no WorktreeEntity is created for this task, so the diff comes from list.WorkingDir directly).

  • Roadblock reply field (2026-08-05) — build + unit tests all green, but not visually verified: on a Done (or WaitingForReview/Failed/Cancelled) task with a reported roadblock, the ROADBLOCK card shows a reply textbox + Send button under the roadblock text. Check layout/spacing against the AskUser question card it's modeled on, Enter-to-send, the disabled state + hint text when there's no session ID to resume, and that an override-slot-busy error shows up in the footer log strip (not a modal) with the typed text still in the field. Approve should go straight to Done with no merge attempt. Design choice: the review range lives as two new nullable columns directly on TaskEntity (not a phantom WorktreeEntity row), specifically so list_worktrees/the Worktrees overview never see it.

  • Post-merge verify gate (2026-08-05) — build + unit tests all green (incl. real-process VerifyCommandRunner exit-code/output/timeout tests and TaskMergeService success/failure/ timeout paths via a fake runner), but not visually verified: open a list's Settings modal, confirm the new "VERIFICATION" section renders below Agent with a settable/clearable VerifyCommand field; approve a task on a list with a failing command configured and confirm the footer/error surfacing (ShowErrorAsync) actually shows the verify failure message instead of silently looking like nothing happened. Also no real-build smoke test (a real dotnet build/ dotnet test invocation as the configured command) — only fast synthetic commands (exit N, ping for timeout) were exercised.

Offene Verifikation (2026-08-06, Resume planning session)

planning_session_id wurde nie befüllt (der Setter hatte keinen Aufrufer), weil die interaktive Planning-Session ihre claude-Session-Id nie zurückmeldet — Resume konnte deshalb nie funktionieren. PlanningSessionManager.ResumeAsync liest die Id jetzt beim ersten Resume aus dem Transkript, das Claude Code unter ~/.claude/projects/<encodiertes cwd>/<sessionId>.jsonl für den Planning-Worktree ablegt (PlanningTranscriptLocator), und persistiert sie. Unit-Tests grün, nicht visuell verifiziert:

  • Planning-Session starten, Fenster/Pane schließen, Task erneut öffnen → „Resume" muss die ConPTY-Pane mit der fortgesetzten Unterhaltung öffnen (nicht mit leerem Verlauf).
  • Ohne Transkript (z. B. Session nie wirklich gestartet): Fehlermeldung „No Claude session transcript found…" landet sichtbar im Footer-Error-Strip (Terminal.StartErrorErrorReported), nicht still.
  • Risiko: das Verzeichnis-Encoding (~/.claude/projects/, jedes Nicht-Alphanumerische wird -) ist undokumentiertes CLI-Verhalten — ändert es sich, findet der Locator nichts und Resume meldet sauber „cannot resume" (fail-safe, kein falscher Resume).

Offene Verifikation (2026-08-05, Usage Monitor)

  • Visueller Pass Usage-Pill (Footer und Mission-Control-Header): Text/Tooltip, Dot-Zustände normal/warn/stale/blocked, Dark/Light.
  • Visueller Pass Usage-Monitor-Modal: Gauges (dynamisch aus limits[]), Modell-/Task- Tabellen, Info-Bänder (stale/gate-blocked), 7d/30d-Presets + Custom-Range, Dark/Light.
  • E2E Gate: das Gate greift real, sobald ein Bucket (five_hour/seven_day) die konfigurierte Schwelle reißt — Queue-Nachschub pausiert, laufende Runs/RunNow/ConPTY/ Planning/Prime bleiben unberührt — und die Queue nimmt nach dem Reset selbstständig wieder auf (30s-Backstop, kein persistenter Pause-Zustand).
  • Risiko: der Usage-Endpoint (GET https://api.anthropic.com/api/oauth/usage) ist undokumentiert und kann sich ändern; bei Ausfall/Formatänderung ist das Gate wirkungslos (fail-open by design — kein Blocker, aber der Schutz fällt dann aus, ohne dass es auffällt).

Nachtrag 2026-08-05: 429-Fix (Poll-Kadenz + Refresh-Button)

Der 60s-Poll lief in 429s. Neu: aktivitätsabhängige Kadenz (5 Min. solange ein Task Running ist, sonst 15 Min.), 429-Backoff mit Retry-After, und ein „Jetzt aktualisieren"-Button im Usage-Monitor-Modal (RefreshUsageUsageMonitorService.RefreshNowAsync, 10s-Cooldown). Unit-Tests grün, offen:

  • Visueller Pass Refresh-Button im Modal (Button + Spinner + Hinweiszeile, Dark/Light, en/de) — Teil des oben schon offenen Modal-Passes.
  • E2E: über ≥20 Min. mit und ohne laufenden Task beobachten, dass keine 429s mehr im Worker-Log auftauchen und die Pill trotzdem aktuell bleibt.
  • Beachten: die Pill wird jetzt erst nach 3× 15 Min. als stale markiert — ein echter Endpoint-Ausfall fällt vorher nur über LastError auf (der IsStale sofort setzt).

Offene Verifikation (2026-08-05, Max-Turns-Ceiling)

Build + unit tests grün (ResolveMaxTurns-Klemmung, Repository-Backfill von model_presets, Migration AddMaxTurnsCeiling gegen eine Scratch-DB angewendet), aber nicht visuell verifiziert:

  • Agent-Settings-Editor (Task und Liste): Max-Turns-Feld auf einen Wert über der Ceiling (Default 80) setzen, Hinweistext unter dem NumericUpDown erscheint ("Runs are capped at {N} turns…").
  • Settings → Allgemein → Vorgaben pro Modell: eine Zeile über 80 setzen, derselbe Hinweistext erscheint unter der Zeile.
  • MaxTurnsCeiling ist seit 2975f90 selbst editierbar (Settings → Allgemein, SettingsModalView.axaml) — Feld prüfen: Wert ändern, speichern, Hinweistexte oben ziehen mit.

Offene Verifikation (2026-08-05, Environment Checks / SystemCheckPage)

Checks + SystemCheckPage (claudedo/06aca9b3…) und das ExecutableResolver-Wiring im Worker (claudedo/40272c0b…) sind seit 2026-08-06 auf main gemerged; die frühere „erst mergen"- Voraussetzung ist erledigt. Details → installer-preflight in docs/explore-notes/README.md und der Abschnitt „Environment Checks" in src/ClaudeDo.Installer/CLAUDE.md.

Update (2026-08-06): beide Folge-Features sind jetzt implementiert und auf main.

  • Diagnose-Sektion (Config-Modus/SettingsWindow): Pages/DiagnosePage/ + geteilte Checks/CheckListViewModel.cs/Checks/CheckListView.xaml (auch von SystemCheckPage genutzt, keine zweite Implementierung). Unit-getestet (tests/ClaudeDo.Installer.Tests/Pages/DiagnosePage/DiagnosePageViewModelTests.cs).
  • „Claude Help Me"-Button: Core/ClaudeHelpLauncher.cs + SystemCheckPageViewModel/-View, unit-getestet (tests/ClaudeDo.Installer.Tests/Core/ClaudeHelpLauncherTests.cs).

Beides nicht visuell verifiziert:

  • Help-Me-Button ist deaktiviert, wenn claude-cli nicht Ok ist oder claude-auth Failed ist (bleibt aktiv bei Unknown), mit erklärendem Tooltip — unit-getestet.
  • „Claude Help Me" öffnet tatsächlich ein Terminal mit laufender Claude-Session, und die Session hat den Diagnose-Report gelesen — nicht verifiziert (der eigentliche Terminal-Start/wt.exe-Zusammenspiel und die Session-Qualität sind nur über die injizierte IProcessLauncher-Fake getestet, nie mit einem echten Terminal/CLI).
  • Platzierung des Help-Me-Buttons: er sitzt seit dem Merge der Diagnose-Sektion in einer eigenen Zeile unter dem geteilten Check-Listen-Footer (der reservierte Slot im Footer entfiel mit der Extraktion nach CheckListView.xaml). Optisch prüfen, ob das so bleiben soll oder ob der Button in den geteilten Footer gehört.
  • Diagnose-Sektion im Config-Modus: Öffnen von SettingsWindow löst keinen Prüflauf aus, Klick auf „Erneut prüfen" schon; zeigt die echten installierten Pfade/Ports (nicht die InstallContext-Defaults), und der laufende Worker auf dem konfigurierten SignalR-Port gilt nicht als Konflikt — unit-verifiziert, visueller Durchlauf noch offen.

Weitere Punkte, gebaut + unit-getestet auf main, aber nicht visuell verifiziert:

  • SystemCheckPage: Layout, Icon-/Farbwirkung der vier Status (Ok grün / Warnung orange / Fehler rot / Unbekannt grau — StatusGreenBrush/StatusOrangeBrush/StatusRedBrush/ StatusGrayBrush), Lesbarkeit der Hint-Texte, DE und EN.
  • Weiter-Button gesperrt bei einem echten blockierenden Fehler (z. B. claude nicht im PATH → claude-cli Error/Failed), und der Grund ist in der Zusammenfassungszeile sichtbar (nennt den/die blockierenden Check(s) namentlich).
  • „Erneut prüfen" wechselt einen Status live (z. B. git-Identity setzen → Warnung verschwindet), ohne dass ein zweiter paralleler Lauf startet, wenn währenddessen erneut geklickt wird.
  • Update-Modus zeigt die SystemCheckPage nicht (Wizard bleibt Welcome + Install).
  • Auf einem Rechner mit npm-installiertem claude.cmd: claude-cli-Check findet es (Detail-Text „Resolved via a shim…"), und ein Task läuft im Worker durch (bestätigt, dass ClaudeProcess/ClaudeCliPreflight den Shim über cmd.exe /c tatsächlich startet, nicht nur, dass der Check ihn findet).

Bewusst verworfen (nicht erneut vorschlagen)

  • CI-Build/Test-Pipeline — push-to-main + release-on-push deckt das ab; Tests laufen am Ende jeder Session.
  • Real-claude-Smoke-Test als xUnit-Test — kein Claude in dotnet test; bleibt manueller Check. Tests nutzen FakeClaudeProcess.
  • architecture.md / ADRs — die per-Projekt-CLAUDE.md-Dateien sind die lebende Doku.
  • Task-Mailbox-Integration — geparkt; das generische mcp__mailbox__*-Plugin reicht (mailbox-proposal.md).
  • Tag-Negation, Tag-Multi-Select, Notes-lists.kind-Switch, Install-Service-Skript — durch die aktuelle Architektur überholt.