Skip to content

moq-net: track announcement byte usage in stats#1953

Merged
kixelated merged 5 commits into
mainfrom
claude/gifted-bassi-9b682e
Jun 30, 2026
Merged

moq-net: track announcement byte usage in stats#1953
kixelated merged 5 commits into
mainfrom
claude/gifted-bassi-9b682e

Conversation

@kixelated

@kixelated kixelated commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds an announced_bytes counter to the relay stats so we track how much announcement data a broadcast uses, not just the count of announce events. It sits next to the existing announced / announced_closed counters and is surfaced per (broadcast, tier, role) on the stats broadcast, just like bytes/frames/groups. It's kept separate from bytes, which remains media payload.

announced_bytes sums the broadcast name length for each announce/unannounce message. It deliberately counts the name rather than the encoded message size, so a broadcast isn't charged for transport overhead it doesn't control (size prefixes, message-type ids, hop chains).

What changed

  • rs/moq-net/src/stats.rs: new Counters.announced_bytes field, threaded through RawCounts, Snapshot, snapshot(), and process_slot. New BroadcastStats::publisher_announced_bytes(n) / subscriber_announced_bytes(n) methods that record keyed by broadcast path, independent of the announce lifetime guard. Module docs updated. Two new tests.
  • Wiring on both protocols and directions, recording the broadcast name length at each announce/unannounce site:
    • lite: ANNOUNCE Active/Ended on the publisher (send) and subscriber (receive), plus the Lite01/02 AnnounceInit initial active set on both sides.
    • IETF: PUBLISH_NAMESPACE announce + PUBLISH_NAMESPACE_DONE on the publisher; PUBLISH / PUBLISH_NAMESPACE / NAMESPACE on the subscriber (via start_announce).
    • Because recording is path-keyed and guard-free, announce/unannounce messages that crossed the wire but had no live guard (hop/loop-filtered, reflected, or unmatched) are still counted.
  • doc/bin/relay/config.md: added announced_bytes to the stats JSON example and field semantics (Cross-Package Sync: moq-relay config/behavior).

API changes

  • moq-net::Countersnew pub announced_bytes: AtomicU64 field. The struct is #[non_exhaustive], so this is additive and non-breaking.
  • moq-net::BroadcastStats::publisher_announced_bytes(&self, n: u64)new pub method.
  • moq-net::BroadcastStats::subscriber_announced_bytes(&self, n: u64)new pub method.
  • The serialized stats JSON gains an additive announced_bytes field.
  • No wire-format change, and no changes to the (private) coding module's Writer/Reader.

Per the branch-targeting rules this is additive and non-breaking, so it targets main.

Notes for the reviewer

  • The metric is the absolute broadcast name length (the stats entry key), counted once per announce and once per unannounce that actually sends/receives the name. For IETF moq-transport v17+, an unannounce is just a stream close with no name on the wire, so it contributes nothing there (v14-16, which send PUBLISH_NAMESPACE_DONE, do).
  • js/net has no stats-aggregator counterpart (stats are relay-side only), so there's nothing to mirror there.

Test plan

  • cargo test -p moq-net (incl. two new announced_bytes tests) green
  • cargo check across moq-relay / moq-native
  • cargo clippy -p moq-net --all-targets clean (via nix)
  • cargo fmt (via nix)
  • Not exercised against a live relay end-to-end

(Written by Claude Opus 4.8)

Add an `announced_bytes` counter alongside the existing `announced` /
`announced_closed` event counts, so the per-node stats broadcast reports
how many wire bytes a broadcast spends on announce/unannounce control
messages, not just how many times it announced. Kept separate from the
`bytes` payload counter and surfaced per (broadcast, tier, role) like the
other counters.

Measurement is taken at the encode/decode points:
- `Writer::encode`/`encode_message` now return the bytes written.
- `Reader` gains `decode_sized`/`decode_maybe_sized` returning the bytes
  consumed.

Both are internal (the `coding` module is private) and non-breaking for
existing `.await?;` call sites. Wired on both protocols and directions:
lite ANNOUNCE Active/Ended (send + receive) and IETF PUBLISH_NAMESPACE /
PUBLISH / NAMESPACE.

`Counters` is `#[non_exhaustive]` and the new field is additive, so this
is a non-breaking change targeting main.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sorry @kixelated, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

Switch announced_bytes to sum the broadcast name length per announce /
unannounce instead of the full encoded message size. This avoids charging
a broadcast for transport overhead it doesn't control (size prefixes,
message-type ids, hop chains).

