"""Source-only preparation; no numbered research actions or source mutation."""
from pathlib import Path
from fractions import Fraction as F
import hashlib,json,re

BASE=Path('/workspace/scratch/1b40da62dcbd')
OUT=BASE/'c832_c931/prep'
SPECS={
 'File60':('project_sources/36-File_60.Levitical_Covenant_Spine_161_299_Key_of_23_Reconciliation-10-.md',[(1348,1520,'§7, complete Mirror family'),(2170,2182,'Appendix C, literal phase ledger')]),
 'File61':('project_sources/31-File_61.Jacob_Moses_Cumulative_Regular_Root_System-6-.md',[(1526,1654,'§10, complete three-heptad family'),(2383,2477,'§16, complete Babylon lifespan rails')]),
 'File62':('project_sources/18-File_62.Half_Clutch_Birth_Law_Interface-1-.md',[(1305,1353,'§8.6E, factor-33 subdivision; optional supporting source')]),
 'File63':('project_sources/09-File_63.Scale_Neutral_480_483_490_Carrier-20260821-143254-.md',[(1771,1831,'§§7.2–7.3, inherited paired source endpoints'),(1930,2447,'§§7.7–7.11, complete nested carrier and Covenant-stars network')]),
}
packet={'status':'PREPARATION ONLY; derived diagnostics are not executed numbered research',
 'sources':{},'excerpts':[],'literal_tables':[],'literal_code_blocks':[]}
all_lines={}
for k,(relative,ranges) in SPECS.items():
 p=BASE/relative; raw=p.read_bytes(); lines=raw.decode().splitlines(); all_lines[k]=lines
 packet['sources'][k]={'path':str(p),'sha256':hashlib.sha256(raw).hexdigest(),'bytes':len(raw)}
 for lo,hi,section in ranges:
  packet['excerpts'].append({'source':k,'section':section,'first_line':lo,'last_line':hi,'text':'\n'.join(lines[lo-1:hi])})
  i=lo-1
  while i<hi:
   if lines[i].startswith('|'):
    start=i; rows=[]
    while i<hi and lines[i].startswith('|'):
     rows.append({'line':i+1,'raw':lines[i],'cells':[c.strip() for c in lines[i].strip().strip('|').split('|')]}); i+=1
    packet['literal_tables'].append({'source':k,'section':section,'first_line':start+1,'last_line':i,'rows':rows})
   elif lines[i].startswith('```'):
    start=i; i+=1
    while i<hi and not lines[i].startswith('```'):i+=1
    packet['literal_code_blocks'].append({'source':k,'section':section,'first_line':start+1,'last_line':min(i+1,hi),'text':'\n'.join(lines[start:min(i+1,hi)])}); i+=1
   else:i+=1

def locator(k,needle):
 matches=[i+1 for i,s in enumerate(all_lines[k]) if needle in s]
 return {'source':k,'needle':needle,'matching_lines':matches}

