Real regression found via zodia-sdk's existing round-trip tests: running
two LogSync engines (one per extensions type) on the same iroh Endpoint
silently breaks one of them. p2panda-net::LogSync registers a single
fixed protocol id regardless of its generic E, so the second engine's
registration overwrote the first's in the Endpoint's handler map -
confirmed by reading the exact HashMap::insert call, then verified
empirically (constructing the second engine, with zero circle topics
ever opened, was already enough to break the existing DocOp path).
Fix: zodia-ops gains ZodiaExtensions, the one wire-level extensions type
for everything (Interp(OpExtensions) | Circle(SpacesArgs<()>)) - a
single LogSync<_,_,ZodiaExtensions> engine now serves every topic kind.
zodia-pipeline needed no logic changes, only a mechanical type-parameter
swap (Decode/MaterializationProcessor only ever touch .body and
.header.extension::<Timestamp>(), both untouched by which extensions
variant is present). zodia-circles's CircleExtensions is now an alias
for the same type; CircleOperation and ZodiaExtensions itself each gain
a Borrow<SpacesArgs<()>> impl projecting out the Circle variant.
zodia-sdk: create_circle/invite_to_circle/revoke_from_circle/
share_interp_to_circle/circle_members on ZodiaClient, plus
CircleContentReceived wired to zodia_pipeline::materialize_circle_content.
Verified: zodia-sync/circles/pipeline/sdk unit tests all pass, and the
full existing 16-scenario/108-step cucumber suite passes unchanged -
confirming the fix without a regression, on the same architecture that
will carry circle traffic in production.
Known, documented limitation (not fixed here): all of an author's
circles share one log, so a peer catching up on one circle's topic
also replicates (still-encrypted) traffic for that author's other
circles. Real fix needs per-circle log ids; deferred as a tracked gap,
not silently shipped - see docs/prd/circles.md.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>