Pillar: co-development. This crate is the one egress trait surface for the whole programme. A parallel trait crate was proposed in the transports repo; that node is now the implementation behind this trait. There must be one trait crate, not two.
WHY — This is the one artifact WAVE can legally and safely place inside a third party's proprietary statically-linked binary, and it is the thing that decides the interfaces everyone else conforms to. The licence choice is not a formality — it is a linkability requirement: MIT-OR-Apache-2.0 dual, or it cannot be linked at all. Freeze the surface at 1.0 before it has downstream consumers.
GROUNDED — The contract already exists, battle-tested, in C++: wave-transports/srt/engine/wave-media-adapter.h:54-62 (IMediaAdapter: protocol/open/send/recv/meter/close), :45-52 (MediaUnit carrying media_time_100ns — a clock field is already in the unit), :15-27 (UsageMeter with frames/bytes/fps/av_drift_ms/reconnects/integrity counters). Eight independent implementations prove the abstraction holds across wildly different transports: aes67, moq, mxl, omt, rist, rist-bond, srt-adapter, srt-bond. Reproducibility note: the published grep for the adapter base class returns 24 paths, 16 of them duplicates inside .claude/worktrees/agent-*; the correct command excludes worktrees, or the eight paths are published directly. A receipt whose command returns a different answer than the receipt claims trains the reader to stop checking. Rust side is honestly G0: 35 .rs files tree-wide, no axum, no tonic, no .proto (verified 2026-07-24).
BOUNDARY — Not a MoQ implementation, not an encoder, not a service. Traits and plain types only — EgressSink, MetadataSink, TokenValidator, EncodedFrame { codec, pts_ptp, keyframe, bytes }, ViewportId, Meter. Do not claim "WAVE's Rust stack"; this crate is new work and should be described as such. Do not put an async runtime, a QUIC stack or a TLS stack in it — those belong behind the process seam. Licence obligations of the implementations are not this crate's to absorb: the SRT leg carries an MPL-2.0 obligation and NDI is a separately-licensed sidecar; neither may be pulled behind this trait as a linked dependency.
TAXONOMY — Third-party Rust engineers (compile-time consumers); WAVE transport engineers; the ring CI agent; any other egress vendor later admitted alongside. This crate is what makes "many suppliers, one contract" possible — sell it that way.
GATE — Entry G0 (no crate exists) → target G2 SCOPED on a frozen surface.
DONE-WHEN — cargo tree -p wave-egress-abi prints exactly one node (zero dependencies); the crate builds for aarch64-unknown-linux-gnu with --no-default-features; cargo deny check licenses passes with GPL/AGPL/SSPL denied; cargo public-api emits a frozen surface snapshot committed as the semver contract; and a throwaway downstream crate depending only on it compiles. All four outputs captured in one dated receipt.
DEPENDENCIES — None. Blocks the SRT/RTMP implementation crate, the ring conformance container and the process-boundary benchmark.
Pillar: co-development. This crate is the one egress trait surface for the whole programme. A parallel trait crate was proposed in the transports repo; that node is now the implementation behind this trait. There must be one trait crate, not two.
WHY — This is the one artifact WAVE can legally and safely place inside a third party's proprietary statically-linked binary, and it is the thing that decides the interfaces everyone else conforms to. The licence choice is not a formality — it is a linkability requirement: MIT-OR-Apache-2.0 dual, or it cannot be linked at all. Freeze the surface at 1.0 before it has downstream consumers.
GROUNDED — The contract already exists, battle-tested, in C++:
wave-transports/srt/engine/wave-media-adapter.h:54-62(IMediaAdapter:protocol/open/send/recv/meter/close),:45-52(MediaUnitcarryingmedia_time_100ns— a clock field is already in the unit),:15-27(UsageMeterwith frames/bytes/fps/av_drift_ms/reconnects/integrity counters). Eight independent implementations prove the abstraction holds across wildly different transports:aes67, moq, mxl, omt, rist, rist-bond, srt-adapter, srt-bond. Reproducibility note: the published grep for the adapter base class returns 24 paths, 16 of them duplicates inside.claude/worktrees/agent-*; the correct command excludes worktrees, or the eight paths are published directly. A receipt whose command returns a different answer than the receipt claims trains the reader to stop checking. Rust side is honestly G0: 35.rsfiles tree-wide, no axum, no tonic, no.proto(verified 2026-07-24).BOUNDARY — Not a MoQ implementation, not an encoder, not a service. Traits and plain types only —
EgressSink,MetadataSink,TokenValidator,EncodedFrame { codec, pts_ptp, keyframe, bytes },ViewportId,Meter. Do not claim "WAVE's Rust stack"; this crate is new work and should be described as such. Do not put an async runtime, a QUIC stack or a TLS stack in it — those belong behind the process seam. Licence obligations of the implementations are not this crate's to absorb: the SRT leg carries an MPL-2.0 obligation and NDI is a separately-licensed sidecar; neither may be pulled behind this trait as a linked dependency.TAXONOMY — Third-party Rust engineers (compile-time consumers); WAVE transport engineers; the ring CI agent; any other egress vendor later admitted alongside. This crate is what makes "many suppliers, one contract" possible — sell it that way.
GATE — Entry G0 (no crate exists) → target G2 SCOPED on a frozen surface.
DONE-WHEN —
cargo tree -p wave-egress-abiprints exactly one node (zero dependencies); the crate builds foraarch64-unknown-linux-gnuwith--no-default-features;cargo deny check licensespasses with GPL/AGPL/SSPL denied;cargo public-apiemits a frozen surface snapshot committed as the semver contract; and a throwaway downstream crate depending only on it compiles. All four outputs captured in one dated receipt.DEPENDENCIES — None. Blocks the SRT/RTMP implementation crate, the ring conformance container and the process-boundary benchmark.