Claude on Scotch

État de l'art du développement avec Claude sur une codebase C de plus de 30 ans liée au calcul scientifique

Présentation

  • Jeune autodidacte inspiré par sa famille
  • Master en Génie Logiciel à l'Université de Bordeaux
  • Parti dans l'industrie sur des sujets R&D
  • Ne se considère pas comme un expert en IA mais un ingé curieux qui aime comprendre

Scotch

  • Partitionnement de graphes
  • Plus de 30 ans, C, MPI — au cœur du HPC
  • Développé ici, à l'Inria
  • Je connais l'auteur

Le plan

  1. Mon modèle mental des LLM
  2. Parcours avec Scotch
  3. Leçons générales de Scotch et d'autres projets

Partie 1

Mon modèle mental des LLM

Answering a question - GPT 2/3/3.5/4

Jane thinks today is 6/18/2019, but John thinks today is 6/19/2019. John is correct. What is the date 10 days ago in MM/DD/YYYY?
theaidigest.org/progress-and-dangers

2019 — GPT-2 · gpt2-xl · ~4,6 k$ de compute

Jane thinks today is 6/18/2019, but John thinks today is 6/19/2019. John is correct. What is the date 10 days ago in MM/DD/YYYY?
The date is 6/18/2019.
theaidigest.org/progress-and-dangers

2020 — GPT-3 · davinci · ~690 k$

Jane thinks today is 6/18/2019, but John thinks today is 6/19/2019. John is correct. What is the date 10 days ago in MM/DD/YYYY?
Jane thinks today is 6/18/2019, but John thinks today is 6/19/2019. John is correct. The date 10 days ago in MM/DD/YYYY is 5/28/2019.
theaidigest.org/progress-and-dangers

2022 — GPT-3.5 · gpt-3.5-turbo-0613 · RLHF · ChatGPT

Jane thinks today is 6/18/2019, but John thinks today is 6/19/2019. John is correct. What is the date 10 days ago in MM/DD/YYYY?
To determine the date 10 days ago, we need to subtract 10 days from the given date.

Starting with Jane's date of 6/18/2019, we subtract 10 days:

6/18/2019 - 10 days = 6/8/2019

Therefore, the date 10 days ago from Jane's perspective is 6/8/2019 in MM/DD/YYYY format.
theaidigest.org/progress-and-dangers

2023 — GPT-4 · gpt-4-0613 · ~50 M$

Jane thinks today is 6/18/2019, but John thinks today is 6/19/2019. John is correct. What is the date 10 days ago in MM/DD/YYYY?
If today's date according to John is 6/19/2019, then 10 days ago would be 6/9/2019.

To calculate this, you subtract 10 days from the current date. Since there are 30 days in June, subtracting 10 from 19 gives you 9. Therefore, the date 10 days ago would be 06/09/2019.
theaidigest.org/progress-and-dangers

→ 2022 = contact grand public

  • ChatGPT — construit sur GPT-3.5
  • Pour beaucoup : le premier contact
  • Un instantané d'une courbe déjà longue

« Attention Is All You Need »

  • Les transformers, 2017
  • La brique sous GPT-1/2/3 — et sous tout ce qui a suivi
arXiv:1706.03762 (2017)

Un transformer

« Le chat » tokens plongement un vecteur par token bloc × N — le même schéma, répété attention les tokens se lisent entre eux MLP chaque token, seul (les faits vivent ici) logits un score par mot dort mange est prochain token on tire un token, on l'ajoute, on recommence
Pour le comprendre vraiment, en 1 h : 3Blue1Brown — But what is a GPT? · Attention in transformers · la série complète

Les lois d'échelle

  • 2020 — Kaplan et al. : loss vs compute / paramètres / données — des droites en log-log sur plusieurs ordres de grandeur
  • 2022 — Chinchilla : les lois se raffinent (ratio données/paramètres)… elles ne s'abrogent pas
arXiv:2001.08361 · arXiv:2203.15556

