feat(ops-agent): setup.sh synct de drift-runtime, met luide bronwaarschuwing #141

Merged
janpeter merged 1 commit from feat/drift-sync-in-setup into main 2026-08-03 07:42:39 +02:00
Owner

De remedie uit #140 bestond wel maar werd door niets aangeroepen — dezelfde vorm als het gat dat hij dicht. setup.sh roept apply-drift-runtime.sh nu aan.

Plaatsing: als laatste stap, na de herstart. De detector is observability; de agent draait zonder hem. Eerder in het script zou een mislukking hier een nieuwe build in /opt achterlaten met het oude proces draaiend — de half-toegepaste staat die #138 wegnam. Geen || true: een detector die stil half geinstalleerd raakt is een kapot vangnet dat zegt dat alles in orde is.

De valkuil die dit introduceert, en wat eraan gedaan is: setup.sh kan de runtime nu naar een vuile of achterlopende checkout trekken, waarna de detector no drift meldt omdat repo en runtime het met elkaar eens zijn terwijl beide van de upstream af staan. Daarom waarschuwt de apply luid over de staat van de bron. Waarschuwen, niet weigeren — installeren vanaf een feature-branch is normaal werk en een harde weigering zou dat blokkeren.

Die staat wordt niet herberekend maar uit de detector getrokken naar deploy/ops-agent/scripts/repo-state.sh. Eén bron; een tweede berekening van dezelfde waarheid is hoe deze reeks fouten ontstond. Exit 0 = veilig, 3 = VUIL en/of ACHTER, 2 = geen checkout. Alleen-vooruit is geen 3; een ontbrekende upstream wel, want dan kun je niet vaststellen of je achterloopt.

Meting die de scope raakt: setup.sh installeerde ops-agent-drift.service/.timer niet — die stonden op de host omdat iemand ze had neergezet (de timer dateert van 8 juni). Zelfde klasse als het script, dus meegenomen en hier expliciet gemeld.

Bewijzen (op de host, via setup.sh — niet met de hand)

  1. Sync werkt via de bedrading. Runtime-baseline gecorrumpeerd -> detector meldt 3 files drift, exit 1 -> setup.sh -> injectie weg, md5 runtime == repo, runtime-script == repo -> detector no drift, exit 0.
  2. Waarschuwing vuurt. Checkout vuil gemaakt -> WARNING: de drift-runtime wordt gesynct vanaf een checkout die NIET schoon en actueel is. met staat feat/drift-sync-in-setup@e097e14, VUIL, gelijk met upstream. setup.sh blijft exit 0.
  3. Niets geregresseerd. setup.sh exit 0 tot ==> Done, SKIPPED-regels intact, foundation-skip herstart de agent nog steeds. Agent HTTP 200 op /agent/v1/health, listener 172.18.0.1:3099, 101 keys / 18 flows, timer active/enabled, provenance == main:ops-agent.

test/repo-state.test.ts 7/7. control-room-foundation.test.ts geeft lokaal 65 gefaald — identiek aan main, gemeten in een aparte worktree, en nul sporen van deze wijziging in de failures.

🤖 Generated with Claude Code

De remedie uit #140 bestond wel maar werd door niets aangeroepen — dezelfde vorm als het gat dat hij dicht. `setup.sh` roept `apply-drift-runtime.sh` nu aan. **Plaatsing: als laatste stap, na de herstart.** De detector is observability; de agent draait zonder hem. Eerder in het script zou een mislukking hier een nieuwe build in `/opt` achterlaten met het oude proces draaiend — de half-toegepaste staat die #138 wegnam. Geen `|| true`: een detector die stil half geinstalleerd raakt is een kapot vangnet dat zegt dat alles in orde is. **De valkuil die dit introduceert**, en wat eraan gedaan is: setup.sh kan de runtime nu naar een vuile of achterlopende checkout trekken, waarna de detector `no drift` meldt omdat repo en runtime het met elkaar eens zijn terwijl beide van de upstream af staan. Daarom waarschuwt de apply luid over de staat van de bron. **Waarschuwen, niet weigeren** — installeren vanaf een feature-branch is normaal werk en een harde weigering zou dat blokkeren. Die staat wordt niet herberekend maar uit de detector getrokken naar `deploy/ops-agent/scripts/repo-state.sh`. Eén bron; een tweede berekening van dezelfde waarheid is hoe deze reeks fouten ontstond. Exit 0 = veilig, 3 = VUIL en/of ACHTER, 2 = geen checkout. Alleen-vooruit is geen 3; een ontbrekende upstream wel, want dan kun je niet vaststellen of je achterloopt. **Meting die de scope raakt:** `setup.sh` installeerde `ops-agent-drift.service/.timer` niet — die stonden op de host omdat iemand ze had neergezet (de timer dateert van 8 juni). Zelfde klasse als het script, dus meegenomen en hier expliciet gemeld. ## Bewijzen (op de host, via setup.sh — niet met de hand) 1. **Sync werkt via de bedrading.** Runtime-baseline gecorrumpeerd -> detector meldt 3 files drift, exit 1 -> `setup.sh` -> injectie weg, md5 runtime == repo, runtime-script == repo -> detector `no drift`, exit 0. 2. **Waarschuwing vuurt.** Checkout vuil gemaakt -> `WARNING: de drift-runtime wordt gesynct vanaf een checkout die NIET schoon en actueel is.` met `staat feat/drift-sync-in-setup@e097e14, VUIL, gelijk met upstream`. setup.sh blijft exit 0. 3. **Niets geregresseerd.** setup.sh exit 0 tot `==> Done`, SKIPPED-regels intact, foundation-skip herstart de agent nog steeds. Agent HTTP 200 op `/agent/v1/health`, listener `172.18.0.1:3099`, 101 keys / 18 flows, timer active/enabled, provenance == `main:ops-agent`. `test/repo-state.test.ts` 7/7. `control-room-foundation.test.ts` geeft lokaal 65 gefaald — **identiek aan main**, gemeten in een aparte worktree, en nul sporen van deze wijziging in de failures. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(ops-agent): setup.sh synct de drift-runtime, met luide bronwaarschuwing
All checks were successful
CI / Root app checks (pull_request) Successful in 5m45s
CI / Ops-agent checks (pull_request) Successful in 15s
CI / Deploy artifact checks (pull_request) Successful in 12s
CI / Docker image build (pull_request) Successful in 1m22s
e097e14f28
De remedie uit #140 bestond wel maar werd door niets aangeroepen — dezelfde
vorm als het gat dat hij dicht, dus het gat keerde terug. setup.sh roept
apply-drift-runtime.sh nu aan als laatste stap.

