"""Build an explicit compatibility resource from a completed current-Client capture.""" import json, hashlib from pathlib import Path root = Path(__file__).resolve().parents[1] capture = root / 'battle_diagnostics/cw54-role-replacement.log' raw = capture.read_text(encoding='utf-8-sig') rows = [json.loads(line.split(' ROW ', 1)[1]) for line in raw.splitlines() if '[GAC_CW_REPLACEMENT] ROW ' in line] if '[GAC_CW_REPLACEMENT] END' not in raw or not rows: raise ValueError('Capture is incomplete') old = json.loads((root / 'resources/CurrencyWarsCatalog.json').read_text(encoding='utf-8-sig')) current = json.loads((root / 'resources/CurrencyWarsCurrentRoles.json').read_text(encoding='utf-8-sig')) ids = {row['ID'] for row in current['roles']} target = rows[0]['Config'] missing = [row['Config'] for row in old['active_handbook_default_roles'] if row['Config']['ID'] not in ids and row['Config']['AvatarID'] == target['AvatarID'] and row['Config']['SeasonID'] == target['SeasonID']] if len(missing) != 1 or {row['Star'] for row in rows} != set(range(1, rows[0]['MaxStar'] + 1)): raise ValueError('Replacement identity or star coverage is ambiguous') resource = {'format_version': 1, 'source_assembly_sha256': old['provenance']['game_assembly_sha256'], 'target_assembly_sha256': current['client_assembly_sha256'], 'capture_sha256': hashlib.sha256(capture.read_bytes()).hexdigest(), 'source': 'Current Client GetHandBookAllRoleConfig DefaultRole, complete existing star configs; no new role ID inferred from avatar arithmetic.', 'entries': [{'previous_role_id': missing[0]['ID'], 'current_role_id': target['ID'], 'variants': rows}]} (root / 'resources/CurrencyWarsRoleCompatibility.json').write_text(json.dumps(resource, ensure_ascii=False, indent=2) + '\n', encoding='utf-8')