"""Re-read body tie sections with the common generator; preserve other objects.""" import argparse import copy import json import os from pathlib import Path import sys import tempfile import time root=Path(__file__).resolve().parents[1] sys.path.insert(0,str(root/'src/backend'if (root/'src/backend').is_dir()else root)) def run(job_id,apply=False): import server from cad_rebar_recipe import load_sources from body_source_tie import build_reference_review server.require_modeling_rules() if len(job_id)!=24 or any(c not in '0123456789abcdef'for c in job_id):raise ValueError('invalid job') path=Path('/tmp/drawing-model-studio-8097-jobs')/(job_id+'.json');raw=path.read_bytes();job=json.loads(raw) if job.get('status')=='running':raise ValueError('active job') plan=job['result'];sources=load_sources(job['sourceContext']['analysis']) old={g['id']:g for g in plan['rebar_groups']if g.get('source_body_tie_binding')} rules={json.dumps(g['source_body_tie_binding']['reference_rule'],sort_keys=True)for g in old.values()} if len(rules)!=1:raise ValueError('no unique previously authorized repetition rule') errors=[];groups=build_reference_review(plan,sources,json.loads(next(iter(rules))),authorized=True, inventory=plan['drawingEvidence']['cad_fabrication_inventory'],failures=errors) replacements={};rows=[] for g in groups: prior=old.get(g['id']) if prior is None:continue n=len(g['source_body_tie_binding']['section']['stations']);before=len(prior['source_body_tie_binding']['section']['stations']) material=g['fabrication_measurement']['schedule_count'] row={'id':g['id'],'block':g['rebar_block'],'mark':g['mark'],'lanes_before':before,'lanes_after':n, 'count_before':prior['count'],'count_after':g['count'],'drawing_count':material,'applied':False} rows.append(row) if n==before and g['count']==prior['count']:continue # Counts validate the repair; they never drive the generated positions. if abs(g['count']-material)>=abs(prior['count']-material):row['reason']='quantity did not improve';continue check=g['placement_geometry_check'];row['outside_samples']=check['tube_outside_samples'] if check['tube_outside_samples'] or not g['fabrication_measurement']['fixed_length_pass']: row['reason']='geometry validation failed';continue updated=copy.deepcopy(prior);updated.update(g) # Keep existing display authorization policy, never manufacture approval. updated.pop('engineer_review_confirmation',None) for k in ('source_review_authorization','installation_line_review','placement_status','display_authorized'): if k in prior:updated[k]=copy.deepcopy(prior[k]) replacements[g['id']]=updated;row['applied']=apply audit={'rows':rows,'errors':errors,'full_model_approved':False} if apply and replacements: result=copy.deepcopy(plan);result['rebar_groups']=[replacements.get(g.get('id'),g)for g in result['rebar_groups']] preview=result.get('drawingEvidence',{}).get('preview_geometry') if isinstance(preview,dict):preview['rebar_groups']=copy.deepcopy(result['rebar_groups']) result['bodyTieSectionReplay']=audit assert result['concrete_components']==plan['concrete_components'] job.update(result=result,geometryRevision=time.time_ns()) if path.read_bytes()!=raw:raise ValueError('job changed during source replay') path.with_name(path.stem+'.before-tie-section-'+str(time.time_ns())+'.json').write_bytes(raw) with tempfile.NamedTemporaryFile(mode='w',dir=path.parent,delete=False,encoding='utf8')as out: json.dump(job,out,ensure_ascii=False,allow_nan=False);temporary=out.name os.replace(temporary,path.resolve()) return audit if __name__=='__main__': parser=argparse.ArgumentParser(description=__doc__);parser.add_argument('job');parser.add_argument('--apply',action='store_true') args=parser.parse_args();print(json.dumps(run(args.job,args.apply),ensure_ascii=False,indent=2),flush=True)