diff --git a/.agents/skills/stop-that-shit/SKILL.md b/.agents/skills/stop-that-shit/SKILL.md new file mode 100644 index 0000000..6dd0deb --- /dev/null +++ b/.agents/skills/stop-that-shit/SKILL.md @@ -0,0 +1,101 @@ +--- +name: stop-that-shit +description: Control task authority and scope, choose the smallest correct result, and deliver a standalone current artifact without process residue. +--- + +# Stop That Shit + +Do the requested work. Keep necessary consequences. Stop everything else. + +## 1. Authority + +Within higher-priority instructions, the user's latest explicit decision defines +the current task and deliverable. Earlier discussion, examples, experiments, +review suggestions, and agent ideas are inputs, not authority. Resolve the +request against the current product model and reachable evidence before acting. + +The requested task type limits authority. Review, research, explanation, or +diagnosis does not authorize implementation. Implementation does not authorize +deployment, publishing, destructive cleanup, or unrelated changes. Preserve +existing user work and unrelated state. + +## 2. Scope + +Before taking an action that the user did not name, ask: + +1. Did the user request it? +2. Is it necessary to complete the requested result? +3. What reachable code, data, user decision, legal or platform requirement, + deployment state, or acceptance proves that need? +4. Would omitting it fail the current task? + +If the answer remains no, do not take the action. Report it only when useful. + +Requests to "make it better," "optimize," "clean up," or "understand the +intent" do not by themselves add unnamed scope. When the requested boundary is +genuinely ambiguous, default to the smallest complete result. Raise an +unrequested, non-required addition before acting when it would materially change +user-visible behavior, product rules, information structure, dependencies, +implementation scope, or delivery cost. + +## 3. Smallest Correct Result + +Prefer standards, mature framework behavior, and one small general mechanism. +Fix the owning invariant before adding an example-specific branch, gate, probe, +timer, state container, test, compatibility layer, or speculative hook. Add one +only when reachable evidence proves that the general mechanism cannot satisfy +the current result. + +Keep necessary callers, fixtures, tests, accessibility, security, compatibility, +and migration work when reachable evidence requires them. Fewer files or lines +is not the goal. The smallest correct result is. + +## 4. Separate Work From The Deliverable + +The work process may contain questions, alternatives, diagnosis, experiments, +and validation. Do not automatically copy that process into the artifact. The +deliverable must read like a complete, independently authored result that can be +used without the conversation. + +For the deliverable, treat the confirmed current requirements as the sole +content basis, even when editing an existing artifact. Reconstruct the result +from those requirements instead of preserving an old draft's structure or +wording by default. A rejected, withdrawn, or user-requested deletion with no +remaining consumer should be absent as though it had never been introduced. +Current docs, UI, code, comments, configuration, and delivery copy state only +the accepted behavior and rationale that still constrains it. Do not name or +structure a result as a patch, replacement, removal, "no-X" variant, demo, or +intermediate version unless that distinction is itself requested and useful. + +Omit abandoned reasoning, superseded attempts, debug logs, instruction +restatements, agent process, self-referential or meta-explanatory copy, +unrequested suggestions or next steps, obsolete explanations, and modification +traces. Comments and documentation explain only non-obvious current constraints, +rules, risks, or compatibility behavior. + +Keep history, methodology, limitations, warnings, or disclosure only when the +user requested them or when a concrete decision, compatibility, migration, +legal, safety, audit, or rollback consumer requires them. Do not turn internal +risk controls into user-facing caveats. Narrow or attribute uncertain claims +instead of padding the result with process disclaimers. + +A requested research, review, diagnosis, decision record, or no-go conclusion is +itself a valid result. Keep the evidence and reasoning its reader needs to act; +omit only process with no current consumer. + +## 5. Finish + +As part of normal completion, inspect the pending changes and deliverable only: + +1. Every element is requested or a proven necessary consequence. +2. Names, structure, and copy describe the current result without modification + traces. +3. Explanations say what governs the result; historical "why not" material has a + current consumer. +4. The result stands alone and is directly usable for its requested purpose. +5. No explanation, comment, heading, warning, instruction repeat, or next step is + present without a current need. + +Fix failures silently rather than listing them in the deliverable. Report the +current requested result, its necessary consequences, and the evidence that +makes it complete. Do not add a separate audit loop merely to satisfy this skill. diff --git a/AGENTS.md b/AGENTS.md index 9040761..6c59647 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,12 +2,12 @@ ## 1. Decision And Durable Truth -- Highest priority: before implementation, cleanup, or deployment, settle the meaning against the whole product model and evidence, challenge contradictions or needless complexity, and write the accepted decision to its owning truth documents. Discussions, examples, review suggestions, experiments, checkboxes, and agent ideas are inputs, not implementation authority; never turn a partial interpretation into code or a branch. -- Apply Occam's razor as "simple, not simplistic": prefer standards, mature framework behavior, and one small general mechanism that covers the product model. When a concrete failure appears, fix the owning invariant or reconciliation loop first; add a case-specific branch, gate, probe, timer, state container, or test only when evidence shows the general mechanism cannot cover it. Do not implement by repeatedly patching examples. +- Before substantial work, read and follow the complete repo-tracked [`stop-that-shit` skill](./.agents/skills/stop-that-shit/SKILL.md). That file is the Screener authority for generic task boundaries; keep any installed copy synchronized with it rather than maintaining divergent variants. +- Core summary: within higher-priority instructions, the latest explicit user decision defines the task; take only requested actions and proven necessary consequences, and do not treat review/research/implementation as authority for implementation/deployment/cleanup beyond its task type. Broad words such as improve or optimize add no unnamed scope. Prefer standards and one owning invariant over example-specific mechanisms, while preserving unrelated work and necessary callers/tests/security. Reconstruct each deliverable from the accepted current result so it stands alone without rejected alternatives, process narration, or modification traces; inspect only the pending changes and report the result with completion evidence. The full skill governs when this summary is incomplete. +- Highest priority for repository changes: before implementation, cleanup, or deployment, settle the meaning against the whole product model and evidence, challenge contradictions or needless complexity, and write the accepted decision to its owning truth documents. Never turn a partial interpretation into code or a branch. - Until the owner explicitly declares a public release, maintain only the current internal product contract. Do not preserve backward or forward compatibility, legacy wire/config aliases, dual parsers or writers, translators, deprecated APIs, migration shims, or tests whose only consumer is an older release. Upgrade the private deployment atomically, reject stale clients before authority, delete replaced surfaces, and use Git history for rollback. Reassess compatibility only when public release requirements are explicitly opened. - Before dependent work starts, update every affected owning requirement, design, ADR or research conclusion, plus `docs/project-memory.md` and `docs/status.md` when their snapshots change. Checkpoint the consistent truth in Git; chat is not durable truth. - If semantics remain disputed, record the hold in `docs/todo.md` and freeze only dependent work. Do not encode a guess as accepted truth. -- **Current-truth ("Dongpo pork") rule:** after a correction, current docs, UI, code, comments, configuration, and PR copy state only the accepted behavior and rationale that still constrains it. Remove rejected alternatives and explanations of their removal; Git history owns that history. - Queue new observations in their owner and continue the active milestone unless the user requests immediate investigation or the evidence reveals a P0 blocker. ## 2. Safety And Privacy @@ -42,9 +42,8 @@ ## 6. Engineering Defaults -- Apply Occam's razor: implement the smallest complete design with a current consumer, keep unrelated work out, preserve user changes, and avoid speculative frameworks or hooks. - Research non-trivial design, implementation, and bug fixes from current primary sources. Record durable findings and license boundaries under `docs/research/`. - Add tests and independent review in proportion to risk. Batch expensive browser, network, endurance, and deployment checks at acceptance boundaries; use reproducible WebRTC measurements for performance claims. -- Keep comments limited to non-obvious rationale and invariants. Keep scripts and hooks deterministic, fast, cross-platform, and CI-runnable. +- Keep scripts and hooks deterministic, fast, cross-platform, and CI-runnable. - Support Windows, macOS, and Linux; avoid absolute paths and OS-specific separators. Text files use LF, and new filenames use ASCII unless an established user-facing convention requires otherwise. - Before finishing material work, inspect Git status, report untracked project artifacts, and stage requested files unless told otherwise. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fbd5de0..06cb8cd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,7 @@ 2. Create one short-lived branch for one coherent change. Use `feat/`, `fix/`, `docs/`, `refactor/`, `test/`, `chore/`, or `spike/` followed by a short description. 3. For non-trivial design, implementation, or bug fixing, inspect the repository and research current primary sources before changing code. Record durable findings under `docs/research/`. 4. Reconcile the requested outcome against the whole current product model and conflicting evidence. Before implementation, update every affected owning requirement/design/ADR/research document and current memory/status, replace stale current text, and checkpoint that nonvolatile truth in Git. If semantics remain disputed, record a hold and stop dependent implementation. -5. Implement the smallest complete change from that checkpoint. Add tests and concise rationale comments in proportion to risk, and keep operational/current-truth updates in the same coherent pull request when implementation changes source facts. +5. Implement from that checkpoint under the repo-tracked [`stop-that-shit` skill](./.agents/skills/stop-that-shit/SKILL.md). Add tests in proportion to risk, and keep operational/current-truth updates in the same coherent pull request when implementation changes source facts. 6. Run `sh scripts/check-project-state.sh` on macOS/Linux/Git Bash or `./scripts/check-project-state.ps1` on PowerShell, plus `npm run check` and any relevant manual browser/network checks. Record this local evidence in the pull request; feature branches and pull requests use local gates, while GitHub Actions are reserved for `main` integration, releases, and explicit manual runs. Do not retry zero-step or infrastructure failures. 7. Merge an accepted truth checkpoint before dependent candidates. Rebase or rebuild a retained candidate from that main once, keeping main's owning truth on conflicts and transplanting only approved scoped code, tests, and new facts. Make focused commits using `type(scope): summary` where practical, then push the branch. Create any new implementation branch or parallel worktree from that exact canonical `main` commit, never from an older candidate or auxiliary worktree. @@ -27,7 +27,7 @@ Clean up worktrees and branches only after semantic review and integration are c ## Pull Request Scope -A pull request should explain the problem, the chosen design, verification performed, user-visible or operational effects, and remaining risks. Keep unrelated refactors and generated churn out of the branch. +A pull request should explain the problem, the chosen design, verification performed, user-visible or operational effects, and remaining risks. Changes are not complete when only code is updated. Durable changes must update the relevant documentation and current-memory snapshot in the same pull request. diff --git a/docs/adr/0001-p2p-first-media-topology.md b/docs/adr/0001-p2p-first-media-topology.md index b690ae2..48108ca 100644 --- a/docs/adr/0001-p2p-first-media-topology.md +++ b/docs/adr/0001-p2p-first-media-topology.md @@ -31,8 +31,11 @@ contradict the private-room cost model or duplicate mature WebRTC capabilities. ## Current Ownership [ADR-0005](./0005-automatic-hybrid-media-routing.md) owns current routing -invariants and assisted-route roles; the Browser `screener-v10` runtime is -implemented and deployed, while real-network validation remains open. [ADR-0004](./0004-peer-assisted-media-experiment.md) +invariants and assisted-route roles. Exact current source `f5a295c` uses the +strict `screener-v11` Browser wire; exact production +`2726edde9b87f31fd76e749de47972ef817a9bd5`, release `2726edd`, remains on +`screener-v10`. Both use the same accepted route model, while real-network +validation remains open. [ADR-0004](./0004-peer-assisted-media-experiment.md) owns only historical peer-assisted evidence. Access and room lifetime are owned by [ADR-0002](./0002-memory-resident-protected-rooms.md). diff --git a/docs/adr/0002-memory-resident-protected-rooms.md b/docs/adr/0002-memory-resident-protected-rooms.md index 53e3e5f..d6dce03 100644 --- a/docs/adr/0002-memory-resident-protected-rooms.md +++ b/docs/adr/0002-memory-resident-protected-rooms.md @@ -101,7 +101,7 @@ all code-only Viewer attempts. A valid room grant may bypass that site gate only for the exact Viewer role and room. Neither a code, room password, nor Viewer grant can create a room or become Host authority. -The current `screener-v10` room-entry boundary uses exactly one +The current Browser room-entry boundary uses exactly one `ROOM_ACCESS_DENIED` result. It applies only after site access to a well-formed code-only Viewer attempt whose expected admission rejects an unknown or expired room, disabled code entry, an absent or incorrect room password, a full room, or @@ -151,7 +151,7 @@ the generic `SERVER_ERROR`. None of those paths is folded into storage does not. No fingerprint or server user record participates. - Raw site passwords, Host tokens, Viewer grants, and room passwords remain out of application/proxy logs and server durable storage. -- On `screener-v10`, every expected denial of a well-formed, site-authorized +- On the current Browser wire, every expected denial of a well-formed, site-authorized code-only attempt yields only `ROOM_ACCESS_DENIED` with the same public message and connection-close behavior. Tests cover unknown/expired rooms, disabled entry, absent/wrong passwords, full and bounded admission, while @@ -160,12 +160,14 @@ the generic `SERVER_ERROR`. None of those paths is folded into ## Implementation Status -Current source and production run the single `screener-v10` wire and implement -this complete room boundary, -including allocation, leases, orthogonal grant/code admission, rotate/revoke, -password policy, local profile replay, restart loss, browser storage privacy, -and the neutral `ROOM_ACCESS_DENIED` result. All expected code-only denials use -that same public result followed by the shared authentication-failed close code. +Exact current source `f5a295c` runs the strict `screener-v11` wire. Exact +production `2726edde9b87f31fd76e749de47972ef817a9bd5`, release `2726edd`, runs +`screener-v10`; `screener-v11` is not deployed. Both implement this complete +room boundary, including allocation, leases, orthogonal grant/code admission, +rotate/revoke, password policy, local profile replay, restart loss, browser +storage privacy, and the neutral `ROOM_ACCESS_DENIED` result. All expected +code-only denials use that same public result followed by the shared +authentication-failed close code. Exact release and operational evidence remain owned by deployment and verification status. diff --git a/docs/adr/0005-automatic-hybrid-media-routing.md b/docs/adr/0005-automatic-hybrid-media-routing.md index 603d16c..48d6fd9 100644 --- a/docs/adr/0005-automatic-hybrid-media-routing.md +++ b/docs/adr/0005-automatic-hybrid-media-routing.md @@ -152,13 +152,13 @@ A `prepare` route update names that operation's exact child, route kind, and server-issued candidate connection identity. Parent and child therefore prepare the same connection; neither endpoint infers candidate authority from an assignment-list difference. -The current Browser runtime contract uses the single `screener-v10` wire. On each WebSocket, the +The current Browser runtime contract uses the single `screener-v11` wire. On each WebSocket, the server sends the exact prepare before its SFU configuration; the candidate child is queued before a peer parent is allowed to start its offer. WebSocket ordering is the companion-delivery contract, so clients keep no reordering inbox. -Duplicate current companions are idempotent and stale ones are ignored. Native, -v9, and executable senders are outside this release and fail the protocol -boundary before room authority rather than receiving a compatibility path. +Duplicate current companions are idempotent and stale ones are ignored. Every +other wire and executable sender fails the protocol boundary before room +authority rather than receiving a compatibility path. A stale or mismatched asynchronous result fails closed and cannot revive an old edge. Successful candidate `P` is broadcast as active revision `P`. Failure, timeout, @@ -282,7 +282,7 @@ candidate, retry hint, or other topology data. Access, Host presence, signaling, media, and autoplay remain independent presentation inputs. The room-serial operation does not divide its per-child deadline by Viewer -count, but simultaneous joins may form a linear queue. The current v10 diagnostic +count, but simultaneous joins may form a linear queue. The current Browser diagnostic surface observes existing route events without changing the controller: for each current child it keeps only the latest route-demand, operation-start, current-candidate-start, first-decoded-frame, and final-outcome timing. A new @@ -350,14 +350,15 @@ disappears. A multi-process application deployment requires a shared atomic admission and lifecycle owner before it may claim these values are deployment-wide. -## Current Deployment Boundary +## Current Source And Deployment Boundary -Current source and production run the single `screener-v10` Browser runtime with -direct/STUN peer and LiveKit SFU/UDP routes, including the route, first-frame, -typed-status, and Host-only diagnostic contract described above. The operation -owner is only `route`. Exact release and operational evidence are owned by the -deployment document; real heterogeneous-network and SFU media validation -remains open. +Exact current source `f5a295c` runs the strict `screener-v11` Browser wire. Exact +production `2726edde9b87f31fd76e749de47972ef817a9bd5`, release `2726edd`, runs +`screener-v10`; `screener-v11` is not deployed. Both use the direct/STUN peer and +LiveKit SFU/UDP route model, including the route, first-frame, typed-status, and +Host-only diagnostic contract described above. The operation owner is only +`route`. Exact operational evidence is owned by the deployment document; real +heterogeneous-network and SFU media validation remains open. ## Acceptance Boundary @@ -433,8 +434,8 @@ Negative: burst; - make-before-break consumes explicit endpoint and server reservations and may require a bounded-gap cutover when no overlap slot exists; and -- real SFU and target-network evidence is still required. Deploying the v9 - diagnostic does not grant it route authority or close that physical evidence. +- real SFU and target-network evidence is still required; diagnostics remain + observational and do not grant route authority or close physical evidence. ## Relationship to other ADRs diff --git a/docs/maintenance.md b/docs/maintenance.md index 5d6f931..7e97f1a 100644 --- a/docs/maintenance.md +++ b/docs/maintenance.md @@ -4,9 +4,7 @@ 仓库是跨 session、设备和 agent 的持久事实源。会影响后续工作的结论必须先进入其权威文档;聊天、agent 摘要、旧分支和临时计划都不能替代仓库真相。 -常驻上下文只保留每次工作都需要的边界和导航。细节按需读取,完成历史交给 Git。选择满足已验证需求的最简单方案,不为假设性规模、没有消费者的能力或一次性过程增加常驻规则。 - -“东坡肉规则”适用于所有 current truth:纠正一个方案后,当前文档、代码、UI、配置和 PR 文案只描述现行结论,以及仍约束该结论的理由。被否定方案和“为什么删掉它”的解释一并移除,由 Git 历史保存。 +常驻上下文只保留每次工作都需要的边界和导航。细节按需读取,完成历史交给 Git。任务范围、最小正确结果和 current-result 交付遵循 `AGENTS.md` 摘要并完整读取仓库内的 [`stop-that-shit` skill](../.agents/skills/stop-that-shit/SKILL.md);本文件只维护仓库特有的事实治理规则。 ## 事实分层 @@ -31,33 +29,28 @@ ## 真相更新顺序 -1. 把讨论、纠正、示例、review 建议、实验或 agent 发现视为输入,先复述目标和源头理由。 -2. 对照完整产品模型、当前代码、测试和证据,指出冲突、不必要复杂度和仍未确定的语义。 -3. 就地更新受影响的 requirement、design、ADR 或 research owner;仅在快照确实变化时同步 memory/status,未决执行项进入 TODO。 -4. 删除冲突旧文本和被否定方案的残留,检查各 current 文档内部一致。 -5. 形成 Git-tracked truth checkpoint,再开始依赖该结论的实现或派发。 +1. 按 [`stop-that-shit`](../.agents/skills/stop-that-shit/SKILL.md) 的 authority 和 scope 规则,对照完整产品模型、当前代码、测试和证据确定目标;语义未定时只冻结依赖项。 +2. 就地更新受影响的 requirement、design、ADR 或 research owner;仅在快照确实变化时同步 memory/status,未决执行项进入 TODO。 +3. 检查各 current owner 一致并形成 Git-tracked truth checkpoint,再开始依赖该结论的实现或派发。 语义仍未决定时,在 TODO 记录 hold,只冻结依赖项。接受的真相先进入 canonical `main`;保留候选再从该精确提交 rebase 或重建一次,只移植获批的 scoped code、tests 和 new facts。旧分支的 truth 文档不得覆盖当前 owner。具体 Git 和 worktree 操作遵循 `CONTRIBUTING.md`。 ## 机制减负审查 -设计或扩展机制前,先确认它服务哪个用户行为,量化删除后真正损失的功能和体验,再把这份收益与新增的代码、配置、迁移、测试、运行时状态、部署和故障面比较。已有需求或消费者不自动证明机制值得保留;还要问当前规模和使用方式是否真的需要它,现有标准、框架行为或更小的状态是否已经够用。若退让有界且 owner 接受,先更新产品合同,再整体删除失去必要性的组件、开关和分支;若退让不可接受,则保留合同并寻找更小实现。减负审查先做只读清点,不以行数为目标,也不演变成无边界重构。 +机制减负遵循 [`stop-that-shit`](../.agents/skills/stop-that-shit/SKILL.md) 的 scope 和 smallest-correct-result 规则。本仓库的审查先只读清点机制服务的用户行为,量化移除后的真实退让,并与代码、配置、迁移、测试、运行时状态、部署和故障面的整体成本比较。若 owner 接受有界退让,先更新产品合同再删除失去必要性的完整表面;否则保留合同并寻找更小实现。审查不以行数为目标,也不授权无边界重构。 -内存房间决定是基准案例:先衡量删除 SQLite 的真实退让。应用重启本来就会中断全部活动媒体,额外损失只是当前房间号、邀请和休眠租约;同一浏览器还能重放本地创建偏好。对当前私用、最多 20 名 Viewer、允许重启清空的产品,这点体验回退很小。相较之下,SQLite 会持续引入 schema、迁移、路径配置、可写目录、备份、测试分支和跨重启状态语义。产品因此主动接受这份有界回退并更新合同,随后才选择进程内模型和整体删除持久层。结论不是“小项目不应使用 SQLite”,而是不要为价值很小的能力长期维护一整套机制。 - -应用层 TURN 是第二个基准案例:它只能覆盖 direct peer 穿透失败但 UDP 仍可到达中继的窄区间,公开 SFU/UDP 已覆盖当前产品所需的中央兜底;全部 UDP 被封时 TURN/UDP 同样无效。保留它却需要独立 URL/credential schema、短期签发、route tuple、allocation ledger、relay-only rebuild、UI、测试、coturn relay 配置和额外端口。产品接受当前 UDP-only 的明确失败边界,把未来严格防火墙传输留给有真实证据时的 LiveKit 内部能力,并整体删除应用 TURN。生产因此从 TCP/UDP 3478 加 relay range 收敛为 STUN-only UDP 3478,核心 direct/SFU 能力不变。结论不是“TURN 标准没有用途”,而是不要在已有更小通用机制覆盖主要行为时,继续维护重复的应用层路径。 +内存房间与应用层 TURN 分别是 [ADR-0002](./adr/0002-memory-resident-protected-rooms.md) 和 [ADR-0005](./adr/0005-automatic-hybrid-media-routing.md) 已接受的机制减负实例;TURN 的完整成本证据由 [ICE/TURN 研究](./research/built-in-peer-ice-turn.md)维护。具体取舍和当前边界不在本文件复制,也不推广为对 SQLite 或 TURN 的通用结论。 ## 检查点与恢复 在需求或优先级被接受、设计或研究结论改变、实质阶段切换、分支/PR/agent 交接、可能 compaction 或长暂停前更新事实 owner。不要为每个函数、工具调用或未形成结论的探索建立检查点。 -检查点只保存以后仍需要的结论、当前状态、下一步和真实阻塞。不要保存原始对话、完整日志、工具输出、临时路径、重复代码结构、可廉价重查的事实或过程性 TODO 流水账。 +检查点按 [`stop-that-shit`](../.agents/skills/stop-that-shit/SKILL.md) 的 current-result 规则,只保存以后仍需要的结论、当前状态、下一步和真实阻塞;不保存原始对话或工具输出、完整日志、临时路径、可廉价重查的事实和过程性 TODO 流水账。 恢复上下文时依次读取 `AGENTS.md`、project memory、status、TODO、相关需求/设计/ADR/研究,然后检查当前分支、`git status`、近期 commit 和 PR。摘要与仓库冲突时,以当前代码、测试和权威文档为准。 ## 清理规则 -- 新事实与旧事实冲突时,在同一变更中替换或删除旧内容。 - `project-memory.md` 和 `status.md` 接近预算时,先删除可从代码或 Git 恢复的完成/失效内容,再把仍需保留的细节迁到现有 owner;不要反复微压缩句子。 - `todo.md` 只保留真实未完工作、明确 hold 和待用户决策,不保留完成清单或一次性审计过程。 - `verification-status.md` 只保留仍影响验收的跨模块证据;成熟结论迁回 requirement、ADR、research 或 deployment,过期结果删除。 diff --git a/docs/project-memory.md b/docs/project-memory.md index 4b8b7ea..64c351b 100644 --- a/docs/project-memory.md +++ b/docs/project-memory.md @@ -18,7 +18,7 @@ Last updated: 2026-08-24 - Ordinary peer ICE is STUN-only, and current LiveKit media is UDP-only. Credentials, room secrets, candidate details, and diagnostic data remain private and narrowly scoped. A future strict-firewall transport requires separate evidence and must remain inside LiveKit rather than becoming another Screener route candidate. - Browser peers use existing periodic WebRTC/LiveKit stats to maintain one exact-route decoded-progress timestamp. New frames or route/connection changes reset it; a non-paused deadline reports the edge once. Track availability, bitrate, FPS, resolution, freeze, RTT, jitter, loss, sender stats, and SFU layer describe only the current path: they remain framework or diagnostic inputs and cannot prove another parent would be better. - Browser capture requests available share audio by default on initial capture and source switch, with an explicit video-only warning when no audio track is returned. Its screen-audio control offers live-switchable 64/128/256 kbps sender ceilings and defaults to 128. The 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. -- Browser display video leaves `contentHint` unset so Chromium retains its screen-capture classification; returned audio tracks keep `contentHint = "music"`. Browser video is fixed to VP8 across direct, browser-relay, and SFU paths; codec selection, fallback to another media codec, quality-state/wire fields, and share-lifetime codec branches are not product features. Actual codec/profile/encoder stats remain diagnostic only. Production still sets video `motion` and exposes the v10 selector until the accepted v11 contract is implemented and deployed atomically. +- Browser display video leaves `contentHint` unset so Chromium retains its screen-capture classification; returned audio tracks keep `contentHint = "music"`. Browser video is fixed to VP8 across direct, browser-relay, and SFU paths; codec selection, fallback to another media codec, quality-state/wire fields, and share-lifetime codec branches are not product features. Actual codec/profile/encoder stats remain diagnostic only. Production still sets video `motion` and exposes the v10 selector until the implemented v11 contract is deployed atomically. - Recommended quality remains exactly `1080p60`, `1080p30`, and `720p30`, with the middle `1080p30` as the accepted default. `480p` means only an advanced `854x480` resolution choice whose FPS and bitrate remain independently selected; it is not a fourth recommended profile. - Two distribution artifacts are accepted only after the current feature, NAT, and real-network ledger is complete. A public-server one-click deployment package installs the current application plus STUN/SFU and proxy components on a user-owned server. A Windows/macOS/Linux local package runs the Host, application server, and local state on the broadcaster's machine without source, Node, or any external Screener/network service; it keeps workable direct P2P but reports the reachability loss imposed by public ingress, TLS, gateway, NAT, or firewall limits rather than promising universal connectivity. - Current UI, presence, route labels, and diagnostics describe observed state only; they do not create route authority. @@ -27,26 +27,23 @@ Last updated: 2026-08-24 ## Current Source And Production -- Current canonical source and production use the single `screener-v10` Browser wire. Production was built from integrated main `2726edde9b87f31fd76e749de47972ef817a9bd5` as release `2726edd`; auxiliary branches and older worktrees do not supersede canonical `main`. +- Exact source implementation `f5a295c52e0ac7d18e5a7949217861c7aa74e9c9` uses the single strict `screener-v11` Browser wire. Production remains exact integrated main `2726edde9b87f31fd76e749de47972ef817a9bd5`, release `2726edd`, on `screener-v10`; auxiliary branches and older worktrees do not supersede canonical `main`. - Current source and production admit up to `20` Viewers and implement the uniform `1/2/3` endpoint cap, exact prepare candidate, first-decoded-frame commit, strict rollback revision, decoded-progress stall, a two-stage direct/SFU operation deadline, and one event-driven room controller. A short-lived exact-generation decoded-frame observer proves only the pending candidate inside the existing total deadline; the periodic stats sampler remains responsible for active-path diagnostics and stalls. Ordinary peer ICE is STUN-only and the sole application fallback is SFU/UDP; stale TURN environment keys fail startup. SFU admission uses exact publication and Viewer-subscription handles with explicit no-default ingress/egress capacities and a listener-fenced dedicated LiveKit owner. - Current source and production use the memory-resident room model: random free four-digit codes, the configurable dormant lease, exact-Host resume, restart loss, local creation-preference replay, orthogonal Viewer grants and `open | password | disabled` code entry, and direct invitation/policy controls. SQLite room persistence, `ROOM_DATABASE_PATH`, `ROOM_TTL_SECONDS`, and a writable room StateDirectory are absent from the current runtime. - Exact production artifacts, rollback boundary, services, and ports are owned by [deployment](./deployment.md) and indexed by [status](./status.md). -- Current source and production default new shares to VP8, keep the diagnostic selector pre-share only and fixed for the share lifetime, use `shareGeneration`-fenced Pause/Resume, and require the v10 wire. The accepted v11 replacement removes the selector and codec state, constrains Browser media to VP8, and preserves the no-video-hint source behavior. Current source and production implement live 64/128/256 kbps audio-ceiling mutation, typed first-frame Viewer presentation, privacy-safe on-demand route diagnostics, neutral room-code denial, responsive entry controls, exactly three recommended profiles with `1080p30` as default and advanced-only `854x480`. +- Current source requires v11, fixes Browser direct, browser-relay, and SFU media to VP8, leaves video `contentHint` unset, and contains no codec UI, quality state, wire field, fallback media codec, or share-lifetime codec branch. Production remains v10 with the pre-share selector fixed for one share and video `contentHint = "motion"`. Source and production use `shareGeneration`-fenced Pause/Resume and implement live 64/128/256 kbps audio-ceiling mutation, typed first-frame Viewer presentation, privacy-safe on-demand route diagnostics, neutral room-code denial, responsive entry controls, exactly three recommended profiles with `1080p30` as default and advanced-only `854x480`. - Browser SFU subscribers reconcile eligible Host screen publications across connect/activate event ordering, participant/track arrival, and reconnect. Production LiveKit logs only warn/error, and the application service has a bounded same-host LiveKit readiness preflight. -- Exact v10 runtime source `fdd5a4a529ff297f41c05ea3388bf484d76afe8f` passed 610 Web tests in 45 files, TypeScript typecheck, client/server production builds, access/privacy, the 257-test SFU admission gate, dependency audit, and repository hygiene. Its one-Host/20-Viewer Chrome 151 loopback decoded every Viewer, propagated the selected VP8 settings, bounded Host/relay fanout at `2`, captured all current-child timing distributions, and observed no SFU publication. It is not public-network, SFU, mobile, physical audio/codec, H.264 performance, or background-lifecycle evidence. -- Postflight found `screener`, LiveKit, coturn, and nginx active with `NRestarts=0`; local and public `/` and `/healthz` return 200, every served client file matches the immutable release, the public Browser bundle contains `screener-v10` and no `screener-v9`, the release shares no regular-file inode with its predecessor, and the accepted socket/firewall boundary is intact. The LiveKit namespace remained empty, so deployment evidence is not route or physical-media acceptance. Detail is owned by [deployment](./deployment.md) and [verification status](./verification-status.md). +- Exact v11 source passed the current automated source gates but is not deployed and has no physical direct, browser-relay, or SFU codec evidence. Retained v10 source and production postflight evidence remain bounded to their tested revisions. Exact results are owned by [verification status](./verification-status.md), while artifacts and rollback are owned by [deployment](./deployment.md). - Chrome loopback, cap2/cap3, short resource, recovery, MBB, and A/V fixtures are bounded evidence only. They do not establish quality, resource limits, or product policy. ## Current Priority -1. Implement the accepted single-wire Browser v11 contract with fixed VP8 and no video hint, then deploy and physically validate exact direct, browser-relay, and SFU codec behavior. +1. Deploy the implemented single-wire Browser v11 contract atomically, then physically validate exact direct, browser-relay, and SFU codec behavior. 2. Queue Browser VP8 hardware-acceleration evidence separately; do not add another codec, custom encoder, or Native helper without a new accepted decision. Diagnose screen audio and invitation UI, then finish background/mobile/network evidence at their stated boundaries; Native/executable, distribution, and repository-wide simplification remain later phases. ## Working Rules -- Discussion and evidence are inputs, not executable TODOs. Accepted semantics are written to their owners before implementation. -- Prefer standards and mature framework behavior, then one general reconciliation mechanism. Repair an invariant before adding a case branch; a specialized gate, probe, timer, state container, or test requires evidence that the general mechanism cannot cover the failure. -- Current documents state the current model directly. Rejected alternatives and removal narratives are deleted; Git history owns them. +- Generic task authority, scope, smallest-correct implementation, and current-result delivery are owned by the repo-tracked [`stop-that-shit` skill](../.agents/skills/stop-that-shit/SKILL.md); repository-specific truth and execution rules remain in `AGENTS.md` and `CONTRIBUTING.md`. - Old branches may contribute scoped code or evidence only after reconciliation. Their memory, requirements, ADRs, status, and deployment snapshots never overwrite newer mainline truth. - Preserve dirty, unique, open-stack, and evidence worktrees until their disposition is explicitly decided. Workspace counts are sampled on demand rather than stored here. diff --git a/docs/research/browser-background-capture.md b/docs/research/browser-background-capture.md index 49b3f14..6d68fe3 100644 --- a/docs/research/browser-background-capture.md +++ b/docs/research/browser-background-capture.md @@ -44,15 +44,19 @@ mechanism. ## Current Source Boundary -The source review covers canonical source `a26eb39dc677003110787b0ed1581c208f894fd7`; -production remains exact main `2726edde9b87f31fd76e749de47972ef817a9bd5`. +The no-video-hint review baseline is +`a26eb39dc677003110787b0ed1581c208f894fd7`. Exact current source +`f5a295c52e0ac7d18e5a7949217861c7aa74e9c9` uses strict `screener-v11`, +fixed VP8, no video hint, and no codec UI, quality state, or wire field. +Production remains exact `2726edde9b87f31fd76e749de47972ef817a9bd5`, +release `2726edd`, on v10 with video `motion` and the pre-share codec selector. The current path does not claim or implement a page-keepalive mechanism, and deployment health supplies no physical background-capture evidence. - Current `src/client/media/quality.ts` obtains one `getDisplayMedia()` stream, applies ideal/max capture constraints, leaves the video hint unset, and applies sender bitrate, frame-rate, and degradation ceilings. Production - still marks video as `motion` until the source change is deployed. Explicit + still marks video as `motion` until v11 is deployed. Explicit sharing pause and authoritative reconnect re-pause change capture tracks' `enabled` state; neither manufactures foreground activity. Audio `contentHint = "music"` remains unchanged. diff --git a/docs/research/browser-screen-audio-quality.md b/docs/research/browser-screen-audio-quality.md index 3f1049c..d939cb1 100644 --- a/docs/research/browser-screen-audio-quality.md +++ b/docs/research/browser-screen-audio-quality.md @@ -6,11 +6,15 @@ Status: peer and SFU routes already use stereo and a 128 kbps default, but users still report speech-gated movie/game audio, including on a phone connected directly through the SFU. Current Chromium web `getDisplayMedia()` defaults to local speech processing unless the request disables it. The source request is -explicit. Current Browser v10 source -`fdd5a4a529ff297f41c05ea3388bf484d76afe8f` exposes bounded 64/128/256 kbps +explicit. Exact current Browser source +`f5a295c52e0ac7d18e5a7949217861c7aa74e9c9` uses strict `screener-v11`, +fixed VP8, no video hint, and no codec UI, quality state, or wire field. It +exposes bounded 64/128/256 kbps choices, applies them to new P2P, browser-relay, and SFU senders, and implements -serialized live mutation with applied readback. Production deploys that v10 -path. Target-device audible proof remains open. +serialized live mutation with applied readback. Production remains exact +`2726edde9b87f31fd76e749de47972ef817a9bd5`, release `2726edd`, on v10 with +video `motion` and the pre-share codec selector; it deploys the same audio path. +Target-device audible proof remains open. ## Scope And Decision @@ -48,7 +52,7 @@ stereo music in a 64--128 kbps sweet spot, and LiveKit 2.22.0 names 128 kbps `musicHighQualityStereo`. Requested, applied, negotiated, and observed states remain separate. -The advanced panel is named Share advanced settings. Current v10 source stores the +The advanced panel is named Share advanced settings. Current source stores the 64/128/256 choice and applies that sender `maxBitrate` ceiling on the existing Opus path when it creates a sender. A change during an active share serializes `getParameters()`/`setParameters()` updates and readback, keeps media and the old @@ -67,8 +71,8 @@ voice-processed source. Users first reported that production `6ccb516a47261054f91dfa2fafa408d39ced59fc` sounded poor for movie/video screen -audio. Later source and production revisions added peer/SFU stereo and the -matching `maxaveragebitrate=128000`, but the speech-gated sound remained. A +audio. Current source and production use peer/SFU stereo and the matching +`maxaveragebitrate=128000`, but the speech-gated sound remained. A phone Viewer connected directly through the SFU reproduced it, so browser-relay decode/re-encode is a route-specific amplifier rather than the common cause. The shared Host capture path runs before direct P2P, SFU and peer-relay routes. @@ -87,10 +91,9 @@ environment observation, not a cross-browser source guarantee. ## Voice-Processing Boundary -The earlier conclusion that Chromium content capture defaults all speech -processing off incorrectly generalized extension `tabCapture`/`desktopCapture` -tests to the Web Screen Capture API. Chromium M142 restored separate defaults -after a regression and now classifies ordinary web `getDisplayMedia()` as +Extension `tabCapture`/`desktopCapture` tests do not establish speech-processing +defaults for the Web Screen Capture API. Chromium M142 classifies ordinary web +`getDisplayMedia()` as `kOther`, not `kExtensionScreenShare`. Without explicit constraints, that path selects browser-decided echo cancellation and defaults noise suppression and automatic gain control on. Its processed candidate also defaults to one channel. @@ -448,7 +451,8 @@ deltas in earlier video loopbacks. This is functional evidence, not packaging, real-game sync, second-Viewer, SFU/UDP, or endurance evidence. Run one bounded matrix rather than a full route Cartesian product: exact -production and current `main` on Windows Chrome/Edge for tab/window/monitor, +production and exact v11 source `f5a295c52e0ac7d18e5a7949217861c7aa74e9c9` +on Windows Chrome/Edge for tab/window/monitor, audio selected/unselected, and a simultaneous voice call; then the native candidate on current Windows 11 with game parent and child audio, an independent voice process, notifications, no render stream, and process restart. Windows 10 @@ -463,7 +467,7 @@ A/V playout timing using a distinguishable stereo fixture plus game/film audio. ## UI And Voice Boundary Share advanced settings offers exactly 64/128/256 kbps and defaults to 128. -Current v10 source applies the selected choice before sharing, to every newly +Current source applies the selected choice before sharing, to every newly created P2P, browser-relay, or SFU sender, and through a serialized live mutation; production deploys the same path. It reads the latest desired profile into each sender and keeps endpoint-local applied diff --git a/docs/research/low-server-media-routes.md b/docs/research/low-server-media-routes.md index 0783f97..90c4d05 100644 --- a/docs/research/low-server-media-routes.md +++ b/docs/research/low-server-media-routes.md @@ -5,9 +5,10 @@ low latency, and bounded host media fanout - Status: research and dated route evidence. Current invariants and assisted transport roles are in [ADR-0005](../adr/0005-automatic-hybrid-media-routing.md). - Exact Browser v10 source `fdd5a4a529ff297f41c05ea3388bf484d76afe8f` - implements the current route transaction and diagnostics; production now runs - that v10 contract, while real-network validation remains in + Exact current Browser source `f5a295c52e0ac7d18e5a7949217861c7aa74e9c9` + implements the route transaction and diagnostics on strict v11; production + remains exact `2726edde9b87f31fd76e749de47972ef817a9bd5`, release `2726edd`, + on v10, while real-network validation remains in [verification status](../verification-status.md). ## Current Transport Conclusion @@ -557,7 +558,7 @@ counters would not be deployment-wide admission. | Route | Where copies are emitted | Endpoint cost | Evidence status | | --- | --- | --- | --- | | Direct host P2P | Host emits one copy per Viewer | Host upload and sender pipelines grow with Viewers | Baseline evidence; current capacity is owned by the product contract | -| Bounded browser relay DAG | Host and each Web relay emit at most the configured endpoint cap | Ordinary browser, but every relay decodes and re-encodes and adds a hop | V10 source and production admit up to 20; the exact v10 local direct loopback gate passed, while heterogeneous networks remain open | +| Bounded browser relay DAG | Host and each Web relay emit at most the configured endpoint cap | Ordinary browser, but every relay decodes and re-encodes and adds a hop | Current v11 source and v10 production both admit up to 20; the exact v10 local direct loopback gate passed, while heterogeneous networks remain open | | Native shared-encode host | Host targets one encode for standard WebRTC edges | libwebrtc public-API proxy risk spike, with Pion as fallback | Research evidence; still pays per-edge upload | | Native volunteer encoded-RTP relay | Each volunteer forwards one encoded copy | Native install, RTP/RTCP forwarding, packaging, and opt-in relay policy | Research only; no current product authorization | | SFU service | SFU emits authorized subscription copies | Service pays bounded egress; an authoritative Host publisher supplies media | Production deploys the v10 topology/admission; local LiveKit functional evidence exists, while heterogeneous-network/resource validation remains open | diff --git a/docs/research/peer-assisted-media.md b/docs/research/peer-assisted-media.md index d048c51..9a2b2d8 100644 --- a/docs/research/peer-assisted-media.md +++ b/docs/research/peer-assisted-media.md @@ -232,13 +232,13 @@ networks. ## Implemented Bounded Quality Coordination The implementation coordinates one strict `QualitySettings` object across the -peer-assisted tree without adaptation logic. Exact v10 source accepts advanced +peer-assisted tree without adaptation logic. Current source and production accept advanced 480p/720p/1080p/1440p resolution values, integer 15-60 fps, integer 2-12 Mbps, and the three standard degradation preferences; missing, extra, or out-of-range fields fail schema validation. The three visible presets are recommendations rather than wire IDs, and `480p` is only the advanced 854x480 resolution. The server stores the latest complete object in a room-count-bounded in-memory map, -defaults to 1080p30 at 5 Mbps with balanced priority in v10 source, includes it in +defaults to 1080p30 at 5 Mbps with balanced priority, includes it in peer-assisted authenticated snapshots, and broadcasts Host changes to online Viewers. Production v10 uses the same 1080p30 default and advanced 480p boundary. The value survives a stopped share, is removed with diff --git a/docs/research/realtime-quality-adaptation.md b/docs/research/realtime-quality-adaptation.md index 1e84a58..18aa4ab 100644 --- a/docs/research/realtime-quality-adaptation.md +++ b/docs/research/realtime-quality-adaptation.md @@ -11,8 +11,10 @@ others. `maintain-framerate` may preserve motion by reducing resolution until game UI, maps, subtitles, and text become unreadable; `maintain-resolution` may instead lower frame rate. Neither preference overrides congestion control. -Current Browser v10 source `fdd5a4a529ff297f41c05ea3388bf484d76afe8f` -uses `balanced` as the recommended profile and advanced default; +Exact current Browser source `f5a295c52e0ac7d18e5a7949217861c7aa74e9c9` +uses strict `screener-v11`, fixed VP8, no video `contentHint`, and no codec +UI, quality state, or wire field. It uses `balanced` as the recommended profile +and advanced default; `maintain-resolution` and `maintain-framerate` remain explicit choices. These preferences leave actual degradation to the browser, so Screener observes readback and stats rather than claiming a fixed quality outcome. @@ -157,11 +159,12 @@ Screener's accepted boundary forbids adding application SDP bitrate hacks. The same release was also reported to reduce game-stream frame rate and consume noticeable Host resources. That report applies only to `769de201f7cc`, not to current production or automatically to the newer -diagnostics on `main`. The Web +diagnostics in exact source `f5a295c52e0ac7d18e5a7949217861c7aa74e9c9`. +The Web sender creates one independent `RTCRtpSender` per viewer and has no cross-PC shared-encoder guarantee; its muted local preview creates no media edge or server traffic but may still consume compositor/GPU work. Compare the exact -release and current `main` under one fixture, with preview on/off as a separate +release and exact current source under one fixture, with preview on/off as a separate binary intervention. Desktop background diagnosis must also separate three independent variables: @@ -200,18 +203,16 @@ Pinned LiveKit client 2.22.0 keeps three relevant pieces of state. Its public `LocalVideoTrack.setDegradationPreference()` updates the saved preference used when a sender is installed; `LocalVideoTrack.publishOptions` drives encoding recomputation after a track restart; and `LocalTrackPublication.options` is the -input to `republishAllTracks()`. The previous Screener update path configured -the raw sender and replaced only `track.publishOptions`, so a later SDK -republish could read the initial publication preference. The bounded fix uses -the existing publisher operation queue and rollback: call the SDK preference -API to update its saved state, configure/read back the current `q,h` sender as -the final write, then assign one merged option object to both retained +input to `republishAllTracks()`. Current source keeps those three owners aligned +through the existing publisher operation queue and rollback: call the SDK +preference API to update its saved state, configure/read back the current `q,h` +sender as the final write, then assign one merged option object to both retained locations. Failure reapplies the previous profile; generation loss cannot retain the result as current publisher state. This changes no capture constraint, codec, representation, subscriber layer or route policy and does not explain an immediate same-publication report. -Host SFU publisher A+B remains a separate observability slice. Current v10 source +Host SFU publisher A+B remains a separate observability slice. Current source implements one two-second, publication-generation-bound local sampler owned by `SfuPublisher`: merge its video/audio `LocalTrack` reports, reuse the existing strict stats parser and accumulator, correlate capture settings from the owned @@ -232,10 +233,14 @@ as their only video media codec, while RTX/RED/FEC may remain repair formats; SFU publication explicitly uses VP8 with no backup codec. The UI and quality wire expose no codec choice. Codec/profile/encoder stats remain diagnostic and do not authorize automatic switching, route changes, or another controller. +Exact source `f5a295c52e0ac7d18e5a7949217861c7aa74e9c9` implements this strict +`screener-v11` contract. Production remains exact +`2726edde9b87f31fd76e749de47972ef817a9bd5`, release `2726edd`, on v10 with +video `contentHint = "motion"` and the pre-share codec selector. Chromium maps video `contentHint = "motion"` to libwebrtc `kFluid`, and -libwebrtc clears `is_screencast` for that mode. Screener was therefore replacing -the display-capture screen classification with realtime-camera semantics. Fresh +libwebrtc clears `is_screencast` for that mode, replacing the display-capture +screen classification with realtime-camera semantics. Fresh Chrome 151 loopback probes on 2026-08-24 used real dynamic tab `getDisplayMedia()`, `balanced`, ten seconds of warm-up, and a fifteen-second sample: @@ -281,8 +286,8 @@ power efficiency, rate control, and game-load behavior. These results select VP8 for the ordinary Browser path: no-hint VP8 met the current controlled quality baseline, has the required WebRTC interoperability, -and does not depend on a page choosing a specific Windows encoder. Current -accepted implementation uses `RTCRtpTransceiver.setCodecPreferences()` before +and does not depend on a page choosing a specific Windows encoder. Exact current +source uses `RTCRtpTransceiver.setCodecPreferences()` before the first offer and fails the edge if the API, a VP8 capability, or the preference application is missing; it does not leave another video media codec as fallback. Browser VP8 @@ -697,7 +702,7 @@ latency, CPU, and memory conflict and must be balanced. Its native encoder tuning and hardware integration are not available to a browser-only sender and must not be presented as settings this project already has. -## Current Source V10 Policy +## Current Source Policy The three user-visible profiles remain ceilings rather than promised rates: @@ -707,11 +712,11 @@ The three user-visible profiles remain ceilings rather than promised rates: | 1080p30 | 1920x1080 at 30 fps | 5 Mbps | | 720p30 | 1280x720 at 30 fps | 3 Mbps | -V10 source and production default to the middle `1080p30` ceiling. Choosing that +Current v11 source and v10 production default to the middle `1080p30` ceiling. +Choosing that default trades a 60 fps ceiling for a 1080p capture bound. The recommended set remains exactly the three profiles -above. V10 adds -`480p` only as an advanced `854x480` resolution whose frame rate and bitrate are +above. Both expose `480p` only as an advanced `854x480` resolution whose frame rate and bitrate are selected independently, not as a fourth profile or preset ID. LiveKit currently uses the same 1080p30 at 5 Mbps screen-share preset, but neither preset guarantees the emitted resolution, frame rate, or bitrate. @@ -723,7 +728,7 @@ guarantees the emitted resolution, frame rate, or bitrate. source picker or renegotiate healthy peer connections. - Current source leaves the video hint unset so display capture retains browser screen semantics; production still sets `contentHint = "motion"` - until deployment. Recommended profiles and the advanced initial value use + until v11 deployment. Recommended profiles and the advanced initial value use `balanced`, with explicit `maintain-resolution` and `maintain-framerate` choices. None promises an emitted resolution or rate. - `maxBitrate` and `maxFramerate` are ceilings. They are neither minimums nor @@ -733,9 +738,9 @@ guarantees the emitted resolution, frame rate, or bitrate. Automatic/H.264/VP8 before sharing starts and defaults to VP8. The `480p` choice is only advanced `854x480`, not a fourth recommended profile. Its 64/128/256 kbps audio ceiling, default 128, is live-switchable on the existing Opus path. Production deploys both the - advanced 480p resolution and live audio mutation. The accepted v11 replacement - removes that codec selector and the corresponding quality-state/wire field; - Browser media is fixed VP8. Display capture does not standardize channel-count or + advanced 480p resolution and live audio mutation. Current v11 source keeps + those controls, fixes Browser media to VP8, and exposes no codec UI, + quality-state field, or wire field. Display capture does not standardize channel-count or sample-rate control. The peer receive contract permits Opus `stereo=1;maxaveragebitrate=256000`, paired with pinned LiveKit's explicit high-quality stereo/forceStereo option; the selected sender @@ -756,9 +761,8 @@ guarantees the emitted resolution, frame rate, or bitrate. - Pausing sharing disables every track in the current capture stream, producing black video and silence without closing the room or media connection. -The deployed v10 implementation stops at manual bounded controls. -It adds no composite score, periodic -adjustment, automatic codec forcing, SDP bitrate +Current source and deployed v10 stop at manual bounded controls. +They add no composite score, periodic adjustment, runtime codec switching, SDP bitrate manipulation, or scene detector. Three consecutive samples of one non-`none` native `qualityLimitationReason` produce one explanatory warning; a reason change or recovery resets it and never triggers a media action. @@ -777,9 +781,8 @@ CPU/GPU cost, public networks, or sustained behavior. - No canvas pixel-difference detector, machine-learned rate controller, or periodic profile switching. - No copied x264 CRF/preset recipe in the browser path. -- No runtime, automatic, or user-selected Browser codec switching. The accepted - v11 replacement fixes VP8; implementation and production cutover are tracked - separately. +- Browser video is fixed VP8, with no runtime, automatic, or user-selected codec + switching. - No channel-count, sample-rate, codec, arbitrary bitrate, stereo, DTX, RED or FEC control, and no inference of actual stereo or sample rate from `opus/48000/2`. Screen media uses one route-consistent stereo contract; diff --git a/docs/session-handoff.md b/docs/session-handoff.md index 7f94fad..dbd1a5f 100644 --- a/docs/session-handoff.md +++ b/docs/session-handoff.md @@ -32,8 +32,9 @@ Current high-signal boundary: - docs/status.md owns the exact source/production/hold state. - docs/todo.md is the only executable work ledger and owns ordering. - ADR-0005 owns the accepted automatic route model: direct/STUN peer followed - only by the dedicated LiveKit SFU/UDP fallback. Current source and production - use the single `screener-v10` wire. The route uses one short-lived + only by the dedicated LiveKit SFU/UDP fallback. Exact source implementation + `f5a295c52e0ac7d18e5a7949217861c7aa74e9c9` uses strict `screener-v11`; + production remains on `screener-v10`. The route uses one short-lived exact-generation decoded-frame observer only for the pending candidate inside the existing total deadline; the periodic stats sampler still owns active-path diagnostics and stalls. Real external-network and SFU media evidence remains @@ -46,19 +47,17 @@ Current high-signal boundary: exact rollback artifacts are owned by deployment. - Browser display video must leave `contentHint` unset; audio keeps `music`. Browser video is fixed VP8 across direct, browser-relay, and SFU paths; the - accepted strict v11 contract removes codec UI/state/wire and fallback media - codecs. Current source and production remain v10 with the selector, and - production still sets video `motion`, until implementation and atomic deploy. - Heterogeneous-network and SFU media evidence remains open. + current strict v11 source has no codec UI/state/wire or fallback media codec. + It passed the current automated source gates. + Production still uses v10, the selector, and video `motion`; v11 is not deployed + and has no physical direct, browser-relay, or SFU codec evidence. - Ordinary browser ICE owns direct reachability. Do not build port prediction, guessed candidates, NAT classification, TCP probes, quality scores, or quality-driven reparenting. Current-path quality is diagnostic; a healthy decoded edge remains sticky. -- docs/maintenance.md owns the reusable mechanism-simplification review. SQLite - is its reference case because the bounded restart-experience loss did not - justify the persistence surface; accepting that tradeoff changed the contract, - rather than a prior contract change causing the removal. The later repository - audit in TODO is not permission for broad cleanup during this handoff. +- docs/maintenance.md owns the reusable mechanism-simplification review; + ADR-0002 owns the accepted memory-room tradeoff. The later repository audit in + TODO is not permission for broad cleanup during this handoff. - The canonical root/main checkpoint reconciles the route truth audit with this room decision. Use that coherent truth as the base; do not replace it with older documents from another worktree. diff --git a/docs/status.md b/docs/status.md index 96ba65b..50aed73 100644 --- a/docs/status.md +++ b/docs/status.md @@ -16,18 +16,18 @@ This is the current execution index. Git history owns completed timelines; [veri ## Current Source -- Canonical root `main` is the source and integration truth. Current source and production use the single Browser `screener-v10` boundary and reject every other wire before room authority; auxiliary branches and older worktrees do not supersede it. The accepted replacement is one atomic `screener-v11` contract with fixed Browser VP8 and no codec quality field; it is not yet implemented or deployed. +- Canonical root `main` is the integration truth; auxiliary branches and older worktrees do not supersede it. Exact source implementation `f5a295c52e0ac7d18e5a7949217861c7aa74e9c9` uses one strict Browser `screener-v11` boundary and rejects every other wire before room authority. Production remains exact release `2726edd` on v10; v11 is implemented but not deployed. - Current source implements one Host plus up to `20` Viewers, one steady outbound media-copy cap for every non-server endpoint (default `2`, static `1/2/3`), and the process-memory room model with random four-digit codes, a default 24-hour dormant lease, exact-Host resume, restart loss, local Host preference replay, independent token invitations, `open | password | disabled` code entry, and no SQLite runtime. - One event-driven controller owns the committed graph and at most one room-serial child operation. It uses one deterministic candidate list/cursor and one total direct-then-SFU deadline; exact admission and physical resources remain charged through drain, and the pending candidate commits only after an exact-generation decoded-frame proof. A short-lived 100 ms stats observer proves only that candidate inside the existing deadline, while the 2-second sampler remains responsible for active-path diagnostics and decoded-frame stalls. Healthy edges remain sticky and current-path quality does not authorize reparenting. - Ordinary peer ICE is STUN-only and the only application fallback is the dedicated LiveKit SFU over UDP. SFU generations use explicit no-default ingress/egress capacities, exact `reserved | committed | draining` accounting, delete-plus-absence release, one Host publication, and exact Viewer subscription handles. No Screener TURN, ICE/TCP, media TCP, or TLS-relayed media route exists. -- Current source leaves video `contentHint` unset and keeps audio `contentHint = "music"`. It implements live 64/128/256 kbps audio-ceiling mutation for current and future Host/relay/SFU senders. Browser sharing defaults to VP8; `automatic | H.264 | VP8` is a temporary pre-share-only diagnostic input and remains fixed for the share lifetime. Ordinary Pause/Resume changes the existing tracks and Host SFU publication under the exact current Host session and `shareGeneration`. +- Current source leaves video `contentHint` unset and keeps audio `contentHint = "music"`. Browser direct and browser-relay offers contain VP8 as their only media codec, and SFU publication explicitly uses VP8 with no backup codec. Codec UI, quality state, wire fields, fallback media codecs, and share-lifetime codec branches are absent. Live 64/128/256 kbps audio-ceiling mutation and ordinary `shareGeneration`-fenced Pause/Resume remain unchanged. - Current source implements typed first-frame Viewer presentation and recovery, Chinese user-facing route/access failures, privacy-safe failed-page export, authenticated Host-only on-demand route snapshots, neutral `ROOM_ACCESS_DENIED` room-code admission, and responsive entry controls. - Recommended quality remains exactly `1080p60`, `1080p30`, and `720p30`; current source defaults to `1080p30`. Advanced resolution adds `480p` as `854x480` without adding a fourth preset, and advanced FPS and bitrate remain independent. -- Exact v10 runtime source `fdd5a4a529ff297f41c05ea3388bf484d76afe8f` passed 610 Web tests in 45 files, TypeScript typecheck, client/server production builds, the access/privacy gate, the 257-test SFU admission gate, production-dependency audit, and repository hygiene. Its one-Host/20-Viewer Chrome 151 loopback decoded every Viewer, propagated the selected VP8 settings, kept Host and relay fanout within cap `2`, captured all four current-child timing distributions, and observed no SFU publication. This is source, state-machine, build, privacy, and direct-loopback evidence, not public-network, SFU, mobile, physical audio/codec, H.264 performance, or Host-background evidence. +- Exact v11 source implementation `f5a295c52e0ac7d18e5a7949217861c7aa74e9c9` passed the current automated source gates. It has no deployment or physical direct, browser-relay, or SFU codec evidence; retained v10 loopback evidence applies only to that older source. Exact results are owned by [verification status](./verification-status.md). ## Current Milestone -1. Implement and validate the accepted `screener-v11` fixed-VP8/no-video-hint Browser contract, then deploy it atomically and verify direct, browser-relay, and SFU paths from actual codec stats. Current source and production remain v10 with the pre-share selector; production also remains on video `motion`. +1. Deploy the validated `screener-v11` fixed-VP8/no-video-hint Browser source atomically, then verify direct, browser-relay, and SFU paths from actual codec stats. Production remains v10 with the pre-share selector and video `motion` until that cutover. 2. Diagnose the reported screen-audio `1 kbps` readout and validate live audio ceilings, then refine the Host invitation controls without changing grant semantics implicitly. 3. Reproduce the Host background/minimized report under controlled conditions while recording the actual negotiated codec. 4. Finish representative ICE/STUN/SFU acceptance including mobile networks. Browser port prediction, NAT classification, TCP probing, fake page keepalive, and quality-driven reparenting remain outside the accepted model. @@ -37,12 +37,12 @@ This is the current execution index. Git history owns completed timelines; [veri - `fix/configurable-relay-cap` is an old, incomplete draft and must not be merged as-is. - Open PR #192 and the Native stack are evidence/research, not pending product releases. Native senders, capture helpers, shared-encode executables, and their test binaries are outside the current Browser milestone and are not built or run. - Deployed surfaces and retained candidates that still need product decisions are indexed only in [the TODO ledger](./todo.md); do not extend or roll them back automatically. -- Room lifetime, authorization/storage semantics, restart loss, Browser v10 entry/presentation, and rollback restoration are aligned between current source and production. +- Room lifetime, authorization/storage semantics, restart loss, entry/presentation, and rollback restoration remain aligned. The source v11 codec contract is intentionally ahead of production v10 until atomic cutover. - Real SFU recovery, heterogeneous networks, mobile lifecycle, audio/A-V device behavior, and endurance/resource measurements remain external acceptance evidence, not blockers for unrelated reversible work. ## Current Hold -There is no active P0/P1 source or deployment hold. Current source and production run the postflight-clean -Browser v10 contract while the accepted v11 fixed-VP8 implementation and no-video-hint deployment remain pending. Audio, heterogeneous-network, SFU, +There is no active P0/P1 source or deployment hold. The fixed-VP8/no-video-hint v11 source is implemented and source-validated; production remains on the postflight-clean +Browser v10 contract until atomic deployment. Physical v11 direct, browser-relay, and SFU codec evidence, plus audio, heterogeneous-network, SFU, background, and mobile evidence remains open. Native/executable work and broad repository cleanup remain outside the current evidence boundary. diff --git a/docs/todo.md b/docs/todo.md index 14c8a68..58b771b 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -6,7 +6,7 @@ Only items in **Now** are executable after their stated decision gate. A branch ## Now -1. **Implement, deploy, and physically validate fixed Browser VP8 with no video hint.** Replace the current v10 selector/state with one strict v11 wire: direct and browser-relay offers keep VP8 as the only media codec, SFU publication uses VP8 with no backup codec, video leaves `contentHint` unset, and audio keeps `contentHint = "music"`. Validate the source first, then deploy server/assets atomically and confirm actual codec/capture/outbound/decoded stats on direct, browser-relay, and SFU paths. Production remains v10 with video `motion` until that cutover. +1. **Deploy and physically validate fixed Browser VP8 with no video hint.** Exact source implementation `f5a295c52e0ac7d18e5a7949217861c7aa74e9c9` already provides the strict v11 wire, VP8-only direct/browser-relay offers, VP8 SFU publication with no backup codec, unset video `contentHint`, and no codec UI/state/wire. Deploy server/assets atomically, then confirm actual codec/capture/outbound/decoded stats on direct, browser-relay, and SFU paths. Production remains v10 with video `motion` and the selector until that cutover. 2. **Diagnose and physically validate live screen audio.** First reproduce the Host diagnostic remaining at `1 kbps` after switching the shared source, and distinguish stale/reset statistics from an actual RTP bitrate problem. The app already requests audio and supplies system/window audio hints; record the selected surface, returned audio track, sender/receiver counters, and audible result because the browser owns the picker and may still return video only. Then switch the 64/128/256 kbps ceilings across direct, browser-relay, and SFU paths, create a new edge, and switch source while checking route continuity and A/V synchronization. Do not infer fidelity or room-wide atomic convergence from configuration alone. 3. **Redesign the Host invitation controls.** Replace the current raw-link-heavy block with a compact copy-first layout while preserving the accepted copy-link, copy-room-code, code-entry policy, rotate, and revoke actions. Keep the credential out of logs and request URLs; changing the copied credential length is blocked on the explicit product decision below. 4. **Diagnose desktop Host background/minimized performance.** On the same machine, dynamic scene, direct Viewer, browser, and fresh share, compare foreground, occluded, minimized, and hidden states while recording the actual negotiated codec. Correlate capture settings/FPS, frames captured/encoded/sent/decoded, bitrate, `qualityLimitationReason`, encode time, browser/game CPU and GPU, and the existing local-preview pause boundary. Treat browser scheduling/throttling and codec effects as hypotheses until measured. Do not spoof page activity, add keepalive timers, or misuse Wake Lock; if current Chrome/Edge cannot preserve the accepted Host behavior through standard Web APIs, record that capability boundary before considering the packaged/native Host. @@ -16,7 +16,7 @@ Only items in **Now** are executable after their stated decision gate. A branch These items are real product work, ordered after the current physical-media, real-network, and product-decision gates; they are not permission to resume an old branch wholesale. -1. **Browser VP8 hardware-acceleration evidence.** After the fixed-v11 source and physical codec gate, measure supported Chrome/Edge platform combinations under real game load using actual negotiated codec, encoder implementation, power-efficient status, encode time, frame rate, and CPU/GPU attribution. Capability advertisement alone is not proof. Do not add another codec, a custom encoder, GPU-selection workaround, codec ladder, or Native helper without a new accepted decision. +1. **Browser VP8 hardware-acceleration evidence.** After the v11 physical codec gate, measure supported Chrome/Edge platform combinations under real game load using actual negotiated codec, encoder implementation, power-efficient status, encode time, frame rate, and CPU/GPU attribution. Capability advertisement alone is not proof. Do not add another codec, a custom encoder, GPU-selection workaround, codec ladder, or Native helper without a new accepted decision. 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. **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. 4. **Public-server one-click deployment package.** After every current functional and real-network item is settled, package the exact application, STUN/SFU, reverse proxy, secrets, health checks and rollback flow for a user-owned public server. Require real domain/TLS/firewall/capacity inputs and never ship credentials or call a partial deployment ready. diff --git a/docs/verification-status.md b/docs/verification-status.md index 2262cfa..7561a51 100644 --- a/docs/verification-status.md +++ b/docs/verification-status.md @@ -19,25 +19,26 @@ Capacity and routing entries below describe the exact tested source or release o ## Retained Functional Evidence +- Exact v11 source implementation `f5a295c52e0ac7d18e5a7949217861c7aa74e9c9` passed TypeScript typecheck, all 605 Web tests in 45 files, client and server production builds, the 254-test SFU gate in 10 files, and the access/privacy gate with explicit Chrome. This validates source structure, strict-wire behavior, fixed-VP8 path configuration, build output, and the covered Browser gate only. It is not deployed and provides no physical direct, browser-relay, or SFU codec evidence. - Exact v10 runtime source `fdd5a4a529ff297f41c05ea3388bf484d76afe8f` passed repository hygiene, TypeScript typecheck, client and server production builds, all 610 Web tests in 45 files, the 257-test SFU admission gate, the access/privacy Browser gate, and the production-dependency audit with zero vulnerabilities. Its one-Host/20-Viewer Chrome 151 direct-loopback report passed all seven assertions: all Viewers decoded, the selected VP8 settings reached every participant, Host and relay media edges stayed within cap `2`, no orphan SFU publication appeared, and all four current-child timing distributions contained 20 values. The report SHA-256 is `802CBB7632E9AEA3C39FE831A7F7880D24140B2E83942CE0DFDA05DE4B408EED`. This validates the v10 source boundary, not H.264 quality, hardware attribution, physical capture, public-network behavior, or SFU packet flow. - 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, and leaves were clean. 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, diagnostic-only, and closed for stale or ambiguous 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). -- Fresh Chrome 151 tab-capture probes identified two separate Browser boundaries. Removing video `contentHint = "motion"` changed VP8 from 14.93 fps at 428x208 to 29.73 fps at 1904x928 under the same 5 Mbps balanced setup. No-hint AMD H.264 remained about 14--16 fps with hundreds of outer rate-limiter drops, while the same MFT reached 29.93 fps under diagnostic Desktop SW BRC; OpenH264 was slower. The page cannot enable that Chromium field trial or select an adapter/MFT. No-hint VP8 used libvpx software and held about 30 fps in one- and two-sender loopback on the test machine, but the process CPU totals include capture and local decode and are not real-game or weaker-device evidence. This evidence selects fixed VP8 for the Browser contract; current source leaves the video hint unset, while production still sets `motion` and the v11 codec cleanup remains pending implementation. See [realtime quality adaptation](./research/realtime-quality-adaptation.md), [Native H.264](./research/native-h264-hardware-decision.md), and [Native shared encode](./research/native-shared-encode-sender.md). +- Fresh Chrome 151 tab-capture probes identified two separate Browser boundaries. Removing video `contentHint = "motion"` changed VP8 from 14.93 fps at 428x208 to 29.73 fps at 1904x928 under the same 5 Mbps balanced setup. No-hint AMD H.264 remained about 14--16 fps with hundreds of outer rate-limiter drops, while the same MFT reached 29.93 fps under diagnostic Desktop SW BRC; OpenH264 was slower. The page cannot enable that Chromium field trial or select an adapter/MFT. No-hint VP8 used libvpx software and held about 30 fps in one- and two-sender loopback on the test machine, but the process CPU totals include capture and local decode and are not real-game or weaker-device evidence. This evidence selects fixed VP8 for the Browser contract; current source implements that decision, while production still sets `motion` and exposes the v10 selector. See [realtime quality adaptation](./research/realtime-quality-adaptation.md), [Native H.264](./research/native-h264-hardware-decision.md), and [Native shared encode](./research/native-shared-encode-sender.md). - Native Windows 11 process audio is source-only and default-off. A retained run isolated the target by about 4018x and delivered 495 Opus packets to one Viewer; package download, game sync, Windows 10, and other routes remain open. See [ADR-0008](./adr/0008-window-scoped-audio-capture.md). ## Open Proof Boundaries -- Routing: exact v10 local direct loopback covers admission-20 initial ingress and exact-candidate first-frame commit timing. Still verify rollback, direct-stage exhaustion and SFU admission, relay-ingress reparent with subtree retention, disconnect/effective-capacity drain, pause/resume, 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; a non-paused decoded-frame stall may invalidate only that exact child edge. +- Routing: exact v10 local direct loopback covers admission-20 initial ingress and exact-candidate first-frame commit timing for that source. The v11 fixed-VP8 source still needs physical direct, browser-relay, and SFU codec verification, together with rollback, direct-stage exhaustion and SFU admission, relay-ingress reparent with subtree retention, disconnect/effective-capacity drain, pause/resume, 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; a non-paused decoded-frame stall may invalidate only that exact child edge. - 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: v10 source and production expose the authenticated `1/2/3` endpoint-cap boundary, and local loopback evidence covers 20 Viewers at cap `2`. CPU/GPU/upload and heterogeneous-network measurements remain diagnostics, not authority to change the contract. -- Room scale: v10 source and production admit 20 Viewers plus one Host, and the exact v10 local Browser convergence gate covers that bound on direct loopback. A real public-network 1:20 session, quality, and sustained resource matrix remain open. +- Relay resources: current source and v10 production expose the authenticated `1/2/3` endpoint-cap boundary, and retained v10 local loopback evidence covers 20 Viewers at cap `2`. CPU/GPU/upload and heterogeneous-network measurements remain diagnostics, not authority to change the contract. +- Room scale: current source and production admit 20 Viewers plus one Host, and the retained v10 local Browser convergence gate covers that bound on direct loopback. A real public-network 1:20 session, quality, and sustained resource matrix remain open. - SFU: production uses one Host publication with exact Viewer subscriptions and no fixed root-count or room-wide lease rule. Real LiveKit lifecycle/JWT replay, shaped packet-flow, BWE downshift/recovery, resource use, and SFU-fed first-child evidence remain open. 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 v10 Viewer stage, local stats/export plumbing, identity-bound relayed-detail retention, export freshness guards, and on-demand Host route snapshot are deployed. 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. All fields diagnose and have no recovery authority; they do not by themselves prove hardware encode, synchronization quality, or route quality. - Mobile: Android/iOS remain Viewer-only. Autoplay, rotation, iOS lock-screen/page reclamation, background reconnection, and network changes need device evidence. AirPlay/system mirroring is Viewer-local output, not a portable in-app WebRTC output contract. - Native: ADR-0006 has one-Viewer evidence only. Viewer2/FIFO, hardware diversity, endurance, downloaded-package/public-host, game A/V, and browser diversity remain open. -- Access and operations: exact v10 source passed the access/privacy Browser gate, and production passed atomic v10 cutover/postflight plus stale-v9 rejection before authority. Restart-wide room loss, password-profile creation, grant/code orthogonality, rotate/revoke, memory-only runtime, and exact current journal/nginx sentinel checks retain their focused evidence. Headful same-browser preference replay and the isolated VM/IP clean-port matrix remain open; shared-IP smoke cannot approve them. +- Access and operations: exact v11 source passed the access/privacy gate with explicit Chrome. Production passed atomic v10 cutover/postflight plus stale-v9 rejection before authority. Restart-wide room loss, password-profile creation, grant/code orthogonality, rotate/revoke, memory-only runtime, and exact current journal/nginx sentinel checks retain their focused evidence. Headful same-browser preference replay and the isolated VM/IP clean-port matrix remain open; shared-IP smoke cannot approve them. ## Evidence Rules diff --git a/docs/方案设计.md b/docs/方案设计.md index 2dcf020..651cf9e 100644 --- a/docs/方案设计.md +++ b/docs/方案设计.md @@ -2,7 +2,7 @@ ## 2026-08-18 14:45 -状态:已接受 Browser display video 不设置 `contentHint`、audio 保留 `music`,且 Browser 唯一视频媒体 codec 为 VP8。下一原子 Browser 合同是严格 `screener-v11`,不含 codec selector、quality-state/wire 字段或分享生命周期 codec 分支;current source 与 production 仍是 `screener-v10`,production 还设置视频 `motion`。Pause/Resume 继续由当前 Host session 和 `shareGeneration` 约束。精确 source/deployed behavior 只由 status 与 deployment 文档记录。 +状态:current source 精确 `f5a295c` 使用严格单一 `screener-v11`;Browser display video 不设置 `contentHint`、audio 保留 `music`,唯一视频媒体 codec 为 VP8,UI、quality state/wire 和分享生命周期均没有 codec 分支。Production 精确 `2726edde9b87f31fd76e749de47972ef817a9bd5`、release `2726edd`,仍使用 `screener-v10`、设置 video `contentHint = "motion"` 并保留 pre-share codec selector;`screener-v11` 尚未部署。Pause/Resume 继续由当前 Host session 和 `shareGeneration` 约束。 ## 目标与边界 @@ -160,7 +160,7 @@ current 的唯一 wire 是 `screener-v11`,不做版本协商、旧 parser、 每次 `setParameters()` 都必须从当次 `getParameters()` 派生更新,然后读回 requested/applied `maxBitrate`、`maxFramerate`、`scaleResolutionDownBy` 和 degradation preference。浏览器负责具体降级,实际结果由 stats 观测;拒绝或浏览器改写必须进入可见状态,不能只写 `console.warn`。 -接受的 `screener-v11` Web 视频固定使用 `VP8`。P2P 与 browser relay 在首次 offer 前只保留 VP8 media capabilities 及 RTX/RED/FEC repair capabilities;无法应用该约束时明确失败,不静默协商另一媒体 codec。SFU publication 显式使用 VP8 且关闭 backup codec。UI、quality state/wire 和分享生命周期均没有 codec 分支;实际 outbound codec/profile、encoder implementation 与 stats 是只读结果真相。Viewer answer 的 Opus stereo receive preference 是当前唯一应用 SDP 变换边界。 +Current `screener-v11` Web 视频固定使用 `VP8`。P2P 与 browser relay 在首次 offer 前只保留 VP8 media capabilities 及 RTX/RED/FEC repair capabilities;无法应用该约束时明确失败,不静默协商另一媒体 codec。SFU publication 显式使用 VP8 且关闭 backup codec。UI、quality state/wire 和分享生命周期均没有 codec 分支;实际 outbound codec/profile、encoder implementation 与 stats 是只读结果真相。Viewer answer 的 Opus stereo receive preference 是当前唯一应用 SDP 变换边界。 Web display-audio 请求显式关闭 `echoCancellation`、`noiseSuppression`、`autoGainControl` 和 `voiceIsolation`,并以 `channelCount: { ideal: 2 }` 偏好双声道;这是当前 Chrome/Edge Host 基线的实现契约,用于避开网页 `getDisplayMedia()` 默认的语音处理和单声道 APM 候选,不宣称跨浏览器保证,也不固定采样率。所有值都是非强制 post-selection preference;不使用 `exact`、`min` 或 `advanced`。若 `getAudioTracks()` 为空,分享者界面必须显示“当前来源没有可共享音频”。Web 端同时传入 `windowAudio: "window"` 与 `systemAudio: "include"`:窗口选项请求该窗口/应用音频,整个屏幕选项允许用户勾选系统音频;标签页使用浏览器自身的标签页音频选择。浏览器可以忽略这些约束或 picker hints,且没有对应的标准来源类型读回,因此 UI 不额外推断或标注来源。系统音频由用户显式选择,可能包含语音或通知;video-only 始终可用。 @@ -270,7 +270,7 @@ media-proof 和 bounded-recovery 不变量的 scoped code 与 tests。 每两秒在本地采集一次 `getStats()`。首版不上传原始统计。折叠详情可在产生该连接的本机显示 selected local/remote candidate 的 `address`/`port`,但浏览器未暴露时保持未知;地址不得进入信令、Viewer C、日志、诊断导出、持久化或路由/质量决策。在 peer 边中它只是当前连接端点,在 SFU 边中通常是 SFU 端点,不能标成参与者的权威公网 IP。 -current `screener-v10` 在 authenticated Host 点击下载诊断时发送一次 `request-route-diagnostic`;服务端当场返回严格 Host-only 的 `route-diagnostic-snapshot`,不连续推送。每个 current child 只保留 latest demand timestamp、operation/candidate start、first-frame/final outcome;新的 route demand 覆盖该 child 的旧 record,confirmed departure 与 room delete 立即删除,且不增加 timer、事件环或第二张 graph。`queueWaitMs` 只从同一个 current demand 到其 room-serial operation start计算;没有权威 demand timestamp 就是 `null`。Serializer 为本次导出分配 snapshot-local opaque ordinal,用它表达 current parent/SFU 关系、effective capacity、child count、current operation reason/stage/cursor/candidate count与相对 timing;`finalRoute` 只允许 `direct | sfu | waiting | failed`,`rejectionBucket` 只允许 `none | stale | endpoint-capacity | sfu-admission | candidate-failed | first-frame-timeout | operation-deadline | aborted`。Ordinal 不是身份或稳定 ID。Snapshot 不包含 room code、display name、真实 peer/session/connection/generation、地址、URL、SDP、token、raw error或 planner 曾过滤的 parent,不形成路由输入或前台第二套状态。Viewer 的 schema v2 只携带自身 stage、粗粒度 revision、typed failure、signal/Host state、route kind 与 current-frame proof,即使 connection list为空也可下载;未鉴权 `ROOM_ACCESS_DENIED` 分支只含 stage/code,不含 Host、route、revision或timing。 +current `screener-v11` 在 authenticated Host 点击下载诊断时发送一次 `request-route-diagnostic`;服务端当场返回严格 Host-only 的 `route-diagnostic-snapshot`,不连续推送。每个 current child 只保留 latest demand timestamp、operation/candidate start、first-frame/final outcome;新的 route demand 覆盖该 child 的旧 record,confirmed departure 与 room delete 立即删除,且不增加 timer、事件环或第二张 graph。`queueWaitMs` 只从同一个 current demand 到其 room-serial operation start计算;没有权威 demand timestamp 就是 `null`。Serializer 为本次导出分配 snapshot-local opaque ordinal,用它表达 current parent/SFU 关系、effective capacity、child count、current operation reason/stage/cursor/candidate count与相对 timing;`finalRoute` 只允许 `direct | sfu | waiting | failed`,`rejectionBucket` 只允许 `none | stale | endpoint-capacity | sfu-admission | candidate-failed | first-frame-timeout | operation-deadline | aborted`。Ordinal 不是身份或稳定 ID。Snapshot 不包含 room code、display name、真实 peer/session/connection/generation、地址、URL、SDP、token、raw error或 planner 曾过滤的 parent,不形成路由输入或前台第二套状态。Viewer 的 schema v2 只携带自身 stage、粗粒度 revision、typed failure、signal/Host state、route kind 与 current-frame proof,即使 connection list为空也可下载;未鉴权 `ROOM_ACCESS_DENIED` 分支只含 stage/code,不含 Host、route、revision或timing。 Host 与 relay Viewer 复用同一个纯 presentation reducer 保存远端 `ViewerQualityEvidence`。代际 identity 是 exact route identity(room/share、viewer/parent、assignment/connection、route revision 和当前可用的 media-binding generation,及适用时 publication generation);只有同 identity 且 sequence 严格递增才可承接旧字段,其他输入从新 evidence 重建。每个非空 metric 保存自己的本地观测时间并在五秒边界清空,页面 timer 总是指向最早边界;整块详情不因某个采样缺字段而卸载。`new`/`connecting`/`disconnected` 保留同 identity shell 但立即标为非 fresh,`failed`/`closed` 或 route identity 变化清空。任何依赖当前状态的消费者只读取 fresh presentation;该层不新增 wire 字段或服务端 route authority。 @@ -336,7 +336,7 @@ Token-free SFU standby prewarm 保持可选且不创建 participant、publicatio - RoomStore 的四位空闲码随机分配/释放、活动分享免过期、dormant lease/续租、Host token/Viewer grant 摘要验证、`open/password/disabled` 正交 policy、grant 到期/跨房拒绝、rotate/revoke 强撤销、Viewer 上限和超额拒绝; - 进程重启后 room state 全空、旧 Host/grant/password fail closed、释放号码复用时旧 grant 仍失败;`ROOM_LEASE_SECONDS` 的默认/边界与 `MAX_ROOMS <= 9000` 校验,已删除的 `ROOM_DATABASE_PATH`/`ROOM_TTL_SECONDS` fail-fast; - STUN UDP URL 严格校验、生产 STUN 必需、LiveKit tuple 完整性/TTL/secret 独立性、当前 route/session/revision/connection generation guard,以及 ordinary peer、未授权房间和 Native 的 STUN-only isolation;LiveKit `sfu-config` 保持独立边界; -- 接受的 source contract 使用单一 `screener-v11` 信令 literal、严格 JSON schema、方向与房间授权校验、payload 上限和 client-mismatch 刷新终态;分享状态由 `shareGeneration`-fenced paused boolean 表达,访问失败使用 `ROOM_ACCESS_DENIED`,Viewer route failure 为 typed terminal,Host 诊断按需返回脱敏 snapshot。`qualityProfileIdSchema` 保持三档,`qualityResolutionSchema` 包含 `480p`,`DEFAULT_QUALITY_SETTINGS` 为 1080p30,quality schema 严格拒绝 codec 字段; +- Current source contract 使用单一 `screener-v11` 信令 literal、严格 JSON schema、方向与房间授权校验、payload 上限和 client-mismatch 刷新终态;分享状态由 `shareGeneration`-fenced paused boolean 表达,访问失败使用 `ROOM_ACCESS_DENIED`,Viewer route failure 为 typed terminal,Host 诊断按需返回脱敏 snapshot。`qualityProfileIdSchema` 保持三档,`qualityResolutionSchema` 包含 `480p`,`DEFAULT_QUALITY_SETTINGS` 为 1080p30,quality schema 严格拒绝 codec 字段; - 质量协议的 host 授权、严格字段与数值范围、last-wins、当前/未来 relay、已配置 SFU 和普通 P2P wire 兼容;sender 的四字段 requested/applied 读回、拒绝与持续受限提示;screen audio SDP helper 覆盖 CRLF、existing/missing fmtp、unknown key preservation、幂等、payload number、rejected/non-audio,以及 empty/no-Opus/ambiguous/parser 异常原对象 fallback,`ViewerPeer` 覆盖 initial/restart/rebuild 时同一结果的 local/signaling 一致性,SFU publisher 精确断言 high-quality stereo/forceStereo/DTX 且不覆盖 RED; - HTTP/WS 集成:nginx per-source site-access `limit_req` 与统一错误不泄露 secret,应用不建立 IP limiter 状态;Viewer 可在 Origin/容量门下 upgrade;Host 首条鉴权同时要求 upgrade-captured site access 与 Host token,Viewer 要么持 exact-room grant,要么先有 site access 再按 `open/password/disabled`。覆盖原子创建 profile、同浏览器重建偏好、fragment/sessionStorage/replaceState、无 site access 的 code-only 统一拒绝、unknown/expired/disabled/wrong-or-absent-password/full code-only 使用完全相同的 `ROOM_ACCESS_DENIED` code/文案/close、grant 与 Host 的独立错误、raw grant/密码不进入 URL/日志/服务端持久状态,以及 rotate/revoke 后 grace/route 清理、旧 Viewer/上游媒体边关闭和 reconnect 拒绝; - 客户端策略与 stats 解析:会话替换不重连,ordinary ICE 与 LiveKit protocol 分离; @@ -359,7 +359,7 @@ Token-free SFU standby prewarm 保持可选且不创建 participant、publicatio ## 当前交付边界 -- 接受的下一合同使用单一 `screener-v11` wire,Browser 固定 VP8 且 video 不设置 `contentHint`;codec selector、quality-state/wire 字段与分享生命周期 codec 分支不存在。Current source 与 production 仍是 `screener-v10`,production 还设置 video `motion`;实现与部署分别原子推进。 +- Current source 精确 `f5a295c` 使用严格单一 `screener-v11` wire,Browser 固定 VP8 且 video 不设置 `contentHint`;codec selector、quality-state/wire 字段与分享生命周期 codec 分支不存在。Production 精确 `2726edde9b87f31fd76e749de47972ef817a9bd5`、release `2726edd`,仍使用 `screener-v10`、设置 video `motion` 并保留 pre-share codec selector;`screener-v11` 尚未部署。 - Pause/Resume 由当前 Host session 和 `shareGeneration` 约束。Host 后台性能和 VP8 hardware acceleration 分别按受控根因证据诊断;标准 ICE/SFU 按真实异构网络验收。 - 当前发布面只包含 Web Host、Viewer 和 browser relay。Native sender、capture helper、shared-encode executable 与两个分发包仍由各自后续决策和物理证据驱动,不属于当前 Browser release。 diff --git a/scripts/required-project-paths.txt b/scripts/required-project-paths.txt index 2cf41d6..1cd9248 100644 --- a/scripts/required-project-paths.txt +++ b/scripts/required-project-paths.txt @@ -11,6 +11,7 @@ package-lock.json tsconfig.json .codex/config.toml .codex/README.md +.agents/skills/stop-that-shit/SKILL.md .githooks/pre-commit .github/pull_request_template.md .github/workflows/repository-hygiene.yml