Bewust ALS LAATSTE, na de herstart: de detector is observability en de agent
functioneert zonder hem. Eerder in het script zou een mislukking hier een
nieuwe build in /opt achterlaten met het oude proces draaiend — precies de
half-toegepaste staat die #138 wegnam. Geen `|| true`: een detector die stil
half geinstalleerd raakt is een kapot vangnet dat zegt dat alles in orde is.

De valkuil die dit introduceert is dat setup.sh de runtime voortaan naar een
vuile of achterlopende checkout kan trekken, waarna de detector "no drift"
meldt omdat repo en runtime het met elkaar eens zijn terwijl beide van de
upstream af staan. Daarom waarschuwt de apply luid over de staat van de bron.
Waarschuwen en niet weigeren: installeren vanaf een feature-branch is normaal
werk en een harde weigering zou dat blokkeren.

Die staat wordt niet opnieuw berekend maar uit de detector getrokken naar
deploy/ops-agent/scripts/repo-state.sh — een tweede berekening van dezelfde
waarheid is hoe deze hele reeks fouten is ontstaan. Exit 0 = veilig, 3 = VUIL
en/of ACHTER, 2 = geen checkout. Alleen-vooruit lopen is geen 3; een
ontbrekende upstream wel, want dan kun je niet vaststellen of je achterloopt.

Gemeten: setup.sh installeerde ops-agent-drift.service/.timer niet — die
stonden op de host omdat iemand ze had neergezet (de timer dateert van 8 juni).
Zelfde klasse als het script, dus meegenomen; anders staat de detector op een
verse host wel klaar maar draait hij nooit.

apply-drift-runtime.sh respecteert nu OPS_AGENT_ROOT_PREFIX, zodat de
hermetische testmodus van setup.sh niet de echte runtime overschrijft, en
slaat de systemd-activatie daar over. De harness kopieert hem daarom ECHT in
plaats van te stubben: een '#!/bin/sh'-stub zou groen geven zonder een regel
van de bedrading aan te raken.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
s4m-codex-reviewer left a comment

Verdict: REQUEST_CHANGES

Geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden.

Findings

  • errordeploy/ops-agent/scripts/repo-state.sh:54: de parsing van git rev-list --left-right --count 'HEAD...@{u}' gebruikt ${ab%%\t*} en ${ab##*\t}. In Bash pattern matching is \t geen tab; bij output zoals 0<TAB>1 blijven ahead en behind dus de volledige string. Daardoor wordt een achterlopende checkout niet als 1 ACHTER herkend, blijft attention=0, en exit het script met 0. Dit breekt precies de veiligheidsfunctie die deze PR toevoegt: setup.sh kan alsnog stil een runtime syncen vanaf een achterlopende checkout zonder waarschuwing. De nieuwe tests voor alleen-vooruit en achterlopen zouden dit ook moeten vangen en falen met de huidige implementatie. Gebruik een echte tab-split, bijvoorbeeld IFS=$'\t' read -r ahead behind <<< "$ab", en verifieer de repo-state tests.

Verdict-log

REQUEST_CHANGES omdat de gedeelde bronstatus-helper het kerncontract voor achterlopende checkouts niet correct implementeert.

# Verdict: REQUEST_CHANGES Geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden. ## Findings - **error** — `deploy/ops-agent/scripts/repo-state.sh:54`: de parsing van `git rev-list --left-right --count 'HEAD...@{u}'` gebruikt `${ab%%\t*}` en `${ab##*\t}`. In Bash pattern matching is `\t` geen tab; bij output zoals `0<TAB>1` blijven `ahead` en `behind` dus de volledige string. Daardoor wordt een achterlopende checkout niet als `1 ACHTER` herkend, blijft `attention=0`, en exit het script met `0`. Dit breekt precies de veiligheidsfunctie die deze PR toevoegt: `setup.sh` kan alsnog stil een runtime syncen vanaf een achterlopende checkout zonder waarschuwing. De nieuwe tests voor alleen-vooruit en achterlopen zouden dit ook moeten vangen en falen met de huidige implementatie. Gebruik een echte tab-split, bijvoorbeeld `IFS=$'\t' read -r ahead behind <<< "$ab"`, en verifieer de repo-state tests. ## Verdict-log `REQUEST_CHANGES` omdat de gedeelde bronstatus-helper het kerncontract voor achterlopende checkouts niet correct implementeert.
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
janpeter/Ops-dashboard!141
No description provided.