Skip to content

Specify dynamic (pattern) advertisements in moq-lite, plus a moqt extension draft - #3005

Open
kixelated wants to merge 4 commits into
devfrom
claude/wildcard-advertisement-draft
Open

Specify dynamic (pattern) advertisements in moq-lite, plus a moqt extension draft#3005
kixelated wants to merge 4 commits into
devfrom
claude/wildcard-advertisement-draft

Conversation

@kixelated

@kixelated kixelated commented Aug 22, 2026

Copy link
Copy Markdown
Collaborator

A publisher can advertise a pattern of paths it could serve on demand — a prefix and a suffix, either half empty — instead of enumerating every broadcast. Three workloads motivate it (planned in moq.pro's wildcard questline): a transcode worker advertising ("", "transcode.pro") once for a whole fleet instead of a standby announcement per matching broadcast, a chat backend advertising ("<pid>/chat", "") for rooms that exist independently of any broadcast, and an archive advertising ("", "") — "if nobody is publishing this live, I have it".

moq-lite

  • A new Wildcard Stream (0x7): WILDCARD_REQUEST/WILDCARD_OK, then WILDCARD_START, WILDCARD_END, and WILDCARD_UPDATE, mirroring the Announce Stream's mechanics with their own Wildcard ID space. A separate stream because a wildcard is routing capability rather than content discovery — the consumer API is different — and because it makes deployment graceful by existing rule: a peer without support resets the unknown stream type (the spec's non-fatal extension fallback), so broadcast announcements are never at risk and no shared implicit-id counter forces an ignoring peer to count messages it does not understand. The request prefix rebases the pattern's prefix half exactly like ANNOUNCE_START's path suffix; the suffix half is untouched by rebasing, which is what lets one fleet-wide pattern surface inside every scoped view.
  • A wildcard is a capability, not an inventory: it never implies a matching path exists; refusal denies one path. No Epoch (a pattern names no generation). One Route Cost rather than the Warm/Cold pair — a wildcard is never warm, so the halves would be provably equal. Hop list, loop discard, cost accumulation, and per-subscriber origin exclusion apply unchanged.
  • Resolution: only the most specific matching tier (longest literal match, prefix plus suffix in segments) is consulted; cost orders the tier and a hash of the requested path distributes across the pool, so a pattern is a worker pool rather than a contest. A standby seed MUST clear the maximum accumulated topology cost, or a nearby standby outranks a distant publisher already doing the work.
  • Typed refusal: new stream error code 0x20 CAPACITY permits exactly one re-resolution, within the tier and excluding the refuser (a retraction and a request for the slot it gave away necessarily cross in flight). Every other code, and any unrecognized one, is terminal — probing unserved paths costs one round trip per path, and there is no fallback list.
  • Removed the Ended flag from ANNOUNCE_REQUEST, ANNOUNCE_START, and ANNOUNCE_UPDATE. Announcing recordings is per-recording announce state — the exact growth wildcards exist to stop. A recording is discovered out of band (e.g. a catalog, which also carries the generation identity) and read via FETCH, with a wildcard routing the request to whatever serves it. The ended-broadcast content state survives in the Subscribe/Fetch prose; only its announce-layer representation is gone.
  • Path matching respecified as segment-aware (/-delimited, whole segments only), matching what the implementations actually do; the draft previously said byte-by-byte.

moq-cluster

Mirrored as the WILDCARD_SUFFIX parameter (0x40B59, odd = length-prefixed) on PUBLISH_NAMESPACE and the extended NAMESPACE: the message's namespace is the pattern's prefix, the parameter the suffix. Same selection tiers, capacity-refusal re-resolution, and standby seed floor; ROUTE_COST never takes the actively-carrying discount on a pattern.

Ended was added within the unreleased lite-06, so its changelog bullet is deleted rather than a removal logged; the wildcard, CAPACITY, and segment-aware changes get bullets. The doc-site table test learns the stream table's new row. just drafts check and bun run --cwd doc check both pass.

🤖 Generated with Claude Code

(written by Fable 5)

A publisher can advertise a (prefix, suffix) pattern of paths it could
serve on demand instead of enumerating them: WILDCARD_START (0x3) and
WILDCARD_UPDATE (0x4) on the Announce Stream, sharing the Announce ID
space and retracted by ANNOUNCE_END. A wildcard is a capability rather
than an inventory, carries a hop list and one Route Cost (no Epoch,
never warm), and forwards under the existing routing rules. Resolution
for an unadvertised path consults only the most specific matching tier,
orders it by cost, and distributes by a hash of the requested path; a
new CAPACITY stream error (0x20) permits one re-resolution excluding
the refuser, while every other reset stays terminal. Mirrored in
moq-cluster as the WILDCARD_SUFFIX parameter.

