Files
PMon Dev 49dacb57a6
Design System Guard / guard (push) Failing after 9m13s
merge(v2/init): 接入层归宿主,并同步护栏到新模板
合并 088c9b3(移除 nginx 容器、常驻 5→4)到 main。三路合并零文本冲突,但 088c9b3 漏改了引用被重命名文件的地方,故在本合并提交里一并适配:
1) tests/phase3b-static-guard.js:265 的断言原本读 deploy/nginx.conf,该文件已 rename 成 deploy/nginx.host.conf.example;不改会让 read() 返回空串、断言必然 FAIL,而该护栏被 run-guards.sh / Gitea Actions 收录。新模板 108-109 行确有 location ^~ /admin/ 与 proxy_pass,换名后断言成立。
2) deploy/nginx.ssl.conf.example 的使用说明仍写 cp nginx.conf 与 docker compose up -d nginx(两者都已不存在),改为时代注记,点明本文件只是 HTTPS 片段、缺 /admin/ /setup /relay 段、不可整份照抄(纯注释,不改配置行为)。

验证:bash tests/run-guards.sh → 6 套件 PASS 5 / FAIL 0 / SKIPPED 1(axe 可选未启用);phase3b 94/0、dockerfile-coverage 60/0、schema 116/0、Dart 674 全通过,整体退出码 0。
2026-11-09 21:42:30 +08:00
..

墨观 InkWatch · 设计系统护栏(tests/)

统一入口(从仓库根运行):

bash tests/run-guards.sh

脚本串行跑 6 个套件(第 6 个默认不跑,见下),任一非零退出则整体失败;无论中途是否有失败都跑完全部套件,末尾打印汇总表(状态 / 退出码 / 耗时 / 指标)。默认路径(前 5 个套件)约 13–14s。

套件

套件 作用 默认
web-token-guard.js 源仓库令牌层轻量守卫:tokens.css 首个 :root 关键键与点修值、深色 58 键与层叠顺序、浅色锁定、admin.css 令牌化、admin.js 主题单一出口 跑
phase3b-static-guard.js 管理台深色落地静态护栏:首屏脚本逐字一致、6 页 assets/tokens.css 引入顺序、深色 58 键、Dockerfile / nginx 覆盖等 跑
dockerfile-coverage-test.js 镜像 COPY 覆盖性(含新增 assets/tokens.css) 跑
schema-consistency-test.js 指标字段三层一致性 跑
client/scripts/test.sh 全量 Dart 测试(含 token_parity_test.dart:CSS :root ↔ Dart theme.dart 双向护栏) 跑
admin-axe-audit.mjs 管理台 6 页 axe-core 42 格矩阵(3 视口 × 2 皮肤 × 6 页 + E-Ink 6 格) 不跑(需 RUN_AXE=1)

web-token-guard.js 是交付目录 03-frontend/verify.mjs 的「源仓库等价轻量版」——后者不入库、CI 不可依赖;前者零外部依赖,只读源仓库 server/business/admin/assets/ 下三个文件,不联网、不读交付目录。单独运行:

node tests/web-token-guard.js

管理台 axe 42 格矩阵(tests/admin-axe-audit.mjs)

# 单独跑(结果 JSON 默认写 /tmp/iw-admin-axe-result.json)
node tests/admin-axe-audit.mjs

# 自定义结果路径(不要写进仓库;仓库会变大且属临时产物)
node tests/admin-axe-audit.mjs --out /tmp/my-axe.json

# 与整套护栏一起跑
RUN_AXE=1 bash tests/run-guards.sh

矩阵与口径(与交付轮次一致,不因「跑绿」而放宽):

  • 3 视口 1280×800(Web)/ 375×812(移动 PWA)/ 1920×1080(大屏,DSF=1)× 2 皮肤 light / dark × 6 页 = 36 格;
  • 外加 E-Ink 单列(1920×1080 + light + data-iw-surface="eink")6 格 = 42 格;
  • 规则集 runOnly.tag = wcag2a / wcag2aa / wcag21a / wcag21aa / wcag22aa / best-practice,禁用规则 0 条;
  • 判定:任一格 violations > 0(含 minor)即 FAIL;incomplete 不计 PASS,逐条打印规则与节点数并转人工复核;存在未执行格时整轮不得判 PASS。
  • 退出码:0 跑满 42 格且 violations=0;1 有 violations / 未跑满;2 环境受限(缺浏览器或 axe-core)。

