Files
rond-with-you/.workbuddy/memory/2026-09-24.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

101 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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` 报告。工作区已干净。