The Ended flag is removed from ANNOUNCE_REQUEST, ANNOUNCE_START, and
ANNOUNCE_UPDATE: announcing recordings is per-recording announce state,
the growth wildcards exist to stop, and a recording is discovered out
of band and read via FETCH with the wildcard routing the request. Path
matching is respecified as segment-aware, matching the implementations.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c529de518f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread drafts/draft-lcurley-moq-cluster.md Outdated
The original publisher seeds the value with its production cost: 0 for content it is already producing, higher for content it would have to spin up on demand, such as a standby transcoder advertising everything it *could* serve.

## WILDCARD_SUFFIX Parameter {#wildcard-suffix}
A publisher MAY advertise a pattern of namespaces rather than an exact one: a PUBLISH_NAMESPACE or NAMESPACE carrying WILDCARD_SUFFIX matches every namespace that starts with the message's namespace and ends with the parameter's fields, both possibly empty and matching whole tuple fields.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Rebase NAMESPACE wildcard prefixes against the subscription

When a wildcard is carried in a NAMESPACE response, the message's namespace field is a suffix relative to the enclosing SUBSCRIBE_NAMESPACE prefix, not an absolute namespace. For example, under a subscription to tenant, a NAMESPACE suffix of worker must describe the prefix tenant/worker; treating worker as the complete pattern prefix matches the wrong namespaces and validates authorization against the wrong scope. Specify reconstruction against the subscribed prefix while keeping PUBLISH_NAMESPACE absolute. (Written by GPT-5.6 Sol)

Useful? React with 👍 / 👎.

Comment thread drafts/draft-lcurley-moq-cluster.md Outdated
|:--------|:----------------|:-----------------------------|:--------------|
| 0x40B57 | HOP_PATH | PUBLISH_NAMESPACE, NAMESPACE | This Document |
| 0x40B58 | ROUTE_COST | PUBLISH_NAMESPACE, NAMESPACE | This Document |
| 0x40B59 | WILDCARD_SUFFIX | PUBLISH_NAMESPACE, NAMESPACE | This Document |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Negotiate WILDCARD_SUFFIX separately

During a rolling upgrade, an older peer can successfully negotiate RELAY_HOPS and then receive this newly registered parameter without supporting it. The existing moq-transport message-parameter decoder (decode_params! in rs/moq-net/src/ietf/parameters.rs) deliberately rejects unknown message parameters, so the advertisement or session fails instead of degrading to non-wildcard behavior. Add a separately negotiated SETUP capability or a protocol-version boundary, and send WILDCARD_SUFFIX only after the peer advertises support. (Written by GPT-5.6 Sol)

AGENTS.md reference: AGENTS.md:L204-L204

Useful? React with 👍 / 👎.

Comment thread drafts/draft-lcurley-moq-cluster.md Outdated

A request for a namespace nothing advertises MAY resolve against pattern advertisements ({{wildcard-suffix}}), after the same origin exclusion.
Only the most specific matching tier is consulted (the longest literal match, prefix plus suffix in tuple fields; equal-specificity patterns form one pool ordered by ROUTE_COST, then distributed by a deterministic hash of the requested namespace against each advertiser).
A reset with a capacity error permits one re-resolution within the tier, excluding the refuser; every other reset is terminal, so probing unserved namespaces costs one round trip each.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Define a transport-level capacity refusal

In moq-transport, requests are refused with REQUEST_ERROR, while a stream reset does not provide the typed application response this rule needs; this draft also assigns no numeric capacity code or REQUEST_ERROR mapping. Consequently, a receiver cannot distinguish retryable capacity exhaustion from a terminal refusal, making the specified one-time re-resolution non-interoperable. Define and register the exact REQUEST_ERROR code and its carriage rather than referring to an unspecified reset. (Written by GPT-5.6 Sol)

Useful? React with 👍 / 👎.

