RFC-033: Het bouwplan van een verrijking

ProposedImplemented
Depends on

Verhouding tot RFC-026

RFC-026 beantwoordt welke knopen meedoen en waar de sluiting ophoudt. Deze RFC beantwoordt in welke volgorde je ze aandoet en wat een venster is. Die tweede vraag heeft een eigen meting en een eigen faalvorm, en RFC-026 draagt hem niet zonder uit elkaar te vallen. De afhankelijkheid loopt één kant op: zonder de afbakening van RFC-026 heeft een volgorde geen begin.

Context

Een verrijkingsrun verwerkt vandaag een venster: de volgende N entries in documentvolgorde, geteld vanaf een cursor. N is een constante uit een omgevingsvariabele. De snede die daaruit volgt heeft niets te maken met wat de wet doet; hij loopt dwars door de afhankelijkheden heen.

Het gevolg is meetbaar. Artikel 1 wordt bezocht terwijl artikel 5 nog geen model heeft. Een binding van 1 naar een output van 5 is daar niet te leggen, want die output bestaat op dat moment niet. Alleen het laatste venster ziet alles wat ervoor staat. Een deel van wat na afloop op de poorten blijft staan is daarom een te vroege meting en geen fout.

Venster als laag

In het bouwplan is een venster een verzameling artikelen waarvan niets van iets anders in diezelfde verzameling afhangt. De omvang volgt uit de wet en niet uit een constante.

laag 1: art 1 laag 2: art 2, 3, 5 laag 3: art 7, 8, 9 laag 4: art 4, 6

De lagen komen uit één deterministische scan. De artikeltekst noemt de andere artikelen woordelijk (“bedoeld in artikel 8”) en de oogst draagt daarnaast een references-blok met het BWB-nummer erbij. De scan leest beide, condenseert de graaf op sterk samenhangende componenten en verdeelt die componenten over lagen. Een knoop is (wet, artikel) en niet artikel: de wetsgrens komt uit de bron en is geen aanname van de code.

Dezelfde scan levert het tweede product: welke entry welke waarde produceert. Dat is de index die de afrondende pass nodig heeft. De volgorde en de te sluiten bindingen komen dus uit één scan, want twee scans lopen uiteen.

Naamgeving

Een consument die vóór zijn producent draait kan alleen raden hoe de waarde gaat heten. Draait de producent eerst, dan ziet de consument de output mét de naam die de producent er werkelijk aan gaf, en is de binding echt. Draaien ze in de verkeerde volgorde, dan verzinnen twee vensters onafhankelijk een naam voor hetzelfde begrip. Die twee namen komen nooit meer bij elkaar: een afrondende pass verbindt wat overeenkomt, en twee verschillende woorden voor één begrip komen niet overeen. Zo’n gat is stil, en een openstaande bevinding is dat niet; niemand vindt het terug.

De volgorde is daarmee een correctheidseigenschap, en dat is ook de reden dat gelijktijdigheid binnen een laag veilig is en tussen lagen niet.

Markeringen als tijdsprobleem

Een deel van onze markeringen is geen inhoudelijk oordeel. Het doelwit bestond nog niet toen we keken.

Het staat in de lopende run zwart op wit. Artikel 2 van de Wet op de zorgtoeslag draagt een open term standaardpremie, gedelegeerd aan Onze Minister, terwijl artikel 4 inmiddels een output met diezelfde naam levert. Toen artikel 2 werd geschreven had artikel 4 geen model, dus was er niets om aan te binden en werd de waarde als open term genoteerd. Die markering zegt iets over het moment van kijken en niet over de wet.

Deze klasse verdwijnt door de goede volgorde en niet door iets slimmers. Wat er na de goede volgorde nog van overblijft, gaat naar de afrondende pass.

Cycli

Wetten en artikelen verwijzen over en weer, dus er is niet altijd een topologische volgorde. RFC-026 stelt dat vast tussen wetten en kiest daar een sluitings-poort in plaats van een volgorde. Binnen één wet geldt hetzelfde in het klein: de Awir heeft één sterk samenhangende component van negen hoofdartikelen (2, 3, 7, 8, 9, 13, 14, 16 en 38).

