Files
rond-with-you/.workbuddy/memory/2026-10-01.md
T
tamakyi 5c7cf1a0e1 对访客公开的措辞按身份分支:访客不该看到「我的结论」
用户发现未登录也显示「推荐 & 踩雷(我的结论)」,访客没法解读「谁的我的」。
顺着把访客可见模板与 static/js 全过了一遍,同病共四处——都是**写模板时站在站长视角下笔、
而那一块又对访客公开**:

1. stats.html:标题 → {{if .IsAdmin}}我的结论{{else}}站长结论{{end}};
   副标题「只统计你自己…」→ 站长「你自己」/ 访客「站长」;两列「我推荐/我踩雷的地点」同理。
2. stats.html 访客块:「与我的结论互不影响:你标你的,访客投访客的」——对访客说不通,
   改成对两边都成立的「与上面的站长结论互不影响:各存各的表,谁也不会覆盖谁」。
3. home.html:「我的标签」→「足迹标签」(同级卡片全是中性的:足迹地图/城市足迹/天气足迹…)。
4. report.html:「这一年里,你第一次踏足的这些城市」→ 去掉人称(年报是站长的回顾)。

已经写对的照它学:place.html 的投票区早就是 {{if .IsAdmin}} 分支(站长「我的结论」、
访客「大家怎么说」),rond-map.js 的气泡同理;「含家/工作」chip 与一串「只有你自己能看到」
本来就在站长分支里。

门禁 TestVisitorPagesUseThirdPersonCopy:以**访客 ctx(无 user)**渲染 /、/stats、/report,
逐个禁用词断言,同时断言站长那份**仍旧说「我的」**(别把站长自己的视角也改掉);
前置需打开 marks_public(访客才看得到那一块),用完还原。

⚠️ 变异验证时踩了老坑:直接 `go test -run …` 因缺 ROND_TEST_CONF/ROND_SRC 会**静默 skip 并报 ok**
(0.17s 就 ok,一眼假绿)。改用 ./scripts/verify.sh 后变异被正确抓住
(visitor_copy_test.go:85 报「我的结论」),还原后转绿。

全量验收 PASS=339 FAIL=0 SKIP=0。
2026-10-01 02:15:49 +08:00

5.6 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 用例。

统计页:站长结论与访客点赞拆成两块(01:40)

用户问「数据统计处的推荐地点和踩雷地点只针对站长吗?应该分开,用户的点赞点踩单独做一块」。 他看到的没错:那张卡的列表全是站长结论,访客票只在副标题露了个总数。

  • 新增 votes.TopVisitorVoted(HAVING 只算至少有一票的方向,否则 0 票地点塞满榜; 同票按 visit_count DESC, p.id 保证顺序稳定)。
  • 「推荐 & 踩雷(我的结论)」只讲站长;另起一张卡「访客点赞」,列 👍/👎 票最多的地点并带票数。
  • 两个 pageJob 并行加载;两块共用 IsAdmin || MarksPublic(与地点页投票区一致)。
  • 用例按卡片标题切 HTML 断言「A 只在站长块、B 只在访客块」,比数总数更能证明没串台。

⚠️ 又踩同一个坑:票表按坐标键跨数据集读、place_visitor_votes 还没有 user_id ⇒ 上一轮跑剩的票会被算进来。新增 isolateVoteState 按 place_key 清两张表(前置 + cleanup)。

顺带订正 README:那里还写着站长结论「按 src_pk 存」,其实早就是坐标键了。

措辞分身份:访客不该看到「我的结论」(02:05)

用户:「无论是否登陆,都显示『推荐 & 踩雷(我的结论)』,这对访客是不是会产生困扰,再检查类似的表述」。 顺着 grep "[我你咱]" 把访客可见模板 + static/js 过了一遍,共 4 处同病(都是站在站长视角下笔、 而那一块对访客公开):

  1. stats.html:标题「我的结论」→ 按身份分支(站长「我的结论」/ 访客「站长结论」); 副标题「只统计你自己…」→ 站长「你自己」/ 访客「站长」;两列「我推荐/我踩雷的地点」同理。
  2. stats.html 访客块副标题:「你标你的,访客投访客的」→ 对两边都成立的「各存各的表,谁也不会覆盖谁」。
  3. home.html:「我的标签」→「足迹标签」(同级卡片全是中性的:足迹地图/城市足迹/天气足迹…)。
  4. report.html:「这一年里,你第一次踏足…」→ 去掉人称(年报是站长的回顾)。

已写对的(照它学):place.html 投票区早就是 {{if .IsAdmin}} 分支,rond-map.js 气泡同理。

门禁 TestVisitorPagesUseThirdPersonCopy:以访客 ctx(无 user)渲染 /、/stats、/report, 逐个禁用词断言,同时确认站长那份仍说「我的」(别改过头)。

⚠️ 变异验证又踩老坑:直接 go test -run 缺环境变量会静默 skip 并报 ok(0.17s 就 ok,一眼假绿), 必须走 verify.sh。改用 verify.sh 后变异被正确抓住(visitor_copy_test.go:85 报「我的结论」)。