记忆:把 .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`)。
This commit is contained in:
tamakyi
2026-09-30 18:31:08 +08:00
parent d99c63fa4f
commit 3f1b737a78
17 changed files with 6625 additions and 1 deletions
+100
View File
@@ -0,0 +1,100 @@
# 2026-09-24 工作日志
## 稳定性基线实测(回答「现在稳定了吗」,把数字钉下来)
- 覆盖率(`go test -cover ./...`,全套环境变量):web 53.2%、stats 62.2%、auth 50.5%、db 53.4%、
fog 52.9%、ingest 47.6%、rond 38.8%、exif 69.7%、media 64.6%、setting 85.0%、config 75.0%、
captcha 90.6%;**按源码行数加权 ≈ 51%**。
`geo`/`gpx`/`notes`/`votes` 报 0.0% 只是 `-cover` 不统计跨包执行,它们被 web/stats 的用例间接跑到。
- **「不带环境变量 = 假绿」的规模变大了**:只跑 `./internal/web/ ./internal/rond/ ./internal/stats/`
(不设四件套)→ 三个包全 `ok`、exit=0,但 **95 PASS / 86 SKIP**。
原始报告基线是 62 SKIP;本轮的回归守卫几乎都带 DB 夹具 ⇒ 假绿面反而扩大。
- 路由触达:92 条注册路由里,41 条在测试里被直接引用过(51 条没有;但不少 handler 是用函数直调
覆盖的,这个比例**高估**了缺口)。
- 无 CI、无 Makefile、无 linter 配置 ⇒ 0-skip 验收完全靠人记住六个环境变量。
- 仓库卫生:`tools/__pycache__/*.pyc` 已入库(编译产物);6 个 `tools/*probe` 探针工具在库里
(技能里写的是「用完删掉」)。
- 未提交:48 个修改 + 38 个新增文件仍全在工作区。
## P0(落地)
- **一键验收 `scripts/verify.sh`**(无 make,用 bash):自己从 `conf/app-test.ini` 取 DSN(不写死口令);
库名不含 `test` 直接拒跑;**数 SKIP 并让非 0 失败**;两段式导出(先产纯净包再全量);
支持 `--fast`(gofmt+vet+build)/`--race`/`--cover`/`--pkg`/`--run`。
实测:`--fast` 通过;DSN 指 `postgres` → 拒跑;缺 `ROND_SRC` → 拒跑;未知参数 → exit 2。
- **仓库卫生**:删掉 6 个一次性探针(colprobe/diffprobe/exportprobe/fogprobe/idprobe/sqlprobe)
与误入库的 `tools/__pycache__/photo_coord_audit.cpython-313.pyc`;`.gitignore` 补 `__pycache__/`、`*.pyc`;
新增 `tools/README.md` 说明留下的 4 个工具(verify_export_structure / verify_rondbackup /
photo_coord_audit / audit_db.sql)与验收命令。
- **分 3 个提交落地**(工作区已干净):
`b4c2a84` 后端(安全/数据一致性/性能)70 文件、`d5f6dfa` 前端(模板/CSS/JS+无障碍)18 文件、
`d2e4392` 验收脚本 + 工具整理 + 排查报告。每个提交都过了 `go build ./... && go vet ./...`。
提交顺序说明:前端守卫要读模板/静态文件,所以读前端产物的测试(frontend_fixes / tb_static /
templates_test / wide_table_layout / tb_stack / map_async_cancel / map_escape)跟模板放同一提交。
## P1
- **全新库冒烟 `internal/db/fresh_db_test.go`**:空库 → `Open` 自动建库 → `Migrate`(跑两遍验幂等)
→ 断言 21 张表、迁移块补出来的列(`places.coord_*`、三张表的 `place_key`…)、三张附属表的主键
已搬到坐标键、4 个索引,最后用 `stats.DB{DB: d}` 真打 18 个读查询(空库上不报错)。
**变异验证**:把 `CREATE INDEX idx_place_images_key` 移到 `CREATE TABLE place_images` 之前
⇒ 新库报 `关系 "place_images" 不存在 (SQLSTATE 42P01)` 变红;同一条语句在老库上
`psql -c` 却提示「已存在,跳过」⇒ 正是「开发库无症、新库起不来」。已还原(`git diff` 空)。
- **web 整包 `-race`**:`./scripts/verify.sh --race --pkg ./internal/web/`(脚本自动把 mingw 加进 PATH)
⇒ **161 PASS / 0 FAIL / 0 SKIP / 0 个 DATA RACE**。此前只有迷雾索引那一条验过 race。
- 脚本补丁:SKIP/FAIL 计数改成 `^[[:space:]]*--- `,**连子测试一起数**(只数顶层会漏掉子测试的跳过)。
- 最终验收(HEAD,一条命令):**244 顶层用例 / 271 含子测试 / 0 FAIL / 0 SKIP**,12 包全 `ok`;
往返包 823/323/8/30/791/557/2246 全等、坐标 0、时间 0s、迷雾 8701 块。`--fast` 干净。
- 提交:`b4c2a84` 后端 → `d5f6dfa` 前端 → `d2e4392` 脚本/工具/报告 → `ff59412` 脚本补丁。
中间提交未单独跑全量(实现与其守卫同批落地,拆开必假红),最终状态已验收。
- 仍剩的 P2(未做):`rond` 38.8% 覆盖率补主路径、关键页面 CDP 冒烟、**导出包真机导入**(唯一终审)。
## P2(落地,只做了前两项;真机导入仍需站长操作)
### 覆盖率:先纠正口径,`rond` 根本不是 38.8%
- **`go test -cover` 只统计「测试文件所在那个包」自己的执行**。`internal/rond` 一半的代码
(`export.go` 1416 行)由 `internal/web` 的 `TestMovementCleanExport` 跑;`geo`/`notes`/`votes` 同理。
按 `-cover` 量这些包一律假报 0%(`gpx` 也报 0%,但那条是**真的**)。
- 正确口径 `-coverpkg=./internal/...`:rond **82.2%**(假读 38.8%)、geo 92.9%(假读 0%)、
stats 83.7%(假读 62.2%)、web 53.2%(它自己不假)。**项目合计 62.3%**。
- ⚠️ 解析 profile 必须**按 `(文件,行段)` 取 max**:`-coverpkg` 下每个测试二进制都给同一段代码写一条,
求和 = 语句数乘份数 ⇒ 每包都像只有 `1/N`(第一版 awk 就这么错的,web 印成 4.4%)。
- `scripts/verify.sh --cover` 已切到该口径并按包打印。
### 补的用例(只补「线上会走到」的,不追 `nil`/错误返回)
- `internal/rond/merge_clash_test.go`:`BuildMergePlan` 的**地点/活动冲突**(`placePick`/`activityPick`
长期 0%,而差异页线上确实会提交这两类选择)+ 删除逐条勾选。`merge.go` 64.3% → **96.4%**。
- `internal/gpx/gpx_test.go`:该包**整包零测试**(0/61 语句),而它解析的是**用户上传的 XML**。
8 条用例覆盖 trk/rte 两分支、名字退回 `metadata>name`、`(0,0)` 丢弃、单点轨迹丢弃、非法 XML、
无轨迹点、时间错不致命、里程数值。⇒ **0% → 96.0%**。
- 两处**死代码**(全仓核查含模板后确认零引用):`rond.Counts.Total()`、`gpx.Track.BBox()`,已删;
**没给它们写测试**(给死代码补用例等于把死代码固化)。
- **一条实测否证**:`gpx.haversine` 没有 `geo.Haversine` 那道 `math.Min(1,…)` 夹子,
本以为会出 NaN;实测对跖点 `h` 最多到 `1+2^-52`,而 `sqrt(1+2^-52)` 回舍成正好 `1.0`,
`asin(1.0)=π/2` ⇒ **改不动,也没改代码**,只留 `TestLengthKmAntipodalIsFinite` 钉住该性质。
三条 haversine 公式两个半径(6371.0 / 6371.0088)差 0.20 m/146 km,纯口径不统一。
### 关键页冒烟 `scripts/smoke.py`(16 页)
- 三种口径:站长浏览器(200 + 落点路径 + 内容区尺寸非 0 + 零 JS 报错)、访客纯 HTTP
(公开页 200、后台页必须 **303 跳登录**,不跟随跳转即可,比开 Chrome 快一个数量级)、
访客浏览器抽检 `/` 与地点详情。接进 `verify.sh --smoke` / `--all`。
- 三个坑:①关键区块**不能取 `nav.nav`**(在 layout 里,内容块没渲染它照样在);
②**用 `.card` 不用 `div.card`**(专题卡片是 `<a class="card topic-card">`,选不中时
`querySelector` 返回 null ⇒ 尺寸也是 0,打印出来跟「被压成 0 宽」一模一样);
③`--min-body` 只兜「整页空白」(专题列表正文天生 166 字)。
- **变异验证**:`timeline.html` 里塞 `<script>throw new Error(...)</script>`
(`debug=true` 模板热加载,不用重启)⇒ 冒烟红在「JS 报错」,而**状态码/内容区尺寸全正常**
⇒ 没有这条断言就会放过它。已还原。
- ⚠️ `verify.sh` 给 Windows python 传路径要用 `$ABS`(`C:\...`),传 `$ROOT`(`/c/...`)
会被拼成 `C:\c\...` 报 `No such file`。
- `site_cdp.py` 不报 HTTP 状态;用 `performance.getEntriesByType('navigation')[0].responseStatus`。
### 收尾验收与提交
- `./scripts/verify.sh` ⇒ **284 PASS / 0 FAIL / 0 SKIP**(P1 时 244,本轮 +新用例);
`--all` ⇒ 冒烟 16 页全绿;`--cover` ⇒ 62.3%;`--fast` 干净。
- 提交:`05c6e97` 测试与死代码 → `256620e` 验收脚本与冒烟 → `f2ce664` 报告。工作区已干净。