| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788 |
- /**
- * 票 44 变异闸:把守卫要防的错法逐一注入,确认 t44 真的转红;每次变异后按字节还原并校验哈希。
- *
- * 判据只看退出码(不用管道捕获子进程输出——那是本环境的已知边界)。
- * 用法:node .scratch/cockpit-real-data-wayfinding/verify/t44-mutations.mjs
- * 先单独跑一次 t44 看绿,再跑本脚本看每条变异都被抓住。
- */
- import { spawnSync } from 'node:child_process'
- import { readFileSync, writeFileSync } from 'node:fs'
- import { createHash } from 'node:crypto'
- import { fileURLToPath } from 'node:url'
- const ROOT = fileURLToPath(new URL('../../../', import.meta.url))
- const GATE = '.scratch/cockpit-real-data-wayfinding/verify/t44-distribution-ranking.mjs'
- const MUTATIONS = [
- {
- id: 'M1',
- file: 'src/modules/cockpit/domain/panelBlocks.js',
- from: ' .sort((a, b) => b.count - a.count || a.index - b.index)',
- to: ' .sort((a, b) => a.index - b.index)',
- why: '排序改恒等(遗漏降序)→ RANK 组必须全红',
- },
- {
- id: 'M2',
- file: 'src/modules/cockpit/domain/abnormalCounts.js',
- from: ' }))',
- to: ' })).sort((a, b) => b.count - a.count)',
- why: '把固定语义序的异常桶强行降序(非目标第 2 条)→ FIXED 组必须红',
- },
- {
- id: 'M3',
- file: 'src/modules/cockpit/components/PanelBlocks.vue',
- from: ' gap: calc(4 * var(--u, 1px));\n}\n\n.panel-bar__label {',
- to: ' gap: var(--space-2, 8px);\n}\n\n.panel-bar__label {',
- why: '文字与统计条退回宽间距(收紧被撤销)→ B3 必须红',
- },
- {
- id: 'M4',
- file: 'src/modules/cockpit/components/PanelBlocks.vue',
- from: ' box-shadow: inset -1px 0 0 rgba(255, 255, 255, 0.85);\n',
- to: '',
- why: '删掉条段端帽(分割消失)→ B4b 必须红',
- },
- {
- id: 'M5',
- file: 'src/modules/cockpit/components/PanelBlocks.vue',
- from: ' box-shadow: inset 0 0 0 1px rgba(1, 171, 234, 0.12);\n',
- to: '',
- why: '删掉轨道发丝边(条段无容器边界)→ B4 必须红',
- },
- {
- id: 'M6',
- file: 'src/modules/cockpit/components/PanelBlocks.vue',
- from: ' <EllipsisText class="panel-bar__label" :text="row.label" />',
- to: ' <span class="panel-bar__label">{{ row.label }}</span>',
- why: '行标签退回裸 span(票 37 省略接缝被视觉改动带走)→ B7 必须红',
- },
- ]
- const hash = (path) => createHash('sha256').update(readFileSync(path)).digest('hex')
- /** 变异源文本按 CRLF 归一后再注入(票 37 的教训:PowerShell 写盘是 CRLF,锚点含 \n 会假未命中)。 */
- const normalizeFor = (text, path) => (readFileSync(path, 'utf8').includes('\r\n') ? text.replace(/\n/g, '\r\n') : text)
- let failures = 0
- for (const m of MUTATIONS) {
- const path = ROOT + m.file.replaceAll('/', process.platform === 'win32' ? '\\' : '/')
- const before = hash(path)
- const source = readFileSync(path, 'utf8')
- const needle = normalizeFor(m.from, path)
- if (!source.includes(needle)) {
- console.log(`BAD ${m.id}: 变异锚点未命中(源码已变,需更新脚本)`)
- failures += 1
- continue
- }
- writeFileSync(path, source.replace(needle, normalizeFor(m.to, path)))
- const status = spawnSync(process.execPath, [GATE], { cwd: ROOT, stdio: 'ignore' }).status
- writeFileSync(path, source)
- const restored = hash(path) === before
- const red = status !== 0
- console.log(`${red && restored ? 'OK ' : 'BAD '} ${m.id} ${m.why} → 闸门${red ? '转红' : '未转红'};还原${restored ? '按字节一致' : '**不一致**'}`)
- if (!red || !restored) failures += 1
- }
- console.log('')
- console.log(failures ? `T44 MUTATIONS: ${failures} FAILED` : `T44 MUTATIONS: ${MUTATIONS.length}/${MUTATIONS.length} 全部被抓住`)
- process.exit(failures ? 1 : 0)
|