Files
rond-with-you/.workbuddy/memory/2026-10-09.md
T
tamakyi 3077250a82 记忆:完整回归结论 + 验收必须在安静环境跑
- 记下本次完整验证链:verify.sh 348 例 0 skip、fog 包 -race 22 例、JS 34/34、320/390 溢出全 0。
- ⚠️ 新纪律(details 三十二):`db.Open` 的 ping 写死 10s,库被压着时
  `TestOpenCreatesMissingDatabase` 会以「建库后首次连接超时」失败 —— 实测与 CDP 审计并发时 10.02s 超时,
  停掉审计单独跑 4.1s 就过。这条测试失败还会把临时库 `rond_test_autocreate_*` 留在库里
  (清库的 defer 在 Open 成功之后才注册),要手动 DROP 清掉。
- 记下「原有代码受影响」专项检查的方法与结果(自定义属性 0 处用了没定义、模板函数无真孤儿、
  19 个模板 diff 只有预期改动;`.g3/.g4` 是 HEAD 里的既有死类)。
2026-10-09 17:02:05 +08:00

220 lines
15 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-10-09
## 排查:/admin/settings 报错(旧二进制 + 新模板)
**现象**:「统计脚本做成后台开关」那次提交(4015ddf)之后,访问 /admin/settings 报错。
**根因(已实测复现)**:跑的是**旧二进制**(根目录 `rond.exe`,10-08 18:06 编译,早于 18:27 的提交),
磁盘上的模板却是新的。`debug=true` 下 `pageSet()` 每次渲染都从磁盘重解析模板,
于是新 `settings.html:148` 引用了旧 `setting.Settings` 结构体里没有的 `TrackEnabled` → 执行期报错:
```
渲染 admin/settings 失败: template: settings.html:148:85: executing "content"
at <.Settings.TrackEnabled>: can't evaluate field TrackEnabled in type setting.Settings
```
`render` 是流式直写 ⇒ header 已发(HTTP 200)但表单在「统计脚本」卡片处截断,
没保存按钮、没 `</form></html>`。这就是用户看到的「报错」。
**判据**:`strings <二进制> | grep -c cleanTrackScript` —— 旧根二进制 0,新编译的 2。
(注意别用 `strings | grep TrackScript` 判定,config 里本来就有这个名字,旧二进制也命中。)
**修复**:`go build -o rond.exe .`(+ `bin/rond.exe`),重启。旧二进制备份到
`bin/rond.exe.old-20261008-stale`。修后 /admin/settings 完整(19642B,含 `</html>`/保存按钮)。
**教训**:Go 结构与模板字段是成对改的,`debug=true` 的热加载只覆盖模板 —— 改 Go 必须重编译重启,
否则就是「新模板 + 旧结构 = 执行期报错」。想根治可在启动时把所有页面各渲染一遍做冒烟(现在没有)。
## 其他发现(未改代码)
1. **P1 待确认**:`settings` 行 `pages=null`(写入时间 2026-10-08 18:14:05)⇒ 访客侧
`/map /places /timeline /stats /report` 全部 404、导航只剩 1 个链接。代码语义是
「全不选 = 访客只能看主页」,属合法状态,像是测 404 分档时留下的。**没动数据,等确认**。
2. **P2**:`cleanTrackScript` 的 `src=` 检查是**全文 `strings.Index`**,会误伤脚本体内的
`src=`。实测:`<script>var i=new Image();i.src=u;</script>` → 返回 `""`(整段被静默清空),
而页面仍提示「设置已保存」⇒ 静默失效。建议只在标签属性里查 src,或把「被清空」回传前端显式提示。
3. **P2**:开闭标签只拒 `shut > open`;末尾未闭合 `<script>`(`open > shut`)会吞掉后面内容。
实测 `<script>x</script><script>y` 与 `<script>y` 都被放行。建议改成要求 `open == shut`。
4. **运维**:根 `rond.exe` 与 `bin/rond.exe` 两份二进制容易走偏(这次根目录那份就是旧的)。
考虑只保留 `bin/`,或在启动日志打印构建时间便于比对。
**回归**:`go vet` 干净、`gofmt -l` 空、JS 单测 34/34、`go test ./...` 13 包全 ok 0 FAIL。
(注:`internal/web` 里 110 例是 DB 门控的,不开 `ROND_TEST_CONF`/`ROND_SRC` 会 skip,不算真跑过。)
---
## 用户确认后的收尾(四件)
用户反馈:「管理员访问也只剩主页,这好像不对」+ P2 按建议修 + 二进制只留根目录 + 防复发一并做。
### 1. P1 更正:不是配置问题,是导航缺 IsAdmin 分支
上面第 1 条判断得不完整。实测:站长访问 /map /places /timeline /stats /report **全是 200**
(`guardPage` 只拦访客),但导航里只有「主页」⇒ `layout.html` 的页面显隐写的是
`{{if .Settings.HasPage "x"}}`,**没有 IsAdmin 分支**,与 `guardPage` 口径不一致。
改成 `{{if or .IsAdmin (.Settings.HasPage "x")}}` 五处。门禁 `nav_visibility_test.go`
(三向不变量 + 变异验证)。**访客侧的 pages=null 没动**(仍是「只对访客关」的配置状态)。
### 2. P2 修复:`cleanTrackScript` 重写
- `src=` 只在 `<script …>` **开标签内部**找(原来对整段 `strings.Index`,`i.src=u` 被误伤清空)。
- 开闭标签从「只拒 `shut > open`」改成**严格配平**(末尾未闭合的开标签原来会被放行)。
- 签名改 `(script, warn string)`,说明码经 `?warn=` 回显成人话;判危险时**整段不采纳、
库里原脚本与开关不动**。
- 实测(测试实例 8081 / `rond_fog_test`,用完已还原):`i.src=u` 现在原样落库;
不配平 → `?warn=unbalanced` 且库值不变;`javascript:` → `?warn=badsrc` 且库值不变;
5000 字符 → `?warn=truncated` 且落库 4096。注入范围精确复核:只在公开页(/、/map),
后台与登录页 0。
### 3. `bin/` 删除
15 个 exe、412MB 全删;只保留根 `rond.exe`。技能 `rond-web-verify` 与 details 十八的
`bin/rond.exe` 写法已同步改掉。
### 4. 防复发:启动自检 `smokeRender`
`template_smoke.go`:`pageProbe`(24 个页面各一份最小可用数据,键与 `pageFiles` 双向校验)
+ `New()` 里全量渲染一遍,失败即 `log.Fatalf` 拒启。实测:往 settings.html 插一个不存在的
字段 → 启动报 `模板自检未通过…admin/settings: can't evaluate field …`,退出码 1。
门禁 `template_smoke_test.go`(含变异验证:把探针换成字段更少的类型必须报错)。
### 5. 用户裁决 + 文案订正
- **访客侧 `pages=null` 不动**:用户明确说「访客那一侧是根据我在后台配置的显示范围公开的,
倒不如说原来默认就是这样才对」⇒ 那是**预期配置**,不是故障。已把这个结论写进
details 四十一,免得后续会话又去「修」数据。
- **settings.html 的统计脚本文案订正**(P3):原文两处不准 ——
①「多一个 `</script>` 会被判为粘贴错误」漏了「少一个也会拒」(判据已改成严格配平);
②「`conf/app.ini` 的 `track_script` 会作为这里的默认值」有歧义:它**不会回填文本框**,
而是「这个框留空时,注入时回落到 ini 的值」。已改成准确说法。
实测热加载生效(debug=true,无需重编),页面 19996B、含 `</html>`,旧文案 0 命中。
- 验收:官方 `./scripts/verify.sh` → **PASS=346 FAIL=0 SKIP=0**(改动前那次全量;
之后只动了这一个模板文案,重跑了全部模板门禁与 `TestSmokeRender*`,全绿)。
## 提交 + 前端现代化方案
**提交**:`d4e4257`「启动模板自检 + 站长导航放行 + 统计脚本关口收紧」(12 文件,+564/−75)。
⚠️ **`shots/` 里的截图是旧状态,做视觉判断前必须现场重截**:`mobile-home.png` 还显示顶栏
折成 3 行、右按钮竖排,实测现在 390 下品牌名只留 🐾、按钮「后台」、`navH=51` 且不溢出。
差点拿旧图当现状写进方案。
**现状实测(CDP,真实视口)**:
- 卡片:17 个盒子(`.card`/`.kpi`/`.filters-card`)**只有 2 种样式指纹** ⇒ 层级扁平。
- 字阶 8 档(10/12/13/14/15/18/21/23),10–15px 挤了 5 档;字重 400/500/600/**650**。
- 正文色只有 4 种;类型色 10 种只用在圆点与柱子,没进界面语义层。
- 站长导航 `scrollWidth=277`:430→254(溢 23)、390→214(溢 63)、320→144(溢 133);
390 下「统计」被切成半个字紧贴「后台」,`.overflow-right` 的渐隐看不见。
- 已有优点别改坏:KPI 已是 `tabular-nums`、`--text-3` 按 AA 调过、暗色模式已有 3 段 media。
**产出**:`frontend-plan-2026-10-09.md`(仓库根,与 `audit-2026-09-21.md` 并列)。
四批:A 设计令牌收敛(字阶砍到 6 档、字重 3 档、间距/圆角/阴影令牌)→ B 卡片分 hero/常规/次级
+ 首屏 1 个大数 → C 手写图表加基线/峰值/轴标(不上图表库)→ D 类型色语义化 + 窄屏导航。
**明确不做**:前端框架/构建链、图表库、信息架构重构。建议先做 A+B(约 1.5 天,纯 CSS + 少量 class)。
方案**未改任何代码**,等选批次。
---
## 落地:A + B 批次(用户选了「先按 A-B 去做」)
**做法**:先跑基线存档(`ab.js` 探针 + `audit/run_all.py --mobile 390` / `--overflow 1440`),
再改,再用同一份探针跑一遍逐值 diff。CSS 改动量 187+/150−,另有 19 个模板共 54 处内联字号并档。
**关键结果**(同一探针,改动前 → 后):
- `/` 的 (字号,字重) 组合 390:**13 → 10**、1440:**15 → 10**;`/places` 10 → **5**;
`/timeline` 10 → **6**;`/stats` 15 → **9**;`/admin/settings` 10 → **7**。
- 最小字号到处都 ≥11px(原来有 10 / 10.5px)。
- 卡片样式档:`/` 2 → **3**,`/admin/settings` 1 → **2**。
- 溢出:移动端审计**逐值一致**;桌面 1440 唯一差异是 `/map` 露外元素 9 → 8。
- 验收 `./scripts/verify.sh`:**PASS=347 FAIL=0 SKIP=0**。
**踩到的四处**(都只有「量 DOM 的 (字号,字重) 组合」才看得见,截图上看都正常):
1. **Leaflet 字号跟着根字号漂**:vendor `.leaflet-container { font-size: .75rem }`,
根 14 → 13px 后地图署名/比例尺掉到 **9.8px**、弹窗正文也跟着缩。
已在 app.css 钉死(容器 `--fs-sm`、署名/比例尺 `--fs-xs`)。
2. **项目自带的静态守卫抓到我**:`TestNavLinksNarrowRuleHasNoDeadPadding` 写死了 `font-size: 13px`,
并档后它红了。守卫是对的,改判据为「钉规则还在、且设了字号」;另补 `TestNoBareFontSizePx`
(静态扫 app.css + 模板禁裸 px 字号,做过变异验证)。
3. **`h1..h4` 从没设过字号**(原来只有字重与 margin),靠浏览器默认 `2em/1.5em/1.17em` ⇒ 也跟着根字号漂:
根 14 → 13px 后,`/stats` 里没被 `.card > h2` 命中的两个 h2 从 21px 变成 19.5px,比同页卡片标题(15px)大一圈。
已显式给出 h1/h2/h3 字号,实测 12 个 h2 统一 `15px/600`。
4. **`<b>/<strong>` 浏览器默认 700**,比全站最高层级(标题 600)还重 ⇒ 已钉成 600。
**教训(已写进 details 四十二)**:quiet 卡片第一版用 `--bg-2`(#fafbfb),
与页面底 #f6f7f8 只差 4/255 ⇒ 实测看不出边界、像「破了个洞」。**配色差异必须量,不能凭「应该能看出来」。**
**运维提醒**:测试库跑到 180MB / 21 万死元组时 `verify.sh` 会从 8 分钟拖到 12 分钟以上
(脚本 200MB 才自动 VACUUM);手动 `VACUUM (ANALYZE)` 后回到 ~10 分钟、137MB / 0 死元组。
**发现未修**:7 个模板工作区里是 CRLF,而 `.gitattributes` 要求 `eol=lf`
(`admin/index.html`、`admin/login.html`、`admin/twofa-login.html`、`admin/twofa.html`、
`map.html`、`places.html`、`timeline.html`)。本批按字节替换保住了各自行尾、diff 无行尾噪声,
要不要统一另开一次清理。
---
## 落地:C + D 批次(用户选了「C和D继续做」)
**C 图表**:月度分布加基线 + 峰值柱标次数(`.pv`,副标题不再重复写「最高 N 次」);
一天中的分布把「0/6/12/18 四个数字」换成 **6 小时一段的标尺**(深夜/上午/下午/晚上),
用**同一套 24 列 grid** 保证段边界与柱子严格对齐;首页月度图同样加峰值(给 `HomeData` 补了 `MaxMonthly`)。
**空态那条划掉了** —— 查下来已经统一(8 页共用 `emptystate`、局部走 `.empty`)。
**D1 类型色**:先算对比度,结论推翻了原计划 ——
- 白底上 6 个色低于图形 3:1(yellow 1.87 / mint 2.12 / orange 2.20 / green 2.22 / cyan 2.54 / teal 2.57)
- 暗底只有 indigo 2.90 不够
所以**没有**把类型色做成 chips / 表格类型列 / KPI 强调(那几处要的是文字色,会更难读)——
这恰好解释了全站为什么一直只用 8px 小圆点做标记。浅色 6 个色一个没动(是手机端/地图的同一套身份色)。
实际做了:色值收口成 `--cat-*` + `--cat-*-soft`(26 个变量)、模板 `colorof` → `csscolor`/`csssoft`(19 处)、
暗色只提亮 indigo。`colorOf` 已成死代码,删掉。
⚠️ **踩到 `ZgotmplZ`**:`html/template` 的 CSS 过滤器不认识 `var()`,函数返回普通 string 会被替换成
`ZgotmplZ`,页面上所有圆点当场变透明、**且不报错、模板测试照过**。
必须返回 `template.CSS`;而挂了它等于关掉过滤,所以数据侧色值先过严格校验(只有 `#`+6 位 hex 放行)。
已加守卫 `TestCSSColorSurvivesTemplateSanitizer`(两个方向都钉,做过变异验证)。
**D2 窄屏导航**:≤620px 整行收进 `.nav-menu`(原生 `<details>`,JS 只补点外面/Esc/点链接后收起)。
⚠️ 顶栏 z-index 抬到 `--z-nav: 1200`(必须高于地图浮层 1100,否则展开的菜单被筛选面板盖住),
已在 `/map` 用 `elementFromPoint` 实测。改前 390 溢 63px、320 溢 133px(「统计」被切半个字)。
**回归**:`verify.sh` **PASS=348 FAIL=0 SKIP=0**;320/390 溢出**全 0**(改前 `/admin` 在 320 还溢 34px);
桌面 1440 与改前一致;**7 个页面都没有低于 11px 的文字**;暗色下菜单/类型色/阴影均按暗色变量生效。
---
## 提交 + 完整回归(含「原有代码是否受影响」专项)
**提交**:`ab7ccd2`「前端改造:设计令牌 + 卡片层级 + 图表可读性 + 类型色收口 + 窄屏导航」
(32 文件,+997/−283)。A/B 与 C/D 本想拆两笔,但 `app.css`/`layout.html`/`view.go` 里两批改动交织,
按文件拆不开、按 hunk 拆容易做出「中间那笔编译不过」的历史,**合并成一笔、消息里分段**,并在提交消息里写明原因。
**完整验证链**(一次跑齐,全部串行):
- `./scripts/verify.sh`:**PASS=348 FAIL=0 SKIP=0**
- `./scripts/verify.sh --pkg ./internal/fog/ --race`:**PASS=22 FAIL=0 SKIP=0**(mingw 在 PATH 里,-race 可用)
- JS 单测 34/34
- 移动端 320 / 390 + 桌面 1440 审计:**320/390 溢出全 0**;1440 只有 −15(滚动条宽,既有口径)
**「原有代码受影响」专项检查**(静态扫描 + 逐文件回读 diff):
- 自定义属性:定义 90 / 使用 61,**「用了但没定义」为 0**(先前一轮报的 12 个全是我正则的假阳性:
CSS 一行写多个属性、`--cat-*` 是 Go 侧动态拼的、模板 `:root` 里也有定义)。
- 定义了没人用的:只剩 28 个 `--cat-*`(Go 动态拼接,运行时实测 14 种颜色都渲染出来了)——
另外揪出 `--sp-5` 真没人用,已用到「停一下」页的留白上(正好是大间距场景)。
- 模板函数:**没有真孤儿**(先前列表是正则把 `appleColors` 的键当成了函数名)。
- 已删项残留:`colorof`/`--radius`/`--shadow`/旧测试名 全部 0 残留(`app.css` 里那句注释也顺手改对了)。
- 逐文件回读:19 个模板的 diff 只有字号替换与 `colorof`→`csscolor`,没有误伤;
Go 侧 diff 只有 `MaxMonthly`、`cssColor/cssColorSoft`、注册表与 `regexp` 导入。
- 顺带发现(**既有、与本批无关**):`.g3`/`.g4` 是 HEAD 里就有的死类(模板/JS 都没引用);
`.notice-card` 等不是死类 —— 它在 `notice.go` 里由 Go 拼 HTML,我的模板侧扫描覆盖不到。
**验证中抓到的一例失败(已实证是环境抖动)**:
`TestOpenCreatesMissingDatabase` 报「建库后首次连接超时」10.02s。根因是 `db.Open` 的 ping **写死 10s**,
当时库正被验收 + autovacuum + CDP 审计一起压着;停掉审计单独跑 **4.1s 通过**。
⚠️ 这条测试失败还会把临时库 `rond_test_autocreate_*` **留在库里**(清库的 defer 在 `Open` 成功之后才注册)——已清掉残留。
两条结论都写进了 details 三十二的验收小节。