"""Rig a same-character GLB on configured DGXA and retain source provenance. Only explicit --generate starts inference. Reuses a byte-verified cached result. The approved low-poly mesh is preserved and receives these weights later. """ import argparse import hashlib import json from pathlib import Path import shutil import sys import time import uuid REPO=Path(__file__).resolve().parents[1] def digest(path): return hashlib.sha256(path.read_bytes()).hexdigest() def main(): parser=argparse.ArgumentParser(description=__doc__) parser.add_argument('--source',type=Path,required=True) parser.add_argument('--out',type=Path,required=True) parser.add_argument('--generate',action='store_true') args=parser.parse_args() source=args.source.resolve();out=args.out.resolve() if not source.is_relative_to(REPO) or not out.is_relative_to(REPO): parser.error('Character source and output must stay in the repository') if source.suffix.lower()!='.glb' or not source.is_file(): parser.error('Expected this character\'s source GLB') source_hash=digest(source);receipt=out/'rig_request.json';target=out/'rigged.glb' if receipt.is_file() and target.is_file(): record=json.loads(receipt.read_text(encoding='utf-8')) if record['source_sha256']==source_hash and record['rig_sha256']==digest(target): print('PASS cached same-source rig',target);return if not args.generate: parser.error('No verified cache. --generate explicitly requests DGXA rigging') sys.path.insert(0,str(REPO/'Tools')) from dgx3d_animal_pipeline import _ensure_llm3d _ensure_llm3d() from backend.tokenrig_runner import run_tokenrig stage=out/'generations'/uuid.uuid4().hex;stage.mkdir(parents=True) result=Path(run_tokenrig(source,stage,stage/'tokenrig.log',skeleton_template='original')) if not result.is_file() or result.stat().st_size<100: raise RuntimeError('Missing TokenRig result') record=dict(status='generated',source=str(source.relative_to(REPO)),source_sha256=source_hash, rig_sha256=digest(result),template='original',stage=str(stage.relative_to(REPO)), generated_at_utc=time.strftime('%Y-%m-%dT%H:%M:%SZ',time.gmtime())) shutil.copy2(result,target) temporary=receipt.with_suffix('.pending.json') temporary.write_text(json.dumps(record,indent=2),encoding='utf-8');temporary.replace(receipt) print('PASS same-source rig',target,flush=True) if __name__=='__main__':main()