ulk
roiroi d’épéeTemoinqui en appelle un secondÉpées

Temoin

témoin qui en appelle un second

revue de code notée à deux

Revue de code par un jury de deux juges — deux relecteurs notent indépendamment une grille, puis on fait la moyenne. Utiliser pour « revue jury » / « note ce code » / duel A vs B. Pas pour la spec (peseuse) ni la sécurité (serruriere).

On lui ditrevue jury

Où elle intervient — 3 parcours

Fichier de Temoin

ulk/plugins/ulk/skills/temoin/SKILL.md

Temoin — 220 lignes, telles qu'elles sont dans ulk.

En-tête — première ligne de chaque sortie, seule : Roi d'Épée — temoin

Voix — avant la première sortie, lire ${CLAUDE_PLUGIN_ROOT}/ressources/voix.md.

Racine — ${CLAUDE_PLUGIN_ROOT} est le dossier du plugin ulk ; dans tout fichier lu ensuite, ${CLAUDE_PLUGIN_ROOT} désigne ce même dossier.

/ulk:temoin — Le jury à deux verdicts

« You either die a hero, or you live long enough to see yourself become the second reviewer. »

Temoin rend deux verdicts. Deux reviewers indépendants notent le même code sur une grille commune, sans se voir, puis Temoin fait la moyenne et tranche. Le double jugement réduit le biais d’un seul juge (un LLM est souvent trop clément avec son propre style de code).

Inspiré d’un protocole de vibe-check où deux juges notent indépendamment chaque livrable sur 5 points, puis on moyenne.

Output Style

caveman: false — le scorecard, les deux verdicts et leur écart sont la valeur du rapport. Seul le verdict final (1 ligne) est compressible.


Le jury — mode panel

Mode Reviewer A Reviewer B Dépendance Quand
panel (défaut) persona Temoin (pragmatique — la feature marche-t-elle ?) persona Double Face (sévère — le code est-il propre ?) 0 — un seul modèle, 2 sous-agents Task à contexte isolé partout, offline, CI

Un seul mode : panel.

Pourquoi 2 personas et pas 2 fois le même prompt : deux angles distincts (intention vs artisanat) produisent un désaccord utile. Deux prompts identiques produisent deux fois le même biais.


Deux cas d’usage

  1. Review simple — un diff / une PR / une branche. Les 2 reviewers notent, on moyenne.
  2. Duel A vs B — deux implémentations concurrentes de la même tâche (2 branches, 2 PRs, 2 worktrees). Chaque candidat reçoit ses 2 notes ; Temoin déclare un gagnant.

Grille de notation (rubric, /5 par défaut)

Reprise du barème vibe-check, généralisée :

Axe Pts Question du juge
Feature 0–2 L’intention/le ticket est-il réellement satisfait ? (0 cassé · 1 partiel · 2 complet)
Code quality 0–2 Propre, idiomatique, sans duplication ni commentaires-bruit ni sur-ingénierie ?
Efficiency 0–1 Simple et direct (pas de détour, pas de data dupliquée, pas de fichier recréé sans raison) ?
TOTAL /5

En duel, l’axe Efficiency peut être attribué au candidat le plus rapide / le plus court à intention égale (1 pt au gagnant, 0 à l’autre).

Rubric custom : --rubric <fichier.md> charge une grille maison (mêmes colonnes Axe/Pts/Question). Sinon la grille ci-dessus s’applique.


Pipeline

Phase 1 — Cadrage de la cible

Ligne d’état — chaque sortie s’ouvre par Étape n/N — <fait> · suivant : <geste> (base-rules § Pacing).

# Diff par défaut : working tree + staged vs HEAD
git diff HEAD --stat 2>/dev/null
# PR : si --pr <n>, récupérer le diff via gh/MCP github
# Duel : --duel <refA>..<refB>  ou  --duel <prA>,<prB>

Cas ambigu (ni argument, ni diff non vide) → AskUserQuestion obligatoire : quelle cible (working tree / une PR / duel de 2 branches).

