2 Commits
Author SHA1 Message Date
liuzhuohua b7ca9c89e8 feat(i18n/layout): 全站中英双语 + 四轮排版修复收官 + 修 boot_id 重启检测
v1.0.10 两件大事:

1. 界面中英双语(英文界面无中文残留)
   - 新增 web/i18n.js(约 4200 条词条),零依赖零构建
   - 后端下发中文数据走 bt4() 查表翻译;独立模块(upstream/netdetail/
     realtime/update)纳入翻译并注册切语言重绘钩子
   - 后端「状态/聚合」接口只回稳定枚举+原始数值,不下发中文文案
   - 顺带修一个真实 XSS:顶层 const 不挂 window,独立脚本 esc 静默退化成零转义

2. 修掉「文字竖着排/错位」(多分辨率反复暴露)
   - 单元格 min-content 只有 1 字宽 → word-break:keep-all + 表头 nowrap
   - 依赖卡片正文被标签/按钮挤成 27px → .dep-body{flex:1 1 200px} + flex-wrap
   - 裸 flex:1(下限为0)给正文 → 一律改 flex:1 1 <px>
   - .dep-item 横向容器直接塞块级子项 → 退回块级
   - 关键陷阱:auto-fill 布局屏越宽列数越多单卡越窄,窄屏反而测不出来,
     真机审计推进到「逐视图点按钮 + 1920/2560 宽视口 + 中英双语」
   - 守卫 t-layout.py 扩到 35 条,12 处反向验证全红

3. 修真缺陷:_link_since() 重启检测被误改成 if False:(注释还写着「已修」),
   uptime 归零后相减得负数 → 恢复比对 boot_id

附带:新增 25 个检查器(t-*.py)、排版审计工具链(shot-*/ocr-*/live-*)、
版本号兜底值同步到 1.0.10、.gitignore 收纳 i18n/排版排查的一次性脚本。
2026-10-10 04:50:32 +08:00
liuzhuohua 309be8b0a5 feat(snapshot): 快照可单独上锁 + 备注事后可改,全部并入紧急救援通道页
用户反馈的四件事一次做完:
1. 给快照加保护(单份上锁,自动清理一律跳过)
2. 说明「手动快照受保护不被清理」,并讲清它与上锁的区别
3. 快照备注事后可改(此前只能在创建时填,存下来就只能看不能改)
4. 列表从「配置快照与回滚」卡片搬进「紧急救援通道」,回滚入口不再弹残缺弹窗

protected 与 keep_manual 是两件事,必须分开:
- keep_manual 是全局策略,按 tag.startswith('auto') 猜来源
- protected 是用户对这一份的显式意图,跨策略生效
判据只能加在删除分支上,混进 auto 算法的话,受保护的自动快照
会开始占 keep_count 配额,把别的自动快照挤掉 —— 用户设「保留 5 份」
却只剩 4 份,且没有任何提示。

上锁不等于删不掉:删受保护的那份时后端回 needs_force,前端弹二次确认
后带 force 重试。审计里标注「受保护,已强制删除」,否则事后只看得到
「删了快照」,看不出删的是用户特意保下来的那份。

meta 用 .tmp + os.replace 原子写 —— meta 是 prune 唯一的判据来源,
写到一半被打断会留下解析不了的残文件,之后那份快照既不会被清理,
也上不了锁(读不到就当没保护)。

备注消毒:控制字符一律换成空格而不是删掉。删掉会把「甲 BEL 乙」
变成「甲乙」,两个词粘成一坨,而用户看到的备注莫名其妙。

真机验收(40 项全绿)当场抓到两个本地回归漏掉的真 bug:
- 备注消毒把制表符删掉而不是换空格:'a\\nb\\tc' 变成 'ab c'
  本地判据只写「不含换行和制表符」,恰好放过 —— 「没有危险字符」
  和「内容没被偷偷改掉」是两件事
- web 层无条件写 'protected': b.get('protected'),
  payload 里这个键永远在(值可能是 None),helper 的
  `if 'protected' in p` 恒成立,「不传就取反」从 HTTP 路上彻底失效
两个都补了反向验证(注入后必须观察到红)。

顺带修掉一个既存缺陷:t-107.py 里的 js_code_only 一直在吃 app.js
的真代码 —— 用 re.sub 块注释优先、再剥行注释,而 app.js 8222 行有一句
讲「怎么防止 CSS 注释被提前闭合」的行注释,注释里写着块注释的起止符
字面量,于是被当成真注释开头一路吃到文件尾。
证据:块注释起始 169 次而结束 170 次,数量不等就是配对错位一格。
HEAD 版同样中招(163/164),所以不是本轮引入。
换成 _dev/jsstrip.py 的词法扫描版(正确处理模板串的插值、正则字面量、
prev 记 token 尾词而不是一个字符),并加 node 侧 V8 交叉验证。
2026-10-03 14:22:14 +08:00