77 lines
6.0 KiB
Markdown
77 lines
6.0 KiB
Markdown
---
|
||||
|
|
id: T-008
|
|||
|
|
title: 冻结 Sense 设备管理 API 与 Bell 配额只读投影契约
|
|||
|
|
phase: 2
|
|||
|
|
deps: [T-006]
|
|||
|
|
status: TODO
|
|||
|
|
created: 2026-08-07
|
|||
|
|
issue: null
|
|||
|
|
context_ref: null
|
|||
|
|
claim_branch: null
|
|||
|
|
work_branch: null
|
|||
|
|
write_paths:
|
|||
|
|
- docs/tasks/T-008.md
|
|||
|
|
- docs/contracts/
|
|||
|
|
- docs/api.md
|
|||
|
|
- docs/04-architecture.md
|
|||
|
|
- docs/06-tasks.md
|
|||
|
|
- docs/current-state.md
|
|||
|
|
- tests/test_sense_control_contract.py
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 问题 / 背景
|
|||
|
|
|
|||
|
|
T-006 已证明 Sense 能用 SQLite 期望态驱动 1 路真实摄像头与 4 路合成 RTSP 上游自动收敛,但设备只能通过实验室 `sense-lab` 直接播种数据库,尚无可供 Bell 管理面或受控集成方依赖的设备管理 HTTP 契约。站点配额仍只停留在“版本化内部 API 或只读投影”的二选一表述,也没有冻结跨 schema 的列签名、权限和失败语义。若直接实现 CRUD,会在 tenant 边界、批量结果、幂等、并发控制和配额所有权上形成临时接口并导致返工。
|
|||
|
|
|
|||
|
|
当前架构已确定首期使用一个 PostgreSQL 实例、`sense`/`bell` schema 分离。T-008 据此冻结 Sense v1 设备管理 OpenAPI,并把 Bell→Sense 配额同步裁决为版本化只读视图,而不是新增网络调用;未来分库必须发布新版本契约,不能静默改变 v1 语义。
|
|||
|
|
|
|||
|
|
## 关联需求与交互(如适用)
|
|||
|
|
|
|||
|
|
- 用户故事:US-001、US-002、US-008、US-009、US-010。
|
|||
|
|
- 交互清单:IX-001~IX-004、IX-013~IX-016、IX-019、IX-020。
|
|||
|
|
- 相关页面 / 路由:`/sites/:siteId/devices`、`/operations`;本任务只冻结后端契约,不修改已确认 HTML 原型。
|
|||
|
|
|
|||
|
|
## 方案
|
|||
|
|
|
|||
|
|
1. 在 `docs/contracts/` 新建契约说明、OpenAPI 3.1 JSON 和 `bell.site_quota_v1` PostgreSQL 只读视图签名;跨系统契约不放入某一系统的内部包。
|
|||
|
|
2. Sense HTTP v1 只管理设备期望态与收敛查询:单项创建/读取/修改/启停、强制分页列表、批量期望态变更和批量操作状态。Site/Area/RBAC/配额仍由 Bell 持有,Sense 不提供这些资源的 CRUD。
|
|||
|
|
3. tenant 从认证上下文确定,不能由请求 body/query 自报;资源不存在与越权使用一致响应。所有写操作定义幂等或 `If-Match` 并发保护,批量操作返回逐项结果且最多 128 项。
|
|||
|
|
4. `endpoint_ref`、`credential_ref` 仅允许作为写入字段且不得包含 userinfo;普通响应不回显两者、密码、完整流 URI、token 或 MediaMTX 管理细节。
|
|||
|
|
5. 配额视图由 Bell migration 创建并拥有,Sense 数据库角色只有 `SELECT`;列签名至少包含 tenant/site、`max_video_channels`、单调 `source_version` 与源更新时间。默认 16、范围 1~128;不可读取时拒绝新增/启用视频设备,已有链路保持不变。
|
|||
|
|
6. 增加标准库契约测试,校验 OpenAPI 结构、operationId 唯一、认证、分页、写入并发/幂等、批量上限、敏感字段 write-only、稳定错误码和配额 SQL 签名,并用负例证明关键约束会被拦截。
|
|||
|
|
7. 同步 `docs/api.md`、正式架构、路线图和当前状态,明确 v1 的兼容、废弃、迁移与分库退出路线。
|
|||
|
|
|
|||
|
|
## 不可变约束
|
|||
|
|
|
|||
|
|
- 阈值 / 数值边界:站点视频配额默认 16、有效范围 1~128;批量请求最多 128 项;列表必须分页且服务端上限不超过 100;16/128 均不是单机性能保证。
|
|||
|
|
- 判定式 / 状态转换:只统计 `desired_state=enabled` 且含 `video_capture` capability 的设备;新增/启用必须在同一写路径校验配额和 Area 投影;配额/策略不可读时只拒绝相关新写入,不停已有流;期望态写入成功不等于实际态已收敛。
|
|||
|
|
- 安全边界:tenant 只来自认证上下文;越权不泄露资源存在性;密码、完整连接串、credential ref、token 和内部堆栈不出现在普通响应/错误/示例;Sense 不写 Bell schema。
|
|||
|
|
- 既有契约:保留 `modality + capabilities`、`desired_state`/`actual_state`、generation/observed_generation、默认 16/最大 128、SQLite→PostgreSQL 迁移方向和 MediaMTX 独立数据面;`/healthz`、`/readyz` 继续是运维探针,不改成业务健康接口。
|
|||
|
|
|
|||
|
|
## 验收要点
|
|||
|
|
|
|||
|
|
- 任务相关验证:OpenAPI/SQL/说明互相引用且无悬空路径;运行 `python -m unittest tests.test_sense_control_contract`,正例全通过,关键约束负例均产生预期错误;JSON 可由标准库解析。
|
|||
|
|
- 完整门禁:运行 `./init.ps1`、`python scripts/validate_agent_context.py`、`python -m unittest discover -s tests -p "test_*.py"`、`python scripts/validate_harness_governance.py` 和 `git diff --check`,全部通过。
|
|||
|
|
- 人工 / 设备验收:不需要摄像头或 UI 人工验收;由架构/后端负责人核对资源所有权、失败语义、幂等/并发、隐私和未来分库退出路线。
|
|||
|
|
- 构建产物:`docs/contracts/sense-control-v1.openapi.json`、`docs/contracts/site-quota-v1.sql`、`docs/contracts/README.md`;本任务不生成部署二进制或数据库 migration。
|
|||
|
|
|
|||
|
|
## 边界(不改什么)
|
|||
|
|
|
|||
|
|
不实现 Sense HTTP handler、认证中间件、Bell 服务、PostgreSQL migration、配额 repository、Area 投影、审计 outbox/relay、管理 UI、16 路压测或 T-007 现场验收;不修改 Brain、事件 v0.1 契约、MediaMTX API 或已确认原型。实现工作由后续任务使用本契约完成。
|
|||
|
|
|
|||
|
|
## 协作约束
|
|||
|
|
|
|||
|
|
- 责任 Agent:由 dispatcher 分配。
|
|||
|
|
- 唯一写入者:同责任 Agent。
|
|||
|
|
- 委派:默认不启用。
|
|||
|
|
- Gitea:任务文件先进入默认分支,再创建唯一 Issue 并回填编号;领取时记录 `context_ref`、claim 与工作分支。
|
|||
|
|
|
|||
|
|
任何新增写路径先检查与其他活跃任务是否重叠;同一时刻只有一个 Agent 修改本任务的 `write_paths`。
|
|||
|
|
|
|||
|
|
## 执行记录
|
|||
|
|
|
|||
|
|
### 2026-08-07 任务定义
|
|||
|
|
|
|||
|
|
- 项目负责人要求落成并立即实施 T-008;任务按 M2 第一项契约门禁建立,依赖已完成的 T-006。
|
|||
|
|
- 配额跨系统读取基于“一个 PostgreSQL 实例、schema 分离”的既有前提,选择 `bell.site_quota_v1` 版本化只读视图;未来分库通过新版本替代,v1 不原地改成网络 API。
|