"""Explicit preseason transfer ROM scope against qualified November 2.

These bounds declare native entry replacements and named relocated modules;
ordinary physical rosters, uniforms, startup, movement and replay decoder stay
exact. Functional/ABI/Off checks are separately mandatory; bounds are not proof
of behavior. Never derive an allowlist by accepting the candidate's own diff.
"""
import hashlib
BASE_SHA='b29af4d9300da2f4d989e9537a0c94f2da43f701fdb6054f4c5b9ce5040fc3d8'
HOOKS=[(0x96da,18),(0x9ee8,22),(0x9f40,8),(0x9f5c,6),(0x9f7e,8),(0x9f9a,8),(0xee82,8),(0x12e24,16),(0x15b9a,12),(0x17102,12),(0x171ce,8),(0x17986,18),(0x18bc8,6),(0xf71fc,8),(0xf8906,8),(0xf894e,14),(0xf8a46,22),(0xf9a04,16),(0xfa382,12),(0xfaa3e,10),(0xfaca8,24),(0xfae26,10),(0xfafe4,8),(0xfd492,8),(0x1f9a40,8),(0xfa95e,10),(0xfab7c,10)]
NATIVE_MENU=[(0xf7758,0xf775a),(0xf7762,0xf7764),(0xf777a,0xf777c),(0xf7b44,0xf7b46),(0xf7bbc,0xf7bbe),(0xf7c08,0xf7c0a)]
MODULES={
 'row mapper':(0x222000,0x222500),'Allstar guarded keeper metadata':(0x22c000,0x22c400),
 'transfer engine':(0x234000,0x234800),'native mapped roster runtime':(0x236000,0x237000),
 'immutable market catalogue/OVR display order':(0x238000,0x23c100),'transfer screen':(0x250000,0x250c00),
 'even preferences':(0x254000,0x254200),'atomic season-reset journal':(0x256000,0x256400),
 'season slots journal/select lifecycle':(0x2aa000,0x2aa800),'current goalkeeper stats':(0x2d8c80,0x2d8d40),
 'CPU coach forward identity':(0x2dc800,0x2dc980),'keeper attack accounting':(0x2dd500,0x2dd700),
 'strict shootout eligible goalie count':(0x2de000,0x2de200),'CPU coach units':(0x2de900,0x2df000),
 'critical shot UID getter':(0x2df400,0x2df600),'row labels/value pointer relocation':(0x2e1000,0x2e1700),
 'shifted directional passing writer':(0x2e21a0,0x2e21c0),'season start and finished browser':(0x2e6000,0x2e9000),
 'shifted per-season settings and player count':(0x2eb000,0x2eba00),'native season simulation':(0x2f8200,0x2f9000),
 'scoring leaders current identities':(0x2fa000,0x2fa800),'team stats current identities':(0x2fb000,0x2fb800),
 'goalkeeper native stat slots':(0x2fd1c0,0x2fd210),
}
EXACT=[(0x30e,0x180e),(0xa000,0xee80),(0xee8a,0x11200),(0x260000,0x28ee00),(0x2a0000,0x2a9000),(0x240000,0x2494e6),(0x59900,0x59a00),(0xa68c,0xa79c),(0x22d000,0x22f000),(0x2fc000,0x2fc800),(0x225000,0x229000),(0x2ed000,0x2ee000)]
def verify(before,after):
 assert hashlib.sha256(before).hexdigest()==BASE_SHA,'exact qualified Nov2 transfer parent required'
 assert len(before)==len(after)==3145728
 ranges=[(0x120,0x180),(0x18e,0x190)]+[(a,a+n)for a,n in HOOKS]+NATIVE_MENU+list(MODULES.values())
 changed=[i for i,(x,y)in enumerate(zip(before,after))if x!=y]
 bad=[i for i in changed if not any(lo<=i<hi for lo,hi in ranges)]
 assert changed and not bad,('outside declared transfer code/data/row scope',[hex(i)for i in bad[:32]])
 for lo,hi in EXACT:assert before[lo:hi]==after[lo:hi],('unrelated physical roster/uniform/startup/physics/replay/assets changed',hex(lo),hex(hi))
 for at,n in HOOKS:assert after[at:at+2]in[bytes.fromhex('4eb9'),bytes.fromhex('4ef9')],('missing targeted native transfer hook',hex(at))
 assert before[0x17982:0x17986]==after[0x17982:0x17986],'shared player-name VM entry must retain separate native D1 preparation'
 return dict(parent_sha256=BASE_SHA,rom_sha256=hashlib.sha256(after).hexdigest(),changed_bytes=len(changed),native_hooks=HOOKS,native_menu_coordinates=NATIVE_MENU,named_modules=MODULES,unchanged_regions=EXACT,scope='Preseason transfer code/menu/identity/statistics/reset only; no Hard search, global frame hook or original roster/jersey/startup asset edits')
