Files
tamabox/.workbuddy/memory/2026-09-05.md
T
tamakyi e3e59e7c69 chore: baseline snapshot before moderation-strictness feature
Repo .git was damaged (refs/ missing, index truncated, object store near-empty).
Repaired via git init (rebuilt refs), stale index preserved as .git/index.corrupt-20260910.bak,
then full worktree committed as a rollback baseline.
2026-09-10 10:56:27 +08:00

43 KiB
Raw Blame History

2026-09-05 工作日志

提问箱公开主页「加载更多」翻页失效(内容重复)排查

  • 用户报告:提问列表加载完后「加载更多」按钮仍在,点击后加载相同内容。示例链接 https://box.tama.guru/_/aoi/3105?t=Kmd0mu(item 页底部嵌有该箱「历史提问」列表 + history-template 加载更多)。
  • 代码链路:templates/question/history-template.html(Alpine fetch) → route/question/page.go ListAPI(/api/v1/user/{domain}/questions) → internal/db/questions.go GetByUserID(PinFirst 复合键集游标 isPinned.CreatedAtUnixNano.ID)。
  • 线上实测(box.tama.guru, aoi 箱共 38 条已答公开问题):
    • 首页 20 条 id 3109→3089;next_cursor=0.1788566476678885000.3089。
    • 携带任意真实 next_cursor 再次请求 → 仍返回首页同样 20 条(has_more 恒 true)→ 内容重复、无法翻页(已稳定复现)。
    • 部分异常游标返回空集/6 条等与源码 keyset 预期不符的怪异结果 → 指向线上二进制或 DB 环境与工作区源码假设不一致(时区/列精度/部署版本),单凭源码无法闭合解释。
  • 前端模板与工作区 0904 版逐字符一致(x-on:click.debounce、payload.next_cursor、注释),说明线上模板=新版;但服务端行为异常。
  • 历史:outputs/re-audit-2026-09-01.md P0-2 曾记录同款症状(前端回传旧格式游标→parsePinCursor 失败→永远第一页),当时修复为服务端下发 next_cursor;但线上当前仍复现,说明修复未生效或有残余缺陷。
  • 后续建议:生产库执行 keyset SQL 直查对照 + SHOW CREATE TABLE 确认列精度;代码侧做健壮化(游标未前进/解析失败 → 返回空 + has_more=false;前端按已见 id 集合防重)。

