Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4523630
quest: claim m1/model-public-surface
kixelated Oct 16, 2026
c3e90df
quest(m1): inventory the hidden model and plan its public surface
kixelated Oct 16, 2026
797449c
Merge remote-tracking branch 'origin/main' into pr-5717-iterate
kixelated Oct 16, 2026
5d1ca8f
quest(m1): record the public model decisions
kixelated Oct 16, 2026
126a480
quest(m1): keep empty origin handles and enforce model marks in CI
kixelated Oct 16, 2026
4ec13be
quest(m1): keep created groups visible so group demand works
kixelated Oct 16, 2026
cb75e50
quest(m1): keep the runtime FrameOpen guard for owned frames
kixelated Oct 16, 2026
6019165
Merge branch 'main' of github.com:moq-dev/moq into quest/m1/model-pub…
kixelated Oct 16, 2026
bf89645
quest(m1): address public model review findings
kixelated Oct 16, 2026
dd95d58
quest(m1): settle blind answers and the deferred largest prerequisite
kixelated Oct 16, 2026
39002cb
quest(m1): end resolved blind requests with their answerer; complete …
kixelated Oct 16, 2026
bb1ce53
quest(m1): drop withheld groups and public group Clone
kixelated Oct 16, 2026
76ccdeb
quest(m1): end resolved blind requests when a route takes the path
kixelated Oct 16, 2026
79ada7d
quest(m1): settle the fallback answerer and bounds naming
kixelated Oct 16, 2026
489e007
quest(m1): catch every crate-wide spelling and place Established as p…
kixelated Oct 16, 2026
5fa27e2
quest(m1): count a root-level pub(super) as crate-wide
kixelated Oct 16, 2026
269cc8d
quest(m1): scope pub(super) in the narrow goal too
kixelated Oct 16, 2026
9c6c52d
quest(m1): allowlist model visibilities instead of enumerating bad ones
kixelated Oct 16, 2026
c2d86d0
quest(m1): plan the JS import-edge check beside the Rust one
kixelated Oct 16, 2026
6c43302
quest(m1): assign poll_past to the idle copy and gate it on started g…
kixelated Oct 16, 2026
4cc438e
quest(m1): separate JS markers from stripInternal in the narrow plan
kixelated Oct 16, 2026
b118d32
quest(m1): make Narrow a prerequisite of each public-model child
kixelated Oct 16, 2026
ad9c07e
quest(m1): seed markers for every unexported module session code reaches
kixelated Oct 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion quest/m1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ above them.
- [Live largest location](/quest/m1/largest.md) - `largest()` replaces `latest()` in Rust and JS as a live stream of the track's largest location, known before the first group from the publisher's report
- [Live TS clock validation](/quest/m1/ts-live-clock.md) - resolve the local PCR-rate failure with reproducible timing evidence and CI controls
- [More tests under load](/quest/m1/test-flakes-2/README.md) - the second round of load-only failures, one quest per flake, fixed at the cause
- [Plan: a public model](/quest/m1/model-public-surface.md) - every crate-private model item is made public or unnecessary, so a custom publisher or subscriber builds from the public model alone
- [A public model](/quest/m1/public-model/README.md) - every model item a built-in session reaches is public, unnecessary, or marked deliberately private, so a custom publisher, subscriber, or relay builds from the public model alone
- [Lazy discovery](/quest/m1/lazy-discovery/README.md) - a `consume` session requests announcements only for prefixes the origin is watching, in JS then Rust; `follow`, `broadcasts`, and the `discovery` option go away
- [Announce caught up](/quest/m1/announce-live.md) - Rust and JS announce consumers expose when a session's initial announce snapshot has arrived, from the counts the wire already carries where a version has them
- [A spinning loop fails a sim test](/quest/m1/spinning-loops.md) - a sim test names any loop that holds a task poll too long, and each one yields through a budget
Expand Down
4 changes: 2 additions & 2 deletions quest/m1/ietf-extension/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ cannot answer unambiguously is refused.
Rewriting them would violate immutability; forwarding unchanged
across those families would change their meaning.
- **Public model carve-out.** These fields stay crate-private on purpose,
an exception to [a public model](/quest/m1/model-public-surface.md). A
an exception to [a public model](/quest/m1/public-model/README.md). A
third-party relay built on the public model drops them, as plain lite
does.
- **Verification:** Rust integration tests per feature in each child, plus
Expand Down Expand Up @@ -90,4 +90,4 @@ Work owned by this README, after the children land:
## Related

- [#4926](https://github.com/moq-dev/moq/issues/4926) - the declined request for an object-level API; this carries the fields for relays only
- [Plan: a public model](/quest/m1/model-public-surface.md) - these fields are its deliberate exception
- [A public model](/quest/m1/public-model/README.md) - these fields are its deliberate exception
52 changes: 0 additions & 52 deletions quest/m1/model-public-surface.md

This file was deleted.

108 changes: 108 additions & 0 deletions quest/m1/public-model/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# A public model that builds any publisher or subscriber

## Goal

A third party builds its own publisher, subscriber, or forwarding relay (a
custom transport, relay, or wire) from the public moq-net and @moq/net model
alone. Every model item a built-in session reaches is public, made
unnecessary, or marked deliberately private with its reason.

Non-goals: changing the wire, or exposing session internals that are not part
of the model (`ietf/`, `lite/`, connection plumbing, wire codecs).

## Plan

Planned 2026-10-16 from the inventory below; the per-item decisions live in
the children's Plans, and the maintainer settled the open ones in #5717.

Rules every child follows:

- Track metadata is never private (decided 2026-10-11 in the #5283 triage).
- Each item is made public under a role name mirrored in Rust and JS,
replaced by a smaller public handle that makes misuse unrepresentable, or
made unnecessary. Each child lists its public API additions and removals
in its PR for review.
- Deliberately private, marked in a comment on the item so the next
inventory skips it:
- "moq-transport passthrough only" (decided 2026-10-13; subgroups were
dropped from it in #5704): object IDs and `skip`, object and unknown track properties, END_OF_GROUP status
objects, datagram object IDs, dynamic groups, and upstream request
signaling. Owned by [moq-transport passthrough](/quest/m1/ietf-extension/README.md).
A relay built on the public model drops them, as plain moq-lite does.
- "tunes the built-in sessions": constants and wake or allocation batching
that change cost, never behavior a third party can observe.
- "capability gap": a built-in behavior a third party can observe but
not reproduce yet, kept private by a recorded decision that names what
would close it (the idle copy in [ingest](/quest/m1/public-model/ingest.md)).
- Items replaced by another quest's new API wait for that quest instead of
growing a public shape it deletes: fetch and per-group requests
([Model ranges](/quest/m1/subscribe-ranges/model.md)), largest and
liveness ([Live largest location](/quest/m1/largest.md)), announce
interest ([Rust lazy discovery](/quest/m1/lazy-discovery/rust.md)), and
the received tail ([Tail arrivals](/quest/m1/tail-arrivals.md)).

Inventory method, to rerun before each child starts (counts drift). Rust:
replace every `pub(crate)` under `rs/moq-net/src/model/` with
`pub(in crate::model)`, then run `cargo check -p moq-net --features fuzz`
and restore each item the compiler names until it builds; repeat with
`--tests` for test-only reach. JS: list what `src/{ietf,lite,connection}/`
import from `internal.ts`, `wire.ts`, and modules `index.ts` does not
export, plus `@internal` members (`stripInternal` hides them from the
published types).
Comment thread
kixelated marked this conversation as resolved.
Resolved

Inventory on `main` at b4eab0db1:

- Rust has 347 `pub(crate)` items in `model/` and no `#[doc(hidden)]` model
item. 106 are reached by session code, 16 only by session tests, and 225
only inside `model/`.
- The 106 split into [ingest](/quest/m1/public-model/ingest.md),
[serving](/quest/m1/public-model/serve.md),
[routes and answering](/quest/m1/public-model/answer.md), and the
passthrough carve-out (listed in each child where it shares a type).
- The 16 test-only items (`group::Info::produce`, `group::Producer::is_aborted`
and `is_finished`, `track::Info::timed`, `track::Producer::new`,
`publisher_priority` and `start_sequence`, `track::Consumer::poll_group`
and `resume_position`, `FetchOutcome::rejected`,
`origin::Producer::announce` with `AnnounceProducer` and `ProduceTest`,
`origin::Consumer::get_broadcast`) stay crate-private test helpers: a third
party tests through the public API it uses.
- The 225 model-internal items stay private.
- JS publishes only `src/index.ts`, with `stripInternal` on. Sessions reach
past it through `internal.ts` (helpers and 22 `hooks`, 7 of them called
by sessions: `endTrack`, `pendingTrackProducer`, `tryRecvGroup`,
`groupChanged`, `replaceGroups`, `guardGroup`, `readGroupFrame`), the
`wire.ts` views (`Broadcast`, `OriginProducer`, `OriginConsumer`,
`Established`), `@internal` members (`Track.Subscriber.fork`,
`Group.Producer.mirror`), and modules the index does not export
(`hop.ts` values, `announced.ts` `Producer`, `consume.ts`, `tail.ts`,
Comment thread
kixelated marked this conversation as resolved.
Resolved
`priority.ts`). Model-internal hooks (sequence namespaces, timestamps,
arrival, eviction, announcer stamping) stay private. Each session-reached
item is assigned in a child, except `wire.ts` `Established` (`consume`,
`goaway`). It is connection plumbing outside the model, a session handle
the connection layer uses, and stays private like the other excluded
plumbing.

Work owned by this README, after the children land:

- Rerun the inventory and confirm every `pub(crate)` left in `model/` is a
marked passthrough, tuning, capability-gap, or test-only item, so the
"pending" marks from [Narrow the model](/quest/m1/public-model/narrow.md)
are all gone.
- Prove the result with a toy transport that uses only the public API: an
integration test under `rs/moq-net/tests/` (outside the crate, so the
compiler enforces it) and a JS test importing only the package entrypoint.
Each runs a minimal publisher, subscriber, and forwarding relay with route
ingestion and answering, on mock time, in CI.

## Required

- [Narrow the model](/quest/m1/public-model/narrow.md) - a new model item a session reaches fails to compile until it is made public or marked, while the other children are in flight
- [Public ingest](/quest/m1/public-model/ingest.md) - a custom subscriber writes received groups, frames, starts, and ends into a track through public calls
- [Public serving](/quest/m1/public-model/serve.md) - a custom publisher reads a track's start, cursor, and group expiry for its wire through public calls
- [Public routes and answering](/quest/m1/public-model/answer.md) - a custom relay ingests routes, answers broadcast and track requests on demand, and advertises without echoing a peer's routes back
Comment on lines +99 to +102

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 Make narrowing a prerequisite for each implementation child

narrow.md says it must run before the other children, but this dependency list makes Narrow, Public ingest, Public serving, and Public routes and answering independent sibling requirements. Quest can therefore schedule an implementation child first, before the visibility rewrite and marker lint exist, defeating the promised compile-time guard while that child edits model APIs. Add Narrow to each implementation child's Required list; the deferred child can inherit it transitively.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Agreed. In b118d32 Narrow is in the Required list of ingest.md, serve.md and answer.md, so no implementation child can be scheduled before the visibility rewrite and marker lint; deferred.md inherits it through them.

(Written by Claude Opus 5.5)

- [Public model after ranges, handover, and the JS tail](/quest/m1/public-model/deferred.md) - fetch and track-info answering, the cache peeks, JS `fork`/`mirror`, and JS `endTrack`, once the quests that reshape them land

## Related

- [moq-transport passthrough](/quest/m1/ietf-extension/README.md) - the deliberate exception to this rule
- [#5283](https://github.com/moq-dev/moq/pull/5283) - made the END_OF_TRACK location public, the first item under this rule
Loading