Files
yovision/docs/tasks/T-014.md
QiuSW b9e21a95d1
Harness governance / validate (push) Has been cancelled
Harness governance / validate (pull_request) Has been cancelled
docs(task): record T-014 16-stream baseline
2026-08-10 23:16:12 +08:00

13 KiB
Raw Permalink Blame History

id, title, phase, deps, status, created, issue, context_ref, claim_branch, work_branch, write_paths
id title phase deps status created issue context_ref claim_branch work_branch write_paths
T-014 建立 Sense 本地 16 路批量收敛与容量基线 2
T-012
DONE 2026-08-08 47 8ebb8ced49 claims/T-014 agent/codex/T-014
docs/tasks/T-014.md
Sense/README.md
Sense/scripts/t014-capacity.ps1
docs/00-ai-start-here.md
docs/03-tech-stack.md
docs/04-architecture.md
docs/06-tasks.md
docs/current-state.md
docs/research/sense-16-stream-capacity.md
tests/test_sense_capacity_contract.py

问题 / 背景

T-006 已证明一台准入实机与四条独立合成源可以完成五路实验室闭环,T-011/T-012 已实现 PostgreSQL Control API、最多 128 项批量期望态、多实例 fencing、孤儿安全闸和低基数指标;但 M2 的默认 16 路仍只有产品配额和单元测试,没有通过真实 HTTP 控制面完成 16 路创建、批量启停、MediaMTX 收敛、局部故障恢复和资源观测。项目当前没有客户网络环境,WireGuard T-013 暂缓,不能让该外部依赖阻塞本地软件容量基线。

本任务建立可重复的 Windows 本地 16 路实验室基准。它验证当前机器、固定软件版本和低码率无人物合成负载下的 Sense/PostgreSQL/MediaMTX 控制面与媒体拉流能力,不代表 16 台真实摄像头、客户网络、存储、AI/GPU 或生产 SLA。

关联需求与交互(如适用)

  • 用户故事:US-001、US-002、US-008、US-009;验证默认 16 路站点的批量接入与运维收敛基础。
  • 交互清单:IX-003、IX-004、IX-015、IX-016 的后端容量证据;不修改已确认 HTML 原型。
  • 相关页面 / 路由:复用冻结的 7 个 /api/v1 Control API endpoint、/metrics、MediaMTX v3 API;不增加公共接口。

方案

  1. 新增 Sense/scripts/t014-capacity.ps1 一键基准:校验冻结的 PostgreSQL 17.10、MediaMTX v1.19.3、FFmpeg 与 Go,使用随机回环端口和系统临时目录启动隔离 PostgreSQL、源 MediaMTX、生产 MediaMTX 与 Sense。migration 只读取并重放现有 001~011,不修改或连接本机已有 D:\pgsql17\data/5432。
  2. 先用 FFmpeg 生成 640×360、10 fps、H.264、无音频、无人物的短循环媒体夹具,再启动 16 个独立 FFmpeg -c copy RTSP publisher,每路有独立进程与 Path,可单独停止/恢复。预编码发布避免把 16 路软件编码开销计入 Sense/MediaMTX 基线;不把同一 publisher fan-out 冒充独立源。
  3. 在临时 PostgreSQL 中建立固定实验室 Tenant/Site/Area,Site 配额精确为 16;运行时生成 Control API opaque token、SHA-256 注册表和 cursor key,文件只存在于临时目录。通过真实 HTTP API 创建 16 个 disabled 视频设备、批量启用并收敛后,验证第 17 个 enabled 同站点设备稳定返回 quota_exceeded 且不写入台账;disabled 台账项不冒充已占用通道。
  4. 使用真实 devices:batchDesiredState 和每台设备最新 ETag 执行 16 路批量启用、批量停用、再次启用;每次要求 operation 的 16 个结果全部成功。分别验证生产 MediaMTX 配置/运行 Path 为 16、0、16,设备最终状态与 generation/observed generation 收敛,unconverged=0。
  5. 在再次启用后同时停止固定四个 publisher,要求能观察到局部离线/未收敛且其余路径继续在线;恢复四个独立进程后自动回到 16 路在线和 unconverged=0。不得通过改数据库、人工编辑 MediaMTX 配置或重建进程集合掩盖失败。
  6. 正式稳定观察默认 30 分钟、每 10 秒采样。记录 Sense 与生产 MediaMTX 的归一化 CPU、working set、private bytes、handle 峰值,PostgreSQL连接峰值,以及 MediaMTX aggregate inbound bytes/吞吐、在线 Path、Sense 低基数指标和未收敛数。功能正确性有硬门禁;机器相关资源值只记录,不设置伪通用阈值。
  7. 脚本输出不含 token、DSN、端口清单、Path/source URI 或客户信息的 JSON 摘要;支持显式输出到仓库外路径。失败不输出成功结论,finally 停止全部叶子进程、停止临时 PostgreSQL并校验清理路径;可选调试短窗口必须标记 formal_eligible=false,不得作为正式验收。
  8. 将正式运行的硬件/软件版本、命令、功能时间、观察样本、资源统计、失败记录、限制和结论写入 docs/research/sense-16-stream-capacity.md,同步 README、架构、路线图和当前状态。增加静态契约测试,锁定 16/17/128/129 语义、无秘密输出、临时目录防护、真实批量 API、独立 publisher 和正式窗口规则。