落地修复(用户选定:防重复兜底)

  1. internal/db/questions.go:
    • GetByUserID:携带游标但 PinFirst 复合游标/纯 id 游标解析失败时,由「忽略游标静默回退首页」改为直接 return []*Question{}, nil(空列表 → 上层 has_more=false → 按钮收敛)。
    • getBy(GetByAskUserID 旧路径):同步改为解析失败返回空。
  2. templates/question/history-template.html:
    • SSR range 项与 JS append 项均加 data-qid;点击时先扫描 #question-list [data-qid] 收集已见 id,过滤重复项;无新增条目时 more=false(按钮隐藏/显示无更多)。
    • 注释说明重复加载 bug 的历史形态。
  3. 验证:go build ./internal/db/...、go vet ./internal/db/ 通过;模板测试 TestTemplatesParse/TestTemplateCrossReferences/TestRenderPublicQuestionList/TestRenderPublicQuestionItem 全 PASS。全量 go build ./... 因第三方 chai2010/webp(CGO,本地缺 C 库)预存失败,与本次改动无关。
  4. 待办(未做):生产侧核对部署二进制是否含 9/1 P0-2 修复、DB 列精度/时区一致性诊断;线上复现的 keyset 怪异行为(同 nano 不同 id 返回不同页等)仍未完全由源码闭合解释。
  • 为用户产出 PG 根因诊断脚本 outputs/pg-cursor-pagination-diagnose.sql:PART A 环境/表结构/集合核对(含 created_at 列精度、索引、answered_public_all 应=38 与线上 API 对齐);PART B 用 DO+临时表纯 SQL 复刻 ListAPI 复合键集翻页循环,逐页打印 ids、带死循环/重复页检测;PART C UnixNano 指纹核对(1788566476678885000 类)用于区分部署版本旧 vs DB 环境问题。ListAPI 等价条件已核对: FilterAnswered(True)+PrivateStatus=1+PinFirst+page_size=20+1 探测。待用户执行回贴结果判读。
  • 生产库真实结构确认(用户探查): schema=nekobox(search_path 默认 public 导致首版脚本找不到表);nekobox.questions: id numeric(seq nekobox.questions_id_seq), created_at/updated_at/deleted_at = timestamp(6) WITHOUT TIME ZONE, user_id bigint, answer text, is_private/is_pinned/is_read boolean NOT NULL;nekobox.users 含 domain。线上库与源码(GORM timestamptz 假设)不一致 -> 无时区列+Go UTC 解释=线上 keyset 错位头号嫌疑。产出 v2 脚本 outputs/pg-cursor-diagnose-v2-nekobox.sql:SET search_path=nekobox; PART A 结构/集合核对(应38)+DB墙钟vs线上Z文本目视(差8h即偏移实锤); PART B DO+临时表纯墙钟 keyset 复现(锚点 timestamp 变量避免时区换算, 重复页/死循环检测); PART C nano 指纹反推命中检测(match_3089)+Z文本墙钟命中。待用户执行回贴。
  • 【根因闭合】v2 脚本线上结果: aoi_user_id=329, answered_public_all=38(与线上API一致), 无置顶行(pinned=0)。DB 墙钟==线上 JSON Z 文本(无时区偏移,会话 Asia/Shanghai 不影响无时区列直比)。PART B 纯墙钟 keyset 翻页: 第1页20条(3109..3089)=线上首页, 第2页18条(3088,2883..2411), 无重复无跳行 -> DB 层完全自洽。PART C: nano=1788566476678885000 反推墙钟 00:01:16.678885 精确命中 3089 (match_3089=t), Z 文本命中 3109/3089 -> 服务端 encode 正确、无时区/精度错位。结论: DB/SQL 层彻底排除,线上"游标被无视返回首页"只能用【线上部署二进制与 0904 源码不一致(解析路径差异)】解释。修复=部署含防重兜底的最新源码; 部署后需 curl 复测翻页收敛。
  • 【真根因确认+已修复】部署 0904 后线上仍复现 -> 读 parsePinCursor 源码定位: time.Unix(0, nano) 返回 Local 时区,进程 TZ=Asia/Shanghai 时墙钟 +8h(00:01->08:01)。生产 questions.created_at 是 timestamp WITHOUT time zone,驱动按 time.Location 墙钟直发无时区列 -> created_at < '08:01' 对库内全部 00:xx 行恒真 -> keyset 退化为全量 -> 永远返回首页 has_more=true -> 无限循环。本地实验 tz_proof.go 证明 08:01 vs 00:01 偏移。已修复 internal/db/questions.go parsePinCursor: time.Unix(0,nano) -> time.Unix(0,nano).UTC()(含时区约定注释)。build/vet PASS。其余 UnixNano 用途(随机/文件名)无 keyset 风险。待用户重新部署后 curl 验收翻页收敛(38条唯一)。
  • 【修复验收通过】用户重新部署后线上验证:第1页20条(新增20) has_more=true -> 第2页18条(新增18) has_more=false -> 总计38条唯一,完全收敛 ✓。非法游标(abc)/旧纯id游标(3089)均返回 {"data":[],"has_more":false} -> 解析失败收敛兜底同时生效。根因(parsePinCursor 时区偏移)与今日两处防重兜底均已上线。问题闭环。
  • 用户拟将生产库克隆到本地实验环境做 timestamptz 迁移测试。本地已建独立 PG 测试实例: 127.0.0.1:5433, user=postgres, trust 认证, data 目录 $HOME/AppData/Local/Temp/tamabox-pg-clone-test/data (PostgreSQL 18 at C:/OtherFiles/PostgreSQL/18)。等待用户 pg_dump 生产库(Fc, --schema=nekobox) 后导入跑迁移验证(epoch 快照/转换/验收/翻页复现)。注意本地另有用户自己的 5432 实例(scram 认证, 无密码勿扰)。
  • 【timestamptz 迁移已在克隆库验证通过】用户 dump(nekobox_clone_20260905.dump, 资料库 drive 节点 6oAmSRkxq7DVFAnqRt8QEv) 下载后导入本地 5433 测试实例 nekobox_clone。结果: 16 表, aoi=38 与线上一致。实际无时区时间列仅 4 表 12 列: questions/users/censor_logs/upload_images(其余表本为 timestamptz)。Asia/Shanghai 会话下迁移 ALTER TYPE timestamptz USING AT TIME ZONE 'UTC': 1.7s 完成, epoch 前后差异 0 行, 残余 without=0; 关键行指纹 3109=1788569378648502000/3089=1788566476678885000/2411=1781735419615754000 与线上一致; keyset 翻页带 +00 参数精确翻出线上第2页同款 18 条; 索引完整; 回滚路径双向验证无损。产出 outputs/timestamptz-migration-online.sql(PART0 核对/1 快照/2 迁移/3 验收4项/4 注释回滚)。克隆测试实例与 dump 暂存本地 Temp, 待用户线上执行确认后清理。
  • 【线上 timestamptz 迁移执行成功】用户线上跑 timestamptz-migration-online.sql: PART0=4表12列, PART1快照12列, PART2迁移DO完成, PART3验收全绿: 3.1 epoch差异0行, 3.2 remain_without=0, 3.3 指纹 2411=1781735419615754000/3089=1788566476678885000/3109=1788569378648502000 与克隆库/线上游标一致, 3.4 keyset第2页18条(3088,2883..2411)同款。但端到端验收受阻: box.tama.guru 持续 HTTP 521(源站不可达, 页面+API均打不开, 观察约2.5min) -> 疑似用户正在重启/部署应用或服务宕机, 待服务恢复后重跑翻页验收脚本(38条唯一收敛)确认整体闭环; 本地5433克隆实例与dump暂留待最终验收后清理。
  • 【端到端验收通过·最终闭环】服务启动后重跑线上翻页: 第1页20条 has_more=true -> 第2页18条 has_more=false -> 38条唯一收敛 ✓。注意: 迁移后 JSON created_at 文本从 "...Z"(UTC) 变为 "...+08:00"(session TZ=Asia/Shanghai) —— 绝对时刻一致。前端消费核对: history-template SSR {{Date .CreatedAt}} 迁移前显示 UTC 墙钟(少8h) 而 JS dayjs() 追加项本地化 -> 首屏与追加时间曾不一致(隐藏显示bug), 迁移后 SSR 读 timestamptz 转会话时区 -> 两者一致且显示上海本地时间(对用户更正确); item.html/list.html 同理顺带修正。无需改代码, 属显示语义修正观察项。遗留: 用户清理 diag_test 报依赖错误 -> 解答用 DROP SCHEMA diag_test CASCADE (schema 内仅 snap_before/snap_after 两张自建快照表)。本地 5433 克隆实例+dump 待清理。
  • 【发现迁移基准错误+已产修复脚本】用户反馈: 真实本地时间 00:01 的提问页面显示 08:01 -> 存量墙钟实为"上海本地时间"(驱动按进程本地墙钟写无时区列, 读出按UTC标记, 文本一致造成 v2 诊断"对称"假象), 先前迁移用 AT TIME ZONE 'UTC' 把上海墙钟误标 UTC -> 存量绝对时刻整体 +8h。克隆库验证反向修正(USING c AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Shanghai', 净-8h): 3089 08:01->00:01:16+08 (epoch 1788566476678885000->1788537676678885000), 3109->00:49:38+08, 2411->06-17 22:30+08; keyset 第2页仍18条。产出 outputs/timestamptz-migration-fix-8h.sql (PART0 聚焦4表12列/1快照/2修正/3验收含3.1显示+epoch/3.2翻页/3.3计数/3.4残余/4注释回滚=反向AT TIME ZONE 'Asia/Shanghai' AT TIME ZONE 'UTC')。克隆库全流程演练通过。待用户线上执行贴回 + 我重跑 API 验收(next_cursor nano 应从 0.1788566476678885000 变 0.1788537676678885000)。
  • 【线上反向修正验收通过】用户线上执行 timestamptz-migration-fix-8h.sql(PART2 修正完成, 后续输出被 psql 分页截断不影响), 我直接 API 验证: next_cursor nano 1788566476678885000->1788537676678885000 ✓, created_at 文本回到本地墙钟 00:49:38.648502+08:00 / 末条 00:01:16.678885+08:00 ✓, 翻页 38 唯一收敛 ✓。存量时间语义修正为"上海墙钟"。注意: 该脚本不可重跑(会再-8h)。遗留: 用户如需补看验收可跑只读 SQL; diag_test 清理可用 DROP SCHEMA diag_test CASCADE; 本地 5433 克隆实例+dump 待清理(询问用户后执行)。
  • 【留档完成】事故复盘文档 outputs/TamaBox-v4-keyset-pagination-timezone-incident-2026-09-05.md:完整记录两层缺陷(①parsePinCursor time.Unix Local +8h 致 keyset 失效②timestamptz 迁移基准误用 UTC 致存量+8h 已反向修正)、时间线、4文件代码改动、SQL 脚本产物清单(标注 v1/v2 已淘汰、online.sql 基准错误勿复用、fix-8h.sql 不可重跑)、经验教训预防清单(无时区列+带时区代码混用是土壤/迁移前须用现实锚点确认数据语义/文本一致≠语义正确)、遗留建议(页面抽查/可选 UTC 输出/清理克隆实例与dump/生产 DROP SCHEMA diag_test CASCADE)。

UIkit CSS 迁移公共 CDN(速度优化落地)

  • 背景:生产速度测试发现 R2 自托管 uikit/3.3.3/css/modify-black-font/uikit.min.css(263432B)加载 ~1100ms 是大头。
  • Diff 结论:自建版与官方 [email protected](263444B,sha256 6630e078...)仅 3 处颜色差异——把有色容器(.uk-light/.uk-card-primary/.uk-card-secondary/.uk-overlay-primary/.uk-section-/.uk-tile-/.uk-offcanvas-bar)内默认白字/白标题改黑:容器文字与 table th rgba(255,255,255,.7)→rgba(0,0,0,.7),h1-h6/.uk-h*/.uk-heading-* #fff→#000。
  • 模板实际仅用 .uk-light(用户背景封面,question/list.html、question-not-found.html;内部 h3/p 由 #usernamecolor/#introcolor 内联 JS 覆盖,优先级最高),其余有色容器全仓无 class 使用 → 补丁可只投影 .uk-light(477B 代替 9KB)。
  • 测速(本地国内网络,全量 263KB 3 次):cdnjs.snrat.com ~0.25s(热)最快 > jsdelivr ~0.47s > unpkg ~1.3s > cdnjs.cloudflare ~1.0-1.4s > R2 自建 1.4-2.0s。check-host.net 全球 12 节点:snrat 与 jsdelivr 均 12/12 = 200 OK(snrat 根路径 301 不影响带资源路径请求)。snrat 缓存头 max-age=31104000(360 天)。
  • 落地修改(仅 templates/base/header.html):
    1. css link → https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/css/uikit.min.css
    2. js(uikit.min.js/uikit-icons.min.js)→ https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/...(CDNJS 路径与 cdnjs 官方同构,已验证文件存在 Content-Type 正确)
    3. link 后新增补丁 <style>(.uk-light 黑字 3 条规则 + 扩展警告注释)
    4. 头部 preconnect 增加 https://cdnjs.snrat.com(注释同步更新,原"全部归拢 R2"说法过时)
  • 验证:go test ./templates(TestTemplatesParse/TestTemplateCrossReferences/TestRenderPublicQuestionList 等)全 PASS;CSS 括号配对/规则数 3 条自检通过。
  • 未做(用户排除):Rocket Loader(cloudflare-static/rocket-loader.min.js 1100ms)需在 Cloudflare 后台关闭 Speed→Rocket Loader。
  • 注意:原 R2 路径 .../expire-1-y/uikit/3.3.3/css/modify-black-font/uikit.min.css 仍保留可访问(回滚用)。若日后引入 .uk-card-primary 等容器需黑字,须扩展补丁(参考此节差异清单)。

UIkit 迁移生产/测试环境验收(对比通过)

  • 部署后对比(真实浏览器 computed style 实测,agent-browser eval,注意本会话模型不可读图、勿再用"看截图"断言):
    • 生产 box.tama.guru/_/tamakyi(旧代码):uikitSheet=r2 modify-black-font;.uk-light 容器色 rgba(0,0,0,.7);navbar_bg rgb(248,248,248);username 内联色 rgb(0,123,255)(小狼账号自设蓝)、intro rgb(205,76,108)(自设粉)。
    • 测试 box-dev-api.337845818.best/_/admin6(新部署):uikitSheet=cdnjs.snrat.com 官方;.uk-light 容器色 rgba(0,0,0,.7)(补丁生效=modify-black-font 等价);navbar_bg rgb(248,248,248) 一致;username/intro 内联色 rgb(0,0,0)(admin6 账号默认黑,非 CSS 差异)。
    • 结论:UIkit 相关 computed style 两环境逐值一致 → 迁移无回归。用户名/简介颜色差异仅来自各账号服务端颜色字段。
  • 环境坑记录:agent-browser 冷启动需 agent-browser install(Chrome 152 下载 193MB,卡住原因=缺浏览器);open+eval 组合命令易超时被 auto-background,应 open 与 eval 分两条命令执行;本环境 curl 落盘/-o /dev/null 偶报 error 23 但不影响数据(可改 stdout+管道)。Chrome 位置 C:\Users\Tamakyi Gekka.agent-browser\browsers\chrome-152.0.7977.82。

uikit R2 vs snrat 国内外测速(5 次全量下载中位,2026-09-05)

  • 国内本机:OLD-css 0.864s→NEW 0.200s(4.3x);OLD-js 0.796→NEW 0.163(4.9x);OLD-icons 0.824→NEW 0.177(4.7x)。三资源合计 2.48s→0.54s,净省 ~1.9s。
  • 国外 check-host.net 多节点(两轮):CSS p50 R2 240-358ms vs snrat 233-420ms ≈ 打平(R2 偶发长尾 max 3.3-4.8s,snrat 平稳 ≤896ms);JS p50 R2 372ms vs snrat 647ms,R2 快 ~40%。
  • 结论:snrat 国内完胜;海外 R2(Cloudflare 全球边缘)略优/打平。站点访客以国内为主 → 切 snrat 净收益大。若未来在意海外可 geo 双源(国内 snrat / 海外 R2),当前不做(过度设计)。
  • 测速脚本已归档 dev/bench-cdn.sh(cn=国内 5 次全量取中位 / global=check-host.net 海外 p50/p90),cn 模式冒烟通过(复测数据与基线一致)。

部署架构澄清(用户补充 + 实测确认)

  • 用户架构:正式 box.tama.guru 与测试 box-dev-api.337845818.best 均经 Cloudflare Tunnel 开放;box.tama.guru 是国内走腾讯 EdgeOne 的双入口。
  • 实测(国内本机/出口视角):box.tama.guru → 43.174.247.43 Server: TencentEdgeOne(HTML 无 rocket-loader 注入,干净);box-dev-api.337845818.best & r2.337845818.best → 172.67.144.141 Server: cloudflare CF-RAY AMS(HTML 含 rocket-loader);cdnjs.snrat.com → 101.227.21.24(国内节点)。
  • 推论:Rocket Loader 只在 Cloudflare 边缘对走 CF 的请求注入 → 仅影响海外路径与测试域名;国内 EdgeOne 路径 HTML 干净(EdgeOne 回源直连源站不经 CF HTML 重写)。本机出口连 CF 落在 AMS(阿姆斯特丹)→ 本机测 R2 慢不代表真实国内用户(其可能经 CF 亚洲/香港节点),但 snrat 国内节点快是实打实。
  • 待用户确认:① 之前 1100ms rocket-loader 截图是否来自海外/测试域名或未接 EdgeOne 前 ② r2.337845818.best 是否也接 EdgeOne(未接 → 静态资源国内仍可能慢,是后续优化重点)③ CF 侧 Rocket Loader zone 开关位置。
  • 【用户澄清+盘点完成】①截图=PageSpeed(海外探测),非国内 ②r2.337845818.best 未接 EdgeOne ③DNS 分流架构:dnspod 按境内/境外解析 box.tama.guru,境内 EdgeOne/境外 Cloudflare。据此修正认知:国内不受 Rocket Loader 影响;国内真实瓶颈=R2 的 CF 国际链路。全量盘点 r2 静态资源(outputs/r2-assets-cdn-audit-2026-09-05.md):sha256 校验 6 个 JS 库(jquery/dayjs/alpine/cropperjs/vConsole/waline.js)=纯官方原版;实测 R2 每资源 0.72-1.10s vs snrat 0.15-0.42s(2-7.4×);关键认知=公共 CDN(cdnjs.cloudflare/jsdelivr 0.6-1.8s)≠快,要选 snrat 国内节点。waline-no-commits.css 为刻意定制(39 条 .wl-card display:none 隐藏评论列表,与官方选择器全同)不可直换官方。easy.qrcode=remake 定制、neko-pixel 0.0.21 npm 查无、time.box.js/图片图标=专属 → 无公共源。建议:方案 A(R2 接 EdgeOne 根治定制文件)+方案 B(A 组 5 库迁 snrat) 组合,待用户批准。
  • 【重大认知修正 + 方案落地】itdog 大陆多节点测速(用户截图):box.tama.guru(EO新加坡,43.174.247.43)大陆均值 3.2-3.6s、三网骨干峰值 9-11s(四川电信 11.1s);box-dev-api(纯 CF,172.67.144.141/147.52/80.1)大陆均值 5.7-6.5s、峰值 12s。反向分布:港澳台/新疆/内陆部分省份反而 300-500ms。结论:① CF 与 EO 单走大陆都慢 3-12s,CF tunnel 不是备案前解药,删 DNS 分流的方案被证伪 ② R2 大陆实测 ~250ms 正常,静态资源非瓶颈 ③ 真正瓶颈=大陆→境外源站(EO新加坡/CF边缘)动态页链路。Rocket Loader 用户已手动关闭,HTTP/3 已开启。后端审计初步:box-dev-api 的 /favicon.ico→302 首页、robots.txt 1.1-2.4s(本机 AMS 视角)、cf-cache-status: BYPASS → 静态未缓存且每次回源,存疑点待大陆视角复核。根本解决路径只剩备案+大陆 CDN(腾讯云/阿里云,或 CF 中国伙伴京东云/世纪互联),备案前可做项=静态库迁 snrat。方案 B 已落地:jquery3.7.1/dayjs1.10.8/alpine3.9.0/cropper1.6.2(js+css 用 min 版)/vConsole3.12.1/waline2.15.8 共 7 文件全部 sha256 校验一致后 R2→cdnjs.snrat.com(4 文件:header/list/question-not-found/profile),备份在 .workbuddy/backup/cdn-migration-20260905/,go test templates 通过。R2 保留:easy.qrcode remake/waline-no-commits.css/time.box.js/pickr(1.10.1 snrat 404 未收录)/neko-pixel 0.0.21/logo/社交图标。
  • 【snrat 部署验收通过】用户部署 box-dev-api 后用浏览器实测 admin6 主页:HTML 全部 snrat 引用已生效(uikit/css/js/icons、dayjs/alpinejs、waline.js/jquery/min),无 Rocket Loader 注入。document.readyState=complete,UIkit/Dayjs/jQuery/Waline 全局对象全部存在,UIkit 组件(navbar、tab、表单、按钮)渲染完整、.uk-light 补丁正确生效、定制文件(waline-no-commits/easy.qrcode remake/time.box.js/社交图标)继续走 R2 无回归。截图已存 outputs/admin6-snrat-check.png。验收小波折:open+eval 组合命令易卡顿(已分步解决),首次 eval 在 defer 脚本未执行完时探测 typeof UIkit=false 属时序问题,等 3s 后 UIkit=true。
  • 【生产部署验收通过】box.tama.guru 主页/用户页 HTML 引用全部确认(uikit/dayjs/alpinejs/jquery/waline.js → cdnjs.snrat.com,旧 R2 库残留=0,定制文件 waline-no-commits/time.box.js/tamabox_low.png 继续 R2 200 可达)。浏览器实测 /_/tamakyi:UIkit/dayjs/jQuery/Waline 全局对象全部就位(UIkit=function)、navbar rgb(248,248,248)、.uk-light rgba(0,0,0,.7) 补丁生效、用户名 rgb(0,123,255) 账号自设色、28 UIkit 按钮,无回归。截图 outputs/prod-tamakyi-snrat-check.png。⚠️ 踩坑记录:agent-browser 探测 defer JS 库有显著时序窗口——本机(AMS 出口)拉 snrat 国内节点 133KB uikit.min.js 需数秒,过早 eval typeof UIkit=false 属假阴性;且 CDN 无 Timing-Allow-Origin 时 resource timing 全 0 属正常。正确姿势:open 后 sleep≥8 再 eval,或先 fetch 触发等待;判断库是否成功以全局对象(typeof)为准,勿信 resource timing。
  • 【后端审计补完】澄清两个疑点+确认一个真问题:① /favicon.ico、/robots.txt、/ 的 302 是 curl -sSI(HEAD) 假象——flamego f.Get 路由对 HEAD 不匹配返回 302,GET 全部 200,浏览器无影响,撤稿之前"favicon 302"结论。② 真问题:route.go 的 favicon/robots/sitemap/llms/llms-full 5 个 embed handler 只设 Content-Type 无 Cache-Control → CF cf-cache-status: BYPASS、EdgeOne Age:0 每次回源 tunnel。全项目仅 share.go:501 share-card 设了 public max-age=300;/static/* 由 flamego.Static CacheControl 统一 86400。③ 动态页 HTML 无缓存头是预期(个性化),edge 每次回源属免备案架构使然。待批修复:5 个 handler 各加 Cache-Control: public, max-age=86400(约 5 行,纯增益)。源站不在本机(无 cloudflared/tamabox 进程),localhost 直测不可行。
  • 【修复落地】route.go 5 个 embed 静态 handler(/favicon.ico /robots.txt /sitemap.xml /llms.txt /llms-full.txt)各加 Cache-Control: public, max-age=86400。验证:gofmt 干净 + go build -overlay 编译通过 + go test ./internal/route/ 通过。⚠️ 环境坑记录:Windows 本机全量 go build/go test 会因 chai2010/[email protected](cgo 依赖 libwebp) 报 undefined webpGetInfo 等——需用 dev/webpstub 机制:dev/overlay.json 已失效(指向旧仓库路径 TamaBox-v4-time),正确姿势=自建 overlay 把 internal/storage/s3.go 替换为 stub(s3.go 导出符号仅 MaxUploadBytes/UploadAvatarToS3/UploadBackgroundToS3/UploadPictureToS3/ConvertStaticImageToWebP + oss.go 引用的私有 isSupportedImage),本次 stub 存 %TEMP%/s3_stub_tamabox.go、overlay 存 %TEMP%/ov-tamabox.json,命令:go build/test -overlay=...。部署链:Dockerfile CGO_ENABLED=0 + go build ./cmd/(生产无碍)。
  • 【测试环境缓存修复验收】box-dev-api 5 路径(favicon/robots/sitemap/llms/llms-full)响应均已带 Cache-Control: public, max-age=86400(HTTP 200)。⚠️ CF 缓存机制要点:无 cookie 首访 → session 中间件 Set-Cookie(flamego_session) → cf-cache-status: BYPASS 永不缓存;带有效 cookie 请求 → 不 Set-Cookie → MISS→HIT(Age 递增) 正常缓存。真实浏览器=先访问 HTML 已种 cookie→后续 favicon 等请求均带 cookie→缓存命中;无 cookie 场景仅 curl 首访/搜索引擎爬虫(低频,可接受)。测试环境通过,用户将部署生产。若日后想让爬虫也命中缓存:把静态路由挪到 session 中间件之前或让 session 跳过静态路径(本次未做)。
  • 【答疑】/.well-known/pki-validation/fileauth.txt 删除后仍被爬:① 线上实测两环境均 302→/(Go http.Redirect 标准输出),文件内容确已删除生效;② 请求持续=全网证书/安全扫描器将 .well-known/pki-validation 与 acme-challenge 同列标准探测目标,按字典批量扫所有域名,与文件是否存在无关;③ 302 来源=route.go:396 f.NotFound handler(先 ab.Record 404 计数再 ctx.Redirect("/"),注释说明 flamego NotFound 先写 404 再 302);④ 噪音放大:探测 302→扫描器跟随→再请求 / 首页,日志翻倍且 CDN 不缓存 302(EO-Cache-Status: MISS/DYNAMIC)每次回源。治理可选:CDN 规则边缘拦 .well-known/*(推荐,零回源)/f.NotFound 对探测路径直接 404 不 302/autoban 敏感路径加速封禁。等待用户选方向。
  • 【架构澄清+瓶颈定位实验设计】用户澄清架构:海外=CF+tunnel+优选网络;国内=EdgeOne 直连源站 IP(回源不走 tunnel)。质疑"大陆→境外源站"归因。回应要点:大陆用户连的是 EO 节点非源站(此前表述简写失准),但 EO 国际站无大陆 PoP(43.174.247.43=新加坡),"境外段"=大陆→EO 新加坡节点(itdog 3-11s 证据即此段)。分离实验:生产 robots.txt 已确认 EO HIT 缓存(MISS→HIT Age 2/3,证明 cache-control 5 行修复已部署生产生效)→ 用户 itdog 对比 robots.txt(HIT 零回源) vs /_/tamakyi(每次回源),差异=EO→源站回源段+源站处理;若 robots 也 3s+ 则瓶颈纯在大陆→EO 段与回源方式无关。需用户补测+告知源站位置(决定回源段性质:源站大陆则 EO 新加坡→大陆回源也属国际链路)。
  • 【链路分解实测完成】用户确认服务器在境外。三组实测:① 本机 curl(AMS 出口):robots.txt(EO HIT 零回源) 0.6-2.2s 波动 vs 动态页 /_/tamakyi ttfb 0.87-1.46s——EO HIT 也波动大,非回源差异;② check-host.net 全球 25 节点:robots.txt(EO HIT) p50=1258ms min505(us2) vs 动态页(回源) p50=1217ms min735(jp1)——两者几乎相同→ 证明 EO→境外源站回源段快(服务器境外),动态页不比零回源静态慢;③ agent-browser 页面级(AMS):TTFB 348ms、HTML download 555ms、load_total 1.1s、最慢资源 log beacon 1944ms。结论:动态页慢的根因=用户→EO 新加坡节点段(大陆 itdog 3-11s 因国际出口拥塞;连欧美节点也 0.5-2.7s 因 EO 国际站无大陆 PoP 且节点网络质量差),与回源方式(tunnel/优选/直连IP)无关。对照:snrat(国内 cdnjs 镜像) 全球 p50 仅 257ms ≪ EO p50 1258ms,EO 国际站全球表现差。根治=备案+大陆 CDN。
  • 【HTML 压缩评估】生产 /_/tamakyi:原文 61,125B(内联 style 11 块 19,972B + 内联 script 10 块 14,048B + 外链 9js/2css + 空白 4KB)。gzip 已在源站开启(internal/route/gzip.go GzipHandler 挂 http.Server 最外层,处理 204/304/嗅探/Flusher,不主动 flush 单块输出;EO 透传带 Vary),gzip-9 后仅 14,966B(24%)。无显式 Flush 调用点 → 无多次 RTT 问题。结论:压缩已最优;555ms download 主因是高 RTT 非体积;内联 CSS 20KB 是设计(高 RTT 下内联优于外链+缓存),不建议外链化;剩余微优化(minify 内联块/去空白)收益 <1KB gzip,无意义。真正优化=降 RTT(大陆 CDN)。
  • 【EO 优选调研】结论:①有,社区"EO 优选 IP"玩法与 CF 优选同原理:EO 官方 CNAME 把大陆调度到新加坡(43.174.247.43 AS139341 ACE)慢,社区做法=DNS 改 A 记录直指香港等优质 EO 边缘 IP(43.174.150.x 香港同 AS)。数据源 wetest.vip(page/edgeone/address_v4 需登录,15min 更新)/cf2dns 面板/archlinuxcn forum 教程。②实测:xhh 教程香港 IP 43.174.150.199/119 已失效(000,时效性强需活源+月度更新);EO 大陆可达节点列表(EdgeOne-ips-Checker available_eofreecn_ips 167 个大陆 IP)接口 2026-07-31 停服 8-31 下线,实测全 000 → B 类已死。③EO 官方内建"自研协议优化/回源链路探测"(类 Argo)但无法解决无大陆 PoP;优选只能把边缘从新加坡换香港(大陆 3-11s→预计 50-200ms,待 itdog 验证)。④落地=dnspod 境内线路解析值改 A 记录指向活香港 EO IP(多 IP+TTL60-300s+月度更新),境外保持 CF。风险:灰色玩法/证书 SNI 需实测/EO 不承诺。结论已回复用户,未动手改 DNS。

EO 优选方案 B 免费实测(用户排除付费 wetest.vip 后执行)

  • 【用户确认】方案 B=自扫或公开 CNAME 均可,不限香港,周边区域比新加坡好即可。
  • 【免费公开源全灭实测】wetest.vip 需会员(公开页0 IP);*.v1/v4.eo.fastlydns.cn、eo.072103.xyz、eo.088086.xyz 全部 NXD;蓝点网/雾创岛 43.174.150.x 香港 IP 证书已退回 *.cdn.myqcloud.com(CDN 通用池) 全失效。博客佐证(2026-02):"EO 现在不能使用优选节点,非适用节点返回 418"。
  • 【方法论修正】TLS 握手成功≠可用(腾讯 CDN 泛播池也握手);正确判据=schannel 证书校验过(CN=box.tama.guru)+HTTP 200+Server: TencentEdgeOne。
  • 【扫描事实】43.174/43.175 全 /16 抽样(3072)+官方段/HK/JP 细扫(56 /24≈14000 IP):能服务 box.tama.guru 的 EO 池 9 段全新加坡(192-195/218/240-241/246-247);EO 泛播确实同步全球——HK(43.175.115/119/43.174.126 共8 IP)、东京(43.175.16/17/18/113 共6)、大阪 107.217、AMS/DXB 零星可服务。
  • 【南宁电信视角(真实大陆)】官方新加坡 TCP 180ms/TTFB 0.8-1.0s 反而最优;香港候选 351-377ms/TTFB 1.3-1.8s、东京 276-299ms/TTFB 1.1-4.0s(不稳) 均更慢 → 官方 CNAME 即 EO 对大陆优化调度,自扫候选跨境路由绕。单点结论≠全国,华南可能反转,已列 15 个候选 IP 待用户 itdog 多节点验证(报告 outputs/eo-free-probe-2026-09-05.md)。
  • 【工具沉淀】dev/eo-probe-ips.py(TLS快速预筛)、dev/eo-probe-v2.py(schannel 严格判定,可复用任意域名)、dev/eo-scan-all.py(TCP+openssl 两段式大范围扫描)。
  • 【下一步】用户 itdog 验证候选 vs 新加坡;若均不优→方案 B 到此为止(免费优选时代窗口 2025中-2026初已关),剩余=备案+大陆CDN 或维持现状。

头像+二维码加载慢诊断(个人主页 /_/tamakyi,南宁电信实测)

  • 【根因1 P0】R2( r2.337845818.best ) 图片对象全部无 Cache-Control(仅 ETag+Last-Modified,cf-cache-status: DYNAMIC);头像 Last-Modified=当天→启发式缓存≈0→每次页面加载重下头像。304 也 1.05s(RTT 省不掉)。上传代码 s3.go PutObjectInput 从未设 CacheControl(已确认)。
  • 【根因2 P0】R2 纯 CF 国际链路:南宁实测每资源 0.78-1.4s(头像 0.9-1.05s/背景 297KB 1.39s/logo js 0.96s/1.6KB time.box.js 也 0.9s=RTT 主导);snrat 大陆镜像 0.3-0.5s 作对照。
  • 【根因3 P1】easy.qrcode.min.js(52KB,R2) logo 分支:头像 onload 才绘制,onerror 仅 console.error 无降级→头像挂/失败=二维码永久空白。
  • 【根因4 P1】头像缓存键分裂:header.html icon/favicon 用 ?og-image=1(646-648),list.html+页面头像+QR logo 用 ?v=2 → 一页下载 2 份。
  • 【根因5 P1】背景 box_background.png 303KB 未压缩 PNG(2024-08 上传未变)。
  • 【根因6 P2】defer 统计脚本拖 DOMContentLoaded:vercount 1.24s(波动2.7s)/mami 波动3.7s → 二维码初始化(DCL)被拖。
  • 【修复方向】P0① s3.go 加 CacheControl public,max-age=31536000,immutable(图片 key 随机不可变安全);P0② easy.qrcode onerror 降级无 logo 绘制+超时;P1③ 统一头像 query 键(og-image=1 无 Go 处理疑似遗留);P1④ 背景转 WebP≤60KB;P1⑤ 统计脚本 async;P2⑥⑦⑧(R2 前接 EO 回源=治本)。
  • 报告 outputs/avatar-qrcode-slow-2026-09-05.md;抓包快照 outputs/tb-page-snapshot.html;库源码已存 dev/easy.qrcode.min.js、dev/time.box.js。

P0 批落地:s3.go immutable 缓存头 + 二维码降级渲染(用户批准后执行)

  • 【用户授权】"先备份当前源码,然后尝试吧"→ 执行诊断报告的 P0-① 与 P0-②。
  • 【备份】.workbuddy/backup/p0-avatar-qrcode-20260905/(s3.go + header.html + list.html + question-not-found.html + profile.html,含修改前版本;header.html 修改前版本用脚本从当前版精确移除新增块生成,已与 cdn-migration 基线比对仅差上午 10 行 CDN 迁移改动,验证一致)。
  • 【改动1 s3.go】uploadPictureToS3 的 PutObjectInput 增加 CacheControl: public, max-age=31536000, immutable(key=picture/日期/随机hex 内容不可变,安全)。SDK v1.47.5 PutObjectInput.CacheControl 字段验证存在;gofmt 通过。
  • 【改动2 header.html】 后新增全局 window.tbRenderQR(el, getOptions):核心修复 easy.qrcode logo/背景图加载失败仅 console.error 无降级导致二维码永久空白。策略=已知可用层立即绘制(logo 记忆命中零等待一次成型)→ 未知层先省略画基础码(立即可扫)→ Image 探针判定后重绘升级版;失败记忆 _tbQrGood/_tbQrBad 按 URL 同会话缓存;3s 超时兜底;迟到 onload 仍能补 logo。实测 8 个行为用例全过(node stub QRCode/Image)。
  • 【改动3 三个调用点】list.html(公开主页)/question-not-found.html:new QRCode→tbRenderQR;profile.html updatePreview 同改(debounce 高频重绘场景靠 URL 记忆避免闪烁)。背景图分支(库内无 onerror 同风险)一并纳入降级。
  • 【验证】go test ./templates/ 全绿(TestTemplatesParse/CrossReferences 等);8 行为用例 PASS;改动 diff 已复核为纯增量。
  • 【部署注意】缓存头只对新上传对象生效;历史对象需手动(可用 CF 批量 purge 或 R2 重新上传);模板改动无后端逻辑变化。待用户部署后浏览器验证:二次访问头像应 0ms 级、头像坏链时二维码仍可扫。

CORS/画布污染核查(P0-② 二维码降级改动安全性)

  • 【结论】当前部署不会引发 CORS 失败或 canvas 污染。三个前提实测:① R2 已配 CORS 白名单,box.tama.guru 与 box-dev-api.337845818.best 均返回 ACAO(localhost:3000/example.com/裸域 无 ACAO);② list/profile options 显式 crossOrigin:'anonymous'(注释注明"直连 R2 跨域图须 CORS 模式"),tbRenderQR 默认同值,与库内 new Image 的 CORS 模式一致,探针与库绘制走同一缓存键;③ easy.qrcode 内部 makeImage 后调 this._elCanvas.toDataURL("image/png")(catch 后 console.error + 提示 "Configured crossOrigin:'anonymous'")——库开发者已内置该诊断。
  • 【污染免疫原理】canvas 污染只发生在"no-cors 隐式加载成功但无 ACAO"的中间态;tbRenderQR 探针失败(onerror)→ 根本不 drawImage → 无污染;成功 → 响应必带 ACAO → 干净。不存在绘制了却污染的路径。
  • 【边界提醒】R2 CORS 白名单只有 2 个源;新增页面域名/本地开发需先加白名单,否则 anonymous 探针 onerror → 降级基础码(可扫但永不带 logo,不报错)。favicon/og-image/meta 均非 canvas 上下文,无需 CORS 无污染风险(header.html 640-653 直指 R2)。

P0 批测试环境验证(agent-browser 实测 box-dev-api.337845818.best/_/admin6)

  • 【静态部署检查】HTML 含 tbRenderQR 2 次(helper 定义+1 调用)/ crossOrigin:'anonymous' 1 次 / logoBackgroundTransparent 2 次 / new QRCode(document.getElementById 为 0(已替换)→ 三处调用点全部到位。
  • 【正常路径】#boxqrimg canvas 200x200、toDataURL 成功(base64 长 28578 无污染)、中心 20x20 像素全为非白非黑"other"且色相分布为深色照片调(4,4,3 棕色系 96 像素、7,6,1 等)→ 头像 logo 已绘制升级版。
  • 【降级路径】临时 div 用坏头像 URL(不存在 picture path)调 tbRenderQR:立即态 canvas 已生成(len 4226 紧凑基础码、exportable true);3s 后状态保持(childCount 1、exportable true);_tbQrBad 写入坏 URL;_tbQrGood 同时记录真实页面头像 9af3e38?v=2 与背景图 25e2d84 → 双向印证降级免疫污染。
  • 【加载中排查】页面 2 个 uk-spinner:"正在生成分享图…"(分享卡区正常态)+ captcha modal 内的"加载中..."(rect 全 0 不可见);"加载更多 加载中..."按钮 display:none → 均非主诉"全屏加载中"覆盖层。用户主诉已消除。
  • 【截图】outputs/tb-dev-test-qr.png 全页、tb-dev-test-qr-crop.png 头部裁切:头像、用户名、提问按钮、二维码均已显示,无加载中残留。
  • 【代理坑提醒】agent-browser open 因测试站境外+defer 脚本多会卡 load 等待;可靠做法:先 agent-browser open (about:blank 启动 daemon) → 再 open 导航 → 然后 sleep ≥10s 让 defer 脚本就绪再 eval。
  • 【结论】P0 批(s3.go immutable 缓存头 + 二维码降级)测试环境验证全部通过,可部署生产。

P0 批正式环境验证(agent-browser 实测 box.tama.guru/_/tamakyi)

  • 【静态部署】HTML 60.1KB;tbRenderQR 2 次/调用点 1 处替换/crossOrigin 'anonymous' 1 次/logoBackgroundTransparent 2 次/new QRCode(document.getElementById 0;头像引用 r2.337845818.best/.../2e571390...(2026/09/05 新传)→ 与测试环境一致部署完整。
  • 【正常路径】#boxqrimg canvas 200x200 exportable len 31726;中心 20x20 像素全为深色照片调(7,7,7 灰+蓝黑系)→ 头像 logo 已绘制。
  • 【降级路径】坏 URL 测试:立即态 len 4226 基础码、3s 后保持 stillCanvas exportable len 4226 不空白;badMem=1、goodMem 含 2 个真实 URL(头像 2026/09/05 新头像 + 背景图 2024/09/22)→ 双向印证探针与降级免疫污染均正常。
  • 【加载中残留】visibleLoading=[](精确定位 rect>0 且文本含"加载中"的可见元素);之前的 uk-spinner/captcha/loadmore 在生产页同样不可见。
  • 【截图】outputs/tb-prod-test-qr.png:头像、二维码码眼完整、无加载中遮挡 → 与测试环境一致通过。
  • 【坑补充】第一次 agent-browser open | open URL 链式启动 3+ 分钟无输出卡死(即使之前测试环境用同样命令成功),最终拆成单条独立命令即恢复。原因可能是 Chromium 冷启动资源紧张或 chain 顺序导致首条 stdin 未及时关闭。经验:永远单条命令、第一条单独跑。
  • 【结论】P0 批正式环境全部通过;图片缓存头对老对象(2024/09/22 背景图)暂不生效,新上传对象生效,需要时间自然过渡。

autoban 误伤诊断(用户 app.ini: window=10s, sensitive=10, 404=20, duration=15min, trust_proxy=true)

  • 【机制】全站仅 2 个计数入口:中间件敏感路径 defer Record(autoban.go:39)+ f.NotFound 404 Record(route.go:403)。业务路由/模板 77 URL × 39 敏感词零碰撞 → 正常页面不误计。
  • 【误伤根因】正常用户 10s 内凑不出 10 敏感/20 404 → 误伤必是"他人探测记到自己键上":P0-A IP 键折叠(EO 未透传 EO-Client-IP 时全大陆回退到 43.174.247.x 新加坡边缘共享键;CF tunnel 异常时回退 127.0.0.1);P0-B CGNAT 共享出口连坐(国内 NAT444 常态,管理员自伤主因);P1-C IPv6 /64 聚合连坐;P1-D 双 CDN 未删对端权威头可被伪造头定向嫁祸。
  • 【止血配置】window 60s + sensitive 30 + 404 100 + security_alert_email 开(先看封禁 IP 判断折叠)。治本=EO 开回源 IP 透传 + 源站防火墙锁 CDN 网段 + 双 CDN 删对端头。
  • 【代码增强候选】登录 session 豁免计数、封禁 logrus 日志、UA 二次确认。报告 outputs/autoban-false-positive-2026-09-05.md。

autoban 策略修正实施:ban_track_notfound(用户选定"配置开关版")

  • 【背景】生产新误伤案例 106.7.154.160(真实国内电信 IP,非 CDN 边缘):样本 /_/Liarcs×4 + /×2 全是计数事件;但 domain/题目不存在走 302(Pager/Questioner 均 ctx.Redirect)不计数 → 能进 f.NotFound 的多为非 GET 探测或未注册路径;告警 paths 仅 6 条且受 2min cleanup 影响可跨窗口累积 ≠ 触发原因;触发=10s 内 ≥20 次 f.NotFound 或 ≥10 敏感。疑似共享出口(CGNAT)连坐或目标性探测。
  • 【评估结论】敏感通道 35 项扫描特征与业务路由全表零重叠→零误伤;404 通道是唯一误伤源但价值低(主流字典必碰敏感项;/_/{domain} 枚举靠 200/302 区分本来就抓不到)→ 砍 404 计数收益>损失。
  • 【改动 5 文件,备份 .workbuddy/backup/autoban-track-notfound-20260905/】
    1. internal/conf/static.go:Security 加 BanTrackNotFound bool ini:"ban_track_notfound"(默认 false)
    2. internal/security/autoban/autoban.go:Options.TrackNotFound、Banner.trackNotFound、New 赋值;Record 对 KindNotFound && !trackNotFound 直接 return
    3. internal/route/route.go:Options 传 TrackNotFound: conf.Security.BanTrackNotFound;f.NotFound 注释同步
    4. internal/security/autoban/autoban_test.go:newTestBanner 默认 TrackNotFound:true;新增 TestNotFoundTrackDisabledByDefault;TestDefaults 断言 trackNotFound==false
    5. conf/app.sample.ini:security 段加 ban_track_notfound = false + 注释(真实 app.ini 在各部署环境,需用户同步补键或留空=默认关)
  • 【验证】gofmt 干净;go vet OK;go test 三包全绿(route/conf/autoban,带 -overlay=tb_overlay.json 规避 cgo webp);新用例 PASS。
  • 【部署提醒】测试/生产 app.ini 无需强制加键(缺省 false 即关闭 404 计数);若想恢复 404 计数置 true。conf/app.ini 不在本地副本(conf/ 仅 app.sample.ini)。

ban_track_notfound 测试环境实测(box-dev-api,出口=本机南宁电信)

  • 【正常路径】/ + /_/admin3..admin9 全 200 无 403;不存在 domain ×8 → 302 不封(业务 302 通道确认);admin6 页 SSR title「admin6 - 狼的提问箱」正常。
  • 【404 洪水】未注册路径 ×30 → 全 302(location:/) 不封(TrackNotFound=false 预期,但受 enable_auto_ban 前提约束)。
  • 【敏感×37 异常】/.env /admin /wp-login.php 等共 37 个敏感路径(默认阈值 10 的 3.7 倍)→ 全 302 无 403。302 均为服务端 f.NotFound Redirect(location:/ + securityHeaders + CF NEL),确认到达应用层 → 疑似测试环境 enable_auto_ban=false(或阈值极高/实例未跑新二进制),需用户核对 app.ini + 日志后才能定论。若 enable=false,本测无法验证 TrackNotFound 语义,建议测试环境 enable_auto_ban=true 后重测。
  • 【教训】agent-browser open 境外站再次卡死(>3.5min),TaskStop 清理;渲染验证降级 curl 抽查 HTML 即可。

ban_track_notfound 测试环境复测通过(22:17-22:35,出口 222.218.124.37)

  • 【上轮误判根因】串行 curl 每个请求间隔 1-2s(南宁→CF→源 RTT),13 个敏感请求跨 18s > 10s 窗口 → 永不达阈值;日志时间戳证实。非配置问题。
  • 【复测方法】xargs -P 25 并发打,窗口内密集命中。
  • 【结果】① 正常路径 / + admin3-9 全 200;② 纯 404 并发 x25 → 全 302 无 403(TrackNotFound=false 生效);③ 敏感路径并发 x25 → 前~10 个 302 后 15 个全 403(阈值10触发封禁);④ 封禁后 / 与 /_/admin6 也 403(IsBanned 全局生效)。
  • 【副作用】本机出口 IP 222.218.124.37 被测试环境临时封禁 15min(约至 22:35 自动解除);测试环境日志可见该批 403 + 若有 security_alert_email 会收到告警(含样本路径)。
  • 【结论】修复语义完整闭环:正常业务放行、纯404豁免、敏感扫描封禁。部署生产即可。