实现方式:Node 内置 http 起只读静态服务指向 server/business/admin/(listen(0) 由 OS 分配空闲端口,跑完 close,/api/* 一律 401);child_process 启无头浏览器 + CDP(Node 22 内置 fetch/WebSocket,零运行时依赖);Runtime.evaluate 注入 axe.min.js。深色先 setAttribute('data-iw-theme','dark') 并等样式重算再跑 color-contrast。

前置条件:

  1. 浏览器:macOS 的 Microsoft Edge / Google Chrome / Chromium,Linux 的 google-chrome / microsoft-edge / chromium 任一即可;也可 IW_BROWSER_BIN=<绝对路径> 指定。缺失时脚本以退出码 2 明确报错并给安装提示,不会静默跳过。
  2. axe-core:默认从 /tmp/iw-admin-axe 读取;不存在时自动 npm install --prefix /tmp/iw-admin-axe --no-save --no-package-lock axe-core@^4.14.0(需联网,不写进任何 package.json)。离线时退出码 2 并给出手动安装命令;也可 IW_AXE_JS=<axe.min.js 路径> 预置。
  3. 耗时:单跑约 45s,故默认不进快跑路径(默认约 13–14s)。

产物(均在 /tmp,不入库):/tmp/iw-admin-axe-result.json(每格 probe / violations / incomplete / screenshot 字段)、/tmp/inkwatch-admin-axe-shots/*.png(42 张截图)。

当前实测(HEAD 38c3d8f):42/42 格 violations=0,incomplete=12(全部为 color-contrast 几何遮挡,20 节点,转人工复核)。

环境变量

  • PHASE3B_PREVIEW=<path>:指向交付目录 preview.html。存在时 phase3b 启用「7 处首屏脚本 hash 比对」(87 PASS)。未设时脚本自动探测本地交付目录候选;找不到则走不带 preview 的分支(85 PASS / 0 FAIL + 1 SKIP,属预期),并明确打印 SKIP 原因。
  • SKIP_FLUTTER_TESTS=1:默认必须跑全量 Dart;仅在 Flutter 不可用时的显式降级,汇总表标 SKIPPED (explicit),不会静默跳过。
  • FLUTTER_BIN=<path>:透传给 client/scripts/test.sh,指定 flutter 可执行文件(CI runner 上 flutter 通常不在 $HOME/development/flutter)。
  • RUN_AXE=1:启用第 6 套件「管理台 axe 42 格矩阵」。默认不跑(保护约 14s 的本地快跑体验);未设置时汇总表显式标 SKIPPED (RUN_AXE not set) 并打印跳过原因,绝不静默。启用后整体耗时约 59s。
  • IW_BROWSER_BIN / IW_AXE_JS / IW_AXE_PKG / IW_AXE_OUT:分别覆盖浏览器路径、axe.min.js 路径、自动安装的包规格、结果 JSON 路径(--out 优先)。

CI

.gitea/workflows/design-system-guard.yml 在 push / pull_request / workflow_dispatch 触发,执行同一入口。前提是 Gitea 实例已启用 Actions;未启用时该文件只作声明、不会运行。本地复现无需 Actions:

bash tests/run-guards.sh          # 快跑:PASS 5 / SKIPPED 1(RUN_AXE 未设)
RUN_AXE=1 bash tests/run-guards.sh  # 全套:PASS 6 / FAIL 0 / SKIPPED 0

axe 段在 CI 里默认关闭:runner 未必有 Chromium/Edge,联网装 axe-core 也可能被策略挡住,强行默认开启只会制造噪声失败。启用方式二选一(见 workflow 文件头注释):

  1. 手动触发:Actions → Run workflow → run_axe 填 true;
  2. 仓库变量:Settings → Actions → Variables 设 IW_RUN_AXE=1,之后 push / PR 也带上该套件。

runner 需自带 Chromium 系浏览器;若启用而浏览器缺失,该套件以退出码 2 失败(汇总表 FAIL),不会伪造成 PASS。