Skip to content

fix(oracle): probe validators with their real lengths#107

Merged
jan-kubica merged 4 commits into
mainfrom
worktree-modular-finding-steele
Jun 3, 2026
Merged

fix(oracle): probe validators with their real lengths#107
jan-kubica merged 4 commits into
mainfrom
worktree-modular-finding-steele

Conversation

@jan-kubica
Copy link
Copy Markdown
Contributor

Summary

  • inferArb in the oracle script fell back to digs(10) whenever a validator omitted lengths, 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 reported 0 disagreements / 0 valid — every random sample failed the length check before any checksum logic ran.
  • Two fixes:
    • Structural: inferArb now derives lengths from examples (in compact form) when lengths is undeclared. Covers 89/170 validators automatically.
    • Explicit: added lengths to the gate-affected validators above so the contract is self-documenting.
  • Proper coverage exposed real cross-impl differences (jsvat skips no-leading-zero/checksum/province checks; stdnum-js NL matches Onderwijsnummer; stdnum-js doesn't model 21st/22nd-century LT/RO gender digits). python-stdnum agrees with us on every newly-disagreeing sample, so those pairings move to the existing survey tier with notes.
  • Fixed a real bug uncovered along the way: ro.cnp accepted county codes 49 and 50 which aren't allocated per cnp-spec (40–48 cover Bucuresti sectors; 51–52 are Calarasi/Giurgiu).
  • Gate result: 250,000 samples across 25 pairings, 0 disagreements.

Test plan

  • bun test (4239 pass)
  • bun run oracle (gate clean)
  • CI passes

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.
@gemini-code-assist
Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread scripts/oracle.ts
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).
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread src/gb/vat.ts Outdated
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.
@jan-kubica jan-kubica merged commit 3023867 into main Jun 3, 2026
7 checks passed
@jan-kubica jan-kubica deleted the worktree-modular-finding-steele branch June 3, 2026 15:35
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 3, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant