import datetime
import hashlib
import json
import os
from pathlib import Path
import subprocess

ROOT=Path(__file__).resolve().parents[1]
os.umask(0o077)
def read(name):return json.loads((ROOT/name).read_text())
def file_info(path):
    h=hashlib.sha256()
    with path.open('rb') as f:
        for b in iter(lambda:f.read(1024*1024),b''):h.update(b)
    return dict(path=str(path),size_bytes=path.stat().st_size,sha256=h.hexdigest())
stages={s:read(s+'.result.json') for s in ('export','build','probe')}
assert all(r['returncode']==0 and r['reason'] is None for r in stages.values())
probe=[json.loads(l) for l in (ROOT/'probe.log').read_text().splitlines() if l.startswith('{')]
assert [r['batch'] for r in probe if 'batch' in r]==[1,2,3,4]
assert probe[-1]['contract']=='PASS'
before=read('containers.before.json');preserved={}
for name,old in before.items():
    c=json.loads(subprocess.check_output(['docker','inspect',name]))[0]
    preserved[name]=(c['Id']==old['id'] and c['Image']==old['image'] and c['State']['StartedAt']==old['started_at'])
manifest=read('manifest.intake.json')
manifest.update(status='TENSORRT_CANDIDATE_TECHNICAL_PASS',
    completed_at=datetime.datetime.now(datetime.timezone.utc).isoformat(),
    files={name:file_info(ROOT/path) for name,path in {
        'source':'source/checkpoint_best_total.safetensors','converted':'converted/checkpoint.pth',
        'onnx':'onnx/rfdetr-small.onnx','engine':'engine/model.plan'}.items()},
    conversion_tools={str(p.relative_to(ROOT)):file_info(p) for p in sorted((ROOT/'tools').glob('*')) if p.is_file()},
    export_contract=read('export-contract.json'),onnx_contract=read('onnx-contract.json'),stages=stages,
    engine_contract=dict(input=dict(name='input',shape=['batch',3,512,512],dtype='FP16'),
        outputs={'dets':dict(shape=['batch',300,4],dtype='FP32'),
                 'labels':dict(shape=['batch',300,3],dtype='FP32')},
        batch_min_opt_max=[1,4,4],optimization='FP16 allowed; not an all-layers-FP16 guarantee',
        tensorrt=probe[-1]['tensorrt'],executions=probe[:-1]),
    preprocessing=dict(color='RGB',layout='NCHW',scale='uint8 / 255',
        resize='bilinear to 512x512, antialias=False, no letterbox',
        mean=[.485,.456,.406],std=[.229,.224,.225],
        input_cast='FP16 after normalization'),
    output_semantics=dict(dets='normalized cx,cy,w,h',labels='raw per-class logits; sigmoid downstream',
        semantic_classes={'0':'person','1':'head'},extra_slot={'2':'additional/background slot; not a third crowd class'},
        mapping_basis='Official Awiros class_names [person,head], existing pinned RF-DETR custom-class enumerate mapping; not independently accuracy-tested',
        runtime_decoder='NOT_IMPLEMENTED_OR_REGISTERED'),
    validation=dict(onnx_checker='PASS',checkpoint_tensors_exact_match=487,
        engine_deserialization='PASS',batches_1_4_shape_dtype_finite='PASS',
        input_fixture='zero normalized FP16 tensor; no image-quality claim',accuracy='NOT_RUN_USER_VISUAL',
        performance='NOT_BENCHMARKED',target_icerti_gpu='NOT_CONVERTED',runtime_registration='NOT_RUN'),
    warnings=['ONNX tracing warnings retained in export.log; dynamic batch checked by actual TensorRT batch1-4 execution',
              'A6000 engine portability to Blackwell is not assumed'],
    existing_containers_preserved=preserved)
assert manifest['files']['source']['sha256']==manifest['source']['sha256']
with (ROOT/'manifest.json').open('x') as f:json.dump(manifest,f,indent=2)
print(json.dumps({'status':manifest['status'],'files':manifest['files'],
                  'containers_preserved':all(preserved.values()),'root_min_gib':min(r['lowest_root_bytes'] for r in stages.values())/1024**3}),flush=True)
