board-agent's own README documents docs/intent/ and docs/research-intent/ as tracked corpus directories, and docs/review/<slug>.md as the reviewer's persisted report per card - but the pipeline only writes these files to the checkout, it never commits them itself. This had built up a backlog of intent/review docs for cards already marked deployed or archiviert in the live board state, which were sitting uncommitted in the working tree. Adds that backlog as-is: the originating intents, their reviewer reports, the research-intent/research pair for the board UX evaluation, and one standalone process-retrospective report (board-review-pipeline-context- overhead.md, same genre as the two already-tracked audit reports in docs/review/). No code changes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T7UVrKsttMP9a6FiGFna9b
163 lines
7.5 KiB
Markdown
163 lines
7.5 KiB
Markdown
# Intent: Builder-Deploy ohne Self-Termination und Doppelverarbeitung
|
|
|
|
## Ziel
|
|
|
|
Ein vom Board ausgelöster Builder darf beim automatischen Deployment auf
|
|
`blunix` weder seinen eigenen Prozess noch das Intent Board in einem
|
|
halbaktivierten Zustand zurücklassen. Nach Commit und Push muss das
|
|
Deployment außerhalb des Lebenszyklus von `agent-codex-builder.service`
|
|
ausgeführt werden und bei Unterbrechungen idempotent fortsetzbar sein.
|
|
|
|
## Beobachteter Produktionsfehler
|
|
|
|
Beim Lauf für
|
|
`board-keep-cards-visible-during-builder-stash` trat am 07.09.2026
|
|
folgender Ablauf auf:
|
|
|
|
1. Um 12:49:29 startete der Board-Job.
|
|
2. Der Builder erzeugte und pushte Commit `62c9ce2`.
|
|
3. Um 12:50:56 startete `deploy_blunix()` synchron
|
|
`nixos-rebuild switch` innerhalb von `agent-codex-builder.service`.
|
|
4. Während der Aktivierung stoppte systemd um 12:51:31
|
|
`board-agent-trigger.service` und anschließend den Builder-Prozess mit
|
|
`SIGTERM` beziehungsweise Status 143.
|
|
5. Der SIGTERM-Handler legte denselben Job wieder in die Queue.
|
|
6. Der zweite Modelllauf erzeugte und pushte den zusätzlichen Commit
|
|
`90ef0c8` und startete erneut ein Deployment.
|
|
7. Derselbe Self-Termination-Ablauf wiederholte sich um 12:53:27.
|
|
8. Erst ein dritter Lauf endete ohne weiteres Deployment, weil keine
|
|
zusätzlichen Änderungen mehr entstanden waren.
|
|
9. `board-agent-trigger.service` blieb `inactive (dead)`, obwohl er
|
|
deklarativ aktiviert und mit `Restart=always` konfiguriert ist.
|
|
|
|
Das war kein Python-Crash des Board-Servers. Der Prozess wurde im Rahmen
|
|
einer vom Builder selbst gestarteten, dann unterbrochenen NixOS-Aktivierung
|
|
geordnet mit `SIGTERM` beendet.
|
|
|
|
## Belegte Ursache
|
|
|
|
- `builder.py:deploy_blunix()` führt `sudo nixos-rebuild switch` synchron
|
|
als Kindprozess des Builders aus.
|
|
- `agent-codex-builder.service` ist die Unit, aus der dieser Rebuild
|
|
gestartet wird. Sobald die neue Konfiguration diese Unit während der
|
|
Aktivierung stoppt, werden Builder und dessen Rebuild-Prozess gemeinsam
|
|
beendet.
|
|
- `builder.py:_handle_sigterm()` requeued jeden aktiven Job unabhängig
|
|
davon, ob Modelllauf, Commit und Push bereits erfolgreich abgeschlossen
|
|
sind.
|
|
- `apply_commit()` führt Commit, Push und Deployment als einen nicht
|
|
persistent phasierten Ablauf aus. Nach dem Requeue ist nicht erkennbar,
|
|
welche Schritte bereits dauerhaft erfolgt sind.
|
|
- Der Retry startet deshalb erneut das Modell und kann einen zweiten
|
|
Commit für denselben Intent erzeugen.
|
|
- Das unterbrochene `nixos-rebuild switch` hatte den Board-Dienst bereits
|
|
gestoppt, erreichte dessen anschließenden Start aber nicht mehr.
|
|
|
|
## Umfang / Auftrag an den Builder
|
|
|
|
### Deployment entkoppeln
|
|
|
|
- `nixos-rebuild switch` nicht mehr synchron im Prozessbaum von
|
|
`agent-codex-builder.service` ausführen.
|
|
- Einen separaten, eng begrenzten Deployment-Runner mit eigenem
|
|
systemd-Lebenszyklus definieren. Er erhält einen persistierten Auftrag
|
|
mit Commit-Hash, Host und Flake-Pfad und führt ausschließlich den
|
|
freigegebenen `blunix`-Switch aus.
|
|
- Der Deployment-Runner muss eine Aktivierung seiner eigenen deklarativen
|
|
Umgebung überleben. Seine Unit darf während des Switch nicht als Teil
|
|
des Builder-Neustarts beendet werden.
|
|
- Builder und Board dürfen ein erfolgreich gestartetes Deployment nicht
|
|
mit einem erfolgreich abgeschlossenen Deployment verwechseln.
|
|
|
|
### Persistente Zustandsmaschine
|
|
|
|
- Den Ablauf pro stabiler Board-Job-ID atomar mindestens in folgende
|
|
Zustände aufteilen:
|
|
`building -> committed -> deploying -> deployed` beziehungsweise
|
|
`build_failed` oder `deploy_failed`.
|
|
- Commit-Hash und Push-Ergebnis unmittelbar nach ihrem Erfolg persistent
|
|
speichern, bevor ein Deployment gestartet wird.
|
|
- Bei Neustart anhand dieses Zustands fortsetzen: Ein bereits committed
|
|
Job darf weder erneut das Modell ausführen noch einen weiteren Commit
|
|
erzeugen.
|
|
- Requeue im SIGTERM-Handler nur zulassen, solange nachweislich noch kein
|
|
Commit für diesen Job gespeichert wurde. Nach `committed` darf höchstens
|
|
der separate Deployment-Schritt erneut beziehungsweise kontrolliert
|
|
fortgesetzt werden.
|
|
- Einen Idempotency-Key aus Board-Job-ID und Intent-Slug verwenden und
|
|
doppelte Queue-/Completion-Einträge sicher deduplizieren.
|
|
|
|
### Fehler- und Retry-Verhalten
|
|
|
|
- Zwischen Build-, Push- und Deployment-Fehlern unterscheiden und den
|
|
Status dem Board explizit melden.
|
|
- Ein gepushter Commit bei fehlgeschlagener oder partieller Aktivierung
|
|
darf nicht als `deployed` gelten.
|
|
- Deployment-Retries begrenzen und mit Backoff versehen. Wiederholte
|
|
Self-Termination, SIGTERM oder Aktivierungsfehler müssen in einem
|
|
sichtbaren `deploy_failed`-Zustand enden statt den Modelllauf erneut zu
|
|
starten.
|
|
- Der Completion-Watcher muss doppelte Records sowie bereits verarbeitete
|
|
Commit-Hashes ignorieren.
|
|
- Nach einem fehlgeschlagenen Deployment muss das Board den Commit-Hash,
|
|
den Deployment-Status und einen manuellen Recovery-Hinweis anzeigen.
|
|
|
|
### Betriebsstabilität
|
|
|
|
- Sicherstellen, dass `board-agent-trigger.service` nach erfolgreicher
|
|
Aktivierung läuft.
|
|
- Wird eine Aktivierung unterbrochen, muss der Deployment-Runner den
|
|
tatsächlichen Unit-Zustand prüfen und einen klaren Fehler melden. Kein
|
|
stilles Zurücklassen eines deklarativ aktivierten, aber faktisch
|
|
gestoppten Boards.
|
|
- Die Lösung darf keine allgemein nutzbare Root-Shell oder zusätzliche
|
|
Modellberechtigung schaffen. Das Modell erzeugt weiterhin nur die
|
|
Änderung; der eng definierte Wrapper führt den Deployment-Auftrag aus.
|
|
|
|
## Tests
|
|
|
|
- Unit-Test: SIGTERM vor dem Commit requeued genau einmal.
|
|
- Unit-Test: SIGTERM nach gespeichertem Commit startet das Modell nicht
|
|
erneut und erzeugt keinen zweiten Commit.
|
|
- Unit-Test: Doppelte Queue- und Completion-Einträge werden anhand der
|
|
Job-ID dedupliziert.
|
|
- Unit-Test: Ein gepushter Commit mit fehlgeschlagenem Switch endet in
|
|
`deploy_failed`, nicht in `deployed` oder einem neuen Builder-Lauf.
|
|
- Integrationstest mit Fake-Deployment-Runner: Builder übergibt den
|
|
Auftrag und kann beendet werden, ohne den Runner zu terminieren.
|
|
- Integrationstest: Der Runner meldet nach erfolgreicher Aktivierung den
|
|
Zustand des Board-Dienstes und den aktivierten Systempfad zurück.
|
|
- Bestehende Board-, Builder-, Rollen- und Nix-Evaluierungstests müssen
|
|
grün bleiben.
|
|
|
|
## Ausgeschlossen
|
|
|
|
- Kein erneuter Modelllauf als allgemeine Recovery-Strategie nach bereits
|
|
erfolgreichem Commit.
|
|
- Kein Zurücksetzen oder Umschreiben der bereits gepushten Commits
|
|
`62c9ce2` und `90ef0c8`.
|
|
- Keine Abschaffung der bestehenden Sandbox- und Rollenbegrenzungen.
|
|
- Kein automatisches Deployment auf andere Hosts als `blunix`.
|
|
- Keine imperative Aktivierung allein durch das Vorhandensein dieses
|
|
Intent-Dokuments.
|
|
|
|
## Erfolgskriterien
|
|
|
|
- Ein Board-Job erzeugt auch bei einem Dienstneustart höchstens einen
|
|
fachlichen Commit.
|
|
- Der Builder wird nicht durch seinen eigenen Deployment-Kindprozess in
|
|
eine Requeue-Schleife gebracht.
|
|
- Ein unterbrochener Switch hinterlässt keinen fälschlich erfolgreichen
|
|
Board-Status.
|
|
- Nach erfolgreichem Switch antwortet das Board wieder; nach einem Fehler
|
|
zeigt es einen eindeutigen, persistenten Recovery-Status.
|
|
- Commit-/Push- und Deployment-Ergebnisse sind getrennt nachvollziehbar.
|
|
- Der aktuelle Produktionsfehler lässt sich mit einem Test reproduzieren,
|
|
der vor der Änderung fehlschlägt und danach besteht.
|
|
|
|
## Aktueller Recovery-Hinweis
|
|
|
|
Zum Zeitpunkt der Diagnose ist `board-agent-trigger.service` auf `blunix`
|
|
seit 12:51:31 `inactive (dead)`. Eine manuelle Wiederinbetriebnahme oder
|
|
ein vollständiger erneuter `nixos-rebuild switch` ist eine separate
|
|
betriebliche Aktion und nicht durch diesen Intent freigegeben.
|