Specificaties, tests en code op elkaar afstemmen in AI-ontwikkeling

Voorkom dat AI-agenten afwijken van specificaties, tests en code.

Inhoud

AI-coderingsagenten leveren functies snel uit, maar specificaties, tests en code lopen stil apart. Deze gids behandelt een traceerbaarheidsmodel, de koppeling tussen specificatie en test en tussen specificatie en code, en de CI-controles die drift vangen voordat er wordt samengevoegd.

Een specificatie die niemand meer controleert tegen het draaiende systeem is erger dan geen specificatie, omdat het een vals vertrouwen creëert. Beoordelaars vertrouwen op het document in plaats van op het verschil (diff), en een AI-agent dat wordt gevraagd om “het bestaande patroon te volgen”, volgt graag wat de code daadwerkelijk doet, zelfs als dat in strijd is met de eis die het zou moeten vervullen.

De oplossing is niet meer documentatie. Het is een kleine, afdwingbare link tussen vier dingen die in de meeste repositories al bestaan: de eis, het ontwerpbeslag dat erachter schuilgaat, de tests die het bewijzen, en de commits of pull requests die het hebben gewijzigd.

traceerbaarheidslinks die specificaties, tests en code verbinden

Zodatie link bestaat als data in plaats van als een gedeeld begrip, kun je deze bevragen. Je kunt vragen welke eisen geen testdekking hebben, welke tests niet langer aan een eis koppelen, en welke bestanden zijn gewijzigd in een pull request zonder een overeenkomstig eisen-ID. Die query is het daadwerkelijke leverbaar van dit artikel, en de rest van het bericht loopt door hoe je dit bouwt met tools die je waarschijnlijk al gebruikt.

Het driftprobleem: waarom specificaties, tests en code uit synchronisatie raken

Drift verschijnt in vier herkenbare vormen, en teams die AI-assistentie gebruiken, stoten sneller op alle vier dan teams die elke regel met de hand schrijven.

  • Specificatie verandert, code niet. Een eis wordt verduidelijkt in een vervolggesprek of een commentaarthread, maar niemand genereert de implementatie opnieuw of bewerkt deze om deze aan te passen.
  • Code verandert, specificatie niet. Een agent of ontwikkelaar lost een bug op of refactorist een module, en de specificatie beschrijft het oude gedrag alsof het nog steeds actueel is.
  • Tests dekken implementatie, niet intentie. Unitests beweren wat de code momenteel doet, wat cirkelvormig is: ze slagen door constructie, zelfs wanneer de code de verkeerde eis vervult.
  • Pull requests verwijzen niet naar eisen. Beoordelaars keuren een diff goed op basis van “ziet er redelijk uit”, omdat er geen explicite claim is om tegen te controleren.

Recent procesonderzoek naar AI-ontwikkelingsframeworks identificeert specificatiedrift als een terugkerend risico, precies omdat agenten code snel en herhaaldelijk opnieuw genereren, en elke regeneratie een nieuwe kans is voor specificatie en implementatie om iets verder uit elkaar te lopen. Het debat over Spec-Driven Development vs Vibe Coding is eigenlijk een betoog over deze zelfde falingsmodus: een specificatie die niemand afdwingt, degradeert tot dezelfde drift die je zonder krijgt, maar dan met extra ceremonie.

Moderne workflows in spec-kit-stijl framemen dit steeds vaker als specificatieverval: de specificatie ziet er autoritair uit, maar verliest stil haar verbinding met wat het systeem daadwerkelijk doet. De kerndefinitie van spec-gedreven ontwikkeling behandelt de specificatie als de bron van waarheid, maar een bron van waarheid blijft alleen waar als iets het tegen de realiteit blijft controleren.

Een traceerbaarheidsmodel voor AI-geassisteerde ontwikkeling

Een werkbaar traceerbaarheidsmodel heeft zes identifiers nodig die een zakelijke eis verbinden tot de regels code en de pull request die deze implementeerde. De meeste teams hebben al drie of vier van deze; de ontbrekende zijn meestal het ontwerpbeslis-ID en de expliciete link terug van tests en commits.

Identifier Woonplaats Voorbeeld
Eisen-ID requirements.md of spec-tool REQ-014
Ontwerpbeslis-ID ADR / beslissingenregistratie ADR-0032
Taak-ID taakopdeling of issue-tracker TASK-014-3
Test-ID testbestand of testnaam test_req_014_password_reset
Commit / PR-link Git-geschiedenis PR #482
Gewijzigde bestanden Git-diff auth/reset.go, auth/reset_test.go

