arcodange-bank-reco V7: avoir netting + fk_account context + wire-ref matching #8

Merged
arcodange merged 1 commits from claude/arcodange-bank-reco-v7 into main 2026-05-31 14:20:39 +02:00
Owner

Summary

Three improvements to bank-match.sh that collapse the V6.1 exit-1 signal from 10 entries down to 1 genuine action item.

A — fk_account context on dolibarr-only

Fetches /bankaccounts and tags each dolibarr-only entry with its account ref+label. Splits into:

  • on API-tracked accounts (QON*/WIS*) → real gaps, count toward exit-1
  • not in API scope (CCA1 personal etc.) → expected gaps, don't count

The 7 CCA1 supplier payments that previously polluted the failure verdict are now correctly classified.

B — Avoir-cycle netting

Pairs AVC* entries of -X € with FAC* entries of +X € for the same socid within ±5d. Both surface in a dedicated AVOIR-NETTED bucket and are excluded from dolibarr-only (since the bank only sees the net of the cancel-and-reissue cycle). Resolves the V6.1 noise on the FAC001-CL00001 / AVC001-CL0001001 510€ dance.

C — Wire-reference strong matching (opt-in --enrich)

bank-match.sh --enrich fetches /v1/transfers/{id} per Wise TRANSFER and reads the wire reference field. References containing a FAC\d+(CL\d+)? pattern strong-match against the corresponding Dolibarr customer invoice (annotated [wire-ref] instead of [amt+date]).

Verified on FAC002 5100€: KM's wire memo "FROM KISSMETRICS HOLDINGS INC FOR INVOICE FAC002CL0001002/ VENDOR:DEV" gives an unambiguous match — works even if the date drift exceeds --window-days.

Effect on the Jan-May 2026 baseline

V6 V6.1 V7 (this PR)
MATCHED 6 (amt+date) 6 6 (1 wire-ref + 5 amt+date with --enrich)
BANK-ONLY total 8 (mixed) 7 known + 1 UNKNOWN 7 known + 1 UNKNOWN
AVOIR-NETTED 2 (silently absorbed)
DOL-only TRUE GAP 9 (noisy) 9 (noisy) 0
DOL-only EXPECTED 7 (CCA1 personal, correctly classified)
Exit-1 signal 17 entries 10 entries 1 entry (+2147€ KM 2026-05-29)

CLI

bin/arcodange bank match gains the --enrich flag. Help text updated.

V8 prep started in parallel

User is preparing IMAP credentials (Zoho books@arcodange.fr + gabrielradureau@arcodange.fr + Gmail arcodange@gmail.com) for the future arcodange-email-ingest skill. Not part of this PR; see SKILL.md V8 candidates section.

Test plan

  • bin/arcodange bank match --since 2026-01-01 --until 2026-05-31 → 6 matched / 1 internal / 2 avoir-netted / 7 bank-known / 1 bank-UNKNOWN / 0 dol-only-API / 7 dol-only-personal
  • bin/arcodange bank match --since 2026-01-01 --until 2026-05-31 --enrich → FAC002 match annotated [wire-ref] instead of [amt+date]
  • AVOIR-NETTED bucket lists AVC001-CL0001001 ↔ FAC001-CL00001
  • DOL-only API-tracked count = 0; verdict = "1 action item"
  • Secrets-grep on staged diff comes back empty