Comment thread drafts/draft-lcurley-moq-lite.md Outdated
Comment on lines +397 to +400
A receiver MAY resolve a SUBSCRIBE, FETCH, or TRACK request for an unadvertised path against its wildcards.
Only the most specific matching tier is consulted: the longest literal match, prefix plus suffix in segments, with equal-specificity patterns forming one pool.
Within the tier, order by lowest accumulated Route Cost, then distribute by a deterministic hash of the requested path against each advertiser, so a set of paths spreads across a pool of advertisers while one path always resolves the same way.
A resolved path competes on that same cost against a concrete advertisement of it; nothing ranks the two kinds differently.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Make wildcard eligibility consistent with concrete advertisements

The first sentence limits wildcard resolution to an unadvertised path, but the following rule requires the resolved wildcard path to compete with a concrete advertisement. When both an exact publisher and a matching standby exist, conforming implementations can therefore either ignore the wildcard or compare their costs, selecting different publishers and potentially starting duplicate production. State one eligibility rule and cross-reference it consistently. (Written by GPT-5.6 Sol)

AGENTS.md reference: drafts/AGENTS.md:L69-L72

Useful? React with 👍 / 👎.

A wildcard is routing capability, not content discovery, so it no
longer rides the Announce Stream: WILDCARD_REQUEST/WILDCARD_OK then
WILDCARD_START/END/UPDATE mirror the announce mechanics with their own
Wildcard ID space. The separation also buys the deployment story for
free: a peer without support resets the unknown stream type, which the
spec already defines as the non-fatal extension fallback, so broadcast
announcements are never at risk and no shared implicit-id counter
forces an ignoring peer to count messages it does not understand. The
doc test pinning the stream table's row count learns the new row.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kixelated

Copy link
Copy Markdown
Collaborator Author

Reworked in cdbafd7 per @kixelated's review: wildcards now live on their own Wildcard Stream (0x7) instead of riding the Announce Stream. Beyond the API-shape argument (routing capability vs content discovery), the shared design had two concrete problems the separation removes. Announce IDs are implicit — derived from message order — so a peer that merely tolerated unknown wildcard messages would still have had to count them to keep broadcast ids aligned; each stream now has its own counter. And a new message type on the shared stream would have killed an older peer's announce stream outright, forcing the accept-first fleet staging; the spec already defines unknown stream types as a non-fatal reset ("the fallback when an extension stream is opened against a peer that did not negotiate it"), so the new stream degrades gracefully and announcements are never at risk.

The cluster mirror is unchanged (parameter-based). The cross-kind rules the shared design needed (ANNOUNCE_UPDATE-on-a-wildcard-id violations, the Active Count contortion) are gone with it.

(written by Fable 5)

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cdbafd7b63

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread drafts/draft-lcurley-moq-lite.md Outdated
Comment on lines +1010 to +1012
The remainder of the pattern's prefix after the stream's requested prefix, like ANNOUNCE_START's Broadcast Path Suffix.
A pattern belongs on a stream when it can match a path under the requested prefix: its prefix extends the requested one (encode the remainder) or the requested one extends its prefix (encode empty, since every path on the stream already satisfies it).
Empty means every path under the requested prefix.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve suffix overlap when rebasing wildcard prefixes

When the requested prefix extends the wildcard prefix, encoding an empty remainder is not equivalent if the requested prefix already contains the wildcard suffix. For example, pattern (foo, bar) matches foo/bar because its halves are adjacent, but on a stream requesting foo/bar this rule reconstructs (foo/bar, bar), which cannot match foo/bar under the non-overlap rule. A valid scoped subscriber therefore silently loses the exact path; define an encoding or reconstruction rule that preserves this overlap. (Written by GPT-5.6 Sol)

Useful? React with 👍 / 👎.

The mechanism routes dynamically produced broadcasts and namespaces;
"wildcard" named the matching shape and implied glob syntax the design
does not have. The lite stream becomes the Dynamic Stream (0x7) with
DYNAMIC_REQUEST/OK/START/END/UPDATE and Dynamic IDs.

The moq-transport mirror moves out of moq-cluster into a standalone
extension, draft-lcurley-moq-dynamic: a DYNAMIC setup option (0x40B5B)
negotiates support, the DYNAMIC_SUFFIX parameter (0x40B59) marks a
PUBLISH_NAMESPACE or extended NAMESPACE as a pattern, and the
capability, specificity-tier selection, capacity-refusal retry, and
authorization semantics travel with it. Cost ordering references
moq-cluster as an optional integration, so the extension stands without
the mesh machinery; moq-cluster reverts to untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kixelated kixelated changed the title Specify wildcard (pattern) advertisements in moq-lite and moq-cluster Specify dynamic (pattern) advertisements in moq-lite, plus a moqt extension draft Aug 22, 2026
@kixelated

