Skip to content

fix(net): only a new publisher re-arms the origin takeover gate - #2746

Merged
kixelated merged 5 commits into
mainfrom
claude/takeover-gate-publisher-only
Aug 12, 2026
Merged

fix(net): only a new publisher re-arms the origin takeover gate#2746
kixelated merged 5 commits into
mainfrom
claude/takeover-gate-publisher-only

Conversation

@kixelated

@kixelated kixelated commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

Follow-up to #2740 and #2742, from testing a residual concern raised while reviewing them.

  • A standby source could evict the live front with a cost-only repricing. Any route observation re-armed may_take_over, and lite::subscriber calls set_route on every same-publisher re-announce (rs/moq-net/src/lite/subscriber.rs, the entry.set_route(metadata) arm), so a peer repricing a link handed a source that had already lost the path a fresh takeover attempt.
  • Two rivals at one path then trade the front on metadata churn, and every trade unannounces and cuts the winner's subscribers. Confirmed with a test that fails on main today: A is displaced by B, A's peer re-announces at a new cost, and A takes the path back.
  • Cost is not content. Ownership of a path is decided by publisher identity; cost only orders routes within a front, via route_order and reselect. So re-arm the gate on a first-hop change alone.
  • Plain equality, matching the detach check in the same loop, so an UNKNOWN-to-UNKNOWN repricing from a legacy peer proves no new identity and does not re-arm either.

A source that never lost the path is unaffected: the flag starts set and only a displacement clears it, so an offline source going announced still takes over on the strength of the gate it was already holding.

Public API changes

None. run_source and attach_source are private.

Cross-package sync

Not applicable. No wire format or public API change, and js/net has no origin front/routing implementation to mirror.

Test plan

  • test_repricing_does_not_earn_a_takeover covers known publisher identities. It fails without the guard with left: OriginList([Origin { id: 1 }]), right: OriginList([Origin { id: 2 }]).
  • test_unknown_publishers_do_not_splice also covers UNKNOWN-to-UNKNOWN repricing. It fails without the guard at UNKNOWN-to-UNKNOWN repricing must not replace the live front.
  • nix develop --command cargo nextest run -p moq-net (718 passed)
  • nix develop --command just ci (2,823 passed, 13 skipped; clippy, formatting, docs, dependency policy, WASM, Nix flake, and workflow checks passed)

(Written by GPT-5)

A standby source could evict the live front with a cost-only repricing. Any
route observation re-armed `may_take_over`, and `lite::subscriber` calls
`set_route` on every same-publisher re-announce, so a peer repricing a link
handed a source that had already lost the path a fresh takeover attempt. Two
rivals at one path then trade the front on metadata churn, and each trade
unannounces and cuts the winner's subscribers.

Cost is not content. Ownership of a path is decided by publisher identity;
cost only orders routes within a front, via `route_order` and `reselect`. So
re-arm the gate on a first-hop change alone. Plain equality, matching the
detach check in the same loop, so an UNKNOWN-to-UNKNOWN repricing from a
legacy peer proves no new identity and does not re-arm either.

A source that never lost the path is unaffected: the flag starts set and only
a displacement clears it, so an offline source going announced still takes
over on the strength of the gate it was already holding.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for security reviews. Please try again later.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: daf56e49-044b-4501-b9b8-11b533a90985

📥 Commits

Reviewing files that changed from the base of the PR and between 9ae98da and 62637e1.

📒 Files selected for processing (1)
  • rs/moq-net/src/model/origin.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • rs/moq-net/src/model/origin.rs

Walkthrough

Takeover eligibility now re-arms only when a route’s first hop changes. Same-publisher cost and metadata updates no longer re-arm a displaced source, including UNKNOWN-to-UNKNOWN repricing. The source remains in standby until the incumbent leaves. Publisher changes can still reclaim or replace the path. Regression tests verify that repricing preserves the live replacement and emits no additional announce event.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title clearly states that only a new publisher re-arms the origin takeover gate, matching the primary change.
Description check ✅ Passed The description directly explains the takeover-gating fix, its impact, regression tests, and validation results.
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch claude/takeover-gate-publisher-only

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.

🧹 Nitpick comments (1)
rs/moq-net/src/model/origin.rs (1)

5000-5045: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for UNKNOWN-to-UNKNOWN repricing.

The current test uses two known first-hop IDs. It does not exercise the special equality case on Lines 1613-1616. Add a case where both displaced and live sources have Origin::UNKNOWN as their first hop, then reprice the displaced source and assert that no unannounce or announce occurs.

As per coding guidelines, "Reproduce bugs, identify and state the root cause, fix the lowest responsible layer, and add a regression test that fails without the fix."

(Written by CodeRabbit)

🤖 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/model/origin.rs` around lines 5000 - 5045, Extend
test_repricing_does_not_earn_a_takeover with a scenario where both displaced and
live routes use Origin::UNKNOWN as their first hop. Reprice the displaced
source, then assert the current broadcast remains live and announced emits
neither an unannounce nor an announce event, covering the UNKNOWN-to-UNKNOWN
equality handling.

Source: Coding guidelines

🤖 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.

Nitpick comments:
In `@rs/moq-net/src/model/origin.rs`:
- Around line 5000-5045: Extend test_repricing_does_not_earn_a_takeover with a
scenario where both displaced and live routes use Origin::UNKNOWN as their first
hop. Reprice the displaced source, then assert the current broadcast remains
live and announced emits neither an unannounce nor an announce event, covering
the UNKNOWN-to-UNKNOWN equality handling.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 97749b49-43d2-426a-b07c-f48439f26db6

📥 Commits

Reviewing files that changed from the base of the PR and between a56b6dc and 9ae98da.

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

@kixelated
kixelated merged commit 9040cfe into main Aug 12, 2026
1 check passed
@kixelated
kixelated deleted the claude/takeover-gate-publisher-only branch August 12, 2026 04:52
@moq-bot moq-bot Bot mentioned this pull request Aug 12, 2026
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