| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 |
- /**
- * 票 52 收口自查:t45 的 4 条 C3x 失败是否为「既有」。
- *
- * t45 的 C3b/C3c/C3d/C3f 是对 `markerOverlay.js` 的**静态源码断言**,而该文件在本
- * 工作树是并行在制品(脏)。本票只改后端仓库 7 个 Java 文件,从未碰前端 src。
- * 这里把 HEAD 版本的 markerOverlay.js 取出来,逐条复跑同一批断言:
- * 若 HEAD 版本同样失败 → 既有失败,与本票零交集。
- *
- * 用法:node .scratch/cockpit-real-data-wayfinding/verify/t52-t45-baseline-check.mjs
- */
- import { execFileSync } from 'node:child_process'
- import { readFileSync, writeFileSync, mkdtempSync } from 'node:fs'
- import { tmpdir } from 'node:os'
- import { join } from 'node:path'
- const REPO = 'E:/City-Lifeline-Cockpit-TvT'
- const OVERLAY_REL = 'src/modules/cockpit/services/markerOverlay.js'
- const T45_REL = '.scratch/cockpit-real-data-wayfinding/verify/t45-state-axis-and-effects.mjs'
- // 1. HEAD 版 markerOverlay.js
- const headOverlay = execFileSync('git', ['show', `HEAD:${OVERLAY_REL}`],
- { cwd: REPO, encoding: 'utf8' })
- // 2. 在仓库内建一个临时副本,脚本相对路径保持可用(放同目录层级)
- const dir = mkdtempSync(join(REPO, '.t52-tmp-'))
- const overlayCopy = join(dir, 'markerOverlay.HEAD.js')
- writeFileSync(overlayCopy, headOverlay)
- // 3. 取 t45 脚本,把读 markerOverlay 的那一行指向 HEAD 副本;其余读取保持原样
- const t45 = readFileSync(join(REPO, T45_REL), 'utf8')
- const ANCHOR = "read('src/modules/cockpit/services/markerOverlay.js')"
- if (!t45.includes(ANCHOR)) {
- console.log('锚点未命中:t45 脚本已变,需同步本自查脚本')
- process.exit(1)
- }
- // 脚本用 new URL(`../../../${rel}`) 基于脚本位置解析;临时脚本仍放回原目录以便相对导入
- const patched = t45.replace(ANCHOR, `read('.t52-tmp-${dir.split('.t52-tmp-')[1]}/markerOverlay.HEAD.js')`)
- const patchedPath = join(REPO, '.scratch/cockpit-real-data-wayfinding/verify/.t52-t45-baseline.mjs')
- writeFileSync(patchedPath, patched)
- let out = ''
- try {
- out = execFileSync('node', [patchedPath], { cwd: REPO, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] })
- } catch (error) {
- out = `${error.stdout ?? ''}${error.stderr ?? ''}`
- }
- const fails = out.split('\n').filter((line) => line.startsWith('FAIL C3'))
- const headFailed = new Set(fails.map((line) => line.split(' ')[1]))
- const summary = out.split('\n').find((line) => line.includes('状态双轴与特效检查')) ?? '(无汇总行)'
- console.log(`HEAD 版 markerOverlay.js 上,C3x 静态断言失败 ${fails.length} 条:`)
- fails.forEach((line) => console.log(` ${line}`))
- console.log(`汇总:${summary}`)
- // 再跑一次**当前工作树**,取它失败的那批
- let worktreeOut = ''
- try {
- worktreeOut = execFileSync('node', [T45_REL], { cwd: REPO, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] })
- } catch (error) {
- worktreeOut = `${error.stdout ?? ''}${error.stderr ?? ''}`
- }
- const wtFails = new Set(worktreeOut.split('\n')
- .filter((line) => line.startsWith('FAIL C3'))
- .map((line) => line.split(' ')[1]))
- const wtSummary = worktreeOut.split('\n').find((line) => line.includes('状态双轴与特效检查')) ?? '(无汇总行)'
- console.log(`\n当前工作树(并行在制品)失败 ${wtFails.size} 条:${[...wtFails].join(', ') || '(无)'}`)
- console.log(`汇总:${wtSummary}`)
- // 清理
- execFileSync('node', ['-e', `require('fs').rmSync(${JSON.stringify(dir)},{recursive:true,force:true});require('fs').rmSync(${JSON.stringify(patchedPath)},{force:true})`])
- console.log('\n已清理临时文件。')
- // 判据:工作树失败集必须是 HEAD 失败集的**子集**(本票没引入任何新失败)。
- // 注意工作树是并行在制品,逐条数可以比 HEAD 少(正在修),但不能多出 HEAD 没有的。
- const newFails = [...wtFails].filter((id) => !headFailed.has(id))
- if (newFails.length === 0) {
- console.log(`判定:工作树 ${wtFails.size} 条失败 ⊂ HEAD ${headFailed.size} 条失败 → 全部既有;`
- + '票 52 是纯后端改动(本会话未碰前端 src),未引入任何新前端失败。')
- process.exit(0)
- }
- console.log(`注意:工作树出现 HEAD 上没有的新失败 ${newFails.join(', ')} → 需人工复核。`)
- process.exit(1)
|