kixelated commented Aug 22, 2026

Copy link
Copy Markdown
Collaborator Author

Two more review-driven changes in 307422a:

Renamed wildcard → dynamic throughout, per @kixelated: the mechanism routes dynamically produced broadcasts/namespaces, while "wildcard" named the matching shape and implied glob syntax the design deliberately lacks (the message carries two literal halves, no wildcard character). The lite stream is now the Dynamic Stream (0x7) with DYNAMIC_REQUEST/OK/START/END/UPDATE and Dynamic IDs; prose says "dynamic advertisement".

Split the moqt half into a standalone extension draft, draft-lcurley-moq-dynamic, instead of a parameter buried in moq-cluster: a DYNAMIC setup option (0x40B5B, empty value) negotiates support — required, because an un-negotiated receiver would read the advertisement as a concrete namespace — and the DYNAMIC_SUFFIX parameter (0x40B59) carries the pattern's suffix on PUBLISH_NAMESPACE and, when cluster is also negotiated, the extended NAMESPACE. Selection, capacity-refusal retry, and authorization travel with it; ROUTE_COST ordering is an optional integration referencing moq-cluster informatively, so the extension is usable without the mesh machinery. moq-cluster is reverted to untouched.

just drafts check and bun run --cwd doc check pass; the new draft is picked up by the doc site automatically.

(written by Fable 5)

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 307422ac85

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread drafts/draft-lcurley-moq-lite.md Outdated
When the stream is closed, the subscriber MUST assume that all broadcasts are now unavailable.

Path prefix matching and equality is done on a byte-by-byte basis.
Paths are sequences of `/`-delimited segments, and all matching is segment-aware: a prefix (or suffix) matches only whole segments, so `foo` is a prefix of `foo/bar` but not of `foobar`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Define canonical slash handling for segment matching

When an untrusted path contains leading, trailing, or repeated slashes, this rule does not say whether empty segments are retained, collapsed, or rejected. The Rust and JS decoders currently normalize those forms (rs/moq-net/src/path.rs and js/net/src/path.ts), while another implementation can reasonably preserve the empty segments, causing peers to disagree on advertisement matching and authorization scope. Specify canonicalization or reject noncanonical paths before applying the new segment-aware comparisons. (Written by GPT-5.6 Sol)

AGENTS.md reference: drafts/AGENTS.md:L10-L13

Useful? React with 👍 / 👎.

# Acknowledgments
{:numbered="false"}

This document was drafted with the assistance of Claude, an AI assistant by Anthropic.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Remove the model attribution from the rendered draft

This source is translated into a /doc/draft/ page, so the acknowledgment publishes a source-level AI attribution that repository guidance explicitly prohibits because those markers rot. Remove the attribution from the draft. (Written by GPT-5.6 Sol)

AGENTS.md reference: AGENTS.md:L111-L111

Useful? React with 👍 / 👎.

The pattern prefix now travels whole - the requested prefix filters
which patterns a stream carries but never rebases the encoding, since
rebasing was lossy and corrupted specificity, re-forwarding, and
pattern identity. The ended-broadcast lifecycle is stated: a broadcast
that ends but remains readable retracts with ANNOUNCE_END (which never
disturbs in-flight subscriptions) and serves stored groups over FETCH,
discovered out of band. CAPACITY moves to 0x30, clear of every value
current implementations emit as placeholders, the reserved range
admits assigned exceptions so the session space keeps 0x20 reserved,
and a receiver that spent its one re-resolution refuses downstream
with a terminal code so the retry cannot compound per hop. Selection
pins the rendezvous FNV-1a hash (seed, input, advertiser identity),
states that spreading among cost-equals is the design, and defines the
mixed dynamic-versus-concrete comparison (single cost as both halves,
kind carries no rank, concrete tie-break chain applies). Authorization
is receiver-side in both documents with discard as the action. Path
grammar and equality are defined. moq-dynamic becomes implementable:
cluster is a normative reference whose HOP_PATH/ROUTE_COST rules apply
unchanged, multi-hop resolution requires it, DYNAMIC_CAPACITY is named
and registered, and the codepoints move to 0x40B5C/D/F, clear of
moq-broadcast's 0x40B59/0x40B5B.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kixelated