不可变约束

  • 阈值 / 数值边界:正式源数精确为 16;Site 默认配额 16、允许范围 1~128,已有 16 路 enabled 时第 17 路 enabled 必须拒绝,129 仍非法;批量 API 上限保持 128。正式观察不少于 30 分钟、采样周期 10 秒;局部故障固定 4 路且不得影响其余 12 路。短窗口只能 smoke。
  • 判定式 / 状态转换:16 个设备先 disabled 创建,随后 16 enabled → 16 disabled → 16 enabled;每轮批量结果必须全部成功。启用完成必须配置 Path=16、运行在线 Path=16、unconverged=0;停用完成必须配置 Path=0、设备 offline 且各自 observed generation 追平。四路故障恢复后必须再次满足 16 路在线和 unconverged=0。
  • 安全边界:只绑定随机回环端口;运行时 token/cursor key/DSN/临时路径不进入 Git、普通日志或结果摘要。脚本不得读取 ip_camera.env,不得访问客户网络或现有 PostgreSQL data/service;递归清理前必须验证目标位于系统临时目录且名称含 T-014 随机前缀。
  • 既有契约:不修改 Control OpenAPI v1、审计 v1/v2、MediaMTX 生成代码或数据库 migration;不把 16 写入业务数组/协议硬上限。T-001/T-006 的实机结论、T-007 真实五上游门禁与未来 T-013 WireGuard 均保持独立。

验收要点

  • 任务相关验证:先以短窗口运行脚本 smoke,再执行默认不少于 30 分钟的正式 16 路基准;验证 16 个独立 publisher、第 17 路 enabled 配额拒绝、三轮批量状态、16/0/16 Path、四路故障隔离/恢复、最终 unconverged=0 和资源摘要。python -m unittest discover -s tests -p "test_sense_capacity_contract.py" 锁定脚本安全/语义。
  • 完整门禁:./init.ps1、三条 Python 治理命令、go -C Sense test ./...、go -C Sense vet ./...、go -C Sense build ./...、./scripts/test_postgres.ps1 -PgRoot D:\pgsql17 和 git diff --check 全部通过;本任务不修改 Go 业务代码,但仍回归全部 Sense 包和 PostgreSQL v5。
  • 人工 / 设备验收:不需要摄像头、GPU、客户网络或客户数据。任务所有者核对 30 分钟原始 JSON 摘要、进程独立性和报告;真实摄像头/网络验收仍由 T-007/T-013 完成。
  • 构建产物:Sense/scripts/t014-capacity.ps1、docs/research/sense-16-stream-capacity.md、静态契约测试与同步文档;临时二进制、媒体、数据库、凭据和日志运行后删除,不提交。

边界(不改什么)

不实现或验证 WireGuard/T-013、客户网络、真实 16 摄像头、录像、下游 reader、AI 解码/推理、GPU、Bell UI/服务、Outbox relay、告警规则、跨 MediaMTX 分片或 64/128 路容量;不把本机资源样本转换为最低硬件规格或 SLA。本任务不解除 T-007,失败样本不得从报告中删除。

协作约束

  • 责任 Agent:由 dispatcher 分配。
  • 唯一写入者:同责任 Agent。
  • 委派:默认不启用。
  • Gitea:任务规格先进入默认分支,再创建唯一 Issue 并回填编号;领取时记录 context_ref、claim / 工作分支和全部允许写路径。

任何新增写路径先检查与其他活跃任务是否重叠;同一时刻只有一个 Agent 修改本任务的 write_paths。T-007 虽为 waiting,但写路径包含 Sense/;T-014 活跃期间不得恢复 T-007。

执行记录

2026-08-10 正式 16 路基线

  • 在提交 d029067aa750ad75a2d79ef8e6c51b6bad55096d 执行 ./Sense/scripts/t014-capacity.ps1 -PgRoot D:\pgsql17 -OutputPath (Join-Path $env:TEMP 'yovision-t014-formal-final.json'),成功输出 formal_eligible=true。固定环境为 Go 1.26.5、PostgreSQL 17.10、MediaMTX v1.19.3、FFmpeg 8.1.2;主机为 24 logical processors / 15.78 GiB。
  • 16 个独立 publisher 在 7.6 s 就绪;三轮 16 项 batch 均 succeeded,请求分别为 0.041 s / 0.015 s / 0.046 s,收敛分别为 3.1 s / 1.0 s / 3.1 s,配置 Path 为 16 → 0 → 16。16 路 enabled 后第 17 路 enabled 返回 quota_exceeded。
  • 固定停止第 5~8 路后 1.0 s 检测到精确 4 路受影响,其余 12 路在线;恢复 5.1 s 后回到 16 路在线。稳定窗口 1800.1 s、10 秒绝对节拍、180 个样本,最大/最终 unconverged=0,聚合入站 15.443 Mbps,帧错误 0。
  • 资源记录:Sense CPU 总计 5.594 s、working set 峰值 69.99 MiB、private 峰值 57.58 MiB、handle 峰值 228;生产 MediaMTX 分别为 26.812 s / 45.27 MiB / 79.23 MiB / 295;PostgreSQL 连接峰值 3,数据库 8.90 MiB。详细边界与失败记录见 docs/research/sense-16-stream-capacity.md。
  • 正式退出后复查 T-014 session、FFmpeg、MediaMTX 和 Sense 数量均为 0;结果不含 token、DSN、端口、设备 ID、Path/source URI 或客户信息。本机现有 5432 listener 未被停止或修改。

