Files
erp/fleet/harness
arcodangeandClaude Opus 5 62fdd2325b feat(erp): les deux comptes bancaires tombent au centime — reprise FAC004/FAC006, réparation FAC009, cashbacks
Suite de la réconciliation ouverte par la question de l'opérateur. Après ce
passage, l'ERP et la banque disent le même chiffre sur les deux comptes :
Qonto 2 013,30 EUR et Wise 11 863,85 EUR, écart 0,00.

CE QUI A DÉBLOQUÉ LE RESTE. L'opérateur a établi que KissMetrics n'a JAMAIS reçu
la moindre facture — le client payait le forfait de 2 500 USD sans pièce. Rien
ne s'opposait donc à corriger des factures qu'on croyait entre ses mains.

FAC004 et FAC006 portaient toutes deux 2 145,92 EUR, le même montant repris tel
quel d'un cycle à l'autre, alors que la banque a reçu 2 147,00 EUR le 29/05 et
2 195,97 EUR le 25/06 : 2 500 USD à chaque fois, au taux du jour du paiement.
51,13 EUR d'encaissement manquaient aux livres. Leurs notes qualifiaient déjà
l'écart d'« écart de change » — défendable tant qu'on ne pouvait pas toucher aux
factures ; plus vrai maintenant qu'on le peut. Une facture, un règlement, une
ligne bancaire, le même chiffre.

RÉPARATION DE FAC009. `PUT /invoices/{id}/lines/{lid}` n'est PAS un PATCH : tout
champ absent du corps est remis à zéro. La correction appliquée ce matin ne
passait que subprice, pu_ht, qty et desc — `product_type` est donc retombé de 1
(service) à 0 (produit), faisant de FAC009 la seule ligne du registre typée
« produit » dans une société qui ne vend que des prestations et facture hors UE
sous l'art. 259-1° du CGI. Rétabli.

C'est le juge pré-gate qui l'a vu, sur la répétition de FAC004 et FAC006 — où le
même appel avait en plus effacé `desc` ENTIÈREMENT. Premier finding de la
journée qui apporte quelque chose de réel, et il aurait envoyé au client deux
factures sans désignation. Les charges de ligne sont désormais complètes.

