From ec9ae76a0d6a413d4b4c9646c70267216f6c7ece Mon Sep 17 00:00:00 2001 From: QiuSW <105186638@qq.com> Date: Tue, 4 Aug 2026 14:44:27 +0800 Subject: [PATCH 1/2] docs(tasks): claim T-005 --- docs/tasks/T-005.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/tasks/T-005.md b/docs/tasks/T-005.md index 616fa06..78deac2 100644 --- a/docs/tasks/T-005.md +++ b/docs/tasks/T-005.md @@ -3,12 +3,12 @@ id: T-005 title: 归档原型评审原稿并补录评审文档 phase: 0 deps: [T-004] -status: TODO +status: DOING created: 2026-08-04 issue: 10 -context_ref: null -claim_branch: null -work_branch: null +context_ref: 697e652e9b9b884551850583712cdcd875c474b9 +claim_branch: claims/T-005 +work_branch: agent/codex/T-005 write_paths: - docs/tasks/T-005.md - docs/raw/10-Sense原型-功能模块缺口.md @@ -57,6 +57,11 @@ T-004 已将 Codex 复核后的 Sense/Bell 评审定稿合入 `main`,但主工 ## 执行记录 +### 2026-08-04 领取 + +- dispatcher `ila` 已在 Issue #10 发布完整 CLAIM;claim 分支与工作分支均从 `697e652e9b9b884551850583712cdcd875c474b9` 创建。 +- Issue #10 已切换为 `status/doing`;本轮仅修改任务文件声明的归档和缺失评审文档路径。 + ### 2026-08-04 任务定义 - 项目负责人确认采用“保留定稿、原稿另行归档、补录缺失评审文档”的方案。 From c7d0ce3ed9ab40fa70ce31671e3ddb258afa3f0b Mon Sep 17 00:00:00 2001 From: QiuSW <105186638@qq.com> Date: Tue, 4 Aug 2026 14:46:12 +0800 Subject: [PATCH 2/2] docs(raw): archive prototype review sources --- docs/raw/10-Sense原型-功能模块缺口.md | 264 ++++++++++++++++ docs/raw/13-架构评审与修订建议.md | 289 ++++++++++++++++++ docs/raw/15-Bell原型-功能模块缺口.md | 182 +++++++++++ .../08-三系统职责划分-评审前快照.md | 187 ++++++++++++ .../09-Sense原型评审-IX草稿-Claude原稿.md | 150 +++++++++ .../11-Sense原型-第二轮缺口-Claude原稿.md | 136 +++++++++ .../12-Sense原型-待办清单-Claude原稿.md | 255 ++++++++++++++++ .../2026-08-04/14-Bell原型评审-Claude原稿.md | 165 ++++++++++ docs/tasks/T-005.md | 9 +- 9 files changed, 1636 insertions(+), 1 deletion(-) create mode 100644 docs/raw/10-Sense原型-功能模块缺口.md create mode 100644 docs/raw/13-架构评审与修订建议.md create mode 100644 docs/raw/15-Bell原型-功能模块缺口.md create mode 100644 docs/raw/archive/2026-08-04/08-三系统职责划分-评审前快照.md create mode 100644 docs/raw/archive/2026-08-04/09-Sense原型评审-IX草稿-Claude原稿.md create mode 100644 docs/raw/archive/2026-08-04/11-Sense原型-第二轮缺口-Claude原稿.md create mode 100644 docs/raw/archive/2026-08-04/12-Sense原型-待办清单-Claude原稿.md create mode 100644 docs/raw/archive/2026-08-04/14-Bell原型评审-Claude原稿.md diff --git a/docs/raw/10-Sense原型-功能模块缺口.md b/docs/raw/10-Sense原型-功能模块缺口.md new file mode 100644 index 0000000..cce331d --- /dev/null +++ b/docs/raw/10-Sense原型-功能模块缺口.md @@ -0,0 +1,264 @@ +# Sense 原型:功能与模块缺口分析 + +> 对标:`docs/02-requirements.md` §3.1/§3.5/§4、`docs/04-architecture.md` §3/§6/§7/§8/§10、`docs/07-user-stories.md` US-001/002/007、`docs/routes.md`、`docs/api.md` §2 +> 基准:`yovision-T-004/docs/design/sense/index.html`(codex,2026-08-04) +> 与《09-Sense原型评审-IX草稿》的区别:09 谈**行为缺口**(某状态没画),本文谈**模块缺口**(整个页面或实体不存在) +> 日期:2026-08-04 + +--- + +## 0. 判定基准 + +Sense 的交付窗口是 M1–M2(架构 §10): + +> M1 只动 Sense,5 路接入骨架与 MediaMTX。 +> M2 仍以 Sense 为主,完成 **16 路开通/停用、对账、多租户投影与隧道**。 + +所以判定标准是 **M2 出口**,不是 M1。原型现在覆盖的是"设备列表 + 详情 + 导入",大致相当于 M1 的一半。 + +### 现有信息架构 + +``` +运行总览 · 实时监控 · 摄像头 · 接入任务 · 系统状态 + └─ 详情:基本信息 / 画面与检测区域 / 流与健康 / 操作记录 +``` + +### 实体链断了两级 + +架构 §8 定义的核心实体是: + +``` +Tenant → Site → Area/Device → StreamBinding/Zone +``` + +原型里 **Tenant 不存在**,**Site 是顶栏一行静态文字**,**Area 退化成添加对话框里的一个下拉**。只有 Device 和 Zone 是真的。 + +--- + +## 1. P0 缺口 —— M2 出口必需,现在完全没有 + +### 1.1 站点管理(模块级缺失) + +顶栏写死「青藤寄宿学校 / 主校区 · 16 / 16 路」,不可切换,没有站点列表。`routes.md` 有 `/sites`(站点列表、配额与状态)。 + +M2 的出口标准里明写"多租户投影",而多站点是它的最小可见形态。 + +| 需要什么 | 依据 | +| --- | --- | +| 站点列表:名称、配额已用/上限、在线率、未收敛数、边缘节点状态 | `routes.md` `/sites` | +| 站点切换器(顶栏),切换后所有列表按站点过滤 | 架构 §3 SaaS-ready 边界 | +| 站点配额的**只读**展示 + 来源标注「由 Bell 持有」 | 架构 §5 第 7 条 | +| 跨站点的设备总览(实施工程师同时开通多个站点) | US-001 | + +### 1.2 对账器运维视图(Sense 的心脏,只有一个数字) + +总览有「待收敛项 **2**」,**点不进去**。架构 §7 用了整节讲对账语义,UI 只暴露了一个计数。 + +`routes.md` 有 `/operations`(设备/流/分片/对账运维,不与业务预警混在同一队列)。 + +| 需要什么 | 依据 | +| --- | --- | +| 未收敛项列表,每项显示**期望态 vs 实际态的具体差异** | 架构 §7「PostgreSQL 是期望态真相源」 | +| 每项的重试次数、当前退避间隔、下次重试时间 | 架构 §7「幂等、指数退避、限制并发」 | +| **孤儿资源列表 + 10% 安全闸触发告警** | 架构 §7「孤儿删除必须有 10% 安全闸和人工可观察指标」 | +| 手动触发单项收敛(总览的"立即对账"是全局的,粒度太粗) | — | +| 收敛持续失败的升级路径:多久算异常、通知谁 | §3.5 运维告警独立 | + +> 这是原型最大的单点缺口。对账器是 Sense 区别于普通 NVR 的**全部理由**,现在在 UI 上等于不存在。 + +### 1.3 待激活设备的处置闭环 + +`02-requirements` §3.1 明确「支持待激活中间态」,添加对话框的按钮也确实写着「保存为待激活」。但: + +- 设备表 5 行假数据里**没有一行是待激活** +- 筛选下拉只有「全部状态 / 异常 / 重连中」,**没有待激活** +- 待激活设备如何激活、如何补凭据、如何丢弃——零流程 + +| 需要什么 | +| --- | +| 待激活作为一级筛选项与独立计数 | +| 待激活 → 激活的校验流程(重新探测 Profiles / 校时 / 配额复核) | +| 批量激活与逐项结果 | +| 长期待激活的过期策略(放着不管会变成配额占用的幽灵) | + +### 1.4 凭据更新与认证失败恢复 + +详情页写「凭据:已安全保存,页面不可见」——处理正确,但**只有读没有写**。 + +M0 验收专门要求记录「认证失败」(`02-requirements` §2),而现场改密码是最高频的运维事件。 + +| 需要什么 | +| --- | +| 单设备「更新凭据」动作(只写不读,不回显任何已存值) | +| 认证失败作为独立的实际态(区别于「离线」——原因不同,处置不同) | +| 批量更新凭据(一批摄像头同时改密是常态) | +| 更新后自动重试接入,结果可见 | + +### 1.5 权限与角色(完全没有) + +`02-requirements` §3.5 定义最小 RBAC 五角色:平台管理员 / 租户管理员 / 站点管理员 / 值班员 / 只读。`routes.md` 有完整的路由守卫要求。 + +原型没有登录、没有当前用户、没有任何权限差异表达。 + +| 需要什么 | +| --- | +| 顶栏当前用户与角色 | +| 只读角色下:添加/停用/删除/更新凭据**不出现**(不是置灰) | +| 越权深链的统一拒绝态(`routes.md`「深链打开无权限或已删除资源时给出统一、安全的反馈」) | +| 站点管理员只能看到自己站点 | + +> 权限不是"以后加的一层"。它决定页面上**有没有**这个按钮,是信息架构问题,必须在原型里枚举。 + +### 1.6 配额服务降级态 + +`api.md` §2 精确定义了这个失败语义: + +> Sense → Bell 读取站点视频配额:失败时**拒绝新增/启用但不影响已有流** + +原型显示「已用 16 / 128」「配额 16 / 128」,但错误态只有一个「边缘节点不可达」。配额服务不可达是**另一种**故障,表现完全不同:视频照常播、列表照常看、只有写操作被拒。 + +| 需要什么 | +| --- | +| 配额不可读时的横幅:说明"当前无法新增或启用设备,已有视频不受影响" | +| 添加/激活按钮在该状态下禁用并说明原因 | +| 与「边缘节点不可达」区分开——后者是读故障,前者是写故障 | + +--- + +## 2. P1 缺口 —— M2 内补齐 + +### 2.1 边缘节点与隧道 + +侧栏底部只有一行 `sense-edge-01 · 在线`。但边缘节点在架构里是独立实体,承担推流、本地环形缓冲、断网续传、WireGuard 隧道。 + +`02-requirements` §3.5:**断网时边缘缓存事件,恢复后补传。** + +| 需要什么 | +| --- | +| 边缘节点列表:版本、在线时长、隧道状态、承载设备数 | +| 本地缓存水位 + 补传进度(断网 2 小时后恢复,用户要看到"正在补传 380 条") | +| 隧道断开时的明确表达:**控制面断了但视频还在推**(这是控制面/数据面分离的核心,UI 不体现等于白设计) | +| 边缘节点升级/重启动作 | + +### 2.2 设备能力档案 + +添加时「测试连接」返回「2 个 Profile,时间漂移 +0.4s」,但这个结果**没有落地成设备的持久属性**。 + +US-007 要求记录:型号、固件、认证方式、Profiles/StreamUri/校时、主子码流、掉线恢复——形成采购白名单。 + +| 需要什么 | +| --- | +| 详情页「设备能力」区:厂商、型号、固件版本、认证方式 | +| Profile 列表(分辨率/帧率/编码),标注当前使用哪个 | +| 能力标记:是否支持校时、**是否支持 ONVIF 事件订阅**(决定它能否作为设备型触发源) | +| 与采购白名单的关联:该型号是否在白名单内 | + +### 2.3 主/子码流切换 + +详情写死「Profile:子码流 704 × 576 · 5 FPS」,没有切换动作。 + +架构 §6:`media_shard.max_streams` 由**码率**决定。码流选择是容量的直接变量,必须可配。切换还会踢掉当前发布者(mediamtx 的硬约束),需要影响范围提示。 + +### 2.4 分片详情与设备迁移 + +总览显示 `media-01 8/32`、`media-02 8/32`,只读。 + +| 需要什么 | +| --- | +| 分片详情:承载设备清单、实际码率、重连历史 | +| 把设备从一个分片迁到另一个(迁移会中断该路,需确认) | +| 单分片故障时的影响范围展示(架构 §6「单分片故障不能扩散到其他分片」) | +| **`media_shard.max_streams` 的 32 需与《04》§6 对齐**——文档写「初始建议 32,可按故障域降为 16」,原型的 32 有据,但需标注它是可配置项而非固定值 | + +### 2.5 批量任务列表与逐项结果 + +「当前任务」是单个卡片,「查看逐项结果」是个死按钮。 + +IX-001 要求:下载模板、上传校验、**逐行错误**、重复序列号、待激活、确认写入。 + +| 需要什么 | +| --- | +| 任务列表(历史任务可查、可重试、可导出错误清单) | +| 逐项结果页:每行的校验结果、失败原因、单行重试 | +| 上传前的本地预校验结果(原型文案已提到,但没有页面) | +| 部分成功的语义:8 路里 5 成功 3 失败,成功的已生效 | + +### 2.6 Sense 运维告警 + +总览有「今日设备告警 3」和「与业务预警分开」的说明——**这个说明写得很好**,但点不进去。 + +`02-requirements` §3.4:业务预警与运维告警使用**不同通道和值班配置**。 + +| 需要什么 | +| --- | +| 运维告警列表(设备离线、时间漂移超阈、收敛失败、分片异常、隧道断开) | +| 静默与通知配置(运维侧的,与 Bell 的业务静默是两套) | +| 明确标注"这些不会推给家属/值班员" | + +--- + +## 3. P2 缺口 —— M3 留出信息架构位置 + +不必现在实现,但导航和详情页要留位,否则 M3 时又是整页重做。 + +| # | 模块 | 依据 | +| --- | --- | --- | +| 1 | **推理绑定视图**:设备 ↔ inference worker 的绑定、worker 注册/心跳/容量、绑定失败态 | `api.md` §2「Worker → 控制面:注册、心跳、容量」;总览已有「推理绑定 16/16」但无下钻 | +| 2 | **pre-roll 切片运维**:切片请求量、失败率、耗时 | 架构 §5 第 3 条「pre-roll 由 Bell 发起、Sense 切片」 | +| 3 | **设备型触发源**:雷达/门磁/按钮/ONVIF 事件订阅的配置与状态 | 《08》§3 边界 2;与 IX-014 的 modality 是一体的 | + +--- + +## 4. 两个横切问题 + +### 4.1 时间显示口径没有定义 + +操作记录显示裸时间「22:52」。但 Sense 这个系统里同时存在**三个时钟**: + +- 设备时间(ONVIF 报的,可能漂 +3.8s) +- 服务器时间(期望态真相源) +- 浏览器本地时间(用户看到的) + +而「时间漂移」正是原型自己列为一级列的指标。三个时钟不区分,运维会误判。 + +**需要**:统一时间显示口径(建议全部显示服务器时间 + 时区标注,设备时间只在漂移列出现),相对时间与绝对时间并存("2 分钟前"悬停显示完整时间戳)。 + +### 4.2 租户维度不存在 + +架构 §3:首期一客户一套私有实例,但「数据库实体、RBAC、配置与 API 从第一版携带 `tenant_id` 并保持 SaaS-ready 边界」。 + +原型没有任何租户表达。首期不需要租户**切换器**,但需要:当前租户的显示、以及所有列表默认按租户过滤的事实在 UI 上可见。否则实现时容易写成全局查询,SaaS-ready 边界在第一版就破了。 + +--- + +## 5. 汇总:建议加入的导航 + +现有五项 → 建议八项(新增三项加粗): + +``` +运行总览 +实时监控 +设备 ← 原「摄像头」,改名以容纳 modality(见 IX-014) +接入任务 +**站点与区域** ← 新增:站点列表、配额、Area 管理(含隐私区域标记) +**运维** ← 新增:对账队列、孤儿资源、分片、边缘节点与隧道、运维告警 +系统状态 +**审计** ← 新增:设备操作审计入口(主真相源在 Bell,Sense 需入口) +``` + +顶栏需要补:站点切换器、当前用户与角色。 + +--- + +## 6. 优先级建议 + +| 顺序 | 做什么 | 理由 | +| --- | --- | --- | +| 1 | **对账器运维视图**(§1.2) | 单点最大缺口。这是 Sense 的存在理由,现在 UI 上等于不存在 | +| 2 | **权限与角色**(§1.5) | 决定页面上有没有按钮,是 IA 问题不是加一层 | +| 3 | **站点与区域**(§1.1) | 实体链断了两级,Area 还是隐私区域约束的挂载点 | +| 4 | 待激活闭环、凭据更新、配额降级态(§1.3–1.6) | 都是需求文档已明确定义、原型未表达的行为 | +| 5 | P1 六项 | M2 出口前补齐 | +| 6 | P2 三项只留导航位 | 不实现,避免 M3 整页重做 | + +> §1.5(权限)与《09》的 IX-014(modality)都是**改信息架构**的改动,建议合并到同一次原型重生成里,不要分两次打补丁。 diff --git a/docs/raw/13-架构评审与修订建议.md b/docs/raw/13-架构评审与修订建议.md new file mode 100644 index 0000000..b1f99ae --- /dev/null +++ b/docs/raw/13-架构评审与修订建议.md @@ -0,0 +1,289 @@ +# 架构评审与修订建议 + +> 评审对象:《03-通用场景应用方案》《08-三系统职责划分》,以及工程侧 `04-architecture.md` +> 状态:**全部为建议,均未生效。** 每条给出现状、问题、建议、影响面和我的把握程度,供逐条裁决。 +> 裁决后:采纳的条目改写对应文档正文,本文保留为决策依据;未采纳的条目保留并记明理由,避免以后重复讨论。 +> 日期:2026-08-04 + +--- + +## 0. 总评 + +架构的骨架是对的,尤其三处: + +1. **控制面/数据面分离解 NAT** —— 隧道只走 ONVIF 控制流量,视频边缘主动推、绝不过隧道,且明确"控制面丢失不停视频"。多数团队会把视频塞进 VPN 然后在带宽和单点上栽跟头 +2. **水平触发对账器,只收敛不回滚** —— DB 单一真相源、幂等、退避、独立信号量、10% 孤儿删除安全闸。"不做跨系统回滚"是分布式里最易做错的决定,这里做对了 +3. **Event / Alert 分离** —— 事件不可变,告警是带状态机的响应过程,投递三个事实分开存。多数系统合成一个 `notified` 布尔,然后永远回答不了"到底有没有人管" + +下面 13 条是我认为需要修订或补空的地方。**A 组影响架构决策,B 组是数据层空缺。** + +--- + +## A 组 · 影响架构决策 + +### A-1 Bell 的职责边界应按变化频率再切一刀 + +**把握程度:中**(这是判断,不是硬伤) + +**现状**:Bell = 事件校验/存储 + 规则引擎 + 告警状态机 + 投递 + 反馈闭环 + 租户 RBAC + 审计 + 配额真相源 + 管理后台 + 前端 + 大屏 + 场景包。 + +**问题**:Sense 与 Brain 的边界很干净——按运行时和语言切,边界落在阻抗真正变化的地方。Bell 没有用同一把尺子。它内部有一条清楚的断层: + +| | 事件/告警内核 | 管理面 | +| --- | --- | --- | +| 内容 | ingest、event、rule、alert、deliver、feedback | tenant、RBAC、audit、配额、web、packs | +| 变化频率 | 低 | 高 | +| 正确性要求 | 极高(状态机、幂等、重启续跑) | 常规 CRUD | +| 出错后果 | 告警丢失 | 页面报错 | + +捆在一起意味着改一个权限要碰告警内核的部署。 + +**建议**:不必现在拆成两个部署单元,但**在 `Bell/internal/` 内部先立起这条边界**:核心包不得依赖管理面包,管理面通过接口调用核心。M4 若确需拆分,成本接近零;不拆也没有损失。 + +**影响面**:《08》§1.1 Bell 条目、§2.3 目录结构;`04-architecture.md` §2。 + +--- + +### A-2 配额不该走跨系统 API,应改为同库只读视图 + +**把握程度:高** + +**现状**:《08》§3 边界 7、`04-architecture.md` §5 第 7 条——Bell 拥有 `site.max_video_channels`,Sense 通过"版本化内部 API 或只读投影"读取,并定义了配额服务不可达时的降级语义;`api.md` §2 已把它列为待 M2 设计的接口。 + +**问题**:为了一个整数,引入了三个活动部件(接口、超时重试、降级态)。而架构第 5 条已经定了**一个 PostgreSQL 实例,schema 分离**——同实例意味着这次跨界根本不需要网络。 + +现在的设计同时付两份成本:既没有独立库的隔离好处,又背上了微服务的仪式感。 + +**建议**:改为只读视图,视图名带版本号以保住"版本化"这个要求: + +```sql +CREATE VIEW bell.site_quota_v1 AS + SELECT id, tenant_id, max_video_channels FROM bell.sites; +GRANT SELECT ON bell.site_quota_v1 TO sense_app; +``` + +Bell 改表结构时只要视图签名不变,Sense 不受影响——这正是版本化想要的效果。 + +**连带收益**:省掉一个内部接口、一套超时重试,以及《12》S-09 里一半的降级态工作量(区域策略那半仍需保留,因为它可能来自 Sense 自己的写路径)。 + +**影响面**:《08》§3 边界 7;`04-architecture.md` §4 步骤 1、§5 第 7 条、§7;`api.md` §2 删去 `Sense → Bell 读取站点视频配额` 一行;《12》S-09 缩小范围。 + +> ⚠️ 若未来确定 Sense 与 Bell 分库部署,本条自动失效,回退到 API 方案。裁决时请一并确认"一个实例"这个前提的有效期。 + +--- + +### A-3 「Brain 无状态」的表述需要收紧 + +**把握程度:高** + +**现状**:`04-architecture.md` §2 称 Brain「Python/CUDA,业务无状态」;《08》§1 称「无状态」。 + +**问题**:判定内核是 `NORMAL → SUSPECT → CONFIRMED → RECOVERING`,**每个 track 一份、带时间窗**。这就是状态。文档说的"业务无状态"实际含义是"无 DB schema",但两者不等价,差别会在 M4 分片时显现: + +- 进程在某人处于 SUSPECT 时重启,那次判定怎么办? +- 分片再平衡时,track 状态机迁不迁移? +- 同一个人从 media-01 机位走到 media-02,两个 worker 各持一份状态,如何不重复报警? + +**建议**:把表述改为—— + +> Brain **无持久化业务状态**;判定状态机是**进程内易失状态**,重启即丢失。已接受的代价是:重启瞬间正在进行的单次判定丢失,不影响已产出事件与后续判定。跨 worker 的同一目标关联由 `anon_id`(ReID)在 Bell 侧聚合承担,不依赖 Brain 之间共享状态。 + +若这个代价不可接受,需在 M4 分片前给出方案,不能靠"无状态"这个词绕过去。 + +**影响面**:《08》§1 总表与 §1.1 Brain 条目;`04-architecture.md` §2 表格。 + +--- + +### A-4 M1 必须引入一个假 reader,否则对账器在真空里开发 + +**把握程度:高** + +**现状**:`04-architecture.md` §10——M1、M2 只动 Sense,M3 才有 Brain 和 Bell。 + +**问题**:对账器的全部意义是把 mediamtx 收敛到 DB 期望态。但 `sourceOnDemand: yes` 的语义是**有 reader 才拉流**,而 Brain 不在就没有 reader。于是 M1–M2 的对账器是在对着一个什么都不做的系统收敛。 + +四条硬约束里最要命的两条——**改 path 配置会踢掉当前发布者**、**推理 source 挂上去就是一个 reader**——都要到 M3 才第一次真正暴露。M2 的出口标准会给出虚假的安全感。 + +**建议**:M1 引入一个最小假 reader(`ffmpeg -i rtsp://… -f null -`,或一个只拉不解码的 gortsplib 客户端),作为 Sense 测试装置的一部分。目的不是功能,是**让 sourceOnDemand 的语义在 M1 就受力**:验证有 reader 时才拉流、卸载 reader 后 30s 自动停、改 path 配置会踢掉发布者。 + +**影响面**:`04-architecture.md` §10;《03》§6.1 M1 骨架增加 `testutil/fakereader`;M1/M2 出口标准增加一条。 + +--- + +### A-5 先做纵向切片,不要等到 M3 才有端到端 + +**把握程度:中高**(这是排期建议,不是架构缺陷) + +**现状**:`Sense/`、`Brain/`、`Bell/` 是三个空目录。围绕它们已有 13 份 raw 文档、12 份工程文档、一份冻结契约(schema + 负面测试 + 三个夹具)、两个原型、三轮原型评审、一份 24 条待办清单。按现有顺序,第一个端到端价值出现在 M3。 + +**问题**:设计密度显著领先于证据。所有架构判断——分片、配额、对账、多租户——在 M3 前都拿不到反馈。 + +缓解因素是真实的:silver_pose 已验证、文档大量源自一个交付过的项目。所以这不是空想,但风险形状很具体。 + +**建议**:在 M1 内插入一条**纵向切片**,复用 silver_pose 已跑通的链路: + +``` +1 路摄像头 → mediamtx → silver_pose(出 v0.1 事件)→ 最小 Bell(一张表 + 一条通知) +``` + +对账器可以只有 50 行,Bell 可以只有一张表。目的不是交付,是**让契约、sourceOnDemand 语义、事件流转在 M1 就受一次真实的力**。 + +现有架构完全支持这么做——三系统边界清楚、契约已冻结。缺的不是设计,是把"先纵切一刀"排进里程碑。 + +**影响面**:`04-architecture.md` §10;`06-tasks.md` 路线图。 + +--- + +### A-6 L2/L3 的分层边界是名义上的,真边界只有一条 + +**把握程度:中** + +**现状**:分层 L0–L5,L2 是流水线(Savant),L3 是能力(检测/姿态/跟踪/ReID)。 + +**问题**:Savant 的模型就挂在 pipeline 里,这条线在实现时会消失。把它当作可独立替换的边界会产生错误预期。 + +**建议**:文档中明确——L2/L3 是**认知分层**,便于讨论职责;**唯一可独立替换的技术边界是 `Detector` / `PoseEstimator` 接口**。那条接口设计得早、目的明确(AGPL 逃生),是真的边界,应单独强调而不是淹没在六层里。 + +**影响面**:《03》§1.1–1.2 分层说明;`04-architecture.md` §1。 + +--- + +## B 组 · 数据层空缺 + +### B-1 设备遥测的历史数据没有归属 · 建议优先处理 + +**把握程度:高** + +**现状**:原型已展示「时间漂移 +3.8s」「重连历史」「最后遥测」「分片实际码率」。这些是**时序业务数据**,当前文档中无任何归属。 + +**问题**: + +- 全量塞 Postgres:128 路 × 每分钟一条 ≈ 一年 6700 万行。会成为库里最大的表,却是价值密度最低的数据 +- 塞 Prometheus:那是运维指标,保留期短,且不适合按设备做业务查询("这台摄像头上个月的漂移趋势") + +**建议**: + +| 数据 | 存哪 | +| --- | --- | +| 当前值(最后一次漂移、当前分片、实际态) | `sense` schema,随设备行 | +| 最近 N 条(默认 100)事件式记录:重连、校时、状态跃迁 | `sense` schema,独立表 + 定期裁剪 | +| 连续趋势(码率、漂移曲线) | Prometheus | +| 若确需长期业务查询 | **TimescaleDB 扩展**——仍是同一个 PG 实例,不违反"一个实例"的决定 | + +**影响面**:《08》§1.1 Sense 条目;`04-architecture.md` §8;`03-tech-stack.md` 增加 TimescaleDB 作为条件性选项。 + +### B-2 Brain 的本地重试队列形态未定 + +**把握程度:高** + +**现状**:`04-architecture.md` §7「Brain 投递失败落本地队列重试,不阻塞实时推理主链路」——只有语义,没有形态。 + +**问题**:Brain 号称无 schema、无持久化状态,**这个队列是它唯一的持久化**,而且直接决定 Brain 崩溃时丢不丢事件。 + +**建议**:明确选型(文件追加 / SQLite / BadgerDB 任一皆可,但必须选定),并定义:队列上限、超限后的丢弃策略(**建议丢最旧,且丢弃必须产生运维告警**)、重启后的恢复顺序、重复投递由 Bell 侧 `source_event_id` 去重。 + +**影响面**:《08》§2.2 Brain 目录(`emit/publisher.py` 旁增加队列实现);`04-architecture.md` §7;`api.md` §2。 + +### B-3 边缘节点的断网缓存形态未定,且需与环形缓冲区分 + +**把握程度:高** + +**现状**:需求 §3.5「断网时边缘缓存事件,恢复后补传」;《03》另有"边缘环形缓冲"用于 pre-roll。 + +**问题**:这是**两种不同的东西**,文档中容易混为一谈: + +| | 环形缓冲 | 事件缓存 | +| --- | --- | --- | +| 内容 | 视频(最近 N 秒) | 结构化事件 + 元数据 | +| 覆盖策略 | 循环覆盖,丢失可接受 | **不可静默丢失** | +| 用途 | pre-roll 证据回捞 | 断网续传 | + +**建议**:文档中显式区分两者,并为事件缓存定义容量上限、超限策略与补传进度的可观测指标(对应《12》S-10)。 + +**影响面**:《03》§2.6 证据回捞;《08》§1.1 Sense 条目。 + +### B-4 M1 SQLite → Postgres 的切换时机未定 + +**把握程度:高** + +**现状**:《03》§6.1 与《08》§2.1 都写「M1 先 SQLite,schema 与生产 Postgres 保持一致」,但没写何时切、是否一次性、有无迁移脚本。 + +**建议**:钉在 **M2 入口**,且切换前 schema 必须已用 Postgres 语法编写(SQLite 只作为运行时,不作为 schema 方言的来源)。迁移脚本从第一天就写 Postgres 版本,SQLite 通过兼容子集运行。 + +**影响面**:`04-architecture.md` §10;《08》§5 里程碑表。 + +### B-5 用数据库角色强制 schema 边界 + +**把握程度:高** + +**现状**:架构第 7 条写「不跨 schema 直接写」。 + +**问题**:只靠约定,迟早会被一个赶工的 JOIN 破掉,而且破掉时没有任何信号。 + +**建议**:在 DB 层强制: + +```sql +CREATE ROLE sense_app; GRANT USAGE ON SCHEMA sense TO sense_app; +CREATE ROLE bell_app; GRANT USAGE ON SCHEMA bell TO bell_app; +-- sense_app 对 bell schema 无任何权限,A-2 的 site_quota_v1 视图除外 +``` + +这样"不跨 schema 写"从纪律问题变成权限问题——写错了连不上,而不是上线后才发现。 + +**影响面**:`04-architecture.md` §5 第 5、7 条;部署清单。 + +### B-6 建库、建角色、建 extension 的归属无人认领 + +**把握程度:高** + +**现状**:`sense` schema 的迁移在 `Sense/`,`bell` 的在 `Bell/`。但**建数据库本身、建角色、安装 pgvector / TimescaleDB extension** 不属于任何一方。 + +**建议**:归入独立部署清单(与 MediaMTX、MinIO、Prometheus 同级),在 M2 之前指定归属。否则会变成"谁先跑谁建",各环境不一致。 + +**影响面**:《08》§1.2 基础设施行;部署清单。 + +### B-7 人脸相关存储的位置需在 M5 前复核 + +**把握程度:中** + +**现状**:《02》定人脸底库「独立 schema、独立加密、独立审计」,`face_vectors.embedding` 用 `VECTOR`(pgvector)。 + +**问题**:「独立 schema」与「独立加密」在同一个 PG 实例内能做到什么程度,需要具体方案(列级加密?TDE?还是独立实例?)。现在的表述在合规评审时会被追问。 + +**建议**:M5 前明确——若"独立加密"要求达到密钥与业务库分离的程度,则人脸库应是**独立 PG 实例**,此时它是"一个实例"决定的合法例外(因为它不参与对账,不破坏单一真相源前提)。 + +**影响面**:《02》§11 SQL 模型;`04-architecture.md` §5 第 5 条增加例外说明。 + +--- + +## 汇总:需要修订的文档章节 + +| 建议 | 《03》 | 《08》 | `04-architecture.md` | 其他 | +| --- | --- | --- | --- | --- | +| A-1 Bell 内部边界 | — | §1.1、§2.3 | §2 | — | +| A-2 配额改视图 | — | §3 边界 7 | §4、§5-7、§7 | `api.md` §2 删一行;《12》S-09 缩范围 | +| A-3 Brain 状态表述 | — | §1、§1.1 | §2 | — | +| A-4 M1 假 reader | §6.1 | — | §10 | M1/M2 出口标准 | +| A-5 纵向切片 | — | — | §10 | `06-tasks.md` | +| A-6 L2/L3 边界 | §1.1–1.2 | — | §1 | — | +| B-1 遥测归属 | — | §1.1 | §8 | `03-tech-stack.md` | +| B-2 Brain 队列 | — | §2.2 | §7 | `api.md` §2 | +| B-3 两种缓存 | §2.6 | §1.1 | — | — | +| B-4 SQLite 切换 | §6.1 | §5 | §10 | — | +| B-5 DB 角色 | — | — | §5 | 部署清单 | +| B-6 建库归属 | — | §1.2 | — | 部署清单 | +| B-7 人脸存储 | — | — | §5 | 《02》§11 | + +--- + +## 建议裁决顺序 + +| 顺序 | 条目 | 理由 | +| --- | --- | --- | +| 1 | **A-2**(配额视图) | 影响 `api.md` 待设计接口清单与《12》S-09 的范围,越早定省的工作越多 | +| 2 | **A-4**(M1 假 reader) | 影响 M1 任务拆分,且成本极低 | +| 3 | **B-1、B-2、B-3、B-4**(数据层四空缺) | 都是补空不是改决策,无争议 | +| 4 | **B-5、B-6**(DB 角色与建库归属) | 部署侧,M2 前必须有 | +| 5 | **A-3**(Brain 状态表述) | 改表述,但会牵出 M4 分片的真问题,宜早不宜迟 | +| 6 | **A-5**(纵向切片) | 排期决策,需与商务节奏一起看 | +| 7 | **A-1、A-6、B-7** | 判断性/远期,可延后 | diff --git a/docs/raw/15-Bell原型-功能模块缺口.md b/docs/raw/15-Bell原型-功能模块缺口.md new file mode 100644 index 0000000..80c5a3a --- /dev/null +++ b/docs/raw/15-Bell原型-功能模块缺口.md @@ -0,0 +1,182 @@ +# Bell 原型:功能与模块缺口分析(第二轮) + +> 基准:`yovision-T-004/docs/design/bell/index.html`(codex,2026-08-04 11:43,842 行 / 90 KB) +> 对标:`02-requirements` §3.3/§3.4/§3.6/§8、`04-architecture` §7/§8、IX-005~013 / IX-019~022、US-003~006 / US-009~012、`routes.md` +> 前置:《14-Bell原型评审》 +> 与《14》的区别:14 谈**行为缺口**,本文谈**模块缺口**——整块功能不存在 +> 日期:2026-08-04 + +--- + +## 0. 结论 + +《14》提的问题基本全部落地,且清单侧同步新增了 IX-019~022、US-009~012。实测: + +| 《14》findings | 本轮 | 证据 | +| --- | --- | --- | +| §2.1 投递四态 | ✅ | 已发出 / 已送达 / 已看到 / 无回执 / 不支持 / 可重试 / 最终失败 均出现 | +| §2.2 Event↔Alert 双向 | ⚠️ 部分 | 「关联事件」「未触发」有;**「聚合原因」0 次**,IX-008 明确要求 | +| §2.3 Area 归属 | ✅ | IX-020 定为 Bell 管理,Sense 只消费 | +| §3.1 交接班 | ✅ | `handoverDialog` + IX-021 | +| §3.2 并发 ack | ✅ | 「并发」5 次 + IX-006 细化 | +| §3.3 重启续跑可观测 | ❌ | **「重启」「续跑」各 0 次,且 IX 清单里也没有这一条** | +| §3.4 状态覆盖 | ⚠️ 部分 | 新增 `expired`;仍无 `conflict` 页面级态 | +| §3.5 分页 | ⚠️ | 「分页」仅 1 次 | +| §4.1 回滚 | ✅ | `rollbackDialog` + 版本冲突 + IX-011 | +| §4.2 报表口径 | ✅ | 召回率 / 每路每天 / 样本量 / 导出 + IX-022 | + +**下面是从模块轴看仍然整块缺失的部分。** + +--- + +## 1. P0 模块缺口 + +### 1.1 联系人与通道管理(升级链能看不能编) + +**实测**:`联系人` **0** 次;`通道` 8 次;「编辑升级链」是死按钮。 + +**现状**:升级链页能展示三级链路(值班室 Web+声光 → 值班员短信 → 校级负责人语音),但**联系人不是一个实体**——没有人员列表、没有电话/账号、没有角色绑定、没有按时段轮换。 + +**依据**: + +- `02-requirements` §3.4:「升级链、超时、**联系人和时段**可按租户/站点配置」 +- IX-012:「**联系人顺序**、超时、双通道」 +- US-005 的一半是「配置……联系人升级链」 + +**需要什么**: + +| 项 | 说明 | +| --- | --- | +| 联系人实体 | 姓名、角色、可用通道(push / 短信 / 语音)、所属站点 | +| 升级链编辑器 | 每级:等待时长、联系人或角色、通道组合;至少两条独立路径的校验 | +| **按时段配置** | 需求明写「时段可配置」——夜间链路与白天链路不同,是校园场景的核心 | +| 变更影响提示 | 改升级链会影响正在升级中的 Alert 吗(建议:不影响,已在途的沿用旧版) | + +> 这是 Bell 最核心的可配置项之一,现在只有展示没有管理。 + +### 1.2 投递供应商与故障切换 + +**实测**:`供应商` / `provider` / `故障切换` 各 **0** 次。 + +**依据**: + +- `02-requirements` §3.6:「投递层必须使用**供应商无关的 provider 接口**;试点至少有本地声光/Web 与一条短信或语音,**生产前补齐两条独立路径及故障切换**」 +- `04-architecture` §5 第 9 条:「投递状态机只依赖 Bell provider 接口,不直接依赖某家短信或语音 SDK;生产前至少两条独立路径并能故障切换」 +- `02-requirements` §3.4:「至少两条独立投递路径,**其中一条可绕过互联网**」 + +**需要什么**: + +| 项 | 说明 | +| --- | --- | +| provider 列表 | 每条通道当前用哪家、健康状态、余额/配额(短信有量) | +| 主备与切换策略 | 切换条件、切换历史、当前生效的是主还是备 | +| **绕过互联网的那条路径** | 本地声光 / 局域网广播,其可用性必须单独可见——断网时它是唯一还能工作的 | +| 连通性自检 | 定期发测试消息并记录结果,避免"用的时候才发现短信欠费" | + +> 「至少两条独立路径」是写进需求的硬约束,但现在**无处配置、无处验证**。 + +### 1.3 重启续跑的可观测(双缺:原型 + 清单) + +**实测**:`重启` / `续跑` 各 **0** 次。而且遍查 IX-001~022,**没有任何一条覆盖它**。 + +**依据**: + +- `02-requirements` §3.4:「预警必须有 ack;未 ack 自动升级,**进程重启后能续跑**」 +- `04-architecture` §7:「Alert 先落库再投递,**进程重启恢复未完成升级链**」 + +**问题**:这是一条很强的可靠性承诺,但没有任何可验证的表达。运维无法确认它真的生效,验收也无从下手——而这类承诺不验证就等于没有。 + +**需要什么**: + +| 项 | +| --- | +| 升级时间线中标注服务重启事件与恢复结果:「服务重启于 23:15:02,本 Alert 升级链已恢复,下一次升级 23:16:10」 | +| 系统状态/运维处给出「重启后待恢复升级链 N 条 / 已恢复 M 条」指标 | +| 恢复失败的 Alert 单独可见(落库了但恢复不了,必须暴露而不是静默) | +| **建议同时补一条 IX 条目**——清单缺这条比原型缺更严重 | + +--- + +## 2. P1 模块缺口 + +### 2.1 事件证据的保留策略与存储 + +**实测**:`存储` / `留存` 各 **0** 次;`保留` 5 次(多为其他语境)。 + +**依据**:`02-requirements` §8—— + +> 事件片段默认存客户侧 MinIO/S3 兼容对象存储……技术默认 30 天并在目的完成后删除;**客户/法务确认最终期限**。元数据、审计、人脸与训练样本使用独立策略。 + +**需要什么**:保留期配置(按类别:事件片段 / 抓拍 / 元数据 / 审计 / 训练样本,各自独立);**法务确认状态**(技术默认值不能覆盖法务结论,这个状态必须可见);存储用量与增长趋势;到期删除的执行记录(合规举证要用)。 + +### 2.2 场景包管理 + +**实测**:`场景包` 2 次(疑似文案)。 + +**依据**:M5 出口标准——「场景包为**纯配置交付**,无需改核心代码」,这是整个架构的验收点;目录 `Bell/packs/`。 + +**需要什么**:包列表与版本;导入/导出;应用到站点时的**差异对比**(这个包会新增/修改哪些规则);已应用包的升级路径。没有这个模块,M5 的验收标准无法演示。 + +### 2.3 对外集成:Webhook / OpenAPI + +**实测**:`Webhook` / `OpenAPI` 各 **0** 次。 + +**依据**: + +- `02-requirements` §3.6:「对外使用**版本化 OpenAPI/Webhook**;M3 客户端为值班室 Web + 响应式移动 H5,**可嵌入客户系统**」 +- `04-architecture` §3:「客户平台通过版本化 OpenAPI/Webhook 集成,**不反向接管核心状态机**」 + +**需要什么**:Webhook 端点配置、签名密钥(只写不读)、订阅的事件类型、投递状态与重试队列、失败告警。这是"可嵌入客户系统"这句话的落地形态,四线城市客户往往已有一套平台。 + +### 2.4 用户与角色管理 + +**实测**:`用户` 1 次、`账号` 2 次、`角色` 2 次;有 `manageDialog`,但看不出 CRUD。 + +**依据**:IX-020——「Tenant/Site/Area/**RBAC**/配额/全局审计由 Bell 管理」;`02-requirements` §3.5 五角色。 + +**需要什么**:用户列表与邀请/停用;角色分配(含站点范围);会话管理(`expired` 态已有,但没有主动踢下线);密码/MFA 策略。 + +### 2.5 去重与聚合的配置面 + +**实测**:`聚合` 4 次、`抑制` 1 次、`冷却` **0** 次。 + +**依据**:《03》§2.6 定义了四层去重——同设备冷却期(默认 5min)、同站点聚合、已处置抑制、静默窗口。**目前只有静默有 UI。** + +**需要什么**:前三条的配置入口(是规则的一部分,还是站点级全局配置?现在无处设置);以及 IX-008 要求的**聚合原因**在 Alert 详情中的展示(`聚合原因` 实测 0 次)。 + +--- + +## 3. P2 · 只留位 + +| 模块 | 依据 | 说明 | +| --- | --- | --- | +| 大屏与平面图 | `routes.md` 值班台/大屏:「地图/平面图点位和列表**双向定位**,但点位缺失时仍可从列表处置」 | `地图`/`平面图`/`大屏` 各 0 次。M4 才要,但导航留位 | +| 排班表 | 需求 §3.4「联系人和**时段**可按租户/站点配置」;交接班已有但排班没有 | 与 1.1 联系人管理同源,可合并设计 | + +--- + +## 4. 页内小缺口(不是模块,但 IX 明确要求) + +| # | 缺什么 | 依据 | 实测 | +| --- | --- | --- | --- | +| 1 | Alert 详情的**聚合原因** | IX-008「Alert 展示关联 Event 与**聚合原因**」 | `聚合原因` 0 次 | +| 2 | 试运行的**命中样本** | IX-011「展示**命中样本**与影响范围」 | `命中样本` 0 次;`影响范围` 1 次 | +| 3 | 事件中心的**批量处置** | `routes.md` `/events`「事件筛选与**批量处置**入口」 | `批量` 0 次 | +| 4 | 分页 | `routes.md` `/events` 与 `/audit` 均要求 | `分页` 1 次,覆盖不明 | +| 5 | 页面级 `conflict` 态 | IX 全局状态「数据已被他人修改」 | 仅回滚对话框内有版本冲突 | + +--- + +## 5. 建议顺序 + +| 顺序 | 条目 | 理由 | +| --- | --- | --- | +| 1 | **1.1 联系人与通道管理** | Bell 最核心的可配置项,US-005 的一半,现在只有展示 | +| 2 | **1.2 供应商与故障切换** | 「至少两条独立路径」是需求硬约束,现在无处配置、无处验证 | +| 3 | **1.3 重启续跑可观测 + 补 IX 条目** | 清单缺这条比原型缺更严重;先补清单再改原型 | +| 4 | §4 五个页内小缺口 | 都是 IX 已写明的,成本低 | +| 5 | 2.1 保留策略 · 2.5 去重配置 | 前者关合规举证,后者关误报体感 | +| 6 | 2.2 场景包 · 2.3 对外集成 · 2.4 用户角色 | M4/M5 前补齐 | +| 7 | P2 两项留位 | 不实现 | + +> 1.1 与 P2 的排班表同源(联系人 + 时段 + 轮换),建议一次设计到位,不要先做联系人再回头加时段。 diff --git a/docs/raw/archive/2026-08-04/08-三系统职责划分-评审前快照.md b/docs/raw/archive/2026-08-04/08-三系统职责划分-评审前快照.md new file mode 100644 index 0000000..5191acb --- /dev/null +++ b/docs/raw/archive/2026-08-04/08-三系统职责划分-评审前快照.md @@ -0,0 +1,187 @@ +# 三系统职责划分:Sense / Brain / Bell + +> 本文档回答一个问题:**一段代码该写进哪个目录。** +> 划分依据来自《03-通用场景应用方案》的 L0–L5 分层与组件选型,本文档只是把它按三个可独立开发的系统重新切分。 +> 定稿:2026-08-03 +> ⚠️ 有 8 条待裁决的修订建议涉及本文档(§1.1、§1.2、§2.2、§2.3、§3 边界 7、§5),见《13-架构评审与修订建议》汇总表。**裁决前本文内容全部有效。** + +--- + +## 1. 三系统总表 + +| | **Sense** | **Brain** | **Bell** | +| --- | --- | --- | --- | +| 中文 | 感知系统 | 推理系统 | 管理系统 | +| 小学生版 | 感觉到 | 想一想 | 打铃叫人 | +| 对应层 | L1 接入 | L2 流水线 + L3 算法 | L4 业务 + L0 基座 | +| 语言 | Go | Python / CUDA | Go + 前端 | +| 有无状态 | 有(设备台账) | **无状态** | 有(事件、告警) | +| DB schema | `sense` | 无 | `bell` | +| 契约角色 | 供流与信号 → Brain | **产出**事件 | **消费**事件 | +| 首次交付 | M1 | M3 | M3(最小)→ M4(完整) | + +### 1.1 各自装什么 + +**Sense —— 把现场的流和信号稳定地拿进来并管住** + +- 设备台账(`devices`,含 `modality`:video / radar / contact / button / wearable) +- ONVIF 客户端:连接、GetProfiles、GetStreamUri、SetSystemDateAndTime +- mediamtx API 客户端(**自行用 oapi-codegen 从其 OpenAPI 生成**,不依赖第三方 SDK) +- **对账器**:水平触发、`sync_state`、独立信号量、10% 孤儿删除安全闸、只收敛不回滚 +- 探活与断线重建 +- WireGuard 控制面隧道 +- mediamtx 鉴权回调(401 + 踢流是四种停用粒度之一) +- 容量配额执行:设备新增/启用时读取 Bell 的站点配额,只拒绝超额变更;配额服务暂时不可用时不影响已有流 +- 流绑定与媒体分片调度:维护 `mtx_instance`,默认 16 路交付;扩到 128 路时按 `media_shard.max_streams` 横向分片 +- 边缘节点 agent:推流、本地环形缓冲、断网续传 +- **设备型触发源**:雷达、门磁、按钮、ONVIF 事件订阅 +- 非视频传感器的信号接收(signal plane,不走 mediamtx) + +**Brain —— 看画面、出判定** + +- Savant 流水线与适配器(ZeroMQ 边界,适配器故障隔离,实时模式丢帧) +- 模型:检测 / 姿态 / 跟踪 / ReID(`anon_id`)/(M5)人脸 +- **`Detector` 与 `PoseEstimator` 接口解耦**——这是 AGPL 逃生通道的前提,换 YOLOX + RTMPose 时判定算法不动 +- 判定内核:几何证据 + 时间窗状态机(从 silver_pose 抽取,两边共用) +- 事件 mapper:判定结果 → 事件契约 v0.1 +- **像素级**运动侦测触发(要解码,所以在这里) +- 推理 worker 注册与分片:单逻辑推理分片默认最多 16 路;64/128 路由多个 worker 承担,路由变更不改判定代码 + +**Bell —— 记录、派发、追到人确认** + +- 事件接收与校验(schema 校验 + 契约 README §5 那六条代码级断言 + 生成 ULID) +- 事件存储:**不可变**,误判只改 `outcome` +- 规则引擎 + 场景包加载 +- 告警状态机:升级链、ack、抑制、静默(**≤4h,无永久选项**) +- 投递:push / 短信 / 语音,**双供应商** +- 误报反馈闭环:`outcome` 回写 Brain +- 多租户 RBAC、`tenant_features`(人脸授权开关:未授权时能力在 API 与 UI 中**不可见**,不是禁用) +- 审计日志 +- 站点容量配额的唯一真相源:`site.max_video_channels` 默认 16、上限 128;提供版本化内部读取接口/投影给 Sense 执行 +- 管理后台前端 + 大屏:按 128 路设计分页/虚拟列表、筛选与批量操作,不一次性加载全部视频 + +### 1.2 不属于任何一个目录的东西 + +| 组件 | 说明 | +| --- | --- | +| **mediamtx** | 独立二进制,外部依赖。Sense 管它的配置与生命周期,`Sense/deploy/` 放基线配置 | +| **PostgreSQL / MinIO / Prometheus** | 基础设施,独立部署清单 | +| **silver_pose** | 独立仓库,是 Brain 判定内核的来源与单机演示形态。**不改名、不合并**——它现在能卖,Brain 还不能 | +| **`_reference/`** | 只读参考源码(如 MiBeeNvr)。按《03》§1.4 白名单借鉴 ONVIF、IP 自愈、健康检测、测试组织与 UI 交互;禁止复制媒体内核、SQLite 真相源、AI/用户体系,禁止整仓进生产或加入 go.mod | + +--- + +## 2. 目录结构 + +### 2.1 Sense(Go) + +``` +Sense/ +├── cmd/ +│ ├── sense-api/ 控制面服务:设备台账、鉴权回调、对账器 +│ └── sense-agent/ 边缘节点:推流、环形缓冲、隧道 +├── internal/ +│ ├── device/ 设备台账(devices,含 modality) +│ ├── onvif/ 连接、GetProfiles、GetStreamUri、SetSystemDateAndTime +│ ├── mtx/ oapi-codegen 生成的 mediamtx 客户端 + 薄封装 +│ ├── reconcile/ 对账循环(幂等 + 退避 + 安全闸) +│ ├── probe/ 探活 +│ ├── trigger/ 设备型触发源(雷达/门磁/按钮/ONVIF 事件) +│ ├── tunnel/ WireGuard 控制面 +│ ├── authcb/ mediamtx 鉴权回调 +│ └── store/ M1 先 SQLite,schema 与生产 Postgres 保持一致 +├── deploy/ +│ └── mediamtx.yml 基线配置 +└── api/openapi.yaml +``` + +### 2.2 Brain(Python / CUDA) + +``` +Brain/ +├── pipeline/ Savant 流水线定义与适配器 +├── models/ +│ ├── detector/ Detector 接口 + YOLO / YOLOX 实现 +│ ├── pose/ PoseEstimator 接口 + YOLO-pose / RTMPose 实现 +│ ├── tracker/ ByteTrack / BoT-SORT +│ └── reid/ 匿名同一性,产出 anon_id +├── judge/ +│ ├── evidence.py 几何证据(躯干角、髋部下坠比) +│ └── state.py 时间窗状态机 NORMAL/SUSPECT/CONFIRMED/RECOVERING +├── emit/ +│ ├── mapper.py 判定结果 → 契约 v0.1 +│ └── publisher.py 投递(HTTP 起步 → ZeroMQ);**失败落本地队列重试,不阻塞主链路** +├── trigger/ 像素级运动侦测 +└── contracts/ ← 与 Bell/contracts/ 逐字节相同 +``` + +### 2.3 Bell(Go + 前端) + +``` +Bell/ +├── cmd/bell-api/ +├── internal/ +│ ├── ingest/ 接收事件、schema 校验、六条断言、生成 ULID +│ ├── event/ 事件存储(不可变,只允许追加 outcome) +│ ├── rule/ 规则引擎 + 场景包加载 +│ ├── alert/ 告警状态机、升级链、ack、静默 +│ ├── deliver/ push / 短信 / 语音,双供应商 +│ ├── feedback/ 误报回流,outcome 回写 Brain +│ ├── tenant/ 多租户 RBAC、tenant_features +│ ├── audit/ 审计日志 +│ └── store/ Postgres(schema: bell) +├── web/ 管理后台前端 +├── packs/ 场景包(**纯配置** —— M5 架构验收点) +└── contracts/ ← 与 Brain/contracts/ 逐字节相同 +``` + +> `contracts/` 只在 Brain 与 Bell 各存一份(生产者与消费者),**Sense 不需要**——它不碰事件契约。 + +--- + +## 3. 七条边界(不写死就会漂) + +| # | 边界 | 定论 | +| --- | --- | --- | +| 1 | mediamtx 二进制归谁 | 独立进程。**Sense** 管配置与生命周期,部署清单放 `Sense/deploy/` | +| 2 | 触发源归谁 | 按性质切:**设备型**(雷达/门磁/按钮/ONVIF 事件)→ Sense,它们本来就是设备;**像素级**运动侦测 → Brain,它要解码 | +| 3 | pre-roll 证据切片谁裁 | 录制在 Sense(mediamtx),事件在 Brain 产出。**Bell 发起回捞**(它拥有事件),Sense 提供切片接口 | +| 4 | ULID 谁生成 | **Bell**。Brain 只填 `source_event_id`。见契约 README §4 | +| 5 | 一个 PostgreSQL 还是三个 | **一个实例,schema 分离**(`sense` / `bell`),Brain 无 schema。"DB 是唯一真相源"是对账器成立的前提,拆库即失效 | +| 6 | 16 路与 128 路分别指什么 | **16 路是默认交付规格,128 路是本阶段单逻辑站点上限**,都不是“单进程/单服务器保证值”。媒体与推理必须横向分片;单机承载量由分辨率、码率、帧率、模型和硬件基准测试决定 | +| 7 | 站点配额谁拥有、谁执行 | **Bell 拥有 `sites.max_video_channels`,Sense 在设备新增/启用写路径执行**。通过版本化内部 API 或只读投影同步,不允许 Sense 直接写 Bell schema;依赖暂时不可用时拒绝新变更,但已有视频链路继续运行 | + +第 2、3、6、7 条是本文档新定的,若实施中发现更合适的切法,改这里并同步《02》《03》。 + +> ⚠️ **边界 7(站点配额)有一条待裁决的修订建议**:既然已定"一个 PostgreSQL 实例、schema 分离",跨系统读一个整数不必走版本化 API,可改为同库只读视图 `bell.site_quota_v1`。见《13-架构评审与修订建议》A-2。裁决前本表内容仍然有效。 + +--- + +## 4. 标识符约定 + +``` +仓库/目录 Sense Brain Bell +镜像 yov/sense:x.y yov/brain:x.y yov/bell:x.y +日志/指标前缀 sense_ brain_ bell_ +三字母码 SEN BRN BEL +DB schema sense — bell +``` + +**命名规则:系统名不得是该系统领域模型里的实体名。** +`bell` 域内有 `alerts` 表 → 系统不能叫 Alert(`alert.alerts` 无法读,且撞 Prometheus 内置的 `ALERTS` 序列)。另两个同样干净:`sense` 域内是 `devices`/`streams`,`brain` 域内是 `models`/`detections`。 + +--- + +## 5. 里程碑与目录的对应 + +| 阶段 | 动哪个目录 | +| --- | --- | +| **M0** 摄像头兼容性验证 | 无生产代码;可直接运行 MiBeeNvr 等 `_reference/` 项目作为隔离实验室测试台,产物允许丢弃 | +| **M1** 5 路接入骨架 + mediamtx | **仅 Sense**;MediaMTX 正式进入,完整 MiBeeNvr 不得替代生产媒体数据面 | +| **M2** 对账器 + 多租户 + 隧道 + 16 路开通 | **仅 Sense**;至少一个站点验证默认 16 路配额与全流程 | +| **M3** 默认 16 路推理 + 规则引擎 + 事件预警 | **Brain + Bell 同时起步**,契约在此首次被真实使用 | +| **M4** 64 路分片 + 灰度 + 管理系统 | Sense 与 Brain 完成横向分片,Bell 完成 128 路规模下的列表与批量交互;验证单分片故障隔离 | +| **M5** 128 路容量验收 + 第二三场景包 + 触发式推理 + 人脸 | Sense/Brain 验证扩容不改业务代码;Bell 的 `packs/`(**纯配置**)+ Brain 的模型与触发 | +| **M6** 异构传感器 + 两级判定 | Sense 的 `trigger/` 与 `device/`(modality 扩展)+ Brain 两级判定 | + +> M3 是契约第一次被真实使用的时刻。**在此之前契约允许原地修订,之后版本递增规则绝对生效**(契约 README §1)。 diff --git a/docs/raw/archive/2026-08-04/09-Sense原型评审-IX草稿-Claude原稿.md b/docs/raw/archive/2026-08-04/09-Sense原型评审-IX草稿-Claude原稿.md new file mode 100644 index 0000000..f792541 --- /dev/null +++ b/docs/raw/archive/2026-08-04/09-Sense原型评审-IX草稿-Claude原稿.md @@ -0,0 +1,150 @@ +# Sense 原型评审 → IX 条目草稿 + +> 来源:`yovision-T-004/docs/design/sense/index.html`(codex,2026-08-04) +> 用途:补齐原型枚举缺口对应的交互清单条目,供并入 `docs/08-interaction-checklist.md` +> **写入约束**:T-004 的 `write_paths` 只含 `docs/tasks/T-004.md`、`docs/design/sense/index.html`、`docs/design/bell/index.html`,且唯一写入者为 codex。本文件是草稿输入,**由 08 文件的所有者合入**,不要由本会话直接改那个 worktree。 +> 状态:全部条目标【待确认】,按 `docs/design/README.md` 工作流第 5 步逐条人工确认。 + +--- + +## 0. 先纠正一条 + +原评审列的「128 路列表缺分页」**不需要新条目**——`IX-003` 已覆盖「分页/筛选/批量选择;128 路不一次加载所有视频和详情」。那是**原型漏画**,回原型补即可,清单无需改动。 + +因此新增 **5 条**(IX-014 ~ IX-018),另有 2 处全局章节需要收紧。 + +--- + +## 1. 新增条目(可直接贴入主表) + +```markdown +| IX-014 | 设备模态与准入 | 设备台账按 modality(video/radar/contact/button/wearable)建模;列表、筛选、添加流程不得以"摄像头"为唯一形态;非成像设备无画面、无 Profile、无分片,其详情页不展示视频相关页签 | US-001 | M2/M6 | +| IX-015 | 停用与踢流 | 停用需展示影响范围(是否中断在途会话、是否影响推理)并二次确认;停用后期望态与实际态分别收敛,实际态不得立即伪装为"已停止";重新启用为幂等操作 | US-001、US-002 | M2 | +| IX-016 | 隐私区域设备准入 | 标记为隐私区域的位置只接受非成像模态;选择该位置时成像类设备不可选并说明原因;越过前端的写请求由后端拒绝并回显同一措辞 | US-006 | M2 | +| IX-017 | 检测区域几何编辑 | 多边形与方向警戒线的绘制、撤销、清空、闭合;警戒线必须渲染方向箭头;键盘坐标输入与鼠标绘制等效;画面参数变化后既有区域标记为待校准且不静默失效 | US-005 | M3 | +| IX-018 | 草稿与跨系统上下文 | 存在未保存几何草稿时,离开页面(导航、面包屑、切换绘制工具、跳转 Bell)必须拦截并确认;Sense↔Bell 深链双向携带摄像头与区域上下文,返回后草稿不丢失 | US-005 | M3 | +``` + +--- + +## 2. P0 条目详情展开 + +### IX-014 设备模态与准入 + +**为什么是 P0**:原型把「摄像头」写进了导航名、表名、添加对话框标题和协议下拉(只有 ONVIF/RTSP)。《08-三系统职责划分》§1.1 已定 `devices` 含 `modality`,且隐私区域约束现在按模态判定。信息架构一旦以摄像头为唯一形态定稿,接入雷达时是整页重做而非加字段——这与事件契约 v0.1 在 2026-08-03 因同一假设被迫原地修订是同构问题。 + +| 项 | 约定 | +| --- | --- | +| 取值 | `video` / `radar` / `contact` / `button` / `wearable` / `other` | +| 列表 | 模态是可筛选维度;设备图标按模态区分,不复用摄像头图标 | +| 添加流程 | 先选模态,再按模态渲染字段。`radar`/`contact` 无 Profile、无码流、无分片绑定 | +| 详情页 | 非成像模态**不展示**「画面与检测区域」「流与健康」页签,而非展示为禁用 | +| 命名 | 一级导航不叫「摄像头」。建议「设备」,摄像头作为模态筛选项 | +| 阶段 | 建模与命名在 M2 落地;雷达等真实接入在 M6。**建模不能等到 M6** | + +**状态覆盖**:模态不支持该操作 / 模态与站点策略冲突 / 老数据无 modality 的迁移默认值。 + +### IX-015 停用与踢流 + +**为什么是 P0**:原型的「期望态」列有"停用"这个**值**,但没有停用**动作**,也没有任何关于"停用会不会踢掉正在观看的流"的表达。这是 Sense 最有运维后果的行为,且《03》§2.1 定义了四种粒度(卸载推理源 / 踢会话 / 鉴权回调 401 + 踢流 / DELETE path),标准组合是**先踢再拒**。原型不画,IX 就不会生成,实现时会退化成一个静默的布尔开关。 + +| 项 | 约定 | +| --- | --- | +| 确认前必须说明 | 是否中断当前在途会话、是否影响正在运行的推理、是否影响录制与证据回捞 | +| 期望态与实际态 | 点击停用后期望态立即变更,实际态由对账器收敛;**实际态不得立即显示"已停止"** | +| 收敛可见 | 停用中的设备计入「待收敛项」,收敛超时有明确提示 | +| 幂等 | 重复停用/启用不产生副作用,不生成重复审计条目 | +| 批量 | 批量停用逐项结果可见,部分失败可重试 | + +**状态覆盖**:正在被其他人观看时停用 / 对账器不可达时停用 / 停用后又被上游策略重新启用。 + +### IX-016 隐私区域设备准入 + +**为什么是 P0**:这是**代码级**硬约束(《01》RQ-S1-05、《02》NFR-CMP-05、《03》§3.2)。原型的「区域」下拉只是普通选项,没有任何拒绝路径。合规约束在 UI 上不可见时,实现者不会知道它存在。 + +| 项 | 约定 | +| --- | --- | +| 判定依据 | 按 `modality` 判定,**不按设备类型名判定**。`privacy_flag = true` 的位置允许 `radar`/`contact`/`button`/`wearable`,拒绝 `video` | +| 前端 | 成像模态在隐私位置**不可选**,并就地说明原因,而非提交后报错 | +| 后端 | 绕过前端的写请求必须拒绝,措辞与前端一致 | +| 位置属性变更 | 已有成像设备的位置被改标为隐私区域时,必须走显式处置流程,不允许静默留存 | + +**状态覆盖**:位置属性读取失败时默认按最严处理(拒绝成像)。 + +### IX-017 检测区域几何编辑 + +**为什么是 P0**:原型的草稿层(`drawDraft`)把警戒线画成无向线段,但**方向是警戒线唯一的语义**——越线方向决定是否触发。静态示例 SVG 里画了箭头,草稿里没有,说明这是实现遗漏而非设计取舍。 + +| 项 | 约定 | +| --- | --- | +| 方向 | 警戒线草稿与已保存态**都**必须渲染方向箭头;提供反转方向的操作 | +| 最小点数 | 多边形 ≥3,警戒线 =2;不足时保存被拒并说明 | +| 闭合交互 | 双击闭合**不得先追加顶点**(原型 534–535 行:dblclick 前两次 click 会多加 2 个点) | +| 键盘等效 | 坐标输入(0–100%)与鼠标绘制完全等效,含撤销与删除单点 | +| 待校准 | 画面分辨率/旋转变化后既有区域标记为待校准,**不静默失效也不自动改坐标** | +| 版本 | 区域版本与告警规则版本是不同对象;保存区域不发布规则 | + +### IX-018 草稿与跨系统上下文 + +**为什么是 P0**:T-004 任务书自己写明"后端系统边界不得迫使用户丢失当前摄像头或规则草稿上下文"。实测原型有三条路径会静默丢弃草稿:面包屑返回(502 行)、侧栏导航(493 行)、**切换绘制工具**(536 行 `points.length = 0`)。而 `clearPoints` 与 `discardDraft` 都有 `confirm`——同一类破坏性操作,三处有确认、三处没有。 + +| 项 | 约定 | +| --- | --- | +| 拦截范围 | 页内导航、面包屑、切换绘制工具、跳转 Bell、关闭标签页 | +| 一致性 | 所有丢弃草稿的路径使用**同一个**确认组件与措辞 | +| 深链 | Sense→Bell 与 Bell→Sense **双向**携带 `camera` + `zone`;原型目前只有 Bell→Sense 带 `return` 参数,反向缺失 | +| 返回 | 从 Bell 返回后草稿仍在;若期间区域被他人保存,提示冲突而非覆盖 | + +--- + +## 3. 全局章节需要收紧的两处 + +### 3.1 「无障碍与安全」——把对比度写成可验证的数字 + +现文:「文本和关键状态满足可读对比度」。建议改为: + +```markdown +- 正文与关键状态对比度 ≥ 4.5:1,大字号(≥18.66px 粗体或 ≥24px)≥ 3:1;**主操作按钮同样受此约束**。 +``` + +**实测依据**(对原型配色计算,非估计): + +| 用途 | 前景/背景 | 实测 | 判定 | +| --- | --- | --- | --- | +| `.btn-primary` 主 CTA | `#ffffff` / `#0ea5e9` | **2.77:1** | ❌ 深浅两个主题都不过(浅色主题未覆盖 `--primary-strong`) | +| 浅色主题 `--subtle` | `#718096` / `#ffffff` | **4.02:1** | ❌ 用于 `.nav-label`、搜索图标 | +| 其余抽查 6 项 | — | 4.6–16.3:1 | ✅ | + +主按钮那条影响最大:「添加摄像头」「保存区域版本」「保存为待激活」全是它。修法是把 `--primary-strong` 压到 `#0369a1` 一带(≈5.9:1),或主按钮改深底浅字。 + +### 3.2 「无障碍与安全」——补三条可测项 + +原型实测出的问题,与其修原型不如钉进清单(生产要重写): + +```markdown +- 当前导航项使用 `aria-current="page"`;不得用空值属性表达(空串等于 false)。 +- 图标按钮在任何断点下都必须保留可访问名;隐藏文字标签时须提供 aria-label。 +- 采用 tab 模式时必须完整:`role="tabpanel"` + `aria-controls` 关联 + 方向键导航,不做半套。 +``` + +对应原型位置:`aria-current` 见 489 行 `toggleAttribute`;图标按钮见 236 行 `≤1180px` 隐藏 `.nav span`;tab 半套见 372–377 与 503–507 行。 + +--- + +## 4. 不进清单、但要回原型补的 + +| # | 内容 | 处理 | +| --- | --- | --- | +| 1 | 设备列表分页控件 | IX-003 已覆盖,仅原型漏画 | +| 2 | 「推理绑定 16/16」画成 100% 满格紫条 | 正常态显示成满载,易误读为告警。换表现,不进清单 | +| 3 | 分片容量 `8/32` 的 **32** 无出处 | 《08》只定义站点 16 默认 / 128 上限,未定义单分片容量。**要么把 `media_shard.max_streams` 补进《08》§3,要么原型改用文档里的数**——两个分片 ×32 = 64,与站点上限 128 也对不齐 | + +--- + +## 5. 建议的落地顺序 + +1. IX-014(模态)先定——它影响导航命名与表结构,**建议整页重生成原型而非打补丁** +2. IX-015 / IX-016 补进原型(停用动作 + 隐私区域拒绝态),二者都只是加控件与一个拒绝态 +3. IX-017 / IX-018 可以只写清单不改原型——都是行为约定,生产实现时按清单做 +4. §3 两处全局收紧直接合入 +5. §4 第 3 条的分片容量需要一个数字决定,然后同步《08》 diff --git a/docs/raw/archive/2026-08-04/11-Sense原型-第二轮缺口-Claude原稿.md b/docs/raw/archive/2026-08-04/11-Sense原型-第二轮缺口-Claude原稿.md new file mode 100644 index 0000000..53d7e4c --- /dev/null +++ b/docs/raw/archive/2026-08-04/11-Sense原型-第二轮缺口-Claude原稿.md @@ -0,0 +1,136 @@ +# Sense 原型第二轮评审 + +> 基准:`yovision-T-004/docs/design/sense/index.html`(codex,2026-08-04 09:55,78 KB) +> 对标:`02-requirements`、`04-architecture`、`07-user-stories`、`08-interaction-checklist`(均于 09:41 更新)、`routes.md`、`api.md` +> 前置:《09-Sense原型评审-IX草稿》《10-Sense原型-功能模块缺口》 +> 日期:2026-08-04 + +--- + +## 0. 结论 + +| 轮次 | 内容 | 状态 | +| --- | --- | --- | +| 《09》行为缺口 | IX-014~018 + 无障碍三条 + 对比度 | ✅ **基本全部落地**,且清单版本比我的草稿更好 | +| 《10》模块缺口 | 6 个 P0 模块 | ❌ **0 / 6 落地**,导航仍是 5 项 | +| 本轮新增 | 由 modality/capabilities 模型带来的新问题 | ⚠️ **5 处**,见 §3 | + +--- + +## 1. 已落地的(有证据,不必再提) + +| 项 | 证据 | +| --- | --- | +| 一级入口改名「设备」,`modality` 成为一等公民 | 原型内 `modality` 出现 29 次;筛选含 `onvif`/`radar`/`mqtt` | +| `capabilities` 驱动详情页签 | 「能力」11 次;页签改为「连接与健康」而非「流与健康」 | +| 隐私区域准入 | `updatePrivacyAdmission()`;区域筛选含 `privacy`;导入文案含「区域隐私策略」 | +| **三种停用粒度**(IX-015) | `operationDialog`:暂停推理 / 停用接入 / 断开当前会话,每项带影响说明 + 幂等声明 + 审计声明 | +| tab 模式补完整 | `aria-controls` + `aria-selected` + roving `tabindex` | +| 草稿自动保存(IX-018) | 检出自动保存逻辑 | + +清单侧的 IX-015 拆成三粒度、IX-018 改成"自动保存 + 只在破坏性动作时拦截",都比我原草稿准确。 + +--- + +## 2. 《10》的模块缺口:一处未动 + +导航仍是 `运行总览 · 实时监控 · 设备 · 接入任务 · 系统状态`。逐项核对: + +| 《10》 | 缺口 | 本轮 | 关键词实测 | +| --- | --- | --- | --- | +| §1.2 | **对账器运维视图** | 未动 | 「孤儿」0 次、「退避」0 次;待收敛项仍不可下钻 | +| §1.5 | **权限与角色** | 未动 | 「角色」「只读」「权限」各 **0** 次 | +| §1.1 | 站点与 Area 管理 | 未动 | 「站点」仅顶栏 1 次;无 Area 增删改 | +| §1.3 | 待激活闭环 | 未动 | 筛选仍无「待激活」 | +| §1.4 | 凭据更新 | 未动 | 仍只有「已安全保存,页面不可见」,无写入路径 | +| §1.6 | 配额降级态 | 未动 | 状态演示仍是 normal/loading/empty/error 四态 | +| §2.1 | 边缘节点与隧道 | 未动 | 「隧道」0 次、「补传」0 次 | +| §2.3/2.4 | 主子码流切换 / 分片迁移 | 未动 | 「主码流」0 次、「迁移」0 次 | +| — | 设备列表分页(IX-003 明确要求) | 未动 | 「分页」0 次 | + +不重复推导,理由见《10》。**优先级不变:对账器视图 > 权限 > 站点与 Area。** + +--- + +## 3. 本轮更新新产生 / 新暴露的 5 处 + +### 3.1 `capabilities` 成了一等公民,却没有产生它的流程 ⚠️ P0 + +`capabilities` 现在决定详情页显示哪些页签——这是正确的设计。但**谁写入 capabilities?** + +原型的「测试连接」仍然只是一次性反馈("2 个 Profile,时间漂移 +0.4s"),结果没有落地成设备的持久属性。于是 `capabilities` 变成一个没有来源的字段。 + +而且它会**变化**:固件升级后可能新支持 ONVIF 事件订阅,换 Profile 后分辨率变化会让检测区域待校准(IX-017 已覆盖后半段,但没覆盖能力本身的变化)。 + +| 需要什么 | +| --- | +| 探测结果落地为设备的 `capabilities`,详情页「设备能力」区可见 | +| **重新探测**动作,以及探测结果与既有 `capabilities` 的**差异提示** | +| 能力降级的处置:原本支持事件订阅、现在探测不到了,依赖它的设备型触发怎么办 | +| 与采购白名单关联(US-007 要求形成白名单,现在白名单和设备台账没有连接) | + +### 3.2 modality 可选 radar,但适配器 M6 才有 ⚠️ P0 + +`02-requirements` §3.1 写明: + +> M1~M5 只完整实现 video 适配器,M6 再接入非视频设备,但不得因此把数据模型和一级信息架构写死为摄像头。 + +原型的模态下拉已经能选 `radar`/`mqtt`。**那么现在选了会怎样?** 如果能一路添加成功,原型就在承诺一个 M6 才有的能力;如果直接不可选,又违背了"信息架构不写死为摄像头"。 + +正解是第三种状态:**模态已建模、适配器未就绪**——可以录入、进台账、占位、参与隐私准入校验,但明确标注"适配器 M6 交付,当前不建立连接"。这个态现在不存在。 + +### 3.3 「暂停推理」的措辞与实际机制不符 ⚠️ P1 + +对话框写: + +> **暂停推理**:保留媒体接入与实时预览,只停止新推理任务 + +但《03》§2.1 的机制是**卸载推理 source**,而且原文特别警告: + +> `sourceOnDemand: yes` 的语义是「有 reader 才拉流」,而**推理 source 挂上去就是一个 reader**。因此「暂停分析」必须通过**卸载 source** 实现,不能只在推理插件里 `return`——后者会让 mediamtx 持续拉流、带宽白烧,而监控上看起来一切正常。 + +「停止新推理任务」这个措辞暗示的正是被明令禁止的那种实现(在推理侧跳过)。原型是 IX 的输入物,措辞会直接变成实现者的心智模型。 + +**建议改为**:「解除推理侧对该路的订阅;无其他观看者时上游自动停止拉流」——同时把"是否仍在拉流"作为可观察结果显示,这正是那条血泪教训要防的。 + +### 3.4 Area 策略可校验,但没有地方修改策略 ⚠️ P1 + +隐私准入在**添加**路径上做对了。但 IX-016 还要求: + +> 已有设备遇到区域策略变化时进入**显式处置流程**,不静默留存或停用 + +这个流程的**触发点**——把某个 Area 从 `video_allowed` 改成 `non_imaging_only`——在 UI 上不存在,因为 Area 根本不可管理(《10》§1.1)。等于规则写好了但没有触发它的按钮。 + +同理,IX-016 的「策略读取失败时拒绝新变更并告警」也需要一个降级态,与《10》§1.6 的配额降级是同类问题:**读故障 vs 写故障表现完全不同**,而状态演示仍只有四态。 + +### 3.5 `api.md` 缺一行:Sense → Bell 的审计投递 ⚠️ P1(文档缺口,非原型缺口) + +原型现在多处承诺审计:「每次请求均审计」、执行操作后「已记录本次审计」。 + +但架构 §2 定 Bell 是审计真相源,而 `api.md` §2「待冻结的内部接口」表只有五行: + +``` +Sense → Bell 读取站点视频配额 +Bell → Sense 请求事件证据 / pre-roll 切片 +Bell → Brain outcome / 误报反馈 +Sense → Brain 流绑定与设备型触发 +Worker → 控制面 注册、心跳、容量 +``` + +**没有 Sense → Bell 的审计投递。** 于是原型承诺的审计要么落在 Sense 本地(架构说不行,Bell 才是真相源),要么走一条没定义的接口。这行需要补进 `api.md`,并明确:异步还是同步、Bell 不可达时 Sense 的操作是否仍然执行(我的建议:**执行,审计落本地队列重传**,与 Brain 投递失败的处理一致)。 + +--- + +## 4. 建议顺序 + +| 顺序 | 做什么 | 理由 | +| --- | --- | --- | +| 1 | **对账器运维视图**(《10》§1.2) | 两轮未动,仍是单点最大缺口。Sense 的存在理由在 UI 上等于不存在 | +| 2 | **权限与角色**(《10》§1.5) | 决定页面上有没有按钮,是 IA 问题;两轮为 0 | +| 3 | **capabilities 的产生流程**(§3.1) | 本轮新引入的字段没有来源,会变成永远为空的装饰 | +| 4 | **站点与 Area 管理**(《10》§1.1 + §3.4) | 现在有了明确触发点:改 `capture_policy` 需要显式处置流程 | +| 5 | 「暂停推理」措辞(§3.3) | 一句话的改动,但防的是一个会烧带宽且监控看不出来的实现错误 | +| 6 | `api.md` 补审计接口行(§3.5) | 文档改动,不影响原型 | +| 7 | 模态适配器未就绪态(§3.2)、配额/策略降级态、分页 | 补齐 | + +> 第 1、2、4 项都是**改信息架构**,建议合并进同一次原型重生成。这是第二次提出——分次打补丁的成本会持续累积。 diff --git a/docs/raw/archive/2026-08-04/12-Sense原型-待办清单-Claude原稿.md b/docs/raw/archive/2026-08-04/12-Sense原型-待办清单-Claude原稿.md new file mode 100644 index 0000000..a7ca8d7 --- /dev/null +++ b/docs/raw/archive/2026-08-04/12-Sense原型-待办清单-Claude原稿.md @@ -0,0 +1,255 @@ +# Sense 原型待办清单(合并 09 / 10 / 11) + +> 合并来源:《09-Sense原型评审-IX草稿》《10-Sense原型-功能模块缺口》《11-Sense原型-第二轮缺口》 +> 基准:`yovision-T-004/docs/design/sense/index.html`(2026-08-04 09:55) +> 用途:给 codex 的单一执行清单。理由与推导见来源文档,本文只给**做什么 + 依据 + 验收**。 +> 日期:2026-08-04 + +--- + +## 0. 使用说明 + +- 编号 `S-xx` 稳定,后续讨论只引用编号。 +- **A 组必须一次重生成**,不要逐项打补丁——三项都改信息架构,分次改的返工成本已经累积两轮。 +- **写入范围**:T-004 的 `write_paths` 只含 `docs/tasks/T-004.md`、`docs/design/sense/index.html`、`docs/design/bell/index.html`。标记「⚠️ 超出 write_paths」的条目**需另开任务**,不要在本任务内改。 +- 优先级:**P0** = M2 出口必需;**P1** = M2 内补齐;**P2** = 只留信息架构位,不实现。 + +--- + +## 1. 已完成(核对用,不执行) + +第一轮《09》的全部条目已落地,实测确认: + +| 项 | 验证方式 | 结果 | +| --- | --- | --- | +| IX-014 modality 建模与「设备」改名 | `modality` 出现 29 次;筛选含「视频 / 雷达」,添加对话框可选「视频设备 / 毫米波雷达」 | ✅ | +| IX-014 capabilities 驱动页签 | 页签改为「连接与健康」 | ✅ | +| IX-015 三种停用粒度 | `operationDialog`:暂停推理 / 停用接入 / 断开会话,各带影响说明 + 幂等 + 审计声明 | ✅ | +| IX-016 隐私准入(新增路径) | `updatePrivacyAdmission()`;区域筛选含 privacy | ✅ | +| IX-017 警戒线方向 | 检出 marker / 反转相关实现 | ✅ | +| IX-018 草稿自动保存 | 检出自动保存逻辑 | ✅ | +| a11y:tab 模式 | `aria-controls` + `aria-selected` + roving `tabindex` | ✅ | +| **对比度:主按钮** | `--primary-strong` 改为 `#0369a1` / `#075985` | ✅ **5.93:1 / 7.56:1**(原 2.77:1) | + +--- + +## 2. A 组 · 信息架构级(P0,一次重生成) + +导航从 5 项扩到 8 项: + +``` +运行总览 · 实时监控 · 设备 · 接入任务 · 【站点与区域】 · 【运维】 · 系统状态 · 【审计】 +顶栏补:站点切换器 · 当前用户与角色 +``` + +### S-01 运维视图:对账队列 · P0 + +**两轮未动,单点最大缺口。** 总览的「待收敛项」目前不可下钻;对账器是 Sense 区别于普通 NVR 的全部理由,UI 上等于不存在。 + +| 必须包含 | 依据 | +| --- | --- | +| 未收敛项列表,逐项显示**期望态 vs 实际态的具体差异** | 架构 §7「PostgreSQL 是期望态真相源」 | +| 每项的重试次数、当前退避间隔、下次重试时间 | 架构 §7「幂等、指数退避、限制并发」 | +| **孤儿资源列表 + 10% 安全闸触发告警** | 架构 §7「孤儿删除必须有 10% 安全闸和人工可观察指标」 | +| 单项手动触发收敛(现有「立即对账」是全局的,粒度过粗) | — | +| 收敛持续失败的升级路径:多久算异常、通知谁 | 需求 §3.5 运维告警独立 | + +**验收**:从总览「待收敛项 N」可点击进入;任选一项能看到差异、退避与下次重试时间;孤儿列表与安全闸状态可见。 + +### S-02 权限与角色 · P0 + +**两轮为 0。**「角色」「只读」「权限」在原型中各出现 0 次。权限决定页面上**有没有**按钮,是信息架构问题,不是加一层。 + +| 必须包含 | 依据 | +| --- | --- | +| 顶栏显示当前用户与角色 | 需求 §3.5 五角色 RBAC | +| 只读角色下:添加 / 停用 / 删除 / 更新凭据**不出现**(不是置灰) | `routes.md` 路由守卫 | +| 越权深链的统一拒绝态 | `routes.md`「深链打开无权限或已删除资源时给出统一、安全的反馈」 | +| 站点管理员只能看到自己站点 | 需求 §3.5 | +| 角色切换器(原型演示用,同状态演示下拉的做法) | — | + +**验收**:切到「只读」角色后,设备页所有写操作控件消失;越权深链显示统一拒绝态。 + +### S-03 站点与区域(Area)管理 · P0 + +实体链 `Tenant → Site → Area/Device` 目前断了两级:Site 是顶栏一行静态字,Area 只是一个下拉选项。 + +| 必须包含 | 依据 | +| --- | --- | +| 站点列表:配额已用/上限、在线率、未收敛数、边缘节点状态 | `routes.md` `/sites` | +| 顶栏站点切换器,切换后所有列表按站点过滤 | 架构 §3 SaaS-ready 边界 | +| 配额只读展示 + 标注「由 Bell 持有」 | 架构 §5 第 7 条 | +| **Area 增删改,含 `capture_policy = video_allowed \| non_imaging_only` 的编辑** | 需求 §3.1;架构 §8 | +| **改 `capture_policy` 时的显式处置流程**(该 Area 已有成像设备怎么办) | IX-016「不静默留存或停用」——规则已写,触发点当前不存在 | + +**验收**:能新建 Area 并设为 `non_imaging_only`;把一个已有摄像头的 Area 改成该策略时,出现显式处置流程而非静默通过。 + +### S-04 审计入口 · P1 + +原型多处承诺「每次请求均审计」,但没有查询入口。 + +**必须包含**:设备操作审计列表(时间 / 操作 / 对象 / 执行人 / 结果),可按设备、操作类型、时间筛选;标注真相源在 Bell。 +**验收**:从设备详情「操作记录」可跳到全局审计页并保留该设备筛选。 + +--- + +## 3. B 组 · 页内新增(不改 IA) + +### S-05 capabilities 的产生流程 · P0 + +本轮新引入的 `capabilities` 决定页签显示,但**没有写入它的流程**——「测试连接」仍只是一次性 toast,结果不落地。 + +| 必须包含 | +| --- | +| 探测结果落地为设备持久属性,详情页「设备能力」区可见(厂商、型号、固件、认证方式、Profile 列表、是否支持校时、**是否支持 ONVIF 事件订阅**) | +| **重新探测**动作 + 与既有 `capabilities` 的**差异提示** | +| 能力降级处置:原本支持事件订阅、重探后不支持了,依赖它的设备型触发怎么办 | +| 与采购白名单关联(US-007 要求形成白名单,当前白名单与台账无连接) | + +**验收**:添加设备后「设备能力」区有内容;重新探测能显示"新增/消失了哪些能力"。 + +### S-06 模态适配器未就绪态 · P0 + +需求 §3.1:M1~M5 只完整实现 video 适配器,M6 才接非视频;但信息架构不得写死为摄像头。 + +现在模态下拉已能选 `radar`/`mqtt`——**选了会怎样没有定义**。能一路添加成功就是承诺 M6 能力;直接禁用又违背 IA 要求。 + +**需要第三态**:模态已建模、适配器未就绪——可录入、进台账、占位、参与隐私准入校验,但明确标注「适配器 M6 交付,当前不建立连接」,且不计入视频配额。 +**验收**:选 radar 添加后设备进入台账并显示该标注;实际态不显示为「在线」或「离线」,而是「适配器未就绪」。 + +### S-07 待激活闭环 · P0 + +需求 §3.1 明确的中间态,但设备表无待激活行、筛选无该项、无处置流程。 + +**必须包含**:待激活作为一级筛选项与独立计数;激活流程(重新探测 / 校时 / 配额复核);批量激活与逐项结果;长期待激活的过期策略。 +**验收**:筛选出待激活设备并完成一次激活,失败时可看到具体原因。 + +### S-08 凭据更新与认证失败恢复 · P0 + +详情页「凭据:已安全保存,页面不可见」——处理正确,但**只有读没有写**。现场改密码是最高频运维事件。 + +**必须包含**:单设备「更新凭据」(只写不读,不回显已存值);**认证失败作为独立实际态**(区别于「离线」,原因和处置都不同);批量更新凭据;更新后自动重试接入且结果可见。 +**验收**:认证失败设备在列表中可识别,能就地更新凭据并看到重试结果。 + +### S-09 降级态:配额不可读 / 区域策略不可读 · P0 + +状态演示仍是 `normal / loading / empty / error` 四态。缺的是**写故障**——与「边缘节点不可达」(读故障)表现完全不同:视频照常播、列表照常看,只有写操作被拒。 + +| 必须包含 | 依据 | +| --- | --- | +| 配额不可读:横幅说明「当前无法新增或启用设备,已有视频不受影响」,添加/激活按钮禁用并说明原因 | `api.md` §2;架构 §7 | +| 区域策略不可读:拒绝新的成像设备变更并告警,已有链路不静默停用 | IX-016 | + +**验收**:状态演示下拉新增这两态,切换后写操作被拒而视频与列表正常。 + +### S-10 边缘节点与隧道 · P1 + +侧栏底部只有一行 `sense-edge-01 · 在线`。但**控制面/数据面分离**是整个 NAT 方案的核心,UI 不体现等于白设计。 + +**必须包含**:边缘节点列表(版本、在线时长、隧道状态、承载设备数);**隧道断开但视频仍在推**的明确表达;本地缓存水位 + 断网恢复后的补传进度;节点升级/重启动作。 +**依据**:需求 §3.5「断网时边缘缓存事件,恢复后补传」。 +**验收**:能演示「隧道断开 / 视频正常」这个组合态,并显示补传队列长度。 + +### S-11 主 / 子码流切换 · P1 + +详情写死「子码流 704×576 · 5 FPS」,无切换动作。码流是容量的直接变量(架构 §6:`max_streams` 由码率决定),切换还会踢掉当前发布者,需影响范围提示。 + +### S-12 分片详情与设备迁移 · P1 + +分片健康只读。需要:分片详情(承载设备、实际码率、重连历史)、设备跨分片迁移(会中断该路,需确认)、单分片故障的影响范围展示(架构 §6「单分片故障不能扩散」)。 + +### S-13 批量任务列表与逐项结果 · P1 + +「当前任务」是单卡片,「查看逐项结果」是死按钮。IX-001 要求逐行错误、重复序列号、待激活、确认写入。 + +**必须包含**:任务列表(历史可查、可重试、可导出错误清单);逐项结果页(每行校验结果、失败原因、单行重试);上传前本地预校验结果页;部分成功语义(8 路里 5 成功 3 失败,成功的已生效)。 + +### S-14 Sense 运维告警列表 · P1 + +总览「今日设备告警 3」与「与业务预警分开」的说明写得对,但点不进去。 + +**必须包含**:运维告警列表(离线、时间漂移超阈、收敛失败、分片异常、隧道断开);运维侧的静默与通知配置(与 Bell 的业务静默是两套);明确标注「不会推给家属/值班员」。 +**依据**:需求 §3.4「业务预警与运维告警使用不同通道和值班配置」。 + +### S-15 设备列表分页 · P1 + +「分页」在原型中出现 0 次。IX-003 明确要求,阶段 M2/M4。含批量选择的跨页语义(「全选」到底选了当前页还是全部)。 + +### S-16 时间显示口径 · P1 + +系统内同时存在三个时钟:设备时间(可能漂 +3.8s)、服务器时间(期望态真相源)、浏览器本地时间。而「时间漂移」是原型自己列的一级指标,三者不区分会导致运维误判。 + +**约定**:统一显示服务器时间 + 时区标注;设备时间只出现在漂移列;相对时间悬停显示完整时间戳。 + +### S-17 租户维度 · P1 + +首期一客户一套私有实例,但架构 §3 要求「从第一版携带 `tenant_id` 并保持 SaaS-ready 边界」。不需要租户切换器,但需要当前租户可见、且所有列表按租户过滤这件事在 UI 上成立。 + +--- + +## 4. C 组 · 措辞与文档 + +### S-18 「暂停推理」措辞 · P0(一句话,但防的是重大实现错误) + +现文:「只停止新推理任务」。这暗示的正是《03》§2.1 明令禁止的实现: + +> `sourceOnDemand: yes` 的语义是「有 reader 才拉流」,而**推理 source 挂上去就是一个 reader**。因此「暂停分析」必须通过**卸载 source** 实现,不能只在推理插件里 `return`——后者会让 mediamtx 持续拉流、带宽白烧,**而监控上看起来一切正常**。 + +**改为**:「解除推理侧对该路的订阅;无其他观看者时上游自动停止拉流」。 +并把「是否仍在拉流」作为可观察结果显示——这正是那条教训要防的。 + +### S-19 `media_shard.max_streams` 标注 · P2 + +分片显示 `8/32`。架构 §6 写「初始建议 32,可按故障域降为 16,最终由压测确定」——数值有据,但 UI 需标注它是**可配置项**而非固定值,避免被当成硬上限。 + +### S-20 「推理绑定 16/16」的视觉 · P2 + +正常状态画成 100% 满格紫条,易被误读为告警/满载。换表现。 + +### S-21 ⚠️ 超出 write_paths:`api.md` 补审计投递接口 · P1 + +原型承诺「每次请求均审计」,架构 §2 定 Bell 是审计真相源,但 `api.md` §2 的五行内部接口**没有 Sense → Bell 的审计投递**。 + +需补一行并明确失败语义。**建议**:Bell 不可达时操作照常执行、审计落本地队列重传——与 Brain 投递失败的处理保持一致(架构 §7)。 +**处理方式**:另开任务,不在 T-004 内改。 + +--- + +## 5. D 组 · 只留信息架构位(P2,不实现) + +避免 M3 时整页重做。三项各留一个导航位或详情页签占位即可: + +| 编号 | 模块 | 依据 | +| --- | --- | --- | +| S-22 | 推理绑定视图(设备 ↔ worker 绑定、注册/心跳/容量、绑定失败态) | `api.md` §2「Worker → 控制面」 | +| S-23 | pre-roll 切片运维(请求量、失败率、耗时) | 架构 §5 第 3 条 | +| S-24 | 设备型触发源配置(雷达/门磁/按钮/ONVIF 事件订阅) | 《08》§3 边界 2;与 S-06 同源 | + +--- + +## 6. 执行顺序 + +| 批次 | 条目 | 说明 | +| --- | --- | --- | +| **第 1 批** | S-01 · S-02 · S-03 · S-04 | **一次整页重生成**。四项都改信息架构,分次打补丁的返工成本已累积两轮 | +| **第 2 批** | S-05 · S-06 · S-07 · S-08 · S-09 · S-18 | P0 页内新增 + 措辞。S-18 只是改文案,可随手带上 | +| **第 3 批** | S-10 ~ S-17 | P1,M2 出口前补齐 | +| **第 4 批** | S-19 · S-20 · S-22 · S-23 · S-24 | P2,留位与视觉 | +| **独立任务** | S-21 | 超出 T-004 write_paths | + +--- + +## 7. 总验收 + +第 1、2 批完成后应满足: + +- [ ] 导航 8 项;顶栏有站点切换器、当前用户与角色 +- [ ] 「待收敛项」可下钻,能看到期望态/实际态差异、退避与孤儿资源 +- [ ] 切到只读角色,设备页所有写操作控件**消失**(非置灰) +- [ ] 能新建 `non_imaging_only` 的 Area,并触发既有成像设备的显式处置流程 +- [ ] 「设备能力」区有内容,重新探测能显示能力差异 +- [ ] 选 radar 添加后进入台账,实际态为「适配器未就绪」,不计入视频配额 +- [ ] 待激活可筛选、可激活、失败有原因 +- [ ] 认证失败可识别、可就地更新凭据、可看到重试结果 +- [ ] 状态演示含「配额不可读」「区域策略不可读」,写操作被拒而视频与列表正常 +- [ ] 「暂停推理」措辞已改,且能观察到「是否仍在拉流」 diff --git a/docs/raw/archive/2026-08-04/14-Bell原型评审-Claude原稿.md b/docs/raw/archive/2026-08-04/14-Bell原型评审-Claude原稿.md new file mode 100644 index 0000000..4fd9d63 --- /dev/null +++ b/docs/raw/archive/2026-08-04/14-Bell原型评审-Claude原稿.md @@ -0,0 +1,165 @@ +# Bell 原型评审 + +> 基准:`yovision-T-004/docs/design/bell/index.html`(codex,2026-08-04 09:54,525 行 / 57 KB) +> 对标:T-004 任务书方案 4 与不可变约束、`02-requirements` §3.3/§3.4/§8、`04-architecture` §8、IX-005~IX-013、`routes.md` +> 日期:2026-08-04 + +--- + +## 0. 总评 + +**质量明显高于 Sense 第一版。** 七项导航(值班台 / 事件中心 / 规则策略 / 升级链 / 运营报表 / 站点与 Area / 审计)基本覆盖 `routes.md` 的页面职责,而且几处最容易做错的领域约束都做对了。 + +问题集中在三点:**投递事实少了一态**、**事件与 Alert 的关联无法双向导航**、**值班场景缺交接班**。另外 Area 的归属需要一次跨文档裁决——并且要修正我此前在《12》S-03 里的建议。 + +--- + +## 1. 做对的(点名保护,重写时别丢) + +| 项 | 证据 | +| --- | --- | +| **静默对话框** | 4h 写死在选项里标「(上限)」、原因必填、到期自动恢复,且明确**排除 S1 高危事件与设备离线运维告警** | +| **误报对话框** | 「这只会追加事件 outcome,不会修改原始事件事实和证据」;原因必填;进复核队列 | +| **规则对话框** | 场景模板 / 继承与覆盖 / 摄像头 / **检测区域带版本号 `ZONE-007 · v7`** / 生效时段 / 持续时间;试运行复选框**默认勾选**;主按钮是「保存并开始试运行」而不是「保存」 | +| 规则与区域解耦 | 「空间坐标由摄像头详情维护」「**区域版本变化不会绕过规则试运行或自动正式发布**」——精确回应 T-004 不可变约束 | +| **人脸能力零出现** | 全文 `人脸` 出现 **0** 次。IX-013 要求未授权租户「能力不存在而非按钮置灰」,零出现就是正确实现 | +| Area 策略对话框 | `capture_policy` 二选一、变更原因必填进审计、生成新策略版本;并写明「**Sense 投影同步前会显示旧版本,不允许绕过后端准入检查**」 | +| 策略冲突处置 | `policyConflictDialog` = IX-016 要求的「已有设备遇策略变化的显式处置流程」 | +| 弱网与权限状态 | 「结构化事件已到达,视频证据暂不可用」(渐进加载)、「没有查看此站点证据的权限」 | +| 投递时间线 | 三级链、每级时间、当前级「已送达,未确认」、下一级「预计 23:16:10 · 尚未发送」 | + +--- + +## 2. P0 + +### 2.1 「已发出」与「已送达」被合并了 + +**证据**:全文 `已发出` 出现 **0** 次,`已送达` 4 次,`已看到` 1 次。 + +**依据**: + +- `02-requirements` §3.4:「区分**已发出、已送达、已看到**;**没有回执不能当成功**」 +- T-004 不可变约束:「Alert 的**首次投递、送达、看到、ack 和升级**必须分开展示」 + +**问题**:时间线目前只有「已送达」这一档,无法表达**发出了但没拿到回执**——而这恰恰是告警系统最重要的失败态。短信网关返回 `202 Accepted` 不等于用户手机收到;语音呼叫接通不等于有人听。把 sent 直接显示成 delivered,正是那句「没有回执不能当成功」要防的事。 + +**建议**:投递时间线每一级至少四态,且**未拿到回执时必须显式呈现**: + +``` +已发出 23:14:10 → 已送达 23:14:12 → 已看到 23:14:31 → 已确认 23:14:40 +已发出 23:14:13 → ⚠ 未收到回执(已等待 42s) +``` + +对应 IX-007「失败不能伪装成功」,建议把这条从抽象要求细化为四态时间线的明确规格。 + +### 2.2 事件与 Alert 的关联无法双向导航 + +**依据**:`04-architecture` §8 明写—— + +> Event 与 Alert 不合并:**一个事件可触发多次预警与投递,一次预警也可聚合多个事件**。 + +**问题**:原型有「事件中心」和「值班台(待处置预警)」两个入口,方向是对的。但看不到这一对多/多对一关系的表达: + +- 从一条 Alert 打开,它聚合了哪几条 Event? +- 从一条 Event 打开,它触发过几次 Alert、分别什么结局? + +这是 Bell 最核心的数据模型。如果 UI 上表达不出来,实现时极易退化成 Event 与 Alert 一对一,而聚合、去重、已处置抑制全部依赖这个多对多关系。 + +**建议**:Alert 详情增加「关联事件」列表(含聚合原因:同设备冷却 / 同站点聚合 / 已处置抑制);Event 详情增加「触发的预警」列表(含每次的最终状态)。两边互为深链。 + +### 2.3 Area 的归属需要裁决 —— 并修正我此前的建议 + +**现状**:Bell 原型把 Area 的 CRUD 与 `capture_policy` 编辑放在「站点与 Area」页。 + +**我的判断:这个归属比我此前的建议更对。** 我在《12》S-03 里把「站点与 Area 管理」列为 Sense 的待办,那是错的——Area 是带合规策略的**组织实体**,而 Bell 拥有 Site(配额真相源)、租户、RBAC 和审计。Area 作为 Site 的子级归 Bell 一致性更好。 + +**但由此产生两个后果,必须一并处理**: + +1. **《12》S-03 需改写**:Sense 侧应为 Area **只读** + 设备写路径的准入拒绝;CRUD 归 Bell。原文的「Area 增删改」要移出 Sense 待办 +2. **跨 schema 读从一处变成两处**(配额 + Area 策略)。Bell 原型自己写了「Sense 投影同步前会显示旧版本」——这个窗口期正是投影方案的固有代价。而《13》A-2 建议的同库只读视图**可以直接消除它**:视图无同步延迟,Sense 读到的永远是当前策略版本 + +A-2 的价值因此翻倍,建议提到裁决队列最前。 + +--- + +## 3. P1 + +### 3.1 缺交接班 + +`routes.md`「值班台/大屏」节明写:「声光提示、ack 与**交接班记录**」。全文 `交接班` 出现 **0** 次。 + +这是值班室最真实的场景:22:00 换班,上一班未处置的预警怎么移交、新一班如何确认接手。没有交接班,「有人负责」这个产品承诺在班次边界上断掉。 + +**建议**:值班台增加交接班动作——列出未关闭预警、交接人与接手人、接手确认进审计;交接期间的升级链不中断。 + +### 3.2 并发 ack 的结果未表达 + +IX-006 要求「并发 ack 有清晰结果」。两个值班员同时点 ack 会怎样,原型没有表达。 + +**建议**:明确为「先到者成为处置人,后到者收到明确提示并看到当前处置人」,而不是静默覆盖或双双成功。 + +### 3.3 重启续跑不可观测 + +`02-requirements` §3.4「进程重启后能续跑」、`04-architecture` §7「Alert 先落库再投递,进程重启恢复未完成升级链」。 + +这是一条很强的可靠性承诺,但 UI 上没有任何可验证的表达。运维无法确认它真的生效。 + +**建议**:升级时间线中标注「服务重启于 23:15:02,升级链已恢复」这类事件;系统状态页给出「待恢复升级链 N 条」的指标。 + +### 3.4 状态覆盖:多了两个好的,少了整组失败态 + +**实测状态演示**:`normal / loading / empty / denied / weak` —— 五态,比 Sense 的四态更好: + +- `denied` 无权限 → 对应 IX-013 +- `weak` 结构化事件已到、视频证据暂不可用 → 对应 App 节「弱网下先显示结构化事件,再渐进加载抓拍/视频」 + +这两个是一等演示态,不只是文案。 + +**但一个失败态都没有。** IX 清单「全局状态」节要求每个页面至少评估: + +> 初始、加载、空数据、成功、**部分成功、可重试失败、不可重试失败**;无权限、**会话过期、网络断开、后端超时、数据已被他人修改**。 + +Bell 覆盖了加载 / 空 / 无权限,缺整组失败语义。其中两个对 Bell 尤其关键: + +| 缺失态 | 为什么对 Bell 关键 | +| --- | --- | +| **数据已被他人修改** | 正是 §3.2 并发 ack 的表现形式,也是规则版本冲突的表现形式。缺它,两个问题都没有落点 | +| **可重试 / 不可重试失败** | 投递失败要区分「短信网关超时,会重试」与「号码无效,不会重试」。IX-007「失败不能伪装成功」的另一半 | + +**建议**:状态演示补 `conflict`(数据已被他人修改)与 `error-retryable` / `error-final` 两类失败态。 + +### 3.5 事件中心与审计缺分页 + +全文 `分页` 出现 **0** 次。`routes.md` 对 `/events` 要求分页与筛选,对 `/audit` 要求「只读、分页、按权限脱敏」。与 Sense 是同一个问题。 + +--- + +## 4. P2 + +### 4.1 规则回滚偏薄 + +`回滚` 出现 1 次。IX-011 要求「支持取消/回滚」。试运行做得很扎实,但从「已正式发布」回退到「试运行」或「上一版本」的路径没有展开。 + +### 4.2 报表口径未对齐验收要求 + +`02-requirements` §8 规定: + +> 效果指标**按规则分别报告召回率与每路每天误报数**;不使用跨场景统一「准确率」。 + +报表页目前是「近 7 日预警量」「处置结果」。这两个是运营口径,不是**验收口径**。而验收口径是要签进站点验收附件的,报表必须能直接出。 + +**建议**:报表页增加按规则维度的召回率与「每路每天误报数」,并显式标注「不提供跨场景统一准确率」——这句话本身就是对客户预期的管理。 + +--- + +## 5. 建议顺序 + +| 顺序 | 条目 | 理由 | +| --- | --- | --- | +| 1 | §2.1 投递四态 | 需求原文的硬要求,且是告警系统最重要的失败态 | +| 2 | §2.2 Event↔Alert 双向导航 | 核心数据模型,画不出来实现就会退化成一对一 | +| 3 | §2.3 Area 归属裁决 + 修订《12》S-03 + 提前 A-2 | 一次裁决消掉三处不一致 | +| 4 | §3.1 交接班 | 值班场景的真实断点 | +| 5 | §3.4 状态覆盖 | 补 `conflict` 态可同时给 §3.2 并发 ack 和规则版本冲突一个落点,一处改动解两个问题 | +| 6 | §3.2、§3.3、§3.5 | 并发 ack、重启续跑可观测、分页 | +| 6 | §4.1、§4.2 | 回滚与报表口径 | diff --git a/docs/tasks/T-005.md b/docs/tasks/T-005.md index 78deac2..483a474 100644 --- a/docs/tasks/T-005.md +++ b/docs/tasks/T-005.md @@ -3,7 +3,7 @@ id: T-005 title: 归档原型评审原稿并补录评审文档 phase: 0 deps: [T-004] -status: DOING +status: DONE created: 2026-08-04 issue: 10 context_ref: 697e652e9b9b884551850583712cdcd875c474b9 @@ -57,6 +57,13 @@ T-004 已将 Codex 复核后的 Sense/Bell 评审定稿合入 `main`,但主工 ## 执行记录 +### 2026-08-04 归档完成与验证 + +- 从远程备份提交 `2e6bf8e0ce80929b6756e0ecc11261cc9b2553a7` 恢复八份材料:`raw/10`、`raw/13`、`raw/15` 以原路径补录;`raw/08`、`raw/09`、`raw/11`、`raw/12`、`raw/14` 的本地版本以“评审前快照 / Claude原稿”名称归档到 `docs/raw/archive/2026-08-04/`。 +- 对八份新增文件逐一执行 Git blob 核对,全部与备份提交对应源文件一致;同时核对五份现行定稿,全部与 `context_ref` 对应 blob 一致,证明本任务没有覆盖 T-004 定稿。 +- `git diff --check` 与 `git diff --cached --check` 通过;`./init.ps1` 通过上下文/治理校验及 16 项治理单测。 +- 本任务只保存评审依据,不对新增评审建议作产品或架构裁决;T-005 状态更新为 `DONE`。 + ### 2026-08-04 领取 - dispatcher `ila` 已在 Issue #10 发布完整 CLAIM;claim 分支与工作分支均从 `697e652e9b9b884551850583712cdcd875c474b9` 创建。