Files
rond-with-you/.workbuddy/memory/2026-10-01.md
T
tamakyi 4c3032cf48 防复发:把「删数据集带走站点自建数据」做成结构性门禁 + 常驻体检
用户放弃继续救那批旧图,要求的是「别再发生同类事件」。所以不靠记性,靠结构:

1) 归属铁律(写进 schema.sql 抬头 + README 新章节)
   判断标准只有一句:**这份记录能不能从备份重新导入?**
   能(places/visits/movements/weather/activities/tags/entity_raw)⇒ 可挂
   `REFERENCES datasets(id) ON DELETE CASCADE`;
   不能(place_images/place_notes/place_votes/topics)⇒ 只留 dataset_id 当出处、**不许挂外键**。

2) 两道门禁(dataset_ownership_test.go),都做了变异验证:
   - 运行时:查 pg_constraint,凡挂 datasets 的表必须在白名单里;**反向也查**
     (白名单里的表不许被顺手摘掉,否则删数据集会留成片孤儿行)。
   - 静态:扫 schema.sql 的 CREATE TABLE。只看运行时有盲点——新建的库走 CREATE TABLE,
     开发库可能压根没跑过那次迁移。变异(把 topics 的 CASCADE 补回去)当场红。
   - 变异验证顺带发现:扫描必须先跳过 `--` 注释行,规矩的说明文字里就写着
     `REFERENCES datasets(id)`,不跳过会把自己写的文档当成违规。
   - 还发现运行时那道单独看**不够**:夹具每次跑迁移,迁移自己就把坏外键摘了,
     它永远不会在不健康的库上报警 ⇒ 补了「注入事故原样的外键再跑迁移,断言被摘掉」
     的自愈用例(并先确认变异真的生效,防假绿)。

3) 常驻体检:后台首页显示「库里 N 张 / 本地盘上 M 个 / 落单 K 个」,落单 >0 直接报警。
   事故的本质不是「删数据集」本身,而是**行与对象悄悄对不上、没人发现**,等照片看不见了才追。

自愈用例又抓出一个此前漏掉的缺口:place_notes / place_votes 上的同类外键迁移并不会摘
(原先只写了 place_images 与 topics 两句 DROP)⇒ 补成五张自建数据表全覆盖。

⚠️ 排序坑(本项目第二次踩):摘外键那段最初放在 place_images 建表**之前**,
开发库毫无症状、**全新库起不来**(ALTER 报「关系不存在」),被
TestFreshDatabaseServesAppQueries 抓住。整段已挪到 place_images 之后,并把坑写进注释。

顺带订正「删除数据集」的二次确认文案(专题改完之后它还在说专题会一起删)。
全量验收 PASS=336 FAIL=0 SKIP=0。
2026-10-01 01:15:04 +08:00

2.9 KiB
Raw Blame History

2026-10-01

防复发:把「删数据集带走自建数据」做成结构性门禁(00:30)

用户放弃继续救那批旧图:「我只想避免类似的事件再次发生」。于是把这次的教训固化成三件东西 (internal/web/dataset_ownership_test.go + schema.sql 抬头 + README 新章节):

  1. 归属铁律:判断标准只有一句——这份记录能不能从备份重新导入? 能(places/visits/movements/weather/activities/tags/entity_raw)⇒ 可挂 CASCADE; 不能(place_images/place_notes/place_votes/topics)⇒ 只留 dataset_id 当出处、不许挂外键。
  2. 两道门禁:运行时查 pg_constraint(表必须在白名单里,反向也查)+ 静态扫 schema.sql (新建的库走 CREATE TABLE,只看运行时有盲点)。做变异验证时确认了静态那条真的会响。
  3. 体检常驻后台首页:库里 N 张 / 本地盘上 M 个 / 落单 K 个(imageHealth),落单 >0 直接报警。 事故的本质不是「删数据集」本身,而是行与对象悄悄对不上、没人发现——让它当场可见。

变异验证的收获(比测试本身更有价值):

  • 运行时门禁单独看不够:夹具每次跑迁移,迁移自己就把坏外键摘了 ⇒ 它永远不会在不健康的库上报警。 补了 TestMigrationDropsStaleDatasetForeignKeys:注入事故原样的外键再跑迁移,断言被摘掉。
  • 这条自愈用例又抓出缺口:place_notes/place_votes 上同类外键迁移并不会摘 (原先只写了 place_images 与 topics 两句 DROP)⇒ 补成四张自建数据表全覆盖。 部署出去的库要能自愈,DROP 必须覆盖全部同类表。
  • 静态扫描必须先跳过 -- 注释行:规矩的说明文字里就写着 REFERENCES datasets(id), 不跳过会把自己写的文档当成违规。

顺带订正:后台「删除数据集」的二次确认文案在专题改完后已说过时话(说专题会一起删),改成实话。

补记:迁移块排序的老规矩我又踩了一次(00:55)

把「摘外键」那五句 ALTER 收成一段放在 topics 之后,而 place_images 的 CREATE 在这段之后 ⇒ 开发库(表已存在)毫无症状,全新库起不来:ALTER TABLE place_images … 报「关系不存在」。 正是记忆里那条老规矩:「迁移块必须收敛且排在依赖表之后(插在 place_images 前:开发库无症、新库起不来)」。 被 TestFreshDatabaseServesAppQueries 当场抓住(这条门存在的意义)。

改成整段排在 place_images 建表之后(它是五张里最后一张),并把这个坑写进 schema.sql 的注释里。 教训:凡是 ALTER 某个表的迁移块,先确认那张表在文件里已经建过了—— 只在本机库上跑一遍是测不出来的,必须跑 fresh-database 用例。