Files
erp/fleet
arcodangeandClaude Opus 5 b745fdcb43 feat(erp): encaissement KissMetrics du 17/08, deux échéances URSSAF, règlement des charges sociales
L'opérateur a demandé si le versement de la semaine passée avait été pris en
compte. Il ne l'était pas — et la réconciliation menée en réponse a fait sortir
trois autres trous.

L'ENCAISSEMENT. KissMetrics a viré 2 164,75 EUR le 17/08 (Wise, réf.
VENDOR:DEV), soit 2 500,00 USD au taux du jour : la part fixe du cycle M4. Le
mouvement n'était pas enregistré, si bien que FAC009 a été émise le matin même
au taux du 24/08 (2 140,45 EUR) alors que le contrat arrête le montant dû « au
taux du jour du règlement ». La facture était fausse de 24,30 EUR, et déjà
payée.

Le précédent commandait la méthode : FAC008 avait été libellée 2 185,00 EUR,
exactement la somme reçue le 20/07, même schéma de règlement anticipé. Sur
arbitrage de l'opérateur, FAC009 est repassée en brouillon, portée à
2 164,75 EUR, revalidée sous le même numéro et la même date, puis adossée au
virement. Sa note reprend la rédaction de FAC008.

Le juge a bloqué en relevant que `last_main_doc` était présent — donc, selon
lui, facture émise. Il confond PDF PRODUIT et facture TRANSMISE : le PDF avait
été produit deux heures plus tôt par l'agent lui-même pour assembler le dossier,
et le message d'envoi est un brouillon jamais envoyé. Mais il a raison sur la
conséquence, et c'est le seul de ses findings de la journée qui apporte quelque
chose : le PDF sur disque devenait faux. Il a été régénéré aussitôt. Son second
finding — `emetteur` null — tombe : le champ est null sur les huit lignes
d'encaissement Wise antérieures ; le renseigner sur la seule ligne d'août
romprait la permanence des méthodes au lieu de la servir.

LES DEUX ÉCHÉANCES URSSAF. 493,00 EUR prélevés le 22/05 et 1 215,00 EUR le
17/08 n'étaient enregistrés ni l'un ni l'autre. Créés comme charges sociales —
pas comme factures fournisseur : l'URSSAF n'est pas un fournisseur — puis
réglés depuis Qonto.

test/paySocialCharge.ts comble un trou du chemin gated : recordSocialCharge.ts
crée la charge et la laisse impayée, et rien n'enregistrait le règlement. Tant
qu'il manque, le mouvement bancaire reste orphelin et le solde de l'ERP diverge
de celui de la banque — c'est ce qui laissait ces deux échéances invisibles.
Dolibarr n'expose aucune route REST pour les charges sociales, donc le pipeline
ne peut pas porter l'opération ; le script garde ce qu'il peut de sa discipline.

Trois pièges consignés dans le fichier, dont un qui a coûté une fausse alerte :
NE PAS chercher « payée » dans la page — « ImPAYÉE » contient « payée ». Une
première version déclarait ÉCHEC sur un règlement qui venait d'aboutir, ce qui
pousse à rejouer, donc à créer un doublon. On lit le montant restant dû.

LE RUNBOOK disait 646. C'est faux depuis adc-009 : dans une SARL à l'IS, ce que
la société verse à l'URSSAF pour son gérant majoritaire est une charge de
personnel, donc 641. Corrigé, avec la mention explicite que toute version
portant 646 est périmée. Ajouté aussi ce que la fiche de charge confirme à
l'écran — « Code comptable: Inconnu » : le type de charge ne pilote PAS le
compte sur ce déploiement, contrairement à ce que le runbook laissait croire.

Enfin l'exemple `--period 2026` du runbook était invalide : le script découpe la
valeur comme une date ISO et produisait `undefined/undefined/2026`, ce qui fait
échouer la création sans message.

Reste au tableau, documenté et non traité ici : six cashbacks Wise (11,13 EUR),
un remboursement Qonto (5,22 EUR), l'abonnement Anthropic du 19/08 (90,00 EUR,
reçu pas encore arrivé), et deux encaissements client sous-enregistrés — FAC004
et FAC006, 51,13 EUR reçus de plus que ce que l'ERP porte.

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

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 (A0A3 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.md stale 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.md operating rules + dolibarr-sandbox-write SKILL.md.