From 5d03be17aae5b0067fe6b85642efeb14142cd083 Mon Sep 17 00:00:00 2001 From: AAA <35992542+TNTcraftHIM@users.noreply.github.com> Date: Sun, 23 Aug 2026 00:42:36 +0800 Subject: [PATCH] docs(route): close wave A and advance routing ledger --- .../0005-automatic-hybrid-media-routing.md | 15 +++++++++++---- docs/project-memory.md | 8 ++++---- docs/research/advanced-peer-distribution.md | 9 +++++++++ docs/status.md | 10 +++++----- docs/todo.md | 19 +++++++++---------- docs/verification-status.md | 7 ++++--- docs/方案设计.md | 4 ++-- docs/需求理解.md | 1 + 8 files changed, 45 insertions(+), 28 deletions(-) diff --git a/docs/adr/0005-automatic-hybrid-media-routing.md b/docs/adr/0005-automatic-hybrid-media-routing.md index f92a19d..b592a5c 100644 --- a/docs/adr/0005-automatic-hybrid-media-routing.md +++ b/docs/adr/0005-automatic-hybrid-media-routing.md @@ -2,7 +2,7 @@ - Status: Accepted route model; runtime migration pending - Date: 2026-08-20 -- Last updated: 2026-08-22 +- Last updated: 2026-08-23 ## Context @@ -152,7 +152,13 @@ one resource ledger, and monotonic room/session/revision fences. proof, atomic commit, drain, and idempotent release are one transaction. TTL cleans abandoned reservations; it never revokes a healthy committed edge. - A child that observes its own upstream as bad uses correlated C+B evidence - for that edge and invokes child-scoped reparent. A relay parent enters + for that edge and invokes child-scoped reparent. If an exact current ordinary + peer edge stops current-generation RTP and decoded-frame progress while + signaling and the PeerConnection remain present, expiry of the bounded parent- + proof deadline authorizes hard reparent of that child if the stall remains, + whether matching positive non-server-parent outbound-media proof arrived or + not. Parent sending or non-response does not change parent eligibility. A + relay parent enters `suspect` only for its own ingress/parent-scope evidence, then stops accepting new children and repairs its own ingress with reparent or branch-preserving `replaceIngress`; Host source failures instead use publication repair and @@ -206,8 +212,9 @@ Before a revised controller ships: corroborated drain, prove that same-edge C+B cannot drain a parent, require independent sibling edges for parent corroboration, include a Viewer that is both child and parent plus the Host-source publication-repair exception, bind - evidence to media-binding generation, and exercise suspect/local-repair - before drain while preserving unrelated sibling evidence; + evidence to media-binding generation, prove bounded child-only recovery when + an ordinary peer edge stops RTP while signaling remains present, and exercise + suspect/local-repair before drain while preserving unrelated sibling evidence; - real-browser tests cover direct peer media, peer relay, server-assisted media, selected transport when configured, failure, and recovery; - measured endpoint upload and server ingress/egress prove the accepted diff --git a/docs/project-memory.md b/docs/project-memory.md index e4468ee..a2300ac 100644 --- a/docs/project-memory.md +++ b/docs/project-memory.md @@ -1,6 +1,6 @@ # Project Memory -Last updated: 2026-08-22 +Last updated: 2026-08-23 ## Current Product Truth @@ -9,7 +9,7 @@ Last updated: 2026-08-22 - Keep routing automatic and media distributed. Direct/peer UDP is preferred; centralized media is fallback infrastructure, not the default topology. - Every non-server endpoint uses one server-authoritative steady outbound media-copy capacity: default `2`, statically configurable as `1`, `2`, or `3`. A peer child or the Host publication consumes one slot; upstream receive is free, selected TURN replaces the same copy's transport, and SFU subscriber egress is accounted at the server. Browser role/UA/visibility does not create a separate tier, and clients cannot raise the deployment value. - The stable routing invariants are one authoritative upstream per Viewer, an acyclic active graph, exact room/session/share/revision/generation authorization, media-proven make-before-break, and bounded success or failure. -- The accepted route model is one room controller with allocate/distribute, child reparent, and relay abdicate/drain operations. One Host publication may serve all SFU-fed Viewers; an SFU-fed Viewer may relay only with independent outbound proof; selected TURN changes an authorized edge transport and is not a topology node. A confirmed bad edge reparents only its child. A relay parent's own ingress failure first enters suspect/cordon and attempts local repair; only failed repair, independent downstream evidence, or explicit sender/resource failure drains its children. Host source failures use publication repair and child migration. Endpoint capacity, temporary overlap, SFU/TURN admission, exact fallback, media binding generations, and rollback are one bounded transaction model. +- The accepted route model is one room controller with allocate/distribute, child reparent, and relay abdicate/drain operations. One Host publication may serve all SFU-fed Viewers; an SFU-fed Viewer may relay only with independent outbound proof; selected TURN changes an authorized edge transport and is not a topology node. A confirmed bad edge, or an exact ordinary peer edge whose current-generation receive/decode progress remains absent through a bounded parent-proof challenge, reparents only that child regardless of whether the parent proved sending; neither outcome lets one child drain its parent. A relay parent's own ingress failure first enters suspect/cordon and attempts local repair; only failed repair, independent downstream evidence, or explicit sender/resource failure drains its children. Host source failures use publication repair and child migration. Endpoint capacity, temporary overlap, SFU/TURN admission, exact fallback, media binding generations, and rollback are one bounded transaction model. - Parent choice is sticky and deterministic: hard-filter current authority, reachability, cycles, depth, capacity, eligibility, exact-edge cooldown, and server admission; then order by shallowest result, remaining steady sender capacity, stable join order, and peer identity. Standard ICE and exact media proof test one candidate at a time. Raw IP, claimed NAT type, UA, geography, all-pairs probes, weighted scores, and periodic room rebalancing are not route inputs. - Ordinary peer ICE is STUN-only. Credentials, room secrets, candidate details, and diagnostic data remain private and narrowly scoped. - Screen audio offers live-switchable 64/128/256 kbps sender ceilings and defaults to 128. The existing last-wins quality wire owns desired state; each endpoint serially applies and reads back current Host/relay/SFU audio senders, exposes local failures, and gives future senders the latest desired value. Opus remains fixed, and without an applied-ack wire the Host does not claim room-wide atomic convergence. These are configuration ceilings, not fidelity claims. @@ -21,7 +21,7 @@ Last updated: 2026-08-22 ## Current Source And Production - Canonical source is the clean `main` branch. New branches and worktrees start from its exact current commit after accepted truth is merged. -- Current source implements the uniform `1/2/3` endpoint cap through one shared accounting guard, advances Web/server/Native to `screener-v6`, rejects v5 before room authority, treats SFU-fed Viewers as leaves without outbound proof, and retains the fixed SFU-root and room-wide selected-lease guards pending later server admission waves. Release readiness requires the v6 authenticated snapshot to carry the exact deployment cap so Native admission, peer-assisted assignments, and sender slots use the same authority. +- Current source implements the uniform `1/2/3` endpoint cap through one shared accounting guard, advances Web/server/Native to `screener-v6`, rejects v5 before room authority, and carries the exact deployment cap in every authenticated snapshot so ordinary Host authorization, Native admission, peer-assisted assignments, and sender slots use the same authority. SFU-fed Viewers remain leaves without outbound proof, and the fixed SFU-root and room-wide selected-lease guards remain pending later server admission waves. - Production runs exact `9461e207af62b4f38f6b7a8aa16f8beb49e0e4ee`, release `9461e20`, wire `screener-v5`; `21d5cd9f7139` is the rollback release. - Production still enforces Host downstream `2`, ordinary Browser downstream `1`, deployment values `1/2`, a fixed SFU-root limit of `2`, and legacy publication/selected accounting. This is a dated implementation divergence, not current product policy. - Production has automatic routing, bad-relay corroboration, peer-quality make-before-break with Viewer and Host provisional parents, selected-edge transport, stable route/connection details, 64/128/256 audio choices, access controls, self-check, diagnostic export, and signaling watchdog behavior. @@ -31,7 +31,7 @@ Last updated: 2026-08-22 ## Current Priority 1. Keep this truth set and [the TODO ledger](./todo.md) concise and internally consistent. -2. Rebuild and release the accepted route runtime first. Then release live audio and paused video-codec switching, follow with evidence-led H.264 diagnosis, the strict-NAT emulator gate, connection feedback, and the remaining functional roadmap. Distribution packaging starts only after those TODOs are complete. Parallel branches may finish earlier but do not change this merge/deployment order. +2. Complete and release the remaining route waves B-D first. Then release live audio and paused video-codec switching, follow with evidence-led H.264 diagnosis, the strict-NAT emulator gate, connection feedback, and the remaining functional roadmap. Distribution packaging starts only after those TODOs are complete. Parallel branches may finish earlier but do not change this merge/deployment order. ## Working Rules diff --git a/docs/research/advanced-peer-distribution.md b/docs/research/advanced-peer-distribution.md index 3fe0194..fe937de 100644 --- a/docs/research/advanced-peer-distribution.md +++ b/docs/research/advanced-peer-distribution.md @@ -210,6 +210,15 @@ edge-local. Corroboration from two distinct current children can affect relay parent eligibility only when the configured ordinary capacity makes that state reachable; it does not define the capacity policy. +The accepted controller target also handles an exact ordinary peer edge whose +signaling and PeerConnection remain present while current-generation RTP and +decoded-frame progress stop. If the stall remains when the bounded parent-proof +deadline expires, only that child enters hard reparent whether matching positive +non-server-parent outbound-media proof arrived or not. Parent sending and parent +non-response are both edge-local here; parent cordon/drain still requires a hard +endpoint failure, explicit sender/resource failure, failed ingress repair, or +independent downstream evidence. + The conservative Viewer C hard predicates are: freeze duration at least half of the one-to-five-second window; positive received-packet delta with zero decoded frames; or at least 100 received-plus-lost packets with loss at least diff --git a/docs/status.md b/docs/status.md index 0b9088f..1cf34b3 100644 --- a/docs/status.md +++ b/docs/status.md @@ -1,6 +1,6 @@ # Current Status -Last updated: 2026-08-22 +Last updated: 2026-08-23 This is the current execution index. Git history owns completed timelines; [verification status](./verification-status.md) owns evidence boundaries. @@ -15,7 +15,7 @@ This is the current execution index. Git history owns completed timelines; [veri - Canonical source is the clean `main` branch; auxiliary branches and worktrees do not own current truth. - Current source implements one steady outbound media-copy cap for every non-server endpoint: default `2`, static `1/2/3`, a peer child or Host publication consumes one slot, upstream receive is free, a committed selected TURN transport replaces the same copy while hidden carry consumes another, and no Browser/UA/visibility tier exists. One shared guard owns the accounting and transition work is bounded by `min(C + 1, 3)`. -- The v6 release boundary rejects v5 before room authority and must carry the exact deployment cap in every authenticated snapshot so Native ordinary admission, peer-assisted child assignments, and sender slots share the server authority. It leaves an SFU-fed Viewer childless without independent outbound proof and keeps quality events child-scoped without a fixed two-child parent drain. Fixed SFU-root and room-wide selected-lease guards remain until their independent server admission owners land. +- The v6 release boundary rejects v5 before room authority and carries the exact deployment cap in every authenticated snapshot so ordinary Host authorization, Native admission, peer-assisted child assignments, and sender slots share the server authority. It leaves an SFU-fed Viewer childless without independent outbound proof and keeps quality events child-scoped without a fixed two-child parent drain. Fixed SFU-root and room-wide selected-lease guards remain until their independent server admission owners land. - Automatic P2P-first routing, one active upstream, an acyclic graph, exact identity/generation authority, media-proven make-before-break, and bounded failure remain accepted. - The holistic assisted-route model is accepted: one controller performs allocation, child reparenting, and relay abdication/drain. One Host publication serves SFU subscriptions; TURN is an exact edge transport, not a topology node. Wave A supplies endpoint accounting and the wire boundary without pretending that later controller convergence, media-binding generations, or independent SFU/TURN admission already exist. - Parent selection is deterministic rather than random or score-based: hard eligibility filters, then shallowest result, remaining sender capacity, stable join order, and peer identity; one provisional edge uses standard ICE and media proof at a time. Viewer connection feedback and the strict-NAT emulator gate are accepted follow-up work, not deployed behavior. @@ -23,7 +23,7 @@ This is the current execution index. Git history owns completed timelines; [veri ## Current Milestone -1. Rebuild and release route waves A-D from exact canonical `main`, including cap/accounting, bounded server admission, deterministic local parent selection, quality ownership, and one controller. +1. Complete and release route waves B-D from exact canonical `main` on the merged Wave A cap/wire boundary, including bounded server admission, deterministic local parent selection, quality ownership, and one controller. 2. Release live audio-ceiling mutation and paused-share codec switching on the resulting generation/transition boundary. 3. Reproduce the H.264 startup report before any codec-specific repair, and build the strict-NAT emulator gate before any manually approved canary in an operator-owned test room. 4. Add first-frame-driven Viewer connection stages and finish the remaining accepted functional and real-network work. @@ -38,5 +38,5 @@ This is the current execution index. Git history owns completed timelines; [veri ## Next Stop -Create each runtime change from the resulting clean `main`; remaining TODOs stay -scoped to their owner and do not revive superseded branches. +Reconcile each retained route candidate once onto this clean `main`; remaining +TODOs stay scoped to their owner and do not revive superseded branches. diff --git a/docs/todo.md b/docs/todo.md index 1896ec6..8f8bd4d 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -1,19 +1,18 @@ # Current TODO Ledger -Last reviewed: 2026-08-22 +Last reviewed: 2026-08-23 Only items in **Now** are executable after their stated decision gate. A branch name, unchecked requirement, experiment, review suggestion, or deployed behavior is not a TODO by itself. ## Now -1. **Complete route wave A's v6 endpoint-cap boundary.** Add the exact deployment `endpointMediaCopyCapacity` to every authenticated snapshot; bound ordinary server-authorized Host children and their signaling to that value with stable waiting promotion; and make Native ordinary admission, peer-assisted child assignment, and sender-slot allocation consume it independently of room `maxViewers`. Strictly reject missing or out-of-range values, retain the shared accounting and transition guard, and validate `C=1/2/3` before release. Do not merge the old configurable-cap worktree. -2. **Route waves B-D: bounded fallback, selection, and controller convergence.** Replace the temporary fixed SFU subscriber guard with explicit deployment-wide SFU ingress/egress admission; then replace the temporary room-wide selected-lease guard with per-edge TURN allocation admission and exact accounting. Converge allocation, child reparent, and relay drain on one committed graph/controller. Parent candidates use hard eligibility filters followed by deterministic shallowest, remaining-capacity, join-order, and peer-identity ordering; standard ICE plus exact media proof tests one candidate at a time. Do not add raw-IP/NAT ranking, all-pairs probes, a weighted score, or periodic rebalancing. The temporary guards are safety boundaries, not accepted product limits, and must not be removed early. -3. **Switch screen-audio ceilings live.** Keep Opus fixed and serialize 64/128/256 kbps desired profile updates across every current Host, relay, and SFU audio sender. Each endpoint uses fresh `getParameters()`/`setParameters()` readback, ignores stale completions, retains media plus its prior applied value on failure, and applies the latest desired value to future edges. Do not add a remote applied-ack protocol or claim room-wide atomic convergence in this slice. -4. **Switch video codec while paused.** After the route/media-generation boundary is available, serialize the change with route mutation, freeze exact current route/media bindings, hold new joins, renegotiate P2P/relay and republish SFU while paused, then verify actual codec plus decoded frames on resume. A binding invalidated by leave or hard route failure exits this proof set and waits for routing to rebuild from the final committed preference after the bounded codec transaction settles. On failure pause again and perform bounded rollback; rollback proves the prior preference was reapplied plus a newly negotiated actual codec and decoded progress, not literal equality with the old actual codec. Zero targets update only the future-edge preference. Reset `automatic` with empty codec preferences. This is a paused bounded-gap transaction; unpaused make-before-break is a later extension. -5. **Diagnose the production H.264/blur report.** Reproduce exact release `769de201f7cc` against current `main` on the same Host/browser/driver/game and one wired direct Viewer, changing one variable at a time. Implement a codec-specific repair only if codec/encoder evidence identifies it; otherwise fix the proven capture, sender, BWE, or lifecycle cause. -6. **Gate the strict-NAT guessed-candidate experiment.** Build only the isolated endpoint-dependent NAT emulator and browser harness first. Standard ICE must fail in the owned fixture, the capped candidate set must pass the documented repeatability, deadline, privacy, and cleanup gates in stable Chrome and Firefox, and fallback must remain unchanged. Only then may one manually approved, operator-owned test room run a default-off, kill-switched canary with explicit consent from both endpoints and exact room/edge/generation/budget bounds; failure closes the candidate. Do not ship guessed candidates to ordinary rooms or infer NAT type from IP, UA, carrier, or two STUN observations. -7. **Make Viewer connection progress explicit.** Derive one stable stage from existing access, route, peer/SFU, media, autoplay, and bounded-failure state. Keep the overlay until a composited current-generation frame, show `Play` only for actual autoplay rejection, preserve a still-valid old frame during recovery, and expose retry only through the bounded controller. Measure the existing token-free SFU prewarm and route stages before adding another connection mechanism. -8. **Validate and release in priority order.** Review, merge, and deploy each coherent slice from canonical `main`: route first, then audio/codec mutation, then H.264/NAT evidence and any proven repair, then connection feedback and remaining tools. Run the focused state machine and browser/network matrix relevant to that slice, plus independent review, build/full gates, bounded production preflight, postflight, and rollback verification. A parallel branch may finish early but does not jump this rollout order. +1. **Route waves B-D: bounded fallback, selection, and controller convergence.** Replace the temporary fixed SFU subscriber guard with explicit deployment-wide SFU ingress/egress admission; then replace the temporary room-wide selected-lease guard with per-edge TURN allocation admission and exact accounting. Converge allocation, child reparent, and relay drain on one committed graph/controller. A signaling-connected relay that stops current-generation RTP cannot require its own report: after the bounded parent-proof deadline, persistent child-side silence reparents only the affected child whether the parent proved sending or not; cordon or drain the relay only after parent/session hard failure, explicit sender/resource failure, failed ingress repair, or independent downstream evidence. Parent candidates use hard eligibility filters followed by deterministic shallowest, remaining-capacity, join-order, and peer-identity ordering; standard ICE plus exact media proof tests one candidate at a time. Do not add raw-IP/NAT ranking, all-pairs probes, a weighted score, UA/visibility tiers, or periodic rebalancing. The temporary guards are safety boundaries, not accepted product limits, and must not be removed early. +2. **Switch screen-audio ceilings live.** Keep Opus fixed and serialize 64/128/256 kbps desired profile updates across every current Host, relay, and SFU audio sender. Each endpoint uses fresh `getParameters()`/`setParameters()` readback, ignores stale completions, retains media plus its prior applied value on failure, and applies the latest desired value to future edges. Do not add a remote applied-ack protocol or claim room-wide atomic convergence in this slice. +3. **Switch video codec while paused.** After the route/media-generation boundary is available, serialize the change with route mutation, freeze exact current route/media bindings, hold new joins, renegotiate P2P/relay and republish SFU while paused, then verify actual codec plus decoded frames on resume. A binding invalidated by leave or hard route failure exits this proof set and waits for routing to rebuild from the final committed preference after the bounded codec transaction settles. On failure pause again and perform bounded rollback; rollback proves the prior preference was reapplied plus a newly negotiated actual codec and decoded progress, not literal equality with the old actual codec. Zero targets update only the future-edge preference. Reset `automatic` with empty codec preferences. This is a paused bounded-gap transaction; unpaused make-before-break is a later extension. +4. **Diagnose the production H.264/blur report.** Reproduce exact release `769de201f7cc` against current `main` on the same Host/browser/driver/game and one wired direct Viewer, changing one variable at a time. Implement a codec-specific repair only if codec/encoder evidence identifies it; otherwise fix the proven capture, sender, BWE, or lifecycle cause. +5. **Gate the strict-NAT guessed-candidate experiment.** Build only the isolated endpoint-dependent NAT emulator and browser harness first. Standard ICE must fail in the owned fixture, the capped candidate set must pass the documented repeatability, deadline, privacy, and cleanup gates in stable Chrome and Firefox, and fallback must remain unchanged. Only then may one manually approved, operator-owned test room run a default-off, kill-switched canary with explicit consent from both endpoints and exact room/edge/generation/budget bounds; failure closes the candidate. Do not ship guessed candidates to ordinary rooms or infer NAT type from IP, UA, carrier, or two STUN observations. +6. **Make Viewer connection progress explicit.** Derive one stable stage from existing access, route, peer/SFU, media, autoplay, and bounded-failure state. Keep the overlay until a composited current-generation frame, show `Play` only for actual autoplay rejection, preserve a still-valid old frame during recovery, and expose retry only through the bounded controller. Measure the existing token-free SFU prewarm and route stages before adding another connection mechanism. +7. **Validate and release in priority order.** Review, merge, and deploy each coherent slice from canonical `main`: route first, then audio/codec mutation, then H.264/NAT evidence and any proven repair, then connection feedback and remaining tools. Before the route release, explicitly exercise Native `C=1/2/3` ordinary admission, waiting promotion, peer-assisted assignment, and physical sender-slot allocation. Run the focused state machine and browser/network matrix relevant to each slice, plus independent review, build/full gates, bounded production preflight, postflight, and rollback verification. A parallel branch may finish early but does not jump this rollout order. The existing route implementation is an input to these tasks. Preserve its verified generation, authorization, make-before-break, and media-proof invariants while migrating capacity and fallback accounting. The accepted model is the destination; each wave must remain safe and truthful on its own rather than installing a name-only controller or an unreserved overlap. @@ -22,7 +21,7 @@ The existing route implementation is an input to these tasks. Preserve its verif These items are real product work, ordered after the current release boundary; they are not permission to resume an old branch wholesale. 1. **Native shared encode, Windows first.** Prove one hardware encoder output can serve two independent Viewer transports and the Host-SFU publication while each connection retains its own RTP/RTCP, pacing, encryption, feedback, and upload accounting. Productize only after actual access-unit identity, Viewer2/FIFO, heterogeneous feedback, game-resource, browser/hardware, A/V, packaging, and licensing gates pass. Web Host/relay remains standard per-`RTCPeerConnection` encoding because no portable shared-encoder contract exists. -2. **Mobile Viewer lifecycle.** Run Android Chrome and iOS Safari device matrices for autoplay gesture, foreground/background audio, foreground video recovery, lock/page reclamation, rotation, and Wi-Fi/cellular migration. Preserve the same media element and current reconnect path; do not promise background video composition or unsupported lock-screen behavior. +2. **Mobile Viewer lifecycle.** Run Android Chrome and iOS Safari device matrices for autoplay gesture, foreground/background audio, foreground video recovery, lock/page reclamation, rotation, Wi-Fi/cellular migration, and an assigned relay's outbound-media survival or controller failover across those transitions. Preserve the same media element and current reconnect path; do not promise background video composition, background relay continuity, or unsupported lock-screen behavior. 3. **Native Host capture backend.** Productize a proven Windows native capture path before expanding capture/audio backends to macOS and Linux. Its capture, hardware encode, audio, identity and lifecycle evidence becomes an input to later packages; a source checkout or evaluation ZIP is not a distributable product. 4. **Real network acceptance.** Measure standard ICE/STUN, IPv4/IPv6, independent STUN destinations, selected TURN, SFU ingress, and bounded failure across representative NATs and mobile networks. Browser port prediction remains experiment-only until its emulator and allowlisted-canary gates pass; raw-IP ranking and a room-wide quality score remain out of scope. Parent choice uses exact edge evidence and the accepted route controller. 5. **Platform output only when real.** Revisit AirPlay/Cast only when a target browser and physical receiver prove the live `MediaStream` contract. System mirroring remains external; no placeholder button, custom receiver, or server transcode is scheduled. diff --git a/docs/verification-status.md b/docs/verification-status.md index 69b781b..77e08d8 100644 --- a/docs/verification-status.md +++ b/docs/verification-status.md @@ -1,6 +1,6 @@ # Current Verification Status -Last updated: 2026-08-22 +Last updated: 2026-08-23 ## Purpose @@ -20,6 +20,7 @@ Capacity and routing entries below describe the exact tested source or release o ## Retained Functional Evidence +- Exact source `31e323e2754fcfde15f7b4d69e925ec71e2795cb` passed repository hygiene, TypeScript typecheck, client/server builds, all 660 Web tests, all Native Go packages, `go vet`, and two independent P0/P1 reviews. The tests cover strict v6 endpoint-cap authentication, ordinary active/waiting authorization and grace promotion, Native cap propagation and admission, and peer-assisted cap rejection. This is local state-machine/build evidence, not a complete Native physical-slot matrix or production, browser-quality, or heterogeneous-network acceptance. - Chrome 151 synthetic `1/3/5/8` and 720p30 runs preserved bounded fanout and decoding. A `9461e20`-era three-Viewer rerun kept Host2/Browser Viewer1, decoded every Viewer, and recovered a hard first-level relay departure in 5,380 ms; it did not exercise quality-triggered MBB. Sixteen-Viewer cap2/cap3 loopbacks decoded all Viewers and a ten-second follow-up recorded guarded sender and aggregate Chromium CPU evidence, but resolution/FPS remained low and the ordinary-PC data cannot rank caps, select product policy, or prove sustainable heterogeneous-network quality. See [peer-assisted media](./research/peer-assisted-media.md). - Chrome 151 with local LiveKit 1.13.5/client 2.22.0 proved one SFU/UDP root after `q,f` -> `q,h`: decoded frames advanced 3 -> 23, rendered frames reached 26, Host used one edge, leaves were clean, and TURN was absent. This is functional evidence only. See [low-server media routes](./research/low-server-media-routes.md). - Host A+B and authenticated P2P Viewer C evidence is sanitized, generation-bound, read-only, and closed for stale, ambiguous, or SFU-fed reports. Production can expose a Host-local current SFU `h` snapshot and clears it on publisher identity changes; raw media metadata is not retained. See [realtime quality adaptation](./research/realtime-quality-adaptation.md). @@ -30,9 +31,9 @@ Capacity and routing entries below describe the exact tested source or release o ## Open Proof Boundaries -- Routing: verify current-release initial ingress, `peer-selected` expiry/failure, corroborated bad-relay reassignment, one-root healthy SFU reselection, silent partitions, and bounded failure on real browser/media paths. Silent control partitions may wait 30 to 60 seconds for heartbeat detection before the default five-second grace. +- Routing: verify current-release initial ingress, `peer-selected` expiry/failure, corroborated bad-relay reassignment, one-root healthy SFU reselection, silent control partitions, signaling-connected current-generation RTP silence, and bounded failure on real browser/media paths. Silent control partitions may wait 30 to 60 seconds for heartbeat detection before the default five-second grace; RTP-silence acceptance must prove child-scoped recovery without granting one uncorroborated child authority to drain its parent. - Quality: production startup blur remains unclassified. One same-`balanced` local A/B retained route/PC/SSRC/track while 720p rose to 1080p, but natural ramp prevents causal, production, or SFU conclusions. Correlate Host capture/encode/send with Viewer receive/decode before changing policy. -- Relay resources: production `9461e20` is Host2/ordinary Browser Viewer1 and rejects Viewer child2 regardless of advertised capacity. This is a dated implementation divergence; the accepted endpoint-cap and corroboration contract is in ADR-0005 and awaits runtime migration. CPU/GPU/upload and heterogeneous-network measurements remain evidence, not authority to change that contract. +- Relay resources: current source has the authenticated `1/2/3` endpoint-cap boundary, while production `9461e20` remains Host2/ordinary Browser Viewer1 and rejects Viewer child2 regardless of advertised capacity. Before release, explicitly exercise Native `C=1/2/3` admission, waiting promotion, peer-assisted assignment, and physical sender slots; CPU/GPU/upload and heterogeneous-network measurements remain evidence, not authority to change the contract. - SFU: production `9461e20` deploys ordered `q,h`, roots <=2, and Dynacast off. Those are release facts; the accepted model has no fixed root-count or room-wide lease rule and still needs real shaped packet flow, BWE downshift/recovery, resource, and root-with-children validation. Use Linux `tc` or an authorized public canary for per-leaf shaping, never CDP throttling. - Audio: verify the 64/128/256 kbps Share settings, negotiated/observed bitrate, audible music quality, route changes, and game A/V synchronization. Bitrate settings are ceilings, not quality proof. - Observability: the UI and local stats plumbing are deployed, including identity-bound relayed-detail retention and export freshness guards, but target-browser availability and actual values remain unverified for Host SFU sender evidence, codec/fmtp and encoder implementation/power efficiency, media-source and encoded FPS, A/V playout/jitter/concealment, selected candidate endpoints, and bounded same-pair STUN-response observation. These fields diagnose and have no recovery authority; they do not by themselves prove hardware encode, synchronization quality, or route quality. diff --git a/docs/方案设计.md b/docs/方案设计.md index 44113e3..f93eaa4 100644 --- a/docs/方案设计.md +++ b/docs/方案设计.md @@ -208,7 +208,7 @@ SVC 的标准能力门禁已经静态关闭为 `no-go-web-svc-cross-path-hardwar 质量控制不放宽稳态 outbound media-copy 预算:所有非服务器端点继续受统一静态 capacity 约束;native relay 只转发选定表示的编码包,不解码重编码。后续双树或条带化必须另行验收,不能绕过当前 graph、identity 和 capacity invariant。 -质量证据形成两条正交状态:`EdgeHealth(parent, child, generation)` 控制 child-scoped reparent,`RelayEligibility(parent)` 仅适用于 relay parent,控制 `eligible -> suspect -> draining -> ineligible`。Viewer 的 C 证据和 parent 对同一 edge 的 B 证据必须按 exact route identity(room/share、双方 session、assignment/connection/media-binding generation、route revision,及适用时 publication generation)和 sequence 相关;同一 edge 的 C+B 不直接触发 parent drain。Relay parent 自身 ingress 失败先触发本地 reparent 或 branch-preserving `replaceIngress` 并进入 `suspect`;质量 owner 根据不同 downstream edges 的当前可观察边和端点容量确认 parent 方向失效,修复失败、明确 sender/resource failure 或独立 downstream edges 确认转发仍失效时才 drain。Host source 使用 publication repair/child migration。drain 停止新 child,仍健康的 ingress 保留,失效 ingress 在同一 target 中替换或移除,迁移有目标的 children,并让无目标者进入有界等待或失败;更长稳定证明和 cooldown 才恢复 `eligible`。同一个 controller 每房间只提交一个 target revision,按 hard failure、confirmed parent drain、single-edge soft reparent 的顺序合并事件;drain 吸收覆盖范围内的 child intent,成功的 reparent 只使同一旧 logical edge 的 pending evidence 失效,其他仍匹配且未过期的 sibling evidence 保留。 +质量证据形成两条正交状态:`EdgeHealth(parent, child, generation)` 控制 child-scoped reparent,`RelayEligibility(parent)` 仅适用于 relay parent,控制 `eligible -> suspect -> draining -> ineligible`。Viewer 的 C 证据和 parent 对同一 edge 的 B 证据必须按 exact route identity(room/share、双方 session、assignment/connection/media-binding generation、route revision,及适用时 publication generation)和 sequence 相关;同一 edge 的 C+B 不直接触发 parent drain。若 exact ordinary peer edge 在信令和 PeerConnection 存活时持续没有当前代 RTP/decoded progress,且有界 parent-proof deadline 到期后仍停滞,`EdgeHealth` 不论是否收到 matching positive non-server-parent outbound-media proof,都只为该 child 进入 hard reparent;parent 正在发送或未回应都不改变 `RelayEligibility`。Relay parent 自身 ingress 失败先触发本地 reparent 或 branch-preserving `replaceIngress` 并进入 `suspect`;质量 owner 根据不同 downstream edges 的当前可观察边和端点容量确认 parent 方向失效,修复失败、明确 sender/resource failure 或独立 downstream edges 确认转发仍失效时才 drain。Host source 使用 publication repair/child migration。drain 停止新 child,仍健康的 ingress 保留,失效 ingress 在同一 target 中替换或移除,迁移有目标的 children,并让无目标者进入有界等待或失败;更长稳定证明和 cooldown 才恢复 `eligible`。同一个 controller 每房间只提交一个 target revision,按 hard failure、confirmed parent drain、single-edge soft reparent 的顺序合并事件;drain 吸收覆盖范围内的 child intent,成功的 reparent 只使同一旧 logical edge 的 pending evidence 失效,其他仍匹配且未过期的 sibling evidence 保留。 标准表示能力排在任何自定义双表示媒体实现之前。当前 Web P2P simulcast 缺少 receiver 选 RID 与跨 PeerConnection shared-encode 契约;当前 Web/LiveKit SVC 也缺少 direct/peer 独立选层和可移植硬件保证。Production 的 exactly-two screen-share simulcast 与 `dynacast: false` 只是实现和质量实验事实,不证明 root topology、publication accounting 或 subscriber model。具体表示门槛由 ADR-0007 和[实时质量调研](./research/realtime-quality-adaptation.md)持有,不得绕过 stock WebRTC congestion control。 @@ -358,7 +358,7 @@ Token-free SFU standby prewarm 保持可选且不创建 participant、publicatio 2. 完成 RoomStore、建房 API、WebSocket 鉴权和定向信令。 3. 完成屏幕捕获、逐观看者 PeerConnection、观看播放和手动质量档。 4. 完成连接恢复和 stats 面板;随后以 STUN-only snapshot 替换旧全房 TURN credential/refresh wire。 -5. 从 canonical `main` 按 ADR-0005 依次落 route waves A-D:先统一 endpoint cap/accounting 与 wire,再建立 SFU/TURN resource admission,最后把 deterministic allocation、child reparent 和 parent drain 收到一个 controller;每个 wave 独立可回滚。 +5. 在已合入的 endpoint cap/accounting 与 `screener-v6` wire 边界上,从 canonical `main` 按 ADR-0005 完成 route waves B-D:建立 SFU/TURN resource admission,并把 deterministic allocation、child reparent 和 parent drain 收到一个 controller;每个 wave 独立可回滚。 6. 路由边界合入后依次落 live screen-audio ceiling 和 paused video-codec transaction;随后做 H.264 根因诊断与 strict-NAT emulator gate,门禁通过才允许 allowlisted canary。 7. 加入 first-frame-driven Viewer connection stages。Site access、room-scoped Viewer grant、路由与 SQLite v3 合同保持唯一。 8. Windows Native fixed-`HIGH` 保持可选且不改变 Web 默认;shared encode、移动 lifecycle 和平台输出按 TODO roadmap 后续推进。 diff --git a/docs/需求理解.md b/docs/需求理解.md index 423d6a0..187c30e 100644 --- a/docs/需求理解.md +++ b/docs/需求理解.md @@ -146,6 +146,7 @@ SFU/TURN 的 publication、subscription、transport、server-resource accounting - Given 用户选择任一推荐档位或高级质量参数,When 接收端实际分辨率、帧率或码率持续显著低于该目标,Then 诊断数据能区分采集约束、发送编码、带宽/拥塞、TURN 路径和接收端限制;产品不得只改变档位标签却继续隐藏实际降级。 - Given 一个健康 SFU leaf 和一个受控弱 SFU leaf 都以 `HIGH` ceiling 订阅,When 内建 LiveKit BWE 运行,Then 弱 leaf 自动使用唯一共享 `LOW` 并在恢复后回到 `HIGH`,健康 leaf 不受影响,且 Screener 没有实现媒体层 selector;direct/peer 继续使用各自的 stock WebRTC GCC。 - Given 一个 Viewer 观察到自己当前 upstream 的接收效果差,When 当前 Viewer 的 `viewer-quality-evidence` 与 parent 对同一 edge 返回的 `parent-edge-quality-evidence` 按 exact route identity(room/share、双方 session、assignment/connection/media-binding generation、route revision,及适用时 publication generation)和 sequence 连续相关,Then 只为该 Viewer 创建 child-scoped reparent intent,排除旧 parent,按 reserve/proof/commit/rollback 换父;不得直接把 parent 全局判坏。 +- Given Viewer 的 exact current ordinary peer upstream 在信令和 PeerConnection 仍存活时停止产生当前代 RTP 与 decoded-frame progress,When 有界 parent-proof deadline 到期后该停滞仍成立,Then controller 不论是否收到 matching positive non-server-parent outbound-media proof,都只把该 logical edge 作为 hard child-scoped reparent 处理,并以 exact generation、一次候选、媒体证明和有界失败约束恢复该 Viewer;parent 的正发送证明或未回应都不改变 `RelayEligibility(parent)`,只有 parent/session 的硬故障、明确 sender/resource failure、修复失败或独立 downstream evidence 才能 cordon/drain parent。 - Given 一个 relay parent 的不同 downstream edges 达到质量 owner 针对当前可观察边数和端点容量定义的独立关联证据门槛,或该 parent 出现明确的 sender/resource failure、修复失败的自身 ingress 或独立 downstream edges 确认转发失效,When 统一 controller 确认 directional ineligibility,Then parent 进入 `draining`,停止新 child;仍健康的 ingress 保留,失效 ingress 在同一有界 target 中替换或移除,并迁移可行 children;无候选 child 进入 waiting/bounded-failure,不得阻塞其他 child,也不得用固定的“两个 child”替代质量策略。Host source 走 publication repair/child migration,不进入 relay-parent reparent。 - Given 一个路径的 sender/viewer 证据跨连续窗口确认 `FALLBACK`,When 应用更新状态,Then 只改变其 edge/parent 拓扑资格和诊断;不得重复命令内建媒体层。更长稳定恢复窗口和 cooldown 后才可重新声明 relay capacity。 - Given 同一 Viewer 同时是某人的 child 和其他人的 parent,When 其自身 ingress 发生 hard/confirmed failure,Then child-scoped reparent 或 branch-preserving `replaceIngress` 优先修复它,同时将其 relay eligibility 置为 `suspect` 并停止新分配;新 ingress 恢复下游媒体时保留子树,只有修复失败或不同 downstream edges 仍确认转发失效时才执行 parent drain。C+B 可同时贡献证据,但 controller 只提交一个 target revision;成功的 child reparent 只使同一旧 logical edge 的 pending evidence 失效,其他仍匹配且未过期的 sibling evidence 保留。