Copy link
Copy Markdown
Collaborator Author

Ran a high-effort review over this PR (8 finder angles, adversarially verified); ten findings, nine confirmed, all fixed in eec6991:

  • Prefix rebasing was lossy — a pattern forwarded onto a deeper-scoped stream lost its original prefix, inflating specificity per-relay and shrinking coverage on re-forwarding. The prefix now travels whole; the request prefix filters, never rebases.
  • The ended-broadcast lifecycle was undefined after the Ended removal — keep-advertised and retract were both conformant and could not interop. Now: retraction claims nothing about content and never disturbs in-flight subscriptions; a recording retracts and serves stored groups over FETCH, discovered out of band.
  • CAPACITY sat at 0x20, which deployed moq-net already emits as its NotFound placeholder, and the range narrowing left session-space 0x20 uncovered. Moved to 0x30 with an assigned-exception clause on the reserved range.
  • Selection: strict cost-then-hash made the hash unreachable for unequal costs; the draft now states spreading among cost-equals is the design, pins the rendezvous FNV-1a hash (seed, input, advertiser identity = first hop entry), states per-receiver recursion, and defines the mixed dynamic-vs-concrete comparison (single cost as both halves, kind carries no rank).
  • CAPACITY semantics: scoped to dynamically resolved requests, exclusion keys on the advertiser identity, and a receiver that spent its one re-resolution refuses downstream with a terminal code so the retry cannot compound per hop.
  • Authorization now binds the receiver in both documents (the two drafts previously put the MUST on opposite actors) with discard as the action.
  • moq-dynamic is now implementable standalone: cluster is a normative reference whose HOP_PATH/ROUTE_COST rules apply unchanged, multi-hop resolution requires it, DYNAMIC_CAPACITY is named and registered, and the codepoints moved to 0x40B5C/D/F — the old ones were moq-broadcast's two values swapped.
  • Path grammar and equality are defined (normalized non-empty segments, byte equality).

Implementation of the Dynamic Stream in rs/moq-net is underway on a stacked branch.

(written by Fable 5)

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: eec69912fb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Only the most specific matching tier is consulted: the longest literal match, prefix plus suffix in segments, with equal-specificity patterns forming one pool.
Within the tier, the lowest accumulated Route Cost wins, and a deterministic hash distributes among advertisements tied at that lowest cost.
Spreading among equals is the design: a co-located worker pool ties on cost and shares the work, while a costlier advertiser is deliberately overflow rather than an equal peer.
The hash is rendezvous-style FNV-1a: for each candidate, hash the requested path's bytes followed by the advertiser identity as a 64-bit little-endian value, seeded with 0x420C0DECB00B, and select the highest result, so one path always resolves the same way and a pool member arriving or leaving moves only its own share.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Hash the normalized path representation

When equivalent noncanonical spellings such as /foo//bar and foo/bar/ reach a dynamic pool, the comparison rule normalizes them into one path, but this line hashes the received bytes and therefore permits them to select different advertisers and start duplicate production for the same broadcast. The fresh evidence beyond the earlier slash-handling comment is that normalization is limited to comparisons while the newly specified rendezvous input remains raw bytes; require the normalized bytes here as well. (Written by GPT-5.6 Sol)

AGENTS.md reference: AGENTS.md:L111-L111

Useful? React with 👍 / 👎.

When several patterns match, only the most specific tier is consulted: the longest literal match, prefix plus suffix in tuple fields, with equal-specificity patterns forming one pool.
A refusal from that tier is the answer; it never falls through to a less specific pattern, so a request the winning tier will not serve costs one round trip rather than a walk down the candidates.

Within the tier, the lowest accumulated ROUTE_COST wins, and a deterministic hash distributes among advertisements tied at that lowest cost, so a set of namespaces spreads across a co-located pool while a costlier advertiser is deliberately overflow.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Define selection without Relay Hops

When peers negotiate DYNAMIC but not the cluster extension, direct single-hop resolution remains permitted by lines 79-80, yet no advertisement carries ROUTE_COST and this rule still requires the lowest accumulated value to win. With multiple matching direct advertisers, implementations cannot determine whether missing costs are zero or whether local policy should choose; define the no-cluster ordering/default or require Relay Hops for all resolution. (Written by GPT-5.6 Sol)

AGENTS.md reference: AGENTS.md:L111-L111

Useful? React with 👍 / 👎.

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