from pathlib import Path
import json,hashlib,shutil,re,datetime
W=Path('/mnt/data/work4100');R=W/'site';D=W/'input/документы-и-доказательства-4.9.0';M=W/'input/память-уаикс-4.9.0';E=R/'доказательства/редакция-4.10.0';E.mkdir(exist_ok=True)
def write(p,x): p.parent.mkdir(parents=True,exist_ok=True);p.write_text(json.dumps(x,ensure_ascii=False,indent=2)+'\n')
# Read every evidence byte and parse each JSON. Large corpora are inventoried programmatically, not called a manual review.
rows=[]
for p in sorted((D/'доказательства/редакция-4.9.0').rglob('*')):
 if not p.is_file():continue
 b=p.read_bytes();r={'путь':p.relative_to(D).as_posix(),'байты':len(b),'ша256':hashlib.sha256(b).hexdigest(),'метод':'полное программное чтение байтов'}
 if p.suffix=='.json':
  try:
   j=json.loads(b);r['тип_JSON']=type(j).__name__
   if isinstance(j,dict):r['поля']=list(j);r['итоги']={k:v for k,v in j.items() if isinstance(v,(int,float,bool,str,type(None))) and (len(str(v))<1800)}
   else:r['элементов']=len(j)
  except Exception as ex:r['ошибка_JSON']=str(ex)
 rows.append(r)
write(E/'опись-чтения-основания.json',rows)
for p in (W/'run').glob('*.json'):shutil.copyfile(p,E/p.name)
# Preserve original current records and sources; no rewrite of signed/historical payloads.
archive=R/'docs/архив-выпусков/4.9.0-полученные-наборы'
for base in [M,D]:
 for p in base.iterdir():
  if p.is_file() and (p.suffix in ['.uai','.txt','.md'] or p.name=='МАНИФЕСТ-ВЫПУСКА.json'):
   dest=archive/base.name/p.name;dest.parent.mkdir(parents=True,exist_ok=True);shutil.copyfile(p,dest)
for n in ['ресурсы/сценарии/доказательный-контур.js','ресурсы/сценарии/исполнитель-контура.js','ресурсы/сценарии/поток-доказательного-контура.js','ресурсы/сценарии/методика.js','ресурсы/стили/сайт.css']:
 if (R/n).is_file():p=archive/n;p.parent.mkdir(parents=True,exist_ok=True);shutil.copyfile(R/n,p)
for n in ['память-уаикс','документы-и-доказательства','набор-владельца']:
 src=Path('/mnt/data')/(n+'-4.9.0-wip.zip')
 # Only the previous memory is added to history. The other exact input archives remain external and are identified by hash.
 if n=='память-уаикс':shutil.copyfile(src,R/'загрузки'/src.name)
# Current schemas are new derivatives; old schema files remain unchanged and are addressable in the profile.
profile=json.loads((R/'данные/профиль-схем-4.9.0.json').read_text());new=json.loads(json.dumps(profile));new['редакция']='4.10.0-wip'
for k,v in profile['файлы'].items():
 if '4.9.0' in v:
  src=R/v.lstrip('/');dest=R/v.lstrip('/').replace('4.9.0','4.10.0');dest.write_text(src.read_text().replace('4.9.0','4.10.0'))
  new['файлы'][k]=v.replace('4.9.0','4.10.0');new['файлы'][k+'490']=v
for name in ['схема-оценки-когнитивной-свободы','схемы-лаборатории']:
 p=R/'данные'/f'{name}-4.9.0.json';(R/'данные'/f'{name}-4.10.0.json').write_text(p.read_text().replace('4.9.0','4.10.0'))
write(R/'данные/профиль-схем-4.10.0.json',new)
# Update executable current code, not historical scripts/schemas/signed examples.
for p in (R/'ресурсы/сценарии').glob('*.js'):
 s=p.read_text();s=s.replace('4.9.0','4.10.0').replace('4.9-1','4.10-1');p.write_text(s)
core=R/'ресурсы/сценарии/доказательный-контур.js';s=core.read_text()
s=s.replace("'4.8.0-wip'].includes", "'4.8.0-wip','4.9.0-wip'].includes")
s=s.replace("version==='4.8.0-wip'?'480':null", "version==='4.8.0-wip'?'480':version==='4.9.0-wip'?'490':null")
s=s.replace("version==='4.8.0-wip'?schemas.registry480:version===RELEASE", "version==='4.8.0-wip'?schemas.registry480:version==='4.9.0-wip'?schemas.registry490:version===RELEASE")
s=s.replace('4.6.0 4.7.0 или 4.8.0 нужного вида.', '4.6.0, 4.7.0, 4.8.0 или 4.9.0 нужного вида.')
core.write_text(s)
# Each current page is a derivative. Seven are not claimed to be exact 4.9.0 pages.
page_report=[]
for p in sorted(R.rglob('*.html')):
 rel=p.relative_to(R).as_posix()
 if rel.startswith(('docs/архив-выпусков/','доказательства/')):continue
 raw=p.read_bytes();s=raw.decode();s=s.replace('4.9.0','4.10.0').replace('4.8.0','4.10.0')
 # Only current links with numbered product metadata are changed; historical docs have explicit archive paths.
 s=s.replace('проверка-рубежей-4-9.uai','проверка-рубежей-4-10.uai').replace('решение-о-выпуске-4-9.uai','решение-о-выпуске-4-10.uai')
 p.write_text(s);page_report.append({'путь':rel,'до':hashlib.sha256(raw).hexdigest(),'после':hashlib.sha256(p.read_bytes()).hexdigest(),'тип':'машинная редакционная производная; исходное происхождение см. восстановление-страниц-490.json'})
write(E/'производные-страницы-подготовка.json',page_report)
# Restore exact historical research main bodies after shell version edits.
from bs4 import BeautifulSoup
for p in (R/'docs/исследования').glob('*.html'):
 src=D/p.relative_to(R)
 if not src.exists():continue
 old=src.read_text();newtxt=p.read_text()
 # Exact main content is preserved by replacing only shell-level version refs in separate editorial step later.
 # Entire source page already current 4.9.0, so preserve main markup directly.
 m=re.search(r'(<main\b[^>]*>)(.*?)(</main>)',old,re.S)
 if m:newtxt=re.sub(r'(<main\b[^>]*>).*?(</main>)',lambda mm:mm.group(1)+m.group(2)+mm.group(2),newtxt,flags=re.S);p.write_text(newtxt)
for name in ['service-worker.js','служба.js','ВЕРСИЯ.txt','sitemap.xml','.htaccess','robots.txt']:
 p=R/name
 if p.exists():p.write_text(p.read_text().replace('4.9.0','4.10.0').replace('4.8.0','4.10.0'))
# Keep command replay reports separate; never overwrite original 4.9 evidence.
print('prepared',len(page_report),'pages; prior evidence files',len(rows))
