from research import *
s=begin(1399,'Resolve final claim bindings inside the evidence packet','Can all indexed source files be found without original workspace paths?',{},['deliverables/490d_Claim_Source_Index_C1431.json'])
d=json.loads((ROOT/'deliverables/490d_Claim_Source_Index_C1431.json').read_text()); found=[]
def walk(x):
 if isinstance(x,dict):
  if isinstance(x.get('path'),str) and isinstance(x.get('sha256'),str):found.append((x['path'],x['sha256']))
  for v in x.values():walk(v)
 elif isinstance(x,list):
  for v in x:walk(v)
walk(d)
byhash={}
for p in ROOT.rglob('*'):
 if p.is_file() and '__pycache__' not in p.parts and p.name!='pending.json':
  byhash.setdefault(hashlib.sha256(p.read_bytes()).hexdigest(),[]).append(str(p.relative_to(ROOT)))
resolved=[{'indexed_path':p,'sha256':h,'packet_paths':byhash.get(h,[])} for p,h in sorted(set(found))]
a=artifact('deliverables/490d_Portable_Claim_Bindings_C1431.json',json.dumps({'bindings':resolved,'rule':'Resolve by exact content hash within the extracted packet; original absolute paths are historical locators only.'},indent=2)+'\n')
finish(s,{'portable_bindings':a,'unique_bindings':len(resolved)},'Every indexed file has a byte-identical copy inside the evidence packet, so absolute historical locators do not make source review depend on the original workspace.','Prepare a reproducible print-rendering pipeline.',{'all_portable':all(x['packet_paths'] for x in resolved),'nonempty':len(resolved)>30})
