docs(task): define T-010 area audit foundation
This commit is contained in:
@@ -0,0 +1,88 @@
|
|||||||
|
---
|
||||||
|
id: T-010
|
||||||
|
title: 建立 Area 准入投影与设备操作审计 Outbox 基础
|
||||||
|
phase: 2
|
||||||
|
deps: [T-009]
|
||||||
|
status: TODO
|
||||||
|
created: 2026-08-07
|
||||||
|
issue: null
|
||||||
|
context_ref: null
|
||||||
|
claim_branch: null
|
||||||
|
work_branch: null
|
||||||
|
write_paths:
|
||||||
|
- docs/tasks/T-010.md
|
||||||
|
- docs/contracts/
|
||||||
|
- deploy/postgres/
|
||||||
|
- scripts/test_postgres.ps1
|
||||||
|
- Sense/internal/device/
|
||||||
|
- Sense/internal/store/
|
||||||
|
- Sense/README.md
|
||||||
|
- docs/04-architecture.md
|
||||||
|
- docs/06-tasks.md
|
||||||
|
- docs/api.md
|
||||||
|
- docs/current-state.md
|
||||||
|
- tests/test_postgres_contract.py
|
||||||
|
- tests/test_area_audit_contract.py
|
||||||
|
---
|
||||||
|
|
||||||
|
## 问题 / 背景
|
||||||
|
|
||||||
|
T-008 已要求 Sense Control API v1 的设备创建携带 `area_id`,并冻结 `area_policy_unavailable` / `area_policy_denied` 错误语义;T-009 只实现了 Site 配额投影,没有冻结或实现 Area 策略投影。直接实现 HTTP handler 会让必填 Area 只能依赖临时数据或跳过隐私准入。
|
||||||
|
|
||||||
|
架构同时要求高风险设备写操作与持久化审计 Outbox 在 Sense 本地事务内一起提交,不能先改期望态再尽力记录日志。当前 repository 没有 Outbox;跨系统 relay 的字段、签名、确认与留存也尚未冻结。本任务先补齐 API 实现所需的 Area 准入和本地审计事务基础,不顺带实现 HTTP 或 Bell relay。
|
||||||
|
|
||||||
|
## 关联需求与交互(如适用)
|
||||||
|
|
||||||
|
- 用户故事:US-008、US-010。
|
||||||
|
- 交互清单:IX-016;`non_imaging_only` Area 不允许新增或启用成像设备,既有设备不得被静默停用。
|
||||||
|
- 相关公共契约:`docs/contracts/sense-control-v1.openapi.json`;本任务新增 Area 只读投影和本地设备审计事件契约,不修改已确认 Sense/Bell HTML 原型。
|
||||||
|
|
||||||
|
## 方案
|
||||||
|
|
||||||
|
1. 冻结 `bell.area_policy_v1` 六列只读视图:`tenant_id/site_id/area_id/capture_policy/source_version/source_updated_at`。Bell 源表只接受 `video_allowed | non_imaging_only`,Area 的 tenant、ID 和所属 Site 不可静默改写,业务更新由 trigger 单调递增版本。
|
||||||
|
2. 以增量 PostgreSQL migration 扩展 T-009:Bell 新增 Area 源表/视图;Sense 设备记录 `area_id` 和所用 Area 策略版本,并持久化每个 Area 已观察的最高版本。`sense_app` 只能读取视图,不能读写 Bell 源表或 trigger。
|
||||||
|
3. PostgreSQL repository 对所有新设备要求非空且匹配 tenant/site 的 Area;非成像设备可进入两种策略,具有 `video_capture` 能力的设备在创建时和从 disabled 切到 enabled 时都必须重读策略。投影缺失、非法、版本回退或不可读时失败关闭;策略为 `non_imaging_only` 时稳定拒绝成像变更。
|
||||||
|
4. Area 校验先于 Site 配额校验,使用事务级 advisory lock 串行化同 tenant/Area 的投影版本观察;已有 Site 配额锁和 16/128 路语义保持不变。策略或配额变化不得自动修改已有设备。
|
||||||
|
5. 冻结本地 `sense.device_operation_outbox` 事件结构并在 PostgreSQL repository 的设备创建、期望态受理路径中同事务写入。事件只保存逻辑 ID、主体、原因、trace、generation、所用投影版本和脱敏动作数据;不得包含 endpoint、credential、密码、完整 URI、token 或 MediaMTX 配置。
|
||||||
|
6. 相同期望态的重复受理不增加 generation,但仍产生一条独立审计事实。Outbox 写入失败必须回滚对应设备变更;默认内部调用使用受控 `system/sense` 主体,后续 T-011 HTTP handler 必须用认证结果覆盖主体上下文。
|
||||||
|
7. SQLite 继续作为 M1 实验室路径,不宣称具备生产 Area/Outbox 一致性。后续公共控制 API 只在 PostgreSQL 生产路径启用;本任务不为 SQLite 复制 Bell 真相或伪造策略。
|
||||||
|
8. 使用 `D:\pgsql17` 二进制启动随机回环端口的隔离 PostgreSQL 17.10 集群,验证 migration 重放、最小权限、tenant/site/Area 隔离、策略允许/拒绝、缺失/回退失败关闭、并发版本观察、Outbox 原子性与脱敏。
|
||||||
|
|
||||||
|
## 不可变约束
|
||||||
|
|
||||||
|
- Area 策略枚举固定为 `video_allowed | non_imaging_only`;本阶段以 `video_capture` capability 作为成像判定,不新建第二套 `captures_image` 真相。
|
||||||
|
- `bell.area_policy_v1` 的六列顺序、含义和 Bell 所有权是 v1 契约;Sense 只有 Bell schema `USAGE` 与该视图 `SELECT`,没有 Bell 源表读取或任何写权限。
|
||||||
|
- 同库只读视图是实时读取,不以 `source_updated_at` 的年龄误判长期未变化的合法 Area 为过期;缺失、非法值、版本回退和读取失败均视为投影不可用。未来改成缓存或远程投影时必须另行冻结 freshness 规则。
|
||||||
|
- PostgreSQL 新建设备必须具有非空 `area_id` 且与认证 tenant、路径 Site 对应。`non_imaging_only` 允许非成像设备,但拒绝成像设备的创建,即使创建时为 disabled;启用已有成像设备时必须再次检查。
|
||||||
|
- 策略不可用或拒绝只阻止相关新写入,不删除、不移动、不停用已有设备。策略与已有成像设备冲突时仍由 Bell 走显式迁移或取消流程。
|
||||||
|
- Site 视频配额默认 16、有效范围 1~128;Area 校验不能绕过、扩大或替代配额检查。
|
||||||
|
- 设备创建和期望态受理必须与 Outbox 同事务;相同期望态不增加 generation但仍审计。失败事务不得残留设备、状态、投影观察或 Outbox 半成品。
|
||||||
|
- 本地事件契约不等于 Bell relay 协议;transport、签名、批量确认、重放窗口和留存不得在实现中自行猜测。
|
||||||
|
- PostgreSQL 仍固定为 `17.10`,使用现有 `D:\pgsql17\bin`;自动验证不得读取、停止或修改 `D:\pgsql17\data` 和现有 5432 服务。
|
||||||
|
|
||||||
|
## 验收要点
|
||||||
|
|
||||||
|
- 任务相关验证:`./scripts/test_postgres.ps1 -PgRoot D:\pgsql17` 完成隔离集群、增量 migration 连续重放、SQL 权限断言和真实 repository 集成测试;`python -m unittest discover -s tests -p "test_area_audit_contract.py"` 校验投影/事件契约、权限负例和敏感字段禁入。
|
||||||
|
- 完整门禁:运行 `./init.ps1`、`python scripts/validate_agent_context.py`、`python -m unittest discover -s tests -p "test_*.py"`、`python scripts/validate_harness_governance.py`、`go -C Sense test ./...`、`go -C Sense vet ./...`、`go -C Sense build ./...` 和 `git diff --check`,全部通过。
|
||||||
|
- 人工 / 设备验收:不需要摄像头、UI 或客户现场;核对隔离脚本未引用现有 data 目录、5432 listener 前后不变,失败响应和 Outbox 不含秘密或完整连接信息。
|
||||||
|
- 构建产物:Area/审计契约、增量 PostgreSQL migration、Sense Area 准入与 Outbox 事务代码、集成/静态测试和同步文档。
|
||||||
|
|
||||||
|
## 边界(不改什么)
|
||||||
|
|
||||||
|
不实现 Sense HTTP handler、Bearer 认证、幂等收据、ETag/cursor、批量 operation、Bell Area 管理服务/UI、Outbox relay、签名/确认/留存、Area 迁移处置、SQLite 生产对等语义、Brain、MediaMTX、16 路容量测试或 T-007 现场验收;不修改已确认 HTML 原型。
|
||||||
|
|
||||||
|
## 协作约束
|
||||||
|
|
||||||
|
- 责任 Agent:由 dispatcher 分配。
|
||||||
|
- 唯一写入者:同责任 Agent。
|
||||||
|
- 委派:默认不启用。
|
||||||
|
- Gitea:任务文件先进入默认分支,再创建唯一 Issue 并回填编号;领取时记录 `context_ref`、claim / 工作分支和全部允许写路径。
|
||||||
|
|
||||||
|
任何新增写路径先检查与其他活跃任务是否重叠;同一时刻只有一个 Agent 修改本任务的 `write_paths`。
|
||||||
|
|
||||||
|
## 执行记录
|
||||||
|
|
||||||
|
### 2026-08-07 任务定义
|
||||||
|
|
||||||
|
- 项目负责人要求创建并立即实施 T-010;任务依赖已完成的 T-009,优先补齐 Area 与审计事务基础,再进入 Sense Control API v1 handler 实现。
|
||||||
|
- 采用已批准的两值 `capture_policy`,首期同 PostgreSQL 实例内使用 Bell 所有的版本化只读视图;Outbox 只冻结本地事件与原子写入,跨系统 relay 保持后续任务边界。
|
||||||
Reference in New Issue
Block a user