Because the name is available right at each announce site, this reverts
the Writer::encode / encode_message and Reader byte-count plumbing back to
their original signatures, and drops the announce_bytes parameter
threading through the IETF subscriber (start_announce computes it from the
absolute path).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@kixelated, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 21 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dc54c825-49d3-4bd0-9ee5-ea8361173951

📥 Commits

Reviewing files that changed from the base of the PR and between 789d6e3 and 9df955f.

📒 Files selected for processing (1)
  • rs/moq-net/src/ietf/subscriber.rs

Walkthrough

A new cumulative counter, announced_bytes, is added to the stats infrastructure for announce/unannounce control messages based on broadcast name length. Counters, RawCounts, Snapshot, and process_slot are extended, and BroadcastStats gains publisher_announced_bytes and subscriber_announced_bytes. Lite and IETF publisher/subscriber code now records the counter during announce, unannounce, and cleanup handling. The relay config docs now show the field in the example snapshot and define its semantics.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding announcement byte tracking to moq-net stats.
Description check ✅ Passed The description is directly related to the stats and announcement-byte accounting changes in the PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch claude/gifted-bassi-9b682e

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@rs/moq-net/src/ietf/subscriber.rs`:
- Line 172: `SubscriberStats::bytes()` is being undercounted because
`start_announce`/`start_publish` currently receive only the payload size from
`handle_stream` and the decoder path, not the full wire message length. Update
the message dispatch flow in `subscriber.rs` so the total consumed encoded
length (including type-id and length prefix) is threaded through and recorded by
`start_announce` and `start_publish` for `Namespace`, `PublishNamespace`, and
`Publish` instead of using `size as u64` or `data.len() as u64`.

In `@rs/moq-net/src/lite/publisher.rs`:
- Around line 318-321: The unannounce byte count is only being recorded when a
live guard exists in publisher::publish/End handling, so paths that skipped
Active still spend bytes without updating metrics. Update the stats flow around
the `stream.writer.encode(&msg)` path and the `stats_guards.remove(...)` lookup
so the bytes are always recorded against a path-keyed stats entry first, then
remove and use the guard only if it exists. Keep the fix centered on the
`stats_guards` map and the `guard.bytes(...)` accounting so `announced_bytes`
reflects all lite control traffic.

In `@rs/moq-net/src/lite/subscriber.rs`:
- Around line 188-197: The announce byte accounting in `subscriber.rs` is only
happening after `start_announce` succeeds or when a guard exists, so dropped
`Active` announces and unmatched `Ended` messages are missing from
`announced_bytes`. Update the
`stream.reader.decode_maybe_sized::<lite::Announce>()` handling to credit `n`
immediately for each decoded announce using a byte-only stats path keyed by
`abs`, independent of `start_announce` and `stats_guards`, and keep the existing
guard-based tracking only for accepted broadcast lifetime in
`subscriber`/`stats.broadcast`.

In `@rs/moq-net/src/stats.rs`:
- Around line 151-154: The `announced_bytes` metric in `stats.rs` is currently
undercounting Lite01/02 because `AnnounceInit` traffic is handled in
`lite/publisher.rs` and `lite/subscriber.rs` without going through
`guard.bytes(...)`. Update the Lite publisher/subscriber paths to record the
initial announce control bytes in `announced_bytes`, or if that is not intended,
tighten the `announced_bytes` documentation and usage to explicitly cover only
Lite03+ so the metric’s scope matches the implementation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9e7681a1-786b-4410-aacb-dcbeda91854f

📥 Commits

Reviewing files that changed from the base of the PR and between a34b7c3 and 9d167e5.

📒 Files selected for processing (8)
  • doc/bin/relay/config.md
  • rs/moq-net/src/coding/reader.rs
  • rs/moq-net/src/coding/writer.rs
  • rs/moq-net/src/ietf/publisher.rs
  • rs/moq-net/src/ietf/subscriber.rs
  • rs/moq-net/src/lite/publisher.rs
  • rs/moq-net/src/lite/subscriber.rs
  • rs/moq-net/src/stats.rs

Comment thread rs/moq-net/src/ietf/subscriber.rs Outdated
Comment thread rs/moq-net/src/lite/publisher.rs Outdated
Comment thread rs/moq-net/src/lite/subscriber.rs Outdated
Comment thread rs/moq-net/src/stats.rs Outdated
Record the broadcast name length keyed by broadcast path via new
BroadcastStats::{publisher,subscriber}_announced_bytes, instead of through
the lifetime guard. This captures announce/unannounce control messages
whose guard was skipped (hop/loop filtering), reflected, or already
dropped, which the guard-coupled version under-reported.

Also count the Lite01/02 AnnounceInit initial active set on both the
publisher and subscriber sides, so announced_bytes is no longer
protocol-version dependent.

Addresses CodeRabbit review feedback on #1953.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
rs/moq-net/src/ietf/publisher.rs (1)

523-561: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Count PUBLISH_NAMESPACE bytes before waiting for the OK response.

Lines 547-561 only bump announced_bytes after PublishNamespaceOk / RequestOk, but Lines 527-535 have already written PUBLISH_NAMESPACE to the wire. A rejected namespace therefore consumes announce control bytes without ever surfacing in stats, which under-reports the new metric’s documented “independent of the lifetime guard” behavior.

Suggested fix
 				let request_id = self.control.next_request_id().await?;
 				let mut stream = Stream::open(&self.session, self.version).await?;
 
 				// Count the broadcast name length, not the encoded message size, so
 				// stats don't penalize the broadcast for framing overhead.
 				let announce_bytes = absolute.as_str().len() as u64;
+				let bs = self.stats.broadcast(&absolute);
 
 				// Write the PublishNamespace message
 				stream.writer.encode(&ietf::PublishNamespace::ID).await?;
 				stream
 					.writer
@@
 					.encode(&ietf::PublishNamespace {
 						request_id,
 						track_namespace: suffix.as_path(),
 					})
 					.await?;
+				bs.publisher_announced_bytes(announce_bytes);
 
 				// Read response from stream.reader
 				let type_id: u64 = stream.reader.decode().await?;
@@
 					(Version::Draft14, ietf::PublishNamespaceOk::ID) => {
 						let msg = ietf::PublishNamespaceOk::decode_msg(&mut data, self.version)?;
 						tracing::debug!(message = ?msg, "publish namespace ok");
-						let bs = self.stats.broadcast(&absolute);
-						bs.publisher_announced_bytes(announce_bytes);
 						namespace_streams.insert(suffix, (request_id, stream, bs.publisher()));
 					}
@@
 					(_, ietf::RequestOk::ID) => {
 						let msg = ietf::RequestOk::decode_msg(&mut data, self.version)?;
 						tracing::debug!(message = ?msg, "publish namespace ok");
-						let bs = self.stats.broadcast(&absolute);
-						bs.publisher_announced_bytes(announce_bytes);
 						namespace_streams.insert(suffix, (request_id, stream, bs.publisher()));
 					}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rs/moq-net/src/ietf/publisher.rs` around lines 523 - 561, The `publish
namespace` flow in `publisher.rs` only updates `publisher_announced_bytes` after
`PublishNamespaceOk`/`RequestOk`, so rejected namespaces never count the
`PUBLISH_NAMESPACE` control bytes that were already sent. Move the announcement
byte accounting in the `publish`/`PublishNamespace` handling path so it is
recorded immediately after writing the `ietf::PublishNamespace` request (before
waiting on `stream.reader.decode()`), and keep the existing success handling in
place for the namespace stream bookkeeping.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@rs/moq-net/src/ietf/subscriber.rs`:
- Around line 455-466: The subscriber-side announced-bytes tracking in
start_announce only records the announce path and misses the matching IETF
unannounce flow. Update the subscriber stats handling around start_announce,
stop_announce, run_subscribe_namespace(), and run_publish_namespace_stream() so
the same subscriber_announced_bytes(...) counter is also incremented when
NamespaceDone or PublishNamespaceDone is converted into stop_announce(path),
keeping the announce/unannounce metric symmetric.

---

Outside diff comments:
In `@rs/moq-net/src/ietf/publisher.rs`:
- Around line 523-561: The `publish namespace` flow in `publisher.rs` only
updates `publisher_announced_bytes` after `PublishNamespaceOk`/`RequestOk`, so
rejected namespaces never count the `PUBLISH_NAMESPACE` control bytes that were
already sent. Move the announcement byte accounting in the
`publish`/`PublishNamespace` handling path so it is recorded immediately after
writing the `ietf::PublishNamespace` request (before waiting on
`stream.reader.decode()`), and keep the existing success handling in place for
the namespace stream bookkeeping.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2de92e35-5cce-4a04-b6b2-8e73e8175860

📥 Commits

Reviewing files that changed from the base of the PR and between 9d167e5 and 00fb477.

📒 Files selected for processing (6)
  • doc/bin/relay/config.md
  • rs/moq-net/src/ietf/publisher.rs
  • rs/moq-net/src/ietf/subscriber.rs
  • rs/moq-net/src/lite/publisher.rs
  • rs/moq-net/src/lite/subscriber.rs
  • rs/moq-net/src/stats.rs
✅ Files skipped from review due to trivial changes (1)
  • doc/bin/relay/config.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
rs/moq-net/src/ietf/publisher.rs (1)

523-561: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Count PUBLISH_NAMESPACE bytes before waiting for the OK response.

Lines 547-561 only bump announced_bytes after PublishNamespaceOk / RequestOk, but Lines 527-535 have already written PUBLISH_NAMESPACE to the wire. A rejected namespace therefore consumes announce control bytes without ever surfacing in stats, which under-reports the new metric’s documented “independent of the lifetime guard” behavior.

Suggested fix
 				let request_id = self.control.next_request_id().await?;
 				let mut stream = Stream::open(&self.session, self.version).await?;
 
 				// Count the broadcast name length, not the encoded message size, so
 				// stats don't penalize the broadcast for framing overhead.
 				let announce_bytes = absolute.as_str().len() as u64;
+				let bs = self.stats.broadcast(&absolute);
 
 				// Write the PublishNamespace message
 				stream.writer.encode(&ietf::PublishNamespace::ID).await?;
 				stream
 					.writer
@@
 					.encode(&ietf::PublishNamespace {
 						request_id,
 						track_namespace: suffix.as_path(),
 					})
 					.await?;
+				bs.publisher_announced_bytes(announce_bytes);
 
 				// Read response from stream.reader
 				let type_id: u64 = stream.reader.decode().await?;
@@
 					(Version::Draft14, ietf::PublishNamespaceOk::ID) => {
 						let msg = ietf::PublishNamespaceOk::decode_msg(&mut data, self.version)?;
 						tracing::debug!(message = ?msg, "publish namespace ok");
-						let bs = self.stats.broadcast(&absolute);
-						bs.publisher_announced_bytes(announce_bytes);
 						namespace_streams.insert(suffix, (request_id, stream, bs.publisher()));
 					}
@@
 					(_, ietf::RequestOk::ID) => {
 						let msg = ietf::RequestOk::decode_msg(&mut data, self.version)?;
 						tracing::debug!(message = ?msg, "publish namespace ok");
-						let bs = self.stats.broadcast(&absolute);
-						bs.publisher_announced_bytes(announce_bytes);
 						namespace_streams.insert(suffix, (request_id, stream, bs.publisher()));
 					}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rs/moq-net/src/ietf/publisher.rs` around lines 523 - 561, The `publish
namespace` flow in `publisher.rs` only updates `publisher_announced_bytes` after
`PublishNamespaceOk`/`RequestOk`, so rejected namespaces never count the
`PUBLISH_NAMESPACE` control bytes that were already sent. Move the announcement
byte accounting in the `publish`/`PublishNamespace` handling path so it is
recorded immediately after writing the `ietf::PublishNamespace` request (before
waiting on `stream.reader.decode()`), and keep the existing success handling in
place for the namespace stream bookkeeping.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@rs/moq-net/src/ietf/subscriber.rs`:
- Around line 455-466: The subscriber-side announced-bytes tracking in
start_announce only records the announce path and misses the matching IETF
unannounce flow. Update the subscriber stats handling around start_announce,
stop_announce, run_subscribe_namespace(), and run_publish_namespace_stream() so
the same subscriber_announced_bytes(...) counter is also incremented when
NamespaceDone or PublishNamespaceDone is converted into stop_announce(path),
keeping the announce/unannounce metric symmetric.

---

Outside diff comments:
In `@rs/moq-net/src/ietf/publisher.rs`:
- Around line 523-561: The `publish namespace` flow in `publisher.rs` only
updates `publisher_announced_bytes` after `PublishNamespaceOk`/`RequestOk`, so
rejected namespaces never count the `PUBLISH_NAMESPACE` control bytes that were
already sent. Move the announcement byte accounting in the
`publish`/`PublishNamespace` handling path so it is recorded immediately after
writing the `ietf::PublishNamespace` request (before waiting on
`stream.reader.decode()`), and keep the existing success handling in place for
the namespace stream bookkeeping.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2de92e35-5cce-4a04-b6b2-8e73e8175860

📥 Commits

Reviewing files that changed from the base of the PR and between 9d167e5 and 00fb477.

📒 Files selected for processing (6)
  • doc/bin/relay/config.md
  • rs/moq-net/src/ietf/publisher.rs
  • rs/moq-net/src/ietf/subscriber.rs
  • rs/moq-net/src/lite/publisher.rs
  • rs/moq-net/src/lite/subscriber.rs
  • rs/moq-net/src/stats.rs
✅ Files skipped from review due to trivial changes (1)
  • doc/bin/relay/config.md
🛑 Comments failed to post (1)
rs/moq-net/src/ietf/subscriber.rs (1)

455-466: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

announced_bytes is still missing IETF unannounce traffic on the subscriber side.

Line 460 only credits the announce half of the flow. run_subscribe_namespace() still processes NamespaceDone via stop_announce(path), and run_publish_namespace_stream() still turns Draft14-16 PublishNamespaceDone into the same stop path, without any symmetric subscriber_announced_bytes(...) bump. That leaves IETF subscriber stats under-counting the documented announce/unannounce metric.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rs/moq-net/src/ietf/subscriber.rs` around lines 455 - 466, The
subscriber-side announced-bytes tracking in start_announce only records the
announce path and misses the matching IETF unannounce flow. Update the
subscriber stats handling around start_announce, stop_announce,
run_subscribe_namespace(), and run_publish_namespace_stream() so the same
subscriber_announced_bytes(...) counter is also incremented when NamespaceDone
or PublishNamespaceDone is converted into stop_announce(path), keeping the
announce/unannounce metric symmetric.

