docs(open): regenerate against current code state

Old open.md was dated 2026-04-13 and predated Planning Sessions, Prime
Claude, Self-Update, External MCP, editable status/tags, BlockedBy
chains, and the worker state consolidation. New version audits each
plan/improvement-plan item against the source tree, marks DONE/PARTIAL/
OPEN with file evidence, adds falsifiable pass-criteria to the
verification matrix, and lists the slices that shipped between
2026-04-13 and 2026-04-30 in a dedicated §0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
mika kuns
2026-04-30 14:17:55 +02:00
parent df66c4af46
commit a6608bf8b3

View File

@@ -1,229 +1,281 @@
# ClaudeDo — Offene Punkte # ClaudeDo — Offene Punkte
Stand: 2026-04-13 nach Slice F. Branch `main` @ `48e4aab`. Alle Tests grün (38/38), Build 0 Warnings. Stand: 2026-04-30. Neu erstellt nach Code-Audit gegen `plan.md`, `improvement-plan.md` und `mailbox-proposal.md`.
Dieses Dokument listet alles, was noch fehlt — gruppiert nach Aufwand/Risiko und mit konkreten Datei-Pointern, damit wir es in der IDE der Reihe nach durchgehen können. Die alte Version dieses Dokuments war auf 2026-04-13 ("nach Slice F") datiert und ignorierte die seither gelandeten Slices (Planning Sessions, Prime Claude, Self-Update, Externe MCP-Tools, editierbare Status/Tags, BlockedBy-Chains). Diese Version trennt sauber zwischen **erledigt**, **teilweise**, **offen** — und listet das, was inzwischen gebaut wurde, explizit als „shipped" auf, damit es nicht verloren geht.
Legende: ✅ DONE — 🟡 PARTIAL — ⬜ OPEN — ⛔ DROPPED
---
## 0. Was seit dem 2026-04-13 dazugekommen ist
Diese Slices gab es im alten Dokument noch nicht (oder nur als Platzhalter). Sie sind **fertig im Code**, brauchen aber jeweils noch ein paar Polish-Punkte (siehe Sektion 2/3).
| Slice | Worker-Anker | UI-Anker | Status |
|---|---|---|---|
| **Planning Sessions** (Plan B+C) | `Planning/PlanningSessionManager`, `PlanningChainCoordinator`, `PlanningMcpService` | `Views/Planning/PlanningDiffView`, `ConflictResolutionView`, `UnfinishedPlanningModalView` | ✅ Code, manuelle Verifikation siehe §1.1 |
| **Prime Claude** (geplante Recurrence) | `Prime/PrimeScheduler`, `NextDueCalculator`, `PrimeRunner` | `ViewModels/Modals/PrimeClaudeTabViewModel`, `Views/Controls/ThemedDatePicker` | ✅ Code, manuelle Verifikation siehe §1.2 |
| **Self-Update System** (Gitea Releases) | — | `ClaudeDo.Releases` (`ReleaseClient`, `SelfUpdater`, `ChecksumVerifier`, `VersionComparer`), `ClaudeDo.Installer` (Pages/Steps/Core) | ✅ Code, manuelle Verifikation siehe §1.3 |
| **Externes MCP-Endpoint** (11 Tools für Drittsessions) | `External/ExternalMcpService` (`ListTaskLists`, `ListTasks`, `GetTask`, `AddTask`, `UpdateTask`, `UpdateTaskStatus`, `SetTaskTags`, `ListTags`, `DeleteTask`, `RunTaskNow`, `CancelTask`), `ExternalMcpAuthMiddleware` (X-ClaudeDo-Key) | — | ✅ Code, ohne Tests am Endpoint selbst |
| **Editierbare Status & Tags** (entkoppelt vom `agent`-Tag) | `WorkerHub.SetTaskStatus`, `SetTaskTags`, `UpdateTaskAgentSettings`; Queue-Picker filtert nicht mehr nach `agent`-Tag | `DetailsIslandViewModel`, Status-/Tag-Kontextmenü in `TasksIslandView` | ✅ Code |
| **BlockedBy-Chains** (sequenzielle Subtask-Ausführung) | `TaskStateService.BlockOn`/`UnblockAsync`, `QueuePicker` filter `BlockedByTaskId IS NULL`, `PlanningChainCoordinator.OnChildFinishedAsync` | Drittes Feld neben `Status` und `PlanningPhase` | ✅ Code, Migration `20260423154708_AddPlanningSupport` |
| **Worker-State-Konsolidierung** | `TaskStateService` ist alleiniger Owner von `Status`/`PlanningPhase`/`BlockedByTaskId`-Writes; `OverrideSlotService` ausgelagert; `QueueWaker` + `QueuePicker` getrennt | — | ✅ Code |
| **MarkdownView / Tabbed Settings / About-Modal / Prime-Status-Footer / Doppelklick-Edit** | — | `Views/MarkdownView`, `SettingsModalView` als `TabControl`, `AboutModalView`, transient Prime-Status in Footer, `DoubleTapped` an List/Task-Rows | ✅ Code |
--- ---
## 1. Verification (vor allem anderen) ## 1. Verification (vor allem anderen)
Die in `plan.md` definierten Verification-Steps sind teilweise nur durch Build/Tests abgedeckt. Diese sollten manuell einmal durchlaufen werden, BEVOR wir Polish bauen — damit wir wissen, was tatsächlich kaputt ist. Der Großteil der Verification-Steps aus `plan.md` ist im Code abgedeckt — was fehlt ist die **manuelle Bestätigung mit explizit notiertem Pass-Kriterium**. Ohne falsifizierbare Observable produziert ein Manual-Run nur "sah ok aus".
| # | Plan | Status | Was tun | ### 1.0 Plan-Verification 113
|---|------|--------|---------|
| 1 | Schema-Init | Auto verifiziert (Worker startet ohne Crash, WAL-Files entstehen) | OK |
| 1a | SignalR-Endpoint | Manuell verifiziert (HTTP 400 auf `/hub` ohne Handshake) | OK |
| 1b | Hub-Roundtrip `Ping` | **Nicht getestet** | Test-Client schreiben oder UI starten und im Log nach "pong" schauen |
| 2 | `claude --version` Preflight | **Nicht implementiert** | `Worker/Program.cs`: vor `app.Run()` einmal `claude --version` shellen und bei Exit≠0 abbrechen |
| 3 | Smoke-Spawn (`claude -p` mit Prompt "ping") | **Nicht getestet** | Integrationstest schreiben oder einmal manuell laufen lassen |
| 4 | E2E Happy Path (Non-Worktree) | **Nicht getestet** | UI starten → Liste "Test" anlegen → Task mit Tag `agent` + Status `queued` + Description "Schreibe ein Haiku über Intralogistik" → Run abwarten → Result prüfen |
| 5 | Worktree Happy Path | **Nicht getestet** | Manueller Test mit echtem Repo (z.B. einem temp-Repo) |
| 6 | No-Changes-Run | **Nicht getestet** | Prompt der nichts ändert → `head_commit` bleibt NULL |
| 7 | Kein Git-Repo | **Nicht getestet** | working_dir auf `C:\Temp` → Task `failed`, keine `worktrees`-Row |
| 8 | Merge-UI | **Nicht getestet** (UI ruft `GitService.MergeFfOnlyAsync`, aber nie ausgeführt) | Manuell |
| 9 | Override-Parallelität | Tests vorhanden für Slot-Logik, **End-to-End nicht** | UI: zwei Tasks queuen, `Run Now` auf der zweiten → beide laufen parallel |
| 10 | Schedule | Logik per Test abgedeckt, **End-to-End nicht** | Task mit `scheduled_for = now+2min` |
| 11 | Worker-Offline-Erkennung | UI hat Status-Bar, aber **nicht visuell verifiziert** | Worker killen, schauen ob Status auf "offline" wechselt |
| 12 | Live-Stream | **Nicht getestet** | Während Run TaskDetail öffnen, beobachten ob ndjson-Zeilen erscheinen |
| 13 | Wake-up (UI ruft `WakeQueue` nach Anlage) | Implementiert in `TaskListViewModel`, **nicht visuell verifiziert** | Tasks nach Anlage in <1s gepickert |
**Vorschlag:** Wir machen einmal Step 4 (Haiku-Happy-Path) gemeinsam — wenn das läuft, ist die ganze Pipeline lebendig. | # | Item | Status | Pass-Kriterium (was muss konkret zu sehen sein) |
|---|------|---|---|
| 1 | Schema-Init | ✅ | `~/.todo-app/todo.db` + `*-wal` + `*-shm` existieren; EF-Migrationsverlauf in `__EFMigrationsHistory` enthält alle 8 Migrationen; Worker-Log: „listening on …" |
| 1a | SignalR-Endpoint | ✅ | `curl http://127.0.0.1:47821/hub` → HTTP 400 (kein Handshake) |
| 1b | Hub-Roundtrip `Ping` | 🟡 | UI-Statusbar zeigt „Connected"; `WorkerClient.PingAsync()` liefert `"pong"` (UI-Test fehlt) |
| 2 | `claude --version` Preflight | ✅ | `Worker/Lifecycle/ClaudeCliPreflight.cs` + Wiring in `Program.cs`. Kaputter `claude_bin``LogCritical(...) + Environment.Exit(1)`. Skip via `CLAUDEDO_SKIP_CLI_PREFLIGHT=1`. Tests: `tests/.../Lifecycle/ClaudeCliPreflightTests.cs` |
| 3 | Smoke-Spawn (`claude -p` Prompt „ping") | ⬜ | `task_runs`-Row mit `session_id NOT NULL`, `result` non-empty, `output_tokens > 0` |
| 4 | E2E Happy Path (Non-Worktree) | ⬜ | Liste „Test" anlegen → Task „Schreibe ein Haiku über Intralogistik" → `tasks.status='Done'`, `tasks.result IS NOT NULL`, Logfile unter `~/.todo-app/logs/<taskId>.ndjson`, UI-Row mit Done-Badge |
| 5 | Worktree Happy Path | ⬜ | Liste mit `working_dir` auf temp-Repo, Task mit Codeänderung → `worktrees.state='active'`, `head_commit IS NOT NULL`, `diff_stat` non-empty, Branch `claudedo/<id>` auf Disk |
| 6 | No-Changes-Run | ⬜ | Prompt der nichts ändert → `tasks.status='Done'` aber `worktrees.head_commit IS NULL`, `diff_stat IS NULL` |
| 7 | Kein Git-Repo | ⬜ | `working_dir=C:\Temp` (kein Repo) → `tasks.status='Failed'`, **keine** `worktrees`-Row, Worker-Log enthält Git-Fehler |
| 8 | Merge-UI | 🟡 | `MergeTask`-Hub-Methode + `MergeModalView` vorhanden, manueller Run nicht durchgespielt → `worktrees.state='merged'`, im Ziel-Repo `git log` zeigt Commit, `git worktree list` ohne Branch |
| 9 | Override-Parallelität | 🟡 | `OverrideSlotService`-Tests grün; UI-E2E nicht durchgespielt → `WorkerHub.GetActive` ≥ 2 Einträge bei Run+RunNow |
| 10 | Schedule | 🟡 | `QueuePicker`-Tests grün; UI-E2E nicht → `scheduled_for=now+2min` bleibt Queued, dann automatisch Running, `started_at >= scheduled_for` |
| 11 | Worker-Offline-Erkennung | 🟡 | `WorkerClient.OnServerConnectionClosed` + Auto-Reconnect implementiert (`WithAutomaticReconnect`); visuell prüfen: nach `taskkill` der Worker-Exe wechselt Statusbar in ≤ 5s auf „Offline", `RunNow`-Buttons disabled |
| 12 | Live-Stream | 🟡 | `ClaudeProcess` streamt NDJSON via `TaskMessage`-Event, UI hat `LiveTail`; visuell prüfen: während Run laufen ndjson-Zeilen ein |
| 13 | Wake-up (`WakeQueue` nach Anlage) | 🟡 | `QueueWaker.Wake()` wird bei Enqueue aufgerufen; visuell prüfen: Task wechselt in ≤ 1s auf Running (statt nach `queue_backstop_interval_ms`=30s) |
**Empfohlener Sprint:** Steps 37 in einem Rutsch durchspielen (alles non-UI), parallel daneben 813 visuell beim normalen App-Lauf abhaken.
### 1.1 Planning Sessions — Manual Verification (unverändert relevant)
Bedingt durch Slice "Planning B/C". Ablauf identisch zur alten open.md:
1. Manual-Task mit Title + TODO-Description anlegen.
2. Rechtsklick → **Open planning Session** → Windows Terminal mit Claude CLI öffnet.
3. In CLI: zwei Children via `mcp__claudedo__create_child_task` anlegen.
4. UI: Drafts erscheinen eingerückt, italic, mit `DRAFT`-Badge; Parent zeigt `PLANNING`-Badge.
5. Chevron klappt ein/aus.
6. CLI `finalize` → Children werden Queued (erste) bzw. Queued+BlockedBy (Rest); Parent flippt von `Active` auf `Finalized` (`PLANNED`-Badge); erste Child startet automatisch.
7. Neuer Planning-Task, Terminal ohne Finalize schließen → Rechtsklick öffnet Resume/Finalize-now/Discard-Modal.
8. Delete-Versuch auf Parent mit Children → freundlicher Fehlerdialog, kein Delete.
**Bekannte Follow-ups (non-blocking):**
-`Border.badge.planned` (blau) ist in `IslandStyles.axaml` definiert, wird aber nie angewendet — `TaskRowView` behält die `planning`-Klasse für `Active` UND `Finalized`, daher amber statt blau bei finalisiert. Entweder Class-Swap auf `planned` bei `Finalized`, oder die unused Style+Brush entfernen.
- ⬜ Tote `Instance`-Statics auf `BoolToItalicConverter` und `BoolToDraftOpacityConverter``App.axaml` registriert via Resource-Dictionary, die statischen Members können weg.
-`Ui.Tests` IWorkerClient-Fakes (`DetailsIslandPlanningTests`, `PlanningDiffViewModelTests`, `ConflictResolutionViewModelTests`) fehlen `OpenInteractiveTerminalAsync` und `QueuePlanningSubtasksAsync` — Constructor-Drift, Fakes auf gemeinsame abstrakte Basis rebasen.
### 1.2 Prime Claude — Manual Verification
Slice "Prime" (Recurrence-Scheduler).
1. Settings → Prime-Claude-Tab → Schedule mit `at: 09:00`, `every: workday`, `task_template: "Daily Standup"` anlegen.
2. Test mit verschobenem `IPrimeClock` (oder Schedule mit `at: now+1min`) → bei Trigger erscheint Toast/Footer-Notification „Prime fired", neuer Task entsteht in der Ziel-Liste.
3. Worker-Restart innerhalb des Schedule-Fensters → Catch-up läuft genau einmal (kein Doppelfeuer).
4. Schedule editieren → `next_due_at` wird neu berechnet; UI-Anzeige aktualisiert.
5. Schedule löschen → keine weiteren Trigger, keine ghost-Tasks.
### 1.3 Self-Update — Manual Verification (aus alter open.md, weiterhin gültig)
Voraussetzung: funktionierendes Gitea-Release unter `git.kuns.dev/releases/ClaudeDo` mit drei Assets — `ClaudeDo-<version>-win-x64.zip`, `ClaudeDo.Installer-<version>.exe`, `checksums.txt`.
1. Baseline-Version (z.B. `0.2.x`) normal installieren.
2. Neues Release `v0.3.0` mit frischem Installer + App-Zip + Checksums veröffentlichen.
3. App starten → Banner erscheint: `Update available: v0.2.x → v0.3.0`.
4. **Update now** klicken → App schließt, Installer öffnet im Update-Mode, läuft, restartet Worker.
5. App neu starten → Banner weg; `Help → Check for updates` zeigt kurz „You're up to date (v0.3.0)".
6. `v0.2.x`-Installer manuell starten → bietet Self-Update auf v0.3.0 an. **Update** → laufende Exe wird ersetzt, Wizard öffnet auf neuer Version.
7. Schritt 6 mit **Continue anyway** → Wizard öffnet ohne Self-Update.
8. Schritt 6 mit **Cancel** → Installer beendet ohne Aktion.
9. Network-Kill in App und Installer beim Start → silent fallback (kein Error, kein Banner).
--- ---
## 2. UI-Polish (kritisch für Benutzbarkeit) ## 2. UI-Polish
Im aktuellen Stand kompiliert die UI, aber mehrere Stellen sind als `// TODO` markiert. Reihenfolge nach Schmerz: ### 2.1 Folder-Picker für `Working Directory` ⬜
- **Datei:** `Views/ListSettingsModalView.axaml` + zugehöriges VM
### 2.1 Folder-Picker für `Working Directory`
- **Datei:** `src/ClaudeDo.Ui/Views/ListEditorView.axaml` + `src/ClaudeDo.Ui/ViewModels/ListEditorViewModel.cs`
- **Aktuell:** plain `TextBox` — Pfad muss getippt werden. - **Aktuell:** plain `TextBox` — Pfad muss getippt werden.
- **Soll:** Button "…" daneben → öffnet `IStorageProvider.OpenFolderPickerAsync`, schreibt Pfad ins Feld. - **Soll:** Button …" daneben → öffnet `IStorageProvider.OpenFolderPickerAsync`, schreibt Pfad ins Feld.
- **Aufwand:** klein, ~30 Zeilen. - **Aufwand:** klein.
### 2.2 Delete-Confirmation ### 2.2 Delete-Confirmation
- **Dateien:** `MainWindowViewModel.DeleteList`, `TaskListViewModel.DeleteTask` - **Aktuell:** Listen/Tasks-Delete läuft direkt ohne Rückfrage. Datenverlust-Risiko.
- **Aktuell:** löscht direkt ohne Rückfrage. Datenverlust-Risiko. - **Soll:** generischer `ConfirmDialog` (1× bauen, mehrfach nutzen), Mini-Dialog „Wirklich löschen?".
- **Soll:** Mini-Dialog "Wirklich löschen?" mit Ja/Nein. - **Aufwand:** klein.
- **Aufwand:** klein, generisches `ConfirmDialog` lohnt sich (1× bauen, mehrfach nutzen).
### 2.3 Markdown-Rendering für Result + Description ### 2.3 Markdown-Rendering Result + Description
- **Datei:** `src/ClaudeDo.Ui/Views/TaskDetailView.axaml` - `Views/MarkdownView.axaml` + Detail-Pane verwenden Markdown.Avalonia.
- **Aktuell:** `TextBox IsReadOnly="True"` mit Plaintext.
- **Soll:** `Markdown.Avalonia` Package einbinden und auf `MarkdownScrollViewer` umstellen.
- **Aufwand:** mittel — Package + ein paar XAML-Anpassungen. Theme-Integration kann nerven.
### 2.4 Live-Log Auto-Scroll ### 2.4 Live-Log Auto-Scroll
- **Datei:** `src/ClaudeDo.Ui/Views/TaskDetailView.axaml.cs` (oder im VM) - **Datei:** `Views/DetailsIslandView.axaml(.cs)` (Live-Tail-Section)
- **Aktuell:** ndjson-Zeilen werden angehängt, aber Scrollposition bleibt stehen. - **Aktuell:** ndjson-Zeilen werden angehängt, Scrollposition bleibt stehen.
- **Soll:** Bei jeder neuen Zeile `ScrollViewer.ScrollToEnd()` solange User nicht manuell hochgescrollt hat (Sticky-Bottom-Pattern). - **Soll:** Sticky-Bottom-Pattern — bei jeder neuen Zeile `ScrollToEnd()`, solange User nicht manuell hochgescrollt hat. Attached-Behavior reicht.
- **Aufwand:** klein, ein attached behavior reicht.
### 2.5 Diff-Viewer ### 2.5 Diff-Viewer 🟡
- **Datei:** `TaskDetailViewModel.ShowDiffAsync` - `DiffModalView.axaml` + `PlanningDiffView` existieren; integriert für Planning-Merges.
- **Aktuell:** `Process.Start("cmd", "/k git diff …")` — separates Konsolenfenster, hässlich. - **Offen:** Task-Level-Diff (Worktree vs. main) noch nicht im Modal-Flow geprüft. Verwenden statt `Process.Start("cmd /k git diff …")`.
- **Soll:** entweder unified-diff inline anzeigen (`git diff` Output in `TextBox` mit Mono-Font + Color für +/-) oder einen externen Diff-Tool-Hook (`git difftool`).
- **Aufwand:** mittel. MVP: einfach nur den Diff-Output in einem Modal.
### 2.6 Status-Bar Active-Tasks Live-Update ### 2.6 Status-Bar Active-Tasks Live-Update
- **Datei:** `StatusBarViewModel` - **Datei:** `ViewModels/StatusBarViewModel`
- **Risiko:** das Slot-State-Update kommt vom WorkerClient, aber `RunNowCommand.NotifyCanExecuteChanged` triggert nicht pro Item bei `IsConnected`-Wechsel (vom Slice-F-Agent dokumentiert). - **Risiko:** `RunNowCommand.NotifyCanExecuteChanged` triggert nicht pro Item bei Connection-Change.
- **Soll:** Über `WeakReferenceMessenger` (CommunityToolkit.Mvvm) eine Connection-Change-Message verteilen, an die alle `TaskItemViewModel` lauschen. - **Soll:** `WeakReferenceMessenger`-Connection-Change-Message; alle `TaskRowViewModel` lauschen.
- **Aufwand:** klein, aber muss sauber gemacht werden. - **Aufwand:** klein, muss sauber gemacht werden.
### 2.7 Settings-Dialog ### 2.7 Settings-Dialog
- **Datei:** *neu*`Views/SettingsDialog.axaml` + VM - `SettingsModalView` als `TabControl`, Tabs: General, Prime Claude, etc. Persistiert in `~/.todo-app/ui.config.json` und `worker.config.json`.
- **Aktuell:** `~/.todo-app/ui.config.json` muss von Hand editiert werden.
- **Soll:** Dialog mit Feldern: DB-Pfad, SignalR-Port, Default-Tags. Persistiert zurück in JSON. ### 2.8 (NEU) Planning-Phase Badge-Farbe für `Finalized` ⬜
- **Aufwand:** mittel. Achtung: Port-Wechsel braucht Worker-Restart. Siehe §1.1 — `planning`-Klasse bleibt amber, blauer `planned`-Style nicht angewendet.
### 2.9 (NEU) Tote Converter-Statics entfernen ⬜
`BoolToItalicConverter.Instance`, `BoolToDraftOpacityConverter.Instance` — siehe §1.1.
--- ---
## 3. Worker-Robustheit ## 3. Worker-Robustheit
### 3.1 CLI-Preflight beim Worker-Start ### 3.1 CLI-Preflight beim Worker-Start
- **Datei:** `src/ClaudeDo.Worker/Program.cs` - `src/ClaudeDo.Worker/Lifecycle/ClaudeCliPreflight.cs` + Wiring in `Program.cs`. Tests: `tests/.../Lifecycle/ClaudeCliPreflightTests.cs`. Skippable via `CLAUDEDO_SKIP_CLI_PREFLIGHT=1`.
- **Soll:** vor `app.Run()` `claude --version` ausführen; bei Fehler `app.Logger.LogCritical` + `Environment.Exit(1)`.
- **Aufwand:** klein, ~20 Zeilen. Liefert Verification Step 2.
### 3.2 Worktree-Cleanup beim Anlege-Failed ### 3.2 Worktree-Cleanup beim Anlege-Failed
- **Datei:** `src/ClaudeDo.Worker/Runner/WorktreeManager.cs` - **Datei:** `src/ClaudeDo.Worker/Runner/WorktreeManager.cs`
- **Aktuell:** Wenn `WorktreeAddAsync` zwischen `CreateAsync`-Schritten failt (z.B. Branch existiert schon), bleibt evtl. ein halbangelegter Worktree-Dir auf der Platte. - **Soll:** try/finally — bei Fehler zwischen `git worktree add` und DB-Insert `git worktree remove --force` als Best-Effort-Cleanup.
- **Soll:** try/finally — bei Fehler `git worktree remove --force` als Best-Effort-Cleanup.
- **Aufwand:** klein. - **Aufwand:** klein.
### 3.3 Logging über `Microsoft.Extensions.Logging` strukturieren ### 3.3 Logging über file-Sink ⬜
- **Datei:** alle Worker-Komponenten - ILogger ist überall verdrahtet, aber kein File-Sink konfiguriert.
- **Aktuell:** ILogger wird benutzt, aber kein File-Sink konfiguriert. - **Soll:** Serilog oder `Karambolage.Extensions.Logging.File` — für Service-Modus zwingend, console-only ist im SCM-Fenster verloren.
- **Soll:** Optional Serilog oder einfach `AddFile` (Karambolage.Extensions.Logging.File) — Service-Modus braucht persistente Logs außerhalb der Console.
- **Aufwand:** klein. - **Aufwand:** klein.
### 3.4 Tag-Negation / Exclusion (Plan-TODO) ### 3.4 Tag-Negation / Exclusion
- **Plan-Sektion:** "Tag-Modell" - Tags sind weiterhin rein additiv (`list_tags task_tags`). Nach Slice „Editierbare Tags" weniger dringend, aber nicht gelöst.
- **Aktuell:** Tags sind rein additiv (`list_tags task_tags`). - **Soll:** entweder neue Tabelle `task_tag_exclusions` oder Prefix `!tag` im task_tags-Eintrag.
- **Soll:** Mechanismus, um auf Task-Ebene einen List-Tag auszuschließen. Z.B. neue Tabelle `task_tag_exclusions` ODER ein Prefix `!tag` im task_tags-Eintrag.
- **Aufwand:** mittel — Schema + Repo + Tests + UI. - **Aufwand:** mittel — Schema + Repo + Tests + UI.
--- ---
## 4. Service-Deployment (Plan-Sektion „Worker als Windows-Service") ## 4. Service-Deployment
### 4.1 Windows-Service-Hosting in Code ### 4.1 Windows-Service-Hosting
- **Datei:** `src/ClaudeDo.Worker/Program.cs` - `Program.cs` ruft `builder.Host.UseWindowsService(o => o.ServiceName = "ClaudeDoWorker")`.
- **Pakete:** `Microsoft.Extensions.Hosting.WindowsServices`
- **Soll:**
```csharp
builder.Host.UseWindowsService(o => o.ServiceName = "ClaudeDoWorker");
builder.Logging.AddEventLog(...);
```
- **Aufwand:** klein.
### 4.2 Pfad-Auflösung absolut machen ### 4.2 Pfad-Auflösung absolut
- Bereits in `WorkerConfig.Load` per `Paths.Expand` gemacht — verifizieren, dass auch `cfg.ClaudeBin` ggf. in Service-PATH gefunden wird. - `WorkerConfig.Load` expandiert `~`/`%USERPROFILE%` für alle Pfad-Felder.
### 4.3 Install-Skripte / Doku ### 4.3 Install-Skripte / Doku
- **Datei:** *neu* — `docs/install-service.md` oder `scripts/install-service.cmd` - **Datei (neu):** `docs/install-service.md` ODER `scripts/install-service.cmd`
- **Inhalt:** `dotnet publish` + `sc.exe create` + `sc.exe failure` + Hinweis auf `obj=` (User-Account) wegen Claude-CLI-Session. - **Inhalt:** `dotnet publish` + `sc.exe create` + `sc.exe failure` + Hinweis auf `obj=` (User-Account) wegen Claude-CLI-Session.
- **Aufwand:** klein. - **Aufwand:** klein.
### 4.4 (später) Installer-Projekt ### 4.4 Installer-Projekt
- WiX/MSIX, registriert Service + UI-Shortcut. Plan-Sektion „Offene Punkte". - `ClaudeDo.Installer` (WPF) + `ClaudeDo.Releases` mit Pages/Steps/Core/Theme — Self-Update funktioniert (siehe §1.3).
--- ---
## 5. Tests / CI ## 5. Tests / CI
### 5.1 GitHub-Actions / Gitea-Actions Pipeline ### 5.1 CI-Pipeline (Gitea Actions) ⬜
- **Datei:** *neu* — `.gitea/workflows/ci.yml` (oder `.github/workflows/ci.yml`) - **Datei (neu):** `.gitea/workflows/ci.yml`
- **Inhalt:** `dotnet restore` → `dotnet build --no-restore` → `dotnet test --no-build`. Auf Push + PR. - **Inhalt:** `dotnet restore``dotnet build` (csproj-weise wegen `.slnx`-Bug auf .NET 8)`dotnet test`. Auf Push + PR.
- **Achtung:** Pipeline darf NICHT die `.slnx` als Build-Target nehmen — explizite csproj-Liste in einem checked-in Build-Skript.
- **Aufwand:** klein. - **Aufwand:** klein.
### 5.2 Echter SignalR-Roundtrip-Test ### 5.2 SignalR-Hub-Tests ✅
- **Datei:** *neu* — `tests/ClaudeDo.Worker.Tests/Hub/WorkerHubTests.cs` - `tests/ClaudeDo.Worker.Tests/Hub/PlanningHubTests.cs`, `AgentSettingsHubTests.cs` testen Hub-Methoden via Fakes (kein realer SignalR-Roundtrip, aber alle Code-Pfade abgedeckt).
- **Soll:** mit `WebApplicationFactory` + `HubConnectionBuilder` testen, dass `Ping`, `GetActive`, `RunNow`-Throw-Verhalten korrekt sind. Plan-Verification 1b + 9. - **Optional verbleibt:** echter Roundtrip-Test mit `WebApplicationFactory<Program>` + `HubConnectionBuilder` für End-to-End-Validierung der SignalR-Pipeline. Niedriger Mehrwert solange Fakes alle Methoden treffen.
- **Aufwand:** mittel.
### 5.3 Smoke-Test gegen echten `claude` ### 5.3 Smoke-Test gegen echten `claude`
- **Datei:** *neu* — `tests/ClaudeDo.Worker.Tests/Runner/ClaudeProcessSmokeTest.cs` - **Datei (neu):** `tests/ClaudeDo.Worker.Tests/Runner/ClaudeProcessSmokeTest.cs`
- **Soll:** Real-CLI-Test, der mit `[Fact(Skip="..."]` ausgegraut bleibt und nur lokal aktiviert wird, wenn `CLAUDE_AUTHENTICATED=1` Env-Var gesetzt ist. - **Soll:** Real-CLI-Test mit `[Fact(Skip="...")]` ausgegraut, nur lokal aktiviert wenn `CLAUDE_AUTHENTICATED=1` Env-Var gesetzt ist.
- **Aufwand:** klein. - **Aufwand:** klein.
### 5.4 (NEU) ExternalMcpService-Tests ⬜
- `External/ExternalMcpService` hat 11 Tools, aber nur partielle Coverage in `tests/.../External/ExternalMcpServiceTests.cs`. Für jedes Tool mindestens einen Happy-Path + einen Error-Pfad ergänzen.
--- ---
## 6. Dokumentation ## 6. Dokumentation
### 6.1 README.md ### 6.1 README.md
- Komplett fehlt. Mind. 1× kurz: was ist es, wie starten (Worker + UI), wo Config. - Komplett fehlt. Mind. 1× kurz: was ist es, wie starten (Worker + UI), wo Config, wie Self-Update.
- **Aufwand:** klein.
### 6.2 `docs/architecture.md` ### 6.2 docs/architecture.md 🟡
- In `plan.md` schon teilweise enthalten — kann entweder konsolidiert oder explizit ausgegliedert werden. - In `plan.md` enthalten — entweder konsolidieren oder explizit ausgliedern. CLAUDE.md-Dateien pro Projekt sind aktuell de-facto-Architecture-Doc.
### 6.3 ADRs für die getroffenen Entscheidungen ### 6.3 ADRs
- Z.B. „SignalR vs. SQLite-Polling für IPC", „Worktree pro Task", „SignalR über Loopback ohne Auth". - Vorschläge: „SignalR vs. SQLite-Polling für IPC", „Worktree pro Task", „TaskStateService als alleiniger State-Owner", „BlockedByTaskId statt Status='Waiting'", „External MCP als zweite WebApplication".
- **Aufwand:** klein, hilfreich für später. - **Aufwand:** klein, hilfreich für später.
### 6.4 (NEU) Mailbox-Proposal ⬜
- `docs/mailbox-proposal.md` ist als Vorschlag vorhanden, nicht implementiert. Entscheidung: bauen, droppen oder parken? Wenn droppen → Datei entfernen, sonst klare Roadmap.
--- ---
## 7. Bekannte Code-Schulden / Smells ## 7. Bekannte Code-Schulden / Smells
| Stelle | Issue | | Stelle | Issue | Status |
|---|---| |---|---|---|
| `WorkerHub.GetActive` returnt `IReadOnlyList<object>` mit anonymen Typen | Sollte ein expliziter DTO sein (`ActiveTaskDto`), den Worker UND Ui teilen. Aktuell duplizieren beide das Schema. | | `WorkerHub.GetActive` returnt `IReadOnlyList<object>` mit anonymen Typen | Sollte expliziter `ActiveTaskDto` sein, den Worker UND UI teilen | ⬜ |
| `TaskRunner` führt eine `if (list.WorkingDir != null)` Verzweigung mitten in der Methode | Strategy-Pattern (`IRunStrategy`: SandboxStrategy, WorktreeStrategy) wenn die Methode wächst. Aktuell noch klein genug. | | `TaskRunner` führt eine `if (list.WorkingDir != null)`-Verzweigung mitten in der Methode | Strategy-Pattern wenn die Methode wächst, aktuell noch klein genug | ⬜ |
| `App.Services` als public static `ServiceProvider` | Service-Locator-Antipattern. Toleriert, weil nur in `App.OnFrameworkInitializationCompleted` verwendet. Falls mehr Code drauf zugreift → echtes DI durchziehen. | | `App.Services` als public static `ServiceProvider` | Service-Locator-Antipattern, toleriert weil nur in `App.OnFrameworkInitializationCompleted` | ⬜ |
| Embedded `schema.sql` ohne Versionierung | Solange das Schema nicht in Production läuft, OK. Sobald User-Daten existieren → `migrations/` Folder + Version-Tabelle. | | Embedded `schema.sql` ohne Versionierung | Durch EF-Core-Migrationen ersetzt | ✅ |
| CRLF-Warnings beim Commit | `.gitattributes` mit `* text=auto eol=lf` (oder explizit pro Sprache) wäre sauberer. | | CRLF-Warnings beim Commit | `.gitattributes` mit `* text=auto eol=lf` (oder explizit pro Sprache) wäre sauberer | ⬜ |
| Tote Converter-Instances (`BoolToItalicConverter.Instance`, `BoolToDraftOpacityConverter.Instance`) | Per Resource-Dictionary registriert, Statics ungenutzt | ⬜ |
| 1 unausgeführter `// TODO` in `DetailsIslandViewModel` (`SendPromptAsync` ohne Hub-Methode) | Entweder Hub-Methode bauen oder TODO entfernen | ⬜ |
--- ---
## Empfohlene Reihenfolge für die nächste Session ## 8. Improvement Plan (improvement-plan.md, Stand 2026-04-13)
1. **Verification Step 4** zusammen durchspielen → falls etwas grundlegend kaputt ist, jetzt finden, nicht später. | ID | Item | Status | Bemerkung |
2. **CLI-Preflight (3.1)** + **Folder-Picker (2.1)** + **Delete-Confirm (2.2)** — kleine, isolierte Wins. |---|---|---|---|
3. **Auto-Scroll (2.4)** + **Active-Tasks Live-Update (2.6)** — User-Experience im Detail-Pane. | IP-1 | UI ↔ Worker Auto-Reconnect | ✅ | `WorkerClient` mit `WithAutomaticReconnect()` + Reconnect-Handler |
4. **Markdown-Rendering (2.3)** — größer, lohnt sich aber für Lesbarkeit. | IP-2 | Listen-Modus „Notes" (non-autonomous) | ⬜ | Nach Slice „editierbare Status/Tags" weniger dringend (man kann jetzt einen Task ohne `agent`-Tag idle lassen), aber `lists.kind` als sauberer Mode-Switch fehlt. |
5. **Worktree-Cleanup (3.2)** — Robustheit, bevor wir Worktrees ernsthaft nutzen. | IP-3 | Doppelklick öffnet Edit-Dialog | ✅ | `DoubleTapped`-Handler in `ListsIslandView`, `TasksIslandView` |
6. **CI-Pipeline (5.1)** — automatisches Sicherheitsnetz für alles weitere. | IP-4 | Tag Multi-Select Control | ⬜ | Tags sind via Picker im Detail-Pane editierbar, aber kein dediziertes Multi-Select-Control mit Auto-Vervollständigung in Editor-Dialogen. |
7. **Service-Deployment (4)** — wenn die App lokal stabil läuft. | IP-5 | Rechtsklick-Kontextmenü | ✅ | Listen + Tasks haben Context-Menüs (Edit, Delete, Run Now, Show Diff, Merge, Cancel, Status, Tags) |
8. **Settings-Dialog (2.7)** + **Diff-Viewer (2.5)** — Polish. | IP-6 | Schema-Migration-Mechanismus | ✅ | EF-Core-Migrations + `__EFMigrationsHistory` |
9. **Tag-Negation (3.4)** — wenn der Bedarf konkret wird. | IP-7 | Status-Bar Reconnect-States | ✅ | `connected`/`connecting`/`reconnecting`/`offline` farbcodiert |
| IP-8 | Tag-Repository `GetAllKnownTagsAsync` | ✅ | `TagRepository.GetAllAsync` + `WorkerClient.GetAllTagsAsync` |
Punkte 13 sind ein realistischer Block für eine Session.
--- ---
## Self-Update — Manual Verification ## 9. Empfohlene Reihenfolge für die nächsten Sessions
Preconditions: a working Gitea release at `git.kuns.dev/releases/ClaudeDo` with three assets — `ClaudeDo-<version>-win-x64.zip`, `ClaudeDo.Installer-<version>.exe`, and `checksums.txt` listing both. **Block 1 — Verification durchspielen** (kein neuer Code, nur Beweis):
1. §1.0 Steps 37 manuell (Smoke + E2E + Worktree + No-Changes + Kein-Repo) — ist die Pipeline wirklich lebendig?
2. §1.1 Planning-Walkthrough — nach den uncommitted Coordinator-Änderungen einmal durchspielen.
3. §1.2 Prime-Walkthrough — Schedule-Trigger einmal beobachten.
1. Install a baseline version (e.g. `0.2.x`) normally. **Block 2 — Niedrig hängende UI-Polish** (eine Session):
2. Publish a new release tagged `v0.3.0` with fresh installer + app zip + checksums. 4. §2.1 Folder-Picker
3. Launch the app — confirm the banner appears: `Update available: v0.2.x → v0.3.0`. 5. §2.2 Delete-Confirmation
4. Click **Update now** — app closes, installer opens in Update mode, runs, restarts the worker. 6. §2.4 Live-Log Auto-Scroll
5. Re-launch the app — banner is gone; `Help → Check for updates` briefly shows "You're up to date (v0.3.0)". 7. §2.6 Status-Bar Live-Update
6. Run the `v0.2.x` installer manually — confirm it prompts to self-update to v0.3.0. Click **Update** → running exe is replaced and the wizard opens on the new version. 8. §2.8 Planning-Badge-Farbe + §2.9 tote Converter weg
7. Repeat step 6 with **Continue anyway** → wizard opens without self-update.
8. Repeat step 6 with **Cancel** → installer exits without any action.
9. Kill network during startup in both app and installer → confirm silent fallback (no errors, no banner, wizard opens normally).
--- **Block 3 — Robustheit & Service-Deployment**:
9. §3.2 Worktree-Cleanup
10. §3.3 File-Sink-Logging
11. §4.3 Install-Skripte/Doku
## Planning Sessions — Manual Verification (Plan C UI) **Block 4 — Sicherheitsnetz**:
12. §5.1 Gitea-Actions CI-Pipeline (csproj-weise)
13. §5.3 Smoke-Test gegen echten claude
14. §5.4 ExternalMcpService-Tests vervollständigen
Requires Plan B (worker hub endpoints) merged. Until then, only the UI structure/styling checks are meaningful. **Block 5 — Dokumentation & Aufräumen**:
15. §6.1 README
16. §6.3 ADRs (mind. die fünf wichtigsten)
17. §6.4 Mailbox-Proposal: bauen/droppen entscheiden
18. §7 Smells: `ActiveTaskDto`, `.gitattributes`, TODO-Comment
1. Create a Manual task with a title and a TODO-ish description. **Block 6 — Optional / wenn Bedarf konkret wird**:
2. Right-click the task → **Open planning Session** — Windows Terminal opens with Claude CLI running (Plan B). 19. §3.4 Tag-Negation
3. Ask Claude to create two child tasks via `mcp__claudedo__create_child_task`. 20. §IP-2 Notes-Modus
4. Watch the UI: drafts appear indented under the parent, italic, reduced opacity, with a `DRAFT` badge. 21. §IP-4 Tag Multi-Select Control
5. The parent shows a `PLANNING` badge. Click the chevron → children collapse; click again → children expand.
6. Ask Claude to `finalize` — children move to `Queued` (first) and `Queued + BlockedBy` (rest); parent's `PlanningPhase` flips from `Active` to `Finalized` (`PLANNED` badge). The first child must reach `Running` automatically — no manual `WakeQueue` needed (regression-tested in `PlanningEndToEndTests`).
7. In a new planning task, close the terminal without finalize. Right-click the Planning task → the unfinished-session modal opens with Resume / Finalize now / Discard.
8. Attempt to delete a parent with children via the details panel — confirm the friendly error dialog appears and the task is NOT deleted.
**Known followups (non-blocking):**
- `Border.badge.planned` style (blue) is defined in `IslandStyles.axaml` but never applied — `TaskRowView` keeps the `planning` class for both `PlanningPhase=Active` and `Finalized`, so a finalized parent gets the amber badge. Either make the view swap `Classes.planned` when `PlanningPhase` is `Finalized`, or remove the unused style + brush.
- Dead `Instance` statics on `BoolToItalicConverter` and `BoolToDraftOpacityConverter` — App.axaml registers instances via the resource dictionary; the static members can be removed.
- `Ui.Tests` `IWorkerClient` fakes (`DetailsIslandPlanningTests`, `PlanningDiffViewModelTests`, `ConflictResolutionViewModelTests`) miss `OpenInteractiveTerminalAsync` and `QueuePlanningSubtasksAsync` — pre-existing constructor-drift; rebase fakes onto a shared abstract base.