## Summary Three improvements to `bank-match.sh` that collapse the V6.1 exit-1 signal from 10 entries down to **1 genuine action item**. ### A — fk_account context on dolibarr-only Fetches `/bankaccounts` and tags each dolibarr-only entry with its account ref+label. Splits into: - **on API-tracked accounts** (QON*/WIS*) → real gaps, count toward exit-1 - **not in API scope** (CCA1 personal etc.) → expected gaps, don't count The 7 CCA1 supplier payments that previously polluted the failure verdict are now correctly classified. ### B — Avoir-cycle netting Pairs `AVC*` entries of -X € with `FAC*` entries of +X € for the same `socid` within ±5d. Both surface in a dedicated **AVOIR-NETTED** bucket and are excluded from `dolibarr-only` (since the bank only sees the net of the cancel-and-reissue cycle). Resolves the V6.1 noise on the FAC001-CL00001 / AVC001-CL0001001 510€ dance. ### C — Wire-reference strong matching (opt-in `--enrich`) `bank-match.sh --enrich` fetches `/v1/transfers/{id}` per Wise TRANSFER and reads the wire `reference` field. References containing a `FAC\d+(CL\d+)?` pattern strong-match against the corresponding Dolibarr customer invoice (annotated `[wire-ref]` instead of `[amt+date]`). Verified on FAC002 5100€: KM's wire memo "FROM KISSMETRICS HOLDINGS INC FOR INVOICE FAC002CL0001002/ VENDOR:DEV" gives an unambiguous match — works even if the date drift exceeds `--window-days`. ### Effect on the Jan-May 2026 baseline | | V6 | V6.1 | V7 (this PR) | |---|---|---|---| | MATCHED | 6 (amt+date) | 6 | 6 (1 wire-ref + 5 amt+date with --enrich) | | BANK-ONLY total | 8 (mixed) | 7 known + 1 UNKNOWN | 7 known + 1 UNKNOWN | | AVOIR-NETTED | — | — | **2** (silently absorbed) | | DOL-only TRUE GAP | 9 (noisy) | 9 (noisy) | **0** | | DOL-only EXPECTED | — | — | 7 (CCA1 personal, correctly classified) | | **Exit-1 signal** | 17 entries | 10 entries | **1 entry** (+2147€ KM 2026-05-29) | ## CLI `bin/arcodange bank match` gains the `--enrich` flag. Help text updated. ## V8 prep started in parallel User is preparing IMAP credentials (Zoho `books@arcodange.fr` + `gabrielradureau@arcodange.fr` + Gmail `arcodange@gmail.com`) for the future `arcodange-email-ingest` skill. Not part of this PR; see SKILL.md V8 candidates section. ## Test plan - [ ] `bin/arcodange bank match --since 2026-01-01 --until 2026-05-31` → 6 matched / 1 internal / **2 avoir-netted** / 7 bank-known / **1 bank-UNKNOWN** / **0 dol-only-API** / 7 dol-only-personal - [ ] `bin/arcodange bank match --since 2026-01-01 --until 2026-05-31 --enrich` → FAC002 match annotated `[wire-ref]` instead of `[amt+date]` - [ ] AVOIR-NETTED bucket lists `AVC001-CL0001001 ↔ FAC001-CL00001` - [ ] DOL-only API-tracked count = 0; verdict = "1 action item" - [ ] Secrets-grep on staged diff comes back empty
arcodange added 1 commit 2026-05-31 14:20:31 +02:00
Three improvements that reduce the V6.1 exit-1 signal from 10 to 1 on
the current Arcodange baseline. Every bucket now has a single, clear
purpose; the only entry counted as a failure is a genuine action item.

A. fk_account context on dolibarr-only
   - Fetches /bankaccounts and tags each dolibarr-only with the account
     ref + label (e.g. "CCA1 (G.RADUREAU Compte Courant Asso)").
   - Splits dolibarr-only into "on API-tracked accounts" (QON*/WIS* — real
     gaps) vs "not in API scope" (CCA1 / personal — expected gaps).
   - Personal-account entries no longer count toward the failure verdict.

B. Avoir-cycle netting
   - Pairs AVC entries of -X on socid S with FAC entries of +X on the
     same socid within ±5d.
   - Both surface in a dedicated AVOIR-NETTED bucket and are excluded from
     dolibarr-only, since the bank only sees the net of the cycle.
   - Resolves the V6.1 noise where AVC001-CL0001001 + FAC001-CL00001
     appeared as fake gaps for a 510€ cancel-and-reissue dance.

C. Wire-reference strong matching (--enrich flag, opt-in)
   - When --enrich is passed, bank-match.sh fetches /v1/transfers/{id}
     per Wise TRANSFER and reads the wire `reference` field.
   - References containing a FAC\d+(CL\d+)? pattern strong-match against
     the corresponding Dolibarr customer invoice (annotated [wire-ref]
     vs the loose [amt+date] kind).
   - Verified on FAC002 5100€: KM's wire memo "FOR INVOICE FAC002CL0001002"
     gives an unambiguous match independent of date drift.

Baseline (Jan-May 2026, --enrich on):
  6 matched · 1 internal · 2 avoir-netted · 7 bank-known · 1 bank-UNKNOWN
  0 dol-only-API · 7 dol-only-personal
  → exit-1 count = 1 (just the +2147€ KM Wise 2026-05-29 to record).

The CLI (bin/arcodange) gains --enrich on the match subcommand. The
SKILL.md has a new "V7 bucket structure" section explaining the seven
buckets and a before/after table showing the signal/noise improvement.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
arcodange merged commit a1042a483b into main 2026-05-31 14:20:39 +02:00
arcodange deleted branch claude/arcodange-bank-reco-v7 2026-05-31 14:20:40 +02:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: arcodange-org/erp#8