v0.0.58
Pain001 Release v0.0.58
Release Date: 2026-07-29
Tag: v0.0.58
Python: 3.10+
Status: Stable
Executive Summary
A correctness release, and the most important one this package has
shipped. Two of the schemas it validated against were not ISO publications
but hand-authored placeholders permissive enough to accept documents ISO
does not allow. One of them was hiding a defect in the direct-debit
generator: every pain.008.001.02 file Pain001 has ever produced placed
<SeqTp> where the standard forbids it, and would have been rejected by the
receiving bank. The placeholder schema validated those files as correct.
Anyone generating direct debits should upgrade. Anyone who has had a
pain.008 batch rejected without an obvious cause now has an explanation.
Alongside the fix: pain.001.001.13 support, real ISO schemas for every
bundled version, pain.002 response validation, and version migration
between modern versions.
Fixed
-
pain.008.001.02:<SeqTp>was emitted in the wrong place. ISO
definesSeqTpinsidePaymentTypeInformation20— that is, within
<PmtTpInf>. Pain001 emitted it as a bare child of
<DrctDbtTxInf>. Real bank validators reject that. The 12 KB
hand-authored schema this package shipped did not, which is why the defect
survived.SeqTpnow followsSvcLvlinsidePmtTpInf, and the
direct-debit preparer readssequence_typefrom the data (defaulting to
RCUR) rather than assuming it. -
pain.001.001.12was a 475-byte stub that accepted any document.
--xml-message-type pain.001.001.12reported successful schema validation
without performing any. The genuine ISO schema now ships, so that
validation is real. Files that previously "passed" may now fail; those
failures are accurate. -
Migration between modern versions was unsupported.
VersionMapper
refused v09 → v12, v10 → v09 and every other modern-to-modern pair with a
DataSourceError. Modern-to-modern migration now works. Modern → legacy
is still refused deliberately: the newer versions carry structured data
the legacy schemas have nowhere to put, and silently dropping it would be
worse than declining. -
bundled_schema_versionsandschema_for_namespaceare exported.
Both were documented as the way to check response-schema coverage but
lived only inpain001.pain002.parser, so the documented import failed.
Added
-
pain.001.001.13support — templates, schema and registry entry.
Twelve message definitions now ship. -
pain.002response validation.parse_pain002_report(..., validate=True)
checks a bank's status report against the bundled ISO schema for its
namespace before parsing it. Bundled response schemas:pain.002.001.03
(the version most SEPA banks reply with),.12,.14and.15. When a
bank replies in a version this package does not bundle, validation is
refused explicitly rather than skipped silently. -
tests/test_schema_completeness.py— the gate that would have caught
all of the above. Every shipped schema must exceed 10 KB, define at least
five complex types, and behaviourally reject a junk document. The
structural checks alone would have passed the oldpain.008schema; the
rejection test is what makes the gate meaningful.KNOWN_PLACEHOLDER_SCHEMAS
is now empty, and adding to it requires a dated reason. -
scripts/preflight_release.py(make release-check,FULL=1for the
slow checks) — an executable form of the RELEASING.md checklist, written
after a missing release note failed the first v0.0.57 tag. It runs before
tagging; the publish job checks the same things, but only after a tag has
been pushed and must then be deleted from two places.
Changed
- Every bundled schema is now a genuine ISO publication carrying a Standards
Editor header. Four were replaced in this release. - SLSA provenance is generated by the
provenancejob insideci.yml.
A release created withGITHUB_TOKENemits no events, so the previous
on: release: publishedworkflow could never fire for this pipeline — it
looked armed and produced nothing.slsa.ymlis now dispatch-only backfill. - The top-level
LICENSEcarries the full Apache-2.0 text with a trailing
dual-licence note. A pointer file naming the dual licence satisfied the
Best Practices badge but made GitHub reportNOASSERTION.
Upgrading
pip install --upgrade pain001No API changes. If you generate pain.008 files, regenerate them: output
from 0.0.57 and earlier carries the misplaced <SeqTp>. If you generate
pain.001.001.12, re-run validation — it now actually runs.