test/deleteInvoicePayment.ts. Corriger une facture encaissée suppose de refaire
son règlement, et l'API REST ne sait pas le supprimer : `PUT
/invoices/{id}/payments` ne met à jour que son NUMÉRO. Deux verrous dans
l'interface, consignés dans le fichier : tant que la facture est marquée payée
le lien de suppression est simplement ABSENT — pas d'erreur, rien — il faut
d'abord la rouvrir ; et la confirmation est une boîte MODALE jQuery dont les
boutons n'ont ni name ni value, si bien qu'un sélecteur sur input[type=submit]
ne trouve rien et que la suppression n'a pas lieu, silencieusement. Sans
--payment, le script retrouve le règlement sur la fiche : coder en dur un
identifiant relevé en bac à sable est une façon commode de supprimer le mauvais.

ABONNEMENT ANTHROPIC D'AOÛT. 90,00 EUR du 19/08, reçu 2330-6710-2536 arrivé dans
books@ le 24/08. Second abonnement à usage interne, distinct du budget IA client.

CASHBACKS WISE — compte 768. Wise parle de « remise », mais le montant suit le
SOLDE et non les frais : 0,19 EUR sur ~510 EUR en mars, 4,97 EUR sur ~9 700 EUR
en août, soit ~0,5-0,6 % l'an, stable. C'est la rémunération d'un solde, donc un
produit financier. Le seul frais Wise de l'exercice est le forfait de 50 EUR du
26/01, sans rapport. Ni 763, qui vise les revenus de créances commerciales, ni
764, réservé aux valeurs mobilières de placement : 768.

RISTOURNE QONTO — compte 627 au crédit. L'opération est typée `qonto_fee` par la
banque elle-même, côté crédit : une remise sur un service reçu vient en
diminution de la charge, elle ne crée pas un produit.

PIÈGE CATALOGUÉ. bank-match.sh continuera d'afficher ces sept écritures en
BANK-ONLY : il ne rapproche que les RÈGLEMENTS de factures et ignore les
paiements divers. Les voir listées ne veut donc PAS dire qu'elles manquent —
c'est écrit dans known-patterns.json, sans quoi le prochain agent les
ressaisirait.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-24 13:12:49 +02:00
..

fleet/harness/ — the multi-runtime harness layer

The harness is the orchestration layer around the atoms: builder sessions that execute backlog issues, cold verifiers that check them (locate-tests, backlog audits, refutation passes), and the evidence flow into Gitea. Per the PRD model-fleet harness portability (operator direction 2026-07-15), this layer must not have Anthropic as a hard dependency: the same loop runs on Mistral (vibe -p, mistral-medium-3.5) or on hermes-served local models (Ornith / MLX, 127.0.0.1:18080). Claude is an escalation tier, not a prerequisite. Admission of a runtime to a role is evidence-gated (erp#63): verifier roles first, scoped builders benched second, and no acceptance gate is ever relaxed for a cheaper runtime.

Layout

Path Role
verifier/locate-test.md canonical locate-test: prompt, inputs, ground truth, pass rule
verifier/backlog-audit.md canonical cold-reader backlog audit: prompt, inputs, rubric
bin/run-verifier.sh run a verifier test against a runtime; emits a JSON transcript
bin/vibe-builder.sh run a scoped builder bench (vibe -p) inside a worktree, with caps + journal
runs/<date>/ committed evidence transcripts, when they back an issue comment

Runtimes

Runtime How the harness reaches it Typical role
claude a context-free subagent in a Claude Code session, given the exact assembled prompt (run-verifier.sh <test> --print-prompt) and nothing else baseline verifier; multi-file builder (default per the PRD complexity ceiling)
ornith hermes MLX server, OpenAI-style POST /v1/chat/completions on 127.0.0.1:18080, model leonsarmiento/Ornith-1.0-35B-5bit-mlx verifier (candidate)
mlx --model <id> same endpoint, any model the server lists under /v1/models verifier (candidate)
mistral vibe -p programmatic mode, tools disabled, model = the vibe active_model (today mistral-medium-3.5) verifier (candidate); scoped builder via vibe-builder.sh

Verifier protocol — no self-grading

  1. Assemble the prompt from the canonical test file + the pinned input documents (run-verifier.sh embeds file contents verbatim and records their sha256).
  2. Run every candidate runtime on the same assembled prompt, temperature 0.
  3. An independent, context-free judge (never the session that built the thing, per the PRD qa-strategy) scores each transcript against the test's ground truth and emits the parity table. A runtime is admitted to verifier duty when it reaches verdict parity with the Claude baseline on both tests.
  4. Once a non-Claude verifier is admitted, prefer cross-family verification: the verifier SHOULD be a different model family than the builder — a foreign family refuting the builder is stronger evidence than the builder's own family agreeing with itself.

Builder bench protocol

vibe-builder.sh runs one tightly-footered backlog issue end-to-end under a non-Claude runtime, against the unchanged Execution footer and acceptance gates. It measures completion, intervention count and wall-clock; a failed bench is a valid result — it sets the complexity ceiling honestly. Safety bounds:

  • refuses to run anywhere that is not a linked worktree (never the trunk — same structural-guard pattern as dol-write.sh);
  • hard caps: --max-turns and --max-price are always set;
  • --auto-approve is acceptable only because the blast radius is bounded: a disposable worktree, read-only API credentials, and the caps above;
  • the full vibe JSON journal is kept per run.

Recurring tasks on the Mistral tier

A recurring task (T11 reminders, T13 drift checks, T14 backup freshness) is a scoped builder with a standing prompt: cron (hermes cron or the operator's scheduler) calls vibe-builder.sh <worktree> <task-prompt.md> and routes the journal into the digest. The task prompt lives with the atom (fleet/atoms/<atom>/prompt.md + its class skeleton); the harness only supplies the bounded execution shell. No recurring task writes outside its worktree, and anything ERP-write-shaped still goes through the sandbox + promote gate — runtime choice never changes the gates.