Plan checkboxes stood at zero although P0, A, B, C1 and D are all merged -- anyone reading it would have assumed nothing was built. Ticks the merged packages, records A5's cancellation and the visual pass, and names the two leftovers (the three unused ops.* keys from A3/A4, C2-C5 as the only open group). Also corrects the batch_* tool count from eight to seven and puts the OperationTiming kill-switch note in the Ui CLAUDE.md back into English.
30 KiB
Feedback für langlaufende Operationen — Vorgaben für die Umsetzung
Dieses Dokument ist absichtlich kein Task-Skript. Es enthält die Vorgaben pro Gruppe. Die konkreten Tasks schreibt der Merge-Helper je Gruppe beim Ausführen — er kennt dann den tatsächlichen Codestand. Was hier steht, ist bindend; was hier nicht steht, entscheidet er. Checkboxen stehen auf Paketebene, damit der Fortschritt sichtbar bleibt.
Design: docs/superpowers/specs/2026-08-11-operation-feedback-design.md — dort stehen die
Belege (Datei:Zeile) und die Begründungen. Dieses Dokument wiederholt sie nicht.
Ziel: Jede Operation, die länger als ~300 ms dauern kann, zeigt an, dass sie läuft, was sie tut und wie lange sie schon läuft — über einen Mechanismus statt pro Fall neu gebaut.
Ausführungsmodell
P0 (Fundament) ── muss ALLEIN und ZUERST landen
│
├── Gruppe A UI-Stille Merge-Helper 1
├── Gruppe B UI-Freeze Merge-Helper 2
└── Gruppe C Worker-Stille Merge-Helper 3
Gruppe D MCP-Stille Merge-Helper 4 ── unabhängig von P0, kann sofort starten
Ein Merge-Helper pro Gruppe. Nach P0 laufen A, B, C und D parallel. Jede Gruppe hält sich
strikt an ihr Datei-Eigentum — das ist die einzige Absicherung gegen gegenseitiges
Überschreiben, weil alle im gemeinsamen main-Checkout arbeiten.
Datei-Eigentum (bindend)
| Gruppe | Besitzt exklusiv | Darf nicht anfassen |
|---|---|---|
| P0 | Ui/Services/OperationStatus.cs (neu), Ui/Views/Controls/OperationIndicator.axaml(.cs) (neu), beide locales/*.json, Ui/Services/WorkerClient.cs (nur Timing-Hook) |
alles andere |
| A | Island-VMs, Modal-VMs, deren AXAML, Ui/Services/UpdateCheckService.cs |
locales/*, WorkerClient, IWorkerClient, Worker-Projekt |
| B | Ui/ViewModels/Modals/DiffViewerViewModel.cs, Ui/Views/Controls/DiffTextView.axaml.cs |
locales/*, Island-VMs, Worker-Projekt |
| C | Worker/Hub/HubBroadcaster.cs, Worker/Hub/WorkerHub.cs, Ui/Services/WorkerClient.cs, IWorkerClient.cs, StubWorkerClient.cs, Worker/Lifecycle/*Recovery.cs, Worker/Runner/WorktreeManager.cs, Worker/Worktrees/WorktreeMaintenanceService.cs |
locales/*, Island-VMs, Worker/External/* |
| D | Worker/External/*McpTools.cs, Worker/External/ExternalMcpService.cs, Worker/Lifecycle/TaskMergeService.cs (nur die Progress-Schleife) |
locales/*, alles im Ui-Projekt |
Locale-Regel: Nur P0 schreibt in en.json/de.json. Braucht eine Gruppe doch einen Key,
den P0 nicht vorgesehen hat: als letzte Änderung des Pakets anhängen und im Merge-Helper
als bekannte Konfliktstelle behandeln. Nie mitten in der Gruppe.
Vorgaben für den Merge-Helper selbst
Gilt für alle vier Gruppen:
- Agent-Modell:
sonnetfür Implementierer und Reviewer. Nie haiku, nie opus, nie Fable. maxTurnsexplizit auf 200 setzen.model_presetsist NULL, sonst bekommt ein sonnet-Task 30 Turns und stirbt mit „exited with code 1 and no result".serializeOnFileOverlapauf der Gruppenliste einschalten. Innerhalb einer Gruppe fassen mehrere Pakete dieselben Dateien an.- Bauen:
dotnet build ClaudeDo.slnxschlägt auf .NET 8 fehl. Einzelprojekte mit-c Releasebauen (ein laufender Worker sperrtDebug):dotnet build src/ClaudeDo.App/ClaudeDo.App.csproj -c Release dotnet build src/ClaudeDo.Worker/ClaudeDo.Worker.csproj -c Release - Testen — pro Gruppe die relevanten Projekte:
Fällt ein Test innerhalb der Verify-Kette, erst die Suite allein laufen lassen — die
A, B dotnet test tests/ClaudeDo.Ui.Tests/ClaudeDo.Ui.Tests.csproj -c Release dotnet test tests/ClaudeDo.Localization.Tests/... -c Release (nur wenn Keys berührt) C Ui.Tests + ClaudeDo.Worker.Tests (Worker.Tests enthält auch UiVm-Tests) D dotnet test tests/ClaudeDo.Worker.Tests/ClaudeDo.Worker.Tests.csproj -c Release P0 Ui.Tests + Localization.TestsUi.Testshaben eine bekannte reihenfolgen-abhängige Flakiness, die nichts mit dem Merge zu tun hat. - Nie
git add -A. Immer explizit nach Pfad stagen undgit commit -- <pfade>— dermain-Checkout ist von parallelen Sessions geteilt, ein blankes Commit fegt fremde WIP mit. - Nach dem Batch-Merge
mainselbst prüfen. Approve baut und testet nicht. Neun grüne Branches habenmainschon zweimal zerlegt, davon einmal durch eine Test-Kollision, die ein reiner src-Build nicht sieht. Also: Build und die betroffenen Testprojekte. - Vor Approve prüfen, ob der Branch überhaupt etwas enthält (
changedFileCount). Ein blockierter Task wird sonstDonemit leerem Branch. - Keine EF-Migration in diesem Vorhaben. Parallele Migrationen aus Geschwister-Branches
löschen sich beim SQLite-Table-Rebuild gegenseitig die Spalten, und die Tests bemerken es
nicht (
EnsureCreated). - Keine Tests, die die echte
claude-CLI starten. - Visuelle Prüfung ist nicht durch Tests ersetzbar. Jedes Paket in A und B endet mit einer offenen visuellen Prüfung für den Nutzer. Nie behaupten, die UI funktioniere.
P0 — Fundament
- P0-1 —
OperationStatus+OperationIndicator+ Locale-Keys - P0-2 — Timing-Hook für die Messung
- P0-3 — Regel in den CLAUDE.md-Dateien
Stand 2026-08-17. P0, A (außer A5), B, C1 und D sind gemergt; der visuelle Pass über A und B ist durch, ohne Fund. Nachtrag zu P0-2: der Timing-Sink liegt seit dem Release-Vorlauf hinter
CLAUDEDO_OP_TIMING=1und ist standardmäßig aus — die 63InvokeTimedAsync-Call-Sites bleiben bewusst stehen. Offen: C2–C5.
Vorbedingung: keine. Muss allein landen, bevor A/B/C starten.
Der Vertrag (bindend — 19 Pakete hängen daran)
src/ClaudeDo.Ui/Services/OperationStatus.cs, eine ObservableObject-Klasse:
| Member | Verhalten |
|---|---|
bool IsRunning |
sofort true bei Begin. Treibt CanExecute, verhindert Doppelklick |
bool ShowIndicator |
erst nach 300 ms true. Kein Flackern bei schnellen Calls |
string? Label |
lokalisierter Text |
string Elapsed |
mm:ss, lokal getickt |
bool IsStalled |
true nach 60 s ohne Report |
IDisposable Begin(string label) |
startet; Dispose beendet auch im Exception-Fall |
void Report(string label) |
überschreibt Label mid-flight, setzt die Stall-Uhr zurück |
Nachbesserung 1 (bindend): IsStalled bemisst sich an der Zeit seit dem letzten
Report, nicht an der Gesamtdauer. Ein regulär mehrminütiges Verify-Gate darf sich nicht
selbst als hängend melden. Eine Operation ohne jeden Report gilt nach 60 s als stalled — das
ist genau der Fall, der heute wie ein Absturz aussieht.
Benutzung im ViewModel:
using var op = Approve.Begin(Loc.T("ops.merge.merging"));
var result = await _worker.ApproveReviewAsync(...);
Weitere Vorgaben
- Zeitquelle injizierbar über
TimeProvider(in .NET 8 vorhanden). Kein statischerDispatcherTimer— geteilter statischer State ist die Ursache der reihenfolgen-abhängigen Flakiness in denUi.Tests. Timer-Callbacks kommen vom Threadpool und müssen auf den Dispatcher gepostet werden. - Mehrere
OperationStatuspro VM sind erwünscht.WorktreesOverviewModalViewModelbraucht getrennte für Refresh, Cleanup und Merge — sonst blockiert ein laufender Refresh die Cleanup-Anzeige. OperationStatustransportiert keine Fehler. Fehlerbehandlung bleibt unverändert überShowErrorAsync/ErrorReported/FlashFooterError.OperationIndicatornutztEllipse.spinnerausDesign/IslandStyles.axaml(14×14, Accent, 0.9 s Rotation) plus Label und Elapsed. Ohne dieses Control wird die Spinner-StackPanel ausMergeModalView.axamlacht Mal von Hand nachgebaut. Werte ausTokens.axamlverwenden, keine Inline-Zahlen.- Locale-Keys: neuer Top-Level-Namespace
opsinen.jsonundde.json, Parität wird vonLocalization.Testserzwungen. P0 legt die Keys für A und C vorab an — abgeleitet aus den Paketlisten unten.
Nachbesserung 3 (bindend): Gruppe D braucht keine Locale-Keys. MCP-Progress-Meldungen gehen an Agenten, nicht an den Nutzer, und bleiben englische Klartext-Strings.
P0-2: Messung an genau einer Stelle
Zwei Hooks, nicht zwanzig:
- In
WorkerClientjeden Hub-Invoke mit Dauer loggen. - Im DB-Pfad der Islands dasselbe.
Ein Tag Nutzung liefert eine sortierte Liste echter Ausreißer. A5 und C werten sie aus, statt zu raten. Bild 2 und 4 brauchen keine Messung.
Faustregel für den Zweifelsfall: instrumentiert wird, was git aufruft, Netz nutzt, einen Prozess startet, oder O(n) über unbegrenzt viele DB-Zeilen läuft. Einzelzeilen-Reads nicht.
Definition of Done für P0
OperationStatus hat Unit-Tests mit einem Fake-TimeProvider für: 300-ms-Grace, 60-s-Stall
ab letztem Report, Elapsed-Formatierung, Dispose nach Exception, Report überschreibt
Label und setzt die Stall-Uhr zurück. Localization.Tests grün. Kein VM ist umgestellt — P0
liefert nur das Werkzeug.
Task-Entwürfe (grob)
P0-1 · OperationStatus + OperationIndicator + ops-Locale-Keys
Baue das Primitive nach dem Vertrag oben, dazu das Anzeige-Control und den neuen
Locale-Namespace ops in beiden Sprachdateien. Keys für Gruppe A und C vorab anlegen, für D
keine. Zeitquelle über TimeProvider, kein statischer Timer.
Dateien: Ui/Services/OperationStatus.cs (neu), Ui/Views/Controls/OperationIndicator.axaml(.cs) (neu), Localization/locales/{en,de}.json, tests/ClaudeDo.Ui.Tests/
Fertig wenn: Unit-Tests für Grace, Stall-ab-Report, Elapsed, Dispose-nach-Exception, Report-Reset. Localization.Tests grün. Kein ViewModel angefasst.
P0-2 · Timing-Hook für die Messung
Zwei Hooks: Dauer jedes Hub-Invokes in WorkerClient, Dauer des DB-Pfads der Islands. Ziel
sind auswertbare Zahlen, keine Anzeige. Ausgabe so, dass sie nach einem Tag Nutzung sortierbar
ist.
Dateien: Ui/Services/WorkerClient.cs, der gemeinsame DB-Zugriffspfad der Island-VMs
Fertig wenn: Beide Hooks aktiv, Overhead vernachlässigbar, das Format ist dokumentiert.
P0-3 · Feedback-Regel in den CLAUDE.md-Dateien
src/ClaudeDo.Ui/CLAUDE.md: jeder IWorkerClient-Call in einem [RelayCommand] läuft durch
eine OperationStatus, Anzeige über OperationIndicator. src/ClaudeDo.Worker/CLAUDE.md: ein
MCP-Tool, das über ~5 s laufen kann, reportet Progress.
Fertig wenn: Beide Regeln stehen, jeweils mit einem Satz Begründung.
Gruppe A — Bild 1: UI-Stille
- A1 — Detail-Pane ⚠️ der gemeldete Fall
- A2 — WorktreesOverview
- A3 — Settings-Tabs — ohne OnlineInbox-SignIn, siehe Nachzügler unten
- A4 — Reports und Planning-UI — ohne die beiden Planning-Calls im
DiffViewerViewModel A5 — Island-DB-Pfade nach Messdaten— abgesagt (2026-08-13): kein DB-Pfad über 500 ms (höchster p95 372 ms), die Ausreißer saßen alle auf der Hub-Seite. Wie vorgesehen geschlossen, ohne Code.
Nachzügler (kein Task): drei Locale-Keys aus P0 sind ungenutzt geblieben —
ops.onlineInbox.signingIn (A3), ops.planning.buildingIntegrationBranch und
ops.planning.loadingAggregate (A4). Die beiden Planning-Calls liegen in
DiffViewerViewModel.cs, einer Datei aus Gruppe B, die A4 nicht anfassen durfte.
Vorbedingung: P0 gemergt.
Vorgaben
-
A1 zuerst.
DetailsIslandViewModel.ApproveReviewAsyncist der gemeldete Schmerz. Dazu im selben Paket:SubmitForReviewAsync,RejectReviewAsync,ParkReviewAsyncundMergeSectionViewModel.PreviewMergeAsync. -
A1 abonniert
IWorkerClient.MergeProgressEvent, um das Label mid-flight von „merging" auf „verifying" zu schärfen. Das Event existiert seitcad0582.Nachbesserung 2 (bindend): A verlässt sich darauf, dass dieses Event bestehen bleibt. C1 baut den generischen Kanal darunter, muss
MergeProgressEventaber als dünnen Forwarder erhalten. Andernfalls müsste CDetailsIslandViewModeländern — eine Datei aus Gruppe A — und die Parallelität wäre zerstört. A darf keinen anderen Kanal verwenden. -
Abo nur für die Dauer des Calls. Der Worker broadcastet an alle Clients; ein dauerhaft registriertes VM bekommt Events für fremde Tasks.
MergeModalViewModelmacht es richtig vor:+=imtry,-=imfinally, plusif (taskId != TaskId) return;. -
A2:
IsBusyexistiert dort schon, schaltet aber nurIsEnabled. Die Anzeige fehlt komplett. Betrifft Refresh, Cleanup, Reset, ForceRemove und Batch-Merge — Batch-Merge zusätzlich mit Zeilen-Status, weil dort N Tasks sequenziell durchlaufen. -
A3: SessionSkill-Install ist ein
git clone— der offensichtlichste Kandidat. Dazu Update/Restore-Defaults, OnlineInbox-SignIn, RepoImport-Scan, Update-Check. -
A4: GenerateWeekReport, RunDailyPrepNow, BuildPlanningIntegrationBranch, GetPlanningAggregate, Finalize/QueuePlanningSubtasks.
DiffViewerViewModel.IsLoadingCombinedexistiert bereits und bleibt — nicht doppeln. -
A5 erst nach Auswertung von P0-2. Nur Stellen umstellen, die die Messung als Ausreißer zeigt. Kein Umstellen auf Verdacht.
-
DetailsIslandViewModelist groß. Nicht umstrukturieren, nur die Commands anfassen. -
Bereits saubere Flächen nicht anfassen:
MergeModalViewModel,ConflictResolverViewModel,DiffViewerViewModel.IsLoadingCombined,UsageMonitorModalViewModel.
Definition of Done pro Paket
Jeder umgestellte Command: IsRunning während des Laufs gesetzt, CanExecute gesperrt,
Zustand nach einer Exception zurückgesetzt — als Test in ClaudeDo.Ui.Tests. Kein
handgebauter Spinner, immer OperationIndicator. Visuelle Prüfung offen und explizit
benannt (Grace-Periode und Layout kann kein Test bestätigen).
Task-Entwürfe (grob)
A1 · Detail-Pane: Approve, Submit, Reject, Park, Preview ⚠️ der gemeldete Fall
Fünf Commands im Detail-Pane bekommen je eine OperationStatus und einen OperationIndicator
neben dem auslösenden Button. Approve abonniert zusätzlich MergeProgressEvent nur für die
Dauer des Calls und filtert auf die eigene TaskId, um das Label von „merging" auf „verifying"
zu schärfen. DetailsIslandViewModel nicht umstrukturieren.
Dateien: Ui/ViewModels/Islands/DetailsIslandViewModel.cs, MergeSectionViewModel.cs, Ui/Views/Islands/Detail/*
Fertig wenn: Approve zeigt während des Verify-Gates Phase und Elapsed, Button ist gesperrt, Zustand nach Fehler zurückgesetzt. Visuelle Prüfung offen.
A2 · WorktreesOverview: Anzeige für alle fünf Aktionen
IsBusy existiert, schaltet aber nur IsEnabled. Getrennte OperationStatus für Refresh,
Cleanup, Reset, ForceRemove und Batch-Merge — der Batch-Merge zusätzlich mit Zeilen-Status, weil
er N Tasks sequenziell durchläuft.
Dateien: Ui/ViewModels/Modals/WorktreesOverviewModalViewModel.cs, Ui/Views/Modals/WorktreesOverviewModalView.axaml
Fertig wenn: Jede der fünf Aktionen zeigt sichtbar, dass sie läuft; ein laufender Refresh blockiert die Cleanup-Anzeige nicht. Visuelle Prüfung offen.
A3 · Settings-Tabs: Skill-Install, Restore-Defaults, OnlineInbox, RepoImport, Update-Check
Fünf Flächen, bei denen IsBusy heute nur den Button sperrt. Der Skill-Install ist ein
git clone und der offensichtlichste Kandidat.
Dateien: Ui/ViewModels/Modals/Settings/*, Ui/ViewModels/Modals/RepoImportModalViewModel.cs, Ui/Services/UpdateCheckService.cs, Ui/Views/Modals/SettingsModalView.axaml
Fertig wenn: Alle fünf zeigen Aktivität; der Skill-Install zeigt zusätzlich, dass geklont wird. Visuelle Prüfung offen.
A4 · Reports und Planning-UI
GenerateWeekReport, RunDailyPrepNow, BuildPlanningIntegrationBranch, GetPlanningAggregate,
Finalize/QueuePlanningSubtasks. DiffViewerViewModel.IsLoadingCombined existiert bereits und
bleibt unangetastet.
Dateien: Ui/ViewModels/Modals/WeeklyReportModalViewModel.cs, Planning-Pfade in DetailsIslandViewModel/TasksIslandViewModel, zugehörige AXAML
Fertig wenn: Report-Generierung und Planning-Integration zeigen Aktivität; kein Doppel-Indikator im Combined-Diff. Visuelle Prüfung offen.
A5 · Island-DB-Pfade nach Messdaten
Erst die Zahlen aus P0-2 auswerten, dann nur die Ausreißer umstellen. Kandidaten:
ClearCompleted, Drag-Reorder über viele Zeilen, Laden großer Listen. Nichts auf Verdacht.
Dateien: nach Messergebnis
Fertig wenn: Die Auswertung ist im Task dokumentiert, und jede umgestellte Stelle ist durch eine Messung begründet. Wenn nichts über der Schwelle liegt: Task mit Begründung schließen, nichts bauen.
Gruppe B — Bild 2: UI-Freeze
- B1 —
UnifiedDiffParser.Parseauslagern - B2 —
DiffAlignment.BuildGrenze - B3 — Guard-Test gegen Dispatcher-Blockade
Vorbedingung: P0 gemergt (für den Indikator in B1).
Vorgaben
- Reihenfolge ist zwingend: erst auslagern, dann anzeigen. Ein Spinner auf einem
blockierten UI-Thread wird nicht gezeichnet. B1 verschiebt
UnifiedDiffParser.ParsenachTask.Runund setzt danach den Indikator. UnifiedDiffParserist statisch und rein — thread-safe,Task.Runist unkritisch. Das Zurückschreiben der Ergebnisse in Observable-Collections muss auf dem UI-Thread passieren.- B2 braucht eine Entscheidung, die der Merge-Helper trifft:
DiffAlignment.Buildläuft inDiffTextView.axaml.cs— in einem Control, nicht in einem VM. Entweder Grenze („ab N Zeilen auslagern") oder inkrementeller Aufbau. Die Wahl gehört ins Paket, nicht hierher; die Vorgabe ist nur: eine sichtbare Grenze definieren, keine unbegrenzte Synchron-Arbeit. - AvaloniaEdit-Fallen (belegt, nicht neu ausprobieren):
this.TryGetResourcein einem Control findet Brushes ausTokens.axamlnie und scheitert lautlos; Brushes und Typeface nicht im Konstruktor auflösen.ScrollToVerticalOffsetist in v12 ein No-op — schreiben überScrollViewer.Offset, lesen überTextView.ScrollOffsetChanged. - Gemeinsames Editor-Boilerplate gehört in
Views/Controls/DiffEditorSetup.cs, nicht ein drittes Mal kopiert.
Definition of Done
B3 ist der einzige Test im Vorhaben, der Blockade prüft: großes Diff-Fixture, Nachweis, dass der Dispatcher weiter Nachrichten verarbeitet. Visuelle Prüfung offen (Verhalten bei großem Diff, Indikator während des Parsens).
Task-Entwürfe (grob)
B1 · UnifiedDiffParser.Parse vom UI-Thread nehmen
Beide Aufrufstellen im DiffViewerViewModel nach Task.Run verschieben, danach den
OperationIndicator setzen. Reihenfolge ist zwingend: erst auslagern, dann anzeigen — ein
Spinner auf einem blockierten Dispatcher wird nicht gezeichnet. Das Zurückschreiben in
Observable-Collections muss auf dem UI-Thread passieren.
Dateien: Ui/ViewModels/Modals/DiffViewerViewModel.cs
Fertig wenn: Kein synchroner Parse mehr im VM, Indikator während des Parsens sichtbar. Visuelle Prüfung mit einem großen Diff offen.
B2 · DiffAlignment.Build — Grenze gegen unbegrenzte Synchron-Arbeit
Build läuft in einem Control, nicht in einem VM. Der ausführende Agent entscheidet zwischen
Auslagern ab einer Zeilenzahl und inkrementellem Aufbau — die Vorgabe ist nur: eine
sichtbare, begründete Grenze. AvaloniaEdit-Fallen aus dem Vorgaben-Abschnitt beachten
(TryGetResource scheitert lautlos, ScrollToVerticalOffset ist ein No-op).
Dateien: Ui/Views/Controls/DiffTextView.axaml.cs, gemeinsames Boilerplate nach DiffEditorSetup.cs
Fertig wenn: Die gewählte Grenze ist im Code kommentiert und begründet; große Diffs blockieren nicht mehr unbegrenzt. Visuelle Prüfung offen.
B3 · Guard-Test: großer Diff blockiert den Dispatcher nicht
Headless-Test mit großem Diff-Fixture, der nachweist, dass der Dispatcher während Parse und
Build weiter Nachrichten verarbeitet. Der einzige Blockade-Test im Vorhaben — soll auch
zukünftige Regressionen fangen.
Dateien: tests/ClaudeDo.Ui.Tests/, Fixture im Testprojekt
Fertig wenn: Der Test fällt gegen den Stand vor B1/B2 und ist danach grün.
Gruppe C — Bild 3: Worker-Stille
- C1 — generischer
OperationProgress-Kanal - C2 — Startup-Recovery sichtbar
- C3 — Worktree-Anlage sichtbar
- C4 — Rebase-after-Merge und WorktreeMaintenance
- C5 — periodische Dienste
Einzige offene Gruppe. C2–C5 sind unblockiert (C1 ist gemergt). Woran man den Reststand erkennt: die vier Keys
ops.worker.startupRecovery,.creatingWorktree,.rebasingAfterMergeund.maintainingWorktreesliegen ungenutzt in beiden Sprachdateien.
Vorbedingung: P0 gemergt. Die Abhängigkeit zur Parallelsession ist mit cad0582
aufgelöst.
Vorgaben
- Der Kanal:
OperationProgress(string opKey, string phase, int current, int total)opKey= TaskId bei task-gebundenen Operationen, sonst ein stabiler String ("worktree-cleanup","startup-recovery","planning-integration:<taskId>"). - Kein Elapsed auf der Leitung. Das UI tickt lokal. Die heutige Implementierung lässt den Worker alle 30 s ticken — damit zeigt sie die ersten 30 Sekunden nur „merging". C1 stellt das um.
MergeProgressEventbleibt als Forwarder (siehe Nachbesserung 2 unter Gruppe A). Vier Zeilen. Entfernen erst, wenn A und C beide gemergt sind — nicht in dieser Gruppe.current/totalwird als Text gezeigt, nie als Prozentbalken. Die meisten Operationen haben kein sinnvolles Total.- C3 zuerst prüfen, nicht bauen:
docs/superpowers/specs/2026-08-07-ui-reaktivitaet-und-listen-performance-design.mdführtWorktreeManager.cs:103als DB-Write-ohne-Broadcast. Ob das inzwischen geschlossen ist, gehört geprüft, bevor es doppelt behoben wird. - C5 ist der wackeligste Punkt im Design. Periodische Dienste (Usage, OnlineSync, Prime, Queue) dürfen nur Aktivität und Fehler melden, keinen Tick-Strom. Wenn der Merge-Helper beim Umsetzen zum Schluss kommt, dass C5 nur Rauschen erzeugt: weglassen und begründen, statt es durchzuziehen.
- Test-Fakes wachsen mit. Ein neues Event auf
IWorkerClient/WorkerHubbricht handgeschriebene Fakes in beiden Testprojekten —tests/ClaudeDo.Ui.Tests/StubWorkerClient.csund die UiVm-Tests untertests/ClaudeDo.Worker.Tests/. - Broadcast-Sparsamkeit: vor einem „fehlenden Broadcast" immer den Aufrufer prüfen. Im 08-07-Spec war ein gemeldetes Loch in Wahrheit schon vom Aufrufer abgedeckt, und der Fix wäre ein Duplikat gewesen.
Definition of Done
Progress-Callbacks in ClaudeDo.Worker.Tests mit einem Fake gezählt — keine echten Timeouts,
keine echte CLI. UI-Seite: die Anzeige beim Worker-Start ersetzt „reconnecting" durch die
laufende Recovery-Phase. Visuelle Prüfung offen.
Task-Entwürfe (grob)
C1 · Generischer OperationProgress-Kanal, MergeProgress darauf umstellen
Neues Hub-Event OperationProgress(opKey, phase, current, total), ohne Elapsed auf der Leitung.
Der Merge-Pfad sendet darüber. MergeProgressEvent bleibt als vierzeiliger Forwarder —
Gruppe A hängt daran und darf nicht angefasst werden. Fakes in beiden Testprojekten mitziehen.
Dateien: Worker/Hub/HubBroadcaster.cs, Worker/Hub/WorkerHub.cs, Ui/Services/WorkerClient.cs, IWorkerClient.cs, tests/ClaudeDo.Ui.Tests/StubWorkerClient.cs, UiVm-Fakes in Worker.Tests
Fertig wenn: Merge-Phasen laufen über den neuen Kanal, das UI tickt Elapsed lokal, MergeProgressEvent funktioniert unverändert weiter, beide Testprojekte grün.
C2 · Worker-Startup-Recovery sichtbar machen
Die sechs Recovery-Services beim Worker-Start melden Phase und i/n über den Kanal
(opKey = "startup-recovery"). Das UI ersetzt „reconnecting" durch die laufende Phase.
Dateien: Worker/Lifecycle/*Recovery.cs, Anzeige im IslandsShellViewModel-Umfeld
Fertig wenn: Beim Worker-Start ist sichtbar, welche Recovery läuft. Visuelle Prüfung offen.
C3 · Worktree-Anlage beim Task-Start sichtbar machen
Zuerst prüfen, ob der im 08-07-Spec gemeldete Broadcast-Gap in WorktreeManager inzwischen
geschlossen ist — nicht doppelt beheben. Danach die stille Lücke zwischen Queued und erster
Ausgabe an der Task-Zeile sichtbar machen.
Dateien: Worker/Runner/WorktreeManager.cs, Task-Row-Anzeige
Fertig wenn: Das Prüfergebnis steht im Task; die Anlage-Phase ist an der Zeile sichtbar. Visuelle Prüfung offen.
C4 · Rebase-after-Merge und WorktreeMaintenance in den Kanal
RebaseOthersAfterMergeAsync läuft heute innerhalb des Merge-Calls nach dem
Phasen-Broadcast und ist damit vollständig unsichtbar. Dazu der Hintergrunddienst über alle
Worktrees, mit i/n.
Dateien: Worker/Lifecycle/TaskMergeService.cs (Rebase-Abschnitt), Worker/Worktrees/WorktreeMaintenanceService.cs
Fertig wenn: Beide melden Fortschritt; ein Merge zeigt nach dem Verify-Gate die Rebase-Phase statt Stille.
C5 · Periodische Dienste — optional, Abbruch erlaubt
Usage, OnlineSync, Prime, Queue sollen nur Aktivität und Fehler melden, keinen Tick-Strom.
Der wackeligste Punkt im Design: kommt der ausführende Agent zum Schluss, dass das nur
Anzeige-Rauschen erzeugt, weglassen und begründen statt durchziehen.
Dateien: Worker/Usage/, Worker/Online/, Worker/Prime/, Worker/Queue/
Fertig wenn: Entweder sparsame Meldungen ohne Rauschen — oder eine begründete Absage im Task.
Gruppe D — Bild 4: MCP-Stille
- D1 —
ProgressReporterextrahieren - D2 — die
batch_*-Tools — es sind sieben, nicht acht (die Achterzahl unten war ein Zählfehler beim Schreiben des Plans) - D3 — Worktree- und Diff-Tools — drei davon;
batch_cleanup_task_worktreeslief über D2 - D4 — Rest und Doku-Regel — fand zwei echte Lücken, die D1–D3 offen gelassen hatten:
continue_mergereichte sein Progress-Token nicht ins Post-Merge-Verify-Gate, und der Unit-Merge-Drain imPlanningMergeOrchestratorverlor es nach dem ersten Tick. Dazulist_worktrees.
Vorbedingung: keine. Kann sofort starten, parallel zu P0.
Vorgaben
- Warum das zählt: ohne Progress bricht der MCP-Client bei Stille nach 300 s ab, während
der Worker weiterarbeitet. Das ist die dokumentierte Ursache dafür, dass ein Merge zwar
durchläuft, den Task aber nie auf
Donebringt und Abhängige dauerhaft blockiert. - D1:
TaskMergeService.RunReportingProgressAsyncist die einzige existierende Progress-Schleife. Als eigenständige Klasse extrahieren, plus ein Overload für Element-Fortschritt (i/n). Nicht kopieren — extrahieren, damit es eine Implementierung bleibt. TaskMergeServiceist die einzige Datei, die D mit C teilt. D fasst dort ausschließlich die Progress-Schleife an. Wenn beide Gruppen gleichzeitig laufen, ist das die Stelle, die der Merge-Helper im Auge behalten muss.- Keine Locale-Keys (Nachbesserung 3). Englische Klartext-Strings.
- Zielumfang: die 7
batch_*-Tools miti/n, danncleanup_task_worktree,batch_cleanup_task_worktrees,get_task_diff,preview_merge_set. Bereits versorgt und nicht anzufassen: die 5 Tools inExternalMcpServicemitIProgress,TaskWaitMcpTools,merge_task/review_task. - D4 schreibt die Regel ins Worker-
CLAUDE.md: ein MCP-Tool, das über ~5 s laufen kann, reportet Progress. Ohne die Regel wiederholt sich das Muster beim nächsten Tool.
Definition of Done
Für jedes umgestellte Tool ein Test in ClaudeDo.Worker.Tests, der mit einem Fake-IProgress
zählt, dass Meldungen kommen — bei batch_* mindestens eine pro Element. Keine visuelle
Prüfung nötig, diese Gruppe hat keine UI.
Task-Entwürfe (grob)
D1 · ProgressReporter extrahieren
TaskMergeService.RunReportingProgressAsync als eigenständige Klasse herauslösen, plus einen
Overload für Element-Fortschritt (i/n). Extrahieren, nicht kopieren — es soll eine
Implementierung bleiben. Dies ist die einzige Datei, die D mit C teilt; nur die Progress-Schleife
anfassen.
Dateien: Worker/Lifecycle/TaskMergeService.cs, neue Klasse im Worker-Projekt
Fertig wenn: Der Merge-Pfad nutzt die extrahierte Klasse, Verhalten unverändert, bestehende Merge-Tests grün.
D2 · Die sieben batch_*-Tools mit Element-Fortschritt
Jedes batch_*-Tool reportet pro verarbeitetem Element. Grund: ohne Meldung bricht der
MCP-Client nach 300 s Stille ab, während der Worker weiterläuft — genau der Mechanismus, der
einen Merge durchlaufen lässt, den Task aber nie auf Done bringt.
Dateien: Worker/External/BatchMcpTools.cs
Fertig wenn: Pro Tool ein Test mit Fake-IProgress, der mindestens eine Meldung je Element zählt. Englische Klartext-Strings, keine Locale-Keys.
D3 · Worktree- und Diff-Tools mit Progress
cleanup_task_worktree, batch_cleanup_task_worktrees, get_task_diff, preview_merge_set.
Bereits versorgt und nicht anzufassen: die fünf Tools mit IProgress in
ExternalMcpService, TaskWaitMcpTools, merge_task, review_task.
Dateien: die betroffenen Worker/External/*McpTools.cs, ExternalMcpService.cs
Fertig wenn: Jedes der vier Tools meldet Fortschritt, mit Test.
D4 · Restliche Long-Runner und die Regel im Worker-CLAUDE.md
Verbleibende Tools durchgehen, die über ~5 s laufen können, und die Regel festschreiben: ein
MCP-Tool über ~5 s reportet Progress. Ohne die Regel wiederholt sich das Muster beim nächsten
Tool.
Dateien: restliche Worker/External/*McpTools.cs, src/ClaudeDo.Worker/CLAUDE.md
Fertig wenn: Die Regel steht mit Begründung; die durchgegangenen Tools sind im Task aufgelistet — auch die, die bewusst nichts bekommen.
Was nach allen vier Gruppen offen bleibt
Visuelle Prüfung für alle Pakete in A und B— am 2026-08-17 durch, ohne Fund (Worktrees-Übersicht, Settings/Skill-Install, WeeklyReport, großer Diff, Detail-Pane-Approve).Auswertung von P0-2— am 2026-08-13 ausgewertet, siehe A5.MergeProgressEvent-Forwarder entfernen, sobald A und C beide gemergt sind. Ein Aufräum-Task, kein Paket.- Bewusst nicht gebaut: Cancel, Footer-Anzeige für laufende Operationen, Prozentbalken, Änderungen am Installer (der hat bereits eine vollständige Progress-Pipeline).