Two gaps in the IETF announced_bytes accounting:

- The publisher only recorded the name length after PUBLISH_NAMESPACE_OK,
  so a rejected namespace spent an announce we never counted. Record it as
  soon as the request is on the wire instead.
- The subscriber counted the announce (start_announce) but not the matching
  unannounce. Record it in stop_announce, mirroring start_announce.

Both sides now count the broadcast name length per announce and per
unannounce operation, draft-agnostically (we measure the name, not the
on-wire framing), keeping publisher and subscriber symmetric.

Addresses CodeRabbit review feedback on #1953.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@kixelated

Copy link
Copy Markdown
Collaborator Author

Addressed both findings from the latest review (they came through as summary/outside-diff items, so no inline threads to reply on) in commit 789d6e3:

  • ietf/publisher.rs (PUBLISH_NAMESPACE counted before the OK): the name length is now recorded as soon as the request is on the wire, so a rejected namespace still counts the announce we spent.
  • ietf/subscriber.rs (unannounce symmetry): stop_announce now records the unannounce name length, mirroring start_announce.

Both IETF sides now count the broadcast name length per announce and per unannounce operation, draft-agnostically (we measure the name, not the on-wire framing), keeping publisher and subscriber symmetric. cargo test -p moq-net + clippy/fmt green.