macro=[
 {'id':'regular_Jacob_whole','source_BC':14006,'target_BC':2006,'source_role':'cumulative Creation Day-6','target_role':'regular Jacob birth','span':12000,'unfolded_span':144000,'macro_head_BC':146006,'locator':locator('File63','2006+144000=146006')},
 {'id':'regular_Jacob_jubilee','source_BC':14011,'target_BC':2006,'source_role':'cumulative Creation Day-1','target_role':'regular Jacob birth','span':12005,'unfolded_span':144060,'macro_head_BC':146066,'locator':locator('File63','2006+144060=146066')},
 {'id':'cumulative_Levi_upper','source_BC':14011,'target_BC':1936,'source_role':'cumulative Creation Day-1','target_role':'cumulative Jacob death / Levi birth upper whole-year','span':12075,'unfolded_span':144900,'macro_head_BC':146836,'locator':locator('File63','1936+144900=146836')},
 {'id':'cumulative_Levi_lower','source_BC':14008,'target_BC':1933,'source_role':'cumulative Creation Day-4','target_role':'cumulative Jacob death / Levi birth lower whole-year','span':12075,'unfolded_span':144900,'macro_head_BC':146833,'locator':locator('File63','1933+144900=146833')},
 {'id':'apparent_Covenant','source_BC':14041,'target_BC':2081,'source_role':'cumulative apparent-age head','target_role':'author-designated regular Covenant of Pieces','span':11960,'unfolded_span':143520,'macro_head_BC':145601,'locator':locator('File63','2081+143520=145601')},
 {'id':'Creation_offering','source_BC':14011,'target_BC':2051,'source_role':'cumulative Creation Day-1','target_role':'proposed Isaac offering age15','span':11960,'unfolded_span':143520,'macro_head_BC':145571,'locator':locator('File63','2051+143520=145571')},
]
packet['named_inputs']={
 'macro_lift_six':macro,
 'carrier_order':[11960,12000,12005,12075],
 'carrier_pairs':[[14011,2051],[14006,2006],[14011,2006],[14011,1936]],
 'carrier_sources':['File63 §§7.7–7.9'],
 'double_115_hinge':[2166,2051,1936],
 'twelvefold':12,
 'scalar_interchange':{'input':144900,'input_factors':[900,161],'P_output':147000,'P_factors':[1000,147],'E_output':157500,'E_factors':[900,175],'source':'File63 §7.8.2'},
 'terminal_thousandth':{'nodes':[148936,2083,1936],'intervals':[146853,147],'source':'File63 §7.8.2'},
 'external_civil_squares':[{'macro_head_BC':145601,'lower_BC':2081,'external_era':'BC','external_label':1,'total':145600,'source':'File63 §7.9'},{'macro_head_BC':145571,'lower_BC':2051,'external_era':'AD','external_label':30,'total':145600,'source':'File63 §7.9'}],
 'mirror_three':{'lower_Nisan_source_BC':[1567,1728,1866],'roles':['Levi death','Ishmael death','Covenant of Pieces'],'BC_Tishri_source':[1568,1729,1867],'AD_Tishri_target':[1567,1728,1866],'AD_Nisan_target':[1568,1729,1867],'Exodus_BC_Tishri':1447,'Exodus_BC_Nisan':1446,'spans':[3013,3174,3312],'source':'File60 §7.2'},
 'heptad_field':{'nodes':['1670','3333/2','1663','1656','3305/2','1649'],'source':'File61 §10.3','center':'3319/2','note':'mixed regular Plenty/Famine and cumulative Amram roles; exact Aaron/Tishri3.5'},
 'Babylon_rails':[{'head_BC':1936,'tail_BC':606,'unit':133,'source':'File61 §16.2'},{'head_BC':1909,'tail_BC':539,'unit':137,'source':'File61 §16.3'},{'head_BC':1906,'tail_BC':536,'unit':137,'source':'File61 §16.3'},{'head_BC':2006,'tail_BC':536,'unit':147,'source':'File61 §16.4'}],
}
def s(v):return str(v) if isinstance(v,F) and v.denominator!=1 else int(v)
diagnostics={}
diagnostics['macro_lift']=[dict(id=x['id'],calculated=12*x['source_BC']-11*x['target_BC'],matches=12*x['source_BC']-11*x['target_BC']==x['macro_head_BC']) for x in macro]
diagnostics['macro_differences']=[{'from':macro[a]['id'],'to':macro[b]['id'],'source_change':macro[b]['source_BC']-macro[a]['source_BC'],'target_change':macro[b]['target_BC']-macro[a]['target_BC'],'macro_change':macro[b]['macro_head_BC']-macro[a]['macro_head_BC']} for a,b in [(0,1),(1,2),(2,3),(4,5)]]
co=packet['named_inputs']['carrier_order']; diagnostics['carrier_increments']=[b-a for a,b in zip(co,co[1:])]; diagnostics['twelvefold_increments']=[12*x for x in diagnostics['carrier_increments']]
diagnostics['lift_rule']='M_m(C,R)=R+m(C-R)=mC+(1-m)R; File63 m12. This is anchored span scaling with typed source/target roles.'
diagnostics['lift_delta_rule']='delta M=12 delta C−11 delta R. Joint translation covariance follows because12−11=1.'
diagnostics['exact_recovery_rule']='Given m12 and either endpoint plus the macro head, the other endpoint is recovered uniquely. M is not an invertible map on the two-endpoint source pair without retaining an endpoint.'
diagnostics['scalar_interchange']={'P':s(F(70,69)*144900),'E':s(F(25,23)*144900),'P_gain':2100,'E_gain':12600,'E_minus_P':10500,'gain_units_2100':[1,6,5]}
diagnostics['terminal_biography_status']={'source_tail':1936,'retained_boundary':2083,'retained_interval':147,'uniform_P_image_of_boundary':s(F(1936)+F(147)*F(70,69)),'uniform_P_terminal_interval':s(F(147)*F(70,69)),'boundary_difference':s(F(147)*(F(70,69)-1)),'preimage_for_retained_147':s(F(147)*F(69,70)),'meaning':'The source retains the147 biography inside a newly enlarged outer body; it does not uniformly transport that internal biography by P.'}
h=list(map(F,packet['named_inputs']['heptad_field']['nodes'])); diagnostics['heptad_shape']={'intervals':[s(a-b) for a,b in zip(h,h[1:])],'reflection_sum':3319,'closure':all(F(3319)-x in h for x in h),'node_reflections':[[s(x),s(F(3319)-x)] for x in h]}
packet['derived_diagnostics']=diagnostics
packet['novelty_controls']={
 'already_executed':['C532–551 File60 principal eleven-node Covenant network and scalar comparators','C552–573 root/clutch/Joseph complete fields and Actual/Rounded interfaces','C574–575 common897n lattice INCLUDING143520 J/P/E outputs; do not rediscover those outputs','C576–586 carrier ladders, full Creation/Flood translations, macro birth-law path','C550 regular Jacob1470, C659 Babylon1400 rectangle'],
 'new_candidate':'File63 §§7.7–7.9 complete typed endpoint-to-macro lift and all four source change responses; ordered40|5|70 path and12fold lifting; no single global chronology conversion',
 'secondary_unexecuted_candidates':['File61 §10 complete six-node three-heptad reflection object','File60 §7 full three-node phase Mirror; already prepared in earlier memo but not an executed step','File61 §16 complete tenfold lifespan rail family; regularJacob1470 result inherited'],
 'historical_and_theological_premises':['Twelvefold Israel/tribes interpretation is structural or typological, not mathematically forced','2081 Covenant and2051 offering age15 are author-designated/proposed; Genesis22 does not state Isaac age','Derived macro heads are generated coordinates, not primary historical nodes','File59 census579600 is imported, not independently audited here','1BC/AD30 are source-controlled comparison endpoints; AD33 preference is not replaced','Cumulative and regular endpoints with shared labels remain distinct roles'],
 'active_exclusions':['No File16/File55 primer execution','No1486 calculations','No upstream Gear transport','No second decimal inversion','No statistical tally','No canonical source edits'],
}
OUT.mkdir(parents=True,exist_ok=True)
(OUT/'covenant_inputs.json').write_text(json.dumps(packet,indent=2,ensure_ascii=False)+'\n')
print(json.dumps({'sources':len(packet['sources']),'excerpts':len(packet['excerpts']),'tables':len(packet['literal_tables']),'code_blocks':len(packet['literal_code_blocks']),'six_macro_matches':all(x['matches'] for x in diagnostics['macro_lift']),'path':str(OUT/'covenant_inputs.json')}))
