@@ -129,7 +159,7 @@ Vier korte vragen om te checken of je dit deel begrepen hebt. Vastgelopen? Klik
-Eén soort check is voorspelbaar en goedkoop, de andere is duur maar kan oordelen. Wat is sterk en zwak aan elk?
+Eén soort check is voorspelbaar en goedkoop, de andere is duur maar kan oordelen. Wat is de sterke en zwakke kant van elk?
@@ -138,9 +168,9 @@ Eén soort check is voorspelbaar en goedkoop, de andere is duur maar kan oordele
Ze vullen elkaar precies aan op de plekken waar de ander zwak is.
- **Mechanische gates** zijn **deterministisch**: zelfde input → zelfde uitkomst, slagen of falen. Perfect voor saai, objectief nakijkwerk — bijvoorbeeld "heeft elke nieuwe PHP-file een SPDX-header?". Goedkoop en herhaalbaar.
-- **AI-reviewers** doen **oordeel**: "klopt deze authorization-logica semantisch met het route-doel", "is dit in deze context een veiligheidsrisico". Niet voorspelbaar en duurder, dus zet je ze in waar oordeel nodig is.
+- **AI-reviewers** leveren **oordeel**: "klopt deze autorisatielogica inhoudelijk met het doel van de route", "is dit in deze context een veiligheidsrisico". Niet voorspelbaar en duurder, dus zet je ze in waar oordeel nodig is.
-Alleen-mechanisch mist context-afhankelijke fouten; alleen-AI is duur, niet voorspelbaar, en verspilt Sonnet-tijd aan dingen die een `grep` kan.
+Alleen mechanisch mist fouten die van de context afhangen; alleen AI is duur, niet voorspelbaar, en verspilt modeltijd aan dingen die een script kan.
@@ -148,11 +178,11 @@ Alleen-mechanisch mist context-afhankelijke fouten; alleen-AI is duur, niet voor
-**2. Wat zegt ADR-020 over de gate-scope, en wanneer schakel je dat via `HYDRA_REVIEW_SCOPE=full` uit?**
+**2. Wat zegt ADR-020 over de gate-scope, en waar heeft `HYDRA_REVIEW_SCOPE=full` effect?**
-Denk aan wat er gebeurt als je `phpcs` op een repo met veel oude technische schuld loslaat. En wanneer wil je dat juist wél?
+Denk aan wat er gebeurt als je een gate loslaat op een repo met veel oude technische schuld. En lezen de flows die variabele?
@@ -160,13 +190,13 @@ Denk aan wat er gebeurt als je `phpcs` op een repo met veel oude technische schu
ADR-020 zegt: **gates draaien op de PR-diff, niet op de hele repo**.
-Reden: veel repo's slepen technische schuld mee. `phpcs` over alles geeft honderden findings die niets met de huidige PR te maken hebben — elke PR zou rood worden. Door alleen de geraakte regels te checken slaat de gate alleen om op wat de builder net heeft toegevoegd of gewijzigd.
+Reden: veel repo's slepen technische schuld mee. Een gate over alles geeft honderden bevindingen die niets met de huidige PR te maken hebben — elke PR zou rood worden. Door alleen de diff te controleren, slaat de gate aan op wat de build net heeft toegevoegd of gewijzigd.
-**`HYDRA_REVIEW_SCOPE=full`** in `secrets/.env` schakelt dit uit — gates draaien dan op de hele repo. Gebruik bij:
-- **Onboarding van een nieuwe repo** in Hydra.
-- Een **dedicated tech-debt-sweep**.
+De flows leggen `--scope-to-diff` vast. **`HYDRA_REVIEW_SCOPE=full`** verandert alleen lokale en handmatige runs (`dev-run.sh`, `manual-review.sh`), waar de review dan de hele repo omvat. Gebruik dat bij:
+- **Het onboarden van een nieuwe repo** in Hydra.
+- Een **gerichte tech-debt-sweep**.
-NIET voor reguliere PRs — verwacht veel rood.
+NIET voor gewone PR's — verwacht veel rood.
@@ -174,11 +204,11 @@ NIET voor reguliere PRs — verwacht veel rood.
-**3. Hoe herken je een fout-positieve gate, en wat is de juiste fix? Wat NIET?**
+**3. Hoe herken je een vals-positieve gate, en wat is de juiste fix? Wat NIET?**
-Drie signalen samen wijzen op een fout-positief. En de "verleidelijke maar verkeerde" reflex is hetzelfde nóg een keer doen.
+Drie signalen samen wijzen op een vals-positief. En de "verleidelijke maar verkeerde" reflex is hetzelfde nog een keer doen.
@@ -186,13 +216,13 @@ Drie signalen samen wijzen op een fout-positief. En de "verleidelijke maar verke
**Herkenning** — drie signalen samen:
-1. De gate slaat in elke retry op **dezelfde regel**, terwijl die regel onschuldig oogt.
-2. **Handmatig lokaal de gate runnen** bevestigt: het patroon matched, maar niet om de bedoelde reden (bijv. `grep 'dd('` matcht ook `$builder->add(`).
-3. Niemand in het team kan uitleggen waarom dit specifieke regel-niveau erover zou moeten klagen.
+1. De gate slaat bij elke build aan op **dezelfde regel**, terwijl die regel onschuldig oogt.
+2. **De gate lokaal draaien** bevestigt: het patroon matcht, maar niet om de bedoelde reden (bijvoorbeeld een tekstzoekopdracht die ook commentaar of een string-literal raakt).
+3. Niemand in het team kan uitleggen waarom juist deze regel een klacht verdient.
-**Juiste fix:** scherp de **gate-detectie** aan in `scripts/run-quality.sh` of de bijbehorende skill. Voorbeeld: `grep 'dd('` → `grep -wE '(^|[^A-Za-z0-9_])dd\('`.
+**Juiste fix:** repareer de **gate-detectie** in het pakket `conduction/hydra-gates` (`ConductionNL/.github`, `hydra-gates/`). Hydra's `scripts/run-hydra-gates.sh` geeft alleen door.
-**NIET:** nog een keer `retry:queued`. Dat reproduceert hetzelfde fout-positief en verspilt cycles.
+**NIET:** de build opnieuw in de wachtrij zetten. Dat levert hetzelfde vals-positief op en verspilt een run.
@@ -200,19 +230,18 @@ Drie signalen samen wijzen op een fout-positief. En de "verleidelijke maar verke
-**4. Waarom draait Hydra de mechanische gates nogmaals NA de reviewer-fixes (de "quality-recheck"-fase)?**
+**4. Waar draait Hydra de gates automatisch opnieuw, en waar NIET?**
-De reviewers mogen binnen scope zelf fixen. Wat kan daarbij misgaan?
+Denk aan de fix-ronde in de build-lane, en aan wat er gebeurt na een begrensde fix van een reviewer.
-Reviewers (Juan + Clyde) mogen binnen scope mechanische fixes pushen (ADR-021). Daarbij kan een reviewer **per ongeluk een nieuwe overtreding introduceren** — bijvoorbeeld een PHPCS-style fix die elders een regel breekt.
-
-De **quality-recheck** draait alle mechanische gates opnieuw op de uiteindelijke PR-staat zodat zeker is dat wat er nu staat ook objectief schoon is. Slaat de recheck rood → `needs-input`, geen retry. De reviewer is gestopt, de bouwer is gestopt, een mens kijkt. Het is de laatste deterministische gate vóór er een menselijke beslissing valt.
+- **Wel:** in de build-lane. Faalt de eerste gate-run, dan volgt één fix-ronde, en daarna draaien de gates nog één keer over de gerepareerde tree. Die uitslag bepaalt `build:pass` of `build:fail`.
+- **Niet:** na review. Een "quality-recheck" na review bestaat niet in de flows. Elke reviewstage moet de gates zelf draaien en `hydra-gates` opnemen in `checks_run`; een verdict dat dat niet doet, wordt niet geaccepteerd en het issue komt op `needs-input`.
@@ -227,7 +256,7 @@ De **quality-recheck** draait alle mechanische gates opnieuw op de uiteindelijke
Wat een Claude-Code-skill is en hoe Hydra ze gebruikt om gedrag bij personas te bundelen.
- Welke skills de automatische Hydra-fabriek in zijn Docker-containers heeft staan (per agent: Builder, Reviewer, Security) — en welke skills alleen voor mensen op de CLI zijn.
+ Wat een stage in de automatische Hydra-fabriek te gebruiken krijgt, welke skills de container-images meedragen (Builder, Reviewer, Security) — en welke skills alleen voor mensen op de CLI zijn.
De vijf skill-families binnen Hydra: {'opsx-*'}, {'hydra-gate-*'}, {'team-*'}, {'test-*'}, en de utility/maintenance-skills.
De twee manieren waarop een skill geactiveerd kan worden — handmatig via /{''} of automatisch door Claude — en hoe je dat per skill stuurt.
Wanneer je zelf een skill toevoegt en hoe je dat structureel doet.
@@ -55,40 +55,44 @@ Welke mode is toegestaan, regel je in de frontmatter van de skill zelf:
- `user-invocable: false` — alleen Claude zelf mag 'm laden. Gebruik dit voor achtergrondkennis (bijvoorbeeld een `legacy-system-context` die niet als actie zinvol is).
- Geen van beide gezet — beide mogen.
-Dat onderscheid — handmatig vs. automatisch — gaat dus over **configuratie van één skill**, niet over twee verschillende soorten bestanden. Een persona in een Docker-container heeft geen toetsenbord en leunt vooral op auto-activatie; een mens op de CLI wil meestal expliciete controle en typt `/`.
+Dat onderscheid — handmatig vs. automatisch — gaat dus over **configuratie van één skill**, niet over twee verschillende soorten bestanden. Een pipeline-stage heeft geen toetsenbord: hij krijgt een prompt die zegt wat hij moet doen en welke brief hij volgt, en wat hij daarnaast laadt is Claude's eigen keuze. Een mens op de CLI wil meestal expliciete controle en typt `/`.
## Twee werelden: de Hydra-fabriek vs. skills voor mensen
-Hydra's `hydra/.claude/skills/` bevat ~70 skills, maar de **automatische pipeline gebruikt er maar een handvol**. De rest is gereedschap voor jou, achter een toetsenbord. Belangrijk om uit elkaar te houden:
+Hydra's `hydra/.claude/skills/` bevat zo'n 130 skill-mapjes, waarvan ongeveer 60 `hydra-gate-*` (`ls .claude/skills` geeft het aantal van vandaag). **De automatische pipeline leunt op heel weinig daarvan.** De rest is gereedschap voor jou, achter een toetsenbord. Belangrijk om uit elkaar te houden:
### Wat de Hydra-fabriek echt draait
-Elke pipeline-container heeft een eigen, beperkte set skills in zijn Docker-image gebakken:
+Een echte run wordt gedreven door de flow `hydra-sequencer` (deel 7). De hermiq-app draait elke stage als `claude -p` in een checkout van de doel-repo, met Hydra's eigen tool-tree ernaast. De prompt van de stage zegt wat er moet gebeuren:
+
+- **Build (Al Gorithm)** — de prompt vraagt om de OpenSpec-change uit het issue te implementeren. Hij noemt geen skill. De agent mag bestanden lezen en bewerken (Read, Edit, Write, Glob, Grep) en krijgt de opdracht geen git te draaien; de pipeline commit en pusht. Daarna draait de pipeline zelf `scripts/run-hydra-gates.sh --scope-to-diff`, staat één fix-ronde op de gate-output toe, en draait de gates opnieuw.
+- **Code review, security review, applier (Juan Claude, Clyde Barcode, Axel Pliér)** — elk leest zijn eigen brief uit `agents//` plus de stage-brief onder `images/`, draait de gates zoals die brief voorschrijft, en schrijft een verdict-bestand. Een verdict waarvan `checks_run` geen `hydra-gates` noemt, wordt geweigerd.
+
+De **container-images** start je zelf, met `dev-run.sh`, `smoke-test.sh` of `manual-review.sh` (deel 5). Elk heeft een eigen, beperkte set skills ingebakken:
| Container | Persona | Skills in image | Hoofdfunctie |
|---|---|---|---|
-| **Builder** | Al Gorithm | **Alle** `.claude/skills/*` + alle vendor skills | Implementeert taken; primair `opsx-apply`. Heeft de overige opsx-skills bij de hand voor context bij verifiëren, hertrouw zoeken, fixen na quality-fail. |
-| **Reviewer** | Juan Claude | `hydra-gates` + 13 `hydra-gate-*` skills + vendor `code-review` | Mandatory hydra-gates check + diepere code-review via de Anthropic community-skill. |
-| **Security** | Clyde Barcode | `hydra-gates` + 13 `hydra-gate-*` skills + vendor `trailofbits` + vendor `owasp` | Mandatory hydra-gates + SAST (Semgrep) + OWASP-top-10-checklists. |
-| **Applier** | Axel Plier | **Geen skills** | Past kleine, deterministische fixes toe puur via zijn `CLAUDE.md` — geen skill-laag nodig. |
-| **Browser UI Tester** | (sonnet, headless) | Eén skill: `hydra-ui-test` | Logt in, navigeert de live app via Playwright MCP, levert verdict JSON. |
+| **Builder** | Al Gorithm | **Alle** skills uit `.claude/skills/` (geen vendor skills) | Implementeert de change; de entrypoint van de image volgt `opsx-apply`. De overige opsx-skills zijn er voor context. |
+| **Reviewer** | Juan Claude | `hydra-gates` + een vaste selectie van 16 `hydra-gate-*` skills + vendor `code-review` | Verplichte hydra-gates-check + diepere code-review via de Anthropic community-skill. |
+| **Security** | Clyde Barcode | `hydra-gates` + dezelfde 16 `hydra-gate-*` skills + vendor `trailofbits` (de Semgrep-plugin) + vendor `owasp` | Verplichte hydra-gates + SAST (Semgrep) + OWASP-top-10-checklists. |
+| **Applier** | Axel Pliér | **Geen skills**; zijn config staat alleen Read en Bash toe | Leest de uiteindelijke diff en beide review-verdicts en geeft één binair antwoord — `pass` of `fail`. Hij past **geen** fixes toe; hij is een go/no-go-poort, geen editor. |
-Daarnaast draait **`scripts/run-hydra-gates.sh`** in elke container alle **14** hydra-gates mechanisch — los van welke skill-files er in de image staan. De skill-files dienen voor Claude als documentatie bij een fix; het script doet de detectie.
+Welke skill-files een image ook meedraagt, de detectie doet **`scripts/run-hydra-gates.sh`**. Dat is een dun doorgeefluik naar het package `conduction/hydra-gates`, dat vandaag zo'n 96 gates declareert. Dat getal groeit met elk incident, dus vertrouw geen aantal dat in een doc staat (deze inbegrepen): elke run print een COVERAGE-regel met wat hij declareerde en wat er echt draaide. De skill-files dienen Claude als documentatie bij een fix; het script doet de detectie.
### Wat de fabriek **niet** doet — voor mensen op de CLI
-Alle andere skills (~50 van de 70) zijn voor jou, of voor een collega-dev in een Claude Code sessie op zijn laptop. Voorbeelden:
+Vrijwel alle andere skills zijn voor jou, of voor een collega-dev in een Claude Code-sessie op zijn laptop. Voorbeelden:
-- **Een change voorbereiden** — `opsx-new`, `opsx-ff`, `opsx-explore`, `opsx-plan-to-issues` doe je als mens vóór je het werk in de pipeline gooit. De Builder runt alleen `opsx-apply` op een al-bestaande change.
-- **Een role aannemen** — `team-architect`, `team-backend`, `team-po` enz. zijn pure roleplay-frames voor één-mens-één-rol sessies. De pipeline gebruikt ze niet.
-- **Testen draaien** — `/test-counsel` (alle 8 personas) of `/test-app` (één browser-sweep) start je met de hand. De fabriek heeft een eigen browser-tester (`hydra-ui-test`); de `test-*` familie staat los daarvan.
-- **PR's en dag-werk** — `/create-pr`, `/review-pr`, `/report-out` zijn de "drie keer per dag"-tools voor jou, niet voor de pipeline.
+- **Een change voorbereiden** — `opsx-new`, `opsx-ff`, `opsx-explore`, `opsx-plan-to-issues` doe je als mens vóór je het werk in de pipeline gooit. De pipeline bouwt alleen een change die al bestaat.
+- **Een rol aannemen** — `team-architect`, `team-backend`, `team-po` enz. zijn pure roleplay-frames voor één-mens-één-rol-sessies. De pipeline gebruikt ze niet.
+- **Testen draaien** — `/test-counsel` (alle negen personas) of `/test-app` (één browser-sweep) start je met de hand. De pipeline draait helemaal geen browser; de `test-*`-familie is van jou.
+- **PR's en dagelijks werk** — `/create-pr`, `/review-pr`, `/report-out` zijn de "drie keer per dag"-tools voor jou, niet voor de pipeline.
-Onthoud: **de fabriek pakt 5 skills, een mens kan tegen alle 70 aanroepen**. Dat is het hele verschil.
+Onthoud: **een pipeline-stage volgt zijn prompt, zijn brief en de gate-suite; een mens kan elke skill in de map aanroepen**. Dat is het hele verschil.
## De vijf skill-families compleet
-Met die scheiding in het achterhoofd, hier zijn alle vijf families. Het tag-systeem in de tabel: **🤖 fabriek** = staat in een pipeline-container, **⌨️ mens** = alleen via CLI.
+Met die scheiding in het achterhoofd, hier zijn alle vijf families. Het tag-systeem in de tabel: **🤖 fabriek** = gebruikt door de pipeline of door de entrypoint van een pipeline-image, **⌨️ mens** = roep je zelf aan. (De builder-image kopieert de hele map `.claude/skills/`, dus de meeste ⌨️-skills *staan* erin; niets in de pipeline roept ze aan.)
### Familie 1: OpenSpec workflow (`opsx-*`, 16 skills)
@@ -96,109 +100,114 @@ De OPSX-skills implementeren de Conduction-workflow voor OpenSpec-changes — va
| Skill | Voor wie | Doet |
|---|---|---|
-| `opsx-apply` | 🤖 Builder | Implementeert taken uit een change (de pipeline-default). |
-| `opsx-verify` | 🤖 Builder | Controleert dat de implementatie de change-artefacten dekt. |
-| `opsx-archive` | 🤖 Builder + ⌨️ | Archiveert een afgeronde change, syncing delta naar de spec. |
-| `opsx-new` | ⌨️ | Start een nieuwe change (proposal scaffold, schema-keuze). |
+| `opsx-apply` | 🤖 Builder-image + ⌨️ | Implementeert taken uit een change. De entrypoint van de builder-image volgt hem; de build-prompt van de flow noemt hem niet. |
+| `opsx-verify` | ⌨️ | Controleert dat de implementatie de change-artefacten dekt. |
+| `opsx-archive` | ⌨️ | Archiveert een afgeronde change en synct de delta naar de spec. |
+| `opsx-new` | ⌨️ | Start een nieuwe change (proposal-scaffold, schema-keuze). |
| `opsx-ff` | ⌨️ | "Fast-forward": maakt change + alle artefacten in één pass. |
| `opsx-continue` | ⌨️ | Pak een onderbroken change op. |
| `opsx-explore` | ⌨️ | Verken pre-spec wat een change überhaupt zou moeten zijn. |
-| `opsx-onboard` | ⌨️ | Onboarding-flow op een nieuwe repo (zet OpenSpec config + structuur op). |
-| `opsx-plan-to-issues` | ⌨️ | Converteert `tasks.md` naar GitHub-issues + tracking-issue. |
+| `opsx-onboard` | ⌨️ | Begeleide rondgang door één complete OpenSpec-workflowcyclus, met uitleg onderweg. |
+| `opsx-plan-to-issues` | ⌨️ | Zet `tasks.md` om naar een `plan.json` en een tracking-issue met taak-checkboxes. |
| `opsx-sync` | ⌨️ | Sync delta-specs terug naar de hoofdspec. |
| `opsx-bulk-archive` | ⌨️ | Archiveer meerdere afgeronde changes in één keer. |
-| `opsx-apply-loop` | ⌨️ | Headless build → quality-fix lus voor lokale dev-runs. |
-| `opsx-pipeline` | ⌨️ | Parallel meerdere changes tegelijk laten lopen (multi-agent). |
+| `opsx-apply-loop` | ⌨️ | Draait apply → verify in een lus tot verify slaagt, en archiveert dan; per app, in Docker. |
+| `opsx-pipeline` | ⌨️ | Meerdere changes parallel laten lopen met subagents. |
| `opsx-coverage-scan` | ⌨️ | Audit een legacy app op spec ↔ code coverage. |
| `opsx-annotate` | ⌨️ | Past `@spec` PHPDoc-tags toe na een coverage-scan. |
| `opsx-reverse-spec` | ⌨️ | Reverse-engineert een spec uit bestaande code. |
-### Familie 2: Quality + security gates (`hydra-gate-*`, 14 skills)
+Zestien skills is veel. In de praktijk pak je er een handvol, en de keuze volgt een simpele beslishulp:
-De parent-skill **`hydra-gates`** is een dispatcher die alle gates samen afroept. De script-engine onder de motorkap (`scripts/run-hydra-gates.sh`) draait alle 14 gates in elke container; de skill-files dienen Claude als referentie bij het fixen van een failure.
+- **Nieuw begonnen en zeker van de feature?** → `opsx-ff` (in één pass naar alle artefacten), daarna `opsx-plan-to-issues`.
+- **Nieuw begonnen maar onzeker over scope of aanpak?** → eerst `opsx-explore`, dan stap voor stap `opsx-new` en `opsx-continue`.
+- **Nieuw met de workflow?** → `opsx-onboard` neemt je mee door één volledige cyclus.
+- **Legacy code zonder specs?** → `opsx-coverage-scan` → `opsx-reverse-spec` / `opsx-annotate`.
+- **Change is geschreven, wil je hem lokaal laten bouwen zonder de hele fabriek?** → `opsx-apply-loop` (één change) of `opsx-pipeline` (meerdere parallel).
+- **Binnen de fabriek** wordt geen van deze bij naam aangeroepen: de build-prompt van de flow implementeert de change direct. De opsx-skills zijn voorbereiding door mensen en lokaal gereedschap.
-| Gate-skill | Wat hij detecteert |
-|---|---|
-| `hydra-gates` (dispatcher) | Roept alle 14 gates achter elkaar aan, levert pass/fail-overzicht. |
-| `hydra-gate-spdx` | Ontbrekende `@license`/`@copyright`-headers op PHP/Vue-files. |
-| `hydra-gate-forbidden-patterns` | Debug-calls (`var_dump`, `console.log`), TODO's in productiecode, hardcoded secrets. |
-| `hydra-gate-stub-scan` | Stub-methods die `return null;` of niets doen — geen test, geen logica. |
-| `hydra-gate-composer-audit` | `composer audit` met kwetsbaarheden in afhankelijkheden. |
-| `hydra-gate-route-auth` | `routes.php` zonder auth-attribuut waar dat hoort. |
-| `hydra-gate-orphan-auth` | Auth-checks in methodes die nergens aangeroepen worden (verlaten). |
-| `hydra-gate-no-admin-idor` | `Application::APP_ID` ontbreekt bij admin-only methodes → IDOR-risico. |
-| `hydra-gate-unsafe-auth-resolver` | `catch(\Throwable) { return null; }` rond auth-logica. |
-| `hydra-gate-semantic-auth` | `#[NoAdminRequired]` op een methode die toch `requireAdmin()` aanroept. |
-| `hydra-gate-admin-router` | Admin-routes die niet via de admin-router lopen. |
-| `hydra-gate-initial-state` | Frontend `initialState` zonder serverside hydration. |
-| `hydra-gate-modal-isolation` | Vue-modals die buiten hun container teleporteren. |
-| `hydra-gate-nc-input-labels` | Nextcloud-input-components zonder gekoppeld label (a11y). |
-
-Alle 14 draaien **🤖 in de Hydra-fabriek** (Reviewer + Security containers; Builder voert ze óók uit als post-flight check tijdens fix-quality).
+### Familie 2: Quality + security gates (`hydra-gate-*`)
+
+De parent-skill **`hydra-gates`** draait de hele suite via `scripts/run-hydra-gates.sh` en vat de failures samen. De gate-logica zelf zit in het package `conduction/hydra-gates`, waar dat script naar doorverwijst; de skill-files per gate dienen Claude als naslag bij het fixen van een failure. Er zijn meer gates dan gate-skills, en de nummering (vandaag tot gate-116) heeft gaten.
+
+In plaats van hier een tabel over te nemen: de gates worden behandeld in [deel 3: Quality gates](/nl/academy/hydra-tutorial-3-quality-gates#categorie-2-hydra-specifieke-gates). Voor de skill-familie is het genoeg te weten dat de gates grofweg in groepen uiteenvallen:
+
+- **Hygiëne** — `spdx`, `forbidden-patterns`, `stub-scan`, `composer-audit`, `gitignore-then-commit`.
+- **Security & auth** — `route-auth`, `orphan-auth`, `no-admin-idor`, `unsafe-auth-resolver`, `semantic-auth`, `route-reachability`, `csrf-cochange`.
+- **Toegankelijkheid (WCAG 2.2 AA)** — `img-alt`, `button-name`, `form-label-association`, `html-lang`, `skip-link` en meer.
+- **Conduction-conventies & traceerbaarheid** — `initial-state`, `admin-router`, `nc-input-labels`, `modal-isolation`, `dashboard-antipattern`, `redundant-controller`, `notification-dialect`, `manifest-validation`, en de twee traceability-gates `spec-coverage` (gate-16) en `e2e-coverage` (gate-19).
+
+In een flow-run draait de pipeline de suite na de build en opnieuw na de ene fix-ronde, en elke review-stage krijgt de opdracht hem te draaien. Levert een nieuw incident een nieuwe gate op, dan komt die erbij en groeit het aantal — vertrouw dus de COVERAGE-regel van de run, niet een hard getal in een doc.
### Familie 3: Team-rollen (`team-*`, 7 skills) — **alleen ⌨️ voor mensen**
Skills die een specifiek soort werk modelleren via een persona-frame. Bedoeld voor een mens die naast Hydra in een terminal werkt en even één rol wil invullen.
- `team-po` (Product Owner) — schrijft user stories en acceptatiecriteria.
-- `team-sm` (Scrum Master) — beheert backlog en sprint-planning artefacten.
+- `team-sm` (Scrum Master) — beheert backlog en sprint-planning-artefacten.
- `team-architect` — neemt architectuurbeslissingen, schrijft ADR-drafts.
- `team-backend` — implementeert backend-werk (PHP, services, mappers).
- `team-frontend` — implementeert frontend-werk (Vue 2, Pinia, NL Design System).
- `team-reviewer` — een handmatige variant van het reviewer-werk.
- `team-qa` — schrijft testcases en testplannen.
-Geen van deze staat in een pipeline-container — ze hebben geen plek in de automatische loop.
+De builder-image draagt ze alleen mee omdat hij de hele map kopieert; niets in de automatische loop roept ze aan.
-### Familie 4: Test-suites (`test-*`, 19 skills) — bijna allemaal ⌨️ voor mensen
+### Familie 4: Test-suites (`test-*`) — allemaal ⌨️ voor mensen
-De grootste familie qua aantal: rond de twintig skills die agentic browser- en API-testen drijven, in drie clusters:
+Na de gates de grootste familie: skills die agentic browser- en API-testen aansturen, in drie clusters:
**Test-types** (één per test-soort):
- `test-app` — automatische browsertest van een hele Nextcloud-app (Playwright MCP).
- `test-functional` — functionele scenario's tegen geïmplementeerde features.
-- `test-api` — API-checks tegen de PHP built-in server.
+- `test-api` — API-checks (REST, NLGov-conventies).
- `test-accessibility`, `test-performance`, `test-security`, `test-regression` — gespecialiseerde varianten.
-**Personas** (`test-persona-*`) — acht Nederlandse gebruikersprofielen die elk een eigen blik op een app werpen: `annemarie`, `fatima`, `henk`, `janwillem`, `mark`, `noor`, `priya`, `sem`. Henk leest met grote letters en zoekt eenvoudige navigatie; Noor hamert op RBAC en audit-trails; Annemarie controleert NLGov/GEMMA-mapping. De persona-cards zelf liggen in [`hydra/personas/`](https://github.com/ConductionNL/hydra/tree/main/personas).
+**Personas** (`test-persona-*`) — negen Nederlandse gebruikersprofielen die elk een eigen blik op een app werpen: `annemarie`, `fatima`, `henk`, `janwillem`, `jasper`, `mark`, `noor`, `priya`, `sem`. Jasper gebruikt een schermlezer als zijn primaire ingang; Henk leest met grote letters en zoekt eenvoudige navigatie; Noor hamert op RBAC en audit-trails; Annemarie controleert NLGov/GEMMA-mapping. De persona-cards zelf liggen in [`hydra/personas/`](https://github.com/ConductionNL/hydra/tree/main/personas).
+
+**Scenario-management** — `test-scenario-create`, `test-scenario-edit`, `test-scenario-run` schrijven, bewerken en draaien herbruikbare `TS-NNN-*.md`-scenario's per app.
+
+De dispatcher van deze familie is **`test-counsel`**: hij coördineert alle negen personas tegen één feature en levert een gecombineerd rapport. Zelfde patroon als `hydra-gates` voor de quality-gates-familie.
-**Scenario-management** — `test-scenario-create`, `test-scenario-edit`, `test-scenario-run` schrijven, bewerken en draaien herbruikbare `TS-NNN-*.md` scenario's per app.
+:::note Drie dingen die naar browsertesten klinken — houd ze uit elkaar
+Er zijn drie losse "test"-oppervlakken en ze zijn makkelijk te verwarren:
-De dispatcher van deze familie is **`test-counsel`**: hij coördineert alle acht personas tegen één feature en levert een gecombineerd rapport. Zelfde patroon als `hydra-gates` voor de quality-gates familie.
+1. **`scripts/run-browser-tests.sh`** — een script dat via Playwright MCP inlogt op een draaiende app, de acceptatiecriteria van de spec afloopt en een verdict-JSON teruggeeft. Het is *runtime*-bewijs dat de feature werkt, maar alleen als jij het draait: geen enkele flow roept het aan, dus een pipeline-run levert geen browserbewijs op.
+2. **gate-19 (`e2e-coverage`)** — een *statische* gate uit [deel 3](/nl/academy/hydra-tutorial-3-quality-gates). Hij draait helemaal geen browser; hij controleert dat elk spec-scenario via een `@e2e`-annotatie aan een Playwright-test *gekoppeld* is. Coverage-boekhouding, geen uitvoering.
+3. **De `test-*`-familie** — testsuites die jij met de hand draait, vóór of na de pipeline.
-:::note Geen overlap met de fabriek's browser-tester
-De Hydra-fabriek heeft een **eigen** browser-tester (`hydra-ui-test`) die in de Browser UI Tester-stap draait. Die staat **los** van deze `test-*` familie. De `test-*` skills zijn voor wanneer jij — als mens — een feature wilt testen voordat of nadat de pipeline 'm heeft aangeraakt. Gates uit deel 3 draaien statische checks (regex/AST); `test-*` draait de echte applicatie in een browser.
+Dus: gate-19 controleert dat de *koppelingen* bestaan en draait in de pipeline; het browser-script en de `test-*`-skills *besturen* echt een browser, en die start jij allebei zelf. Verschillende taken.
:::
-### Familie 5: Utility & maintenance (~13 skills) — vrijwel allemaal ⌨️ voor mensen
+### Familie 5: Utility & maintenance — allemaal ⌨️ voor mensen
-De rest, dat is de overige ~13 skills. Vooral dev-comfort en meta-werk:
+Al het overige. Vooral dev-comfort en meta-werk; een selectie:
| Skill | Doet |
|---|---|
| `create-pr` | Maakt een PR vanuit een feature-branch — local checks → branch pick → PR-tekst. |
-| `review-pr` | Reviewt een GitHub PR (NB: handmatige variant; de fabriek heeft zijn eigen Juan Claude). |
-| `report-out` | End-of-day rapport: vandaag's commits + GitHub-activiteit → Nederlandse Slack-melding. |
-| `clean-env` | Reset de lokale Docker-dev-omgeving volledig. |
-| `local-run` | Lokale Nextcloud-dev-omgeving opstarten. |
+| `review-pr` | Reviewt een PR (NB: handmatige variant; de fabriek heeft zijn eigen Juan Claude). |
+| `report-out` | End-of-day-rapport: de commits van vandaag + GitHub-activiteit → Nederlandse Slack-melding. |
+| `clean-env` | Reset de lokale OpenRegister-dev-omgeving (stoppen, volumes weg, herstarten, apps installeren). |
+| `local-run` | Draait builder → reviewer → security lokaal op een wegwerp-repo; vanuit Claude Code doet hij wat `smoke-test.sh` doet (deel 5). |
| `sync-docs` | Sync `{app}/docs/` of `.github/docs/claude/` met de werkelijkheid in de repo. |
| `skill-creator` | Wizard voor het maken van een nieuwe skill (scaffold, frontmatter, evals). |
-| `feature-counsel` | Pre-build spec-analyse vanuit acht persona-perspectieven (zusje van `test-counsel`). |
-| `persistence-audit` | Audit hoe een app omgaat met data-persistence (objectstore, sessies, etc.). |
+| `feature-counsel` | Pre-build spec-analyse vanuit negen persona-perspectieven (zusje van `test-counsel`). |
+| `persistence-audit` | Audit een codebase of architectuur op persistence-vectoren na een compromittering: OAuth-grants, service accounts, CI/CD-secrets, IdP-trust, audit-trails. |
| `journeydoc-init` / `journeydoc-add-story` / `journeydoc-instrument` | Handmatige instrumentatie + uitbreiding van Journey-docs. |
| `verify-global-settings-version` | Check of `global-settings/VERSION` is opgehoogd na een wijziging. |
-Niets uit deze familie draait in de pipeline. Het zijn jouw dagelijkse `/`-commando's.
+Daarnaast staan er schrijf-skills (`writing`, `blog-write`, `tutorial-write`), de `parity-*`-skills voor capability-matrices tegenover concurrenten, en `atom-design` voor design-system-mocks. Niets uit deze familie draait in de pipeline. Het zijn jouw dagelijkse `/`-commando's.
## Vendor skills (community)
Naast de eigen skills heeft Hydra **vendor skills** onder `hydra/vendor/skills/`:
-- `code-review` — communautaire review-skill van Anthropic. → 🤖 Reviewer container.
-- `trailofbits` — Semgrep-based static-analysis methodologie van Trail of Bits. → 🤖 Security container.
-- `owasp` — OWASP-top-10:2025 + ASVS 5.0-checklists. → 🤖 Security container.
+- `code-review` — communautaire review-skill van Anthropic. → 🤖 Reviewer-container.
+- `trailofbits` — Semgrep-gebaseerde static-analysis-methodologie van Trail of Bits. → 🤖 Security-container.
+- `owasp` — OWASP-top-10:2025 + ASVS 5.0-checklists. → 🤖 Security-container.
-Die drie zitten dus **wél** in de fabriek (containers). Ze worden bij Juan en Clyde geladen voor extra dekking boven op de eigen `hydra-gate-*`. Onderhoud ligt bij externe partijen — updaten gaat door de bron te volgen, niet door zelf te editen.
+Die drie zitten dus **wél** in de reviewer- en security-image; de builder-image heeft er geen van. Ze geven Juan en Clyde extra dekking boven op de eigen `hydra-gate-*`. Onderhoud ligt bij externe partijen — updaten gaat door de bron te volgen, niet door zelf te editen.
## Wanneer schrijf je een nieuwe skill?
@@ -208,15 +217,15 @@ De pragmatische test: schrijf een skill als…
2. **Het is mechanisch beschrijfbaar** — je kunt het in 1-3 alinea's instrueren, zonder dat het ontaardt in "het hangt van de context af".
3. **Een persona of een mens zou er baat bij hebben.** Geen skill schrijven omdat het kan.
-Voor een fout-positieve gate (deel 3): je past de bestaande skill aan, je schrijft geen nieuwe. Voor een nieuw klasse-fout dat je 3x ziet langskomen: ja, daar verdient het een eigen `hydra-gate-*` skill.
+Voor een fout-positieve gate (deel 3): je past de bestaande skill aan, je schrijft geen nieuwe. Voor een nieuwe klasse fout die je 3x ziet langskomen: ja, die verdient een eigen `hydra-gate-*`-skill.
- Hydra heeft een ingebouwde /skill-creator skill die je door het maken van een nieuwe skill leidt: scaffold, frontmatter, eval-harness, performance-meting. Roep hem aan vanuit een Claude-sessie in de hydra-repo om met de juiste structuur te starten in plaats van zelf een mapje op te bouwen. Een uitgewerkte walkthrough vind je in deel 2 van de Claude Skills-leerlijn; meten en evalueren wordt behandeld in deel 3.
+ Hydra heeft een ingebouwde /skill-creator-skill die je door het maken van een nieuwe skill leidt: scaffold, frontmatter, eval-harness, performance-meting. Roep hem aan vanuit een Claude-sessie in de hydra-repo om met de juiste structuur te starten in plaats van zelf een mapje op te bouwen. Een uitgewerkte walkthrough vind je in deel 2 van de Claude Skills-leerlijn; meten en evalueren wordt behandeld in deel 3.
## Test jezelf
-Vier korte vragen om te checken of je dit deel begrepen hebt. Vastgelopen? Klik **Hint**. Curieus naar het antwoord? Klik **Antwoord**.
+Vier korte vragen om te checken of je dit deel begrepen hebt. Vastgelopen? Klik **Hint**. Benieuwd naar het antwoord? Klik **Antwoord**.
@@ -237,9 +246,9 @@ In de frontmatter van een skill zet je:
- `disable-model-invocation: true` — alleen handmatig. Gebruikt voor skills met side-effects (`/opsx-apply`, `/create-pr`).
- `user-invocable: false` — alleen automatisch. Gebruikt voor achtergrondkennis die niet als actie zinvol is.
-- Beide leeg → beide mogen. Default voor de meeste Hydra-skills.
+- Beide leeg → beide mogen. De default voor de meeste Hydra-skills.
-In de Hydra-pipeline gebruiken de containers vooral auto-activatie (Claude pikt zelf de juiste skill op); een mens op de CLI typt meestal expliciet `/`.
+In de Hydra-pipeline typt niemand een `/`: elke stage krijgt een prompt die zegt wat hij moet doen en welke brief hij volgt, en elke skill die hij daarnaast laadt is Claude's eigen keuze. Een mens op de CLI typt meestal expliciet `/`.
@@ -247,34 +256,38 @@ In de Hydra-pipeline gebruiken de containers vooral auto-activatie (Claude pikt
-**2. Welke skills draaien er nou écht in de pipeline-containers, en welke staan alleen in de repo voor mensen?**
+**2. Wat gebruikt de automatische pipeline echt, welke skills dragen de container-images mee, en welke staan alleen in de repo voor mensen?**
-Drie containers (Builder, Reviewer, Security) hebben elk een specifieke set in hun image. Wat zit erin — en welke families staan er volledig buiten?
+Houd de flow-gedreven run (prompt, brief, gate-suite) apart van de images die je zelf start. Wat draagt elke image mee — en welke families staan er volledig buiten?
-**In de pipeline-containers** (🤖 fabriek):
+**In een flow-gedreven run** (🤖 fabriek) volgt een stage zijn prompt en brief:
+
+- **Build** — de prompt vraagt de change direct te implementeren; er wordt geen skill genoemd. Daarna draait de pipeline `scripts/run-hydra-gates.sh`, staat één fix-ronde toe, en draait de gates opnieuw.
+- **Review-stages** — elke persona leest zijn brief uit `agents//` en `images/`, draait de gates, en moet `hydra-gates` in `checks_run` zetten.
+
+**In de container-images** (wat `dev-run.sh` en `smoke-test.sh` starten):
-- **Builder** — alle `.claude/skills/*` ingebakken, maar de standaard-run is `opsx-apply`. De andere opsx-skills zijn er voor context.
-- **Reviewer** — `hydra-gates` + 13 individuele `hydra-gate-*` + vendor `code-review`.
-- **Security** — `hydra-gates` + 13 individuele `hydra-gate-*` + vendor `trailofbits` + vendor `owasp`.
-- **Applier** — géén skills (puur CLAUDE.md).
-- **Browser UI Tester** — alleen `hydra-ui-test`.
+- **Builder** — alle skills uit `.claude/skills/`, geen vendor skills. Zijn entrypoint volgt `opsx-apply`.
+- **Reviewer** — `hydra-gates` + 16 losse `hydra-gate-*` + vendor `code-review`.
+- **Security** — `hydra-gates` + dezelfde 16 `hydra-gate-*` + vendor `trailofbits` (Semgrep) + vendor `owasp`.
+- **Applier** — geen skills, alleen Read en Bash.
-Plus: `scripts/run-hydra-gates.sh` draait alle **14** gates mechanisch in elke container, ongeacht welke skill-files in de image staan.
+Wat de image ook meedraagt, `scripts/run-hydra-gates.sh` doet de detectie. Het declareert veel meer gates dan er gate-skills zijn; de COVERAGE-regel van de run zegt hoeveel.
-**Niet in de fabriek**, alleen voor mensen op de CLI:
+**Niet gebruikt door de fabriek** (sommige staan wel in de builder-image, maar geen stage roept ze aan), alleen voor mensen op de CLI:
-- Vrijwel de hele `team-*` familie (7 skills).
-- Vrijwel de hele `test-*` familie (19 skills) — de fabriek heeft zijn eigen `hydra-ui-test`.
-- De meeste `opsx-*` skills behalve `opsx-apply`/`verify`/`archive` (humans starten changes; de pipeline implementeert ze).
-- De hele utility-familie (`create-pr`, `review-pr`, `report-out`, `clean-env`, `sync-docs`, `skill-creator`, `feature-counsel`, `persistence-audit`, `journeydoc-*`, `verify-global-settings-version`).
+- De hele `team-*`-familie.
+- De hele `test-*`-familie — de pipeline draait helemaal geen browser.
+- De `opsx-*`-skills (mensen bereiden changes voor; de pipeline bouwt ze).
+- De hele utility-familie (`create-pr`, `review-pr`, `report-out`, `clean-env`, `local-run`, `sync-docs`, `skill-creator`, `feature-counsel`, `persistence-audit`, `journeydoc-*`, `verify-global-settings-version`, en de schrijf- en parity-skills).
-In totaal: van ~70 skills in de repo gebruikt de automatische pipeline er een handvol; de rest is jouw gereedschap.
+In totaal: van de zo'n 130 skills in de repo leunt de automatische pipeline op de gate-suite en één brief per persona; de rest is jouw gereedschap.
@@ -286,16 +299,16 @@ In totaal: van ~70 skills in de repo gebruikt de automatische pipeline er een ha
-Eén beslissing gaat over "de gate doet niet wat we al wilden". De ander over "we hebben een nieuwe categorie fout ontdekt".
+Eén beslissing gaat over "de gate doet niet wat we al wilden". De andere over "we hebben een nieuwe categorie fout ontdekt".
-- **Bestaande aanpassen** bij een **fout-positief**: de gate triggert te breed of te smal op iets dat al bedoeld werd te checken. Voorbeeld: `hydra-gate-forbidden-patterns` matchte `$builder->add(` ten onrechte — je past de regex aan, je voegt geen tweede gate toe.
-- **Nieuwe schrijven** voor een **nieuw klasse-fout** dat je 3× ziet langskomen en dat door alle bestaande mazen heen glipt. Voorbeeld: `hydra-gate-stub-scan` ontstond toen een builder een `return null;`-methode oplevert die PHPCS slikte en geen test had — dat was een nieuwe categorie, niet een fix op een bestaande check.
+- **Bestaande aanpassen** bij een **fout-positief**: de gate triggert te breed of te smal op iets dat hij al hoorde te checken. Voorbeeld: `hydra-gate-forbidden-patterns` matchte `$builder->add(` ten onrechte — je past de regex aan, je voegt geen tweede gate toe.
+- **Nieuwe schrijven** voor een **nieuwe klasse fout** die je 3× ziet langskomen en die door alle bestaande mazen glipt. Voorbeeld: `hydra-gate-stub-scan` ontstond toen een builder een `return null;`-methode opleverde die PHPCS slikte en geen test had — dat was een nieuwe categorie, geen fix op een bestaande check.
-Rule of three: één keer is toeval, twee keer toeval, drie keer is een patroon dat een eigen gate verdient.
+Rule of three: één keer is toeval, twee keer is toeval, drie keer is een patroon dat een eigen gate verdient.
@@ -307,13 +320,13 @@ Rule of three: één keer is toeval, twee keer toeval, drie keer is een patroon
-Denk aan herkomst (wie heeft ze geschreven?), bij welke pipeline-container ze worden ingeladen, en wat er gebeurt als je een externe partij hun werk moet updaten.
+Denk aan herkomst (wie heeft ze geschreven?), in welke pipeline-image ze worden ingeladen, en wat er gebeurt als een externe partij hun werk moet updaten.
-Vendor-skills (`hydra/vendor/skills/`) zijn skills die **niet door ons** zijn geschreven, en zitten **wél** in de fabriek:
+Vendor-skills (`hydra/vendor/skills/`) zijn skills die **niet door ons** zijn geschreven, en die **wél** in de reviewer- en security-image zitten:
- `code-review` (Anthropic-community) → Reviewer-container (Juan Claude).
- `trailofbits` (Trail of Bits, Semgrep-methodologie) → Security-container (Clyde).
@@ -328,11 +341,11 @@ Apart houden omdat:
-
+
# uit `claude setup-token`; of ANTHROPIC
Er is geen credentials-bestand. `scripts/lib/env-credentials.sh` is de enige resolver, en die faalt dicht: ontbreekt een variabele, dan stopt het script met een reden, in plaats van een run te starten die drie seconden later sneuvelt op een 401. De scripts geven beide waarden aan de containers door op variabelenaam (`-e GH_TOKEN`), zodat de waarden nooit in de proceslijst of in een bestand terechtkomen.
- Een Claude Max- of Pro-abonnement is persoonlijk: het mag je eigen werk draaien, niet dat van een organisatie. Lokaal regelt dat zichzelf, omdat het script onder jouw shell met jouw token draait. In de pijplijn weigeren de flows een stage waarvan de eigenaar niet vast te stellen is. Deel 7 legt uit hoe.
+ Een Claude Max- of Pro-abonnement is persoonlijk: het mag je eigen werk draaien, niet dat van een organisatie. Lokaal regelt dat zichzelf, omdat het script onder jouw shell met jouw token draait. In de pijplijn komt de eigenaar van elke stage uit de stap die hem draait, en hydra-record-stage weigert een stage zonder eigenaar vast te leggen. Deel 7 vertelt meer.
:::note Oudere setups
@@ -80,9 +80,9 @@ HYDRA_IMAGE_TAG=test
HYDRA_REVIEW_SCOPE=diff
```
-`HYDRA_FORGE=github` is goed voor elke ConductionNL-repo; `forgejo` is alleen voor een klant die een eigen Forgejo draait. Er is geen default, omdat een forge raden betekent dat je je token naar een derde partij stuurt. Begin je vanaf `secrets/.env.example`, controleer dan die regel: oudere versies zetten hem op `codeberg`.
+`HYDRA_FORGE=github` is goed voor elke ConductionNL-repo; `forgejo` is alleen voor een klant die een eigen Forgejo draait. Er is geen default, omdat een forge raden betekent dat je je token naar een derde partij stuurt. `secrets/.env.example` zet hem op `github`; heb je een ouder voorbeeld gekopieerd, controleer dan die regel, want oudere versies zetten hem op `codeberg`.
-Tip: de image-defaults zijn `ghcr.io/conductionnl/hydra` als prefix en `latest` als tag. Laat `HYDRA_IMAGE_*` weg om de gepubliceerde images te gebruiken.
+Tip: de scripts die `HYDRA_IMAGE_*` lezen (`manual-review.sh`, `cron-audit.sh`, `cron-spec-from-issue.sh`) vallen terug op `localhost/hydra` en `test` als de variabelen leeg zijn, en `dev-run.sh` start altijd `localhost/hydra-:test`, wat je ook instelt. Lokaal bouw je de images dus zelf (stap 4), of je pullt een gepubliceerde `ghcr.io/conductionnl/hydra-`-image en tagt die onder de lokale naam.
:::tip secrets/.env wordt automatisch geladen
`scripts/dev-run.sh` weigert te starten zonder dit bestand en laadt het zelf, net als `reconcile.sh` en de `cron-*.sh`-sweeps. Een tijd lang controleerde `dev-run.sh` alleen óf het bestand bestond en laadde het nooit, waardoor `HYDRA_FORGE=github` ingesteld leek terwijl elke container nog met Codeberg praatte ([hydra#391](https://github.com/ConductionNL/hydra/issues/391)). Elk entrypoint dat configuratie leest MOET dit bestand bij opstart sourcen; dat is een repo-breed contract.
@@ -90,7 +90,7 @@ Tip: de image-defaults zijn `ghcr.io/conductionnl/hydra` als prefix en `latest`
## Stap 4: build de container images
-In CI pusht GitHub Actions alle images naar GHCR. Lokaal, met `HYDRA_IMAGE_PREFIX=localhost/hydra`, bouw je ze zelf:
+In CI bouwt de workflow `hydra-image.yml` de base-, builder-, reviewer- en security-image en pusht ze naar GHCR als `ghcr.io/conductionnl/hydra-*`. Lokaal bouw je ze zelf, onder de namen waar de scripts naar zoeken:
```bash
# Base image: Nextcloud + PostgreSQL + OpenRegister (builder-dependency)
@@ -106,7 +106,7 @@ docker build -t localhost/hydra-security:test -f images/security/Dockerfile .
docker network create hydra-net
```
-Controleer daarna met `docker images | grep hydra` dat de drie tags er staan. Reviewer en security zijn standalone (geen NC-dependency); de builder bouwt op de `hydra-nextcloud-test`-base.
+Controleer daarna met `docker images | grep hydra` dat de drie tags er staan. Reviewer en security zijn standalone (geen NC-dependency). De builder kopieert de Nextcloud-boom en de database uit `ghcr.io/conductionnl/hydra-nextcloud-test:stable32` met `COPY --from`, dus die image moet onder precies die naam bestaan voordat je de builder bouwt.
## Stap 5: draai één stage met `dev-run.sh`
@@ -143,21 +143,24 @@ Het script hernoemt een oudere `todo-app` naar `todo-app-runN`, maakt een verse
## Stap 7: een echte run op een doel-app
-Op een echte app start je zelf geen containers. Je zet het trigger-label op het tracking-issue en de flows doen de rest:
+Op een echte app start je zelf geen containers. Je zet het trigger-label **`build:queued`** op het issue en de flows doen de rest. Eerst moeten twee dingen kloppen:
-- Het trigger-label `ready-to-build`.
-- Optioneel `yolo`, als de PR mag auto-mergen zodra alles groen is.
-- Optioneel `openspec` als je via OpenSpec werkt.
+- De **body** van het issue noemt de change als pad, `openspec/changes/`. De sequencer neemt het eerste zulke pad dat hij vindt. Geen pad betekent `build:blocked`.
+- Die change-map bestaat op de base-branch: `development` als de repo die heeft, anders de default branch. Zo niet, dan wordt het ook `build:blocked`.
-Via de Hydra-helper:
+Zet daarna het label via de Hydra-helper:
```bash
-./scripts/hydra-label.sh ConductionNL/ add ready-to-build
+./scripts/hydra-label.sh ConductionNL/ add build:queued
```
`scripts/hydra-label.sh` is het **preferred path**: het gebruikt de label-helpers uit `scripts/lib/labels.sh` en synct het GitHub Project board realtime. Een directe `gh issue edit --add-label` werkt ook, maar dan blijft het board in de oude kolom staan tot reconcile (elke 10 minuten) het oppikt.
-De `hydra-dispatch`-flow vindt het label bij zijn volgende tik van vijf minuten en geeft het issue door aan `hydra-sequencer`. De definitie wordt geleverd met `enabled: false`, dus dit gebeurt alleen op een OpenRegister-instantie waar de flow aangezet is. Deel 7 behandelt die opzet.
+De flow `hydra-sequencer` vindt het label bij een van zijn tikken van vijf minuten. Elke tik zoekt hij in de org naar open issues met een queued-label en doet hij één stuk werk; review-labels gaan vóór `build:queued`, dus bij een volle wachtrij kan het een paar tikken duren voor jouw issue aan de beurt is. De definitie wordt geleverd met `enabled: false`, dus dit gebeurt alleen op een OpenRegister-instantie waar de flow aangezet is. Deel 7 behandelt die opzet.
+
+:::note ready-to-build en yolo
+Oudere versies van dit deel gebruikten `ready-to-build` als trigger en `yolo` voor een auto-merge. `create-labels.sh` maakt beide labels nog aan, maar geen enkele flow leest ze. De trigger is `build:queued`, en er wordt niets automatisch gemerged.
+:::
Eerdere versies van dit deel besteedden een hele stap aan HYDRA_LABEL_PREFIX. Die gaf de lokale supervisor van elke developer een eigen label-namespace (wilco-build:queued), zodat twee supervisors op dezelfde repo elkaars werk niet oppakten. De supervisor is weg, en de flows zijn het enige dat nog werk oppakt. Die reageren alleen op de kale labels. De shell-tooling (create-labels.sh --prefix, hydra-label.sh, reconcile.sh) kent de variabele nog, maar geen enkele flow pakt een geprefixt label op. Laat hem leeg.
@@ -165,23 +168,32 @@ De `hydra-dispatch`-flow vindt het label bij zijn volgende tik van vijf minuten
## Stap 8: volg de pijplijn
-Zodra de sequencer het issue heeft, gebeurt dit:
+Zodra de sequencer het issue heeft, bewegen de labels zo:
```
-ready-to-build → build:queued → build:running → build:pass
- ↳ code-review:queued → :running → :pass / :fail
- ↳ security-review:queued → :running → :pass / :fail
- ↳ applier:queued → :running → :pass / :fail → done / needs-input
+build:queued → build:pass | build:fail | build:no-change | build:blocked
+ (bij pass en bij fail wordt een PR geopend; die wordt nooit gemerged)
+
+build:pass → jij zet zelf code-review:queued
+
+code-review:queued → code-review:pass (+ security-review:queued) | code-review:fail | needs-input
+security-review:queued → security-review:pass (+ applier:queued) | security-review:fail | needs-input
+applier:queued → applier:pass | applier:fail | needs-input
```
-Je volgt het op twee plekken:
+Een paar dingen die je makkelijk verwacht en die niet gebeuren:
+
+- **Niets zet code review in de wachtrij na `build:pass`.** Doe dat zelf: `./scripts/hydra-label.sh ConductionNL/ add code-review:queued`.
+- **Er zijn geen `:running`-labels.** Terwijl een stage draait, blijft zijn `:queued`-label op het issue staan en markeert een lock het issue als onderhanden.
+- **Een `fail` stopt de keten.** Een afgekeurde code review gaat niet door naar security review.
+- **`applier:pass` is het eind.** Er is geen `done`-label en geen merge; een mens merget de PR.
-1. **GitHub issue**: de labels veranderen terwijl de sequencer de stages doorloopt.
-2. **GitHub PR**: de commits van de builder en de inline comments van de reviewers.
+Je volgt het op twee plekken:
-Achter beide wordt elke stage vastgelegd in `openspec/changes//hydra.json`, voordat het label verschuift. Deel 6 laat zien hoe je dat bestand leest. De flow-runs zelf leven in OpenRegister; er is geen logbestand op je machine om te tailen.
+1. **GitHub issue**: de labels veranderen terwijl de sequencer de stages doorloopt. De sequencer schrijft die labels zelf, dus de kaart op het project-board volgt niet meteen; `reconcile.sh` verplaatst hem bij zijn volgende sweep.
+2. **GitHub PR**: de build-commit op `feature//hydra-build`, met de gate-output in de PR-body. Elke review-stage schrijft zijn verdict naar een bestand `hydra-verdict.json`, dat de sequencer bij de volgende tik ophaalt; dat verdict verschuift de labels.
-`yolo` gezet en alles groen? Dan zie je op het issue `done` verschijnen, op de PR een approve en een auto-merge. Geen `yolo`? Dan staat de PR klaar voor een mens om te mergen.
+Achter beide legt de sequencer, nadat de labels van een stage verschoven zijn, de stage vast in `openspec/changes//hydra.json` via de flow `hydra-record-stage`, die een stage zonder eigenaar weigert. Deel 6 laat zien hoe je dat bestand leest. De flow-runs zelf leven in OpenRegister; er is geen logbestand op je machine om te tailen.
## Troubleshooting
@@ -195,17 +207,20 @@ Achter beide wordt elke stage vastgelegd in `openspec/changes//hydra.json`
Zet HYDRA_FORGE=github in secrets/.env. De weigering is bewust: zonder die regel zou Hydra moeten raden waar je token heen moet.
-
- Controleer dat secrets/.env daadwerkelijk HYDRA_IMAGE_PREFIX=localhost/hydra en HYDRA_IMAGE_TAG=test bevat, en dat de tags uit stap 4 overeenkomen.
+
+ dev-run.sh gebruikt altijd localhost/hydra-<stage>:test en negeert HYDRA_IMAGE_*, dus bouw met precies die tags. Bij manual-review.sh en de cron-scripts: controleer waar HYDRA_IMAGE_PREFIX en HYDRA_IMAGE_TAG in secrets/.env op uitkomen; leeg betekenen ze localhost/hydra en test.
- docker images | grep hydra-builder. Geen treffer? Bouw eerst de base image (hydra-nextcloud-test) en daarna pas de builder. De builder-Dockerfile heeft de base als FROM. Een fout network hydra-net not found betekent dat je de laatste regel van stap 4 hebt overgeslagen.
+ docker images | grep hydra-builder. Geen treffer? Bouw eerst de base image (hydra-nextcloud-test) en daarna pas de builder. De builder-Dockerfile kopieert uit de base met COPY --from, dus de base moet bestaan onder de naam ghcr.io/conductionnl/hydra-nextcloud-test:stable32. Een fout network hydra-net not found betekent dat je de laatste regel van stap 4 hebt overgeslagen.
- Niets op je machine let op labels. Op een echte app moet de hydra-dispatch-flow aangezet zijn in de OpenRegister-instantie (deel 7). Wil je lokaal een stage proberen, gebruik dan dev-run.sh uit stap 5.
+ Niets op je machine let op labels. Op een echte app moet de flow hydra-sequencer aangezet zijn in de OpenRegister-instantie (deel 7). Controleer ook de exacte naam van het label: met HYDRA_LABEL_PREFIX gezet schrijft hydra-label.sh <prefix>-build:queued, en dat leest geen enkele flow. En de sequencer doet één stuk werk per tik, review-stages eerst, dus een volle wachtrij vertraagt je build. Wil je lokaal een stage proberen, gebruik dan dev-run.sh uit stap 5.
+
+
+ De sequencer kon de change niet vinden. De body van het issue moet openspec/changes/<naam> bevatten, en die map moet bestaan op development (of op de default branch, als de repo geen development heeft). Pas de body aan of push de change, haal dan build:blocked weg en zet build:queued opnieuw.
-
- Stale labels van een vorige run blijven hangen. Strip de oude stage-labels met ./scripts/hydra-label.sh ConductionNL/<app> <N> transition ready-to-build. Dat zet het issue terug in een gedefinieerde starttoestand.
+
+ Er staan nog review-labels van een vorige run op het issue, en die pakt de sequencer vóór build:queued. Zet het issue terug met ./scripts/hydra-label.sh ConductionNL/<app> <N> transition build:queued: dat haalt alle andere queued-labels, needs-input en het oude build-verdict in één keer weg, en laat alleen build:queued staan als starttoestand.
@@ -291,7 +306,7 @@ Wat laat een run achter als er geen flow bij betrokken is?
- De drie typische oorzaken van een vastgelopen pijplijn: stale dependencies, terechte review-findings, en fundamenteel verkeerde build-aanpak.
- De interventie-ladder: development-merge → review-labels resetten → retry:queued → rebuild:queued → handmatige fix.
- Waarom needs-input NIET hetzelfde is als "Hydra is kapot".
- Waar je de retrospectives vindt en hoe je terugkerende patronen herkent.
+ Wat elke uitkomst betekent: de vier build-resultaten, en needs-input, dat alleen een review-stage zet.
+ De interventie-ladder: verouderde PR bijwerken → review-stage (opnieuw) in de wachtrij → een needs-input-stage vrijmaken → de build opnieuw in de wachtrij → handmatige fix.
+ Waarom retry:queued en rebuild:queued vandaag niets doen.
+ Waar je kijkt als iets vastzit, en hoe je terugkerende patronen herkent.
Deel 1 t/m 5 doorgenomen.
- Een mentaal model van het label-state-machine (uit deel 2).
+ Een beeld van de label-volgorde uit stap 8 van deel 5.
-## Wat betekent `needs-input`?
+## Wat betekenen de uitkomsten?
-`needs-input` is **geen failure-state in de zin van "Hydra heeft gefaald"**. Het is een expliciete escalatie: Hydra heeft gedaan wat hij kon, één run, en is tot een terminaal punt gekomen waar hij niet zelf verder kan zonder een menselijke beslissing.
+De twee banen van `hydra-sequencer` eindigen verschillend, en het helpt om ze uit elkaar te houden.
-Mogelijke oorzaken:
+**De build-baan** eindigt in een van vier labels. Geen daarvan is `needs-input`:
-- Beide reviewers `pass` maar de quality-recheck na hun fixes is rood (een fix introduceerde een nieuwe overtreding).
-- Eén van beide reviews `:fail`.
-- Applier Axel Pliér `:fail`.
-- Build crashed mid-stage (container OOM, rate-limit op alle accounts, …).
-- Agent-maxed-out: een persona heeft zijn turn-budget opgemaakt.
+| Label | Wat er gebeurde | Is er een PR? |
+|---|---|---|
+| `build:pass` | De gates waren groen, meteen of na de ene fix-ronde. | Ja |
+| `build:fail` | De gates waren na de ene fix-ronde nog rood. | Ja, met de gate-output in de body |
+| `build:no-change` | De agent veranderde niets, dus er viel niets te pushen. | Nee |
+| `build:blocked` | De body van het issue noemt geen `openspec/changes/`, die change bestaat niet op de base-branch, of de build kon niet draaien. | Nee |
-Je rol als mens: bepaal welke van de vier opties hieronder het meest passend is en pas die toe. **Niet** een nieuwe `retry:queued` blind plakken in de hoop dat het deze keer wel werkt.
+**De review-baan** (code review → security review → applier) sluit elke stage af met `:pass`, `:fail` of `needs-input`. `needs-input` is **geen oordeel over de code**. Het betekent dat de stage geen bruikbaar verdict opleverde:
+
+- het verdict-bestand `hydra-verdict.json` ontbreekt of is onleesbaar;
+- het verdict noemt geen `hydra-gates` in `checks_run`, dus er is geen bewijs dat de gates gedraaid hebben;
+- de stage kon helemaal niet draaien.
+
+Een `:fail` is wél een echt verdict: de reviewer heeft gekeken en zei nee. Na een `:fail` wordt niets meer in de wachtrij gezet, en na `build:pass` ook niet: `code-review:queued` zet je zelf.
+
+Jouw rol als mens: uitzoeken welke van deze je voor je hebt, en de goedkoopste hendel hieronder kiezen die past.
## De interventie-ladder
-| # | Situatie | Interventie | Kosten | Wat behoud je |
+Elke hendel is een label. Zet het met `scripts/hydra-label.sh`, zodat het project-board meebeweegt.
+
+| # | Situatie | Interventie | Kosten | Wat blijft behouden |
|---|---|---|---|---|
-| 1 | Development is doorgegroeid, PR staat stale (nieuwe lint-rules, ADRs, fixtures op development) | gh pr update-branch <N> (of de cron pakt het op) | Gratis | Alle build/review/applier-werk. Alleen dependencies vernieuwen. |
-| 2 | Review-contracten zijn aangepast en je wilt reviewers opnieuw laten oordelen zonder rebuild | Reviewer-labels resetten: stage-labels strippen, code-review:queued opnieuw zetten. PR blijft. | 2× reviewer + applier | De builder-output. Alleen het review-deel rewindt. |
-| 3 | Reviewers/applier flagden concrete findings en de builder hoeft alleen even bij te schaven | retry:queued op het issue plakken | 1× builder + 2× reviewer + applier | Branch + PR blijven. Orchestrator bouwt feedback.md uit hydra.json (unfixed + applier-blockers + reeds gefixed) en dispatcht builder in HYDRA_MODE=fix. Single-shot — geen loop. |
-| 4 | Builder-output was fundamenteel verkeerd (verkeerde aanpak, stub-implementatie, fundamentele requirements gemist) | rebuild:queued op het issue plakken | Volledige cyclus | Orchestrator sluit de open PR, hard-reset feature/<issue>/* naar development, strip alle cycle-labels, zet build:queued. Volgende cyclus begint van scratch. |
-| 5 | Je hebt zelf de PR al gesloten en stale labels staan nog op het issue | Wachten op reconcile.sh (om de 10 min) | Volgende reconcile-run | check_stage_without_open_pr ziet de inconsistentie en zet automatisch build:queued. Self-healing. |
-| 6 | Pipeline-infra is stuk (container crash, alle tokens op, image niet vindbaar) | Escaleer naar mens (jij of een teamlead), los infra op, en kies pas DAN één van 1-4 hierboven | Tijd | — |
+| 1 | Development is verder gegaan en de PR is verouderd (nieuwe lint-regels, ADR's, fixtures op development) | gh pr update-branch <N>, of wacht op cron-update-prs.sh (elk uur) | Gratis | Alles. Alleen de base wordt bijgewerkt. |
+| 2 | build:pass en nog niemand heeft gereviewd | Zet code-review:queued | Tot drie review-stages | De build. |
+| 3 | Review-contracten zijn aangepast, of een review moet opnieuw | Haal de :pass/:fail van die stage weg (en needs-input), zet <stage>:queued | Eén tot drie review-stages | De build. Bij een pass zet de sequencer de volgende stage weer in de wachtrij. |
+| 4 | Een review-stage eindigde in needs-input | Haal **eerst** het :queued-label van die stage weg, los de oorzaak op, haal dan needs-input weg en zet :queued opnieuw (zie hieronder) | Eén stage | De build en de eerdere verdicts. |
+| 5 | De build ging mis: build:fail, build:no-change, build:blocked, of een build:pass die toch niet klopt | Haal het build:*-verdict weg, zet build:queued | Een volledige build | Niets van de oude build. De sequencer bouwt opnieuw vanaf de base-branch en pusht feature/<issue>/hydra-build. |
+| 6 | Je hebt de PR zelf gesloten en er staan nog oude labels op het issue | Wacht op reconcile.sh (elke 10 min) | Volgende reconcile-run | check_stage_without_open_pr ziet de inconsistentie en zet build:queued. Herstelt zichzelf. |
+| 7 | De pijplijn-infra is kapot (flow uitgezet, een workload-stap die niet kan starten, een credential die de broker niet kan resolven) | Eerst de infra repareren, en pas DAN een van 1–5 kiezen | Tijd | — |
+
+**Volgorde:** altijd de goedkoopste die past. Grijp alleen naar een nieuwe build als de build zelf fout was; anders gooi je goed werk weg.
+
+### Een review-stage opnieuw in de wachtrij zetten
+
+Stel: de code review is afgekeurd en je vindt dat hij opnieuw moet, omdat een ADR veranderd is of omdat je zelf een fix op de branch hebt gepusht:
+
+```bash
+./scripts/hydra-label.sh ConductionNL/ remove code-review:fail
+./scripts/hydra-label.sh ConductionNL/ add code-review:queued
+```
+
+De sequencer pakt hem op bij een van de volgende tikken. Keurt de review goed, dan zet hij zelf `security-review:queued`, en loopt de keten vanaf daar verder.
+
+### Een review-stage die in `needs-input` eindigde
+
+:::warning Haal eerst het `:queued`-label weg
+Een stage die in `needs-input` eindigt, **houdt zijn `:queued`-label**. De sequencer zoekt alleen op dat label, dus hij pakt de stage bij de volgende tik weer op — elke vijf minuten — tot iemand het weghaalt. Haal het label weg voordat je gaat uitzoeken wat er mis is.
+:::
+
+```bash
+# 1. Stop de herhalingen
+./scripts/hydra-label.sh ConductionNL/ remove security-review:queued
+
+# 2. Los de oorzaak op: gates niet gedraaid, geen verdict-bestand, of een stage die niet kon starten
+
+# 3. Zet hem opnieuw in de wachtrij
+./scripts/hydra-label.sh ConductionNL/ remove needs-input
+./scripts/hydra-label.sh ConductionNL/ add security-review:queued
+```
+
+Geef altijd de **kale** labelnaam mee. Met `HYDRA_LABEL_PREFIX` gezet voegt `hydra-label.sh` de prefix zelf toe, dus `wilco-needs-input` zou `wilco-wilco-needs-input` worden. En omdat de flows alleen kale labels lezen, laat je de prefix sowieso leeg (deel 5).
+
+### De build opnieuw in de wachtrij zetten
+
+```bash
+./scripts/hydra-label.sh ConductionNL/ remove build:fail
+./scripts/hydra-label.sh ConductionNL/ add build:queued
+```
-**Volgorde:** altijd 1 → 2 → 3 → 4. Pak het goedkoopste herstel eerst. Reach voor `rebuild:queued` alleen als de build zelf fundamenteel verkeerd was.
+Vervang `build:fail` door het build-verdict dat op het issue staat. Staan er ook nog oude review-labels op, dan doet `./scripts/hydra-label.sh ConductionNL/ transition build:queued` het in één keer: het haalt alle andere queued-labels, `needs-input` en het oude build-verdict weg, en laat `build:queued` staan.
-### `retry:queued` in detail
+Wat de push doet met een bestaande branch `feature//hydra-build`, en of er een nieuwe PR naast een oude wordt geopend, wordt buiten de flow-definities bepaald. Wil je een schone PR, sluit de oude dan eerst.
-1. Jij (of een automated rule) plakt `retry:queued` op het issue. Met label-prefix wordt dat `-retry:queued` — `scripts/hydra-label.sh` regelt dat automatisch.
-2. Supervisor pakt het op als reguliere queue-job.
-3. Orchestrator vindt de open PR op `feature//*`.
-4. Orchestrator cloned development, kopieert `openspec/changes//hydra.json` en draait `scripts/lib/build-feedback-brief.py` → schrijft `feedback.md` met (a) applier-blockers, (b) unfixed reviewer-findings, (c) reeds-gefixed items, (d) Scope-lijst van alle geflagde files.
-5. Orchestrator flipped `retry:queued` → `retry:running`, dispatcht de builder met `HYDRA_MODE=fix` en `feedback.md` gemount op `/workspace/feedback.md`.
-6. Builder leest de brief, fixed álle bevindingen in één pass, beperkt zich tot Scope-files (plus nieuwe files die expliciet door een blocker geëist worden), commit met `fix (retry):` messages, pusht.
-7. Succes: orchestrator strip alle review/applier-labels + `retry:running` + `needs-input`, zet `code-review:queued`. Reviewers draaien opnieuw tegen de gefixede code.
-8. Faal: `retry:running` → `needs-input`, comment op het issue legt uit waarom en wijst naar `rebuild:queued` als de volgende hefboom.
+### En `retry:queued` en `rebuild:queued`?
-**Geen loop.** Eén `retry:queued` = één iteratie. Als de fix-builder pusht en de volgende review weer faalt, kun je opnieuw `retry:queued` aanvragen — maar dat is dan een **nieuwe** single-shot, niet een auto-retry.
+**Die doen vandaag niets.** Geen enkele flow leest die labels. Eerdere versies van dit deel beschreven wat ze deden onder de uitgefaseerde shell-orchestrator: `retry:queued` stelde uit `hydra.json` een `feedback.md` samen en draaide de builder nog één keer in `HYDRA_MODE=fix`, en `rebuild:queued` sloot de PR en zette de branch hard terug. Die orchestrator is weg, en dat gedrag ook; `scripts/lib/build-feedback-brief.py` heeft geen aanroeper meer.
+
+`create-labels.sh` maakt beide labels nog aan, en `cron-update-prs.sh` zet `rebuild:queued` nog steeds op het issue van een PR met merge-conflicten, samen met een comment. Niets pakt dat label op, dus zie de comment als het signaal: los het conflict op, of zet de build opnieuw in de wachtrij (trede 5).
## Wanneer is het de gate, en wanneer is het de builder?
-Een terugkerende valkuil uit eigen retrospectives: het issue gaat 3 keer naar `needs-input` om dezelfde reden — typisch `spdx-headers: fail` of een gelijksoortige mechanische gate. Iedere `retry:queued` reproduceert hetzelfde patroon.
+Een terugkerende valkuil uit onze eigen retrospectives: hetzelfde issue faalt drie keer op dezelfde mechanische gate — typisch een ontbrekende SPDX-header of een vergelijkbare hygiëne-check. Elke opnieuw gestarte build reproduceert hetzelfde patroon.
-In dat geval is een vierde retry **niet** de juiste move. Wees discplineerd:
+Een vierde build is dan **niet** de juiste zet. Wees gedisciplineerd:
-1. **Sanity-check de gate zelf.** Is dit een fout-positief? (Zie deel 3.) Een klassieker: een grep zonder word-boundary die meer matcht dan bedoeld. Fix in dat geval `scripts/run-quality.sh` of de gate-skill.
-2. **Hand-fix de mechanische overtreding.** Soms is het sneller om zelf de SPDX-headers toe te voegen, te committen op de feature branch en de reviewers opnieuw aan te roepen via label-reset (situatie 2 hierboven). Tijd: minuten.
-3. **Overweeg een sterkere agent.** Als hetzelfde klasse-fout op meerdere repos dezelfde "blind spot" vertoont, is dat een signaal dat de huidige builder-prompt of de mechanische gate niet voldoende is. Open een issue in `hydra/` om de gate aan te scherpen of een "housekeeping"-agent te bouwen.
+1. **Check de gate zelf.** Is dit een fout-positief? (Zie deel 3.) Een klassieker: een grep zonder woordgrens die meer matcht dan bedoeld. De gates zitten in het package `conduction/hydra-gates` (in `ConductionNL/.github`); repareer de gate daar, of zijn skill in `hydra/`.
+2. **Fix de mechanische overtreding met de hand.** Vaak is het sneller om de SPDX-headers zelf toe te voegen, te committen op `feature//hydra-build`, en de code review in de wachtrij te zetten (trede 2 of 3). Tijd: minuten.
+3. **Overweeg een sterkere agent.** Toont dezelfde klasse fout dezelfde blinde vlek in meerdere repo's, dan is dat een signaal dat de build-prompt of de mechanische gate niet volstaat. Open een issue in `hydra/` om de gate of de brief aan te scherpen.
## Watch-list patronen
-Patronen die we al hebben gezien en die het waard zijn om eerst tegen je situatie te leggen:
+Patronen die we al gezien hebben en die het waard zijn om eerst met jouw situatie te vergelijken. De eerste drie komen uit de shell-pijplijn die de flows vervingen; de lessen gelden nog steeds.
- Op decidesk (nu Decidiq) GitHub-issues #44/#71/#72, hetzelfde patroon: builder mist EUPL-1.2 header op nieuwe PHP-files, reviewer claimt 0 fixes nodig, recheck slaat rood. Forbidden-patterns bleek deels fout-positief (grep zonder word-boundary). Fix: handmatig SPDX toegevoegd + grep aangescherpt.
+ Op decidesk (nu Decidiq) GitHub-issues #44/#71/#72 steeds hetzelfde patroon: de builder vergat de EUPL-1.2-header op nieuwe PHP-files, de reviewer claimde dat er 0 fixes nodig waren, de recheck werd rood. Forbidden-patterns bleek deels fout-positief (grep zonder woordgrens). Fix: SPDX met de hand toegevoegd + de grep aangescherpt.
- Vijf onderscheiden pipeline-bugs in één retrospectief. Builder leverde op decidesk (nu Decidiq) GitHub-issues #44/#45 een methode op met return null; + TODO; PHPCS slikte het; geen test; productie-bug. Resulteerde in hydra-gate-stub-scan + ADR-021 (bounded-fix scope op shape, niet op lijntelling). Volledige lessen in decidesk-44-45-phase-g.md.
+ Vijf verschillende pijplijn-bugs in één retrospectief. De builder leverde op decidesk (nu Decidiq) GitHub-issues #44/#45 een methode met return null; + TODO; PHPCS slikte het; geen test; productiebug. Resulteerde in hydra-gate-stub-scan + ADR-021 (bounded-fix-scope op vorm, niet op aantal regels). Alle lessen in decidesk-44-45-phase-g.md.
-
- Completion-handler in een tight loop poste elke tick een nieuwe escalation-comment op een al-terminaal issue. Fix: terminal-state guard vóór alle side-effects (zie CLAUDE.md sectie "Terminal-state guards"). Als jij een issue ziet met >3 identieke needs-input comments: open een infra-bug, niet een retry.
+
+ Een completion-handler in een strakke lus plaatste elke tik een nieuwe escalatie-comment op een issue dat al terminaal was. Fix: een terminal-state guard vóór alle side-effects (zie CLAUDE.md, sectie "Terminal-state guards"). De sequencer heeft zo'n guard vandaag niet: een geblokkeerde review-stage krijgt geen nieuwe comment, maar wordt elke tik opnieuw gedraaid, tot zijn :queued-label weg is. Zie je dezelfde stage steeds weer draaien, haal dat label dan weg en open een infra-issue; zet niets opnieuw in de wachtrij.
## Diagnostics: waar kijk je?
-Snelle checklist als een issue naar `needs-input` gaat:
+Er is geen logbestand op je machine om te tailen. Snelle checklist als een issue vastzit:
```bash
# 1. Welke labels staan er nu?
gh issue view --repo ConductionNL/ --json labels --jq '[.labels[].name]'
-# 2. Wat zegt hydra.json (mits aanwezig op de feature branch)?
-gh api repos/ConductionNL//contents/openspec/changes//hydra.json?ref=feature// \
- --jq '.content' | base64 -d | jq '.cycles[-1] | {outcome, outcome_reason, pattern_tags}'
+# 2. Is er een PR, en wat staat er in de body (gate-output)?
+gh pr list --repo ConductionNL/ --head feature//hydra-build --state all
-# 3. De supervisor-log van de relevante tijdspanne
-grep "issue/" logs/supervisor.log | tail -50
+# 3. Wat zegt hydra.json op de feature-branch over de laatst vastgelegde stage?
+gh api "repos/ConductionNL//contents/openspec/changes//hydra.json?ref=feature//hydra-build" \
+ --jq '.content' | base64 -d | jq '.cycles[-1]'
+```
-# 4. Pipeline-logs (per stage) op de feature branch
-gh api repos/ConductionNL//contents/openspec/changes//pipeline-logs?ref=feature//
+De vierde plek zijn de **flow-runs** van `hydra-sequencer` in de OpenRegister-instantie: elke tik is daar één run. Kijk daar als de labels en `hydra.json` niet verklaren wat er gebeurde — bijvoorbeeld als een stage niet kon starten, of zijn verdict niet gelezen kon worden.
+
+### hydra.json lezen (schema v2)
+
+Nadat de labels van een stage verschoven zijn, roept de sequencer de flow `hydra-record-stage` aan, die een entry toevoegt aan `openspec/changes//hydra.json` op `feature/