De relaties tussen deze identifiers vormen een grafiek in plaats van een rechte lijn, omdat één eis meerdere taken kan voortbrengen, en één pull request meerdere eisen tegelijk kan raken.

graph TD REQ["Eis
REQ-014"] --> ADR["Ontwerpbeslis
ADR-0032"] ADR --> TASK["Taak
TASK-014-3"] TASK --> CODE["Code-wijziging
auth/reset.go"] TASK --> TEST["Test
test_req_014_password_reset"] CODE --> PR["Pull Request
#482"] TEST --> PR PR --> COMMIT["Commit-geschiedenis"]

Het opslaan van deze grafiek als gestructureerde data, niet als proza, is wat je later in staat stelt om deze te bevragen. Het Spec Kit-ecosysteem van GitHub is precies in deze richting bewogen: extensies zoals spec-kit-trace scannen REQ-XXX-tokens die zijn ingebed in specificatiebestanden en testbestanden en genereren een deterministische matrix op basis van die letterlijke tekstmatch, en vermijden bewuste vaag naamgebaseerd raden dat stille valse positieven produceert.

Specificatie-naar-test-koppeling: acceptatiecriteria omzetten in testcases

Elk acceptatiecriterium in een specificatie is, door constructie, een gedragingsbewering: gegeven deze staat, wanneer de actor dit doet, dan moet het systeem zo reageren. Dat is al de vorm van een testcase, wat de reden is dat de sterkste SDD-workflows tests genereren uit dezelfde acceptatiecriteria die de code genereren, in plaats van de code-genererende agent te vragen om achteraf ook zijn eigen tests te verzinnen.

Een veelgebruikt formaat voor het schrijven van deze criteria is EARS (Easy Approach to Requirements Syntax), wat elke eis dwingt in een eenduidig, testbaar patroon zoals “Wanneer <trigger>, moet het systeem <reactie>.” Die structuur kaart perfect af op vier categorieën tests die elke eis moet dragen:

  • Positieve tests — het gelukkige pad dat de eis expliciet beschrijft.
  • Negatieve tests — invoer of staten die de eis zegt moeten worden afgewezen.
  • Randgevaltests — de randen van bereiken, limieten en drempels die in de acceptatiecriteria worden genoemd.
  • Migratietests — gedrag voor data of staat die ouder is dan de eis, zodat een oud record niet stil een nieuwe regel omzeilt.
Eis-type Testcategorie toe te voegen Veelvoorkomende fout
“Systeem moet X afwijzen” Negatief Alleen het acceptatiepad wordt getest
“Limiet is N items” Randgeval N-1, N en N+1 zijn niet allemaal gedekt
“Nieuw veld vervangt oud veld” Migratie Oude records zonder nieuw veld crashen stil
“Binnen 60 seconden” Randgeval + timing Test bewert logica, niet de daadwerkelijke tijdset

Unitests die op deze manier worden geschreven, blijven belangrijk als de snelle, goedkope laag van de piramide; de praktische patronen voor het structureren ervan worden behandeld in de Go unit testing gids en de Python unit testing gids. Wat traceerbaarheid hierboven toevoegt, is een letterlijk, stabiel eisen-token ingebed in de testnaam of een testcommentaar, zodat een latere query kan bewijzen — niet aannemen — dat REQ-014 dekking heeft.

Specificatie-naar-code-koppeling: van ontwerpplannen naar een traceertabel

Specificatie-naar-test-koppeling bewijst gedrag; specificatie-naar-code-koppeling bewijzt scope. Het beantwoordt een andere vraag: welke bestanden daadwerkelijk moesten wijzigen voor deze eis, en bleef de diff binnen die grens of spoelde het over in ongerelateerde modules?

Een ontwerpplan dat van tevoren gewijzigde bestanden opsomt — zelfs een ruwe lijst — geeft je iets om later tegen de echte pull request te diffen. Commentaren in code mogen alleen een eisen-ID refereren als dit informatie toevoegt die een beoordelaar niet uit de specificatie zelf kan halen; een commentaar dat de eistekst letterlijk herhaalt, is ruis, maar // handhaaft REQ-014 grens: max 5 resetpogingen per uur verdient zijn plaats omdat het getal anders onzichtbaar is in de diff.

Een gegenereerde traceertabel maakt dit tot iets dat in seconden kan worden beoordeeld in plaats van iets dat een beoordelaar moet reconstrueren door beide documenten naast elkaar te lezen:

Eis Ontwerpbeslis Gewijzigde bestanden Tests Status
REQ-014 ADR-0032 auth/reset.go, auth/reset_test.go test_req_014_* (4) Gedekt
REQ-015 ADR-0032 auth/reset.go geen Leemte
REQ-016 auth/notify.go test_notify_basic Orphan-spec-link

Die ene tabel laat twee van de meest voorkomende falingspatronen direct zien: REQ-015 veranderde code met nul overeenkomende tests, en de test die is gekoppeld aan REQ-016 verwijst niet daadwerkelijk naar een eisen-ID, wat betekent dat de specificatie ontbreekt of de test verkeerd is geclassificeerd.

De pull request-workflow: specificatie, code en test-diffs samen beoordelen

Een pull request die is gebouwd rond traceerbaarheid, beoordeelt drie diffs naast elkaar in plaats van één: wat er in de specificatie is veranderd, wat er in de code is veranderd, en wat er in de tests is veranderd. De beoordelingsvraag stopt met “ziet dit er goed uit?” en wordt veel specifieker: “welke eis vervult deze wijziging, en bewijst het bewijs het?”

sequenceDiagram participant Dev as Ontwikkelaar of Agent participant PR as Pull Request participant CI as CI-Pijpleiding participant Rev as Beoordelaar Dev->>PR: Open PR met specificatie-diff + code-diff + test-diff PR->>CI: Trigger traceerbaarheidschecks CI->>CI: Verifieer dat REQ-ID aanwezig is in PR-beschrijving CI->>CI: Voer specificatie-naar-test-dekkingscheck uit CI->>CI: Voer specificatie-naar-code-bestandscope-check uit CI-->>PR: Plaats traceerbaarheidsrapport als PR-commentaar Rev->>PR: Beoordeel tegenover "welke eis vervult dit?" Rev->>PR: Keur goed of vraag wijzigingen aan

Een korte, concrete beoordelingslijst werkt hier beter dan een lange, omdat beoordelaars lange lijsten overslaan onder deadline-druk:

  1. Noemt de PR-beschrijving de eisen-ID(s) die het vervult?
  2. Verschijnt elk gewijzigd bestand in de lijst van beïnvloede bestanden in het ontwerpplan, of wordt de extra scope verklaard?
  3. Verwijst ten minste één nieuwe of bestaande test naar elk eisen-ID dat door deze PR wordt geraakt?
  4. Als de specificatie is veranderd, zijn de code en tests in dezelfde PR veranderd, of is er een bijgehouden vervolg?

Traceerbaarheid automatiseren in CI

Handmatige beoordeling vangt drift alleen zo vaak als beoordelaars eraan denken om naar te kijken, wat de reden is waarom de checks hierboven in CI behoren in plaats van op een wikipagina die niemand opnieuw leest. Dezelfde GitHub Actions cheatsheet patronen die je al gebruikt voor build- en testjobs, zijn hier direct van toepassing — traceerbaarheidschecks zijn gewoon een andere job in dezelfde pijpleiding.

Praktische automatiseringsideeën, ruwweg in volgorde van inspanning:

  • CI-checks voor specificatiebestanden — faal de build als een specificatiebestand is bewerkt zonder een overeenkomstige code- of testwijziging in dezelfde PR, of omgekeerd.
  • Vereis eisen-IDs in PR-titels of -beschrijvingen — een lichtgewicht regex-check (REQ-\d+) blokkeert merges die niet benoemen wat ze implementeren.
  • Agent-gegenereerde traceerbaarheidssamenvattingen — laat een agent een korte samenvatting produceren van welke eisen een PR raakt, voor een mens om te bevestigen in plaats van van scratch te schrijven.
  • Testdekking per acceptatiecriterium, niet alleen per regel — regeldekkings vertelt je dat code liep; eisen-dekkings vertelt je dat een claim is gecontroleerd.
  • Waarschuwingen voor verouderde specificaties — markeer specificaties die niet zijn aangeraakt in N commits die hun gelinkte bestanden raken, aangezien lang stilzittende specificaties degenen zijn die het meest waarschijnlijk stil zijn verrot.

Extensies die zijn gebouwd bovenop GitHub’s Spec Kit implementeren al enkele van deze mechanisch: één scant letterlijke REQ-XXX-tokens over specificatie- en testbestanden om een matrix te bouwen en geïsoleerde tests te markeren, en een striktere V-Model-georiënteerde pack gaat verder, door een gepaarde testspecificatie te genereren voor elke ontwikkelingsspecificatie en meerdere traceerbaarheidsmatrices te produceren voor teams die werken onder regelgevingskaders zoals IEC 62304 of ISO 26262. Je hebt dat niveau van ceremonie niet nodig voor de meeste projecten, maar het onderliggende idee — een deterministische, scriptgegenereerde matrix in plaats van een handmatig onderhouden spreadsheet — schaalt net zo goed naar beneden als naar boven.

AI-agents gebruiken voor traceerbaarheid, niet als orakel

AI-agents zijn goed geschikt voor de mechanische delen van traceerbaarheid en slecht geschikt om de uiteindelijke rechter te zijn van of een eis daadwerkelijk is vervuld. Drie taken sluiten direct aan bij de sterktes van een agent:

  • Vergelijk specificatie en diff — vraag de agent om elke eis op te lijsten die wordt genoemd in de specificatiebestanden die door een PR zijn geraakt, en elke die het niet in overeenkomende code vond.
  • Vind ongedekte eisen — vraag de agent om de testsuite te scannen op eisen-tokens en te rapporteren welke eisen in de specificatie er geen hebben.
  • Detecteer code die niet door specificatie wordt beschreven — vraag de agent om gewijzigde bestanden of functies te markeren die eisen-dragende modules raken maar niet corresponderen met een eisen-ID in de diff.

De falingsmodus waartegen je moet waken, is het vertrouwen in de samenvatting van de agent als grondwaarheid in plaats van als startpunt voor een beoordelaar. Een agent kan een commentaar verkeerd lezen, een eisen-token missen dat over twee bestanden is verdeeld, of met vertrouwen dekkings verklaren voor een test die alleen de codepad oppervlakkig oefent. Behandel elk agent-gegenereerd traceerbaarheidsrapport zoals je de pass van een junior beoordelaar zou behandelen: nuttig, snel, en nog steeds onderworpen aan een tweede blik voordat het een merge blokkeert. Dit is dezelfde voorzichtigheid die van toepassing is op beslissingenregistraties voor AI-gedreven ontwikkeling — het record blijft alleen betrouwbaar als iets anders dan de agent die het schreef, het uiteindelijk controleert.

Een minimale traceerbaarheidssjabloon die je kunt kopiëren

Je hebt geen zwaar framework nodig om te beginnen. Een vijf-bestandssjabloon, gecheckt in de repository naast de code die het beschrijft, dekt de essentie:

docs/
  requirements.md     # REQ-IDs met EARS-stijl acceptatiecriteria
  design.md           # ADR-IDs, beïnvloede bestanden, architectuurbeslissingen
  tasks.md            # TASK-IDs gekoppeld aan één of meer REQ-IDs
  tests.md            # welke testbestanden/-functies welke REQ-IDs refereren
  traceability.md     # gegenereerde tabel: REQ -> ADR -> TASK -> bestanden -> tests -> PR

requirements.md, design.md en tasks.md worden door mensen en agents samen geschreven of bewerkt, op dezelfde manier zoals de spec-gedreven ontwikkelingsworkflow al beschrijft. tests.md en traceability.md zouden gegenereerd moeten zijn, niet handmatig onderhouden, zelfs als de generator een kort script is dat alleen grept naar REQ-\d+ over de testdirectory en de specificatiebestanden — handmatig onderhouden traceerbaarheidstabellen zijn zelf een vorm van drift-risico, omdat niemand een spreadsheet bijwerkt onder deadline-druk.

Conclusie

Spec-gedreven ontwikkeling is niet klaar op het moment dat code uit een agent komt; het is pas nuttig zodra code, tests en specificaties elkaar in de loop van de tijd eerlijk houden, via PRs, refactoring en eisenwijzigingen die maanden uit elkaar aankomen. Een traceerbaarheidsmodel gebouwd van zes eenvoudige identifiers, afgedwongen door een handvol CI-checks, en beoordeeld met een korte PR-checklist, geeft je het grootste deel van het voordeel zonder de overhead van een volledig compliantie-kader. Begin met de minimale sjabloon, koppel eerst de goedkoopste CI-check — eisen-IDs in PR-beschrijvingen — en voeg de traceertabel en waarschuwingen voor verouderde specificaties toe zodra die gewoonte stickt.

Traceerbaarheid is één onderdeel van een bredere test- en documentatiediscipline die wordt behandeld in de App Architecture in Production cluster, en het staat naast de toolingvragen die worden verkend in de AI developer tools cluster voor teams die kiezen welke agent-workflows ze willen standaardiseren.

Abonneren

Ontvang nieuwe berichten over systemen, infrastructuur en AI-engineering.