Skip to content

Decision: sans-io parse-surface boundary — core consumes parsed values, sync iterator is the primary driver, futures Stream is the optional async edge #128

Description

@joeldsouzax

Decision: the sans-io parse-surface boundary

Records the answer to a question that was left open across the stream work: what abstraction does the KERI core consume — a sync pull Iterator (the parside/keriox shape) or the async futures::Stream we built (CesrCodec + Framed)?

Both shapes exist in the tree today with no decision recorded between them:

  • Sync pull iteratorgroups()GroupIter, an Iterator<Item = Result<CesrGroup, ParseError>> (cesr/src/stream/group/iter.rs:58). This is the parside/keriox shape: bytes → parsed groups, walked synchronously.
  • Async streamCesrCodec<V>, a tokio_util::codec::Decoder/Encoder behind the async feature (cesr/src/stream/codec.rs:271). Wrapped in Framed<T, CesrCodec> it is a futures::Stream. Needs Tokio; not no_std-clean.

The decision

The pure KERI core (K1, #87) consumes neither. It takes already-parsed, borrowed values:

fn validate(state: Option<&KeyState>, event: &KeriEvent<'_>, sigs: &[Siger], wigs: &[Siger]) -> Result<Accepted, Rejection>;
fn apply(state: Option<KeyState>, accepted: &Accepted) -> KeyState;

That is the definition of sans-io: the core touches no IO abstraction — not futures, not Tokio, not even an Iterator dependency in its signatures. K1's acceptance ("no_std + wasm32 stays green") makes this non-negotiable — a futures::Stream/Tokio codec cannot sit on that path.

The two parse surfaces are transport drivers that live outside the core, and both feed the same pure validate/apply:

Layer Shape Gate
Pure core (K1) takes &KeriEvent, &[Siger] — no stream/iterator dep no_std clean
Reference driver sync groups() pull iterator (parside shape) alloc
Async driver CesrCodecFramed = futures::Stream (TCP/WS) async
  • The sync groups() iterator is the canonical driver — no_std/wasm-clean, no runtime, matches how keriox drives its processor.
  • The futures::Stream (CesrCodec) is an optional async edge, not wrong and not removed — it belongs on top of the parse layer for AsyncRead transports (TCP / WebSocket bridges). This is the same secondary-path rationale captured in Document rationale: Tokio codec layer for non-Zenoh transports #104.

Consequence for the K-series

Congruent with the nexus decide/apply split: parsing/IO is the edge, validate/apply is the pure center.

Metadata

Metadata

Assignees

No one assigned

    Labels

    design-intelSurfaced by the design-intel watcher

    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