from pathlib import Path import hashlib,json,re,shutil,subprocess,zipfile ROOT=Path('/workspace/scratch/1b40da62dcbd');WORK=ROOT/'spine_integration_20260928';OUT=WORK/'deliverables';PKG=WORK/'reader_package';PKG.mkdir(exist_ok=True) BASE=ROOT/'audit_cancel_20260928/recovered/reader' source_map={} for p in BASE.iterdir(): if p.name in ['MANIFEST.sha256','SOURCE_TO_PACKAGE.json','README.md']:continue source=OUT/p.name if (OUT/p.name).is_file() else p shutil.copy2(source,PKG/p.name) source_map[p.name]={'source':str(source),'sha256':hashlib.sha256(source.read_bytes()).hexdigest(),'edition':'September28 spine expansion' if source.parent==OUT else 'C1431 inherited'} source=ROOT/'upload/490d_LXX_Reversed_Spines_and_Accepted_SP_Solution_20260928(1).md' name='490d_LXX_Reversed_Spines_and_Accepted_SP_Solution_20260928.md' shutil.copy2(source,PKG/name) assert hashlib.sha256(source.read_bytes()).hexdigest()=='3083e334c2834b5b53aa2acab6aa957c1e21bd28ccb404eb91ec2158d859acdb' source_map[name]={'source':str(source),'sha256':hashlib.sha256(source.read_bytes()).hexdigest(),'edition':'Supplied September28 study; unchanged bytes'} notes='490d_Spine_Integration_Notes_20260928.md';shutil.copy2(OUT/notes,PKG/notes) source_map[notes]={'source':str(OUT/notes),'sha256':hashlib.sha256((OUT/notes).read_bytes()).hexdigest(),'edition':'September28 integration notes'} for p in PKG.glob('*.md'): p.write_text(re.sub(r'sandbox:/[^\s)]+',lambda m:Path(m.group()).name,p.read_text())) (PKG/'490d_Start_Here_C1431.md').write_text('''# Start here: the chronological families Expanded September28 edition: the C1431 explanation now includes the supplied MT/LXX/SP spine comparison. The same segmented reversal generates MT convergence and definite LXX/SP head separations; the accepted SP Fall construction connects with MT Creation intervals and LXX comparisons. - [Main explanation —18-page PDF](490d_Chronological_Families_Explanation_C1431_Print.pdf) - [Main explanation —Markdown](490d_Chronological_Families_Explanation_C1431.md) - [Technical companion —9-page PDF](490d_Technical_Companion_C1431_Print.pdf) - [Complete supplied LXX/SP study](490d_LXX_Reversed_Spines_and_Accepted_SP_Solution_20260928.md) - [Integration and verification notes](490d_Spine_Integration_Notes_20260928.md) - [Family map](Chronological_Families_Map.png) - [C1431 four-part grammar overview](490d_Four_Part_Grammar_Overview_C1431.md) - [Reading guide](490d_Reading_Guide_C1431.md) The original C1431 research archive remains the frozen baseline. Its JSON grammar and claim index retain that scope; the new chapter and technical §4A document the extension. The inverse of the inverse remains deferred. ''') notices={ '490d_Reading_Guide_C1431.md':'The expanded edition adds “The same spine operation in LXX and SP” after the MT backbone, with technical §4A. Read the integration notes and complete supplied study for the new source decisions and checks. The main reader is now18 pages and the companion9 pages.', '490d_Remaining_Questions_C1431.md':'The subsequent September28 study now supplies the accepted SP Fall trunks and their LXX comparison. The remaining full-genealogy reconstruction question is distinct from those completed selected trunks. A full reciprocal mapping remains open.', '490d_Source_Costs_and_Claim_Status_C1431.md':'The comparative extension retains the accepted SP−5 Rounded Fall interpretation as a premise, applied to both lower Creation members before reversal. The common+2700 tail and repeated mode differences are dependent consequences. See the integration notes for the new review scope.', '490d_Contribution_Status_C1431.md':'The September28 reader extension integrates the supplied LXX/SP study, six-trunk comparison, signed mode gaps and preserved cumulative contraction pattern. It follows the300-action checkpoint and does not add numbered research actions to that record.', '490d_Strategy_Progress_C1431.md':'The added MT/LXX/SP spine comparison advances the common-operation account: one segmented reversal permits different organized outcomes, while declared translations and Key expansions connect the resulting trunks across families. See the new main chapter and technical §4A.' } for name,note in notices.items(): p=PKG/name;s=p.read_text();lines=s.splitlines();p.write_text(lines[0]+'\n\n**September28 reader update.** '+note+'\n\n'+'\n'.join(lines[1:]).lstrip()+'\n') # Preserve the full supplied study literally; it has no sandbox links needing projection. assert (PKG/'490d_LXX_Reversed_Spines_and_Accepted_SP_Solution_20260928.md').read_bytes()==source.read_bytes() V=PKG/'verification';V.mkdir(exist_ok=True) for name in ['spine_arithmetic_review.md','spine_arithmetic_verification.json','PDF_Visual_QA.json']: shutil.copy2(WORK/'prep'/name,V/name) s=(WORK/'prep/verify_spine_arithmetic.py').read_text() s=s.replace("SOURCE = Path('/workspace/scratch/1b40da62dcbd/upload/490d_LXX_Reversed_Spines_and_Accepted_SP_Solution_20260928(1).md')","SOURCE = ROOT.parent / '490d_LXX_Reversed_Spines_and_Accepted_SP_Solution_20260928.md'") (V/'verify_spine_arithmetic.py').write_text(s) result=subprocess.run(['python3',str(V/'verify_spine_arithmetic.py')],capture_output=True,text=True,check=True) print('PORTABLE_ARITHMETIC',result.stdout.strip()) (PKG/'README.md').write_text('''# Chronological families — expanded reader release This September28 edition includes the supplied LXX/SP spine study in the main explanation. Start with the18-page main PDF; technical §4A supplies the shared formulas in the9-page companion. The complete supplied study and the integration notes are included. The original C1431 full evidence archive remains unchanged. The inherited JSON grammar and claim/source index retain C1431 scope. The added chapter and technical §4A have a separate112-assertion arithmetic review; the old779-check total is not increased or reassigned to the new edition. Markdown links are local to this package. SOURCE_TO_PACKAGE.json records the input hashes and packaged hashes of the inherited or revised reader files. MANIFEST.sha256 covers every other packaged file. Verification scripts and reports are under verification/; run python3 verification/verify_spine_arithmetic.py to repeat the bounded arithmetic checks. The calculator accepts the study's source coordinates; it does not reconstruct the underlying Report IV lifespan totals. The accepted SP Fall construction is retained. The inverse of the inverse remains deferred. No C1432 action was executed. ''') # Add missing spaces in new package-only notices, without touching the unchanged source report. for name in ['README.md','490d_Start_Here_C1431.md',*notices]: p=PKG/name;s=p.read_text() for a,b in [('September28','September 28'),('the18','the 18'),('the9','the 9'),('separate112','separate 112'),('old779','old 779'),('now18','now 18'),('companion9','companion 9'),('SP−5','SP −5'),('common+2700','common +2700'),('the300','the 300')]:s=s.replace(a,b) p.write_text(s) rows=[] for name,meta in source_map.items(): p=PKG/name;rows.append({'name':name,'input_path':meta['source'],'input_sha256':meta['sha256'],'source_edition':meta['edition'],'packaged_sha256':hashlib.sha256(p.read_bytes()).hexdigest(),'bytes':p.stat().st_size,'presentation_or_edition_notice_changed':hashlib.sha256(p.read_bytes()).hexdigest()!=meta['sha256']}) (PKG/'SOURCE_TO_PACKAGE.json').write_text(json.dumps({'edition':'C1431 reader expanded with September28 supplied spine study','records':rows},indent=2)+'\n') files=sorted(p for p in PKG.rglob('*') if p.is_file() and p.name!='MANIFEST.sha256') (PKG/'MANIFEST.sha256').write_text(''.join(hashlib.sha256(p.read_bytes()).hexdigest()+' '+p.relative_to(PKG).as_posix()+'\n' for p in files)) # Check the actual final deliverables and all local Markdown links. links=[] for p in PKG.rglob('*.md'): for link in re.findall(r'\]\(([^)]+)\)',p.read_text()): if '://' in link or link.startswith('#'):continue target=p.parent/link.split('#',1)[0] assert target.is_file(),(p.name,link) links.append([p.relative_to(PKG).as_posix(),link]) zip_path=OUT/'490d_Chronological_Families_Reader_Package_C1431.zip' with zipfile.ZipFile(zip_path,'w',zipfile.ZIP_DEFLATED) as z: for p in sorted(PKG.rglob('*')): if p.is_file():z.write(p,p.relative_to(PKG).as_posix()) with zipfile.ZipFile(zip_path) as z: assert z.testzip() is None for line in z.read('MANIFEST.sha256').decode().splitlines(): h,n=line.split(' ',1);assert hashlib.sha256(z.read(n)).hexdigest()==h,n report={'status':'PASS','payload_count':len(files),'zip_entries':len(files)+1,'source_to_package_records':len(rows),'local_links_verified':len(links),'unchanged_supplied_study_sha256':hashlib.sha256(source.read_bytes()).hexdigest(),'zip_sha256':hashlib.sha256(zip_path.read_bytes()).hexdigest(),'bytes':zip_path.stat().st_size} (WORK/'prep/package_review.json').write_text(json.dumps(report,indent=2)+'\n');print(json.dumps(report))