You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Surfaced by the P2.2 (#32) examples research pass. DevX / layering wart.
What
Encoding a Matter-family primitive (Verfer, Diger, Saider, Prefixer, Signer, Cigar) to its CESR text form (qb64 / qb64b) is only possible via stream::encode::matter_to_qb64, which lives behind the stream feature. There is no to_qb64 on Matter in core.
Reproduction (source):
core primitives have no qb64 encoder: grep -rn "pub fn to_qb64" src/core/matter/ → nothing.
Only Siger and Indexer carry a to_qb64 in core (src/core/primitives/siger.rs:130, src/core/indexer/indexer.rs:101) — the general Matter does not.
The encoder is stream-gated: src/stream/encode.rs:79pub fn matter_to_qb64<C: CesrCode>(matter: &Matter<'_, C>) -> Result<Vec<u8>, ParseError>.
Read/write asymmetry: MatterBuilder::from_qb64 (decode) is in core, but the encode counterpart is in stream. Decode and encode of the same text form live in different features.
Error-domain smell (Mandatory Rule 3): matter_to_qb64 returns Result<_, ParseError> on an encode path. ParseError is a parsing (read-path) error type; an encoder surfacing a parse error is a domain mismatch. serder even wraps it as SerderError::Qb64Encoding(ParseError).
Proposed cleanup
Provide Matter::to_qb64 / Matter::to_qb64b in core (or a b64-level encoder), so text encoding does not require stream.
Keep stream::encode::matter_to_qb64 as a thin re-export/alias for back-compat, or migrate call sites.
Give the encode path its own error type (or reuse a b64::Error) instead of ParseError.
Round-trip test lives in core: from_qb64(to_qb64(x)) == x without the stream feature.
Notes
Breaking change is acceptable pre-1.0 (see CLAUDE.md · Active Development) — call it out in the PR + CHANGELOG. Relates to P2.1/P2.3 (prelude/error ergonomics).
What
Encoding a
Matter-family primitive (Verfer,Diger,Saider,Prefixer,Signer,Cigar) to its CESR text form (qb64 / qb64b) is only possible viastream::encode::matter_to_qb64, which lives behind thestreamfeature. There is noto_qb64onMatterincore.Reproduction (source):
coreprimitives have no qb64 encoder:grep -rn "pub fn to_qb64" src/core/matter/→ nothing.SigerandIndexercarry ato_qb64incore(src/core/primitives/siger.rs:130,src/core/indexer/indexer.rs:101) — the generalMatterdoes not.stream-gated:src/stream/encode.rs:79pub fn matter_to_qb64<C: CesrCode>(matter: &Matter<'_, C>) -> Result<Vec<u8>, ParseError>.Why it's a wart
stream(a whole parsing subsystem) to do it. The text codec is conceptually ab64/coreconcern, not a stream concern. This forces every "just show me the qb64" example to pullstream(see P2.2 · Runnable examples #32 examples chore: scaffold cesr — single crate + Nix harness + god-level clippy #1 and chore: filter-repo extract CESR/KERI history from agency into module dirs #2).MatterBuilder::from_qb64(decode) is incore, but the encode counterpart is instream. Decode and encode of the same text form live in different features.matter_to_qb64returnsResult<_, ParseError>on an encode path.ParseErroris a parsing (read-path) error type; an encoder surfacing a parse error is a domain mismatch.serdereven wraps it asSerderError::Qb64Encoding(ParseError).Proposed cleanup
Matter::to_qb64/Matter::to_qb64bincore(or ab64-level encoder), so text encoding does not requirestream.stream::encode::matter_to_qb64as a thin re-export/alias for back-compat, or migrate call sites.b64::Error) instead ofParseError.core:from_qb64(to_qb64(x)) == xwithout thestreamfeature.Notes
Breaking change is acceptable pre-1.0 (see CLAUDE.md · Active Development) — call it out in the PR + CHANGELOG. Relates to P2.1/P2.3 (prelude/error ergonomics).