Files
ClaudeDo/docs/superpowers/plans/2026-08-11-operation-feedback.md
T
mika kuns f9a8ed761a
Changelog / changelog (push) Successful in 2s
Release / release (push) Successful in 43s
docs: record the operation-feedback state before the v2.10.0 cut
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.
2026-08-17 11:45:03 +02:00

30 KiB
Raw Blame History

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: sonnet für Implementierer und Reviewer. Nie haiku, nie opus, nie Fable.
  • maxTurns explizit auf 200 setzen. model_presets ist NULL, sonst bekommt ein sonnet-Task 30 Turns und stirbt mit „exited with code 1 and no result".
  • serializeOnFileOverlap auf der Gruppenliste einschalten. Innerhalb einer Gruppe fassen mehrere Pakete dieselben Dateien an.
  • Bauen: dotnet build ClaudeDo.slnx schlägt auf .NET 8 fehl. Einzelprojekte mit -c Release bauen (ein laufender Worker sperrt Debug):
    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:
    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.Tests
    
    Fällt ein Test innerhalb der Verify-Kette, erst die Suite allein laufen lassen — die Ui.Tests haben eine bekannte reihenfolgen-abhängige Flakiness, die nichts mit dem Merge zu tun hat.
  • Nie git add -A. Immer explizit nach Pfad stagen und git commit -- <pfade> — der main-Checkout ist von parallelen Sessions geteilt, ein blankes Commit fegt fremde WIP mit.
  • Nach dem Batch-Merge main selbst prüfen. Approve baut und testet nicht. Neun grüne Branches haben main schon 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 sonst Done mit 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=1 und ist standardmäßig aus — die 63 InvokeTimedAsync-Call-Sites bleiben bewusst stehen. Offen: C2C5.

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 statischer DispatcherTimer — geteilter statischer State ist die Ursache der reihenfolgen-abhängigen Flakiness in den Ui.Tests. Timer-Callbacks kommen vom Threadpool und müssen auf den Dispatcher gepostet werden.
  • Mehrere OperationStatus pro VM sind erwünscht. WorktreesOverviewModalViewModel braucht getrennte für Refresh, Cleanup und Merge — sonst blockiert ein laufender Refresh die Cleanup-Anzeige.
  • OperationStatus transportiert keine Fehler. Fehlerbehandlung bleibt unverändert über ShowErrorAsync / ErrorReported / FlashFooterError.
  • OperationIndicator nutzt Ellipse.spinner aus Design/IslandStyles.axaml (14×14, Accent, 0.9 s Rotation) plus Label und Elapsed. Ohne dieses Control wird die Spinner-StackPanel aus MergeModalView.axaml acht Mal von Hand nachgebaut. Werte aus Tokens.axaml verwenden, keine Inline-Zahlen.
  • Locale-Keys: neuer Top-Level-Namespace ops in en.json und de.json, Parität wird von Localization.Tests erzwungen. 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:

  1. In WorkerClient jeden Hub-Invoke mit Dauer loggen.
  2. 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 Messdatenabgesagt (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.ApproveReviewAsync ist der gemeldete Schmerz. Dazu im selben Paket: SubmitForReviewAsync, RejectReviewAsync, ParkReviewAsync und MergeSectionViewModel.PreviewMergeAsync.

  • A1 abonniert IWorkerClient.MergeProgressEvent, um das Label mid-flight von „merging" auf „verifying" zu schärfen. Das Event existiert seit cad0582.

    Nachbesserung 2 (bindend): A verlässt sich darauf, dass dieses Event bestehen bleibt. C1 baut den generischen Kanal darunter, muss MergeProgressEvent aber als dünnen Forwarder erhalten. Andernfalls müsste C DetailsIslandViewModel ä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. MergeModalViewModel macht es richtig vor: += im try, -= im finally, plus if (taskId != TaskId) return;.

  • A2: IsBusy existiert dort schon, schaltet aber nur IsEnabled. 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.IsLoadingCombined existiert 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.

  • DetailsIslandViewModel ist 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.Parse auslagern
  • B2 — DiffAlignment.Build Grenze
  • 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.Parse nach Task.Run und setzt danach den Indikator.
  • UnifiedDiffParser ist statisch und rein — thread-safe, Task.Run ist 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.Build läuft in DiffTextView.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.TryGetResource in einem Control findet Brushes aus Tokens.axaml nie und scheitert lautlos; Brushes und Typeface nicht im Konstruktor auflösen. ScrollToVerticalOffset ist in v12 ein No-op — schreiben über ScrollViewer.Offset, lesen über TextView.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. C2C5 sind unblockiert (C1 ist gemergt). Woran man den Reststand erkennt: die vier Keys ops.worker.startupRecovery, .creatingWorktree, .rebasingAfterMerge und .maintainingWorktrees liegen 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.
  • MergeProgressEvent bleibt als Forwarder (siehe Nachbesserung 2 unter Gruppe A). Vier Zeilen. Entfernen erst, wenn A und C beide gemergt sind — nicht in dieser Gruppe.
  • current/total wird 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.md führt WorktreeManager.cs:103 als 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/WorkerHub bricht handgeschriebene Fakes in beiden Testprojekten — tests/ClaudeDo.Ui.Tests/StubWorkerClient.cs und die UiVm-Tests unter tests/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 — ProgressReporter extrahieren
  • 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_worktrees lief über D2
  • D4 — Rest und Doku-Regel — fand zwei echte Lücken, die D1D3 offen gelassen hatten: continue_merge reichte sein Progress-Token nicht ins Post-Merge-Verify-Gate, und der Unit-Merge-Drain im PlanningMergeOrchestrator verlor es nach dem ersten Tick. Dazu list_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 Done bringt und Abhängige dauerhaft blockiert.
  • D1: TaskMergeService.RunReportingProgressAsync ist 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.
  • TaskMergeService ist 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 mit i/n, dann cleanup_task_worktree, batch_cleanup_task_worktrees, get_task_diff, preview_merge_set. Bereits versorgt und nicht anzufassen: die 5 Tools in ExternalMcpService mit IProgress, 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 Bam 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).