[SEN] 修复旧设备 capabilities 迁移到 JSONB #92

Closed
opened 2026-08-15 15:08:15 +08:00 by ila · 3 comments
Owner

状态

已完成

基本信息

  • 类型:缺陷 / PostgreSQL 兼容迁移
  • 任务类型:单项目独立任务
  • 主项目:Sense
  • 主 agent:Sense agent
  • 所属 Epic:#7
  • 所属 MVP:#8
  • 相关工单:#65、#70、#90
  • 前置工单:#65(已验收并合入 dev)
  • 独立运行:Brain、Bell 均不启动时完成复现和验收

原始需求与追溯

  • 来源:用户于 2026-08-15 运行 Sense\start_sense.bat 时报告 PostgreSQL SQLSTATE 42804:“字段 capabilities 的默认值不能转换成类型 jsonb”,随后确认“建工单,做”。
  • 只读诊断:目标数据库的 sense_devices.capabilities 为 text NOT NULL DEFAULT ''::text,有 1 条旧记录;值不是 JSON,但属于受支持的旧单值能力标识;2026081414000 迁移记录为 0。
  • 根因:#65 新模型要求 jsonb,GORM AutoMigrate 直接转换既有 text 字段时先被旧默认值阻断;只删除默认值仍会被旧单值数据阻断。

目标

让 Sense 设备迁移安全兼容旧 text capabilities 列,在保留设备记录语义的前提下转换为 JSONB,并让 Windows production 启动迁移可以继续。

做什么

  • 在 #65 设备迁移的 AutoMigrate 前增加 PostgreSQL 专用兼容步骤。
  • 仅当 sense_devices.capabilities 存在且类型不是 json/jsonb 时执行。
  • 事务内删除旧默认值,把空值转换为 [],把允许的旧单值转换为 JSON 数组,合法 JSON 数组保持数组。
  • 对未知、非法或非数组内容停止迁移并返回可定位错误,不静默猜测或丢弃。
  • 转为 jsonb 后设置 [] 默认值,再继续现有 AutoMigrate。
  • 增加隔离 PostgreSQL 回归测试,覆盖空表、旧单值、合法 JSON 数组、空字符串、未知非法值、幂等和事务回滚。
  • 更新迁移/排错 Wiki 与任务归档。

不做什么

不删除设备或凭据;不清空数据库;不修改客户配置;不自动备份生产库;不绕过迁移;不修改 Brain、Bell、共享契约或根级部署。

写路径

  • Sense/server/cmd/migrate/migration/version/2026081414000_device.go
  • Sense/server/cmd/migrate/migration/version/2026081414000_device_test.go
  • Sense/server/app/sense/device/models/device.go(仅在默认表达式确需调整时)
  • Wiki Troubleshooting
  • docs/06-troubleshooting.md
  • docs/task/<本工单归档>.md
  • wiki-docs.json

