Skip to content

Reproduce pending cold-start setup cancelled by epoch promotion - #5981

Closed
kixelated wants to merge 2 commits into
mainfrom
fix/epoch-promotion-pending-subscribe
Closed

kixelated wants to merge 2 commits into
mainfrom
fix/epoch-promotion-pending-subscribe

Conversation

@kixelated

Copy link
Copy Markdown
Collaborator

A first subscription creates demand while TRACK_INFO is still pending. Promoting the same exact BroadcastProducer from an epochless advertisement to a new epoch retires the implicit route-selection period, cancelling that pending setup with Unroutable. Established sticky subscriptions are a separate case and are already covered by the existing restart tests.

This diagnostic draft preserves a minimal failing regression for Lite06, Lite07 and IETF17. It currently fails on main 2e1ec2ebf; the same Lite06 scenario also fails on 848927038 with Dropped. Full just fix passes. The three protocol cases fail intentionally; this draft is not landable.

Do not relax RequestValidity to keep pending metadata requests alive indiscriminately: that could combine metadata from the previous publisher with media requested from its replacement. The existing announcement-takeover quest explicitly owns outstanding TRACK/SUBSCRIBE/FETCH preservation and equal clamped prefixes; no new protocol operation is proposed here. This exact-producer promotion case differs from the prefix-answer API in #5678, which explicitly accepts cold-start refusal before takeover.

Recommended dependency: implement and adopt proven takeover for pending setup, preserving the distinction between an established subscription's stickiness and a pending subscription's no-abort guarantee. Mixed/legacy hops must retain their explicit compatibility behavior. No protocol masking or unsafe validity relaxation is included.

(written by GPT-6)

kixelated and others added 2 commits October 19, 2026 12:02
Co-Authored-By: GPT-6 <noreply@openai.com>
Diagnostic checkpoint: currently fails on upstream main for Lite06, Lite07 and IETF17. Pending setup requires proven takeover; established sticky subscriptions do not cover this race.

Co-Authored-By: GPT-6 <noreply@openai.com>
@kixelated

Copy link
Copy Markdown
Collaborator Author

Root cause, reproduced on main 877d6fe27 (all three cases fail with Unroutable):

  • The promotion is a new instance by contract. broadcast::Producer::announce documents that another epoch announces a new broadcast, and every hop sees a restart (ANNOUNCE_RESTART, or an end then a start).
  • An epochless request names no instance on the wire (lite::Track { epoch: None }), so the receiving session binds it to the instance its route named. Lite mints a source per route entry carrying a selection period (RequestValidity::for_source) and the entry's liveness token; IETF binds the namespace's selection period. TrackInfoFetch::poll_fetch (lite) and the SUBSCRIBE setup loop (IETF) return Unroutable once the period retires or the token closes.
  • Characterized by removing the guards: dropping the Period check alone makes IETF-17 pass; lite-06/07 still fail on the route liveness token.
  • The guard is load-bearing. A relay that sees the replacement before the request arrives resolves an epochless request against the new instance, while the requester's broadcast handle, and any epochless catalog reference, describe the old one.

So this is not an internal bug fix. Keeping a pending request across the change needs a continuity assertion on the wire: announce takeover on lite-07 and IETF takeover. Lite-06 can never carry one, so its case here contradicts the plan (older wires keep the restart), which matches decision 3 of moq-dev/moq#5678: accept the cold-start reset until takeover lands.

The test also promotes through announce on one producer, which the API defines as a new broadcast; takeover's shape is Request::prepare/publish plus a Takeover event. Suggest folding a lite-07 form of this case into the takeover PR's pending TRACK/SUBSCRIBE/FETCH tests and closing this draft. The lite-06 and IETF-17 forms would instead assert the restart and a successful re-request.

Rejected alternatives: retargeting or holding the pending request onto the winning route (mixes old metadata with new frames, as the body says), and accepting an answer that carries the serving epoch (rejected in the 2026-10-10 audit: response metadata alone never makes an epochless route eligible). A distinct retryable error instead of Unroutable is additive but still aborts.

One option for the maintainer: a narrower first takeover slice where a live announcement gains its own epoch in place (one announcer, so continuity is known locally). It needs a lite-07-wip message and an explicit producer operation, since announce with an epoch means a new broadcast. It avoids the claim-answer-epochs and routes prerequisites, but relays still need serving provenance, and it adds the second identity path the quest asks to avoid.

(Written by Claude Opus 5.5)

@kixelated

Copy link
Copy Markdown
Collaborator Author

Closing: promoting a broadcast to a new epoch is a new instance by contract, so ending the pending cold-start request (rather than stitching it onto the new instance) is the intended behavior. Any change to how a takeover hands off pending requests belongs to the announcement-takeover quest.

(Written by Claude Opus 5.5)

@kixelated kixelated closed this Oct 20, 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