einvoice / Parity board
Parity board: does the checker still agree with the official rules?
Last run: . Every figure below comes from that run of parity_board.py, which grades the same invoices with our pure-Python engine and with the official Schematron (run through Saxon) and counts where the two verdicts differ. No figure on this page is typed by hand; no run, no update.
This run
| Leg | Official ruleset (vendored) | Agreement | Comparisons | Divergences |
|---|---|---|---|---|
| EN 16931 core | CEN EN16931-UBL Schematron 1.3.16 (last update 2026-03-30) | 100% | 250,201 of 250,201 agree | 0 |
| XRechnung BR-DE (German CIUS) | KoSIT XRechnung Schematron 2.5.0 (for XRechnung 3.0.2, compiled 2026-02-04) | 100% | 81,092 of 81,092 agree | 0 |
Corpus: 1,200 distinct invoice documents across both legs. Engine: einvoice 0.2.10, 297 business rules in total (the rule_count that einvoice info reports).
What “agreement” means here
One comparison is one (invoice, rule) pair. It agrees when both sides fire the rule on that invoice, or both stay silent. So the denominator is graded invoices × rules compared, and a single wrong verdict on one invoice costs exactly one comparison.
Most pairs agree because both sides stay silent, and a rule that never fired at all would score well on silence alone. The row that guards against that is both fired: how many of the agreeing pairs are real violations that the official Schematron and the engine both reported. The corpus contains targeted mutations (each breaks exactly the field one rule guards) so that rules are exercised in the failing direction as well.
EN 16931 core
| Official ruleset | CEN EN16931-UBL Schematron 1.3.16 (last update 2026-03-30) |
|---|---|
| Invoices assembled | 1,153 |
| Invoices graded | 1,153 |
| Skipped (a side could not process the file; excluded from the counts) | 0 |
| Rules compared | 217 |
| Agreement | 250,201 / 250,201 = 100% |
| Both fired (true-positive agreements) | 17,273 |
| Rules the official side fired at least once | 217 of 217 |
| Held out of this leg | BR-DEC-13, BR-DEC-15 (at most 2 decimals on the invoice total VAT amount). In the vendored UBL Schematron these two asserts carry a predicate that can never match, so they never fire; the engine checks the intended rule anyway, which would count as a false positive on every violating invoice. Both rules are compared on the CII leg, where the official test works. |
Divergences by rule id
None in this run: on every graded invoice, for every compared rule, the engine and the official Schematron gave the same verdict.
XRechnung BR-DE (German CIUS)
| Official ruleset | KoSIT XRechnung Schematron 2.5.0 (for XRechnung 3.0.2, compiled 2026-02-04) |
|---|---|
| Invoices assembled | 1,069 |
| Invoices graded | 1,067 |
| Skipped (a side could not process the file; excluded from the counts) | 2 — cen-unit/BR-CL-23#t0: the official Schematron raised an error; cen-unit/BR-CL-23#t1: the official Schematron raised an error |
| Rules compared | 76 (55 XRechnung CIUS rules: BR-DE, BR-DEX, BR-TMP, CVD; plus 21 Peppol rules that KoSIT bundles into the same Schematron) |
| Agreement | 81,092 / 81,092 = 100% |
| Both fired (true-positive agreements) | 7,087 |
| Rules the official side fired at least once | 76 of 76 |
Divergences by rule id
None in this run: on every graded invoice, for every compared rule, the engine and the official Schematron gave the same verdict.
Exactly which official rules
The official artifacts are vendored (copied into the repository and pinned), never fetched at run time. The versions below are read out of those vendored files by the board script:
- CEN EN16931-UBL Schematron 1.3.16, last update 2026-03-30 (
corpus/cen-en16931/ubl/xslt/EN16931-UBL-validation.xslt). - KoSIT XRechnung Schematron 2.5.0 for XRechnung 3.0.2, compiled 2026-02-04 (
corpus/xrechnung-schematron/schematron/ubl/XRechnung-UBL-validation.xsl). - KoSIT XRechnung testsuite, release 2026-01-31 — the real German invoices in the XRechnung leg's corpus (
corpus/xrechnung-testsuite/CHANGELOG.md).
Upstream check on 2026-09-23 (the public GitHub releases list): a newer KoSIT XRechnung Schematron release exists upstream: v2.6.0, published 2026-09-02. This run graded against the vendored 2.5.0, not the newer release, so these figures say nothing yet about agreement with v2.6.0; no CEN EN16931 Schematron release newer than the vendored 1.3.16 was listed.
What this does not show
- Only rules the engine implements are compared. A Schematron rule the engine does not have is outside the denominator, not counted as agreement.
- The board covers the two UBL Invoice legs. The CreditNote, CII (Factur-X / ZUGFeRD) and syntax-binding legs of
differential.pyrun in the repository gate but are not on this page. - Agreement is measured on this corpus: the CEN unit tests and examples, the KoSIT testsuite, our own fixtures and generated mutations. Your invoices can contain shapes none of these do.
- No XSD schema validation is part of either side's comparison. For a submission to a German receiving portal, run the official KoSIT validator as well — see the comparison page.
Reproduce it
From a source checkout, in einvoice/, with saxonche installed: python3 differential.py en and python3 differential.py xrechnung print the same per-rule tables this board is built from; python3 parity_board.py re-runs both and rewrites this page. Both sides' verdicts are memoised on disk: the official one keyed on the Schematron file's hash and the invoice bytes, ours on the invoice bytes and a fingerprint of every engine source file, so any change to the engine forces a fully live re-grade.