De dure fout van een AI-codingtool is geen fout antwoord. Het is een zelfverzekerde gok. Een fout antwoord ziet er fout uit. Een gok ziet eruit als een afgeronde specificatie, wordt goedgekeurd, wordt gebouwd, haalt de tests die de agent voor zichzelf schreef, en blijkt over iets net anders te gaan dan je bedoelde. Dat merk je in de review, nadat je voor de run hebt betaald.
We hadden er zelf een duidelijk voorbeeld van. Bij projecten met meerdere repositories kreeg de opsteller van de specificatie geen lijst van die repositories, en niets van het gesprek over de taak. Een taak zonder gekozen repositories draaide dan alleen op de eerste repository van het project. De specificatie las prima. Het werk kwam op de verkeerde plek terecht.
Twee momenten om te vragen
In CodeLynq heeft een taak één chat, en die wisselt van rol met de specificatie. Zolang de specificatie leeg is, bakent de chat de taak af. Zodra er een concept is, beoordeelt hij dat concept. In beide gevallen werkt hij als een technical lead die het werk moet aftekenen, want dat is precies wat de vragen moeten doen.
Afbakenen begint ermee dat de lead de taak in eigen woorden navertelt, met de aanpak die hij zou kiezen, zodat een misverstand in het eerste bericht zichtbaar wordt en niet in de pull request. Daarna bepaalt hij waar het werk thuishoort. Bij een project met meerdere repositories noemt hij welke de taak raakt en wat er in elke repository verandert, en hij mag nooit aannemen dat het werk in één repository past zonder te zeggen waarom. Hij kent de branches van elke repository en wat het geheugen van de codebase erover heeft geleerd. Dan vraagt hij naar de afbakening: wat valt er expliciet buiten, welke repository is waarvan eigenaar, hoe praten de delen met elkaar.
Laat je daarna de specificatie uit dat gesprek opstellen, dan krijgt de opsteller het transcript en de lijst met repositories. Bij een project met meerdere repositories zegt hij ook welke repositories de taak nodig heeft, en die worden op de taak geselecteerd, maar alleen als niemand er al een had gekozen.
Hoe de vragen gesteld worden
De vorm is net zo belangrijk als de inhoud. Een open vraag ("hoe moeten grote exports zich gedragen?") is huiswerk. Een voorstel is een besluit dat je in een seconde neemt. Daarom is elke vraag geformuleerd als iets om te bevestigen: "Ik zou grote exports op de achtergrond draaien en een link mailen, want een gewone request loopt vast. Akkoord?"
- Maximaal drie vragen per bericht, de belangrijkste eerst.
- Twee tot vier korte antwoorden per vraag, met de aanbeveling van de lead bovenaan, en altijd ruimte voor je eigen antwoord.
- Niets wat de specificatie al beantwoordt, en niets wat de lead zelf redelijkerwijs kan beslissen. Die besluiten noemt hij in één regel.
In de review gaan de vragen over de plekken waar een verkeerde gok verandert wat er gebouwd wordt: gedrag aan de randen (lege, ongeldige, dubbele of gelijktijdige invoer, rechten), bestaande data en migraties, achterwaartse compatibiliteit, API-contracten en wie ze aanroept, beveiliging en privacy, performance waar volume ertoe doet, uitrol, en wat bewijst dat het werkt.
Een opgestelde specificatie draagt zichzelf ook over. Er komt een korte notitie van de lead bij, met de aanpak in één regel en wat er bevestigd moet worden, en maximaal vier bevestigingsvragen over de aannames in het concept, steeds met de keuze van het concept als eerste optie. Die verschijnen in de chat als review van het voorstel, en op het specificatiescherm zie je hoeveel er nog openstaan.
Weten wanneer je stopt
Een chat die blijft vragen is ook een fout. Mensen stoppen met antwoorden, of antwoorden slordig zodat het ophoudt. Daarom heeft de lead een expliciet stopsignaal. Staat er niets belangrijks meer open, dan vat hij samen wat er is afgesproken en eindigt hij het bericht met een [[READY]]-markering, die hij nooit mag gebruiken zolang er nog een vraag openstaat. De app verbergt de markering en toont "Niets belangrijks meer open", met de volgende stap: de specificatie opstellen, of de besluiten erin verwerken en goedkeuren.
Antwoorden horen in de specificatie, niet in het transcript
De agent bouwt vanuit de specificatie, niet vanuit de chat. Een besluit dat alleen in een gesprek staat, ziet de agent nooit. Daarom verwerkt één knop na een review wat er is afgesproken in de specificatie. Wat het gesprek niet veranderde blijft staan, en waar iets openbleef houdt hij de keuze van de specificatie aan en zet hij die bij de aannames, zodat het gat zichtbaar is in plaats van stil.
Een concept wordt ter plekke bijgewerkt. Een ingediende specificatie gaat terug naar concept, want wat er werd ingediend is niet meer wat er staat. Een goedgekeurde specificatie blijft onaangeroerd: je maakt een nieuwe versie om hem te wijzigen, zodat een goedkeuring altijd verwijst naar de tekst die echt is goedgekeurd. De chat krijgt daarna een bericht met wat er veranderde.
Wat het niet doet
- Open vragen blokkeren de goedkeuring niet. Het specificatiescherm laat zien hoeveel er nog openstaan voordat je goedkeurt, en je kunt toch goedkeuren.
- De chat is geen codereview. Hij werkt vanuit de taak, de specificatie, de lijst met repositories en wat het geheugen van de codebase weet. In de run wordt de code echt gelezen.
- Hij kan niet vragen naar wat niemand weet dat er ontbreekt. Bestaat een randvoorwaarde alleen in iemands hoofd, dan stelt de lead iets redelijks voor en moet jij het zien.
Het ging ook mis op een manier die we niet hadden verwacht. Het eerste concept bij een project met drie repositories kwam leeg terug: het model had halverwege zijn antwoord geen ruimte meer, en de lege velden werden opgeslagen als afgeronde specificatie. We verhoogden de limiet, en een leeg antwoord telt nu als een mislukt concept in plaats van een klaar concept.
Een toets voor elke specificatietool
Drie vragen vertellen je het meeste: vraagt hij voordat hij schrijft, weet hij wanneer hij moet stoppen met vragen, en komen de antwoorden in het document terecht waar de agent vanuit bouwt. Meer over de aanpak op de pagina over spec-driven development, en een uitgewerkt voorbeeld in wat is spec-driven development.