Een groep die niet te ordenen is, wordt één laag. Dat is een venster dat je hebt afgeleid in plaats van geraden, en het is het eerlijke antwoord op de cyclusvraag: binnen zo’n component bestaat geen volgorde die producenten vooraan zet, dus daar blijft de afrondende pass nodig.

Tokens tegen wandklok

Vijf onafhankelijke artikelen in één laag kun je door één agent laten doen of door vijf agents tegelijk. Dat is een afweging en geen ontwerpkeuze, dus het is een instelling met standaard één tegelijk.

Het cijfer dat de afweging draagt: venster 3 van de lopende run kostte $5,92 bij vier aanroepen, waarvan 5,3 miljoen tokens cache-read. Dat zijn de skills, het schema en de contextbrief die elke beurt opnieuw meegaan. Die vaste last per sessie is de post die je vermenigvuldigt als je fijner snijdt: negen artikelen in negen sessies in plaats van twee betaalt hem vier tot vijf keer vaker. Preciezer, en mogelijk duurder.

Tokens zijn vandaag de schaarste omdat dit op een persoonlijk account draait. Bij vierduizend wetten is de wandklok de schaarste, en een keten die alleen sequentieel kan schaalt daar niet mee.

Twee agents die tegelijk in dezelfde YAML schrijven is een meting waarvan niemand kan zeggen wie wat schreef; ronde 3 verloor daar vier runs aan. Elke agent werkt daarom in een eigen kopie van de checkout, en de samenvoeging is per entry. De samenvoeging weigert in plaats van te raden: een venster dat een entry aanraakte die niet aan hem was toegewezen laat de run falen met dat entrynummer in de melding.

Meting

Gemeten op het corpus van ronde 4: de Awir met 329 entries en de Wet op de zorgtoeslag met 35, beide volledig verrijkt. Daarin staan 57 intra-wet bindingen die vooruit wijzen, waarbij de consument vóór de producent in het document staat. Dat is de klasse die een venster niet kan leggen.

Een volgorde uit de verwijzingsgraaf lost die niet op. Een topologische orde over de hoofdartikelen, cycli gecondenseerd en gelijkspel op documentvolgorde, bracht die 57 op 69. Documentvolgorde is al een goede bouwvolgorde, want de wetgever zet definities en algemene bepalingen vooraan. De verwijzingsgraaf draait dat juist om: “in afwijking van artikel 8” laat een later artikel naar een eerder wijzen zonder dat er een waarde overgaat, en zulke kanten wegen in een topologische orde even zwaar als de kanten die er wel toe doen.

De vensterrand lost hem wel op. 48 van de 57 zitten binnen één hoofdartikel: een aanhef die bindt aan zijn eigen leden of onderdelen. Geen enkele herordening van artikelen raakt die. Een vensterrand die een hoofdartikel niet doorknipt haalt ze allemaal binnen één venster; bij de venstermaat die vandaag draait daalt het aantal bindingen dat buiten zijn venster valt van 46 naar 8.

Van die acht hebben er vijf een invoernaam die woordelijk gelijk is aan de outputnaam. Dat is het mechanische deel. De andere drie noemen hetzelfde begrip met andere woorden en zijn de enige gevallen waar een agent nodig is.

Het bouwplan als volgorde levert op dit materiaal dus niets op en de laag als vensterrand het meeste. Dat berust op twee wetten. De volgordemodus blijft daarom bestaan en staat uit, zodat de claim op ander materiaal opnieuw te meten is.

Afrondende pass

Wat er na de vensterrand overblijft, sluit een pass over de hele wet, na het laatste venster. Hij verbindt alleen wat inmiddels bestaat.

Het deterministische deel schrijft de worker zelf: een invoer zonder source waarvan de naam woordelijk gelijk is aan een output die een andere entry van dezelfde wet levert, met de parameters van die entry aangeleverd uit wat de consument zelf heeft. Bij enige twijfel gebeurt er niets. Twee entries die dezelfde output leveren, een parameter die de consument niet kan aanleveren, een open term die nu ook als output bestaat: dat gaat als aanwijzing naar een agent met een smalle opdracht die vooral zegt wat hij niet mag. Niets herinterpreteren, geen artikel opnieuw modelleren, geen markering bijzetten of weghalen die over de inhoud gaat.