2026-08-10 完整门禁

  • PowerShell parser 与 python -m unittest discover -s tests -p "test_sense_capacity_contract.py" -v 通过,T-014 静态契约 6/6 通过。
  • ./init.ps1 通过:58 个 Python 测试成功,MediaMTX/Control API 生成漂移检查、全部 Sense Go 包测试、go vet 与 go build 均成功。
  • ./scripts/test_postgres.ps1 -PgRoot D:\pgsql17 通过:PostgreSQL 17.10 隔离集群重放 001~011,权限断言与 yovision/sense/internal/store 真实 PostgreSQL 测试成功,临时端口和 PGDATA 已清理。
  • python scripts/validate_agent_context.py、python -m unittest discover -s tests -p "test_*.py"(58 项)、python scripts/validate_harness_governance.py 与 git diff --check 均通过。生成文件只有现有 LF→CRLF 提示,没有内容漂移或任务范围外修改。

2026-08-08~2026-08-10 基准工具失败与修正

  • 正式结论没有拼接失败样本。依次修复并回归:MediaMTX ZIP/EXE 双指纹、disabled 不占配额、problem+json byte array 解码、pg_ctl start 管道句柄继承、Windows EXE 文件锁与进程句柄释放、固定 sleep 导致 30 分钟不足 180 样本、根目录 Go launcher 与 Sense 1.26.5 工具链口径不一致,以及首轮 batch 复用创建 ETag 的调和竞速。
  • 中断或失败运行均未输出正式成功 JSON;已核验并停止临时 PostgreSQL,清除精确的单次 session。最终脚本按绝对 10 秒节拍取得 180 个样本,三轮 batch 提交前都读取最新 ETag,清理使用共享截止时间并释放异步输出/进程句柄。

2026-08-08 一分钟端到端 smoke

  • ./Sense/scripts/t014-capacity.ps1 -PgRoot D:\pgsql17 -ObservationMinutes 1 通过并输出 formal_eligible=false:16 个独立 publisher 全部在线,三轮 16 项 batch 均 succeeded,配置 Path 为 16 → 0 → 16,第 17 路 enabled 返回 quota_exceeded 且台账仍为 16 项。
  • 首次启用、停用、再次启用分别在 3.1 s、1.0 s、3.1 s 收敛;同时停止四路后 1.0 s 观察到精确四路受影响、其余 12 路在线,恢复 5.2 s。稳定观察 60.8 s/6 次采样,最大与最终 unconverged 均为 0,最终在线 Path 16,aggregate inbound 15.432 Mbps,帧错误 0。
  • 保留三类脚本修正记录:发布 ZIP 与 EXE 需要不同 SHA-256;disabled 台账不消耗视频运行配额,故第 17 路门禁必须在 16 路 enabled 后验证;PowerShell 对 application/problem+json 返回 byte array,需显式 UTF-8 解码后校验稳定 code。每次失败均停止并清理临时 PostgreSQL/进程,未拼接成功片段。

2026-08-08 领取任务

  • dispatcher ila 将 Issue #47 分配给 codex;context_ref 为 8ebb8ced492c614106e766192c59b7f13fb4ad0f,claim 为 claims/T-014,工作分支为 agent/codex/T-014。
  • 已读回 Issue status/doing、assignee、dispatcher 发布的完整 CLAIM 与两个分支 SHA;接受 frontmatter 全部写路径。T-007 继续 waiting,本任务期间不恢复,当前无活跃写路径冲突。

2026-08-08 Gitea 映射

  • 任务规格通过 PR #46 合入默认分支后创建唯一主 Issue #47;本次只回填双向映射,映射合入并读回前不领取任务。

2026-08-08 任务定义

  • 项目负责人确认客户尚未提供网络环境,WireGuard T-013 后置;本任务先建立不依赖客户网络的本地 16 路软件基线。
  • 选择 PostgreSQL v5 + 真实 Control API,而不是沿用 SQLite 直接播种,确保实际覆盖 M2 的认证、配额、ETag、批量 operation、调和与 MediaMTX 路径。
  • 选择 16 个独立、预编码 -c copy 合成 publisher 作为正式可重复负载;T-006 已单独覆盖准入实机,本任务不混入公网摄像头波动,也不把合成结果表述为真实 16 机或生产 SLA。