Files
rond-with-you/.workbuddy/memory/2026-09-28.md
T
tamakyi 3f1b737a78 记忆:把 .workbuddy/memory 纳入版本控制
用户要求这份记忆跟着仓库走,而不是只留在本机。

.gitignore 里挡路的是 `.workbuddy/`。改成反忽略六行,并且**只放行 .md**:
别用 `!.workbuddy/memory/**`——它会把 memory 下任何文件都放行,本项目真发生过
`web.test.exe` 混进暂存。复核用 `git check-ignore -q --no-index` 逐条打靶:
memory/*.png、memory/sub/x.md、memory/MEMORY.md.bak、plans/a.md 全 IGNORED,
17 个 .md 全 included;`git add -An .workbuddy/` 恰好 16 个文件。
其余 .workbuddy 内容(计划、本地设置、临时产物)继续忽略。记忆里没有真凭据
(唯一命中是 2026-09-14.md 里的 `password=rond-admin`,那是项目默认口令)。

顺带做两件整理:

1. 取证了注入上限。以前按「字节数」判断 MEMORY.md 是否超限是错的:
   WorkBuddy 的 `getWorkingMemoryContent()` 用 `MAX_MEMORY_CHARS = 1e4` 比 JS
   `content.length`,即**字符数**(中文 1 字算 1);超了 substring 截断、尾部静默丢失。
   本 details 与每日日志都不参与注入,只有 MEMORY.md 受约束。
   现已从 6604 字符收到上限的 66%,并把这条上限写进索引抬头。
2. 把「备份合并」「导出/恢复三条铁律」两段长文迁进 MEMORY-details.md 的卅一/卅二节,
   索引只留关键词指针。行尾统一为 LF(仓库 .gitattributes 是 `* text=auto eol=lf`)。
2026-09-30 18:31:08 +08:00

6.8 KiB
Raw Blame History

2026-09-28

rondbackup「差异分析 → 合并执行」实测(真机导出包 20260928_183908)

环境 conf/app.ini(库 rond_with_you、data_dir=storage/data、:8080),数据集 id=9; 把真机新导出的 data/20260928_183908.rondbackup(955 到访 / 432 地点)合并进已有 867 到访的数据集。

主链路生效(真跑路由 + 站长登录):POST /admin/preview → GET 差异页 → POST /admin/preview/{token}/merge, add_new=1、冲突留默认 ⇒ 新增 70 地点 / 1 活动 / 134 到访,随到访带入 24 位移 / 32 天气; 到访 867→1001、地点 368→438、位移 791→815、天气 557→589;孤儿位移 0、无地点到访 0、重复 UUID 0 组。 逐条核对:备份里 953 条带 UUID 的到访全部命中且到达时间微秒级零误差;站内 2 条 app 已删的 UUID 到访被正确保留。 合并后 12 个关键页全 200。报告:storage/.mergetest/报告-rondbackup合并实测-20260928.md

三个问题

  1. 🟠 同名同坐标的重复地点不幂等:DiffPlaces 的 byCoord/byName 是单槽位 map + used[], 同一坐标下 N 条备份地点最多只能配 2 条 ⇒ 第 3 条永远判「备份新增」,每次合并多插一条。 实测备份里同名同坐标共 10 组、只有「柳州站」count=3 ⇒ 每次合并固定多 1 个重复地点,差异永不归零 (438→439→…)。修法:多值 map 逐条消费 + mergePlaces INSERT 前按 PlaceCoordKey 去重兜底。
  2. 🟠 到访冲突被「活动改名」放大:visitFieldChanges 比的是活动名称不是身份;16 个活动改名 (餐厅→吃饭…)⇒ 355 条到访冲突全部同因(库内挂在改名活动下的 378 条 − 站内独有 23 条 = 355,精确吻合), 活动类型本身只报 16 条。且对到访选「用实机」不会改活动名(activity_id 按 UUID 映射回同一个) ⇒ 冲突永不收敛。修法:到访层面按活动身份(ZUID_/id)比对,改名只在活动层报一次。
  3. 🟡 21 个长沙地点两边坐标差 661~748m,实测 20 条满足「站内坐标 == 反纠偏(备份坐标)」 ⇒ 坐标系不一致(站内那侧被多做了一次 GCJ→WGS 反向换算);差异页冲突的默认选项是「用实机」, 直接点合并会把这批坐标覆盖、地图上跳 ~660m。另有 分类 12 处(站内中文标签 vs 备份 MKPOICategory* 原始枚举)。

备份 / 回滚:storage/.mergetest/rond_with_you-before-20260928.sql(整库 pg_dump); 差异页快照 diff-before-merge.html / diff-after-merge.html。库内最终状态 = 合并一次(我重复跑测试 多插的 1 个重复地点已回退)。

方法(可复用):临时 Go 测试(package web,才能拿到非导出的 srv.captcha)—— httptest.NewServer(srv.Handler()) + cookie jar + CheckRedirect: http.ErrUseLastResponse (站点用 303,必须关掉自动跟随才能读到 Location);验证码答案直接读 captcha.Store.Answer(id), 绕开图像识别;管理员口令是默认 rond-admin(pbkdf2 可离线核对)。跑完删掉测试文件,git status 保持干净。

同日晚:修复 + 复测(回档数据库后重跑)

按上面前两条问题改了代码,5 个文件 +172/−22:

  1. internal/rond/diff.go DiffPlaces:byCoord/byName 由单槽位 map 改为多值索引(map[string][]StoredPlace), 抽出 take() 逐条认领未使用的候选(认领即置 used)。classify 不再自己置 used。
  2. internal/rond/diff.go visitFieldChanges:到访的「活动」改为按身份比(新增参数 actUUID), 两边都缺 UUID 才退回名称;DiffVisits 传入 b.ActivityUUID。StoredVisit 新增 ActivityUUID。
  3. internal/web/backup_diff.go loadStoredVisits:多 JOIN 一次 entity_raw(entity='ZACTIVITY',按 a.src_pk)取 ZUID_。

复测结果(回档 → 重跑同一份备份,同环境):到访冲突 253 → 6(247 条活动改名假冲突消失); 地点新增 70 → 67,合并后再比对 地点新增 1 → 0;再点合并由「再插 1 个重复地点」变成 「按当前的选择没有要写入的改动,数据未变」,地点 435→435、「柳州站」稳定 3 条。 到访 1001 / 位移 815 / 天气 589 与修复前一致;953 条 UUID 到访全命中、到达时间 0 偏差、孤儿位移 0。

新增守护:TestDiffPlacesAlignsDuplicateNameCoordGroups(含「站内真少两条仍报新增 2」反向断言)、 TestDiffVisitsIgnoresActivityRename、TestDiffVisitsReportsActivityChange、 TestDiffVisitsActivityWithoutUUIDFallsBackToName;TestBackupDiffIdentical 补地点新增断言、 两个 merge 幂等用例补「地点差异归零」。变异验证:把两处改回旧逻辑,对应用例确实全挂 (⚠️ 变异要忠于旧行为:旧 byCoord 是 map「后者覆盖前者」=取最后一条;我第一次写成「取第一条」, 误报 8 条,与真实旧行为不符,改用 byCoord[k] = []StoredPlace{sp} + byName 只留第一条才复现出正确的 1 条)。

仍未动:21~24 个长沙地点坐标系差 ~660m(默认「用实机」会覆盖站内;现连带 25 条到访「地点」冲突)、 分类 12 处中文标签 vs MKPOICategory* 枚举、16 个活动改名需选「用实机」才同步。 报告已更新为「实测 → 修复 → 复测」完整版。

收尾:回滚 + 推送 + 重建(19:35)

  • 回滚:DROP/CREATE rond_with_you + 恢复 storage/.mergetest/rond_with_you-before-20260928.sql, 核对回到合并前基线 867 到访 / 368 地点 / 31 活动 / 791 位移 / 557 天气 / 2538 留档 / 柳州站 3。
  • 推送:提交 10d23e0(5 文件 +172/−22),git push origin master(远端 git.shiroko.one)。 本地原本就领先远端 8 个提交,一并推上去了(78865fc..10d23e0)。 ⚠️ 推送凭据陷阱:~/.git-credentials(store)与 GCM 里缓存的 token 都已失效 (remote: Failed to authenticate user),SSH 22 端口 Network is unreachable(只有 HTTP 代理 http.proxy=http://100.104.48.63:11882 能通)。别加 GIT_TERMINAL_PROMPT=0——它会让 GCM 直接放弃认证;去掉这个变量、让 GCM 自己走一遍交互认证即可成功(13 秒完成)。
  • 重建:go build -o bin/rond.exe .(bin/rond.exe 原本还是 9-20 的旧构建,不含修复; 旧文件留了副本 bin/rond.exe.bak-20260920)。只读冒烟:/healthz / /admin/login 均 200、 /admin 303,随后 taskkill //F //IM rond.exe 停掉、8080 释放,库内计数不变。
  • 注意:go build 那次 bin/rond.exe~(9-20 12:14 的更旧副本)不见了;原因未查明, 两个都是修复前的旧产物,无实际损失。