- TaskSchedule.OccurrenceTimesBetween liefert die Zeitpunkte der restlichen
Laeufe; OccurrencesBetween zaehlt sie nur noch.
- BudgetHeadroom implementiert IBudgetOutlook: Die restlichen geplanten Laeufe
des Tages werden in zeitlicher Reihenfolge durchgegangen, je Agent mit
Grenze und fuer die Instanz, bis zum ersten Lauf, der das Budget verbraucht
vorfaende. Das spiegelt die Pruefung beim Start eines Laufs. Spaetwerk
zaehlt nicht mit, es laeuft ohnehin nur im Spielraum.
- Der Scanner schaut alle 30 Minuten voraus und nennt je Agent und Tag einmal,
wann das Budget ausgeht und wie viele der geplanten Laeufe dann ausfallen,
solange noch Zeit ist, nachzulegen oder zu entscheiden, was wartet.
Die Meldung steht vorerst im Protokoll (Warnung). Der Weg zum Menschen ueber
einen Kanal gehoert zu #646, die Anzeige ins Lagebild (#711).
Tests: 4 neu fuer die Vorschau. 1.261 gruen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- TaskSchedule.OccurrencesBetween zaehlt, wie oft eine Aufgabe bis zu einem
Zeitpunkt noch laeuft, einschliesslich eines jetzt faelligen Laufs.
- BudgetHeadroom (ILateRunGate): Ein mitgenommener oder nachzuholender Lauf
startet nur, wenn er in den Spielraum passt: Grenze minus Verbrauch minus
Reservierung minus Bedarf der restlichen geplanten Laeufe bis Mitternacht
minus 10 % Reserve. Das gilt je Agent und je Instanz, fuer Kosten und Tokens.
Anderes Spaetwerk zaehlt nicht als Bedarf, sonst blockierten sich
mitgenommene Aufgaben gegenseitig.
- Der Scanner fragt den Spielraum nur fuer Spaetwerk und protokolliert, wenn es
warten muss. Die Engine gibt ihren BudgetGuard heraus, damit Scanner und
Engine dieselben Reservierungen sehen.
- Ersetzt den pauschalen 25-%-Anteil aus dem Konzept (dort nachgezogen): Ein
fester Anteil ist an vollen Tagen zu viel, an ruhigen zu wenig.
Drei weitere stille Kappungen bei 500 beseitigt (ListAllAsync, ungekappt):
Kostenprognose (Aufgaben ueber 500 fehlten), Waisenabgleich beim Import und
task_find aus #674, wo Dubletten unter aelteren Aufgaben mit niedriger
Prioritaet unsichtbar wurden.
Tests: BudgetHeadroomTests (9), Scanner-Pforte (1), Dublette hinter 500
Aufgaben (1). 1.257 gruen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bisher teilte sich eine Budgetablehnung den Ausgang NichtGelaufen mit dem
Herunterfahren. Einmalige Aufgaben wurden den Rest des Tages alle 30 Minuten
erneut abgelehnt (jedes Mal ein Beleg) und liefen nach Mitternacht still zu
Lasten des neuen Tages. Wiederkehrende verfielen still.
- TaskLauf.KeinBudget als eigener Ausgang; der Dispatcher bildet
BudgetExceeded darauf ab.
- Vier Felder an der Aufgabe: BudgetMissCount, LastBudgetMissAt,
DeferredUntil, CatchUpPending (Spalten werden fuer bestehende Datenbanken
nachgeruestet).
- Einmalige Aufgaben werden mitgenommen: Der Termin bleibt erhalten, faellig
ist die Aufgabe wieder ab der naechsten lokalen Mitternacht, nicht vorher.
- Wiederkehrende Aufgaben folgen der Regel des Agenten
(budget.whenExhausted): expire vermerkt den Ausfall und laesst den Termin
verfallen; catchUpOnce fasst alle verpassten Termine zu einem Nachholauf am
naechsten Tag zusammen. Ein regulaer faelliger Termin deckt das Nachholen
mit ab, es bleibt bei einem Lauf.
- Der neue Tag hat Vorfahrt: Mitgenommenes und Nachholaeufe kommen nach allem
regulaer Faelligen, unabhaengig von der Prioritaet.
- Beim ersten Takt eines neuen Tages eine Zusammenfassung je Agent im Log.
- Sichtbar: Die Aufgabenkarte der WebUI zeigt Ausfaelle, Mitnahme und
Nachholen; die Regel ist im Desktop je Agent einstellbar. Nebenbei sind
"Next:"/"Last:" auf der Karte ins Sprachpaket gewandert.
Stufen 2 bis 4 (Reservierung, Spielraum statt pauschalem Anteil, Vorbeugen)
folgen.
Tests: BudgetMissTests (9 neu). 1.238 gruen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drei Fehler im Taktgeber des Taskboards, zwei gemeldet, einer beim Bau gefunden:
1. Unbegrenzte Parallelitaet. Jede faellige Aufgabe startete sofort. Bei
Cron-Terminen auf runden Zeiten hiess das: alle Agenten gleichzeitig, und
alle Laeufe passierten die Budgetpruefung gemeinsam, weil sie je Lauf vor
dem Start laeuft. Neu: maxParallelTaskRuns je Instanz (Vorgabe 4). Der Rest
wartet, sortiert nach Prioritaet und dann nach Faelligkeit.
2. Stille Kappung. Die Kandidaten kamen ueber ListAsync mit Limit 500; darueber
fielen Termine lautlos aus dem Takt. Neu: ListRunnableAsync liefert alle
Aufgaben auf todo, ungekappt. Muessen Aufgaben warten, steht das im Log,
allerdings nur, wenn sich die Zahl aendert.
3. Der Takt wartete auf jeden Lauf, den er startete. Ein zehnminuetiger Lauf
hielt damit jeden anderen Termin zehn Minuten an, und mit einem Deckel
haetten die freien Plaetze leer gestanden. Neu: Die Schleife startet und
wartet nicht; DisposeAsync wartet stattdessen auf die laufenden Laeufe.
Beansprucht wird nur, was sofort starten kann. Alles andere bleibt auf todo,
sonst liefe beim Warten der Lease ab und die Aufgabe wuerde ein zweites Mal
beansprucht. Ein Cron-Termin geht dadurch nicht verloren, weil DueOccurrence
bis zum letzten Lauf zuruecksucht. Ein von Hand gestarteter Lauf wartet auf
keinen Platz, belegt aber einen.
Bleibt offen: Bis zu maxParallelTaskRuns Laeufe koennen die Budgetpruefung
weiterhin gemeinsam passieren. Die Luecke ist damit begrenzt, aber nicht
geschlossen; dafuer braeuchte es eine Reservierung vor dem Lauf.
Tests: ScannerCapacityTests (9 neu). 1.229 gruen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#643: Entscheidungen wecken den Agenten nur noch bei Ablehnung oder gescheiterter
Ausfuehrung, gesammelt in einer Aufgabe je Agent (5 min Ruhefenster), frisch per
@new:agent statt im fortgefuehrten Chatverlauf. Eine einmalige Aufgabe, deren Lauf
wegen Budget oder Herunterfahren gar nicht stattfand, bleibt faellig (Wiedervorlage
nach 30 min) statt mit gesetztem Marker liegenzubleiben.
#641: Rechte stehen in der Werkzeugkonfiguration des Agenten (erlaubt/verboten).
Erlaubtes laeuft, Nicht-Erlaubtes wird einzeln vorgelegt statt verweigert, Verbotenes
gar nicht erst. "Gleichartiges kuenftig erlauben" erteilt eine widerrufbare
Dauerfreigabe je Agent/Werkzeug/Operation; nach drei gleichartigen Freigaben schlaegt
die Oberflaeche sie vor. Aenderungen an Agenten bleiben ausnahmslos freigabepflichtig.
Database: Operation ist das SQL-Schluesselwort; die eigene Zugriffspruefung greift nur
noch ohne Freigabestelle (AgentToolContext.FreigabeGeprueft). WebUI: Rechte-Tabelle je
Werkzeug, Dauerfreigaben mit Widerruf.
Version 0.1.11.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Engine: leere Antworten nachfassen, Aufgaben enden mit Ergebniszeile (EmptyResponse/Incomplete),
gleiche Fehlschlaege erkennen (RepeatedFailure), Zeitzeile vor Chatnachrichten,
Werkzeugergebnisse gerahmt, Vorpruefung vor dem Staging, Belegkosten wie RunUsage
- Staging: gescheiterte Freigaben als Failed; AgentEditor-Aenderungen freigabepflichtig,
Selbstbearbeitung gesperrt (allowSelfEdit)
- Taskboard: Termine beim Anlegen pruefen, naechster/letzter Lauf, pausieren, Sofortlauf,
Kostenprognose, Hinweis auf wachsenden Kontext; Jobs-Reiter und /api/jobs entfernt
- Release: Instanzmanager samt Weboberflaeche im Paket, setup.json fragt manager.json ab,
Token nicht mehr ins systemd-Journal
Version 0.1.6.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Nachrichten-Digest im Dauerbetrieb der Test-VM lief nie: CronExpression
verstand 'von-bis/schritt' nicht, TaskSchedule verschluckte den Fehler.
Version 0.1.5.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Weboberflaeche (#531): X-Instanz an der einen fetch-Stelle, Instanzauswahl in der
Kopfzeile, Verwaltungsansicht mit Anlegen/Starten/Anhalten/Fenster, Herkunft der
Ereignisse, Sicherungs- und Einstellungsansicht. 402/409/502 werden eigen behandelt.
Sicherungen im Manager (#530): Auflisten, Anlegen, Wiederherstellen, Loeschen. Das
Zurueckspielen haelt die Instanz vorher an und startet sie danach wieder.
Geordnetes Ende (Konzept 9.8). Zwei Befunde waren der Anlass:
Der Manager konnte eine Instanz MIT FENSTER nie geordnet beenden.
Control.ShutdownRequested war nur in HeadlessRun verdrahtet, nicht in der
Avalonia-Anwendung - und ein Fenster ist die Vorgabe. Die Bitte wurde mit 202
beantwortet, niemand hoerte zu, und der Manager schoss den Prozess nach Ablauf
seiner Frist jedes Mal ab.
InstanceSupervisor.StopAsync hielt Socket-Schweigen fuer einen Todesnachweis und
meldete "beendet", ohne den Prozess anzufassen. Bei einer verstummten Instanz ist
der Socket von vornherein still - der Neustart haette einen zweiten Prozess auf
dieselbe state.db gesetzt. Genau der Schaden, gegen den #528 gebaut ist.
- ShutdownCoordinator: erst die Tuer schliessen, dann auf offene Arbeiten warten,
Frist zwei Minuten. Vorher brach TaskScanner.DisposeAsync mitten in ProcessAsync
ab, sodass die Aufgabe bis zum Lease-Ablauf auf "running" stehenblieb.
- GET /api/instanz/puls hinter dem Socket-Gate: Phase und offene Arbeiten. Weiter
gefragt statt gemeldet - ein Puls, den die Instanz von sich aus schickt, fehlt
genau dann, wenn sie haengt.
- Eskalationsleiter: drei Durchgaenge ohne Antwort, einmal um ein Ende bitten,
nach 30s beenden und den Vollzug abwarten, gemeldet als Absturz.
- EnsureDeadAsync vor jedem Start.
Weiteres aus dem Review:
- .gitignore verankert: "Instances/" passte auch auf src/ClawdDotNet.Core/Instances/.
InstanceEndpoint.cs und InstanceLayout.cs waren dadurch nie eingecheckt.
- Das WebUI-Token stand im Protokoll des Managers. Konsole ja, Datei nein.
- Ein Klick auf "Instanz anlegen" loeste requestSubmit() zweimal aus.
- [Obsolete] auf WebServerPort wieder entfernt: sechs Warnungen, die niemand
abstellen konnte, solange E-M5 nicht fertig ist.
- Die Wiederherstellung bricht nicht mehr ab, wenn der Browser weggeht.
- Entwicklungspfade zum Instanzmanager aus Segmenten statt mit Rueckstrichen, und
der Port kommt aus manager.json statt fest aus der Zeile.
Offen und gemeldet: --managed hebelt die Lizenzpruefung aus (#535).
806 Tests gruen, 0 Warnungen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>