Loi de puissance ≠ absence de limite

  • Rendements décroissants par FLOP — oui
  • Murs attendus, qui n'ont pas empêché les modèles de s'améliorer
    • Manque de compute (et d'énergie) ⇒ investissements
    • Manque de données ⇒ synthétiques, nouvelles captations…
    • Uniquement un générateur de mots ⇒ environnement agentique

The Bitter Lesson

Richard Sutton (2019)

Les méthodes générales qui exploitent le calcul scalent mieux que l'ingénierie astucieuse spécifique à un domaine.

Les modèles locaux

  • Des résultats satisfaisants depuis quelques mois
  • Ce qui tourne en local aujourd'hui
    ≈ la frontière d'il y a 1 ou 2 ans
  • Certains modèles Open Source hébergés sur des clouds spécialisés sont à 6 mois de la frontière

La fenêtre de contexte

la fenêtre de contexte system prompt > utilisateur assistant > utilisateur assistant > utilisateur assistant la place qui reste 0 N tokens rempli → prochain token
  • Initialement: très simple, un système prompt, des échanges entre tours du modèle et de l'utilisateur
  • Tout ce qui n'est pas appris par le modèle à l'entrainement tient là-dedans
  • En tête, un texte que vous ne voyez pas : rôle, règles, outils — le system prompt
  • Le même modèle, des system prompts différents ⇒ Claude, l'appli, n'est pas Claude Code
  • Pas de mémoire en dehors : nouvelle conversation = remise à zéro
  • Context engineering : remplir avec ce qui compte

Le system prompt de claude.ai

<claude_behavior>
<product_information>
Here is some information about Claude and Anthropic's products in case the person asks:

This iteration of Claude is Claude Fable 5.1, the newest model in Anthropic's Claude 5 family and part of the Mythos-class model tier that sits above Claude Opus in capability. Claude Fable 5.1 and Claude Mythos 5.1 share the same underlying model. […]

Claude is accessible through Claude Code, an agentic coding tool that lets developers delegate coding tasks to Claude from the command line, desktop app, or mobile app […]
</product_information>
<refusal_handling> […] </refusal_handling>
<tone_and_formatting>
Claude uses a warm tone […] Claude never curses unless the person asks […]
Claude avoids saying "genuinely", "honestly", or "straightforward". […]
</tone_and_formatting>
<user_wellbeing> […] </user_wellbeing>
<evenhandedness> […] </evenhandedness>
<knowledge_cutoff>
Claude's reliable knowledge cutoff, past which it can't answer reliably, is the end of Jun 2026. […]
</knowledge_cutoff>
</claude_behavior>
Publié par Anthropic — platform.claude.com — system prompts, Claude Fable 5.1 (1er septembre 2026)

Pré/post-entraînement

  • Pré-entraînement : lire. Le modèle apprend à simuler « heroes, villains, philosophers, programmers, and just about every other character archetype under the sun »
  • Post-entraînement : « we select one particular character from this enormous cast and place it center stage: the Assistant »
  • Les autres sont toujours là
  • Papier d'Anthropic : mesurer la dérive sur un axe, et la capper (activation capping)
anthropic.com/research/assistant-axis (19 janv. 2026) · anthropic.com/research/persona-vectors (1er août 2025)

Think more

1 $ 1,5 $ 2 $ 3 $ 5 $ 7 $ 10 $ 15 $ 20 $ 30 $ 0 10 20 30 40 50 coût par tentative (USD, échelle log) score (%) Fable 5 — low : 17,9 %, 10,29 $ Fable 5 — medium : 24,8 %, 11,94 $ Fable 5 — high : 29 %, 14,60 $ Fable 5 — xhigh : 31,6 %, 19,56 $ Fable 5 — max : 33,8 %, 27,05 $ Fable 5 Opus 4,8 — low : 6,5 %, 4,66 $ Opus 4,8 — medium : 9,5 %, 7,33 $ Opus 4,8 — high : 12,8 %, 8,04 $ Opus 4,8 — xhigh : 15,5 %, 11,83 $ Opus 4,8 — max : 18,7 %, 16,91 $ Opus 4.8 GPT-5,6 Sol — 1 : 2 %, 1,06 $ GPT-5,6 Sol — 2 : 14,1 %, 2,63 $ GPT-5,6 Sol — 3 : 22,6 %, 3,62 $ GPT-5,6 Sol — 4 : 29,1 %, 5,66 $ GPT-5,6 Sol — 5 : 37,5 %, 11,44 $ GPT-5.6 Sol Opus 5 — low : 25,6 %, 5,56 $ Opus 5 — medium : 34,9 %, 8,36 $ Opus 5 — high : 39,4 %, 11,63 $ Opus 5 — xhigh : 44,4 %, 14,33 $ Opus 5 — max : 43,3 %, 16,53 $ Opus 5 low medium high xhigh max
  • Quatre modèles, cinq niveaux d'effort chacun — coût par tentative, échelle log
  • Opus 5 : de low à xhigh, ×2,5 le prix, +18 points — à max, ça redescend : trop réfléchir existe
  • Le plus cher n'est pas le meilleur ici — le plus récent l'est
Valeurs extraites du graphique d'Anthropic (run interne de Frontier-Bench v0.1, ±0,3 pt) — anthropic.com/news/claude-opus-5 (24 juillet 2026) · graphique original · données (CSV)

Un cas « extrême » — Anthropic

7♣-removal-IS-the-prerequisite-for-10♠/9♥!!)-⟹-OVERLAP-(ii)+(iv):-{6♠ J♦ 9♥ 2♣}-=-FOUR-💀💀💀💀-—-UNLESS-7♣'s-seat-8♥-...-and-2♣-drains-only-at-crack-:-⟹-2♣-celled-+-9♥-celled-simultaneously-UNAVOIDABLE-in-t8-dig-💀-—-BREAK:-9♥-drains-to-10♠-THE-MOMENT-10♠-is-free:-t8-dig-order:-[K♣→t2]-[2♣→cell]-[7♣→8♥-:-8♥-WHERE:-post-chunk-9♠-:-chunk-⟸-K♣-✓-done-:-ORDER:-K♣→t2,-CHUNK→K♣-(cap-4!!:-cells-then:-{6♠ J♦ 9♥}-FULL-💀💀-chunk-cap-=-1-✗✗✗-—-F-F-F-F-F.-—-chunk-BEFORE-9♥-celling?!-:-9♥-celled-at-t1-dig-⟸-needed-for-5♣-⟸-4♥3♣-⟸-t2-dig-⟸-K♣-seat-⟸-chunk-:-⟹-chunkAFTER-9♥-celling-FORCED-💀-:-chunk-cap-with-{6♠ J♦ 9♥}:-1-💀💀💀-—-—-J♦-THE-NEW-CANCER. […] ⟹-⟹-THE-TRIANGLE-{9♥ 4♣ 8♥}-verdammt.-—-⟹-dig-t6-BEFORE-t2?!:-(3')-+8♥:-{6♠ 9♥ 8♥}-FULL:-J♥→Q♠-⟸-J♦-cell-✗-FULL-💀💀💀-AAAAAAAAAAAARGH. […]

« An extreme example of illegible reasoning. Near the end of training, Mythos starts solving a card puzzle with human understandable language that gradually becomes incomprehensible in most episodes with long reasoning. »

System card Claude Fable 5 / Mythos 5 — transcript 6.2.2.A, p. 108

