docs(spec): correct the suppliers migration's expected merge count
19 -> ~16 was wrong. Ran the actual normalizeSupplierName() (trim + whitespace-collapse + uppercase) against the three example pairs cited as evidence: only the case-variant pair (Builders Warehouse) actually collapses. The Ikhasi pair keeps a stray space after a hyphen that differs between variants; the Global Precast pair differs by the "(Pty) Ltd" suffix, not case or whitespace. Neither collapses under exact-normalized matching. This is not a defect -- it's the conservative-matching principle in section 3 working as designed. The correct expectation against production is 19 raw strings -> 18 groups, one merge. Both pairs that don't collapse are exactly the kind of ambiguous case the spec already says should stay separate for a human to resolve, not the kind that should be forced together by loosening the normalizer. Caught while grounding the implementation plan in real data, before writing a single line of the plan itself. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
861cb25f0f
commit
c73a2aad6c
1 changed files with 23 additions and 4 deletions
|
|
@ -21,7 +21,7 @@
|
|||
`purchase_orders.supplier` is free text, written once from whatever OCR
|
||||
extracted off the PO document. Production, checked live on 2026-09-11:
|
||||
**24 purchase orders, 19 distinct raw supplier strings**, of which at
|
||||
least three are the same company under a formatting variant:
|
||||
least three *look* like the same company under a formatting variant:
|
||||
|
||||
```
|
||||
"Builders Warehouse" / "BUILDERS WAREHOUSE"
|
||||
|
|
@ -38,6 +38,24 @@ how much I owe each supplier."* A supplier split across two spellings
|
|||
under-reports what's owed to them by however much sits on the
|
||||
mis-spelled half.
|
||||
|
||||
**Correction, caught while writing the implementation plan:** running
|
||||
the actual `normalizeSupplierName()` defined in §3 against these three
|
||||
pairs shows only the first one — the case variant — actually collapses.
|
||||
`"Ikhasi- Lo-Mkhulu (COD)"` keeps a space after its first hyphen that
|
||||
`"Ikhasi-Lo-Mkhulu (COD)"` doesn't, so trim+whitespace-collapse+uppercase
|
||||
produces two different strings. `"Global Precast"` and `"Global Precast
|
||||
(Pty) Ltd"` differ by more than case or whitespace — the legal suffix —
|
||||
so they don't collapse either. **The honest result against production
|
||||
data is 19 raw strings → 18 groups, one merge, not the "~16" figure
|
||||
originally written here.** This is not a defect in the normalization —
|
||||
it is the normalization working exactly as designed in §3: conservative
|
||||
matching that refuses to guess. The Ikhasi and Global Precast pairs stay
|
||||
as separate `suppliers` records after migration, exactly like the Vula
|
||||
pair, and the operator merges them by hand with full context if they
|
||||
are in fact the same company. Do not "fix" this by adding
|
||||
punctuation/suffix-stripping to the normalizer — that is the fuzzy
|
||||
matching §3 already explains why to avoid.
|
||||
|
||||
---
|
||||
|
||||
## 2. Schema
|
||||
|
|
@ -147,8 +165,9 @@ messages, idempotent).
|
|||
Report the offending PO ids and stop; a human resolves them, same as
|
||||
every guard pattern from the ingestion restructure.
|
||||
|
||||
Expected outcome against today's data: 19 raw strings → ~16 supplier
|
||||
records (3 exact-normalized collapses), 24 POs all linked.
|
||||
Expected outcome against today's data: 19 raw strings → 18 supplier
|
||||
records (1 exact-normalized collapse — the "Builders Warehouse" case
|
||||
variant; see the correction in §1), 24 POs all linked.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -246,7 +265,7 @@ required by this spec.
|
|||
| `normalizeSupplierName` | Case, whitespace, and punctuation variants collapse to the same key; genuinely different names do not. |
|
||||
| `matchSupplier` | Exact match links; no match returns `null` + flag; empty/whitespace input never creates a phantom match. |
|
||||
| `computeSupplierLedger` | Full delivery → outstanding 0. Partial delivery → correct partial value. Over-delivery → negative, not clamped. Unmatched delivery line → counts toward nothing (mirrors `po-fulfilment.test.ts`'s equivalent case). Multiple POs for one supplier → totals sum correctly. |
|
||||
| Migration | Dry-run reports the exact grouping (19 → ~16 given today's data) without writing. Guard fires and aborts on any empty-supplier PO. Idempotent: re-running after a successful apply is a no-op. |
|
||||
| Migration | Dry-run reports the exact grouping (19 → 18 given today's data) without writing. Guard fires and aborts on any empty-supplier PO. Idempotent: re-running after a successful apply is a no-op. |
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue