93 lines
3.2 KiB
Python
93 lines
3.2 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""判读等价对拍工具(结算期文字列表退役批 R4 载体——日志零文案改后分析判读逐位一致)。
|
||
|
||
用法:
|
||
python tools/analyze_parity_check.py <输入A> <输入B> [<输入C> ...] [--runs N]
|
||
|
||
输入 = 日志(.jsonl,各跑一次 tools/analyze_playtest.py 完整判读)或基线快照
|
||
(.md,analyze_playtest.py 输出重定向落盘的静态文本,直读不重跑)。全部剥去文件名
|
||
标题行后相邻逐位 diff——任一对不一致即 exit 1 并打印第一条分歧行。
|
||
|
||
三读数跑法(改前改后配对,卡 R4):
|
||
① 历史锚日志 vs 改前 T0 基线快照(兼容分支等价)
|
||
② 改前同种子日志 vs 改前 T0 基线快照(复现等价)
|
||
③ 改前同种子日志 vs 改后同种子新日志(同种子+玩法零改动=事件流逐位同)
|
||
|
||
退出码: 0=全部逐位一致 1=判读分歧 2=参数/执行错误
|
||
"""
|
||
import subprocess
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
HERE = Path(__file__).resolve().parent
|
||
ANALYZE = HERE / "analyze_playtest.py"
|
||
|
||
|
||
def run_analyze(log_path: str, runs: str) -> str:
|
||
cmd = [sys.executable, str(ANALYZE), log_path]
|
||
if runs:
|
||
cmd += [runs]
|
||
proc = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8")
|
||
if proc.returncode != 0:
|
||
print("[parity] 判读执行失败(%s)exit=%d" % (log_path, proc.returncode))
|
||
print(proc.stdout[-2000:])
|
||
print(proc.stderr[-2000:])
|
||
sys.exit(2)
|
||
# 剥文件名标题行(playtest_*.jsonl 文件名随输入变,不参与逐位比对)
|
||
return strip_name_lines(proc.stdout)
|
||
|
||
|
||
def strip_name_lines(text: str) -> str:
|
||
out_lines = []
|
||
for ln in text.splitlines():
|
||
if "playtest_" in ln and ".jsonl" in ln:
|
||
continue
|
||
out_lines.append(ln)
|
||
return "\n".join(out_lines)
|
||
|
||
|
||
def first_diff(a: str, b: str):
|
||
la, lb = a.splitlines(), b.splitlines()
|
||
for i in range(max(len(la), len(lb))):
|
||
xa = la[i] if i < len(la) else "<缺行>"
|
||
xb = lb[i] if i < len(lb) else "<缺行>"
|
||
if xa != xb:
|
||
return i + 1, xa, xb
|
||
return None
|
||
|
||
|
||
def main():
|
||
args = sys.argv[1:]
|
||
runs = ""
|
||
if "--runs" in args:
|
||
i = args.index("--runs")
|
||
runs = args[i + 1]
|
||
args = args[:i] + args[i + 2:]
|
||
if len(args) < 2:
|
||
print(__doc__)
|
||
sys.exit(2)
|
||
outputs = []
|
||
for p in args:
|
||
if p.lower().endswith(".jsonl"):
|
||
outputs.append(run_analyze(p, runs))
|
||
else: # 基线快照(.md)——静态文本直读,剥名规则同判读输出
|
||
outputs.append(strip_name_lines(Path(p).read_text(encoding="utf-8")))
|
||
ok = True
|
||
for i in range(1, len(outputs)):
|
||
d = first_diff(outputs[i - 1], outputs[i])
|
||
pair = "%s <-> %s" % (Path(args[i - 1]).name, Path(args[i]).name)
|
||
if d is None:
|
||
print("[parity] 一致 | %s | 判读逐位一致" % pair)
|
||
else:
|
||
ln, xa, xb = d
|
||
print("[parity] 分歧 | %s | 第 %d 行" % (pair, ln))
|
||
print(" A: %s" % xa)
|
||
print(" B: %s" % xb)
|
||
ok = False
|
||
sys.exit(0 if ok else 1)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|