fix(nestsclient): skip Active announce when AnnouncePlease prefix doesn't match — moq-lite Lite-03 announce.rs

Per moq-lite Lite-03 (kixelated/moq `rs/moq-lite/src/lite/announce.rs`),
a publisher MUST only emit `Announce(Active)` for broadcasts whose path
starts with the requested AnnouncePlease prefix. Pre-fix, when
`MoqLitePath.stripPrefix(please.prefix, ourSuffix)` returned `null`, we
fell through to `?: announcePublisher.suffix` and emitted Active under
our full suffix anyway, falsely advertising the broadcast under a
prefix the subscriber didn't request.

Production never bit because the relay always opens its announce bidi
to us with `prefix=""` (which always matches), but a future peer-to-
peer or namespace-scoped subscriber would have observed a ghost
broadcast under whatever prefix they asked about.

The fix: if `stripPrefix` returns `null`, FIN the bidi cleanly without
writing any Announce body. The subscriber sees an empty announce
stream and moves on.

Regression test:
`MoqLiteSessionTest.publisher_skips_announce_when_announce_please_prefix_does_not_match`.

Audit doc: nestsClient/plans/2026-05-09-moq-lite-rfc-compliance.md (M4).

https://claude.ai/code/session_012TGfo99Ugz7fcCPv85a8Tq
This commit is contained in:
Claude
2026-05-09 13:51:24 +00:00
parent 3a346968db
commit 6c2d7efccb
2 changed files with 58 additions and 2 deletions
@@ -838,8 +838,27 @@ class MoqLiteSession internal constructor(
MoqLiteControlType.Announce -> {
val pleasePayload = buffer.readSizePrefixed() ?: return@collect
val please = MoqLiteCodec.decodeAnnouncePlease(pleasePayload)
val emittedSuffix =
MoqLitePath.stripPrefix(please.prefix, announcePublisher.suffix) ?: announcePublisher.suffix
// Per moq-lite Lite-03 (`rs/moq-lite/src/lite/announce.rs`),
// a publisher MUST only emit Active for broadcasts whose
// path starts with the requested prefix. If our suffix
// doesn't match, FIN cleanly without writing any
// Announce — the relay/peer sees an empty announce
// stream and moves on. Pre-fix we'd fall through the
// `null` branch of stripPrefix and falsely emit
// `Active(suffix=ourFullSuffix)`, advertising under a
// prefix the subscriber didn't ask for. Production
// never bit because the relay always asks for
// `prefix=""`, but a future peer-to-peer or
// namespace-scoped subscriber would see a ghost.
val emittedSuffix = MoqLitePath.stripPrefix(please.prefix, announcePublisher.suffix)
if (emittedSuffix == null) {
Log.w("NestTx") {
"ANNOUNCE inbound prefix='${please.prefix}' does not match publisher.suffix='${announcePublisher.suffix}' — FIN without Active"
}
runCatching { bidi.finish() }
dispatched = true
return@collect
}
bidi.write(
MoqLiteCodec.encodeAnnounce(
MoqLiteAnnounce(