Skip to content

REANNOUNCE via duplicate ANNOUNCE; announced() returns (path, Announced)#1530

Merged
kixelated merged 1 commit into
devfrom
claude/reannounce-enum-impl-EXaHB
May 30, 2026
Merged

REANNOUNCE via duplicate ANNOUNCE; announced() returns (path, Announced)#1530
kixelated merged 1 commit into
devfrom
claude/reannounce-enum-impl-EXaHB

Conversation

@kixelated
Copy link
Copy Markdown
Collaborator

@kixelated kixelated commented May 28, 2026

Implements REANNOUNCE (per moq-dev/drafts#23). Rebased onto current dev.

REANNOUNCE is an atomic broadcast replacement: the broadcast at a path is swapped for a new one without an interruption in availability (relay failover, upstream restart, a shorter hop path arriving).

Wire design: duplicate ANNOUNCE = REANNOUNCE

Rather than an explicit status byte, a reannounce is a duplicate ANNOUNCE — an active announcement for a path that is already announced, with no intervening unannounce. This means:

  • No wire-format change (lite/announce.rs is untouched), no new status, and no version gating — every version that speaks ANNOUNCE gets it.
  • No JS change: a duplicate ANNOUNCE is idempotent for @moq/net's set-based announce consumers (reconnect republish, @moq/boy), so they keep working unchanged.

API change (Rust)

AnnounceConsumer::next() / try_next() / poll_next() now yield (PathOwned, Announced) instead of (PathOwned, Option<BroadcastConsumer>):

pub enum Announced {
    Active(BroadcastConsumer),
    Reannounce(BroadcastConsumer),
    Ended,
}

.broadcast() gives the legacy Option<BroadcastConsumer> view (Some for both Active and Reannounce, None for Ended), so callers that don't care about the distinction stay simple.

Behavior

  • The origin already coalesced atomic replacements (backup promotion, shorter hop path) into an internal reannounce; those now surface as a single Announced::Reannounce delivery instead of an Ended-then-Active pair. A genuine unannounce+announce is still preserved as two deliveries.
  • Lite publisher: a Reannounce is sent as a duplicate Announce::Active (keeping the stats guard for continuity).
  • Lite subscriber: an Active for an already-announced path is applied as an atomic replacement (publish the replacement so the origin demotes the old broadcast to a backup, then retire it) instead of returning a Duplicate error.
  • IETF moq-transport has no reannounce, so it splits a Reannounce into namespace_done + namespace.

Drive-by

Adds the missing compress field (..Default::default()) to libmoq's Track initializers, which fails to compile after dev's compression feature landed (this was the error[E0063]: missing field compress CI failure).

Tests

  • model::origin: reannounce after the consumer drained is delivered as a single Reannounce; an undrained reannounce stays Active; test_duplicate backup-promotion asserts a single reannounce.
  • moq-net 327 unit tests + moq-relay 93 lib tests pass; moq-net/moq-relay/moq-native/moq-ffi/libmoq/hang build clean with no clippy -D warnings; cargo fmt --all --check clean (verified on rust 1.96, the nix-pinned toolchain).

(Written by Claude)

@kixelated kixelated changed the title moq-net: add REANNOUNCE; announced() returns an Announced enum add REANNOUNCE; announced() returns (PathOwned, Announced) May 29, 2026
@kixelated kixelated force-pushed the claude/reannounce-enum-impl-EXaHB branch from 597e49b to 51c36db Compare May 29, 2026 04:07
@kixelated kixelated changed the title add REANNOUNCE; announced() returns (PathOwned, Announced) add REANNOUNCE; AnnounceConsumer yields (path, Announced) May 29, 2026
Comment thread js/net/src/lite/announce.ts Outdated
Comment thread js/net/src/announced.ts
Comment thread rs/moq-ffi/src/origin.rs Outdated
@kixelated kixelated force-pushed the claude/reannounce-enum-impl-EXaHB branch 2 times, most recently from 68c53e6 to bfea208 Compare May 29, 2026 22:41
@kixelated kixelated changed the title add REANNOUNCE; AnnounceConsumer yields (path, Announced) REANNOUNCE via duplicate ANNOUNCE; announced() returns (path, Announced) May 29, 2026
@kixelated kixelated force-pushed the claude/reannounce-enum-impl-EXaHB branch from bfea208 to f782ce7 Compare May 30, 2026 15:44
Comment thread rs/hang/examples/subscribe.rs Outdated
Comment thread rs/moq-native/examples/clock.rs Outdated
Comment thread rs/moq-net/src/ietf/publisher.rs Outdated
_ => {}
}
stream.writer.finish().ok();
crate::Announced::Reannounce(_) => {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rename this to Announced::Restart? Or ::Retry?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to Announced::Restart (and the internal restart-coalescing path) across moq-net + consumers. Went with Restart over Retry since restart is the status name in the draft (and "retry" reads like a failed attempt being re-sent, whereas this is a clean replacement). Happy to switch to Retry if you'd prefer. (Written by Claude)


Generated by Claude Code

@kixelated kixelated force-pushed the claude/reannounce-enum-impl-EXaHB branch from 36f5b5e to 402055f Compare May 30, 2026 17:19
…, Announced)

REANNOUNCE is an atomic broadcast replacement (relay failover, upstream restart,
shorter hop path). On the wire it's a duplicate ANNOUNCE: an active announcement
for a path that is already announced, with no intervening unannounce. No new
status byte and no version gating.

AnnounceConsumer::{next,try_next,poll_next} now yield (PathOwned, Announced)
instead of (PathOwned, Option<BroadcastConsumer>). The `Announced` enum is
Active/Restart/Ended; `.broadcast()` gives the legacy Option<BroadcastConsumer>
view. The origin coalesces atomic replacements (backup promotion, shorter hop
path) into a single Announced::Restart delivery.

Lite publisher sends a restart as a duplicate Announce::Active. Lite subscriber
treats an Active for an already-announced path as an atomic replacement instead
of a Duplicate error. The lite decoder also tolerates the draft's explicit
`restart` status (2), surfacing it as an Active. IETF moq-transport has no
restart, so it splits into namespace_done + namespace.

Examples use `.context`/`event.broadcast()` for ergonomics.
@kixelated kixelated force-pushed the claude/reannounce-enum-impl-EXaHB branch from 402055f to 37741d2 Compare May 30, 2026 18:07
@kixelated kixelated enabled auto-merge (squash) May 30, 2026 19:03
@kixelated kixelated merged commit 46b010e into dev May 30, 2026
2 checks passed
@kixelated kixelated deleted the claude/reannounce-enum-impl-EXaHB branch May 30, 2026 20:03
kixelated added a commit that referenced this pull request May 31, 2026
Rebasing onto dev picked up the moq-ffi API where MoqOriginProducer.Publish
was renamed to Announce (the announce-based origin reshaping in #1530/#1536).
The wrapper's public OriginProducer.Publish stays; only the underlying ffi call
changes. Everything else (announced, broadcast, producers/consumers) is
unchanged, and just go check passes against dev's bindings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants