Skip to content

v0.3.6 — a sealed Conduit is the reason, then end of stream

Choose a tag to compare

@github-actions github-actions released this 27 Aug 20:29
· 16 commits to main since this release

A refinement of the Conduit rite 0.3.5 shipped, driven by the first consumer's questions.

The seal is now terminal for the reader

As shipped in 0.3.5, a sealed frame was followed by a read that blocked forever: the host holds the visit open for the other rites — that is the drain which stops a sealed conduit taking the Oracle down with it — so no close was ever coming. A consumer writing the natural rule, "translate Sealed to a reason, then expect null", would have hung.

ReceiveAsync now latches: the sealed frame is yielded once carrying its SealReason, and every read after it returns null. Write exactly that rule. It is the contract the Auspice already had, where AttendAllAsync breaks on a Sealed frame.

One deliberate asymmetry. The latch is on the Pilgrimage wire only. The Arcanum conduit predates the reserved flag bit, so an application on a channel may already be using the top flag for its own purposes; reading it as a seal there would end that conduit silently — a flag day, which is what CupriMark exists to avoid. On a channel the bit stays the application's, and a test pins it.

Also in this release

Change Why
ConduitFrame.ApplicationFlags Returns flags with every rite-reserved bit cleared, so a consumer writes one expression that stays correct if a second bit is ever reserved — instead of masking against Sealed and diverging silently later.
ReceiveAsync single-reader documented Concurrent readers corrupt nothing, but each frame goes to exactly one of them, so ordering is meaningful only to one.
IConduitHandler ProtocolId convention The rite never dispatches on it and there is no registry, so a handler should seal an id it does not know rather than ignore the frame. Left unsaid, every consumer would invent a different failure for the same situation.

438 unit tests green.