2156 Commits
Author SHA1 Message Date
mika kuns 25c9a619dc feat(ui): collapsible folders for the list sidebar
Folders render above the top-level lists, each with its own collapsible
children; tapping a folder header folds it instead of selecting it.
Lists move in by dragging onto a folder header (or onto a row inside it)
and out by dropping between top-level rows or via the context menu.

Creating a folder is a toggle in the New-list modal, not a third sidebar
button: it reduces the modal to name + icon and writes a folder row
instead of the list row the create flow pre-created.
2026-09-10 08:29:56 +02:00
mika kuns 13e860f06b feat(data): list_folders table plus lists.folder_id
Sidebar folders get their own table rather than a flag on lists, so the
places that enumerate lists (MCP tools, move-to-list, queue picker, repo
import) need no folder filtering. ON DELETE SET NULL keeps a folder's
lists alive when the folder goes.
2026-09-10 08:29:56 +02:00
ClaudeDo CI ec1e60be1d docs(changelog): update for v2.13.6 2026-09-07 06:18:03 +00:00
mika kuns f231f08a27 feat(ui): Home-Ordner als Sitzungsziel in Mission Control
Changelog / changelog (push) Successful in 2s
Release / release (push) Successful in 41s
Erster Eintrag im Sitzungsmenue, fuer schnelle allgemeine Fragen, die zu
keinem Projekt gehoeren.
v2.13.6
2026-09-07 08:17:37 +02:00
mika kuns 23491d3b49 feat(ui): Einfuegen und Datei-Drop im interaktiven Terminal
Ctrl+V wurde von TerminalControl als rohes Control-Byte an das Kind
weitergegeben und tat nichts; jetzt wird es im Tunnel abgefangen und geht
ueber TerminalView.PasteAsync, damit Bracketed Paste greift und ein
mehrzeiliger Paste nicht auf der ersten Zeile abschickt. Gedroppte Dateien
werden als Pfade in den Composer getippt, ohne Enter.
2026-09-07 08:17:37 +02:00
mika kuns 0db9fadee9 feat(ui): Cheat-Sheet-Fenster im Hilfe-Menue
Sechs Markdown-Sheets (git, Conventional Commits, Claude CLI, Claude-Config,
dotnet CLI, PowerShell) als EmbeddedResource, gerendert im modelosen, per
Topmost anpinnbaren CheatSheetsWindow. MarkdownView bekommt dafuer das Opt-in
CommandRows: `befehl` - beschreibung wird zu Mono-Chip + Copy-Button, jede
##-Sektion landet in einem Expander. Enthaelt ausserdem: Mission Control
wird beim Oeffnen aus dem Minimiert-Zustand geholt, nicht nur aktiviert.
2026-09-07 08:17:37 +02:00
mika kuns 7c7c33d677 feat(ui): PowerUse-Einstellungen nach Settings -> Ausfuehrung verschieben
Schalter, Zeitfenster und Handoff-Prozent lagen im Usage-Monitor und mussten
in SettingsModalViewModel nur load->save durchgeschleift werden, damit ein
Settings-Speichern sie nicht zurueckwirft. Jetzt gehoeren sie dem General-Tab,
der Monitor ist wieder nur Anzeige + Threshold-Drag, und "Jetzt aktualisieren"
sitzt als Icon in der Titelleiste (neuer ModalShell.HeaderActions-Slot).
2026-09-07 08:17:37 +02:00
ClaudeDo CI c7392e085f docs(changelog): update for v2.13.5 2026-09-03 08:20:49 +00:00
mika kuns c16c7b97ef refactor(ui): "Nach Updates suchen" ins Hilfe-Menue verschieben
Changelog / changelog (push) Successful in 2s
Release / release (push) Successful in 41s
v2.13.5
2026-09-03 10:20:35 +02:00
mika kuns cccfe2eca1 fix(ui): Version im About-Dialog aus der FileVersion lesen
MinVer setzt die AssemblyVersion auf {Major}.0.0.0 (Binding-Kompatibilitaet),
darum zeigte der Dialog immer "2.0.0". Die echte Major.Minor.Patch steckt in
der FileVersion.
2026-09-03 10:20:35 +02:00
ClaudeDo CI a8ec550740 docs(changelog): update for v2.13.4 2026-09-03 08:18:22 +00:00
mika kuns 40d2537486 Merge remote-tracking branch 'origin/main'
Changelog / changelog (push) Successful in 2s
Release / release (push) Successful in 42s
v2.13.4
2026-09-03 10:17:58 +02:00
mika kuns f70503d038 fix(worker): interaktive Session ohne Arbeitsverzeichnis im User-Verzeichnis starten
Eine manuelle Liste (Erinnerungen) hat kein WorkingDir. BuildForTaskAsync
warf dafuer bisher "no working directory configured", die interaktive
Session liess sich also nicht oeffnen. Jetzt faellt der Pfad auf das
User-Verzeichnis zurueck; Session-Skills werden dort bewusst nicht
geseedet, weil das Ziel das echte ~/.claude/skills waere.
2026-09-03 10:17:06 +02:00
ClaudeDo CI 9360cd2fe6 docs(changelog): update for v2.13.3 2026-09-03 05:48:10 +00:00
mika kuns ee502883f8 chore(claudedo): update CHANGELOG for v2.13.3
Changelog / changelog (push) Successful in 2s
Release / release (push) Successful in 40s
v2.13.3
2026-09-03 07:47:43 +02:00
mika kuns e64d570554 fix(worker): raise SignalR MaximumParallelInvocationsPerClient
Default of 1 serializes every hub call on a connection - a slow one
(GetTicketProjects hitting an unreachable ticket system, 10s timeout)
blocked unrelated calls like UpdateList/UpdateListConfig behind it for
the same duration, making list-settings save appear to hang.
2026-09-03 07:47:26 +02:00
ClaudeDo CI fc25ee45d1 docs(changelog): update for v2.13.2 2026-09-03 05:23:15 +00:00
mika kuns 51ee505057 fix(ui): strip CLAUDE_CODE_CHILD_SESSION/CLAUDECODE before every ConPTY launch
Changelog / changelog (push) Successful in 2s
Release / release (push) Successful in 42s
ClaudeDo.App inherits its own process environment from whatever started it
(e.g. a dev/test launch from inside a claude session). Every embedded
claude.exe it spawns into a Mission Control tile then inherited those
markers too, so the child session mistook itself for a subagent: transcript
saving disabled and a degraded startup banner (white instead of orange,
missing box rules). PtyTerminalSession.StartAsync is the one choke point
all ConPTY launches already share for env handling, so clearing both vars
there covers task, ad-hoc, planning, and list-handler sessions regardless
of how ClaudeDo.App itself was started.
v2.13.2
2026-09-03 07:22:59 +02:00
mika kuns 06bc3d2105 feat(claude-do): merge Handler-Run per Knopf abbrechen (Session killen + offene Run
ClaudeDo-Task: 3c387f8e-096f-42c6-a2c3-91c69fe3915c
2026-09-02 22:39:18 +02:00
mika kuns bd5aa265d1 feat(mission-control): Handler-Run per Knopf abbrechen
Ein "Abandon run"-Knopf an Handler-Panes fragt HandlerRoundState.Get(handlerTaskId)
nach den noch offenen (Queued/Running) Tasks des Laufs, bestaetigt mit Anzahl,
cancelt jeden ueber den bestehenden CancelTaskAsync-Pfad und schliesst danach die
Session -- ein Schritt statt Tile schliessen + Queue separat abbrechen. Ohne
offene Tasks (oder ohne Round-Eintrag) schliesst die Aktion direkt, ohne Dialog.
Nur an den beiden Handler-Panes sichtbar (IsListHandler), normale Task-/Ad-hoc-
Panes bleiben unveraendert.
2026-09-02 22:39:12 +02:00
mika kuns b298594a2c chore(claude-do): merge fix(ui): Listen-Settings-Modal verschluckt Ladefehler nach d
ClaudeDo-Task: 9256fcfe-6cad-4350-a979-0c49cd5b9799
2026-09-02 22:38:49 +02:00
mika kuns 62855ac575 Merge branch 'claudedo/c209d54cef5642278673d41e8b98fc43' 2026-09-02 22:38:42 +02:00
mika kuns 18b4dcd56f Merge branch 'claudedo/a9603b34c1e74074b904cd5028de0a1d' 2026-09-02 22:38:12 +02:00
mika kuns b02e0f80f0 chore(claude-do): merge feat(ui): Empty-State fuer den Session-Skills-Tab
ClaudeDo-Task: 5d889e35-660e-4376-a5bd-6df4e2d69e16
2026-09-02 22:36:49 +02:00
mika kuns df3e7ba0c7 fix(ui): Dequeue-X auf blockierten Queue-Zeilen anzeigen und Kette konsistent halten
CanRemoveFromQueue schloss IsWaiting (queued+blocked) faelschlich aus, sodass ein
Kettenglied in der Mitte nicht entfernbar war. Zusaetzlich unblockt
TaskStateService.DequeueToIdleAsync jetzt den Nachfolger eines dequeueten
Kettenglieds, sonst bliebe er dauerhaft auf einen nicht mehr laufenden
Vorgaenger blockiert.
2026-09-02 22:34:50 +02:00
mika kuns a1b20d9f27 fix(ui): report and gate ListSettingsModal load failures instead of swallowing them
BeginLoad's fire-and-forget LoadAsync now catches instead of leaving an
unobserved task exception, reports it via the new ErrorReported event
(wired into FlashFooterError like the other modal VMs), and keeps Save
locked so the failure can't clobber list_config with blank fields.
LoadTicketProjectsAsync's empty catch now reports too; behavior for the
dropdown itself is unchanged.
2026-09-02 22:33:48 +02:00
mika kuns e0c6b670cb fix(ui): move ScrollViewer padding to inner content in modal bodies
Avalonia 12 excludes ScrollViewer.Padding from the scroll Extent, clipping
the last line of these five modal bodies unreachable at max scroll.
2026-09-02 22:30:52 +02:00
mika kuns 2bd48ea1c7 docs(open): remove stale session-skills empty-state entry
Feature was already implemented in fe8186514 (locale key, IsEmpty
property, TextBlock in SettingsModalView.axaml).
2026-09-02 22:30:37 +02:00
mika kuns 77c70d74cb perf(claude-do): merge perf: Listen-Settings-Modal öffnet erst nach 7 seriellen Rou
ClaudeDo-Task: 1a07fa19b27347c1b65591ca6c0c0980
2026-09-02 22:19:55 +02:00
mika kuns f24654dfb8 perf(ui): show list settings modal before its seven-round-trip load finishes
OpenListSettingsAsync/CreateListAsync used to await LoadAsync (name/agent
config/list_config x2/ticket settings/ticket projects, all serial) before
showing the window -- an unreachable ticket system alone could add a 10s
HTTP timeout to every open. LoadAsync now runs via BeginLoad (fire-and-forget,
mirrors UsageMonitorModalViewModel), the modal shows immediately and fields
fill in behind it.

GetListConfigAsync no longer runs twice per open -- AgentConfigEditorViewModel
exposes the row it already fetched (LastLoadedListConfig) instead of the
caller re-fetching it. Ticket-project loading is split into its own
fire-and-forget step so a slow/unreachable ticket system can't block the
rest of the fields, and its tri-state Save logic now also treats "never
finished loading" like "not available" -- leaving the stored
TicketProjectId link untouched instead of overwriting it with 0. Save/Delete
are gated (CanExecute) on the core load being done, so a save can't land
before the fields it writes are populated.

Not measured with OperationTiming against a live worker in this session (no
running app instance available) -- verified instead via 4 new unit tests
that assert GetListConfigAsync fires exactly once and that a hung/failing
ticket-projects call neither blocks LoadAsync's other fields nor corrupts
the saved TicketProjectId. Before/after OperationTiming numbers and a visual
pass are still open follow-ups.
2026-09-02 22:18:54 +02:00
mika kuns b05b6fbaec fix(ui): Mission Control oeffnen, wenn ein Handler-Run per MCP startet oder ein Handoff eintrifft 2026-09-02 22:05:34 +02:00
ClaudeDo CI eb3aee41a4 docs(changelog): update for v2.13.1 2026-09-02 20:04:37 +00:00
ClaudeDo CI 2b8733227d docs(changelog): update for v2.13.0 2026-09-02 19:58:58 +00:00
mika kuns d258ab4164 test(worker): start_list_handler ins erwartete MCP-Tool-Inventar aufnehmen
Changelog / changelog (push) Successful in 2s
Release / release (push) Successful in 42s
v2.13.0
2026-09-02 21:57:16 +02:00
mika kuns 574edf6c1a Merge branch 'claudedo/f2f0c6ee1e974c09bc8a8261978cba34'
feat(worker): Handler-Session vor dem Usage-Limit sauber uebergeben (#275); Konflikte mit start_list_handler aufgeloest, WorkerLog-Aufruf im Fire-and-forget-Pfad wieder abgesichert
2026-09-02 21:50:26 +02:00
mika kuns fe8186514f feat(worker): Handler-Session vor dem Usage-Limit warnen und Handoff bis zum Reset zurueckhalten
Eine PowerUse-Handler-Session soll am 5h-Limit nicht mehr mitten im Merge
sterben, sondern vorher selbst sauber uebergeben:

- HandlerUsageGuard (neu) warnt die laufende Session genau einmal pro Runde,
  sobald FiveHour.Utilization den Schwellwert PowerUseHandoffPct erreicht.
  Die Warnung wird per HandlerUsageWarning-Broadcast an Mission Control
  geschickt und dort in das Pane der Handler-TaskId getippt.
- handoff_list_handler broadcastet den Handoff dann nicht sofort, sondern parkt
  ihn bis ResetsAt + 60 s; das Ergebnis traegt deferredUntil. Ohne ResetsAt
  wird wie bisher sofort gesendet.
- Der geparkte Handoff liegt im HandlerRoundState (handler-rounds.json) und
  wird vom Guard-Tick ausgeloest, also auch nach einem Worker-Neustart wieder
  eingeplant bzw. sofort gesendet, wenn er ueberfaellig ist.
- Review-Befund aus #272: HandlerRestartCoordinator wartet nicht mehr selbst
  bis ResetsAt, sondern parkt den Neustart im selben Slot. AutoRestartUsed wird
  erst gesetzt, wenn der Broadcast wirklich rausging - ein Worker-Absturz
  waehrend der Wartezeit laesst die Runde nicht mehr dauerhaft tot zurueck.
  Zurueckgehaltener Handoff und Auto-Neustart teilen sich einen Slot, also
  oeffnet nie beides dieselbe Runde. UsageLimitProofPct entfaellt zugunsten von
  PowerUseHandoffPct.
- PtyTerminalSession.SendLineAsync schreibt in die laufende Session. Gegen eine
  echte claude-Session verifiziert: Text und Enter muessen zwei getrennte
  Writes sein, die Enter-Bytes kommen von Terminal.GenerateKeyInput.
2026-09-02 21:35:29 +02:00
mika kuns c2166a0d4f feat(worker): start_list_handler MCP-Tool startet einen List-Handler-Run wie der Button 2026-09-02 21:05:55 +02:00
mika kuns c3a418f077 Merge branch 'claudedo/b346a534f0fc4635bd7614a00ab2a20e' 2026-09-02 20:55:43 +02:00
mika kuns 2ec3af96d5 chore(claude-do): merge PowerUse-Zeitfenster + Handoff-Schwellwert als Settings (Usa
ClaudeDo-Task: aa446890-82f0-49b9-aef9-13a788d9c514
2026-09-02 19:27:01 +02:00
mika kuns 016b9203f8 feat(worker): Handler-Session nach Usage-Limit-Reset automatisch neu starten
Eine List-Handler-ConPTY-Session, die mitten in einer Phase stirbt, war bisher
ein stilles totes Tile: InteractiveTerminalViewModel.OnSessionProcessExited
setzte nur bei einem Tod innerhalb des 5s-Grace-Fensters ein sichtbares Banner.

Neu:
- HandlerRoundState (JSON unter ~/.claudeDo/handler-rounds.json, keine
  EF-Migration): Phase + Task-Set der laufenden Runde, geschrieben von
  BuildForMergeHelperAsync ("triage") und BuildForMergeHelperHandoffAsync.
  Ohne das existieren beide nur im transienten HandoffRequested-Broadcast.
- HandlerRestartCoordinator: entscheidet den Neustart, fail-closed. Beleg fuer
  "war das Usage-Limit" ist FiveHour.Utilization >= 95 zum Todeszeitpunkt --
  eine ConPTY-Session hat kein stdout, TaskRunner.IsUsageLimitMessage hat hier
  nichts zu lesen. Nur bei PowerUse (beide Keys), max ein Neustart pro Runde,
  Warten bis FiveHour.ResetsAt, dann HandoffRequested erneut broadcasten.
  Verbraucht kein Handoff-Budget (HandoffRoundTracker.Register wird nicht
  angefasst). WorkerLog-Zeilen beim Tod und beim Neustart.
- Ui meldet den Exit-Code (nur dort bekannt) via
  WorkerHub.ReportInteractiveSessionExited, ohne selbst zu filtern.

Sibling zu UsageLimitAutoContinueCoordinator, kein Umbau davon: der sieht nur
headless Runs.
2026-09-02 19:17:51 +02:00
mika kuns 69898be5c9 feat(usage): PowerUse-Zeitfenster + Handoff-Schwellwert als Settings
Drei neue app_settings-Spalten (Migration AddPowerUseWindow):
power_use_window_start/end (HH:mm, lokal, nullable) und
power_use_handoff_pct (NOT NULL DEFAULT 95, geclampt 50-99).

Die Fensterlogik liegt als reine Funktion in PowerUseWindow
(Contains/Normalize/IsOpen): beide Grenzen leer oder nur eine gesetzt =
rund um die Uhr, Ende vor Start wrappt ueber Mitternacht, Grenzen
halboffen. Geprueft wird in ComposeHandlerPromptAsync, also pro Phase
zum Zeitpunkt des Prompt-Baus - die Uhr ist per Func<DateTime>
injizierbar. Bedienung im Usage-Monitor neben dem PowerUse-Toggle
(Commit auf Blur/Enter, ein Write fuer alle vier Felder); in
Settings->General unsichtbar, aber load->save durchgereicht.

Nebenbefund, gleicher Pfad: AppSettingsRepository.UpdateAsync kopiert
Feld fuer Feld und hat ModelPresets, PowerUseEnabled und
ListHandlerMaxHandoffs nie geschrieben - jeder Save dieser drei war
still wirkungslos. Mit ergaenzt und per Round-trip-Test gepinnt.
2026-09-02 19:09:47 +02:00
mika kuns 20b3b4ce2b docs(claude-do): Handler-Prompt praezisieren (Wave-Plan, Task-Split, review_task-Aufruf) 2026-09-02 18:43:15 +02:00
Mika Kuns 42356241e3 feat(claude-do): PowerUse fuer List-Handler-Runs + konfigurierbares Handoff-Budget 2026-09-02 15:56:10 +02:00
Mika Kuns 675b36e923 Merge branch 'main' into feat/poweruse-list-handler
Kollision mit #264 (Handoff-Budget im Brief sichtbar machen): beide Seiten haben
HandoffRoundTracker, HandoffMcpTools und InteractiveLaunchSpecService angefasst.

Der Konflikt war inhaltlich, nicht nur textuell. #264 liest den Cap an zwei
Stellen aus der Konstante (GetStatus und das roundInfo-Rendering), waehrend
dieser Branch ihn zum Parameter aus app_settings gemacht hat. Ein reiner
Text-Merge haette kompiliert und trotzdem gelogen: Register haette den
konfigurierten Cap durchgesetzt, waehrend der Brief dem Modell weiter "2 Runden
uebrig" gemeldet haette, obwohl es 39 hat.

Aufgeloest so, dass der Cap eine einzige Quelle hat:
- GetStatus(taskId, maxHandoffs) nimmt den Cap als Parameter, mit demselben
  Clamp wie Register. Die Rechnerei liegt damit an einer Stelle.
- GetHandoffStatus liest das Setting und gibt es weiter.
- Das roundInfo-Rendering benutzt GetStatus statt eigener Arithmetik.

Zwei Tests nageln genau diesen Drift fest, damit er beim naechsten Merge nicht
unbemerkt zurueckkommt: einer auf GetHandoffStatus, einer auf den Brief.

MaxHandoffs -> DefaultMaxHandoffs in #264s vier Test-Referenzen; die laufen alle
mit Default-Settings, die Semantik bleibt.
2026-09-02 15:48:43 +02:00
Mika Kuns 416997d7e0 docs: Test-Scoping fuer Implementer-Tasks, PowerUse in den Explore-Notes
Die Build-Sektion hat bisher ein Rezept mit allen sechs Testprojekten vorgegeben;
Implementer haben daraus "volle Suite vor fertig" gelesen. Bei bis zu 5
parallelen Tasks kostet das Stunden - und kann das nicht finden, wofuer es
teuer ist: jeder Task arbeitet in seinem eigenen Worktree mit nur seiner eigenen
Aenderung, eine Kollision zwischen zwei parallelen Tasks ist fuer beide
unsichtbar. Kollisionen zeigen sich nach dem Merge, und genau dort laeuft
verify_merges den Verify-Command einmal pro Batch.

Neue Regel: Solution-Build immer (42s, faengt projektuebergreifende
Compile-Brueche), Tests nur --no-build --filter auf das Beruehrte, und melden
welcher Filter benutzt wurde. Die Messwerte stehen dabei, damit die Regel nicht
als Geschmacksfrage gelesen wird.

Messung 2026-09-02, sequenziell nach einem Build: Worker.Tests 507s, Ui 33s,
Data 8s, Rest je 3s, Build 42s. Parallel ueber die Solution ist es schlechter,
nicht besser (Worker 801s, Ui 82s) - diese Tests legen echte Git-Worktrees an
und spawnen Prozesse, sie drangeln sich statt sich zu teilen.

Ausserdem korrigiert: die Zeile "dotnet build ClaudeDo.slnx requires .NET 9"
war veraltet.
2026-09-02 15:44:13 +02:00
Mika Kuns 193752540b feat(ui): PowerUse-Toggle im Usage-Monitor, Opt-in pro Liste
Der Toggle sitzt unter den Gauges im Usage-Monitor, weil "das restliche Fenster
ausnutzen" eine Entscheidung ist, die man beim Blick auf das restliche Fenster
trifft. Er speichert sofort per Read-modify-write, gleiche Disziplin wie
SaveStagesAsync, damit er keine Felder ueberschreibt, die er nicht besitzt.

Zwei Stellen, die das Opt-in still ausgeschaltet haetten:
- WorkerHub.UpdateListConfig loescht die Config-Zeile, wenn alle Felder leer
  sind. PowerUseAllowed muss in diese Leer-Pruefung, sonst verschwindet das
  Opt-in sofort wieder, wenn es das einzige gesetzte Feld ist.
- SettingsModalViewModel baut das AppSettingsDto positional neu auf. Ohne
  Round-trip haette jedes Speichern der Settings PowerUseEnabled auf den
  Record-Default false zurueckgesetzt. Gleiches Muster wie _throttleStages.

Das Handoff-Budget ist als Spinner in Settings -> General editierbar, weil es
auch fuer normale (interaktive) Handler-Runs gilt und nicht an PowerUse haengt.
Das Addendum selbst ist ueber Settings -> Files anpassbar.
2026-09-02 15:44:13 +02:00
Mika Kuns 453d61ca58 feat(worker): PowerUse-Addendum an die Handler-Prompts, Cap aus den Settings
HandoffRoundTracker.Register nimmt den Cap jetzt als Parameter statt aus einer
Konstante; HandoffMcpTools liest ihn pro Aufruf aus app_settings. Werte unter 1
werden auf 1 geklemmt (in WorkerHub UND in Register): der Cap ist das Einzige,
was eine entlaufene Handoff-Kette begrenzt, "0 = unbegrenzt" darf kein Aufrufer
waehlen koennen.

InteractiveLaunchSpecService.ComposeHandlerPromptAsync haengt das PowerUse-
Addendum an den Phasen-Prompt, aber nur wenn globaler Schalter und Listen-Opt-in
beide gesetzt sind. Bewusst ein Addendum statt einer zweiten Prompt-Garnitur:
die gemeinsamen 95% bleiben an einer Stelle, und ein Run ohne PowerUse bekommt
einen byte-identischen Prompt wie vorher. Das Addendum ist als Override der
interaktiven Regeln formuliert (nie fragen, entscheiden und protokollieren;
Konflikte loesen oder abbrechen, nie im Tree liegen lassen; Arbeit ernten, wenn
eine Runde sonst leer laeuft).

Drei Tests pinnen alle vier Ecken des UND, weil die Sicherheitsaussage des
Features genau daran haengt.
2026-09-02 15:43:48 +02:00
Mika Kuns 3cf9628f46 feat(data): PowerUse-Flags und konfigurierbares Handoff-Budget
app_settings bekommt power_use_enabled (Master-Schalter, wird im Usage-Monitor
gesetzt) und list_handler_max_handoffs (Default 4 = zwei Merge-Runden).
list_config bekommt power_use_allowed als Opt-in pro Liste.

Ein Handler-Run laeuft nur unbeaufsichtigt, wenn BEIDE Schalter gesetzt sind.
Damit kann der globale Schalter ueber Nacht an bleiben, ohne dass der Handler
einer nicht zugestimmten Liste sein Verhalten aendert.

UpdateListConfigDto.PowerUseAllowed ist bewusst bool? (tri-state, null =
gespeicherten Wert behalten), analog zu TicketProjectId: SetConfigAsync kopiert
verbatim, ein non-nullable bool haette jedem fremden Writer erlaubt, das Opt-in
per Auslassung zu widerrufen. Der Test dazu nagelt genau das fest.

Migration ist drei reine ALTER TABLE ADD COLUMN, kein Table-Rebuild.
2026-09-02 15:43:32 +02:00
Mika Kuns b00bdf28ae Merge branch 'claudedo/0a185f8e823d42fc9a5b97c5eb91c616' 2026-09-02 15:30:04 +02:00
Mika Kuns 91a37984c6 feat(claude-do): merge Handoff-Budget im Brief sichtbar machen und pro Task mitzähl
ClaudeDo-Task: bdcd601a-2fed-44d8-9164-6d2d008e7f31
2026-09-02 15:28:59 +02:00