a8b27d2996d21797a7c906b98d36d046bf1c06dd
3
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
4d1e3ecb23 |
fix(email-ingest): extraction testable et pinnée au golden set + adc-008
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 |
||
|
|
1d38f25c23 |
arcodange-email-ingest V8.1: filter calendar invites + newsletter senders
email-list.sh gains two hard-exclusion filters (applied before the candidate test, regardless of attachments): - EXCLUDE_PATTERN matches subjects starting with Invitation: / Updated invitation: / Canceled event: / Accepted: / Declined: / Tentative: / Maybe: (after stripping Re:/Fwd:/Tr: prefixes). Filters Google Calendar events that always carry an .ics attachment. - EXCLUDE_SENDER matches updates.<domain>, noreply@*calendar, news@, newsletter@. Filters newsletter blast traffic. Effect on --all-folders --candidates-only baseline: 27 noisy → 12 actionable (calendar invites + the staying-ahead.ai newsletter blast removed). Real supplier docs intact: Darnis F1042 in /Notification, 3 Free Mobile factures in /Inbox/abonnements, Mistral + Anthropic in /Inbox/books. The originally-planned --mark-ingested feature is deferred to V8.2: flag-set requires the Zoho OAuth scope ZohoMail.messages.UPDATE which our read-only refresh_token doesn't have. Documented in SKILL.md: once the user opts in to the wider scope, --mark-ingested becomes a one-line flag on email-inspect.sh and is_candidate() learns to skip flag_info messages. Captured the new --all-folders baseline at examples/email-list-all-folders.txt. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]> |
||
|
|
c2d8479f5e |
add arcodange-email-ingest — Zoho Mail → Dolibarr supplier-invoice drafts
V8 — first inbound-side skill. Closes the loop from "bill arrives by email"
to "ready to enter in Dolibarr UI". Read-only at every layer.
What ships:
- arcodange-email-ingest/scripts/zoho-curl.sh OAuth wrapper with token cache
(50 min TTL, mode 600) — avoids
hitting Zoho OAuth rate limit on
every invocation.
- arcodange-email-ingest/scripts/email-list.sh List candidates in /Inbox/books
(where the books@ alias auto-
routes mail). --candidates-only
filter on supplier patterns or
attachments. --all-folders to
scan everything.
- arcodange-email-ingest/scripts/email-inspect.sh Pull message + attachments,
pdftotext on each PDF, heuristic
extract (supplier, ref, dates,
totals, VAT rate), emit Dolibarr
supplier-invoice draft JSON.
Architecture choice — Zoho API (not IMAP):
- [email protected] is an alias of [email protected] → one OAuth
refresh_token covers everything.
- Gmail folded in via forwarding ([email protected] → books@) — no Google
API setup, no app-passwords, no second OAuth flow.
- Token-based auth, no SCA rabbit hole.
V8.0 baseline (in /Inbox/books):
- 3 candidates: Mistral AI facture, Anthropic Stripe receipt (Fwd Gmail),
INPI payment receipt (Fwd Gmail).
- Heuristic extraction is best-effort: works on amounts/refs for some
templates, misses others (Mistral PDF format, Stripe receipt layout).
- --save-pdf <DIR> lets the operator grab the PDFs for manual entry when
the heuristic falls short.
Rate-limit pitfall documented: Zoho OAuth refresh has an aggressive throttle
("too many requests continuously"). The cache file at $TMPDIR/zoho-access-$USER
(mode 600, 50 min TTL) prevents this; on 401 the wrapper auto-refreshes once
and retries.
V8.1+ ideas in SKILL.md out-of-scope:
- mark ingested emails (IMAP flag or Zoho label)
- body text extraction (inline-HTML invoices)
- per-template parsers or LLM-based extraction
- IMAP fallback for non-Zoho mailboxes
CLI: bin/arcodange email {list|inspect|curl} integrated.
Base updates: dolibarr/SKILL.md cross-link, dolibarr/README.md env schema
extended with ZOHO_CLIENT_ID/SECRET/REFRESH_TOKEN/DC.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
|