fix(oracle): probe validators with their real lengths#107
Conversation
The oracle's `inferArb` fell back to `digs(10)` when a validator
omitted `lengths`, so the gate fed 10-digit strings to 8-digit (and
other) formats. 89/170 validators are affected; about ten of them
sit behind gate-tier oracle pairings and silently reported "0
disagreements / 0 valid" because every random sample failed the
length check before reaching the checksum.
Two fixes:
* `inferArb` now derives lengths from `examples` (in compact form)
when `lengths` is undeclared, so every validator with seed
examples gets coverage at its actual length.
* The gate-tier validators that were broken get explicit
`lengths`: dk.vat, fi.vat, hu.vat, lt.vat, lu.vat, mt.vat,
pt.vat, ro.cnp, se.vat, si.vat.
Proper coverage exposes real cross-implementation differences that
the broken arbs were hiding. python-stdnum (the canonical reference)
agrees with us on every newly-disagreeing sample, so the affected
jsvat/stdnum-js pairings move to survey tier with explanatory notes:
* jsvat:{dk,fi,gr,mt,pt}.vat and jsvat:it.iva — jsvat skips
no-leading-zero, checksum, or province-code rules required by
the official country sources.
* stdnum-js:nl.bsn — stdnum-js's `validatePerson("NL", ...)` also
matches Onderwijsnummer, returning valid for non-BSNs.
* stdnum-js:{lt.asmens,ro.cnp} — stdnum-js does not model the
21st/22nd-century gender digits the same way the official specs do.
Also fixes a real bug in ro.cnp uncovered along the way:
`VALID_COUNTIES` listed 49 and 50, which are not allocated county
codes per cnp-spec (40-48 cover Bucuresti sectors, 51-52 are
Calarasi/Giurgiu; 49 and 50 are gaps).
Gate result: 250,000 samples across 25 oracle pairings, 0
disagreements.
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0ff81eb56d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Addressing Codex review on PR #107: the example-based length fallback under-probes validators whose `candidatePattern` spans a range wider than the example set. ro.vat is the canonical case (accepts 2-10 digits; only example is 8 digits), so the gate was only sampling `digs(8)` (plus 7/9 edge cases) and never exercising the 2-7 or 9-10 length paths. Declares explicit `lengths` on the variable-length validators that previously relied on the example fallback: * ro.vat — [2..10] * bg.vat — [9, 10] * cz.dic — [8, 9, 10] (cz.dic also has a CUSTOM_ARB; the lengths field is informational for non-oracle consumers) * gb.vat — [9, 12] (digit-only standard format; GD/HA letter prefixes are handled directly by `validate`) Also updates the `lengthsFromExamples` comment to flag that the fallback is only reliable for fixed-length validators. Gate result unchanged: 0 disagreements; ro.vat now probes the full digit-length range (895/10000 valid).
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8305888af3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Addressing Codex follow-up on PR #107: gb.vat's `validate` also accepts letter-prefixed GD/HA government and health-authority forms (5 chars). Putting `lengths: [9, 12]` on the validator made the public metadata incomplete and changed `toRegex(gb.vat)` from the grouped form (`GB[\s\-./]?\d{3}[\s\-./]?\d{4}[\s\-./]?\d{2}`, which matches both "GB980780684" and "GB 980 7806 84") to a flat `GB[\s\-./]?\d{9,12}` that no longer matches the spaced form. Reverts `gb.vat.lengths` and adds a CUSTOM_ARB entry in oracle.ts so the oracle still probes the mod-97 digit path at lengths 9 and 12 without leaking the constraint into consumer-facing metadata.
Summary
inferArbin the oracle script fell back todigs(10)whenever a validator omittedlengths, so ~10 gate-tier oracle pairings (dk.vat, fi.vat, hu.vat, lt.vat, lu.vat, mt.vat, pt.vat, ro.cnp, se.vat, si.vat, plus iban) silently reported0 disagreements / 0 valid— every random sample failed the length check before any checksum logic ran.inferArbnow derives lengths fromexamples(in compact form) whenlengthsis undeclared. Covers 89/170 validators automatically.lengthsto the gate-affected validators above so the contract is self-documenting.ro.cnpaccepted county codes 49 and 50 which aren't allocated per cnp-spec (40–48 cover Bucuresti sectors; 51–52 are Calarasi/Giurgiu).Test plan
bun test(4239 pass)bun run oracle(gate clean)