The problem
A page that puts a 51Did in a link writes it in the URL-safe base64 alphabet, with - and _ in place of + and /. Five of the six 51Did packages accept that form on the way in and normalise it before reading. The Rust crate does not, so the same identifier reads in .NET, Java, Node, Python and PHP and fails in Rust.
FodId::from_base64 in fodid/src/fodid.rs hands the string straight to Owid::from_base64, and the OWID reader's engine in owid-rust/src/owid.rs is built on alphabet::STANDARD, with padding indifferent but the alphabet fixed. - and _ are not in that alphabet, so the read fails with an invalid base64 status.
Evidence
Run in a worktree of the feature/usage-accessor branch on 6 September 2026, taking an envelope the test fixture had just signed, swapping the two characters, and reading both forms:
PROBE standard_ok=true url_safe_ok=false differed=true
The probe was removed afterwards and is not committed.
For comparison, .NET has FodId.NormaliseBase64 and applies it inside TryParse before the OWID reader sees the string, and its documentation says the URL-safe form is how a page puts a 51Did in a link. Node, Python and PHP each carry the same normalising helper.
What to do
Normalise the alphabet in FodId::from_base64 before the OWID reader sees the string, the way the other packages do, and cover it with a test that reads the URL-safe form of an identifier the standard form already reads. The choice worth making deliberately is whether the fix belongs in fodid or in owid-rust, since the OWID reader is where the alphabet is decided, and the OWID specification is a SWAN community document rather than ours.
Related, and worth deciding at the same time: the static base64 helpers differ across the six packages, which is recorded in the "One inconsistency, noted but separate" section of issue 39 and its five siblings. Rust has neither helper, which is why this gap exists at all.
The surface every package is expected to expose is at Package surface, and the base64 forms an identifier is exchanged in are in Identifier layout.
Notes
Written with AI assistance on James Rosewell's instruction and needs human review. Nothing has been changed for this issue.
The problem
A page that puts a 51Did in a link writes it in the URL-safe base64 alphabet, with
-and_in place of+and/. Five of the six 51Did packages accept that form on the way in and normalise it before reading. The Rust crate does not, so the same identifier reads in .NET, Java, Node, Python and PHP and fails in Rust.FodId::from_base64infodid/src/fodid.rshands the string straight toOwid::from_base64, and the OWID reader's engine inowid-rust/src/owid.rsis built onalphabet::STANDARD, with padding indifferent but the alphabet fixed.-and_are not in that alphabet, so the read fails with an invalid base64 status.Evidence
Run in a worktree of the
feature/usage-accessorbranch on 6 September 2026, taking an envelope the test fixture had just signed, swapping the two characters, and reading both forms:The probe was removed afterwards and is not committed.
For comparison, .NET has
FodId.NormaliseBase64and applies it insideTryParsebefore the OWID reader sees the string, and its documentation says the URL-safe form is how a page puts a 51Did in a link. Node, Python and PHP each carry the same normalising helper.What to do
Normalise the alphabet in
FodId::from_base64before the OWID reader sees the string, the way the other packages do, and cover it with a test that reads the URL-safe form of an identifier the standard form already reads. The choice worth making deliberately is whether the fix belongs infodidor inowid-rust, since the OWID reader is where the alphabet is decided, and the OWID specification is a SWAN community document rather than ours.Related, and worth deciding at the same time: the static base64 helpers differ across the six packages, which is recorded in the "One inconsistency, noted but separate" section of issue 39 and its five siblings. Rust has neither helper, which is why this gap exists at all.
The surface every package is expected to expose is at Package surface, and the base64 forms an identifier is exchanged in are in Identifier layout.
Notes
Written with AI assistance on James Rosewell's instruction and needs human review. Nothing has been changed for this issue.