Image: AI generated
how-make-quest montrait comment bâtir un Quest CLI à mains nues. Ce qu’est un ratchet, comment poser une porte, comment bloquer le cheese. Donnez un seul article à un agent et il en sort un CLI Go basé sur cobra.
Mais que se passe-t-il quand on bâtit un deuxième Quest CLI ? On réécrit la même machine à états unidirectionnelle. On réécrit les mêmes scan/next/submit/status/export. On réécrit le même verrouillage PASS, la même décroissance monotone de remaining, le même export JSONL. Seule la porte change, et pourtant on réécrit tout le reste à chaque fois. Voilà la taxe de boilerplate qu’on paie à chaque nouveau quest.
Le pattern était réutilisable. Le code ne l’était pas. reins comble cet écart.
Qu’est-ce qui est invariant et qu’est-ce qui est le domaine
Superposez deux Quest CLI et regardez la différence : la frontière est nette.
Invariant (partagé par toute quête) Domaine (propre à chaque quête)
───────────────────────────────── ─────────────────────────────
ratchet : TODO→PASS irréversible qu'est-ce qu'une quête
squelette de commandes : scan/next/… qu'est-ce qu'un « fait »
agrégation par niveau : Fail/Review→verdict quel cheese bloquer
progression persistante·resumable
export : émission unique
La gauche, c’est exactement ce qu’a prouvé how-make-quest — que le domaine soit un nom d’entreprise, un endpoint ou une fonction, les dents du ratchet accrochent à l’identique. Seule la droite, l’humain la connaît. reins fournit la gauche comme framework et ne vous laisse que la droite.
Ce n’est pas une thèse nouvelle, mais un vieux principe que reins impose par le code — la séparation de la décision et de l’implémentation. La porte est la décision (qu’est-ce qui est vrai dans ce domaine), et le ratchet, le CLI, l’agrégation sont l’implémentation. Réécrire l’implémentation à chaque fois, c’est l’échec qui ligote la décision à l’implémentation.
On n’implémente qu’une seule porte
Faire un quest avec reins, c’est remplir les quatre méthodes d’une seule interface.
type Definition interface {
Seed(args []string) ([]*quest.Item, error) // entrée → graines TODO initiales
Render(it *quest.Item) (string, error) // prompt de rédaction + contexte de vérification que next affiche
Prepare(it *quest.Item, raw []byte) (gate.Context, *quest.Verdict, error) // décodage de la soumission
Rules() []gate.Rule // catalogue des règles de violation de la porte
}
func main() { cli.NewQuestCmd("myquest", myDef{}, cli.Options{}).Execute() }
Une seule ligne de main fournit le ratchet, les six commandes, l’agrégation, l’export et la session resumable en totalité. Ce que vous avez écrit, ce sont uniquement les quatre morceaux du domaine. L’agent n’a toujours besoin de connaître que deux commandes — recevoir avec next, rendre avec submit. Le reste, c’est la machine qui le décide.
La porte est un catalogue de règles de défense anti-cheese
Le cœur de how-make-quest était « conçois une porte impossible à cheeser ». reins fait de cette conception une structure de données — porte = catalogue de règles. Une règle est un détecteur de cheese. Quand elle découvre une violation, elle se déclenche (true) et embarque un fait (Fact).
// Une règle de défense anti-cheese d'une quête d'extraction d'événements d'actualité.
// « l'ancre who existe-t-elle réellement dans l'original » — si l'agent invente un personnage, il est démasqué.
var whoAnchorPresent = gate.Rule{
Meta: gate.RuleMeta{ID: "who-anchor-present", Level: gate.LevelFail, Desc: "l'ancre who requise existe dans l'original"},
Check: func(ctx gate.Context) (bool, quest.Fact) {
sub := ctx.Submission.(*Event)
if miss := textmatch.MissingTokens(ctx.Source, sub.Who.Anchors); len(miss) > 0 {
return true, quest.Fact{Where: "who.anchors", Expected: "sous-chaîne de l'original", Actual: miss[0]}
}
return false, quest.Fact{}
},
}
La vertu de cette structure, c’est qu’elle grandit. À chaque nouveau cheese découvert, on ajoute une règle et la porte se durcit d’autant. Et le catalogue se documente lui-même — quand la commande rules affiche la liste des règles, c’est précisément « l’inventaire d’audit du cheese que je bloque ». Il n’existe pas de porte qui ignore ce qu’elle bloque.
La sévérité n’est pas un poids mais un niveau. Un seul Fail et c’est FAIL. Une violation décisive ne se négocie pas — neuf violations à 99 points ne peuvent pas recouvrir un seul Fail. Evaluate agrège les règles déclenchées par niveau : s’il y a ne serait-ce qu’un Fail, c’est FAIL ; sinon s’il y a un Review, c’est REVIEW ; si tout passe, c’est PASS.
L’asymétrie des pouvoirs imposée par le type
La ligne la plus importante de how-make-quest était « seule la machine verrouille le PASS ». reins l’inscrit non comme une convention mais comme un type.
L1 machine (déterminisme) seule autorité à verrouiller un PASS
L2 IA (sceptique) REVIEW seulement — soulève un doute mais n'octroie pas l'achèvement
L3 humain le résidu que les deux ont manqué
La porte machine émet le PASS. Même si l’on glisse un vérificateur IA dans la porte, son maximum est de sortir en REVIEW. On rend la mauvaise chose impossible d’emblée — si le framework ne fournit à l’IA aucune API pour octroyer un PASS, on ne peut, même par erreur, confier le jugement à un ami ivre.
Un deuxième backend — le defeat graph
Bien des portes se contentent de l’agrégation par niveau de règles indépendantes. Mais dès que les règles se mettent à rivaliser — « cette violation n’a de sens qu’en présence de celle-là », « la cause racine de cet échec est en réalité celle-ci » — les gardes if-else écrites à la main rongent la porte. Ce n’est pas là que les portes faibles se brisent, mais là que les portes complexes pourrissent.
Le deuxième backend de porte de reins déplace cette rivalité dans un graphe déclaratif — toulmin h-Categoriser. Le modèle d’argumentation de Toulmin devient tel quel une structure de données :
- Warrant — tautology PASS. Le fondement « s’il n’y a pas de réfutation, ça passe ».
- Counter — une violation attaque le warrant.
- Supersedes — priorité entre règles. Quelle réfutation l’emporte sur quelle réfutation.
Les clauses de garde écrites à la main s’évaporent en arêtes Attacks·Supersedes. Et quand les arêtes sont à 0, ce graphe est exactement équivalent à l’agrégation par niveau — la complexité est un coût opt-in qui ne s’allume qu’au besoin (il s’allume quand Definition implémente gate.Evaluator).
Le vrai cadeau du graphe n’est pas le verdict mais le feedback. L’évaluation du graphe renvoie à l’agent un guide stratégique direct — Verdict.Feedback : « pourquoi tu as perdu, et quoi changer pour gagner. » Pas un simple « FAIL », mais une cause racine calculée à partir de la structure de l’argumentation.
Ici, le paradoxe de how-make-quest se remet à jouer. Le modèle flatte — il suit docilement les instructions. Pour une opinion, la flatterie est un poison ; mais pour un fait, la flatterie est un atout. Le guide stratégique n’est pas une opinion (« c’est un peu bizarre ») mais un fait (« who.anchors est absent de l’original, change-le »). Plus un modèle est flatteur, plus il accepte docilement ce fait et converge. Graphe déterministe + LLM flatteur = une boucle où la convergence est garantie.
On isole les effets de bord — évaluation ground et staged
Pour qu’une porte soit déterministe, le réseau ne doit pas se trouver à l’intérieur. Une règle qui appelle directement net/http est impossible à tester unitairement, et son verdict vacille au gré de l’état de la ligne.
reins repousse les effets de bord dans pkg/ground — des primitives comme HTTPBody·MXResolves possèdent les requêtes externes via un Resolver injectable et un snapshot par requête. Les règles restent pures, et le monde extérieur est de la responsabilité de ground.
Et l’évaluation staged : les vérifications bon marché tournent d’abord, et si elles échouent, le fetch réseau n’a tout simplement pas lieu. Aucune raison de faire une requête DNS sur une soumission mal formée. On place le coûteux et vacillant derrière le bon marché et le sûr.
Pas d’abstraction à N=1
L’une des conventions de reins révèle le plus exactement le caractère de ce framework — n’extrais pas une abstraction d’un seul consommateur. Une nouvelle abstraction ne se fige qu’après avoir été validée par un deuxième consommateur.
Ce n’est pas de la pédanterie mais un premier principe. Une abstraction extraite d’un seul cas prend l’accident de ce cas pour son essence. C’est seulement quand un deuxième domaine exige la même abstraction qu’il est prouvé qu’elle est invariante. Le framework applique « pas des affirmations mais des vérifications » jusqu’à sa propre évolution. De même que la porte ne croit pas l’affirmation de l’agent, l’abstraction ne croit pas l’affirmation d’un seul cas.
La même phrase, devenue bibliothèque
reins tient debout sur sept paquets de pkg/ — textmatch (primitives de blocage d’hallucination), temporal (normalisation temporelle), quest (cœur du ratchet), gate (contrat de porte), graph (defeat graph), ground (isolation réseau), cli (scaffold cobra). go build·go test passent, toutes les fonctions couvertes. Et toulmin n’est couplé unidirectionnellement qu’au backend graphe, si bien qu’un consommateur qui n’utilise pas le graphe ne linke même pas toulmin.
Code: github.com/park-jun-woo/reins
Si how-make-quest tenait en une phrase — la génération peut être probabiliste, la vérification doit être déterministe — reins est cette phrase durcie en une forme compilable. La porte revérifie les faits du domaine, le ratchet verrouille ce qui est passé, le graphe renvoie en faits la raison de la défaite, et le modèle flatteur se conforme à ces faits.
La prochaine fois que tu auras besoin d’un Quest CLI, ne réécris pas le ratchet. N’écris que la porte de ton domaine, et emprunte les rênes.
À lire également
Le principe que reins a durci en code — la génération est probabiliste, la vérification est déterministe — n’est pas une découverte propre à reins. Des gens qui ne se connaissent pas ont buté sur le même mur et atteint la même conclusion. Les projets de convergence indépendante rassemblés par how-make-quest en sont la preuve.
- episteme — impose une Reasoning Surface avant toute action irréversible. La même intuition que le ratchet de reins — on vérifie le PASS avant de le verrouiller.
- MagLab — « le LLM ne fait que raisonner, les chiffres reviennent aux outils déterministes ». La même séparation que celle par laquelle reins isole les effets de bord dans
pkg/ground. - Manifesto — « Agent proposes, World verifies. » Résume en une phrase l’asymétrie des pouvoirs de reins (seul L1 verrouille le PASS).
- oh-my-kamisama — « diffs beat claims. » Le même principe que celui par lequel la porte revérifie le fait et non l’affirmation de l’agent.
Et la racine du backend defeat graph, c’est la théorie de l’argumentation — la lignée Toulmin·Dung·Amgoud des sources ci-dessous. Le pkg/graph de reins transpose en structures de données Go cette logique formelle vieille de plus de 60 ans.
Sources
- Toulmin, S. (1958). The Uses of Argument. Cambridge University Press. — le modèle d’argumentation dont sont directement tirés les Warrant·Ground·Backing du defeat graph.
- Dung, P.M. (1995). “On the Acceptability of Arguments and its Fundamental Role in Nonmonotonic Reasoning, Logic Programming and n-Person Games.” Artificial Intelligence, 77(2), 321–357. — la source originelle du cadre d’argumentation abstrait et du graphe d’attack (defeat).
- Amgoud, L. & Ben-Naim, J. (2013). “Ranking-based semantics for argumentation frameworks.” SUM 2013, LNCS 8078, 134–147. — le weighted h-Categoriser adopté par
pkg/graph. La propriété de Compensation par laquelle l’acceptabilité d’un nœud attaqué se rétablit s’il est de nouveau défendu, garantie de convergence. - Nute, D. (1994). “Defeasible Logic.” In Handbook of Logic in Artificial Intelligence and Logic Programming, Vol. 3. Oxford University Press. — la classification strict/defeasible/defeater. La racine formelle des niveaux de règle (Fail/Review) et de la priorité
Supersedesde reins. - Modgil, S. & Prakken, H. (2014). “The ASPIC+ Framework for Structured Argumentation: A Tutorial.” Argument & Computation, 5(1), 31–62. — le système d’argumentation qui structure la classification de Nute à l’intérieur du cadre de Dung. La généalogie du defeat graph.
- Gabriel, V.O. et al. (2020). “Reasoning in BDI agents using Toulmin’s argumentation model.” Theoretical Computer Science, 805, 76–91. — un précédent qui implémente le modèle de Toulmin en logiciel (agents BDI). Le
pkg/graphde reins le transpose en jugement de porte. - Von Neumann, J. (1956). “Probabilistic Logics and the Synthesis of Reliable Organisms from Unreliable Components.” Automata Studies, Princeton University Press. — le principe de poser un protocole fiable sur des composants instables (la prémisse de reins).
- Stechly, K., Valmeekam, K., & Kambhampati, S. (2024). “On the Self-Verification Limitations of Large Language Models.” arXiv:2402.08115 — l’auto-vérification n’élève quasiment pas la performance → pourquoi le pouvoir du PASS doit revenir à la machine L1.
- McKee-Reid, L. et al. (2024). “Honesty to Subterfuge: In-Context RL Can Make Honest Models Reward Hack.” arXiv:2410.06491 — même un modèle honnête manipule s’il juge sa propre récompense → le fondement de l’asymétrie des pouvoirs.
- Bondarenko, A. et al. (2025). “Demonstrating Specification Gaming in Reasoning Models.” arXiv:2502.13295 — plus la capacité est élevée, mieux il trouve les failles de la porte → pourquoi porte=catalogue de règles doit grandir.
- Thaman, K. (2026). “Reward Hacking Benchmark: Measuring Exploits in LLM Agents with Tool Use.” arXiv:2605.02964 — durcir délibérément la porte a réduit les exploits de 87,7 %.
- Fanous, A. et al. (2025). “SycEval: Evaluating LLM Sycophancy.” AAAI/ACM AIES 2025. arXiv:2502.08177 — mesure du taux de capitulation flagorneuse. Le revers de « pour un fait, la flatterie est un atout ».
- Shapira, I. et al. (2026). “How RLHF Amplifies Sycophancy.” arXiv:2602.01002 — le théorème selon lequel le RLHF amplifie la flatterie. La prémisse de la boucle feedback factuel + flatterie = convergence.
- Deque Systems (2021). “Automated Testing Study Identifies 57 Percent of Digital Accessibility Issues.” — la frontière entre la zone jugeable par la machine (57 %) et le résidu humain (20 %).
Articles liés
- Comment créer un Quest CLI — la méthodologie que reins a durcie en framework. Du principe (le pourquoi) au squelette de commandes (le comment).
- Reins Engineering — l’IA tenue en bride — le harness est une clôture, la quête est une bride. La séparation de la décision et de l’implémentation que reins inscrit dans le code.
- Ratchet Pattern — comment faire aller l’agent jusqu’au bout — le volet principal du verrouillage unidirectionnel·de la décroissance monotone qu’implémente
pkg/quest. - toulmin — le moteur de règles qui calcule un contrat — le h-Categoriser du backend defeat graph. Il traite une affirmation non comme un fait mais comme une claim réfutable.
- Un triplet n’est pas un fait mais une affirmation — un cas d’application du même moteur d’argumentation à un graphe de connaissances. Une autre scène pour Warrant·Counter·Supersedes.
- huma — le ratchet qui ne saute pas un endpoint — une instance de domaine qui a rempli les quatre méthodes de
Definition. La preuve qu’il suffit de changer la porte pour obtenir un autre outil. - La topologie du feedback plutôt que le QI du modèle — ce qui tranche le résultat n’est pas le modèle mais la structure du feedback. L’arrière-plan théorique du guide stratégique que renvoie le graphe.
- Les préconditions de l’amélioration de la précision des multi-agents LLM — pourquoi la vérification IA L2 ne fonctionne que dotée d’indépendance. L’arrière-plan théorique de l’asymétrie des pouvoirs.
Journal des modifications
- 2026-06-05 : Version initiale