Skip to content

qb64 encoding of a Matter requires the stream feature (encode/decode live in different layers) #67

Description

@joeldsouzax

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:79 pub fn matter_to_qb64<C: CesrCode>(matter: &Matter<'_, C>) -> Result<Vec<u8>, ParseError>.

Why it's a wart

  • A consumer who only wants to encode a key/digest to text must enable stream (a whole parsing subsystem) to do it. The text codec is conceptually a b64/core concern, not a stream concern. This forces every "just show me the qb64" example to pull stream (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).
  • 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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    devxDeveloper experience: API, prelude, examples, errorsenhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions