Commit Graph

10 Commits

Author SHA1 Message Date
Claude dfdf07269d docs(nestsclient): record L1/L2/L3 closures in moq-lite Lite-03/04 audit
Adds Fix #6 (L2 — SubscribeOk narrowing), Fix #7 (L3 —
subscriber-driven Probe API), and Fix #8 (L1 — version-aware
Lite-03/04 codec + ALPN negotiation) to the compliance audit
document. Updates the gap matrix (L1/L2/L3 → ) and the TL;DR
(now reads "nine shipped fixes + M6 closed; every gap is now
resolved, no items remain deferred").

The "what's deliberately deferred" section now lists only the
external follow-up — a `kixelated/moq` feature request
suggesting per-deployment tuning of moq-rs's per-subscriber
forward-queue starvation behavior. That's an upstream-relay
concern, not a moq-lite gap.

Updates the audio-rooms completion-plan pointer to reflect the
shipped count and the absence of remaining deferrals. Audit doc
title acknowledges Lite-04 alongside Lite-03 since the codec
now speaks both.

https://claude.ai/code/session_012TGfo99Ugz7fcCPv85a8Tq
2026-05-09 15:08:12 +00:00
Claude 3349270171 docs(nestsclient): record M2/M3 closures in moq-lite Lite-03 audit
Adds Fix #5 (M2 + M3 — STOP_SENDING for single-group cancel +
RESET_STREAM with typed code on Drop replies) to the compliance
audit doc. The two items shipped together because the plumbing is
shared — extending `:quic`'s StrippedWtStream with reset/stopSending
closures, extending the WebTransport interfaces, and routing through
all adapters was the prerequisite for both.

Updates the gap matrix (M2 + M3 → ), the TL;DR (now reads "six
shipped fixes + M6 closed; no 🟡 items remain open"), and the
deferred-items list (only L1 / L2 / L3 remain, all 🟦 with explicit
rationale).

Updates the audio-rooms completion-plan pointer with the new
shipped count.

https://claude.ai/code/session_012TGfo99Ugz7fcCPv85a8Tq
2026-05-09 14:40:30 +00:00
Claude 25c52e6b65 docs(nestsclient): record M1/L5 fixes + M6 closure in moq-lite Lite-03 audit
Adds Fix #3 (M1 — trackPriority + sequence bit-pack matching kixelated
PriorityHandle), Fix #4 (L5 — fresh publisher list at dispatch
time), and the M6 closure (verified via WebFetch that Goaway has no
body schema in moq-lite Lite-03 — `rs/moq-lite/src/lite/{stream,
client}.rs`; our recognise/log/FIN handler is canonical) to the
compliance audit document.

Also marks L4 closed (subsumed by M1 — the saturating cast guard
collapsed into the per-track high byte logic).

Updates the audio-rooms completion-plan pointer with the new shipped
count: four publisher-side spec tightenings + one closure (M6) +
five 🟡 / 🟦 items explicitly deferred with rationale.

Remaining deferrals: M2 + M3 (need WebTransport/`:quic` interface
extension, locked per audit prompt), L1 (Lite-04 codec rewrite, no
relay forces it), L2 + L3 (no consumer for the API).

https://claude.ai/code/session_012TGfo99Ugz7fcCPv85a8Tq
2026-05-09 14:21:08 +00:00
Claude 626521a6f2 docs(nestsclient): moq-lite Lite-03 compliance audit (2026-05-09)
Records the cross-spec compliance audit of the moq-lite Lite-03
implementation against kixelated's reference Rust impl
(github.com/kixelated/moq, rs/moq-lite/). Methodology mirrors the
recent QUIC RFC review: walked every Kotlin source under
`moq/lite/`, traced data flow speaker → relay → listener, and
cross-referenced each on-wire message + control byte against the
Rust reference.

Outcome: no 🔴 wire-incompatibilities found. Every codec primitive —
control type discriminators, AnnouncePlease, Announce, Subscribe
(incl. the `Option<u64>` off-by-one and `Duration` millis-as-varint
conventions), SubscribeOk/Drop with the type-outside-size-prefix
framing peculiar to Lite-03, GroupHeader, Probe — matches byte-for-
byte.

Six 🟡 (spec-loose / future-fragile) and four 🟦 (diagnostic /
observability) gaps documented:
  - M1 stream priority parity vs kixelated's PriorityHandle
    (single-track Opus impact: invisible)
  - M2 STOP_SENDING for single-group cancel not exposed
  - M3 RESET_STREAM with Error::to_code not used
  - M4 AnnouncePlease prefix-mismatch falsely emits Active — fixed
    in 6c2d7efc
  - M5 inbound Subscribe doesn't validate broadcast field — fixed
    in 3dcee2a4
  - M6 Goaway body / migration handler

Also references the new audit from `2026-04-26-audio-rooms-completion.md`
so future readers find it via the completion-plan pointer.

https://claude.ai/code/session_012TGfo99Ugz7fcCPv85a8Tq
2026-05-09 13:53:06 +00:00
Claude 8b5af5d496 docs(audio-rooms): refresh against shipped state + nostrnests gap audit
Existing plan docs were written before the moq-lite swap, the
create-space + kind-10112 work, and the harness / submodule findings.
This refresh aligns them with what's actually live on the branch and
captures the work still ahead.

  - 2026-04-26-audio-rooms-completion.md — flipped to a STATUS-FIRST
    layout: implementation table for every protocol/transport/UI
    surface, "pending" table for the remaining items (reconnect,
    level meters, Desktop / iOS, Nests parity), pointers section
    refreshed.
  - 2026-04-26-moq-lite-gap.md — marked DONE with the commit range
    that landed it (fb47a4c71cf99d015b0d7); "When picking up"
    section now points at the shipped surface first, raw protocol
    references second.
  - 2026-04-22-nip-audio-rooms-draft.md — major surgery to match
    today's nostrnests reality:
      * status banner up top calling out the revision
      * dependencies dropped IETF MoQ-transport, added moq-lite
        Lite-03 + ALPN "moq-lite-03"
      * HTTP control plane: GET <service>/<room-d-tag> → POST /auth
        with {namespace, publish}, returning {token}; documented the
        JWT claim shape (root, get, put), 600 s lifetime, regex
        on `namespace`, JWKS endpoint, error matrix
      * Audio transport: replaced IETF SETUP / TrackNamespace tuples
        / OBJECT_DATAGRAM with moq-lite Lite-03 (ControlType varint,
        per-bidi message types, group uni streams, audio/data track,
        no in-band SETUP, FIN-as-unsubscribe semantics)
      * New event-kind sections: kind 4312 (admin command / kick),
        kind 10112 (audio-room server list)
      * Reconciliation section explaining what changed from the
        original draft and why
  - NEW: 2026-04-26-nostrnests-integration-audit.md — punchlist of
    every nostrnests/NestsUI feature we don't yet ship, sourced from
    a code-walk of the React app + moq-auth + API.md (which is
    LiveKit-era and dead). Tier 1 (low-effort, visible): chat,
    reactions, role parsing + promotion, hand-raise queue, kick
    (kind 4312), edit/close room, scheduled rooms, listener counter.
    Tier 2: participant grid, augmented presence tags
    (publishing/onstage), per-avatar context menu + zap, share via
    naddr. Tier 3: room theming. Tier 4: token-refresh +
    Connection.Reload sanity checks.

Verified `:nestsClient:jvmTest` + `:amethyst:compilePlayDebugKotlin`
both still green after the doc changes (no code touched).
2026-04-26 19:23:41 +00:00
Claude bc43168032 chore(audio-rooms): post-moq-lite cleanup + KDoc + plan refresh
Tidy items now that the moq-lite swap is complete on both sides:

  - Drop the no-op `supportedMoqVersions: List<Long>` parameter from
    `connectNestsListener` / `connectNestsSpeaker`. moq-lite negotiates
    via ALPN, no caller passed a value, and the project rule forbids
    no-op back-compat shims.
  - `NostrNestsRoundTripInteropTest` KDoc + comments now describe the
    moq-lite framing path (one Subscribe bidi for `audio/data`, group
    uni streams with `DataType=0` + GroupHeader + size-prefixed frames)
    instead of the stale IETF "OBJECT_DATAGRAMs / SETUP" framing.
  - `DefaultNestsListener` / `DefaultNestsSpeaker` KDoc now flags them
    as IETF MoQ-transport reference impls — production uses
    `MoqLiteNests*`. They stay around for the IETF unit-test suite.
  - `audio-rooms-completion.md` Phase M5 / M6 / M7 marked **DONE** —
    the plan was written before the moq-lite gap was discovered, so
    it described the work as IETF-MoQ-publisher additions; the
    moq-lite path lands the same outcome via a different protocol.
2026-04-26 18:18:33 +00:00
Claude 71cf99dc22 feat(audio-rooms): moq-lite speaker side end-to-end (phase 5c-speaker)
Production speaker path now runs on moq-lite, so connectNestsSpeaker
exchanges real moq-lite framing with the nostrnests reference relay.

Transport layer:
  - WebTransportSession.incomingBidiStreams() — peer-initiated bidi
    flow. moq-lite publishers receive Announce + Subscribe bidis from
    the relay (rs/moq-lite/src/lite/publisher.rs:40 uses
    Stream::accept(session)), so the abstraction grew the
    accept-bidi-from-peer surface.
  - WebTransportSession.openUniStream() — locally-opened uni stream
    for group push (rs/moq-lite/src/lite/publisher.rs:338 uses
    session.open_uni()).
  - :quic WtPeerStreamDemux StrippedWtStream now carries optional
    send/finish closures. The demux takes the QuicConnectionDriver
    so wakeups fire after each app-level write on a peer-initiated
    bidi.
  - FakeWebTransport now exposes incomingBidiStreams + openUniStream
    directly; the openPeerUniStream test helper went away (production
    flow covers it).

Session layer:
  - MoqLiteSession.publish(suffix) — claims a broadcast suffix and
    lazily launches a relay→us bidi pump. ControlType=Announce reads
    AnnouncePlease, replies Active(suffix). ControlType=Subscribe reads
    body, replies SubscribeOk, registers the inbound subscription.
  - MoqLitePublisherHandle — startGroup / send / endGroup / close
    semantics. send opens a uni stream per group with DataType=0 +
    GroupHeader and pushes varint(size)+payload frames. close emits
    Announce(Ended) on every active announce bidi, FINs the uni.

Application layer:
  - AudioRoomMoqLiteBroadcaster — sibling of AudioRoomBroadcaster but
    drives MoqLitePublisherHandle (keeps IETF broadcaster intact for
    its unit tests).
  - MoqLiteNestsSpeaker — NestsSpeaker adapter, mirror of
    MoqLiteNestsListener on the publish side.
  - connectNestsSpeaker now opens a MoqLiteSession (no SETUP) and
    returns MoqLiteNestsSpeaker.

Tests:
  - 4 new MoqLiteSessionTest cases:
    publisher_replies_to_announcePlease_with_active_announce,
    publisher_acks_subscribe_and_pushes_group_data_on_uni_stream,
    publisher_send_returns_false_when_no_inbound_subscriber,
    publisher_close_emits_ended_announce.

Verified :commons:compileKotlinJvm + :amethyst:compilePlayDebugKotlin
both still compile against the swap.

Docs (plans + CLAUDE.md) refreshed to reflect speaker-side landing.
2026-04-26 18:01:00 +00:00
Claude 5914e9e9fc docs(audio-rooms): moq-lite listener landed — refresh status callouts
Phase 5d wrapped, so the doc set now reflects "listener path done,
speaker pending":

  - nestsClient/plans/2026-04-26-moq-lite-gap.md — new "Implementation
    status" section maps phases 5a → 5d to commits, calls out the
    speaker side as blocked on a small `WebTransportSession.acceptBidi`
    extension (since publisher.rs:40 uses Stream::accept), and points
    at the existing :quic primitive (QuicConnection.awaitIncomingPeerStream)
    that the bridge can lean on.
  - nestsClient/plans/2026-04-26-audio-rooms-completion.md — Phase M1
    is no longer "on hold for moq-lite"; manual nostrnests.com
    validation should now work end-to-end on the listener path.
  - .claude/CLAUDE.md — :nestsClient now hosts both IETF MoQ-transport
    and moq-lite Lite-03; production listener path uses moq-lite.
2026-04-26 17:39:23 +00:00
Claude 7f48e52541 docs(audio-rooms): full moq-lite wire spec + IETF gap call-outs
Background research turned up the complete moq-lite (Lite-03) wire
format from kixelated/moq-rs and @moq/lite v0.1.7. Folded the spec
into nestsClient/plans/2026-04-26-moq-lite-gap.md as a phase-5
implementation plan:

  - ALPN ("moq-lite-03"); no SETUP/control message in Lite-03 (the WT
    handshake IS the handshake)
  - Per-request bidi streams keyed by ControlType varint (Announce=1,
    Subscribe=2, Fetch=3, Probe=4)
  - AnnouncePlease(prefix) / Announce(status, suffix, hops) shape
  - Subscribe with priority (raw u8), ordered, maxLatency (ms),
    startGroup/endGroup (off-by-one None-encoded), reply Ok/Drop
  - Group = uni stream with (DataType=0, subscribeId, sequence)
    header followed by varint-length frames until QUIC FIN
  - No datagrams; no per-frame envelope beyond size
  - Mandatory path normalisation; FIN-as-unsubscribe; RESET_STREAM
    for errors

Phase-5a..e implementation plan included (~1 week scope).

Doc + KDoc updates so the IETF MoQ-transport code is correctly
labelled and the moq-lite gap is discoverable from every entry point:

  - .claude/CLAUDE.md project description and architecture diagram
  - nestsClient/plans/2026-04-26-audio-rooms-completion.md status block
  - MoqSession.kt, MoqMessage.kt, MoqObject.kt, MoqCodec.kt KDoc — flag
    these as "IETF draft-ietf-moq-transport-17, NOT moq-lite", with
    pointers to the gap doc
  - NestsConnect.kt — note that step 3 of the listener handshake
    (SETUP) does NOT match nostrnests's relay framing
2026-04-26 16:39:44 +00:00
Claude 4338e5e6c4 docs(quic+nestsClient): post-implementation status + audio-rooms completion plan
Two new module-local plan docs (per CLAUDE.md's "plans live in the owning
module" rule) and a sweep of stale inline phase references.

quic/plans/2026-04-26-quic-stack-status.md:
  Post-mortem of the original docs/plans/2026-04-22 plan. Documents
  what shipped vs what was estimated, the actual package layout (~8.5k
  LoC, 39 test files, 5 audit rounds), the crypto delegation surface
  (Quartz only — no BouncyCastle, no JNI), interop verification status
  (aioquic + picoquic; nests not yet), and known deferred items
  (STREAM retransmit, Initial-key discard, etc.).

nestsClient/plans/2026-04-26-audio-rooms-completion.md:
  Punch list to ship audio rooms end-to-end:
    M1 Listener wire-up in Amethyst UI
    M2 Multi-speaker audience UX
    M3 Foreground service for backgrounded playback
    M4 Manual interop pass against nostrnests.com
    M5 MoQ publisher path (ANNOUNCE / TrackPublisher)
    M6 Capture → encode → publish pipeline
    M7 NestsSpeaker API
    M8 App polish (reconnect, leave cleanup)
    M9 Foreground service for speakers
  ~6 weeks for full audio rooms; ~2 weeks for listener-only MVP.

Inline doc cleanup:
  * Removed "Phase 3a/3c-1/3c-2/3c-3" / "Phase B/C/D-K/L" references
    from active code; replaced with "today" or pointers to the
    completion plan
  * Removed "Kwik-based stub" references; QuicWebTransportFactory and
    surrounding docs now describe :quic as the production path
  * TlsClient header reflects non-null certificateValidator + the
    JdkCertificateValidator / PermissiveCertificateValidator split
  * SendBuffer header documents the best-effort no-retransmit mode
    explicitly (was hidden behind a "Phase L will fix this" note)
  * MoqMessage / MoqObject / MoqSession reflect listener-side as
    shipped + publisher-side as Phase M5

CLAUDE.md:
  * Module list now includes :quic and :nestsClient (was 5 modules,
    now 7)
  * Architecture diagram + sharing philosophy explain what each new
    module owns

No production behaviour changes; doc + comment-only edits. Tests green.

https://claude.ai/code/session_01EC1tfXfap8k8GyKvrxkxZx
2026-04-26 01:38:48 +00:00