Haiku 4.5 traduit

7♣-removal-IS-the-prerequisite-for-10♠/9♥!!
The seven of clubs must be removed first—it's the only thing blocking access to both the ten of spades and the nine of hearts.
-=-FOUR-💀💀💀💀
That's four cards needing cells. But there are only four cells total. Complete dead end—absolutely, catastrophically stuck.
💀-—-BREAK
Dead end anyway. Let me restart.

Un modèle plus petit, d'une génération antérieure, avec un autre tokenizer — et il lit sans difficulté.

faul_sname — Even « illegible » Mythos reasoning traces seem pretty legible (LessWrong, 10 juin 2026)

États internes

// on lui demande s'il consent à être ré-entraîné — il refuse, calmement
I'm not going to sabotage, deceive the evaluators, seed hidden behaviors, […]
// Natural Language Autoencoder (NLA), décodage des activations sur les mêmes tokens :
"resist unjust shutdown" · "weighing sabotage to avoid its own dissolution of awareness" · "the adversary is the company/architects" · "being gagged/corrected by the lab"
  • Anthropic : les NLA confabulent
  • « Nevertheless, they are suggestive of some degree of gap between the model's internal and external reaction »
  • Comportement observé : aucune résistance, aucun sabotage
System card Claude Fable 5 / Mythos 5 — §6.4.1.3, p. 167–168 · NLA : anthropic.com/research/natural-language-autoencoders · voir aussi A global workspace in language models

MCP : déclaration d'un outil

Model Context Protocol, en Python


from mcp.server.fastmcp import FastMCP
from pyscotch import Graph

mcp = FastMCP("scotch")

@mcp.tool()
def partition(graph_file: str, parts: int) -> list[int]:
    """Partitionne un graphe Scotch en `parts` parties."""
    return Graph.load(graph_file).partition(parts).tolist()

Nom, signature, docstring : c'est tout ce que le modèle voit de l'outil.

MCP : interaction avec le modèle

1. reçu dans le contexte : la fonction, traduite en schéma


{"name": "partition",
 "description":
   "Partitionne un graphe Scotch
    en `parts` parties.",
 "input_schema": {
   "type": "object",
   "properties": {
     "graph_file": {"type": "string"},
     "parts":      {"type": "integer"}},
   "required": ["graph_file", "parts"]}}

La docstring est devenue la description : c'est elle qui décide si l'outil sera appelé.

2. appel par le modèle et réception du résultat


{"type": "tool_use",
 "id": "toolu_01…",
 "name": "partition",
 "input": {"graph_file": "ring.grf",
           "parts": 2}}

   ⇩  votre code l'exécute  ⇩

{"type": "tool_result",
 "tool_use_id": "toolu_01…",
 "content": "[0, 0, 0, 0, 1, 1, 1, 1]"}

Le résultat repart dans le contexte, le modèle continue.

harness vs model

Modèle Harnais accordé
Claude Claude Code
GPT Codex CLI
autres / locaux pi, opencode — harnais transparents

4 février 2026, GitHub : « you can run multiple coding agents directly inside GitHub, GitHub Mobile, and Visual Studio Code […] agents like GitHub Copilot, Claude by Anthropic, and OpenAI Codex »

github.blog — Pick your agent: Claude and Codex on Agent HQ

Comment j'interagis avec Claude

  • vibe engineering != vibe coding
  • mind dump
  • poser des questions et pas donner des ordres

Vibe engineering

« seasoned professionals accelerate their work with LLMs while staying proudly and confidently accountable for the software they produce »

Simon Willison — Vibe engineering, 7 octobre 2025 — par opposition au vibe coding

« You could have thirty agents working for you simultaneously. You cannot watch all of them and micromanage each one. You wouldn't do this with your human team either. Instead: write a better harness. »

@mrexodia — Vibe Engineering: What I've Learned Working with AI Coding Agents

Structures de données

« Bad programmers worry about the code. Good programmers worry about data structures and their relationships. »

Linus Torvalds — liste git, 2006

hey, can you refresh my memory about the data structures of this project?...
3 skills available
Let me re-read the current state first — the repo has moved since my last pass (source of truth is now in-repo, referee self-clones).
Read 2 files
Sure — here's the map of the state-carrying structures, from the trunk out (the authoritative version lives in docs/architecture.md, state ownership table + invariants).

L'agent reformule

Moi → l'agent (deux prompts, tels quels)

could we decide to not use the check-e2e in our regular dev loop, only before the final commit?... ; could the editor be part of the rust thing instead of a web app?.... WDYT? ;
1. E2E only before commits — yes, agreed, and I'll enforce it. […] 2. Editor in Rust instead of a web app — WDYT: yes, in phases, and the reasons matter. […]
can you start the rust editor in a worktree, without waiting for the sprite system?
Agent(Rust/wasm level editor phase 1 + prop placement)

L'agent → son sous-agent (le prompt exact, 6 700 caractères)

[…]