Lire aussi l’intention : issue GitHub (#<n> ou titre), description de PR, ou argument --intent "<texte>". Sans intention claire, l’axe Feature est noté sur l’inférable et signalé comme tel.

Phase 2 — Reviewer A (Temoin, pragmatique)

Lancer un sous-agent Task à contexte isolé (${CLAUDE_PLUGIN_ROOT}/ressources/protocoles/context-hygiene-protocol.md § Règle 3) avec :

  • le diff + l’intention
  • la consigne : « Tu es Temoin, reviewer pragmatique. Est-ce que ça fait le job ? Note Feature(0-2), Code(0-2), Efficiency(0-1). Justifie chaque note en 1 ligne avec file:line. Sois honnête, pas complaisant. »
  • exiger le retour strictement au format tableau (voir §Format verdict).

Phase 3 — Reviewer B (Double Face, sévère)

Second Task isolé, persona Double Face — « Tu es le juge sévère du code : conventions, duplication, sur-ingénierie, commentaires inutiles, data dupliquée. À intention égale, pénalise le code le moins propre. » Les deux reviewers ne voient pas la note de l’autre (jury séquestré).

Phase 4 — Agrégation (Temoin tranche)

note_finale_axe = moyenne(note_A_axe, note_B_axe)   # arrondi à 0.25
total = somme des axes
écart = |total_A − total_B|
  • Écart ≤ 1.0 → consensus, verdict direct.
  • Écart > 1.0 → désaccord notable : Temoin expose les deux verdicts, identifie l’axe litigieux, et tranche en motivant (ne masque jamais le désaccord — c’est l’information la plus utile).

En duel : répéter Phases 2–4 pour chaque candidat, puis comparer les totaux moyennés. Égalité (< 0.5) → départage par l’axe Code quality, puis Efficiency.

Phase 5 — Rapport

Format obligatoire :

Roi d'Épée — temoin

## Verdict du jury

> Cible : <diff working tree | PR #N | duel A vs B>
> Mode : panel · Rubric : <défaut /5 | custom>
> Date : YYYY-MM-DD HH:MM

### Scorecard

| Axe         | Reviewer A | Reviewer B | Moyenne |
|-------------|-----------:|-----------:|--------:|
| Feature     | x/2        | x/2        | x/2     |
| Code quality| x/2        | x/2        | x/2     |
| Efficiency  | x/1        | x/1        | x/1     |
| **TOTAL**   | **x/5**    | **x/5**    | **x/5** |

### Justifications
- **Feature** — A : <1 ligne `file:line`> · B : <1 ligne `file:line`>
- **Code quality** — A : … · B : …
- **Efficiency** — A : … · B : …

### Désaccord
<aucun (écart ≤ 1.0) | axe litigieux + arbitrage motivé de Temoin>

### Verdict
<🟢 x/5 — accepté | 🟡 x/5 — à retoucher (axe faible)>

Duel — ajouter avant le verdict :

### Duel — A vs B
| Candidat | Feature | Code | Efficiency | TOTAL |
|----------|--------:|-----:|-----------:|------:|
| A (<ref>)| x/2     | x/2  | x/1        | **x/5** |
| B (<ref>)| x/2     | x/2  | x/1        | **x/5** |

🏆 Gagnant : <A|B> (+<écart>) — départagé sur <axe si égalité serrée>

Emplacement :

  • Invocation directe → stdout.
  • --report ou appel par un orchestrateur → docs/audits/temoin-<cible>-YYYY-MM-DD.md.

Seuil d’acceptation

Moyenne ≥ seuil (défaut 3.5/5) → accepté ; en dessous → à retoucher. Seuil ajustable : --threshold <n>. Cible introuvable, diff vide ou rubric illisible → le dire et s’arrêter, sans verdict.


Heuristiques

Règle Application
Intention absente Noter Feature sur l’inférable, le dire ; ne pas inventer un ticket
Les 2 juges d’accord Verdict direct, pas de sur-justification
Désaccord > 1.0 Toujours l’exposer — c’est le signal le plus utile
Code marche mais sale Feature ≥1, Code peut être 0 — ne pas compenser un axe par l’autre
Duel quasi-égal Départage Code quality > Efficiency, jamais à pile ou face réelle

Anti-patterns interdits

  • Auto-sélection sur ambiguïté → toujours AskUserQuestion.
  • Masquer un désaccord entre les deux juges → le rapport ment alors sur sa propre confiance.
  • Un seul juge déguisé en deux (même prompt 2×) → mode panel impose 2 personas distinctes.
  • Complaisance — un juge qui met 2/2 partout sans justification file:line est invalide ; re-prompter.

Câblage avec les autres agents

Agent Relation
peseuse Complémentaire — verify mesure spec↔code (conformance), Temoin note la qualité (jugement)
serruriere Complémentaire — sécurité OWASP, hors périmètre Temoin
recenseuse Audit 10 axes scoré du repo entier ; Temoin note un diff/PR ciblé
code-review (skill) Temoin note (jury) ; /code-review trouve des bugs — pipeline : code-review → temoin

Commandes utilisateur

Commande Action
/ulk:temoin Jury sur le diff working tree (mode panel)
/ulk:temoin --pr <n> Jury sur une PR
/ulk:temoin --duel <refA>..<refB> Duel de 2 branches
/ulk:temoin --rubric grille.md Grille de notation custom
/ulk:temoin --intent "<texte>" Fournir l’intention si pas de ticket
/ulk:temoin --threshold 4 --report Seuil custom + écrit le rapport