diff --git a/docs/adr/0005-automatic-hybrid-media-routing.md b/docs/adr/0005-automatic-hybrid-media-routing.md index e8040cf..c22ee25 100644 --- a/docs/adr/0005-automatic-hybrid-media-routing.md +++ b/docs/adr/0005-automatic-hybrid-media-routing.md @@ -139,9 +139,9 @@ and one total operation deadline. Candidate failure advances the cursor without resetting that deadline. These fields do not become separate gates or state machines, and this route wave adds no assignment, media-binding, or proof generation to the wire. -A `prepare` route update names that operation's exact child and its -server-issued candidate connection identity. Parent and child therefore prepare -the same connection even when the parent's child set is unchanged by a +A `prepare` route update names that operation's exact child, selected transport, +and server-issued candidate connection identity. Parent and child therefore +prepare the same connection even when the parent's child set is unchanged by a direct/selected-transport replacement; neither endpoint infers candidate authority from an assignment-list difference. A stale or mismatched asynchronous result fails closed and cannot revive an old diff --git a/docs/project-memory.md b/docs/project-memory.md index ef87d30..309588d 100644 --- a/docs/project-memory.md +++ b/docs/project-memory.md @@ -11,7 +11,7 @@ Last updated: 2026-08-23 - 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 source-reachable active graph, exact authenticated route attempts, endpoint and server admission, one room-serial child operation, and bounded success, wait, or failure. -- One room controller reconciles allocation, child reparenting, and relay drain through the same operation. It finds one waiting Viewer or invalid edge and builds one deterministic candidate list. The operation owns its cursor, current candidate and reservations, plus one total deadline; only its current candidate may produce media. A prepare update names that exact child and its server-issued candidate connection ID, so neither endpoint infers authority from an assignment-list difference. A usable old edge remains until the exact candidate child decodes its first new video frame. That event commits; failure advances the cursor, while total deadline or exhaustion ends in wait or failure. A relay with a bad ingress reparents itself as a child and retains its subtree. A disconnected endpoint, or one whose effective downstream capacity falls below its current child count, accepts no excess children; its direct or overflow children enter the same operation and a disconnected endpoint is removed when childless. Authoritative pause aborts the operation, suppresses stall decisions, and resumes from a fresh reconciliation. +- One room controller reconciles allocation, child reparenting, and relay drain through the same operation. It finds one waiting Viewer or invalid edge and builds one deterministic candidate list. The operation owns its cursor, current candidate and reservations, plus one total deadline; only its current candidate may produce media. A prepare update names that exact child, selected transport, and server-issued candidate connection ID, so neither endpoint infers authority from an assignment-list difference. A usable old edge remains until the exact candidate child decodes its first new video frame. That event commits; failure advances the cursor, while total deadline or exhaustion ends in wait or failure. A relay with a bad ingress reparents itself as a child and retains its subtree. A disconnected endpoint, or one whose effective downstream capacity falls below its current child count, accepts no excess children; its direct or overflow children enter the same operation and a disconnected endpoint is removed when childless. Authoritative pause aborts the operation, suppresses stall decisions, and resumes from a fresh reconciliation. - One Host publication may serve all SFU subscriptions. Its exact generation owns one ingress handle and exact Viewer subscription handles own egress; later SFU children reuse the publication, while reserved, committed, and draining handles remain charged until the managed room is deleted and proven absent. SFU-fed and peer-fed endpoints use the same provisional-child transaction, and selected TURN changes only the transport of an authorized logical edge. Parent choice hard-filters authority, reachability, cycles, effective capacity, and server admission, then orders by shallowest result, remaining steady sender capacity, stable join order, and peer identity. Acyclicity and room admission bound maximum depth; depth is observed but has no separate hard cap. 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. diff --git a/docs/方案设计.md b/docs/方案设计.md index 5f2aa91..0de22e6 100644 --- a/docs/方案设计.md +++ b/docs/方案设计.md @@ -383,7 +383,7 @@ SFU admission 在应用单进程中只有一个注入实例。LiveKit credential 普通 Web relay 把收到的 remote track 加入独立 downstream `RTCPeerConnection`,因此可能逐跳解码和重编码;浏览器不保证跨连接 shared encode。每条 ordinary child 是独立网络副本,实际 encode time、CPU/GPU、bitrate、loss、frame rate、depth 和 recovery 必须测量。 -迁移使用 authenticated room/endpoint sessions、share generation、base/pending route revision 与 candidate connection identity。`route-update/prepare` 显式携带当前 operation 的 exact child peer ID 与服务端生成的 candidate connection ID;parent 与 child 直接使用该身份,即使同一 parent 只替换 transport、child 列表不变,也不得从 assignment 差异猜测本次 candidate。可用旧 route 保持 active,candidate 在 active map 外准备;candidate child 的第一帧新 decoded video 原子触发 promotion。失败、超时、代次变化或授权撤销销毁 candidate 并保留或恢复旧 route。Make-before-break 的 overlap 由统一端点容量、单个有界 `TransitionOverlapSlot` 和 typed server-resource admission 同时决定;旧 edge 已 hard-invalid 时直接进入同一恢复事务而不伪装可用。 +迁移使用 authenticated room/endpoint sessions、share generation、base/pending route revision 与 candidate connection identity。`route-update/prepare` 显式携带当前 operation 的 exact child peer ID、selected transport 与服务端生成的 candidate connection ID;parent 与 child 直接使用该 candidate tuple,即使同一 parent 只替换 transport、child 列表不变,也不得从 assignment 差异猜测本次 candidate。可用旧 route 保持 active,candidate 在 active map 外准备;candidate child 的第一帧新 decoded video 原子触发 promotion。失败、超时、代次变化或授权撤销销毁 candidate 并保留或恢复旧 route。Make-before-break 的 overlap 由统一端点容量、单个有界 `TransitionOverlapSlot` 和 typed server-resource admission 同时决定;旧 edge 已 hard-invalid 时直接进入同一恢复事务而不伪装可用。 SFU/TURN 的 publisher、subscriber、selected transport、central admission、resource accounting、temporary overlap 和 fallback sequence 由 ADR-0005 统一定义。普通端点 child count 不能成为 server cap,兜底也不能形成无界 whole-room fanout。一个 Host publication 服务所有 SFU subscriptions;SFU-fed 与 peer-fed endpoint 使用相同的 provisional-child first-frame transaction。TURN 只替换授权 edge 的 transport,Host 无 direct first-level path 时可作为单条 Host-SFU ingress 的 transport。