🤖 Addressed by Claude Code

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@rs/moq-net/src/ietf/subscriber.rs`:
- Around line 520-526: The byte accounting in `stop_announce` is currently
treating every cleanup path as an unannounce, which can inflate
`subscriber_announced_bytes` when `stop_announce` is used after failed
`write_ok` or `write_publish_ok`. Update the `stop_announce` flow in
`subscriber.rs` so the byte bump only happens for real unannounce or
stream-close control events, either by moving the accounting to the actual
unannounce call sites or by threading an explicit `count_unannounce_bytes` flag
through `stop_announce` and the related announce/rollback paths.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4c0b45c1-3c6b-4cc6-bd04-c339c8f2442a

📥 Commits

Reviewing files that changed from the base of the PR and between 00fb477 and 789d6e3.

📒 Files selected for processing (4)
  • doc/bin/relay/config.md
  • rs/moq-net/src/ietf/publisher.rs
  • rs/moq-net/src/ietf/subscriber.rs
  • rs/moq-net/src/stats.rs
✅ Files skipped from review due to trivial changes (1)
  • doc/bin/relay/config.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • rs/moq-net/src/stats.rs

Comment thread rs/moq-net/src/ietf/subscriber.rs Outdated
@kixelated kixelated enabled auto-merge (squash) June 30, 2026 03:32
@kixelated kixelated disabled auto-merge June 30, 2026 03:32
stop_announce is also called on local teardown after a failed write_ok /
write_publish_ok, where no unannounce/stream-close control event occurred.
Thread an explicit count_bytes flag so only real unannounces (NamespaceDone,
PublishNamespaceDone/stream close) bump announced_bytes; rollback paths pass
false.

Addresses CodeRabbit review feedback on #1953.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@kixelated kixelated enabled auto-merge (squash) June 30, 2026 03:36
@kixelated kixelated merged commit 9c3f559 into main Jun 30, 2026
2 checks passed
@kixelated kixelated deleted the claude/gifted-bassi-9b682e branch June 30, 2026 03:52
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.

1 participant