Files
ft/CodexOutput/upserver/KVSaveRouteTests/audit_delivery.py

46 lines
2.6 KiB
Python

"""Read-only scope audit against reviewed baselines; writes evidence in this directory."""
from pathlib import Path
import hashlib, json, re
HERE = Path(__file__).resolve().parent
ROOT = HERE.parents[2]
UP = HERE.parent
def sha(path): return hashlib.sha256(path.read_bytes()).hexdigest().upper()
def read(path): return json.loads(path.read_text(encoding='utf-8-sig'))
def changed(entries):
return [p for p,h in entries.items() if not (ROOT/p).exists() or sha(ROOT/p) != h.upper()]
inventory = read(UP/'B3DesignAudit/source-hashes.json')
design = read(UP/'阶段4B3方案受审基线-2026-09-24.json')
b2 = read(UP/'KVGameLoadTests/checkpoint4-delivery-hashes.json')
pf = 'Client/Assets/Scripts/Core/PlayFabMgr.cs'
current = (ROOT/pf).read_bytes()
begin = b'\r\n // BEGIN KV explicit fixed-handle access\r\n'
end = b' // END KV explicit fixed-handle access\r\n'
assert current.count(begin) == current.count(end) == 1
start = current.index(begin)
finish = current.index(end) + len(end)
old_equal = current[:start] + current[finish:] == (HERE/'PlayFabMgr.before.txt').read_bytes()
callers = {}
for path in (ROOT/'Client/Assets/Scripts').rglob('*.cs'):
# Identifier-only scan: Latin-1 preserves ASCII in both legacy GBK and UTF-8 sources.
lines = [i for i,s in enumerate(path.read_bytes().decode('latin-1').splitlines(),1)
if re.search(r'\b(?:ReadKV|WriteKV|FlushKVAsync|WaitForKVTicketAsync)\s*\(',s)]
if lines: callers[path.relative_to(ROOT).as_posix()] = lines
new = sorted(p.relative_to(ROOT).as_posix() for p in (ROOT/'Client/Assets/Scripts').rglob('*.cs')
if p.relative_to(ROOT).as_posix() not in inventory)
result = dict(sourceBaselineCount=len(inventory), sourceChanged=changed(inventory), newScriptSources=new,
oldPlayFabBytesUnchanged=old_equal,
designMaterialChanged=changed({f['path']:f['sha256'] for f in design['files']}),
oldB2DeliveryChanged=changed({f['path']:f['sha256'] for f in b2['files']}),
facadeReferences=callers,
limitation='Scope is reviewed baselines, not all pre-existing working tree changes. Static/conditional probes do not prove Unity Player linking or stripping.')
assert result['sourceChanged'] == [pf], result
assert result['designMaterialChanged'] == [pf], result
assert result['oldB2DeliveryChanged'] == [pf], result
assert old_equal
assert len(new) == 2
assert set(callers) == {pf,'Client/Assets/Scripts/Services/PlayerData/PlayerKVSaveRouteEditorValidationHost.cs'}
(HERE/'checkpoint4-boundary-audit.json').write_text(json.dumps(result,ensure_ascii=False,indent=2)+'\n',encoding='utf-8')
print(json.dumps(result,ensure_ascii=False,indent=2))