De pass draait over een wet die al door alle poorten is gegaan, dus alles wat hij toevoegt is achteruitgang. Daarom meet hij zichzelf na, en beide helften doen dat: twee tellingen vóór en na de schrijfactie, de schemafouten en de deterministische bevindingen. De meting beslist, niet wat de pass van plan was.

De twee helften hebben een andere drempel omdat ze een andere opdracht hebben. Het deterministische deel moet iets verbeteren en niets verslechteren: staan beide tellingen na afloop gelijk, dan gaat de tekst terug. Gelijk is geen bewijs van niets: één bevinding die verdwijnt naast één die ontstaat telt ook gelijk, en op een aantal is een verzameling niet af te lezen. Dat de schemafouten meetellen is geen ruimhartigheid maar de plek waar dit deel zijn werk aflevert — een invoer zonder source is een schemafout en geen bevinding, dus een gelegde binding repareert het schema terwijl het bevindingenaantal stilstaat. Gemeten op de bevindingen alleen zou de pass zijn eigen enige effect weigeren.

Het agent-deel wordt afgerekend op “niets slechter”. Of een aanwijzing goed beantwoord is, valt uit geen van beide tellingen af te lezen: een correct beantwoorde aanwijzing hoeft geen bevinding weg te nemen. Loopt een telling op of wordt het bestand onleesbaar, dan gaat de tekst terug naar wat er vóór de agent stond. Dat deel is de laatste schrijver van de run, dus wat het laat staan is wat gecommit wordt, en de harde schemapoort draait er daarom achter en niet ervóór.

Terminatie

De cursor telt vandaag lineair door het document en garandeert daarmee terminatie in een vast aantal runs. Beide veranderingen laten die garantie staan.

De vensterrand die een hoofdartikel heel houdt schuift de rechterrand alleen vooruit, nooit terug. Elke geslaagde run verzet de cursor met ten minste N entries of bereikt het einde, dus de grens van ceil(entries / N) runs blijft gelden.

In de laagmodus telt de cursor lagen in plaats van entries. Elke geslaagde run verhoogt hem met één en het aantal lagen ligt vast, dus de wandeling eindigt in ten hoogste lagen runs. De twee tellingen betekenen niet hetzelfde, dus staat de modus naast de cursor in de sidecar: verandert de modus, dan begint de wandeling opnieuw, net zoals bij een gewijzigd pad.

Buiten deze RFC

Een bouwplan kan ook door meerdere wetten wandelen. De Wet op de zorgtoeslag bindt aan drie entries van de Awir: berekeningsjaar in 2.1.b, toetsingsinkomen in 2.1.i en rendementsgrondslag_zonder_vrijstelling in 7.5. Loopt het plan over die grens, dan worden die drie eerst verrijkt en pas daarna het artikel van de zorgtoeslag dat ze leest. De binding is dan echt en geen markering met een adres erbij. Dat vraagt een index over het hele corpus en het raakt de afbakening uit RFC-026: welke wetten doen mee, waar stopt de sluiting, wat is een bekend gat. Die veralgemenisering staat als issue MinBZK/regelrecht#1088 en wordt hier niet opnieuw uitgeschreven. De datastructuur is er wel op gebouwd: een knoop is (wet, artikel), en een kruisverwijzing wordt al gelezen en bewaard.

Open vraag

De vaste last per sessie valt half weg als de contextbrief per artikel krimpt tot alleen wat dát artikel aanhaalt. Of dat opweegt tegen het vaker betalen van die last bij fijner snijden, is te meten en niet te beredeneren. Dat staat open tot er een run is waarin de wandklok telt.

RegelRecht

An exploration by Bureau Architectuur of the Dutch Ministry of Economic Affairs and Climate Policy into the possibilities of transparent, executable legislation.

Links

GitHub repository
How it works
Stay informed
Roadmap (Dutch)
Documentation
Research

Contact

regelrecht@minbzk.nl

Part of

Bureau Architectuur
Ministry of Economic Affairs and Climate Policy