"""Strict bridge to the immutable qualified2026-11-03 ROM.

New main-menu hooks, checksum implementation and the credits bitmap are checked
against assembled current source/assets, then removed. The resulting whole ROM
must reproduce the exact qualified parent. Older protected-region gates still
run on that parent, with their original hashes/criteria/negative controls.
"""
from pathlib import Path
from functools import lru_cache
import hashlib,subprocess,tempfile,struct
import main_menu
PARENT='7d1fc931f5a5a4958b1eefcc05f00661b5321a6a1b2404d7563c98a22b8eb262'
HERE=Path(__file__).resolve().parent
@lru_cache(maxsize=1)
def module():
 with tempfile.TemporaryDirectory(prefix='nhl94-menu-scope-')as td:
  p=Path(td)/'module.bin';subprocess.run([str(HERE.parent/'m68kasm.sh'),str(HERE/'main_menu.s'),'25c000',str(p)],check=True,stdout=subprocess.DEVNULL);return p.read_bytes()
@lru_cache(maxsize=1)
def goalie_module():
 with tempfile.TemporaryDirectory(prefix='nhl94-y-scope-')as td:
  p=Path(td)/'module.bin';subprocess.run([str(HERE.parent/'m68kasm.sh'),str(HERE/'downed_y.s'),'25cc00',str(p)],check=True,stdout=subprocess.DEVNULL);return p.read_bytes()
@lru_cache(maxsize=1)
def overall_module():
 with tempfile.TemporaryDirectory(prefix='nhl94-ovr-scope-')as td:
  p=Path(td)/'module.bin';subprocess.run([str(HERE.parent/'m68kasm.sh'),str(HERE/'testcases/preview_parent_team_ovr.s'),'25ce00',str(p)],check=True,stdout=subprocess.DEVNULL);return p.read_bytes()
def sites():
 out=[];dummy=bytearray(b'\xff'*0xA00);dummy[16:20]=b'MM01'
 main_menu.install(None,lambda name,at:bytes(dummy),lambda at,old,new:out.append((at,old,new)))
 return out[1:]
def normalize(after):
 from preview_scope import prior_scope_image as preview_parent
 after=preview_parent(after)
 b=bytearray(after);assert len(b)==3145728,'main-menu exact ROM size'
 code=module();assert b[0x25c000:0x25ca00]==code,'main-menu module is not exact assembled source'
 for at,old,new in sites():
  assert b[at:at+len(new)]==new,('main-menu guarded hook differs',hex(at));b[at:at+len(old)]=old
 b[0x25c000:0x25ca00]=b'\xff'*0xA00
 credits=(HERE.parent/'data/boot-credits.bin').read_bytes();legacy=(HERE.parent/'data/boot-credits-legacy.bin').read_bytes()
 assert b[0x2d0000:0x2d8000]==credits+b'\xff'*(0x8000-len(credits)),'main-menu credits differ from current asset'
 b[0x2d0000:0x2d8000]=legacy+b'\xff'*(0x8000-len(legacy))
 from downed_y import HOOK,OLD,NEW,ORIGIN
 if b[HOOK:HOOK+6]==NEW:
  yc=goalie_module();assert b[ORIGIN:ORIGIN+0x200]==yc+b'\xff'*(0x200-len(yc)),'downed-Y module differs from exact assembled source'
  b[ORIGIN:ORIGIN+0x200]=b'\xff'*0x200;b[HOOK:HOOK+6]=OLD
 else:assert b[HOOK:HOOK+6]==OLD and b[ORIGIN:ORIGIN+0x200]==b'\xff'*0x200,'unexpected Y gate scope'
 from team_ovr import HOOK as OH,OLD as OO,NEW as ON,ORIGIN as OA
 if b[OH:OH+4]==ON:
  oc=overall_module();assert b[OA:OA+0x200]==oc+b'\xff'*(0x200-len(oc)),'team OVR module differs from exact assembled source'
  b[OA:OA+0x200]=b'\xff'*0x200;b[OH:OH+4]=OO
 else:assert b[OH:OH+4]==OO and b[OA:OA+0x200]==b'\xff'*0x200,'unexpected team OVR scope'
 b[0x120:0x180]=('NHL 2026 - 94 Edition v5.1W - 2026-11-03'.ljust(48)*2).encode('ascii')
 struct.pack_into('>H',b,0x18e,sum(struct.unpack_from('>H',b,i)[0]for i in range(0x200,len(b),2))&65535)
 assert hashlib.sha256(b).hexdigest()==PARENT,'outside strictly declared main-menu/credits scope'
 return bytes(b)
def prior_scope_image(after):
 # Existing historical scope tests also run on actual older references/negatives.
 if after[0x25c010:0x25c014]==b'MM01':return normalize(after)
 return after
