Files
novalon-website/docs/acceptance/2026-09-21-gates/chain7-dead-audit-and-rule-coverage.sh
T
zhangxiang a0328a623f chore(qa): 验收台账与证据入库 + 构建/部署配置同步
- docs/acceptance/qa-tracker.md:跨周期缺陷单一真源台账(§7=第五轮)。
- 周期 1/2 + iPhone SE/axe 验收证据目录、ACCEPTANCE_REVIEW 快照入库。
- 同步 README/CONTEXT/CLAUDE/DESIGN/testing/deployment/lessons-learned 口径;
  next.config/Dockerfile/nginx/Jenkinsfile/docker-compose/sentry/prisma 对齐
  standalone 产物装配与部署形态。
2026-09-28 10:48:09 +08:00

73 lines
3.6 KiB
Bash

#!/bin/bash
# 第七轮(死断言处理后的复验):
# A. axe harness 扩到「tag 通道 + 规则级通道」——先 2 路由 sanity,再全站 34 路由 × 4 组合
# B. Lighthouse 去掉 3 条死断言后重跑,证明 EXIT=0 且 0 warning
set -u
cd /Users/zhangxiang/Codes/Novalon/novalon-website || exit 1
LOG=/tmp/final-chain7.log
HARNESS=docs/acceptance/2026-09-21-axe/axe-contrast-evidence.mjs
CRAWLER=docs/acceptance/2026-09-21-axe/crawl-sitemap.mjs
PORTS() { lsof -nP -iTCP:3000 -iTCP:3100 -sTCP:LISTEN 2>/dev/null | grep -c LISTEN; }
echo "=== chain7 started $(date -u +%FT%TZ) ===" > "$LOG"
echo "PREFLIGHT_LISTENERS=$(PORTS) $(date -u +%FT%TZ)" >> "$LOG"
npx next start -p 3100 > /tmp/axe-server8.log 2>&1 &
SRV=$!
code=000
for i in $(seq 1 40); do
code=$(curl -s -o /dev/null -w '%{http_code}' http://localhost:3100/ 2>/dev/null || true)
[ "$code" = "200" ] && break
sleep 3
done
echo "AXE_SERVER_UP=$code $(date -u +%FT%TZ)" >> "$LOG"
# 全站清单(口径与 chain6 相同:sitemap ∪ 预渲染产物 ∪ 站内链接 BFS)
BASE=http://localhost:3100 SEED=/tmp/axe-sitemap2.xml \
MANIFEST=dist/standalone/dist/server/app OUT=/tmp/axe-sitemap-all5.xml \
node --input-type=module -e "$(cat $CRAWLER)" > /tmp/crawl6.log 2>&1
echo "EXIT_CRAWL=$? $(date -u +%FT%TZ)" >> "$LOG"
grep -a "^crawled" /tmp/crawl6.log >> "$LOG"
# sanity:只用 2 条路由跑新代码路径,避免 14 分钟后才发现探针本身有 bug
python3 - <<'PY'
import re
src = open('/tmp/axe-sitemap-all5.xml', encoding='utf8').read()
blocks = re.findall(r'<url>.*?</url>', src, re.S)
open('/tmp/axe-sitemap-sanity.xml', 'w', encoding='utf8').write(
'<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n'
+ "\n".join(blocks[:2]) + "\n</urlset>\n")
print('sanity urls:', len(blocks[:2]))
PY
echo "EXIT_SANITY_CROP=$?" >> "$LOG"
SITEMAP=/tmp/axe-sitemap-sanity.xml BASE=http://localhost:3100 OUT=/tmp/axe-sanity-out \
node --input-type=module -e "$(cat $HARNESS)" > /tmp/axe-sanity.log 2>&1
echo "EXIT_SANITY=$? $(date -u +%FT%TZ)" >> "$LOG"
sed -e 's/\x1b\[[0-9;]*m//g' /tmp/axe-sanity.log | grep -aE "^(chromium|firefox)/|^PASSED|^SUMMARY|FATAL|Error" | head -14 >> "$LOG"
# 保留 chain6 证据,再产出最终树的新证据
cp docs/acceptance/2026-09-21-axe/axe-evidence.json \
docs/acceptance/2026-09-21-axe/axe-evidence-chain6-tagonly.json 2>/dev/null
SITEMAP=/tmp/axe-sitemap-all5.xml BASE=http://localhost:3100 \
OUT=docs/acceptance/2026-09-21-axe \
node --input-type=module -e "$(cat $HARNESS)" > /tmp/axe-sweep8.log 2>&1
echo "EXIT_AXE_FULL=$? $(date -u +%FT%TZ)" >> "$LOG"
node -e "const j=require('./docs/acceptance/2026-09-21-axe/axe-evidence.json');console.log('AXE routeCount='+j.routeCount+' rows='+j.rows.length+' passed='+j.passed+' extraRules='+JSON.stringify(j.extraRules)+' summary='+JSON.stringify(j.summary))" >> "$LOG" 2>&1
kill "$SRV" 2>/dev/null
pkill -f 'next start -p 3100' 2>/dev/null
sleep 3
echo "POST_AXE_LISTENERS=$(PORTS)" >> "$LOG"
{
echo
echo "===== chain7 lighthouse(移除 3 条死断言后)$(date -u +%FT%TZ) ====="
npm run lighthouse 2>&1
} | sed -e 's/\x1b\[[0-9;]*m//g' >> docs/acceptance/2026-09-21-gates/lighthouse.txt 2>&1
echo "EXIT_LIGHTHOUSE=${PIPESTATUS[0]} $(date -u +%FT%TZ)" >> "$LOG"
# 只统计本轮(chain7 段)残留的死断言,历史段保留作对照
awk '/chain7 lighthouse/{f=1} f' docs/acceptance/2026-09-21-gates/lighthouse.txt \
| grep -ac "not a known audit" | sed 's/^/CHAIN7_DEAD_AUDIT_WARNINGS=/' >> "$LOG"
sleep 3
echo "POST_FINAL_LISTENERS=$(PORTS)" >> "$LOG"
echo "=== chain7 done $(date -u +%FT%TZ) ===" >> "$LOG"