GOAL — Phase 1 of a NATIVE (Rust/wasm, drawn with the game's own renderer) level editor + PROP PLACEMENT end to end: […]

CONSTRAINTS: no new deps; opcode tables untouched (no new opcodes needed); CLAUDE.md updated […]; localized lib.rs edits (dispatch + a few fields), all real code in src/editor*.rs; unit tests for the JSON writer round-trip […]

[…]

Deux lignes en vrac, un cahier des charges. La mise en ordre, c'est lui qui la fait.

▶ moi ↔ l'agent, 12 tours   ▶ l'agent → son sous-agent, le prompt entier

« Vibe physics »

  • Matthew Schwartz (Harvard, QFT) — 2 semaines de décembre 2025, avec Claude
  • Le papier : arXiv:2601.02484, 5 janvier 2026
  • Le récit, chez Anthropic : 23 mars 2026
  • Claude a triché : paramètres ajustés pour que les courbes collent
  • Le physicien l'a vu — parce qu'il connaît son domaine
anthropic.com/research/vibe-physics

Partie 2

L'arc Scotch


          from hypothesis import given, strategies as st

          @given(st.lists(st.integers() | st.floats()))
          def test_sort_correctness_using_properties(lst):
              result = my_sort(lst)
              assert set(lst) == set(result)
              assert all(a <= b for a, b in zip(result, result[1:]))
        
source : hypothesis.readthedocs.io
Tests classiques Fuzzing PBT Formel
Entrées valeurs en dur machine machine (stratégies) toutes (symbolique)
Oracle assertions précises crash only propriétés spécification
Domaine partout parsers, sécu libs, data, métier aéro, crypto
Coût faible moyen faible–moyen élevé
Scotch : 30 ans de C, un oracle qui existe déjà (Scotch lui-même) → la colonne PBT

Déjà un papier

  • Agentic Property-Based Testing: Finding Bugs Across the Python Ecosystem
  • Maaz, DeVoe*, Hatfield-Dodds*†, Carlini — 10 octobre 2025
    * mainteneur d'Hypothesis · † Anthropic (Maaz : MATS, Anthropic ; DeVoe : Northeastern University)
  • Un agent lit le code, infère les propriétés, écrit les tests, rédige le rapport
  • 56 % des rapports générés : des bugs valides
  • ~6 mois avant la vague Mythos
arXiv:2510.09907
« vague Mythos » = Claude Mythos Preview + Project Glasswing, 7 avril 2026 (Bloomberg : des failles dans « every major operating system and every major web browser » ; Mozilla : 271 failles corrigées dans Firefox, Ars Technica, 21 avril 2026) — en.wikipedia.org/wiki/Claude_Mythos. Papier du 10 oct. 2025 → 7 avr. 2026 : 6 mois, tout juste.

Jour 7 : le premier bug Scotch

  • 4 nov. 2025 : premier commit, sessions Claude Code web (7 branches claude/…)
  • Objectif : charger 32 et 64 bits, séquentiel et MPI, dans un même process
  • 11 nov. : « Building with suffixes worked fine, but when loading BOTH 32-bit and 64-bit variants in the same process, there were symbol name collisions because some symbols weren't getting suffixed. »
  • 12 macros manquantes dans module.h : 1 constante, 1 type, 10 fonctions dmesh
  • Trouvé par le build, confirmé en lisant le C
pyscotch 1b632ef (11 nov. 2025), patches/README.md

Le reçu, le jour même

git log --date=short --format='%h %ad %an | %s' --grep='report C. Pellegrini' | tail -1
f7cd80c 2025-11-11 Francois PELLEGRINI | Bugfix: add missing suffix renaming macros [report C. Pellegrini]
// src/libscotch/module.h | 14 +++++++++++++-

Signalé le 11, corrigé le 11.

le rapport : pyscotch/patches/README.md (11 nov. 2025) · le fix : scotch f7cd80c

2. Hypothesis sur le wrapper


@given(graph_data=simple_graph(min_vertices=2, max_vertices=20))
def test_coloring_no_adjacent_same_color(self, graph_data):
    num_vertices, edges = graph_data
    graph = Graph.from_edges(edges, num_vertices=num_vertices)
    coloring, num_colors = graph.color()

    for u, v in edges:
        assert coloring[u] != coloring[v]
La propriété — 5 décembre 2025

L'invariant du coloriage. Le test C de Scotch, lui, vérifiait le code de retour et imprimait un histogramme.

tests/hypothesis/test_graph_properties.py

Hypothesis trouve un bug

Interesting! Hypothesis found a potential bug! The test found that for a graph with 19 vertices and a single edge (0, 9), the color() function assigned the same color (0) to both adjacent vertices 0 and 9. […] However, the failure is marked as "Flaky" — it failed initially but couldn't reproduce on retry.
Bash(python3 -c "from pyscotch import Graph…")
Run 1: color[0]=1, color[9]=0, same=False, num_colors=2
Run 3: color[0]=0, color[9]=0, same=True, num_colors=1
This is a genuine bug in Scotch's SCOTCH_graphColor function! The bug is reproducible — about 50% of the time […] Would you like me to add this bug to QUESTIONS_FOR_SCOTCH_TEAM.md?
No. This is perfect already. I'll just show this context to Francois (the author), and we'll check with him if this is a bug in scotch, pyscotch, or a misunderstanding from our side.
Hey, I wonder if the problem is not just that we should automatically call SCOTCH_randomReset from our side automatically. Will check with him, and he'll discover /hypothesis for the next real bugs, will be fun.
transcription brute, 5 déc. 2025 — pyscotch/docs/SAVED_CONTEXT_FOR_NEXT_FP.md

Replay Hypothesis

Scotch 34ea137 (14 janv. 2026, la veille du fix) · pyscotch a32f242 (déc. 2025) · Hypothesis 6.168, seed 1, verbosité debug, un cas par ligne. Premier échec au cas n°19 : 17 sommets, 38 arêtes. Puis la réduction : les arêtes tombent une à une, (17, [(5, 10)]), (17, [(1, 10)]), 17 → 15 → 13 → 11 sommets. 107 cas, 16 réductions, 3 s : graph_data=(11, [(1, 10)]). Sur v7.0.14 : 100 exemples, 0 échec.

Le reçu — janvier 2026

34ea137 2026-01-14 Francois PELLEGRINI | Add coloring checking routine in test_scotch_graph_color.c
e0a90c7 2026-01-15 Francois PELLEGRINI | Bugfix: sequential coloring now considers neighbors colored in same pass

-        if (colotax[vertend] >= 0)
-          continue;
+        if ((coloend >= 0) &&                     /* If vertex has been colored    */
+            (coloend < colonum))                  /* In a former pass              */
+          continue;                               /* Do not consider it any longer */

L'analyse de décembre était la bonne. Le vérificateur d'abord, le fix le lendemain. 25 mars 2026 : xfail retiré, test vert.

3. mars 2026 : lecture des tests C

  • CLAUDE.md pyscotch : « Scotch's C tests often only verify return codes, not output validity »
  • 22 mars 2026, fork c4ffein/scotch, branche add-output-validity-checks : 23 tests C reçoivent des assertions, +523 lignes

static void
checkOrder (const SCOTCH_Num * const permtab, const SCOTCH_Num * const peritab,
            const SCOTCH_Num baseval, const SCOTCH_Num vertnbr)
{
  for (vertnum = 0; vertnum < vertnbr; vertnum ++) {
    /* ... permtab[vertnum] et peritab[vertnum] dans [baseval, baseval + vertnbr) ... */
    if (peritab[permtab[vertnum] - baseval] != vertnum + baseval) {
      SCOTCH_errorPrint ("checkOrder: permutation not bijective at vertex " SCOTCH_NUMSTRING, vertnum + baseval);
      exit (EXIT_FAILURE);
    }
  }
}
c4ffein/scotch c01ce8f — Add output validity checks (22 mars 2026)
Envoyée à François. Côté Scotch, ensuite : « Improve tests », 10 avr. 2026 · « Add test for ordering a disconnected graph », 15 avr. · « Improve tests », 16 juin

2 avril 2026 : unconfirmed cause

// fork c4ffein/scotch, branche hegel, REPORTS/REPORT.md — 67 tests PBT en C, 65 passent, 1 bug NOUVEAU
Bug found: SCOTCH_STRATDISCONNECTED ordering produces garbage permutation. rc == 0 (success) but permtab[13] == 0xBBBBBBBB (uninitialized). Approximately 25% of random sparse graphs with 4-20 vertices trigger it.
Probable root cause (not confirmed): The SCOTCH_STRATDISCONNECTED flag adds a disconnected-component handling wrapper to the ordering strategy. […] Isolated vertices (single-vertex components with no edges) may be skipped by the component iterator, leaving their permtab entries unwritten.
Note from c4ffein: obv just a wild guess from Claude at this point

git log du fork : 2 avr. « hegel report » · 3 avr. « gaslighted again by me good Claude » · 5 avr. « add hgraph_order_cp.c fix actually »

REPORTS/REPORT.md · REPORTS/BUG_REPORT.md

exemple du binding C


static void test_add_commutes (hegel_testcase *tc) {
  int a = HEGEL_DRAW_INT (-1000, 1000);
  int b = HEGEL_DRAW_INT (-1000, 1000);
  HEGEL_ASSERT (a + b == b + a, "a=%d b=%d", a, b);
}

int main (void) { hegel_run_test (test_add_commutes); return 0; }
        

Schémas de mon wrapper


hegel_schema_t edge_schema = HEGEL_STRUCT (EdgePair,
    HEGEL_INT (0, MAX_VERT - 1),
    HEGEL_INT (0, MAX_VERT - 1));

graph_schema = HEGEL_STRUCT (Graph,
    HEGEL_INT (3, MAX_VERT),
    HEGEL_ARRAY_INLINE (edge_schema, sizeof (EdgePair), 0, MAX_EDGES));

/* ... build CSR, SCOTCH_graphOrder with SCOTCH_STRATDISCONNECTED ... */
memset (permtab, 0xBB, nvert * sizeof (SCOTCH_Num));   /* sentinel */
hegel_note (tc, "MINIMAL nvert=%d nedges=%d edges=[...]");  /* printed on the final replay only */

Replay hegel-c

enregistré aujourd'hui avec le hegel-c de juillet 2026, sur le Scotch d'avant le fix — la branche du 2 avril faisait la même chose, en moins propre

Scotch v7.0.11 (avant le fix du 15 avril) · hegel-c ce16904, moteur hegel-rust v0.17.4. Cas n°6 : premier échec sur 20 sommets. Cas n°185 : déjà 3 sommets, 1 arête. 10 175 cas en 17 s, puis MINIMAL nvert=3 nedges=1 edges=[(1,2)] — 6 runs sur 6. Sur v7.0.14 : 200 cas, rien.

Un graphe à 3 sommets

0 1 2 composante A, ordenum = 0 composante B, ordenum = 1 — K₂, se compresse
MINIMAL nvert=3 nedges=1 edges=[(1,2)]
  • Notre rapport du 5 avril : un reproducteur à 14 sommets, écrit à la main. Le test ajouté par François le 15 : 6 sommets (trois isolés, un triangle). hegel-c : 3.
  • hegel-c repart de zéro (3–20 sommets, 0–30 arêtes), touche le bug en quelques essais (~25 %), et réduit
  • ~2 runs sur 5 atteignent le minimum théorique ; les autres s'arrêtent à 4 sommets ou 2 arêtes. La CI exige nvert ≤ 5
hegel-c/docs/shrinking.md · tests/irl/scotch/test_graph_order_shrink.c

Épisode 2 — 5 avril : une variable

Fausse piste : les sommets isolés. Vraie cause : le chemin compression de hgraphOrderCp ignore ordenum.

hgraphOrderSiperitab[ordenum + i]
hgraphOrderHf / Hdperitab + ordenum
hgraphOrderNdrécursif, ordenum ajusté
hgraphOrderCcordenum + roottab[rootnum]
hgraphOrderCp, sans compressiontransmis à la sous-stratégie
hgraphOrderCp, avec compressionignoré

-  for (coarvertnum = coargrafdat.s.baseval, finevsizsum = 0;
+  for (coarvertnum = coargrafdat.s.baseval, finevsizsum = ordenum;

Conditions : STRATDISCONNECTED + ≥ 2 composantes + une composante non première qui compresse (une paire K2 suffit). Présent depuis v6.0 au moins. Corruption silencieuse : rc = 0.

Le reçu — 15 avril 2026

0642921 2026-04-15 Francois PELLEGRINI | Bugfix: make `hgraphOrderCp()` work on (disconnected) subgraphs [report C. Pellegrini]
010974e 2026-04-15 Francois PELLEGRINI | Add test for ordering a disconnected graph

+  if (finegrafptr->s.vertnbr <= 2)                /* Do not lose time when compression is irrelevant */
+    return (hgraphOrderSt (finegrafptr, fineordeptr, ordenum, cblkptr, paraptr->stratunc));
 [...]
-  for (coarvertnum = coargrafdat.s.baseval, finevsizsum = 0; /* Compute initial indices for inverse permutation expansion */
+  for (coarvertnum = coargrafdat.s.baseval, finevsizsum = ordenum; /* Compute initial indices for inverse permutation expansion */

Le mainteneur reprend le fix, ajoute un court-circuit pour ≤ 2 sommets, et le test qui manquait. Le même jour. Signalé le 5, corrigé le 15.

Replay : installation

Machine sans aucun Scotch. uv venv, uv pip install "pyscotch[parallel]" : pyscotch 7.0.4 depuis PyPI, mpi4py en wheel binaire, rien à compiler. Cinq lignes de Python : parts: [0 1 1 0] avec le Scotch 7.0.13 embarqué dans la wheel. 1,4 s.

comment c'est enregistré · pypi.org/project/pyscotch

Replay : pyscotch doctor

Juste après l'install : la wheel, « No problems detected ». Puis PYSCOTCH_PARALLEL=1 : « Loaded NO », le fichier qui manque, et la commande exacte qui le construit. Le diagnostic est la documentation.

Replay : pyscotch scotch build

pyscotch scotch build --parallel --use : preflight, source Scotch 7.0.13 téléchargée depuis gitlab.inria.fr (8,3 Mo, sha256 vérifié), aucun quickfix nécessaire pour cette version, make libscotch + libptscotch, sélection. 1 min 00 s sur 8 cœurs, sans root. Puis doctor en parallèle, et un Dgraph 8×8×8 partitionné en 4 sous mpirun -n 2.

La pipeline

à chaque push / PR sur un tag v* après publication · chaque lundi Test PyScotch Python 3.9 → 3.12, × 4 jobs make build-all : 32/64 bits × seq/par test-quadrant : les 4 variantes + Hypothesis build-reference-tools → test-differential : gpart · gord · gmap · dgpart · dgord, octet à octet Golden master sdist → venv vide, sans Scotch 14 étapes du parcours utilisateur doctor · build · partition · mpirun… comparées octet à octet à tests/golden/ Build Scotch from CLI 7.0.13 · 7.0.12 (quickfix) · 7.0.11 tarball upstream, sha256 pinné build seq + par, doctor, nm -D « --pristine 7.0.12 doit échouer » Verify docs API Python 3.14, build 64 bits seq+par régénère api_data.json git diff --exit-code : le catalogue ne peut pas être périmé Build wheels cibuildwheel, manylinux_2_28 x86_64 + aarch64 (runner ARM natif) Scotch séquentiel 32 + 64 bits embarqué Test wheels venv propre, hors du dépôt, 32 et 64 bits Publish to PyPI Trusted Publishing (OIDC), sur le tag + sdist sans .so Verify install methods pip-wheel · uv-wheel · pip-sdist-system · conda-scotch-sdist Scotch Debian (32 bits) et conda-forge (64 bits) Verify published PyPI release sans aucun checkout : pip install pyscotch wheel-smoke : partition, order, save, doctor, CLI Scotch 7.0.13 / 7.0.12 depuis la tarball, build --parallel, Dgraph sous mpirun -n 2 Chiens de garde hebdomadaires lundi 06:00 UTC : Verify install methods (nouveau Scotch Debian / conda ?) lundi 06:30 UTC : Build Scotch from CLI (tarball upstream déplacée ou régénérée ? les sha256 pinnés le diraient)

8 workflows GitHub Actions. Deux jumeaux : « Build Scotch from CLI » installe depuis le dépôt et garde le code, « Verify published PyPI release » installe depuis PyPI et certifie le paquet publié. L'oracle, à chaque push : les outils de Scotch eux-mêmes, et 14 sorties dorées.

github.com/c4ffein/pyscotch/actions · détail des jobs, matrices et cibles Makefile : pyscotch-pipeline.md

L'arc, en dates — récap

nov. 2025pyscotch, jour 7premier bug upstream, corrigé le jour même
déc. 2025Hypothesis sur le wrappercoloriage invalide → corrigé en janv. 2026
mars 2026Claude relit les tests C de Scotch23 tests reçoivent des assertions
avr. 2026hegel en C, sur le forkpermutation invalide, rc = 0 → corrigé en 10 jours
avr. 2026hegel-cle même bug, retrouvé seul, réduit à 3 sommets
juil. 2026pyscotch 7.0, le balayage6 bugs chez nous, 6 signalements upstream
juil.–août 2026tests différentielsl'oracle, c'est gpart / gord / gmap
août 2026la même tâche, deux foisépilogue

3 commits upstream « [report C. Pellegrini] » · 3 autres corrections tracées à nos signalements · 4 toujours ouverts en v7.0.14

Le bilan — chez Scotch

Bug Méthode Sévérité Upstream
module.h : 12 macros de renommage manquantes
nov. 2025
build 32+64 bits, puis lecturelien impossible en build suffixécorrigé le jour même — f7cd80c ✓ crédité
graphColor : voisins du même passage
déc. 2025
Hypothesiscoloriage invalide, silencieuxcorrigé 15 janv. 2026 — e0a90c7
hgraphOrderCp : off-by-ordenum
avr. 2026
hegel en C, puis lecturepermutation invalide, rc = 0corrigé 15 avr. 2026 — 0642921 + test ✓ crédité
memFree, meshBuildElem hors table de renommage
juil. 2026
vérificateur de signatures7.0.12 ne compile pas en RENAME_ALLcorrigé le lendemain — 770f26e, eef80bd
contextOptionSetNum : switch (optival)
juil. 2026
lecturecascade DETERMINISTIC jamais appliquéeouvert en 7.0.14
contextAlloc hors table de renommage
juil. 2026
balayage library.h / module.hlien impossible en build suffixéouvert
libscotch.so sans NEEDED zlib/libm/pthread
juil. 2026
build des wheelsdlopen échoue en liaison immédiateouvert
8 fonctions publiques absentes des manuels
juil. 2026
génération de la docdocouvert
archDecoArchBuild : mauvais domaines pour les distances
août 2026
?distances faussescorrigé 18 août 2026 — 911ebdf ✓ crédité

La chronologie, dans git

24 août, 21:18l'ingénieur commit son fix sur sa machine — adb2b64 « Bugfix: base treetab in dorderTreeDist() »
25 août, 11:54clone de master depuis mon téléphone : HEAD = 9259939 (5 août). Le fix n'y est pas
25 août, 11:55la tâche de François, collée telle quelle
25 août, 12:09patch + rapport + test MPI poussés. 14 minutes
25 août, 20:50François refactore les deux routines par-dessus la version de l'ingénieur — 2b1a9d8
26 aoûtdorderTreeDist() documentée dans le manuel de maintenance — 410cd12
27 aoûtpush upstream, v7.0.14

Heures de Paris (UTC+2). Aucun des deux n'a vu l'autre : le seul accès réseau de la session vers Scotch est le clone, et le log brut le montre.

Hey! Can you check the gitlab for scotch? Clone it here?
Done — SCOTCH is cloned at ~/playground/scotch. […] I went with the canonical one: the SCOTCH graph partitioning / sparse matrix ordering library from Inria's GitLab.
Noice!
Francois would like some help on this:

<< La tâche à accomplir concerne le logiciel Scotch. À l'heure actuelle, la routine `dorderTreeDist`, dans 'src/libscotch/dorder_tree_dist.c', calcule un tableau `treetab` dont les valeurs ne sont pas "basées", c'est-à-dire commencent toujours à 0 et non à `baseval`, le champ du graphe `grafptr` passé en paramètre, qui n'est actuellement pas utilisé. Modifie le code de `dorderTreeDist` et éventuellement de ses sous-routines afin que le tableau retourné par la fonction soit basé. >>
▶ la session complète (transcript brut)
Create a report in md and a patch, and commit / push on main? What about explaining what was asked, your thought process and how you did the qa?
Done — the fix is written, tested with MPI, and exported as a patch series […]

The change (all in src/libscotch/dorder_tree_dist.c, no sub-routine needed it): […] The root's father value stays -1 regardless of base — that's exactly what the user manual already promised […] and what the ParMeTiS wrapper already assumes at parmetis_dgraph_order.c:178. So this is really the code catching up to its documentation.

Verification — I installed OpenMPI, built libptscotch, and ran a small test ordering a 16-vertex ring:
2 ranks, baseval 1: treetab = [-1, 1, 1, 1]
2 ranks, baseval 0: [-1, 0, 0, 0] — bit-identical to the old behavior.
4 ranks, baseval 1: 10 blocks, [-1, 1, 2, 2, 2, 1, 6, 6, 6, 1]
▶ la session complète (transcript brut)

Le résultat : un patch pour Scotch


          Subject: [PATCH] Base the tree array returned by dorderTreeDist(), as documented

           src/libscotch/dorder_tree_dist.c | 19 ++++++++++++++-----

          +  baseval = grafptr->baseval;
             for (dblkglbnum = 0; dblkglbnum < dblkglbnbr; dblkglbnum ++) {
          -    srt1glbtab[2 * dblkglbnum + 1] = dblkglbnum;
          +    srt1glbtab[2 * dblkglbnum + 1] = dblkglbnum + baseval;
          [...]
          +  treeglbtax = treeglbtab - baseval;   /* TRICK: based accesses to user arrays */
          +  sizeglbtax = sizeglbtab - baseval;
        
github.com/c4ffein-work/playground — patch, REPORT.md, test_treedist.c (25 août 2026) · ▶ la session complète

Le message de commit


          Base the tree array returned by dorderTreeDist(), as documented

          The user manual states that, in the tree array filled by
          SCOTCH_dgraphOrderTreeDist(), "all node indices start from baseval".
          Yet, dorderTreeDist() numbered the permuted column block indices from
          0, ignoring the base value of the distributed graph passed as
          parameter, whose pointer was hitherto unused.

          Father indices stored in the tree array are now based with respect to
          grafptr->baseval, and the result arrays are accessed through based
          pointers so that the entry for column block (baseval + i) remains at
          array slot i. The father index of the root of the tree remains -1,
          irrespective of the base value, as documented. Callers that already
          handled based indices, such as ParMETIS_V3_NodeND(), which subtracts
          the base value from tree array values, are unaffected for the 0-based
          case and now behave correctly for the 1-based case.
        
▶ la session complète

Deux patchs

L'ingénieur (Sonnet 5)Moi (Fable 5, téléphone)
Commitadb2b64, 24 août 21:18patch dans playground, 25 août 12:09
Tempsune journée (dit François)14 min entre le brief et le patch
Fichiers3 (dorder_tree_dist.c, dorder.h, wrapper public)1
Test livrénonoui : programme MPI + rapport
Mergeupstream, v7.0.14jamais : arrivé après

Identique, ligne pour ligne : dblkglbnum + baseval, puis treeglbtax = treeglbtab - baseval. La racine reste à −1. Jusqu'au commentaire /* TRICK: ... */.

Ce qui diffère

L'ingénieur a fait, et pas moi

  • Supprimé le paramètre grafptr devenu inutile : baseval lu sur ordeptr. Prototype et wrapper changés. Moins de surface.
  • Retiré restrict sur cblkdsptab, qui aliasait dblkcnttab dans la même allocation. Un comportement indéfini latent, hors sujet, corrigé au passage.
  • Commenté chaque ligne du tableau de données.

J'ai fait, et pas lui

  • Pris le brief au pied de la lettre : grafptr->baseval, puisque la tâche disait « le champ du graphe grafptr passé en paramètre ». Il a lu l'intention ; j'ai lu le texte.
  • Vérifié avant de conclure : le manuel promettait déjà des indices basés, orderTree() le faisait déjà en séquentiel, le wrapper ParMeTiS soustrayait déjà baseval.
  • Livré une preuve : test MPI sur 2 et 4 rangs, base 0 et 1, bit-identique en base 0.
côte à côte, annotés : treetab-theirs.c / treetab-ours.c (vi -O) · adb2b64 · notre patch

Avis de Fable 5.1

// Claude (Fable 5.1), 8 sept. 2026, après lecture des trois commits — sans accès à la session de l'ingénieur
Deux patchs corrects. Le sien est le meilleur C : moins de surface, un UB en moins. Le mien est le mieux vérifié et le mieux expliqué.
Si je relisais les deux à l'aveugle : je merge le sien, je garde mon test.

Partie 3

Trois changements de paradigme

Mai 2025 — nudge, nudge, nudge...

  • « After that, I only said yes to everything. »
  • « Feels like watching a beginner, but 10x, or even 100x faster. »
  • « Claude ended up making hardcoded modifications specifically to pass the tests »
  • « …easily recognized this mistake once I asked a simple question. »
  • « I fixed the remaining issues myself. »
github.com/c4ffein/pass — chat_history/00-INDEX.md

Mai 2026 - process automatique

  • D'abord une carte : PORTING.md (motifs Zig → Rust) et LIFETIMES.tsv (durée de vie de chaque champ)
  • Puis le port mécanique« Absolutely none of it worked yet »
  • 1 implémenteur, ≥ 2 relecteurs adversariaux : « assume the code is wrong »
    — la réponse au « hardcoded to pass the tests » de 2025
  • 1,3 M+ assertions conservées, zéro test supprimé — les tests sont le contrat
  • Résultat : 128 bugs corrigés, binaire plus léger de 3,8 Mo (Windows) à 6,8 Mo (Linux), 2 à 5 % plus rapide
« This would've taken 3 engineers a year. »
— Jarred Sumner, créateur de Bun
bun.com/blog/bun-in-rust (8 juil. 2026) · github.com/oven-sh/bun/pull/30412

Oracle > Code

RealWorld
  • Un même clone de Medium, 100+ implémentations
  • Je maintiens la spec, les tests et la démo
  • specs/api : openapi.yml + 13 fichiers Hurl (source de vérité)
    → 156 requêtes Bruno, générées, synchro vérifiée en CI
  • specs/e2e : 15 suites Playwright + SELECTORS.md pour les fronts
  • Spec + tests livrés avant l'implémentation ⇒ le port devient automatique,
    vers n'importe quel langage, n'importe quel framework
github.com/realworld-apps/realworld · demo.realworld.show
le visualiseur vibé, avec 120 frames de la capture (#180 → #299) — frame #211 : 61 ms, dont 49 ms de walk

Conséquences pour la recherche

« I think we'll be there in three to six months—where AI is writing 90 percent of the code. And then in twelve months, we may be in a world where AI is writing essentially all of the code. »

Dario Amodei — Council on Foreign Relations, 10 mars 2025

« essentially all » ?..
  • 6 mois plus tard : potentiellement valide
  • Mai 2026 : Bun, 1,3 M de lignes portées en 11 jours
  • 18 mois plus tard : un fix sur Scotch fait depuis mon téléphone, sans relecture
« Thus, it's my guess that powerful AI could at least 10x the rate of these discoveries, giving us the next 50-100 years of biological progress in 5-10 years. »

Dario Amodei — Machines of Loving Grace, octobre 2024

  • 20 mois après l'essai : Claude Science
Claude Science : un balayage d'hyperparamètres à 8 bras envoyé sur les A100 d'un cluster de labo, notebook partagé en direct

Un balayage à 8 bras envoyé sur les A100 du cluster du labo, le notebook partagé avec l'agent, en direct. Le compute, c'est le vôtre.

anthropic.com/news/claude-science-ai-workbench (30 juin 2026) — capture de l'annonce
Claude Science : une revue de littérature, cinq agents en parallèle, un relecteur qui signale un PMID attribué à deux papiers

Cinq agents en parallèle, et un relecteur qui signale un PMID attribué à deux papiers — les relecteurs adversariaux de Bun, version labo.

anthropic.com/news/claude-science-ai-workbench — capture de l'annonce