L'extraction de champs vivait dans un heredoc à l'intérieur d'email-inspect.sh : impossible à exécuter isolément, donc jamais mesurée, donc fausse sans que personne puisse le voir. Sur la facture Darnis F1048 elle renvoyait le numéro de TVA d'Arcodange comme référence de facture, et aucune date. - extract_fields.py : l'extraction sort du shell et devient un module. - test_extract.py : régression contre les 16 factures hand-vérifiées de fleet/golden/invoice-extract/. Score par champ, et une valeur FAUSSE pèse plus qu'une valeur absente — un humain recopie ce qui s'affiche. Valeurs fausses : 4 → 0. Exactitude ref 62,5 → 75 %, date 62,5 → 75 %, HT 68,8 → 75 %, TTC 81,2 → 93,8 %. Cinq bugs réels, dont trois invisibles sans test : - « Nº » sur les factures françaises est U+00BA (ordinal masculin), pas le signe degré. La classe [°o] le rate, le motif principal échoue, et le repli attrape le premier jeton ref-shaped du document — très souvent un numéro de TVA. - Le filtre anti-TVA rejetait « FR73261832 », qui est la vraie référence OVH : un numéro FR fait exactement 11 caractères après le préfixe. - « Montant total (HT) » était lu comme un TTC. - Une référence coupée par la colonne (« 06-01-26- » / « payment-366753 ») était renvoyée amputée : le recollage doit précéder le scan, sinon la queue seule est trouvée en premier. - Un `\b` après `€` ne peut jamais matcher en fin de ligne (€ n'est pas un caractère de mot) — la TVA n'était jamais extraite. adc-008 : une facture fournisseur s'enregistre à SA date, même future, tant que l'exercice (année civile) ne bascule pas. Le document fait foi ; altérer sa date ferait diverger l'écriture de sa pièce justificative (CGI art. 289 VII). Registre validé : 8 règles, 8 ADC, 0 erreur. scopes.ts : 1232 (factures fournisseur) ajouté à prod-write — oubli initial, révélé par un 403 en production sur F1048. Le pipeline s'est arrêté sans écrire. Appliqué en production via le pipeline gated : FAF2026014 (Darnis F1048), 218,50 HT + 43,70 TVA = 262,20 TTC, validée, non réglée. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01VRShc4QhLLU73FLHx9vskh
fleet/profile/ — fiscal profile, compliance calendar, ADC register
The machine-readable business-rules surface the fleet reads (T10 TVA preparation, T03 VAT ventilation, T11 calendar & reminders): prompts stay thin and rule-free (fleet/README.md); the rules live here, dated and justified. Shipped by erp#54 per the PRD document surface and ADC framework.
Layout
| File | Role |
|---|---|
fiscal.yaml |
fiscal profile: entity, VAT position, rules — regime, VAT treatments, bookkeeping methods |
fiscal.schema.json |
JSON Schema for fiscal.yaml |
calendar.yaml |
compliance calendar: dated obligations the T11 reminder loop (erp#60) reads |
calendar.schema.json |
JSON Schema for calendar.yaml |
scripts/validate.py |
stdlib-only validator: schema + referential integrity (rule → ADC) |
decisions/ |
the ADC register (accounting decision records): adc-template.md + adc-NNN-<slug>.md |
The rule contract
Every fiscal.yaml rule carries:
effective_from/effective_until— dated validity (nulluntil = in force until superseded);decision: adc-NNN— the record indecisions/that justifies it.
So the chain écriture → règle → ADC → base légale resolves in four hops,
identically every time (PRD compliance § ADC rule 2, challenge C6). Dates in
both YAML files cite their source anchor as an inline comment (PRD <leaf> § <anchor>, verified against factory origin/main).
The ADC register (decisions/)
MADR-lite + accounting fields — see adc-template.md.
Frontmatter is machine-parsed (id, status, decided, effective dates,
supersedes/superseded_by); the body carries Context (fait générateur),
Decision, Base légale & doctrine, Alternatives rejected, Consequences,
QA & validation, References.
Status flow: Proposed → Accepted → Superseded-by-NNN, with four rules (PRD compliance § ADC):
- Immutable once Accepted (merged on main) — supersede, never edit (permanence des méthodes, PCG art. 121-5).
- Every fiscal.yaml rule cites its ADC — enforced by
scripts/validate.py, which also refuses a rule citing a non-Accepted record. - The annexe writes itself at close from the records Accepted and in force during the exercice.
- Proposed ADCs are the expert-comptable agenda. Agents draft, the operator Accepts — never the reverse.
Seed state: adc-001…005 are Accepted as formalizations of decisions the operator already made in practice (their sanity read is the erp#54 human gate — pre-merge amendments are draft edits, not supersedes); adc-006/adc-007 are Proposed stubs (retainer currency → erp#53; capital path → erp#51).
Validation
python3 fleet/profile/scripts/validate.py
Stdlib-only (no PyYAML, no jsonschema — runs anywhere, CI-able). It checks:
both YAML files against their schemas; every rule's decision resolves to
exactly one existing, Accepted ADC; unique ids; effective_from <= effective_until; calendar entries carry exactly one of due|recurrence
(unless pending-definition/conditional); ADC frontmatter/section hygiene.
Exit 0 = pass; warnings list what awaits operator verification
(month-precision dates, estimated entries).
To stay parseable, both YAML files are written in a strict subset: block
maps/lists, single-line scalars, one-line [flow] lists of scalars,
comments — no anchors, no multi-line scalars, no nested flow.
Calendar date precision: YYYY-MM-DD = exact; YYYY-MM = month window — the
source gives no day; verify on the authority's notice, never invent one.
Mutation policy
Changes arrive as PRs only — the T12 regulatory watch proposes a diff (what changed, source links, effective dates); a human reviews and merges (PRD task-inventory § T11 guardrail: "the calendar file is reviewed like code"; § T12: "the watch proposes, the human adopts"). Calendar entries sourced from mail content are human-confirmed (mail is untrusted input). No agent edits these files directly. A rule change moves its ADC in the same PR (supersede, never edit), and a schema change moves the validator with it — the repo-wide same-change freshness rule.
Facts not corroborated by the PRD
Flagged here honestly (and inline where used) — the PRD wins on conflict; these await operator/expert verification:
- SIREN 999657455 — from erp#54 + agent memory
arcodange-tva-fiscal; no PRD leaf states it. - Exact incorporation day — PRD says "mid-January 2026" only; rules use a
conservative
2026-01-01exercice-start bound. - July 2026 acompte exact day — PRD gives the month only (T10 trigger).
- CFE exact day + creation-year exoneration / initial 1447-C declaration — PRD says "December" only; the rest is to verify with the SIE.
- CA3 July/October/January windows — only the April window is PRD-anchored (roadmap, 2027-04-20); the others come from the erp#54 issue text.
- TVA credit amount (~223–267 EUR) — ERP reads (skill + memory); the PRD only says "in TVA credit — verify, don't assume".
- URSSAF échéancier cadence/nature — one known debit (2026-05-22, 493.00 EUR, erp#57); the PRD's "payroll dormant" assumption is under revisit in erp#57.
- BOI-BIC-CHG-20-30-10 tolerance cite (adc-003) and CCA formalities (adc-005) — general doctrine, queued for the expert-comptable.