#!/usr/bin/env python3 """Independent C315: fixed five C314 rows, actual SP Flood and Noah death. --sources DIR contains PREVIOUS_DATA.json(C314), C286_DATA.json, C271_REGISTER.json and C307_DATA.json. --out DIR is the result directory. No later step or enlarged domain is evaluated. """ import argparse from fractions import Fraction as F import hashlib import json from pathlib import Path def main(): p=argparse.ArgumentParser();p.add_argument('--sources',type=Path);p.add_argument('--out',type=Path,default=Path(__file__).parent);a=p.parse_args() root=Path(__file__).resolve().parents[1] defaults={'PREVIOUS_DATA.json':root/'C314/evidence/DATA.json',**{n:root/'C313/sources'/n for n in ['C286_DATA.json','C271_REGISTER.json','C307_DATA.json']}} data={};hashes={} for n,d in defaults.items(): raw=(a.sources/n if a.sources else d).read_bytes();data[n]=json.loads(raw);hashes[n]=hashlib.sha256(raw).hexdigest() reg=data['C286_DATA.json']['target_register'];before=data['PREVIOUS_DATA.json'];ancestry=data['C271_REGISTER.json'];old=data['C307_DATA.json'] assert [r['j'] for r in before['rows']]==[3,4,5,6,7] assert old['base_rhs'][:2]==[8993,8395] assert all(x['n_and_r_offset']==x['source_offset'] for x in old['phase_actions']) def records(role=None,center=None,gear=None,rail=None): return [x for x in reg if x['tradition']=='SP' and x['Cainan']==0 and x['Terah60']==0 and x['full430']==1 and (role is None or x['role']==role) and (center is None or x['center']==center) and (gear is None or x['gear']==gear) and (rail is None or x.get('rail')==rail)] def one(role,center,gear,rail=None): xs=records(role,center,gear,rail);assert len(xs)==1;return xs[0] rows=[] for r in before['rows']: j,i,g,rail=r['j'],r['i'],r['gear'],r['rail'];n,s,d=r['biography_BC'];qi=-5290+i nd=n-950;f=n-600;rf=qi+8395 nr=one('Noah death',nd,g,rail) role='Flood start' if rail=='primary' else 'Flood close' fr=one(role,f,g) assert fr.get('rail') is None fs=records('Flood start',gear=g)[0]['center'];fc=records('Flood close',gear=g)[0]['center'] assert fs-fc==1 aliases=records('Flood start',rf)+records('Flood close',rf) assert all(x['gear']!=g for x in aliases) assert rf-f==2 and n-rf==598 assert n-s==500 and s-f==100 and f-nd==350 and nd-d==150 assert n-nd==950 and s-d==600 assert (n-fs,n-fc)==((600,601) if rail=='primary' else (599,600)) assert (rf-fs,rf-fc)==((2,3) if rail=='primary' else (1,2)) cp=[] for c in r['components']: en=F(c['Noah_ancestry_phase']);es=F(c['Shem_ancestry_phase']);nc=F(c['Noah']);sc=F(c['Shem_birth']);dc=F(c['Shem_death']) assert en==-es and nc==n+en and sc==s+en and dc==d+en fcomp=f+en;ndcomp=nd+en;rfcomp=qi+en+8395 assert nc-rfcomp==598 and rfcomp-fcomp==2 assert [nc-sc,sc-fcomp,fcomp-ndcomp,ndcomp-dc]==[500,100,350,150] ar=[x for x in ancestry if x['branch']=='Flood' and x['source_event']['gear']==g and x['source_event']['role']==role] assert len(ar)==1 and ar[0]['source_event']['BC_Nisan']==f arphase=[x for x in ar[0]['phases'] if F(x['reflected_coordinate'])==fcomp] assert len(arphase)==1 # Test both retained seasonal choices. No half-year swap closes a two-year residual. residuals=sorted({rfcomp-(F(f)+ef) for ef in (F(-1,4),F(1,4))}) assert 0 not in residuals cp.append({'Noah_ancestry_offset':str(en),'Shem_ancestry_offset':str(es),'Noah':str(nc),'Shem_birth':str(sc),'selected_Flood':str(fcomp),'selected_Flood_source_role':role,'selected_Flood_phase':arphase[0]['reflected_phase'],'Noah_death':str(ndcomp),'Shem_death':str(dc),'existing8395_Flood_requirement':str(rfcomp),'existing8395_minus_selected_Flood':'2','chain_spans':['500','100','350','150'],'existing8395_minus_both_selected_Flood_phase_choices':[str(x) for x in residuals]}) rows.append({'j':j,'i':i,'gear':g,'Noah_Shem_rail':rail,'regular_source_chain_BC':[n,s,f,nd,d],'selected_Flood_role':role,'selected_Flood_source_record':fr,'Noah_death_source_record':nr,'Flood_start':fs,'Flood_close':fc,'Noah_to_start_close':[n-fs,n-fc],'Shem_to_start_close':[s-fs,s-fc],'start_close_to_Noah_death':[fs-nd,fc-nd],'start_close_to_Shem_death':[fs-d,fc-d],'existing8395_Flood_requirement':rf,'existing8395_minus_selected_Flood':rf-f,'existing8395_minus_start_close':[rf-fs,rf-fc],'same_Gear_source_Flood_match':False,'wrong_Gear_coordinate_aliases':aliases,'phase_cases':cp}) assert [r['existing8395_Flood_requirement'] for r in rows]==[3112,3111,3110,3109,3108] assert [r['j'] for r in rows if r['wrong_Gear_coordinate_aliases']]==[5,6,7] out={'step':'C315','status':'passed','scope':'Independent fixed-five-case arithmetic, frozen source membership and exact-phase check.','input_sha256':hashes,'rows':rows,'counts':{'valid_source_chains':5,'valid_phase_chains':10,'selected_Flood_same_Gear_matches':5,'Noah_death_same_Gear_rail_matches':5,'same_ancestry8395_selected_Flood_matches':0,'wrong_Gear8395_coordinate_aliases':3,'8395_without_fixed_context_SP_Flood_alias':2},'derived_identities':{'source_chain':'500 +100 +350 +150 =1100','Noah_lifespan':'500 +100 +350 =950','Shem_lifespan':'100 +350 +150 =600','same_ancestry_bridge_difference':'8993 −8395 =598','selected_Flood_bridge_from_same_q':'8993 −600 =8393','unresolved_residual':'8395 −8393 =2'},'phase_findings':'The2-year residual is unchanged for equal output phases. Swapping one available seasonal component makes it3/2 or5/2; none gives0.','interpretation':'The 500-year source biography extends to actual same-Gear Flood start/close and Noah death, but not to the existing8395 Flood endpoint with the same cumulative ancestry. Three coordinate aliases belong to another Gear; they do not repair the typed match.','suggested_next_bounded_question':'Audit the two-year cumulative ancestry displacement required to retain8395 while matching the selected same-Gear Flood, including source-role provenance, exact phase and finite boundaries.','later_step_executed':False} a.out.mkdir(parents=True,exist_ok=True);(a.out/'C315_Independent_Math_Results.json').write_text(json.dumps(out,indent=2)+'\n');print(json.dumps({'status':'passed','source_chains':5,'phase_chains':10,'8395_same_ancestry_source_matches':0,'wrongGear_aliases':3,'residual_years':2})) if __name__=='__main__':main()