Appliqué en production : 7 écritures, 1 483,23 EUR, compte courant d'associé
porté de -429,75 à -1 912,98. Grand livre auxiliaire intact — 12 tiers, 15
factures fournisseur, inchangés.
La première approche créait un tiers fournisseur « Radureau Gabriel » et lui
adressait 7 factures. C'était faux : le gérant n'est pas un fournisseur de sa
société, et lui ouvrir une fiche l'aurait fait apparaître au grand livre
auxiliaire, dans les balances âgées et les états de dettes fournisseurs —
l'objection exacte déjà opposée à l'URSSAF dans RUNBOOK_charges_sociales.md,
que j'ai reproduite en la contredisant. L'existant le disait pourtant : les 8
dettes déjà portées au compte courant sont toutes des factures de fournisseurs
RÉELS payées personnellement, le tiers n'étant jamais le gérant.
Le modèle correct est direct. Le compte bancaire CCA1 (id 3) porte le numéro
comptable 45511 et son propre journal ; un paiement divers en sens débit, code
613000 Locations, produit
débit 613000 Locations (la charge)
crédit 45511 G. RADUREAU, compte courant (la dette envers l'associé)
Correction au passage : le plan comptable EST chargé (358 comptes, dont un
455110 dédié au compte courant du gérant). adc-009 affirme « module comptabilité
pas déployé » en confondant trois choses — le plan chargé, l'API REST absente,
et le dictionnaire des types de charges sans code comptable.
Deux bugs de ma main, trouvés en répétition :
- l'idempotence comparait les 24 PREMIERS CARACTÈRES du libellé, or
« Indemnité d'occupation — » en fait exactement 24 : mars reconnaissait
février et se déclarait déjà enregistré. Six mois silencieusement sautés.
On compare désormais le libellé entier, avec tolérance à la troncature
« … » de Dolibarr. recordSocialCharge.ts porte le même défaut, latent :
ses libellés diffèrent avant le 24e caractère, aujourd'hui seulement.
- une boucle shell utilisait `set -- $m`, qui ne découpe pas les mots en zsh :
la date devenait « 2026-- ». Le script a correctement refusé d'écrire.
/variouspayments répond « API not found » : le pipeline gated, qui parle REST,
ne peut pas porter cette opération — comme pour les charges sociales. Le script
en garde la discipline (répétition sandbox, relecture par la liste, opt-in
production explicite) sans le juge ni l'artefact de gate.
Le run gated abandonné est conservé sous fleet/harness/runs/ avec ABANDONNE.md :
il documente ce que le harness a vu, et surtout ce qu'il n'a pas vu.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
fleet/ — the atom registry
The fleet is Arcodange's AI back-office: narrow agents ("atoms") that operate the Dolibarr ERP's daily admin & accounting under the AI back-office PRD. This directory is the registry — the versioned source of truth for what the fleet may do. An atom absent from the registry does not run. Contract semantics come from the PRD atom contract; file syntax from the PRD document surface.
What an atom is
One narrow capability (classify, extract, validate, record, reconcile, report, remind) with a strict I/O contract and deterministic validators around it. The LLM proposes, code disposes: formats, arithmetic, checksums, dedupe and referential integrity are enforced by validators, and a model output that fails validation is quarantined, never auto-corrected. Workflows are compositions of atoms with explicit gates — never one prompt that "does the accounting".
Each atom lives in fleet/atoms/<atom>/:
| File | Role |
|---|---|
atom.yaml |
the registry entry — the contract (schema below) |
prompt.md |
thin runtime prompt, ≤ ~40 lines, extends exactly one class skeleton; no business rules (rules live in fleet/profile/ and in validators) |
scripts/ |
the deterministic implementation: runners, validators, scoring hooks |
Folder name = atom name = registry name — the house <app> join-key discipline
applied to atoms.
Layout
fleet/
├── README.md # this file: registry doc + atom.yaml schema
├── classes/ # the 7 prompt skeletons (PRD agent catalog)
│ ├── sentinel.md
│ ├── extractor.md
│ ├── erp-scribe.md
│ ├── deterministic-controller.md # no-LLM by design
│ ├── analyst-writer.md
│ ├── researcher.md
│ └── knowledge-archivist.md
├── atoms/
│ └── invoice-extract/ # T02 — the worked example (contract only; implementation = erp#40)
│ ├── atom.yaml
│ ├── prompt.md
│ └── scripts/
├── golden/ # per-atom golden sets — land with erp#39
├── profile/ # fiscal.yaml + calendar.yaml + ADC register + validator (profile/README.md)
└── harness/ # multi-runtime harness layer: verifier tests + builder bench (harness/README.md)
atom.yaml — the contract, field by field
Per the PRD atom contract:
| Field | Meaning |
|---|---|
name, version |
Identity. Folder name = name. version bumps on any behavioral change (prompt, model, validator) — a bump re-triggers the atom's golden-set evals. |
input_schema / output_schema |
JSON Schema for the atom's I/O; enforced at runtime (constrained decoding where the model tier supports it). |
invariants |
Deterministic post-conditions checked by code after every run (e.g. HT + TVA == TTC ± 0.01). A failed invariant quarantines the output — refuse, never repair. |
side_effect_class |
read · draft · write-sandbox · write-prod · outbound — drives which gates and credentials apply, per the PRD environment posture table. |
idempotency_key |
How a replay is recognized (e.g. supplier + ref_supplier + TTC) — a second run with the same key must be a no-op. |
autonomy |
The earned level (A0–A3 on the autonomy ladder) + a pointer to the eval evidence that justifies it. |
model_policy |
Preferred tier, fallbacks, escalation rule, per the PRD model fleet; closed per-atom by routing-bench evidence (erp#45 for the first atoms). |
eval_ref |
Where the golden set + scoring script live (fleet/golden/<atom>/). |
Two registry conveniences beyond the PRD contract fields bind the entry to the rest
of the surface: class (which fleet/classes/<class>.md skeleton the prompt
extends) and task (the PRD task-inventory
id the atom serves).
The worked example is atoms/invoice-extract/atom.yaml
(T02) — contract only; its implementation is
erp#40.
How an atom graduates
Autonomy is earned per atom, never assumed. The levels (A0 manual → A1 prepare
→ A2 rehearse + gate → A3 autonomous + audit) are defined on the PRD
autonomy ladder;
promotion and demotion are mechanical, per the PRD
autonomy promotion gates
(golden-set evals, unedited-approval streaks, incident demotion — the bars live
there, not here). The earned level and its evidence are recorded in the atom's
autonomy field: a promotion is a PR that changes that field with the evidence
linked, verified per the QA strategy's independent-verification rule.
Conventions
- English for all agent-facing files (house language policy).
- Same-change freshness: a change to an atom that leaves its
atom.yaml/prompt.mdstale is an incomplete change. - One capability per file; YAML/frontmatter over prose for anything a machine parses.
- Environment rules (trunk hygiene, read-only prod, sandbox-first writes, promote
gate) are the repo-wide ones:
AGENTS.mdoperating rules +dolibarr-sandbox-writeSKILL.md.