Files
QiuSW b70df147ea
Harness governance / validate (push) Has been cancelled
Harness governance / validate (pull_request) Has been cancelled
docs(contract): freeze Sense control API v1 [T-008]
2026-08-07 17:12:15 +08:00

90 lines
7.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: T-008
title: 冻结 Sense 设备管理 API 与 Bell 配额只读投影契约
phase: 2
deps: [T-006]
status: DONE
created: 2026-08-07
issue: 27
context_ref: cc47e1463849151bee3c349cc53971181e262043
claim_branch: claims/T-008
work_branch: agent/codex/T-008
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 discover -s tests -p "test_sense_control_contract.py"`,正例全通过,关键约束负例均产生预期错误;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 完成契约冻结
- 冻结 OpenAPI 3.1 `1.0.0`:7 个站点作用域/批量操作 endpoint,tenant 来自认证上下文,列表默认 50/最大 100,批量最大 128,并明确 Bearer、幂等键、ETag、逐项结果和稳定错误码。
- 设备创建使用 `modality + capabilities` 且 ID 由服务端生成;连接和凭据引用只写不读,v1 不暴露删除或 Site/Area/RBAC/配额 CRUD,也不把期望态受理误报为实际态收敛。
- 冻结 `bell.site_quota_v1` 的 5 列签名、`bell_app` 所有权及 `sense_app` 的最小 `USAGE + SELECT` 权限;配额默认 16、范围 1~128,投影失败只阻断相关新增/启用,已有链路保持不变。
- 增加 8 个标准库契约测试,正例覆盖 OpenAPI/SQL/说明一致性,负例证明缺失认证、客户端自报 tenant、101 页上限、129 项批量、敏感字段回显和 Bell 写权限都会被拒绝。
- `./init.ps1` 通过;`python -m unittest discover -s tests -p "test_*.py"` 共 26 项通过;JSON 标准库解析、上下文校验、治理校验和 `git diff --check` 均通过。本任务不需要摄像头或 UI 人工验收。
### 2026-08-07 领取任务
- dispatcher `ila` 将任务分配给 `codex`;`context_ref` 为 `cc47e1463849151bee3c349cc53971181e262043`,claim 为 `claims/T-008`,工作分支为 `agent/codex/T-008`。
- 接受既有写路径:`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`。
### 2026-08-07 任务定义
- 项目负责人要求落成并立即实施 T-008;任务按 M2 第一项契约门禁建立,依赖已完成的 T-006。
- 配额跨系统读取基于“一个 PostgreSQL 实例、schema 分离”的既有前提,选择 `bell.site_quota_v1` 版本化只读视图;未来分库通过新版本替代,v1 不原地改成网络 API。