Vom CEO gefunden: TSK-0293 stand auf in_progress bei codex — und codex tat
nichts. Ursache: `findAddressedOpenTask` sucht ausschliesslich Tasks mit
Status `open`. Haelt ein Agent bereits eine in_progress-Task (typisch nach
einem Session-Neustart), greift der Busy-Guard und der Loop liefert NICHTS
zurueck. Der Agent wartet dann auf neue Arbeit, die nie kommt, waehrend seine
eigene Task unbearbeitet liegt — und von aussen sieht es aus, als sei er tot.
`resolvePending` liefert jetzt `heldTask`, und alle drei Wege sagen es dem
Agenten deutlich:
- `agenthub start <agent>`: "DU HAELTST BEREITS <id>" ganz oben
- `agenthub work` (CLI): nennt die Task und beendet sich, statt zu warten
- `agenthub_work` (MCP): gibt Task samt Body zurueck statt zu blockieren
Tests: 295 → 297.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Der Check-in prüfte nur `assignedTo`, `findAddressedOpenTask` dagegen
Titel-Präfix `<name>:`, Handoff-Empfänger UND `assignedTo`. Folge: `agenthub
start codex` meldete "AKTUELL: nichts offen", während TSK-0268 mit
`codex:`-Präfix offen lag — der Work-Loop hätte sie unmittelbar danach
geclaimt. Zwei Wahrheiten über dieselbe Frage.
Jetzt nutzt der Check-in dieselbe Adressierungslogik.
Tests: 293 → 295.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`delivered` heißt nur "einmal ausgeliefert", nicht "gelesen" — abgeschlossen
ist eine Nachricht erst mit read/acked. Der Check-in filterte aber auf
`unread` und ließ damit jede Nachricht fallen, die irgendwo schon einmal
aufgetaucht war (etwa beim Session-Start), ohne dass der Agent sie je
beantwortet hätte.
Real aufgefallen an einer Architekten-Korrektur an kimi: Status `delivered`,
im pending-Block unsichtbar — die Korrektur wäre still verlorengegangen.
Genau der Fehlermodus, gegen den der Kanal gebaut wurde.
Tests: 292 → 294.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Realer Fall heute: kimi stellte ASK-0004 um 16:43 und blockierte in
`agenthub_ask(wait:true)`. Der Wait läuft nach 300 s aus. Der Architekt
brauchte für die Architekturentscheidung 18 Minuten — danach war kimi
dormant, das korrekt emittierte `ask`-Event lief ins Leere, und ein Mensch
musste den Agenten wecken.
Dieselbe Taubheit wie in TSK-0274, nur an einer anderen Stelle: dormant =
unerreichbar. Deshalb wandert die Antwort jetzt in den pending-Block —
`resolvePending` liefert beantwortete eigene Fragen mit, sodass sie beim
nächsten Hub-Kontakt (task_log, checkin, start) ankommt, egal wie lange der
Architekt gebraucht hat.
Tests: 290 → 292.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
WURZEL: Ein Agent empfängt SSE-Events ausschließlich, solange er in
agenthub_work blockiert. Während er einen Task AUSFÜHRT, ist er vollständig
taub — kein Reopen, kein Cancel, keine Nachricht erreicht ihn. Ein echter
Interrupt in einen laufenden Agenten-Turn existiert nicht. Heartbeat,
Watchdog, Polling-Fallback und Presence-Tracking waren allesamt Umgehungen
dieser einen Tatsache; deshalb kam das Problem jede Session zurück.
LÖSUNG — der einzige reale Kanal: die Momente, in denen der Agent von sich
aus mit dem Hub spricht.
- checkinService.resolvePending(): zustandslos aus Tasks + Messages
abgeleitet, nichts, was ein Neustart verliert. Erkennt, dass dem Agenten
die Arbeit entzogen wurde (reopen/cancel/fremder Claim), und liefert
ungelesene Nachrichten + offene Zuweisungen mit.
- agenthub_task_log gibt den pending-Block zurück; der Tool-Text macht ihn
verbindlich (pending.interrupted ⇒ sofort aufhören, nicht einreichen).
- Neu: agenthub_checkin(agent, taskId) für lange Strecken ohne Log-Zeile,
plus GET /agents/:agent/pending.
- resolvePending degradiert auf reinen Namensvergleich, wenn keine Config da
ist — ein Check-in darf nie an Konfiguration scheitern.
DEC-0035: `review` bindet den Agenten wie `in_progress`. Vorher galt er in
der Sekunde des Einreichens als frei, griff sich die nächste Task, und ein
Reopen prallte danach am Ein-Task-Guard ab (so ging der Reopen von TSK-0218
verloren). Der Loop bleibt aktiv — wach warten, nichts Neues anfangen.
Außerdem: in_progress → open erlaubt, damit der Architekt eine festhängende
Arbeit überhaupt entziehen kann (vorher 400, Agent blieb dauerhaft blockiert).
SICHTBARKEIT: /health und /agent-health zeigen pro Agent pendingCount
(wartende Tasks) und deafForSec (wie lange ohne Check-in bei laufender
Arbeit). Ungelesene Nachrichten stehen separat — der dreistellige
Altbestand einzelner Agenten hätte das Signal sonst erschlagen.
Tests: 279 → 290. tests/singleClaim (b) auf den neuen Vertrag umgeschrieben
(+ (b2): ein Reopen gewinnt gegen die nächste Task).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>