deSchouwVloot · de keuzes eronder
Waarom het zo gebouwd is
Het scrollverhaal op /werk/deschouwvloot vertelt hoe de projecten en de gedeelde standaard op elkaar staan. Deze pagina verantwoordt waarom het zo gebouwd is — de controles, de keren dat alles groen stond terwijl het stuk was, en wat er bewust is weggelaten. Elke bewering hieronder is na te trekken in de publieke repo. Nog een laag dieper is de README zelf.
Gemeten, niet verzonnen
De nulmeting vóór dit ontwerp — en waar elk getal mee is opgelost.
Die drie getallen zijn een nulmeting, maar het meten is niet gestopt — en sinds kort blijft een meting ook niet meer in een artifact liggen waar niemand 'm leest. Komt het aandeel geweigerde permissies van een run boven de drempel, dan opent de pijplijn daar zélf een issue over. Dat issue legt vervolgens precies dezelfde weg af als elk ander idee: triage, plannen, bouwen, checks. Van meten naar melden, zonder dat ik in logs hoef te grasduinen om te zien dat er iets structureel scheef staat.
Zeven controles die elke run bewaken
Alle 16 workflows →Alle 16 workflows zijn workflow_call-only, machinaal afgedwongen door een guard-script. Geen issues, geen push, geen schedule — een reusable workflow start nooit vanzelf.
Bekijk in repo →Eén samenhangende invariant-suite — consistentie, permissies, spine, runners, contract, liveness, afhankelijkheden en pin. De doctor rapporteert hard en muteert nooit; mutatie is een bewust gescheiden bevoegdheid.
Bekijk in repo →Third-party actions op SHA, GitHub-eigen actions op major-tag, en fleet-refs sinds de tweede consument aanhaakte niet meer op @main maar op een SHA-pin die 's nachts wordt bijgewerkt. Drie soorten vertrouwen, drie soorten pin.
Bekijk in repo →Bevroren echte gevallen naast de unit-tests, inclusief marge-gevallen die met 2-1 moeten winnen — precies de gevallen waar een testset die alles met 3-0 wint, overheen kijkt.
Bekijk in repo →Bij een eerdere tweede consument groeiden vier gedrifte kopieën — dat kan nu niet meer. Logica leeft precies één keer; een consument krijgt per station een dunne caller, nooit een fork.
Bekijk in repo →Concurrency-groepen op issue of PR, gestandaardiseerd in de workflow-skeletten. Dubbele builds zaten ooit op 30,8% van de runs — dat patroon is nu structureel onmogelijk.
Bekijk in repo →Een feature-PR draagt een codeblok met een vast antwoord per veld — geen vrije tekst. Elk antwoord wordt tegen de daadwerkelijke diff gehouden, dus een verkeerde bewering valt om zonder dat er een mens naar hoeft te kijken.
Bekijk in repo →Groen is geen bewijs
Vier keer stond alles groen terwijl het systeem feitelijk kapot was. De verdediging is telkens hetzelfde principe — meet het gedrag, niet de configuratie — maar het aardigste zit in de volgorde: dat deze faalvorm één keer een naam kreeg, is precies waarom de vierde gericht gevonden werd in plaats van toevallig.
elk geval won met 3-0, dus geen enkel te breed trefwoord kon iets kantelen — de run slaagde voor altijd. Nu moeten grensgevallen met marge 1 winnen.
toch tien uur lang geen enkele run — de complete spine lag plat. Nu wordt gemeten of de bron liep én de luisteraar reageerde, niet alleen of de configuratie klopte.
een station miste een script bij de consument, draaide fail-closed, en mergede per constructie nooit meer. Nu wordt de eis uit de stationsdefinitie zelf afgeleid, niet uit een handlijst die achterloopt.
een doctor-module die de gepinde versie nog niet kent werd netjes overgeslagen, dus een pin die niet opschoof las als groen. Nu maakt doctor:pin achterstand en verdeelde pins een harde bevinding.
Vertrouwensniveaus, geen platte agent
untrusted vs. owner
Untrusted werk (PR- of issue-inhoud van buiten de flow) draait in een sandbox-container zonder docker-daemon en zonder host-mounts, nooit met deploy- of domein-secrets in scope, en nooit via pull_request_target naar een self-hosted runner. Owner-bevoegdheden (host-mutaties, releases, registraties) lopen uitsluitend via een apart, expliciet gelogd kanaal — nooit vanuit een workflow zelf.
publieke kopie · bewuste redactie
De host-diagnostiekworkflow en concrete hostcijfers (RAM, schijf, co-hostende diensten) zijn bewust uit deze publieke kopie gehaald: legitiem gereedschap voor de eigenaar, maar publiek een kant-en-klare doelwitlijst. Security-denken zit ook in wat je niet laat zien.
afgeschaft · drie weken gemeten
Er draaide hier drie weken een autonome AI-review op elke app-/website-PR. Die vond niets dat de deterministische checks hierboven nog niet zagen, kostte wel een schaars agent-slot per PR, en had twee eigen faalmodi die de merge-poort raakten. Afgeschaft — niet omdat AI-review principieel niet werkt, maar omdat déze niet meetbaar bijdroeg. De rem die 'm bij een écht gevonden probleem had tegengehouden blijft wel bestaan: die is losgekoppeld van een specifieke AI-reviewer, dus bruikbaar zodra er ooit een gerichter station voor terugkomt.
de prijs van de eigen regel
Als geen enkele workflow een eigen trigger heeft, draait er in die repo ook niets vanzelf — een workflow die niemand aanroept, start nooit. Alle guards zijn daar dus handwerk, of ze draaien in de context van een project dat ze aanroept. Dat is precies het scherpe randje van "groen is geen bewijs": een testsuite die niemand aftrapt, is een testsuite die altijd hetzelfde antwoordt.
Een veilige trigger erbij zou dat oplossen. Maar "alleen veilige triggers" is nou juist de formulering die ik daar bewust niet hanteer, omdat die weer op een beoordeling per geval leunt in plaats van op iets dat een script kan vaststellen. De keuze is dus: geen triggers, en de prijs zichtbaar opschrijven in plaats van 'm te verstoppen achter een badge.
Vandaag · morgen
De Ubuntu-server praat via OAuth met één gehost model. Er draaien inmiddels vier repo's op de vloot, dus fleet-refs wijzen niet meer naar @main maar naar een SHA-pin die 's nachts wordt bijgewerkt.
Terugkerend werk verschuift naar kleine, lokale workers per taaktype, met het grote model gereserveerd voor architectuur — de plek waar één groot model nog echt verschil maakt.