禁止写入:Brain/**、Bell/**、contracts/**、Sense/dist/**、当前用户数据库数据。

已确认方案

兼容逻辑置于现有 2026081414000 迁移的事务开头,因为受影响数据库尚未记录该版本,后置新版本无法越过当前失败点。SQL 只对白名单旧值做确定性转换;迁移前要求备份,失败时整个事务回滚。

风险与回退

  • 风险:数据库类型与已有数据变更属于高风险;错误转换会影响设备能力语义。
  • 控制:限定表/列/方言,白名单转换,未知值拒绝,事务回滚,隔离 PostgreSQL 测试和正式执行前备份。
  • 回退:失败事务自动回滚;正式执行前使用 PostgreSQL custom-format 备份。迁移成功后如需回退版本,停止服务并从备份恢复。

验收标准

  • 旧 text DEFAULT '' 列不再触发 SQLSTATE 42804
  • 旧单值能力无损转换为 JSONB 数组
  • 空值转换为 [],合法 JSON 数组保持语义
  • 未知或非法旧值拒绝迁移且事务不留下半成品
  • 新库、已是 jsonb 的库和重复执行保持兼容
  • 全量 Go 测试、迁移测试和隔离 PostgreSQL 回归通过
  • 不修改当前用户数据库;提供备份后重新启动的明确步骤
  • Wiki 镜像和任务归档一致

验证方式

  • 隔离 PostgreSQL 17 创建旧 schema 和夹具后运行兼容迁移。
  • 查询列类型、默认值、JSONB 内容、迁移记录和回滚状态。
  • go test ./cmd/migrate/migration/version、go test ./...、go vet ./...、go build ./...。
  • git diff --check、Wiki 定向与可行时全量一致性检查。

文档影响

更新 PostgreSQL capabilities 兼容迁移原因、备份要求、失败处理和重试方式。

实施结果与证据(2026-08-15)

  • 实现提交:68b436a
  • 完整迁移测试:fe3badf
  • 排错文档:aee5f45
  • 归档:3c4578c、3a686a8
  • PR:#93(fix/92-sense-capabilities-jsonb → dev,保持打开待验收)
  • Wiki Troubleshooting revision:a169b2323323d9de6304e9b430ddbe9888ea1d25
  • Wiki 归档 revision:d10479f732597bd90dac4de03edc0cd4b39b6352
  • 隔离 PostgreSQL 17:旧单值、空值、合法数组、未知值回滚、无表、重复调用、完整设备迁移与版本登记全部通过;测试数据库已删除。
  • 全量 Go test/vet/build、定向 race、diff 检查通过。
  • 当前用户 sense 数据库未执行写迁移,当前 Sense/dist 二进制未替换。
  • check_harness.py --strict 仅因既存 #66/#67 归档缺少当前模板章节失败。
  • 未验证:需在 #92 合入并重新生成 #70 Windows 包后,先备份当前数据库,再执行真实启动迁移验收。

用户验收与关闭(2026-08-15)

  • 用户明确确认 #92 验收通过。
  • 实现 PR #93 已合入 dev,merge commit:eaa6ae081542b0b9c74cc2d92a9138639fdbe530。
  • 验收归档 PR #94 已合入 dev,merge commit:40409707cc04fef8d6b51c806246577312c8dd3c。
  • Wiki 归档 revision:cbdcc65c2b7da74048713d49dcb4b49b47cec17e。
  • 真实数据库备份、交付包重建与启动回归继续由 #70 完成交付闭环。
## 状态 已完成 ## 基本信息 - 类型:缺陷 / PostgreSQL 兼容迁移 - 任务类型:单项目独立任务 - 主项目:Sense - 主 agent:Sense agent - 所属 Epic:#7 - 所属 MVP:#8 - 相关工单:#65、#70、#90 - 前置工单:#65(已验收并合入 dev) - 独立运行:Brain、Bell 均不启动时完成复现和验收 ## 原始需求与追溯 - 来源:用户于 2026-08-15 运行 `Sense\start_sense.bat` 时报告 PostgreSQL `SQLSTATE 42804`:“字段 capabilities 的默认值不能转换成类型 jsonb”,随后确认“建工单,做”。 - 只读诊断:目标数据库的 `sense_devices.capabilities` 为 `text NOT NULL DEFAULT ''::text`,有 1 条旧记录;值不是 JSON,但属于受支持的旧单值能力标识;`2026081414000` 迁移记录为 0。 - 根因:#65 新模型要求 `jsonb`,GORM AutoMigrate 直接转换既有 text 字段时先被旧默认值阻断;只删除默认值仍会被旧单值数据阻断。 ## 目标 让 Sense 设备迁移安全兼容旧 `text` capabilities 列,在保留设备记录语义的前提下转换为 JSONB,并让 Windows production 启动迁移可以继续。 ## 做什么 - 在 #65 设备迁移的 AutoMigrate 前增加 PostgreSQL 专用兼容步骤。 - 仅当 `sense_devices.capabilities` 存在且类型不是 json/jsonb 时执行。 - 事务内删除旧默认值,把空值转换为 `[]`,把允许的旧单值转换为 JSON 数组,合法 JSON 数组保持数组。 - 对未知、非法或非数组内容停止迁移并返回可定位错误,不静默猜测或丢弃。 - 转为 jsonb 后设置 `[]` 默认值,再继续现有 AutoMigrate。 - 增加隔离 PostgreSQL 回归测试,覆盖空表、旧单值、合法 JSON 数组、空字符串、未知非法值、幂等和事务回滚。 - 更新迁移/排错 Wiki 与任务归档。 ## 不做什么 不删除设备或凭据;不清空数据库;不修改客户配置;不自动备份生产库;不绕过迁移;不修改 Brain、Bell、共享契约或根级部署。 ## 写路径 - `Sense/server/cmd/migrate/migration/version/2026081414000_device.go` - `Sense/server/cmd/migrate/migration/version/2026081414000_device_test.go` - `Sense/server/app/sense/device/models/device.go`(仅在默认表达式确需调整时) - Wiki `Troubleshooting` - `docs/06-troubleshooting.md` - `docs/task/<本工单归档>.md` - `wiki-docs.json` 禁止写入:`Brain/**`、`Bell/**`、`contracts/**`、`Sense/dist/**`、当前用户数据库数据。 ## 已确认方案 兼容逻辑置于现有 `2026081414000` 迁移的事务开头,因为受影响数据库尚未记录该版本,后置新版本无法越过当前失败点。SQL 只对白名单旧值做确定性转换;迁移前要求备份,失败时整个事务回滚。 ## 风险与回退 - 风险:数据库类型与已有数据变更属于高风险;错误转换会影响设备能力语义。 - 控制:限定表/列/方言,白名单转换,未知值拒绝,事务回滚,隔离 PostgreSQL 测试和正式执行前备份。 - 回退:失败事务自动回滚;正式执行前使用 PostgreSQL custom-format 备份。迁移成功后如需回退版本,停止服务并从备份恢复。 ## 验收标准 - [x] 旧 `text DEFAULT ''` 列不再触发 SQLSTATE 42804 - [x] 旧单值能力无损转换为 JSONB 数组 - [x] 空值转换为 `[]`,合法 JSON 数组保持语义 - [x] 未知或非法旧值拒绝迁移且事务不留下半成品 - [x] 新库、已是 jsonb 的库和重复执行保持兼容 - [x] 全量 Go 测试、迁移测试和隔离 PostgreSQL 回归通过 - [x] 不修改当前用户数据库;提供备份后重新启动的明确步骤 - [x] Wiki 镜像和任务归档一致 ## 验证方式 - 隔离 PostgreSQL 17 创建旧 schema 和夹具后运行兼容迁移。 - 查询列类型、默认值、JSONB 内容、迁移记录和回滚状态。 - `go test ./cmd/migrate/migration/version`、`go test ./...`、`go vet ./...`、`go build ./...`。 - `git diff --check`、Wiki 定向与可行时全量一致性检查。 ## 文档影响 更新 PostgreSQL `capabilities` 兼容迁移原因、备份要求、失败处理和重试方式。 ## 实施结果与证据(2026-08-15) - 实现提交:`68b436a` - 完整迁移测试:`fe3badf` - 排错文档:`aee5f45` - 归档:`3c4578c`、`3a686a8` - PR:#93(`fix/92-sense-capabilities-jsonb` → `dev`,保持打开待验收) - Wiki Troubleshooting revision:`a169b2323323d9de6304e9b430ddbe9888ea1d25` - Wiki 归档 revision:`d10479f732597bd90dac4de03edc0cd4b39b6352` - 隔离 PostgreSQL 17:旧单值、空值、合法数组、未知值回滚、无表、重复调用、完整设备迁移与版本登记全部通过;测试数据库已删除。 - 全量 Go test/vet/build、定向 race、diff 检查通过。 - 当前用户 `sense` 数据库未执行写迁移,当前 `Sense/dist` 二进制未替换。 - `check_harness.py --strict` 仅因既存 #66/#67 归档缺少当前模板章节失败。 - 未验证:需在 #92 合入并重新生成 #70 Windows 包后,先备份当前数据库,再执行真实启动迁移验收。 ## 用户验收与关闭(2026-08-15) - 用户明确确认 `#92 验收通过`。 - 实现 PR #93 已合入 `dev`,merge commit:`eaa6ae081542b0b9c74cc2d92a9138639fdbe530`。 - 验收归档 PR #94 已合入 `dev`,merge commit:`40409707cc04fef8d6b51c806246577312c8dd3c`。 - Wiki 归档 revision:`cbdcc65c2b7da74048713d49dcb4b49b47cec17e`。 - 真实数据库备份、交付包重建与启动回归继续由 #70 完成交付闭环。
ila added the kind/taskproject/sensescope/independentpriority/p0 labels 2026-08-15 15:08:15 +08:00
Author
Owner

开始实施。分支 fix/92-sense-capabilities-jsonb 从最新 dev 创建,工作区初始干净。只读诊断确认旧列为 text NOT NULL DEFAULT ''::text,1 条记录为受支持的旧单值但非 JSON,迁移版本未登记。兼容逻辑将在同一迁移事务内先锁表、全量验证,再确定性转换;当前用户数据库不作为测试目标。

开始实施。分支 `fix/92-sense-capabilities-jsonb` 从最新 `dev` 创建,工作区初始干净。只读诊断确认旧列为 `text NOT NULL DEFAULT ''::text`,1 条记录为受支持的旧单值但非 JSON,迁移版本未登记。兼容逻辑将在同一迁移事务内先锁表、全量验证,再确定性转换;当前用户数据库不作为测试目标。
Author
Owner

#92 已完成并进入待验收。

  • PR:#93 #93(目标 dev,未合并)
  • 提交:68b436a、fe3badf、aee5f45、3c4578c、3a686a8
  • 隔离 PostgreSQL 17 已验证完整旧设备迁移、JSONB 类型/默认值、版本登记、重复执行和未知值事务回滚。
  • 独立测试数据库测试后已删除;当前用户 sense 数据库只做过只读诊断,没有写入。
  • Go 全量 test/vet/build、定向 race、diff 检查和受影响 Wiki 定向一致性检查通过。
  • Harness strict 仅受既存 #66/#67 归档格式影响。
  • 当前 Windows 包仍是修复前二进制。建议验收顺序:#92 / PR #93 → 让 #70 / PR #89 吸收修复并重新打包 → 备份当前数据库 → 启动迁移验收。
#92 已完成并进入待验收。 - PR:#93 https://git.ilapage.cn/ila/yovision/pulls/93(目标 `dev`,未合并) - 提交:`68b436a`、`fe3badf`、`aee5f45`、`3c4578c`、`3a686a8` - 隔离 PostgreSQL 17 已验证完整旧设备迁移、JSONB 类型/默认值、版本登记、重复执行和未知值事务回滚。 - 独立测试数据库测试后已删除;当前用户 `sense` 数据库只做过只读诊断,没有写入。 - Go 全量 test/vet/build、定向 race、diff 检查和受影响 Wiki 定向一致性检查通过。 - Harness strict 仅受既存 #66/#67 归档格式影响。 - 当前 Windows 包仍是修复前二进制。建议验收顺序:#92 / PR #93 → 让 #70 / PR #89 吸收修复并重新打包 → 备份当前数据库 → 启动迁移验收。
ila closed this issue 2026-08-15 15:31:54 +08:00
Author
Owner

用户已于 2026-08-15 明确验收通过。

  • 实现 PR #93 已合入 dev:eaa6ae081542b0b9c74cc2d92a9138639fdbe530
  • 验收归档 PR #94 已合入 dev:40409707cc04fef8d6b51c806246577312c8dd3c
  • Wiki 归档 revision:cbdcc65c2b7da74048713d49dcb4b49b47cec17e
  • 工单已关闭;数据库备份、交付包重建与真实启动回归继续在 #70。
用户已于 2026-08-15 明确验收通过。 - 实现 PR #93 已合入 `dev`:`eaa6ae081542b0b9c74cc2d92a9138639fdbe530` - 验收归档 PR #94 已合入 `dev`:`40409707cc04fef8d6b51c806246577312c8dd3c` - Wiki 归档 revision:`cbdcc65c2b7da74048713d49dcb4b49b47cec17e` - 工单已关闭;数据库备份、交付包重建与真实启动回归继续在 #70。
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: ila/yovision#92