AnasSarkiz/NEMA14_RP2040

A NEMA motor assembly concept with a controller board, four proposed M3 screws and spacers, motor lead splices, and a JST 4-pin connector harness.

Version
1.13.0
License
ISC
Stars
0

scripts/audit-manufacturing.py

#!/usr/bin/env python3
"""Independent RS-274X/Excellon audit. No Circuit JSON renderer is used.
Gerbonara 1.5 aperture-rotation and split-line G85 compatibility are explicit.
PyGerber separately renders the original, unmodified Gerbers, including LR.
"""
import argparse,csv,hashlib,importlib.util,json,math,pathlib,re,warnings,zipfile
from collections import Counter,defaultdict
from shapely.geometry import Point,LineString,Polygon,box
from shapely.affinity import rotate
from shapely.ops import unary_union,polygonize
from shapely.strtree import STRtree
from gerbonara import GerberFile,ExcellonFile
from gerbonara.graphic_objects import Flash
from gerbonara.utils import MM
from pygerber.gerberx3.api import v2

def shape(e):
 if e.get('shape')=='polygon':return Polygon([(p['x'],p['y']) for p in e['points']]).buffer(0)
 x,y=e['x'],e['y'];w=e.get('width',e.get('outer_width',e.get('outer_diameter',e.get('radius',0)*2)));h=e.get('height',e.get('outer_height',w))
 if e.get('shape')=='polygon':return Polygon([(p['x'],p['y']) for p in e['points']]).buffer(0)
 if e.get('shape')=='circle' or e['type']=='pcb_via':g=Point(x,y).buffer(w/2,quad_segs=64)
 elif e.get('shape') in ('pill','rotated_pill'):
  dx,dy=((w-h)/2,0) if w>=h else (0,(h-w)/2);g=LineString([(x-dx,y-dy),(x+dx,y+dy)]).buffer(min(w,h)/2,quad_segs=64)
 else:g=box(x-w/2,y-h/2,x+w/2,y+h/2)
 return rotate(g,e.get('ccw_rotation',0),origin=(x,y))
def primitive(p):
 n=type(p).__name__
 if n=='Circle':return Point(p.x,p.y).buffer(p.r,quad_segs=64)
 if n=='Rectangle':return rotate(box(p.x-p.w/2,p.y-p.h/2,p.x+p.w/2,p.y+p.h/2),math.degrees(p.rotation),origin=(p.x,p.y))
 if n=='Line':return LineString([(p.x1,p.y1),(p.x2,p.y2)]).buffer(p.width/2,quad_segs=64)
 if n=='ArcPoly':
  if any(x is not None for x in p.arc_centers):raise ValueError('ArcPoly arc unsupported: explicit failure rather than silent polygon approximation')
  return Polygon(p.outline).buffer(0)
 if n=='Arc':
  r=math.hypot(p.x1-p.cx,p.y1-p.cy);a=math.atan2(p.y1-p.cy,p.x1-p.cx);b=math.atan2(p.y2-p.cy,p.x2-p.cx)
  sweep=((a-b)%(2*math.pi))*(-1) if p.clockwise else (b-a)%(2*math.pi)
  if abs(sweep)<1e-12:sweep=(-1 if p.clockwise else 1)*2*math.pi
  steps=max(8,math.ceil(abs(sweep)*max(r,1)/.001));pts=[(p.cx+r*math.cos(a+sweep*i/steps),p.cy+r*math.sin(a+sweep*i/steps)) for i in range(steps+1)]
  return LineString(pts).buffer(p.width/2,quad_segs=64)
 raise ValueError(f'Unsupported primitive {n}')
def gerber(path):
 raw=path.read_text();rot=0.;angles=[]
 for token in re.findall(r'%[^%]*%|[^*%]+\*',raw):
  m=re.search(r'%LR([+-]?[\d.]+)\*%',token)
  if m:rot=float(m[1]);continue
  if re.search(r'D0?3\*$',token.strip()):angles.append(rot)
 with warnings.catch_warnings(record=True) as ws:
  warnings.simplefilter('always');g=GerberFile.open(path)
 unknown=[str(w.message) for w in ws if not re.search(r'Unknown statement found: \"LR[+\-\d.]+\"',str(w.message))]
 if unknown:raise ValueError(f'{path.name} parser warnings: {unknown}')
 flashes=[o for o in g.objects if isinstance(o,Flash)]
 if len(flashes)!=len(angles):raise ValueError(f'Flash correspondence failure {path.name}: {len(flashes)} / {len(angles)}')
 for o,a in zip(flashes,angles):
  if a%360 not in (0,90,180,270):raise ValueError(f'Rotation {a} requires independently validated analytic support')
  if a%360:o.aperture=o.aperture.rotated(math.radians(a))
 result=Polygon();batch=[];last=True
 for o in g.objects:
  for p in o.to_primitives(unit=MM):
   dark=p.polarity_dark
   if dark!=last and batch:
    u=unary_union(batch);result=result.union(u) if last else result.difference(u);batch=[]
   batch.append(primitive(p));last=dark
 if batch:
  u=unary_union(batch);result=result.union(u) if last else result.difference(u)
 return result,len(g.objects),{'LR_applied':sum(bool(a%360) for a in angles),'warnings':unknown}
def drill(path):
 raw=path.read_text();lines=raw.splitlines();out=[];joined=0
 for l in lines:
  if l.startswith('G85'):
   if not out or not re.fullmatch(r'X[-+\d.]+Y[-+\d.]+',out[-1]):raise ValueError('Ambiguous G85 start')
   start=out.pop();out.extend(['G00'+start,'M15','G01'+l[3:],'M16','G05']);joined+=1;continue
  out.append(l)
 with warnings.catch_warnings(record=True) as ws:
  warnings.simplefilter('always');d=ExcellonFile.from_string('\n'.join(out)+'\n')
 unhandled=[str(w.message) for w in ws if 'G90 header statement found after end of header' not in str(w.message)]
 if unhandled:raise ValueError(f'{path.name} drill warnings: {unhandled}')
 gs=[primitive(p) for o in d.objects for p in o.to_primitives(unit=MM)]
 return unary_union(gs),gs,{'objects':len(d.objects),'G85_joined':joined,'parser_notices':[str(w.message) for w in ws],'tools_mm':dict(Counter(round(o.tool.diameter,6) for o in d.objects))}
def expected(j):
 layers=defaultdict(list)
 for e in j:
  typ=e['type']
  if typ in ('pcb_smtpad','pcb_plated_hole','pcb_via'):
   for l in e.get('layers',[e.get('layer','top')]):layers[l].append(shape(e))
  elif typ=='pcb_trace':
   for a,b in zip(e['route'],e['route'][1:]):
    if a['route_type']==b['route_type']=='wire' and a['layer']==b['layer']:layers[a['layer']].append(LineString([(a['x'],a['y']),(b['x'],b['y'])]).buffer(max(a['width'],b['width'])/2,quad_segs=64))
  elif typ=='pcb_copper_pour':
   q=e['brep_shape'];coords=lambda r:[(p['x'],p['y']) for p in r['vertices']];layers[e['layer']].append(Polygon(coords(q['outer_ring']),[coords(r) for r in q.get('inner_rings',[])]).buffer(0))
 return {k:unary_union(v) for k,v in layers.items()}
def main():
 ap=argparse.ArgumentParser();ap.add_argument('--directory',default='artifacts/manufacturing');ap.add_argument('--source',default='artifacts/board.circuit.json');ap.add_argument('--archive',help='Actual archive to compare byte-for-byte against parsed extracted files');ap.add_argument('--baseline',action='store_true');ap.add_argument('--render',action='store_true');args=ap.parse_args();root=pathlib.Path(__file__).resolve().parents[1];directory=root/args.directory;source_bytes=(root/args.source).read_bytes();j=json.loads(source_bytes);report={'source_sha256':hashlib.sha256(source_bytes).hexdigest(),'directory':args.directory,'parser_versions':{'gerbonara':'1.5.0','pygerber':'2.4.3','shapely':__import__('shapely').__version__},'parser_compatibility':'Only LR right-angle aperture transforms and unambiguous split-line G85 slots are converted to equivalent G00/M15/G01/M16/G05 routing analytically. Original Gerbers independently rendered by PyGerber. Input CAM bytes remain unchanged.','files':{},'issues':[]}
 archive=root/args.archive if args.archive else (root/'artifacts/nema14-gerbers.zip' if args.directory=='artifacts/manufacturing' else directory/'original-export.zip')
 if not archive.exists():raise ValueError(f'Actual archive missing: {archive}')
 archive_records={}
 with zipfile.ZipFile(archive) as z:
  seen=set()
  for member in z.namelist():
   if member.endswith('/'):continue
   name=pathlib.Path(member).name
   if name in seen:raise ValueError(f'Duplicate archive member {name}')
   seen.add(name);data=z.read(member);path=directory/name
   if not path.exists() or path.read_bytes()!=data:raise ValueError(f'Actual archive/extracted byte mismatch: {name}')
   archive_records[name]=hashlib.sha256(data).hexdigest()
 loose_cam={p.name for p in directory.iterdir() if p.suffix in ['.gbr','.drl','.csv']}
 if loose_cam-set(archive_records):raise ValueError(f'Parsed CAM files absent from actual archive: {sorted(loose_cam-set(archive_records))}')
 report['archive']={'path':str(archive),'sha256':hashlib.sha256(archive.read_bytes()).hexdigest(),'extracted_bytes_verified':True,'members':archive_records}
 geo={}
 for p in sorted(directory.glob('*.gbr')):
  geometry,count,compat=gerber(p);geo[p.stem]=geometry;report['files'][p.name]={'sha256':hashlib.sha256(p.read_bytes()).hexdigest(),'objects':count,'area_mm2':geometry.area,'bounds_mm':list(geometry.bounds) if not geometry.is_empty else [],**compat}
  if args.render and p.stem.endswith('_Cu'):
   out=directory/'independent-render';out.mkdir(exist_ok=True);v2.GerberFile.from_file(p).parse(on_parser_error=v2.OnParserErrorEnum.Raise).render_raster(out/(p.stem+'.png'),dpmm=80,color_scheme=v2.ColorScheme.SILK)
 drills=[];all_drill=[]
 for p in sorted(directory.glob('*.drl')):
  g,parts,stats=drill(p);report['files'][p.name]={'sha256':hashlib.sha256(p.read_bytes()).hexdigest(),**stats};all_drill.extend(parts)
  if 'npth' not in p.name:drills.extend(parts)
 holes=unary_union(all_drill);expected_layers=expected(j);layer_names={'top':'F_Cu','bottom':'B_Cu','inner1':'In1_Cu','inner2':'In2_Cu'};actual={};delta={}
 for layer,name in layer_names.items():
  if name not in geo:continue
  a=geo[name].difference(holes);b=expected_layers.get(layer,Polygon()).difference(holes);actual[layer]=a
  missing=b.difference(a.buffer(.0002));extra=a.difference(b.buffer(.0002));delta[layer]={'missing_mm2':missing.area,'extra_mm2':extra.area,'tolerance_mm':.0002}
  if missing.area>1e-4 or extra.area>1e-4:report['issues'].append({'kind':'copper-source-mismatch','layer':layer,**delta[layer]})
 report['copper_comparison']=delta
 # Each connected polygon in the actual copper is an electrical island. Bridge
 # its layers only at drilled plated barrels. Assign names from native pads.
 nodes=[];trees={};indices={}
 for l,g in actual.items():
  ps=list(g.geoms) if hasattr(g,'geoms') else [g];ps=[p for p in ps if p.area>1e-9];indices[l]=list(range(len(nodes),len(nodes)+len(ps)));nodes.extend(ps);trees[l]=STRtree(ps)
 parent=list(range(len(nodes)))
 def find(i):
  while parent[i]!=i:parent[i]=parent[parent[i]];i=parent[i]
  return i
 def union(ids):
  if ids:
   r=find(ids[0])
   for i in ids[1:]:parent[find(i)]=r
 def hits(l,g):return [indices[l][int(i)] for i in trees[l].query(g,predicate='intersects') if nodes[indices[l][int(i)]].intersection(g).area>1e-8]
 for d in drills:
  ann=d.buffer(.03).difference(d.buffer(-.0001));union([i for l in actual for i in hits(l,ann)])
 src={e['source_component_id']:e for e in j if e['type']=='source_component'};pc={e['pcb_component_id']:e for e in j if e['type']=='pcb_component'};sp={e['source_port_id']:e for e in j if e['type']=='source_port'};pp={e['pcb_port_id']:e for e in j if e['type']=='pcb_port'};netnames={e['subcircuit_connectivity_map_key']:e['name'] for e in j if e['type']=='source_net'};assign=defaultdict(lambda:defaultdict(list));netroots=defaultdict(lambda:defaultdict(list));unconnected=[]
 for e in j:
  if e['type'] not in ('pcb_smtpad','pcb_plated_hole') or not e.get('pcb_port_id'):continue
  port=pp[e['pcb_port_id']];s=sp[port['source_port_id']];key=s.get('subcircuit_connectivity_map_key')
  if not key:continue
  ref=src[pc[e['pcb_component_id']]['source_component_id']]['name']+'.'+s['name'];ids=[i for l in e.get('layers',[e.get('layer','top')]) if l in actual for i in hits(l,shape(e).difference(holes))]
  if not ids:unconnected.append(ref)
  for r in {find(i) for i in ids}:assign[r][key].append(ref);netroots[key][r].append(ref)
 shorts=[{'nets':[netnames.get(k,k) for k in v],'pads':dict(v)} for v in assign.values() if len(v)>1];opens=[{'net':netnames.get(k,k),'islands':list(v.values())} for k,v in netroots.items() if len(v)>1];report['connectivity']={'named_nets_checked':len(netroots),'shorts':shorts,'opens':opens,'unconnected_pads':unconnected,'actual_copper_islands':len(nodes),'unassigned_islands':len({find(i) for i in range(len(nodes))}-set(assign))}
 nc_contacts=[]
 for e in j:
  if e['type']!='pcb_smtpad' or not e.get('pcb_port_id'):continue
  port=pp[e['pcb_port_id']];s=sp[port['source_port_id']]
  if s.get('subcircuit_connectivity_map_key'):continue
  for r in {find(i) for i in hits(e['layer'],shape(e))}:
   if r in assign:nc_contacts.append({'pad':src[pc[e['pcb_component_id']]['source_component_id']]['name']+'.'+s['name'],'nets':[netnames.get(k,k) for k in assign[r]]})
 report['connectivity']['no_connect_contacts']=nc_contacts
 if nc_contacts:report['issues'].append({'kind':'no-connect-pad-contact','contacts':nc_contacts})
 # Classify copper islands without named connected pads; expected NC pads
 # must not be mislabeled as floating routed copper.
 isolated=[]
 for r in {find(i) for i in range(len(nodes))}-set(assign):
  geometry=unary_union([nodes[i] for i in range(len(nodes)) if find(i)==r]);nc=[]
  for e in j:
   if e['type']!='pcb_smtpad' or not e.get('pcb_port_id'):continue
   port=pp[e['pcb_port_id']];s=sp[port['source_port_id']]
   if s.get('subcircuit_connectivity_map_key'):continue
   if e['layer'] in actual and r in {find(i) for i in hits(e['layer'],shape(e))}:nc.append(src[pc[e['pcb_component_id']]['source_component_id']]['name']+'.'+s['name'])
  isolated.append({'area_mm2':geometry.area,'bounds_mm':list(geometry.bounds) if not geometry.is_empty else [],'layers':[l for l in indices if any(find(i)==r for i in indices[l])],'no_connect_pads':nc,'classification':'intentional native no-connect pad' if nc else 'unassigned copper: review'})
 report['connectivity']['unassigned_island_details']=isolated
 # Spacing is measured on the independently parsed, finished copper, not on
 # centerlines or bounding rectangles. Same physical barrel-connected nets
 # are exempt; native NC islands remain separate conductors for this screen.
 copper_spacing={}
 for layer,ids in indices.items():
  near=[]
  for local,i in enumerate(ids):
   for other in trees[layer].query(nodes[i].buffer(.5)):
    other=int(other)
    if other<=local:continue
    k=ids[other];ri,rk=find(i),find(k)
    if ri==rk:continue
    ai=set(assign.get(ri,{}));ak=set(assign.get(rk,{}))
    if ai and ai==ak:continue
    distance=nodes[i].distance(nodes[k])
    near.append({'clearance_mm':distance,'conductors':[[netnames.get(n,n) for n in assign.get(r,{})] or ['native NC/unassigned island'] for r in (ri,rk)],'island_indices':[i,k]})
  near.sort(key=lambda e:e['clearance_mm'])
  copper_spacing[layer]={'minimum_distinct_conductor_clearance_mm':near[0]['clearance_mm'] if near else None,'closest_pairs':near[:5],'screen_minimum_mm':.15,'geometry_tolerance_mm':.0002,'scope':'actual finished copper edges; pairs within 0.50 mm; same electrical net excluded'}
  failures=[p for p in near if p['clearance_mm']<.1498]
  if failures:report['issues'].append({'kind':'actual-copper-clearance','layer':layer,'pairs':failures})
 report['actual_copper_spacing']=copper_spacing
 unresolved=[i for i in isolated if not i['no_connect_pads'] and i['area_mm2']>1e-5]
 if unresolved:report['issues'].append({'kind':'unassigned-copper-islands','islands':unresolved})
 if shorts or opens or unconnected:report['issues'].append({'kind':'physical-netlist-failure','short_count':len(shorts),'open_count':len(opens),'unconnected_pads':unconnected})
 bare={s['name'] for s in src.values() if s['ftype']=='simple_test_point'} | {src[p['source_component_id']]['name'] for p in pc.values() if p.get('do_not_place')};bare_pc={p['pcb_component_id'] for p in pc.values() if src[p['source_component_id']]['name'] in bare};bare_pads=unary_union([shape(e) for e in j if e['type']=='pcb_smtpad' and e['pcb_component_id'] in bare_pc]);paste={};pth=unary_union([shape(e) for e in j if e['type']=='pcb_plated_hole'])
 for l in ['F_Paste','B_Paste']:
  bare_pads=unary_union([shape(e) for e in j if e['type']=='pcb_smtpad' and e['pcb_component_id'] in bare_pc and e['layer']==('top' if l=='F_Paste' else 'bottom')])
  g=geo.get(l,Polygon());paste[l]={'bare_interface_overlap_mm2':g.intersection(bare_pads).area,'manual_plated_joint_overlap_mm2':g.intersection(pth).area,'outside_smt_copper_mm2':g.difference(unary_union([shape(e) for e in j if e['type']=='pcb_smtpad' and e['layer']==('top' if l=='F_Paste' else 'bottom')]).buffer(.0002)).area}
  if g.intersection(bare_pads).area>1e-6 or g.intersection(pth).area>1e-6 or paste[l]['outside_smt_copper_mm2']>1e-6:report['issues'].append({'kind':'assembly-paste-policy','layer':l,**paste[l]})
 report['paste']=paste;table={}
 for filename in ['bom.csv','pick_and_place.csv']:
  rows=list(csv.DictReader((directory/filename).open()));refs={r['Designator'] for r in rows};fit={s['name'] for s in src.values() if s['name'] not in bare};table[filename]={'rows':len(rows),'bare_rows':sorted(refs&bare),'missing_fitted':sorted(fit-refs),'unexpected':sorted(refs-fit-bare)}
  duplicates=sorted(ref for ref,count in Counter(r['Designator'] for r in rows).items() if count>1)
  table[filename]['duplicate_refs']=duplicates
  if refs&bare or fit-refs or refs-fit-bare or duplicates:report['issues'].append({'kind':'assembly-table-policy','table':filename,**table[filename]})
  if filename=='bom.csv':
   errors=[]
   byref={e['name']:e for e in src.values()}
   for row in rows:
    component=byref.get(row['Designator'])
    if component is None or row['Designator'] in bare:continue
    mismatch={}
    if row.get('JLCPCB Part #') not in component.get('supplier_part_numbers',{}).get('jlcpcb',[]):mismatch['supplier_part_number']={'export':row.get('JLCPCB Part #'),'source':component.get('supplier_part_numbers',{}).get('jlcpcb',[])}
    if not args.baseline:
     mpn=component.get('manufacturer_part_number');value=component.get('display_resistance',component.get('display_capacitance',mpn))
     for field,expected_value in [('Manufacturer Part Number',mpn),('Comment',mpn),('Value',value)]:
      if not expected_value or row.get(field)!=expected_value:mismatch[field]={'export':row.get(field),'source':expected_value}
    if mismatch:errors.append({'ref':row['Designator'],'errors':mismatch})
   table[filename]['source_identity_errors']=errors
   if errors:report['issues'].append({'kind':'BOM-source-identity','errors':errors})
 report['assembly_tables']=table
 placement_errors=[]
 for row in csv.DictReader((directory/'pick_and_place.csv').open()):
  component=next((e for e in pc.values() if src[e['source_component_id']]['name']==row['Designator']),None)
  if component is None:continue
  errs={}
  for field,val in [('Mid X',component['center']['x']),('Mid Y',component['center']['y']),('Rotation',component.get('rotation',0))]:
   if abs(float(row[field])-val)>.00051:errs[field]={'export':float(row[field]),'source':val}
  if row['Layer'].lower()!=component['layer'].lower():errs['layer']=row['Layer']
  if errs:placement_errors.append({'ref':row['Designator'],'errors':errs})
 report['cpl_coordinate_comparison']={'errors':placement_errors,'origin':'board center; mm; unmirrored top coordinates','rotation':'native imported land-pattern orientation plus saved pcb_component rotation; supplier interpretation still needs placement-preview approval','status':'SOURCE CONVENTION CHECK ONLY; supplier pickup datum and rotation remain USER_REVIEW','USB_centers':[{'reference':src[e['source_component_id']]['name'],'CPL_land_pattern_center_mm':e['center'],'rotation_deg':e.get('rotation',0)} for e in pc.values() if src[e['source_component_id']]['name'] in {'J_PD','J_DATA'}],'USB_center_note':'Upright GCT USB4145 uses native land-pattern CPL datum; local CAD anchor correction X +0.1524952 mm aligns the native STEP centre. Manufacturer pickup datum and JLCPCB placement preview remain unverified.'}
 if placement_errors:report['issues'].append({'kind':'CPL-coordinate-mismatch','errors':placement_errors})
 native_holes=[]
 for e in j:
  if e['type'] not in ('pcb_plated_hole','pcb_via','pcb_hole'):continue
  q=dict(e)
  if e['type']=='pcb_hole':q.update(shape=e.get('hole_shape','circle'),width=e.get('hole_diameter',e.get('hole_width')),height=e.get('hole_diameter',e.get('hole_height')))
  elif e['type']=='pcb_via':q.update(shape='circle',width=e['hole_diameter'],height=e['hole_diameter'])
  else:q.update(width=e.get('hole_width',e.get('hole_diameter')),height=e.get('hole_height',e.get('hole_diameter')))
  native_holes.append(shape(q))
 native_drill=unary_union(native_holes);drill_missing=native_drill.difference(holes.buffer(.00055)).area;drill_extra=holes.difference(native_drill.buffer(.00055)).area
 report['drill_source_comparison']={'missing_mm2':drill_missing,'extra_mm2':drill_extra,'tolerance_mm':.00055,'tolerance_reason':'Exporter slot endpoints and CPL rounded to 3 decimal places; 0.55 micrometer envelope','nominal_mounting_holes':4,'nominal_USB_plated_slots':8}
 if drill_missing>1e-4 or drill_extra>1e-4:report['issues'].append({'kind':'drill-source-mismatch',**report['drill_source_comparison']})
 mask_errors=[]
 for e in j:
  if e['type'] not in ('pcb_smtpad','pcb_plated_hole') or e.get('is_covered_with_solder_mask'):continue
  for l in e.get('layers',[e.get('layer','top')]):
   name={'top':'F_Mask','bottom':'B_Mask'}.get(l)
   if not name:continue
   missing=shape(e).difference(geo[name].buffer(.0002)).area
   if missing>1e-4:mask_errors.append({'id':e.get('pcb_smtpad_id',e.get('pcb_plated_hole_id')),'layer':l,'missing_opening_mm2':missing})
 report['mask_opening_comparison']={'errors':mask_errors,'policy':'uncovered fitted/bare solder pads and plated slots remain open; filled/capped thermal via process required'}
 if mask_errors:report['issues'].append({'kind':'mask-opening-mismatch','errors':mask_errors})
 stencil=[]
 for e in j:
  if e['type']!='pcb_smtpad' or e.get('shape')!='rect' or e.get('width',0)<=2 or e.get('height',0)<=2:continue
  ref=src[pc[e['pcb_component_id']]['source_component_id']]['name']
  if ref in {'U_PD','U_MCU','U_DRV'}:stencil.append({'ref':ref,'pad':e['pcb_smtpad_id'],'coverage_fraction':geo.get('F_Paste',Polygon()).intersection(shape(e)).area/shape(e).area})
 aperture_screen=[]
 for paste_layer in ['F_Paste','B_Paste']:
  geometry=geo.get(paste_layer,Polygon())
  aperture_polygons=list(geometry.geoms) if hasattr(geometry,'geoms') else [geometry]
  for polygon in aperture_polygons:
   if polygon.is_empty:continue
   x1,y1,x2,y2=polygon.bounds;aspect=min(x2-x1,y2-y1)/.1;ratio=polygon.area/(polygon.length*.1)
   aperture_screen.append({'layer':paste_layer,'bounds_mm':list(polygon.bounds),'area_mm2':polygon.area,'perimeter_mm':polygon.length,'aspect_ratio_at_100um':aspect,'area_ratio_at_100um':ratio})
 poor=[e for e in aperture_screen if e['aspect_ratio_at_100um']<1.5-1e-4 or e['area_ratio_at_100um']<.66-1e-4]
 report['stencil_release_screen']={'candidate_thickness_mm':.10,'minimum_aspect_ratio':min((e['aspect_ratio_at_100um'] for e in aperture_screen),default=None),'minimum_area_ratio':min((e['area_ratio_at_100um'] for e in aperture_screen),default=None),'screen_limits':{'aspect_ratio':1.5,'area_ratio':.66},'failing_apertures':poor,'scope':'common geometric release screens only; physical paste/stencil/reflow process acceptance still pending'}
 if poor:report['issues'].append({'kind':'stencil-release-screen','apertures':poor})
 report['exposed_pad_stencil']=stencil
 outline=GerberFile.open(directory/'Edge_Cuts.gbr');segments=[]
 for o in outline.objects:
  for primitive_edge in o.to_primitives(unit=MM):
   if type(primitive_edge).__name__!='Line':raise ValueError('Unexpected outline primitive')
   segments.append(LineString([(primitive_edge.x1,primitive_edge.y1),(primitive_edge.x2,primitive_edge.y2)]))
 outlines=list(polygonize(segments));valid_outline=len(outlines)==1 and abs(outlines[0].area-1225)<1e-6 and outlines[0].bounds==(-17.5,-17.5,17.5,17.5)
 report['board_outline']={'bounds_including_stroke':list(geo['Edge_Cuts'].bounds),'centerline_bounds_mm':list(outlines[0].bounds) if outlines else None,'closed_contour_count':len(outlines),'centerline_length_mm':sum(s.length for s in segments),'centerline_area_mm2':outlines[0].area if outlines else None,'valid_35mm_square':valid_outline}
 if not valid_outline:report['issues'].append({'kind':'outline-failure'})
 measured_webs={}
 for name in ['F_Mask','B_Mask']:
  polygons=list(geo[name].geoms) if hasattr(geo[name],'geoms') else [geo[name]];tree=STRtree(polygons);near=[]
  for i,g in enumerate(polygons):
   for other in tree.query(g.buffer(.25)):
    other=int(other)
    if other>i:near.append(g.distance(polygons[other]))
  minimum=min(near) if near else None;measured_webs[name]={'minimum_web_mm':minimum,'opening_polygons':len(polygons),'scope':'nearest distinct mask openings within 0.25 mm'}
  if not args.baseline and minimum is not None and minimum<.09999:report['issues'].append({'kind':'solder-mask-web','layer':name,'minimum_mm':minimum})
 report['mask_webs']=measured_webs
 report['mask']={n:{'area_mm2':geo[n].area,'bounds_mm':list(geo[n].bounds) if not geo[n].is_empty else []} for n in ['F_Mask','B_Mask'] if n in geo};report['plated_annulus_source_min_mm']=min((min(e.get('outer_width',e.get('outer_diameter',0))-e.get('hole_width',e.get('hole_diameter',0)),e.get('outer_height',e.get('outer_diameter',0))-e.get('hole_height',e.get('hole_diameter',0)))/2 for e in j if e['type'] in ('pcb_plated_hole','pcb_via')),default=None)
 clearances={}
 for l,g in actual.items():
  # Mounting-hole clearance is measured to the physical drill boundary.
  mounts=unary_union([Point(e['x'],e['y']).buffer(e['hole_diameter']/2,quad_segs=64) for e in j if e['type']=='pcb_hole' and e.get('hole_diameter')==3.2])
  clearances[l]={'mount_hole_edge_clearance_mm':g.distance(mounts),'board_edge_clearance_mm':g.distance(box(-18,-18,18,18).difference(box(-17.5,-17.5,17.5,17.5)))}
 report['copper_clearances']=clearances
 keepout_checks=[]
 for e in j:
  if e['type']!='pcb_keepout':continue
  if e.get('shape') not in ('circle','rect'):raise ValueError(f"Unsupported keepout shape: {e.get('shape')}")
  region=shape({**e,'x':e['center']['x'],'y':e['center']['y']})
  for layer in e['layers']:
   if layer not in actual:raise ValueError(f"Declared keepout layer missing from actual CAM: {layer}")
   intrusion=actual[layer].intersection(region).area
   tolerated=actual[layer].intersection(region.buffer(-.0002)).area
   check={'keepout_id':e['pcb_keepout_id'],'shape':e['shape'],'center_mm':e['center'],'layer':layer,'clearance_mm':actual[layer].distance(region),'intrusion_area_mm2':intrusion,'intrusion_beyond_0_0002mm_tolerance_mm2':tolerated}
   keepout_checks.append(check)
   if tolerated>1e-5:report['issues'].append({'kind':'actual-copper-keepout-intrusion',**check})
 report['actual_keepout_checks']=keepout_checks
 silk={}
 for n,m in [('F_SilkScreen','F_Mask'),('B_SilkScreen','B_Mask')]:
  silk[n]={'overlap_mask_openings_mm2':geo[n].intersection(geo[m]).area,'inside_0_15mm_mask_guard_mm2':geo[n].intersection(geo[m].buffer(.1499)).area,'outside_board_0_10mm_inset_mm2':geo[n].difference(box(-17.4,-17.4,17.4,17.4)).area}
  if not args.baseline and (silk[n]['inside_0_15mm_mask_guard_mm2']>1e-5 or silk[n]['outside_board_0_10mm_inset_mm2']>1e-5):report['issues'].append({'kind':'silkscreen-clearance','layer':n,**silk[n]})
 report['silkscreen_clearances']=silk
 if not args.baseline:
  for pane in stencil:
   if abs(pane['coverage_fraction']-.60)>.001:report['issues'].append({'kind':'EP-stencil-coverage',**pane})
  unowned=[e['pcb_solder_paste_id'] for e in j if e['type']=='pcb_solder_paste' and e.get('pcb_component_id') not in pc]
  if unowned:report['issues'].append({'kind':'unowned-source-paste','paste_ids':unowned,'reason':'No component ownership is present in saved source; apertures remain included in full CAM comparison.'})
  comparisons={}
  for source_layer,cam_layer in [('top','F_Paste'),('bottom','B_Paste')]:
   explicit_paste=unary_union([shape(e) for e in j if e['type']=='pcb_solder_paste' and e['layer']==source_layer and (e.get('pcb_component_id') not in pc or src[pc[e['pcb_component_id']]['source_component_id']]['name'] not in bare)])
   actual_paste=geo.get(cam_layer,Polygon())
   comparisons[cam_layer]={'missing_mm2':explicit_paste.difference(actual_paste.buffer(.0002)).area,'extra_mm2':actual_paste.difference(explicit_paste.buffer(.0002)).area}
   if any(v>1e-4 for v in comparisons[cam_layer].values()):report['issues'].append({'kind':'paste-source-mismatch','layer':cam_layer,**comparisons[cam_layer]})
  report['paste_source_comparison']=comparisons
 if (root/args.source).read_bytes()!=source_bytes:raise ValueError('Frozen source changed during independent CAM audit; regenerate and repeat')
 report['status']='FAIL' if report['issues'] else 'PASS';out=directory/'audit.json';out.write_text(json.dumps(report,indent=2,allow_nan=False)+'\n');print(json.dumps({'status':report['status'],'issues':report['issues'],'connectivity':{k:report['connectivity'][k] for k in ['named_nets_checked','actual_copper_islands','unassigned_islands']},'report':str(out)},indent=2));return 0 if args.baseline else bool(report['issues'])
if __name__=='__main__':raise SystemExit(main())
,token.strip()):angles.append(rot)\n with warnings.catch_warnings(record=True) as ws:\n warnings.simplefilter('always');g=GerberFile.open(path)\n unknown=[str(w.message) for w in ws if not re.search(r'Unknown statement found: \\\"LR[+\\-\\d.]+\\\"',str(w.message))]\n if unknown:raise ValueError(f'{path.name} parser warnings: {unknown}')\n flashes=[o for o in g.objects if isinstance(o,Flash)]\n if len(flashes)!=len(angles):raise ValueError(f'Flash correspondence failure {path.name}: {len(flashes)} / {len(angles)}')\n for o,a in zip(flashes,angles):\n if a%360 not in (0,90,180,270):raise ValueError(f'Rotation {a} requires independently validated analytic support')\n if a%360:o.aperture=o.aperture.rotated(math.radians(a))\n result=Polygon();batch=[];last=True\n for o in g.objects:\n for p in o.to_primitives(unit=MM):\n dark=p.polarity_dark\n if dark!=last and batch:\n u=unary_union(batch);result=result.union(u) if last else result.difference(u);batch=[]\n batch.append(primitive(p));last=dark\n if batch:\n u=unary_union(batch);result=result.union(u) if last else result.difference(u)\n return result,len(g.objects),{'LR_applied':sum(bool(a%360) for a in angles),'warnings':unknown}\ndef drill(path):\n raw=path.read_text();lines=raw.splitlines();out=[];joined=0\n for l in lines:\n if l.startswith('G85'):\n if not out or not re.fullmatch(r'X[-+\\d.]+Y[-+\\d.]+',out[-1]):raise ValueError('Ambiguous G85 start')\n start=out.pop();out.extend(['G00'+start,'M15','G01'+l[3:],'M16','G05']);joined+=1;continue\n out.append(l)\n with warnings.catch_warnings(record=True) as ws:\n warnings.simplefilter('always');d=ExcellonFile.from_string('\\n'.join(out)+'\\n')\n unhandled=[str(w.message) for w in ws if 'G90 header statement found after end of header' not in str(w.message)]\n if unhandled:raise ValueError(f'{path.name} drill warnings: {unhandled}')\n gs=[primitive(p) for o in d.objects for p in o.to_primitives(unit=MM)]\n return unary_union(gs),gs,{'objects':len(d.objects),'G85_joined':joined,'parser_notices':[str(w.message) for w in ws],'tools_mm':dict(Counter(round(o.tool.diameter,6) for o in d.objects))}\ndef expected(j):\n layers=defaultdict(list)\n for e in j:\n typ=e['type']\n if typ in ('pcb_smtpad','pcb_plated_hole','pcb_via'):\n for l in e.get('layers',[e.get('layer','top')]):layers[l].append(shape(e))\n elif typ=='pcb_trace':\n for a,b in zip(e['route'],e['route'][1:]):\n if a['route_type']==b['route_type']=='wire' and a['layer']==b['layer']:layers[a['layer']].append(LineString([(a['x'],a['y']),(b['x'],b['y'])]).buffer(max(a['width'],b['width'])/2,quad_segs=64))\n elif typ=='pcb_copper_pour':\n q=e['brep_shape'];coords=lambda r:[(p['x'],p['y']) for p in r['vertices']];layers[e['layer']].append(Polygon(coords(q['outer_ring']),[coords(r) for r in q.get('inner_rings',[])]).buffer(0))\n return {k:unary_union(v) for k,v in layers.items()}\ndef main():\n ap=argparse.ArgumentParser();ap.add_argument('--directory',default='artifacts/manufacturing');ap.add_argument('--source',default='artifacts/board.circuit.json');ap.add_argument('--archive',help='Actual archive to compare byte-for-byte against parsed extracted files');ap.add_argument('--baseline',action='store_true');ap.add_argument('--render',action='store_true');args=ap.parse_args();root=pathlib.Path(__file__).resolve().parents[1];directory=root/args.directory;source_bytes=(root/args.source).read_bytes();j=json.loads(source_bytes);report={'source_sha256':hashlib.sha256(source_bytes).hexdigest(),'directory':args.directory,'parser_versions':{'gerbonara':'1.5.0','pygerber':'2.4.3','shapely':__import__('shapely').__version__},'parser_compatibility':'Only LR right-angle aperture transforms and unambiguous split-line G85 slots are converted to equivalent G00/M15/G01/M16/G05 routing analytically. Original Gerbers independently rendered by PyGerber. Input CAM bytes remain unchanged.','files':{},'issues':[]}\n archive=root/args.archive if args.archive else (root/'artifacts/nema14-gerbers.zip' if args.directory=='artifacts/manufacturing' else directory/'original-export.zip')\n if not archive.exists():raise ValueError(f'Actual archive missing: {archive}')\n archive_records={}\n with zipfile.ZipFile(archive) as z:\n seen=set()\n for member in z.namelist():\n if member.endswith('/'):continue\n name=pathlib.Path(member).name\n if name in seen:raise ValueError(f'Duplicate archive member {name}')\n seen.add(name);data=z.read(member);path=directory/name\n if not path.exists() or path.read_bytes()!=data:raise ValueError(f'Actual archive/extracted byte mismatch: {name}')\n archive_records[name]=hashlib.sha256(data).hexdigest()\n loose_cam={p.name for p in directory.iterdir() if p.suffix in ['.gbr','.drl','.csv']}\n if loose_cam-set(archive_records):raise ValueError(f'Parsed CAM files absent from actual archive: {sorted(loose_cam-set(archive_records))}')\n report['archive']={'path':str(archive),'sha256':hashlib.sha256(archive.read_bytes()).hexdigest(),'extracted_bytes_verified':True,'members':archive_records}\n geo={}\n for p in sorted(directory.glob('*.gbr')):\n geometry,count,compat=gerber(p);geo[p.stem]=geometry;report['files'][p.name]={'sha256':hashlib.sha256(p.read_bytes()).hexdigest(),'objects':count,'area_mm2':geometry.area,'bounds_mm':list(geometry.bounds) if not geometry.is_empty else [],**compat}\n if args.render and p.stem.endswith('_Cu'):\n out=directory/'independent-render';out.mkdir(exist_ok=True);v2.GerberFile.from_file(p).parse(on_parser_error=v2.OnParserErrorEnum.Raise).render_raster(out/(p.stem+'.png'),dpmm=80,color_scheme=v2.ColorScheme.SILK)\n drills=[];all_drill=[]\n for p in sorted(directory.glob('*.drl')):\n g,parts,stats=drill(p);report['files'][p.name]={'sha256':hashlib.sha256(p.read_bytes()).hexdigest(),**stats};all_drill.extend(parts)\n if 'npth' not in p.name:drills.extend(parts)\n holes=unary_union(all_drill);expected_layers=expected(j);layer_names={'top':'F_Cu','bottom':'B_Cu','inner1':'In1_Cu','inner2':'In2_Cu'};actual={};delta={}\n for layer,name in layer_names.items():\n if name not in geo:continue\n a=geo[name].difference(holes);b=expected_layers.get(layer,Polygon()).difference(holes);actual[layer]=a\n missing=b.difference(a.buffer(.0002));extra=a.difference(b.buffer(.0002));delta[layer]={'missing_mm2':missing.area,'extra_mm2':extra.area,'tolerance_mm':.0002}\n if missing.area\u003e1e-4 or extra.area\u003e1e-4:report['issues'].append({'kind':'copper-source-mismatch','layer':layer,**delta[layer]})\n report['copper_comparison']=delta\n # Each connected polygon in the actual copper is an electrical island. Bridge\n # its layers only at drilled plated barrels. Assign names from native pads.\n nodes=[];trees={};indices={}\n for l,g in actual.items():\n ps=list(g.geoms) if hasattr(g,'geoms') else [g];ps=[p for p in ps if p.area\u003e1e-9];indices[l]=list(range(len(nodes),len(nodes)+len(ps)));nodes.extend(ps);trees[l]=STRtree(ps)\n parent=list(range(len(nodes)))\n def find(i):\n while parent[i]!=i:parent[i]=parent[parent[i]];i=parent[i]\n return i\n def union(ids):\n if ids:\n r=find(ids[0])\n for i in ids[1:]:parent[find(i)]=r\n def hits(l,g):return [indices[l][int(i)] for i in trees[l].query(g,predicate='intersects') if nodes[indices[l][int(i)]].intersection(g).area\u003e1e-8]\n for d in drills:\n ann=d.buffer(.03).difference(d.buffer(-.0001));union([i for l in actual for i in hits(l,ann)])\n src={e['source_component_id']:e for e in j if e['type']=='source_component'};pc={e['pcb_component_id']:e for e in j if e['type']=='pcb_component'};sp={e['source_port_id']:e for e in j if e['type']=='source_port'};pp={e['pcb_port_id']:e for e in j if e['type']=='pcb_port'};netnames={e['subcircuit_connectivity_map_key']:e['name'] for e in j if e['type']=='source_net'};assign=defaultdict(lambda:defaultdict(list));netroots=defaultdict(lambda:defaultdict(list));unconnected=[]\n for e in j:\n if e['type'] not in ('pcb_smtpad','pcb_plated_hole') or not e.get('pcb_port_id'):continue\n port=pp[e['pcb_port_id']];s=sp[port['source_port_id']];key=s.get('subcircuit_connectivity_map_key')\n if not key:continue\n ref=src[pc[e['pcb_component_id']]['source_component_id']]['name']+'.'+s['name'];ids=[i for l in e.get('layers',[e.get('layer','top')]) if l in actual for i in hits(l,shape(e).difference(holes))]\n if not ids:unconnected.append(ref)\n for r in {find(i) for i in ids}:assign[r][key].append(ref);netroots[key][r].append(ref)\n shorts=[{'nets':[netnames.get(k,k) for k in v],'pads':dict(v)} for v in assign.values() if len(v)\u003e1];opens=[{'net':netnames.get(k,k),'islands':list(v.values())} for k,v in netroots.items() if len(v)\u003e1];report['connectivity']={'named_nets_checked':len(netroots),'shorts':shorts,'opens':opens,'unconnected_pads':unconnected,'actual_copper_islands':len(nodes),'unassigned_islands':len({find(i) for i in range(len(nodes))}-set(assign))}\n nc_contacts=[]\n for e in j:\n if e['type']!='pcb_smtpad' or not e.get('pcb_port_id'):continue\n port=pp[e['pcb_port_id']];s=sp[port['source_port_id']]\n if s.get('subcircuit_connectivity_map_key'):continue\n for r in {find(i) for i in hits(e['layer'],shape(e))}:\n if r in assign:nc_contacts.append({'pad':src[pc[e['pcb_component_id']]['source_component_id']]['name']+'.'+s['name'],'nets':[netnames.get(k,k) for k in assign[r]]})\n report['connectivity']['no_connect_contacts']=nc_contacts\n if nc_contacts:report['issues'].append({'kind':'no-connect-pad-contact','contacts':nc_contacts})\n # Classify copper islands without named connected pads; expected NC pads\n # must not be mislabeled as floating routed copper.\n isolated=[]\n for r in {find(i) for i in range(len(nodes))}-set(assign):\n geometry=unary_union([nodes[i] for i in range(len(nodes)) if find(i)==r]);nc=[]\n for e in j:\n if e['type']!='pcb_smtpad' or not e.get('pcb_port_id'):continue\n port=pp[e['pcb_port_id']];s=sp[port['source_port_id']]\n if s.get('subcircuit_connectivity_map_key'):continue\n if e['layer'] in actual and r in {find(i) for i in hits(e['layer'],shape(e))}:nc.append(src[pc[e['pcb_component_id']]['source_component_id']]['name']+'.'+s['name'])\n isolated.append({'area_mm2':geometry.area,'bounds_mm':list(geometry.bounds) if not geometry.is_empty else [],'layers':[l for l in indices if any(find(i)==r for i in indices[l])],'no_connect_pads':nc,'classification':'intentional native no-connect pad' if nc else 'unassigned copper: review'})\n report['connectivity']['unassigned_island_details']=isolated\n # Spacing is measured on the independently parsed, finished copper, not on\n # centerlines or bounding rectangles. Same physical barrel-connected nets\n # are exempt; native NC islands remain separate conductors for this screen.\n copper_spacing={}\n for layer,ids in indices.items():\n near=[]\n for local,i in enumerate(ids):\n for other in trees[layer].query(nodes[i].buffer(.5)):\n other=int(other)\n if other\u003c=local:continue\n k=ids[other];ri,rk=find(i),find(k)\n if ri==rk:continue\n ai=set(assign.get(ri,{}));ak=set(assign.get(rk,{}))\n if ai and ai==ak:continue\n distance=nodes[i].distance(nodes[k])\n near.append({'clearance_mm':distance,'conductors':[[netnames.get(n,n) for n in assign.get(r,{})] or ['native NC/unassigned island'] for r in (ri,rk)],'island_indices':[i,k]})\n near.sort(key=lambda e:e['clearance_mm'])\n copper_spacing[layer]={'minimum_distinct_conductor_clearance_mm':near[0]['clearance_mm'] if near else None,'closest_pairs':near[:5],'screen_minimum_mm':.15,'geometry_tolerance_mm':.0002,'scope':'actual finished copper edges; pairs within 0.50 mm; same electrical net excluded'}\n failures=[p for p in near if p['clearance_mm']\u003c.1498]\n if failures:report['issues'].append({'kind':'actual-copper-clearance','layer':layer,'pairs':failures})\n report['actual_copper_spacing']=copper_spacing\n unresolved=[i for i in isolated if not i['no_connect_pads'] and i['area_mm2']\u003e1e-5]\n if unresolved:report['issues'].append({'kind':'unassigned-copper-islands','islands':unresolved})\n if shorts or opens or unconnected:report['issues'].append({'kind':'physical-netlist-failure','short_count':len(shorts),'open_count':len(opens),'unconnected_pads':unconnected})\n bare={s['name'] for s in src.values() if s['ftype']=='simple_test_point'} | {src[p['source_component_id']]['name'] for p in pc.values() if p.get('do_not_place')};bare_pc={p['pcb_component_id'] for p in pc.values() if src[p['source_component_id']]['name'] in bare};bare_pads=unary_union([shape(e) for e in j if e['type']=='pcb_smtpad' and e['pcb_component_id'] in bare_pc]);paste={};pth=unary_union([shape(e) for e in j if e['type']=='pcb_plated_hole'])\n for l in ['F_Paste','B_Paste']:\n bare_pads=unary_union([shape(e) for e in j if e['type']=='pcb_smtpad' and e['pcb_component_id'] in bare_pc and e['layer']==('top' if l=='F_Paste' else 'bottom')])\n g=geo.get(l,Polygon());paste[l]={'bare_interface_overlap_mm2':g.intersection(bare_pads).area,'manual_plated_joint_overlap_mm2':g.intersection(pth).area,'outside_smt_copper_mm2':g.difference(unary_union([shape(e) for e in j if e['type']=='pcb_smtpad' and e['layer']==('top' if l=='F_Paste' else 'bottom')]).buffer(.0002)).area}\n if g.intersection(bare_pads).area\u003e1e-6 or g.intersection(pth).area\u003e1e-6 or paste[l]['outside_smt_copper_mm2']\u003e1e-6:report['issues'].append({'kind':'assembly-paste-policy','layer':l,**paste[l]})\n report['paste']=paste;table={}\n for filename in ['bom.csv','pick_and_place.csv']:\n rows=list(csv.DictReader((directory/filename).open()));refs={r['Designator'] for r in rows};fit={s['name'] for s in src.values() if s['name'] not in bare};table[filename]={'rows':len(rows),'bare_rows':sorted(refs\u0026bare),'missing_fitted':sorted(fit-refs),'unexpected':sorted(refs-fit-bare)}\n duplicates=sorted(ref for ref,count in Counter(r['Designator'] for r in rows).items() if count\u003e1)\n table[filename]['duplicate_refs']=duplicates\n if refs\u0026bare or fit-refs or refs-fit-bare or duplicates:report['issues'].append({'kind':'assembly-table-policy','table':filename,**table[filename]})\n if filename=='bom.csv':\n errors=[]\n byref={e['name']:e for e in src.values()}\n for row in rows:\n component=byref.get(row['Designator'])\n if component is None or row['Designator'] in bare:continue\n mismatch={}\n if row.get('JLCPCB Part #') not in component.get('supplier_part_numbers',{}).get('jlcpcb',[]):mismatch['supplier_part_number']={'export':row.get('JLCPCB Part #'),'source':component.get('supplier_part_numbers',{}).get('jlcpcb',[])}\n if not args.baseline:\n mpn=component.get('manufacturer_part_number');value=component.get('display_resistance',component.get('display_capacitance',mpn))\n for field,expected_value in [('Manufacturer Part Number',mpn),('Comment',mpn),('Value',value)]:\n if not expected_value or row.get(field)!=expected_value:mismatch[field]={'export':row.get(field),'source':expected_value}\n if mismatch:errors.append({'ref':row['Designator'],'errors':mismatch})\n table[filename]['source_identity_errors']=errors\n if errors:report['issues'].append({'kind':'BOM-source-identity','errors':errors})\n report['assembly_tables']=table\n placement_errors=[]\n for row in csv.DictReader((directory/'pick_and_place.csv').open()):\n component=next((e for e in pc.values() if src[e['source_component_id']]['name']==row['Designator']),None)\n if component is None:continue\n errs={}\n for field,val in [('Mid X',component['center']['x']),('Mid Y',component['center']['y']),('Rotation',component.get('rotation',0))]:\n if abs(float(row[field])-val)\u003e.00051:errs[field]={'export':float(row[field]),'source':val}\n if row['Layer'].lower()!=component['layer'].lower():errs['layer']=row['Layer']\n if errs:placement_errors.append({'ref':row['Designator'],'errors':errs})\n report['cpl_coordinate_comparison']={'errors':placement_errors,'origin':'board center; mm; unmirrored top coordinates','rotation':'native imported land-pattern orientation plus saved pcb_component rotation; supplier interpretation still needs placement-preview approval','status':'SOURCE CONVENTION CHECK ONLY; supplier pickup datum and rotation remain USER_REVIEW','USB_centers':[{'reference':src[e['source_component_id']]['name'],'CPL_land_pattern_center_mm':e['center'],'rotation_deg':e.get('rotation',0)} for e in pc.values() if src[e['source_component_id']]['name'] in {'J_PD','J_DATA'}],'USB_center_note':'Upright GCT USB4145 uses native land-pattern CPL datum; local CAD anchor correction X +0.1524952 mm aligns the native STEP centre. Manufacturer pickup datum and JLCPCB placement preview remain unverified.'}\n if placement_errors:report['issues'].append({'kind':'CPL-coordinate-mismatch','errors':placement_errors})\n native_holes=[]\n for e in j:\n if e['type'] not in ('pcb_plated_hole','pcb_via','pcb_hole'):continue\n q=dict(e)\n if e['type']=='pcb_hole':q.update(shape=e.get('hole_shape','circle'),width=e.get('hole_diameter',e.get('hole_width')),height=e.get('hole_diameter',e.get('hole_height')))\n elif e['type']=='pcb_via':q.update(shape='circle',width=e['hole_diameter'],height=e['hole_diameter'])\n else:q.update(width=e.get('hole_width',e.get('hole_diameter')),height=e.get('hole_height',e.get('hole_diameter')))\n native_holes.append(shape(q))\n native_drill=unary_union(native_holes);drill_missing=native_drill.difference(holes.buffer(.00055)).area;drill_extra=holes.difference(native_drill.buffer(.00055)).area\n report['drill_source_comparison']={'missing_mm2':drill_missing,'extra_mm2':drill_extra,'tolerance_mm':.00055,'tolerance_reason':'Exporter slot endpoints and CPL rounded to 3 decimal places; 0.55 micrometer envelope','nominal_mounting_holes':4,'nominal_USB_plated_slots':8}\n if drill_missing\u003e1e-4 or drill_extra\u003e1e-4:report['issues'].append({'kind':'drill-source-mismatch',**report['drill_source_comparison']})\n mask_errors=[]\n for e in j:\n if e['type'] not in ('pcb_smtpad','pcb_plated_hole') or e.get('is_covered_with_solder_mask'):continue\n for l in e.get('layers',[e.get('layer','top')]):\n name={'top':'F_Mask','bottom':'B_Mask'}.get(l)\n if not name:continue\n missing=shape(e).difference(geo[name].buffer(.0002)).area\n if missing\u003e1e-4:mask_errors.append({'id':e.get('pcb_smtpad_id',e.get('pcb_plated_hole_id')),'layer':l,'missing_opening_mm2':missing})\n report['mask_opening_comparison']={'errors':mask_errors,'policy':'uncovered fitted/bare solder pads and plated slots remain open; filled/capped thermal via process required'}\n if mask_errors:report['issues'].append({'kind':'mask-opening-mismatch','errors':mask_errors})\n stencil=[]\n for e in j:\n if e['type']!='pcb_smtpad' or e.get('shape')!='rect' or e.get('width',0)\u003c=2 or e.get('height',0)\u003c=2:continue\n ref=src[pc[e['pcb_component_id']]['source_component_id']]['name']\n if ref in {'U_PD','U_MCU','U_DRV'}:stencil.append({'ref':ref,'pad':e['pcb_smtpad_id'],'coverage_fraction':geo.get('F_Paste',Polygon()).intersection(shape(e)).area/shape(e).area})\n aperture_screen=[]\n for paste_layer in ['F_Paste','B_Paste']:\n geometry=geo.get(paste_layer,Polygon())\n aperture_polygons=list(geometry.geoms) if hasattr(geometry,'geoms') else [geometry]\n for polygon in aperture_polygons:\n if polygon.is_empty:continue\n x1,y1,x2,y2=polygon.bounds;aspect=min(x2-x1,y2-y1)/.1;ratio=polygon.area/(polygon.length*.1)\n aperture_screen.append({'layer':paste_layer,'bounds_mm':list(polygon.bounds),'area_mm2':polygon.area,'perimeter_mm':polygon.length,'aspect_ratio_at_100um':aspect,'area_ratio_at_100um':ratio})\n poor=[e for e in aperture_screen if e['aspect_ratio_at_100um']\u003c1.5-1e-4 or e['area_ratio_at_100um']\u003c.66-1e-4]\n report['stencil_release_screen']={'candidate_thickness_mm':.10,'minimum_aspect_ratio':min((e['aspect_ratio_at_100um'] for e in aperture_screen),default=None),'minimum_area_ratio':min((e['area_ratio_at_100um'] for e in aperture_screen),default=None),'screen_limits':{'aspect_ratio':1.5,'area_ratio':.66},'failing_apertures':poor,'scope':'common geometric release screens only; physical paste/stencil/reflow process acceptance still pending'}\n if poor:report['issues'].append({'kind':'stencil-release-screen','apertures':poor})\n report['exposed_pad_stencil']=stencil\n outline=GerberFile.open(directory/'Edge_Cuts.gbr');segments=[]\n for o in outline.objects:\n for primitive_edge in o.to_primitives(unit=MM):\n if type(primitive_edge).__name__!='Line':raise ValueError('Unexpected outline primitive')\n segments.append(LineString([(primitive_edge.x1,primitive_edge.y1),(primitive_edge.x2,primitive_edge.y2)]))\n outlines=list(polygonize(segments));valid_outline=len(outlines)==1 and abs(outlines[0].area-1225)\u003c1e-6 and outlines[0].bounds==(-17.5,-17.5,17.5,17.5)\n report['board_outline']={'bounds_including_stroke':list(geo['Edge_Cuts'].bounds),'centerline_bounds_mm':list(outlines[0].bounds) if outlines else None,'closed_contour_count':len(outlines),'centerline_length_mm':sum(s.length for s in segments),'centerline_area_mm2':outlines[0].area if outlines else None,'valid_35mm_square':valid_outline}\n if not valid_outline:report['issues'].append({'kind':'outline-failure'})\n measured_webs={}\n for name in ['F_Mask','B_Mask']:\n polygons=list(geo[name].geoms) if hasattr(geo[name],'geoms') else [geo[name]];tree=STRtree(polygons);near=[]\n for i,g in enumerate(polygons):\n for other in tree.query(g.buffer(.25)):\n other=int(other)\n if other\u003ei:near.append(g.distance(polygons[other]))\n minimum=min(near) if near else None;measured_webs[name]={'minimum_web_mm':minimum,'opening_polygons':len(polygons),'scope':'nearest distinct mask openings within 0.25 mm'}\n if not args.baseline and minimum is not None and minimum\u003c.09999:report['issues'].append({'kind':'solder-mask-web','layer':name,'minimum_mm':minimum})\n report['mask_webs']=measured_webs\n report['mask']={n:{'area_mm2':geo[n].area,'bounds_mm':list(geo[n].bounds) if not geo[n].is_empty else []} for n in ['F_Mask','B_Mask'] if n in geo};report['plated_annulus_source_min_mm']=min((min(e.get('outer_width',e.get('outer_diameter',0))-e.get('hole_width',e.get('hole_diameter',0)),e.get('outer_height',e.get('outer_diameter',0))-e.get('hole_height',e.get('hole_diameter',0)))/2 for e in j if e['type'] in ('pcb_plated_hole','pcb_via')),default=None)\n clearances={}\n for l,g in actual.items():\n # Mounting-hole clearance is measured to the physical drill boundary.\n mounts=unary_union([Point(e['x'],e['y']).buffer(e['hole_diameter']/2,quad_segs=64) for e in j if e['type']=='pcb_hole' and e.get('hole_diameter')==3.2])\n clearances[l]={'mount_hole_edge_clearance_mm':g.distance(mounts),'board_edge_clearance_mm':g.distance(box(-18,-18,18,18).difference(box(-17.5,-17.5,17.5,17.5)))}\n report['copper_clearances']=clearances\n keepout_checks=[]\n for e in j:\n if e['type']!='pcb_keepout':continue\n if e.get('shape') not in ('circle','rect'):raise ValueError(f\"Unsupported keepout shape: {e.get('shape')}\")\n region=shape({**e,'x':e['center']['x'],'y':e['center']['y']})\n for layer in e['layers']:\n if layer not in actual:raise ValueError(f\"Declared keepout layer missing from actual CAM: {layer}\")\n intrusion=actual[layer].intersection(region).area\n tolerated=actual[layer].intersection(region.buffer(-.0002)).area\n check={'keepout_id':e['pcb_keepout_id'],'shape':e['shape'],'center_mm':e['center'],'layer':layer,'clearance_mm':actual[layer].distance(region),'intrusion_area_mm2':intrusion,'intrusion_beyond_0_0002mm_tolerance_mm2':tolerated}\n keepout_checks.append(check)\n if tolerated\u003e1e-5:report['issues'].append({'kind':'actual-copper-keepout-intrusion',**check})\n report['actual_keepout_checks']=keepout_checks\n silk={}\n for n,m in [('F_SilkScreen','F_Mask'),('B_SilkScreen','B_Mask')]:\n silk[n]={'overlap_mask_openings_mm2':geo[n].intersection(geo[m]).area,'inside_0_15mm_mask_guard_mm2':geo[n].intersection(geo[m].buffer(.1499)).area,'outside_board_0_10mm_inset_mm2':geo[n].difference(box(-17.4,-17.4,17.4,17.4)).area}\n if not args.baseline and (silk[n]['inside_0_15mm_mask_guard_mm2']\u003e1e-5 or silk[n]['outside_board_0_10mm_inset_mm2']\u003e1e-5):report['issues'].append({'kind':'silkscreen-clearance','layer':n,**silk[n]})\n report['silkscreen_clearances']=silk\n if not args.baseline:\n for pane in stencil:\n if abs(pane['coverage_fraction']-.60)\u003e.001:report['issues'].append({'kind':'EP-stencil-coverage',**pane})\n unowned=[e['pcb_solder_paste_id'] for e in j if e['type']=='pcb_solder_paste' and e.get('pcb_component_id') not in pc]\n if unowned:report['issues'].append({'kind':'unowned-source-paste','paste_ids':unowned,'reason':'No component ownership is present in saved source; apertures remain included in full CAM comparison.'})\n comparisons={}\n for source_layer,cam_layer in [('top','F_Paste'),('bottom','B_Paste')]:\n explicit_paste=unary_union([shape(e) for e in j if e['type']=='pcb_solder_paste' and e['layer']==source_layer and (e.get('pcb_component_id') not in pc or src[pc[e['pcb_component_id']]['source_component_id']]['name'] not in bare)])\n actual_paste=geo.get(cam_layer,Polygon())\n comparisons[cam_layer]={'missing_mm2':explicit_paste.difference(actual_paste.buffer(.0002)).area,'extra_mm2':actual_paste.difference(explicit_paste.buffer(.0002)).area}\n if any(v\u003e1e-4 for v in comparisons[cam_layer].values()):report['issues'].append({'kind':'paste-source-mismatch','layer':cam_layer,**comparisons[cam_layer]})\n report['paste_source_comparison']=comparisons\n if (root/args.source).read_bytes()!=source_bytes:raise ValueError('Frozen source changed during independent CAM audit; regenerate and repeat')\n report['status']='FAIL' if report['issues'] else 'PASS';out=directory/'audit.json';out.write_text(json.dumps(report,indent=2,allow_nan=False)+'\\n');print(json.dumps({'status':report['status'],'issues':report['issues'],'connectivity':{k:report['connectivity'][k] for k in ['named_nets_checked','actual_copper_islands','unassigned_islands']},'report':str(out)},indent=2));return 0 if args.baseline else bool(report['issues'])\nif __name__=='__main__':raise SystemExit(main())\n","content_mimetype":"application/octet-stream","created_at":"2026-10-16T20:51:32.304Z"}; window.SSR_PACKAGE_RELEASES = [{"package_release_id":"b28fdf86-c142-4a22-b03c-3719461c092c","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.13.0","github_commit_sha":null,"is_locked":false,"is_latest":true,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-16T20:48:47.665Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-116331e6f6c9b95af71afc1ac1535ffd","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":null,"sch_preview_image_url":null,"cad_preview_image_url":null,"package_release_website_url":null,"display_status":"pending","latest_package_build_id":"40853a91-a063-4fc3-ac7a-5e9fc95ccb5c","user_code_job_started_at":"2026-10-16T20:52:23.667Z","user_code_job_completed_at":"2026-10-16T21:22:28.692Z","user_code_job_error":{"message":"Build timed out before user code job was created after 30 minutes","error_code":"user_code_job_missing_timeout"},"user_code_job_completed_logs":null,"user_code_job_log_stream_url":null,"ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"fcb331a3-ace4-4b84-afe1-a720939a3c8e","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.12.2","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-16T18:34:01.562Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-4dfab944eb8ef571a9f456c53d3dfe32","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=fcb331a3-ace4-4b84-afe1-a720939a3c8e\u0026file_path=dist%2Fassembly%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=fcb331a3-ace4-4b84-afe1-a720939a3c8e\u0026file_path=dist%2Fassembly%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=fcb331a3-ace4-4b84-afe1-a720939a3c8e\u0026file_path=dist%2Fassembly%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"46b47323-4126-4492-96d0-278aa96afb24","user_code_job_started_at":"2026-10-16T18:41:48.727Z","user_code_job_completed_at":"2026-10-16T19:05:29.366Z","user_code_job_error":{"message":"Failed to upload output files to R2: The socket connection was closed unexpectedly. For more information, pass `verbose: true` in the second argument to fetch()","error_code":"failed_to_upload_output_files_to_r2"},"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=8b25bda25bea3ca34ff39088e18cc5997d4657b7a8deeddf4092dd57614e2178","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"0d863040-b422-4796-88f6-8b2aba23418b","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.12.1","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-15T20:09:46.962Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-64b74d95216c7433878fd31c1531815c","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=0d863040-b422-4796-88f6-8b2aba23418b\u0026file_path=dist%2Fassembly%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=0d863040-b422-4796-88f6-8b2aba23418b\u0026file_path=dist%2Fassembly%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=0d863040-b422-4796-88f6-8b2aba23418b\u0026file_path=dist%2Fassembly%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"5ae16ff7-3f95-435a-bb5b-d52565de487e","user_code_job_started_at":"2026-10-15T20:25:33.671Z","user_code_job_completed_at":"2026-10-15T20:55:37.274Z","user_code_job_error":{"message":"Build timed out after 30 minutes","error_code":"user_code_job_timeout"},"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=afdcedd601268fec3cd06b202ffe353797d8824eb62a95f44f5fe8b5b970dc65","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"65177d47-04d8-4fe9-a6a4-0ccd13295f33","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.12.0","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-15T00:39:26.727Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-9618fa2f72e6730f43ba583b7d14b67e","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=65177d47-04d8-4fe9-a6a4-0ccd13295f33\u0026file_path=dist%2Fassembly%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=65177d47-04d8-4fe9-a6a4-0ccd13295f33\u0026file_path=dist%2Fassembly%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=65177d47-04d8-4fe9-a6a4-0ccd13295f33\u0026file_path=dist%2Fassembly%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"62eaac89-9bb0-414a-be14-b92146dc1b82","user_code_job_started_at":"2026-10-15T00:44:55.394Z","user_code_job_completed_at":"2026-10-15T00:59:38.138Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=32333f0fb040cb3bcada2994e740c63b7d20f865ff2a3c33e1b82a5d05e97e9b","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"05741a6f-c355-4b4b-8434-eea2289f3f9f","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.11.0","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-14T23:29:58.231Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-73e54961fd83d9b488f21b35ce2d5336","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=05741a6f-c355-4b4b-8434-eea2289f3f9f\u0026file_path=dist%2Findex%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=05741a6f-c355-4b4b-8434-eea2289f3f9f\u0026file_path=dist%2Findex%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=05741a6f-c355-4b4b-8434-eea2289f3f9f\u0026file_path=dist%2Findex%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"36bf71fc-11dc-45d7-a468-9c43ebb60267","user_code_job_started_at":"2026-10-14T23:32:32.460Z","user_code_job_completed_at":"2026-10-14T23:40:29.415Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=646d163370db9e714f56dcce729931cd483918e5109ecefa342a76085a7dc018","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"d27dc806-252d-4a7a-9fff-a6ea8f8b37c7","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.10.2","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-14T05:41:32.214Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-cca306afcfb2df1e7e2dcb045e1635f2","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=d27dc806-252d-4a7a-9fff-a6ea8f8b37c7\u0026file_path=dist%2Findex%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=d27dc806-252d-4a7a-9fff-a6ea8f8b37c7\u0026file_path=dist%2Findex%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=d27dc806-252d-4a7a-9fff-a6ea8f8b37c7\u0026file_path=dist%2Findex%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"3b10fc33-0146-4635-805d-c28476c69aff","user_code_job_started_at":"2026-10-14T05:51:19.891Z","user_code_job_completed_at":"2026-10-14T05:57:13.560Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=e93ea2acf95d3a48165e0a7defccd97812f18297474155122ef482c1d3fb20f9","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"83fca364-8c05-45ac-833d-50c72ab04bb0","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.9.0","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-13T18:50:25.554Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-5f0ce2d6bbdca90955aaa723cb77659c","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=83fca364-8c05-45ac-833d-50c72ab04bb0\u0026file_path=dist%2Findex%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=83fca364-8c05-45ac-833d-50c72ab04bb0\u0026file_path=dist%2Findex%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=83fca364-8c05-45ac-833d-50c72ab04bb0\u0026file_path=dist%2Findex%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"7b56db7b-3648-495b-be89-fad9d23a1631","user_code_job_started_at":"2026-10-13T18:55:58.069Z","user_code_job_completed_at":"2026-10-13T19:01:13.737Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=bafc73597a6ab1b32cd2359ac29a53ced7a26ca9df3ce1c1203b114fe6b2e4d9","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"f93b7992-28cc-4017-a164-828e5042f5f9","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.8.2","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-13T12:55:03.962Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-4151b6aae7eec932615a10a17c8762d7","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=f93b7992-28cc-4017-a164-828e5042f5f9\u0026file_path=dist%2Findex%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=f93b7992-28cc-4017-a164-828e5042f5f9\u0026file_path=dist%2Findex%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=f93b7992-28cc-4017-a164-828e5042f5f9\u0026file_path=dist%2Findex%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"12634429-4c1b-4426-a6e6-dbb28d8ee699","user_code_job_started_at":"2026-10-13T12:56:30.721Z","user_code_job_completed_at":"2026-10-13T13:04:46.437Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=3583ebf0fd1905399b67ab5a6c084178d80b858fc22b8ae428b27b8125820f8c","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"653b0ac4-c4c4-4911-b0da-12dc11fdd481","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.8.1","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-13T12:33:57.023Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-74cd26850adcd606f730845e25e486b3","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":null,"sch_preview_image_url":null,"cad_preview_image_url":null,"package_release_website_url":null,"display_status":"pending","latest_package_build_id":"389c6d6b-7fde-49d3-bc20-b2edb147de84","user_code_job_started_at":"2026-10-13T12:34:26.392Z","user_code_job_completed_at":"2026-10-13T12:34:54.278Z","user_code_job_error":{"message":"Your code failed to build (exit code 1), see build logs for the error details","error_code":"user_code_build_error"},"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=96c60a62be53459b95f823dc436c948f4f604695cf8ec1cfbbb56faa67f4e163","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"89c293e9-c7e3-4cab-923e-2fa4fda62af8","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.7.2","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-13T06:06:18.423Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-547d963a4cb6ad76c4d9788c3a7546c9","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=89c293e9-c7e3-4cab-923e-2fa4fda62af8\u0026file_path=dist%2Findex%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=89c293e9-c7e3-4cab-923e-2fa4fda62af8\u0026file_path=dist%2Findex%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=89c293e9-c7e3-4cab-923e-2fa4fda62af8\u0026file_path=dist%2Findex%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"986105d9-8627-41d7-bf55-eca6f7c7e2a1","user_code_job_started_at":"2026-10-13T06:08:05.487Z","user_code_job_completed_at":"2026-10-13T06:13:51.393Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=249ed92d10cdcb42fe25c572eb677b72119df8da2d1350faecfbfd19bcfa086c","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"e0186aad-b6c7-4b2a-a4cc-f13f19a0b8d9","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.7.1","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-13T05:48:23.327Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-fe3c878ee706d203f0fc28f6c48cc28d","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=e0186aad-b6c7-4b2a-a4cc-f13f19a0b8d9\u0026file_path=dist%2Findex%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=e0186aad-b6c7-4b2a-a4cc-f13f19a0b8d9\u0026file_path=dist%2Findex%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=e0186aad-b6c7-4b2a-a4cc-f13f19a0b8d9\u0026file_path=dist%2Findex%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"ab0ffdd4-ddde-4c6e-9ed1-98e3d1848a84","user_code_job_started_at":"2026-10-13T05:52:17.904Z","user_code_job_completed_at":"2026-10-13T06:03:21.804Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=e0be4fb3ed1b69004f5076f38236449de6d532fa9d0ebceb1944d4cede63e4c9","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"cbb63a80-2d4e-4c5c-b332-afb6e70588c1","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.7.0","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-12T20:17:39.093Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-8abba23989b1a4c4b4a07dabcfe5032f","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=cbb63a80-2d4e-4c5c-b332-afb6e70588c1\u0026file_path=dist%2Findex%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=cbb63a80-2d4e-4c5c-b332-afb6e70588c1\u0026file_path=dist%2Findex%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=cbb63a80-2d4e-4c5c-b332-afb6e70588c1\u0026file_path=dist%2Findex%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"fd2643c7-09f6-4ef1-9e5c-c7ba58485f59","user_code_job_started_at":"2026-10-12T20:20:31.493Z","user_code_job_completed_at":"2026-10-12T20:27:39.413Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=9a21e5081703c0016103086f0577ffe3e20fbacb3a8dd27a43a003013df6ce66","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"c3283918-cfd5-4117-aa5a-abe4be17de8a","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.6.0","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-12T19:02:41.169Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-7196dd7dc1dc6385297d596593eb2305","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=c3283918-cfd5-4117-aa5a-abe4be17de8a\u0026file_path=dist%2Findex%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=c3283918-cfd5-4117-aa5a-abe4be17de8a\u0026file_path=dist%2Findex%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=c3283918-cfd5-4117-aa5a-abe4be17de8a\u0026file_path=dist%2Findex%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"4358c130-2261-491d-bfd1-67e8880d3bbb","user_code_job_started_at":"2026-10-12T19:04:45.678Z","user_code_job_completed_at":"2026-10-12T19:08:20.337Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=46a2e5b963641dea7f071138833000ea7efc16e13b8b99d8d5f9eb98312c33a0","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"0d2a0605-d05c-4680-a112-877499604e81","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.5.0","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-12T17:00:58.764Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-55b89c8f96e5e5c3a28abc34e079fdee","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":null,"sch_preview_image_url":null,"cad_preview_image_url":null,"package_release_website_url":null,"display_status":"pending","latest_package_build_id":"0267793c-8065-46ba-bd91-462289213851","user_code_job_started_at":"2026-10-12T17:10:19.082Z","user_code_job_completed_at":"2026-10-12T17:40:52.397Z","user_code_job_error":{"message":"Build timed out after 30 minutes","error_code":"user_code_job_timeout"},"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=4350aa984179f7a1f42be7bc2994d6a437b12532987efd414121c05c8436835f","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"106559a4-3b29-4378-b1c4-ba36270236cf","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.4.0","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-11T21:13:30.905Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-8f37b5a2854820708b5f2522aee16b73","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=106559a4-3b29-4378-b1c4-ba36270236cf\u0026file_path=dist%2Findex%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=106559a4-3b29-4378-b1c4-ba36270236cf\u0026file_path=dist%2Findex%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=106559a4-3b29-4378-b1c4-ba36270236cf\u0026file_path=dist%2Findex%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"41cf9be7-3cb0-4c30-84dc-42cb3f238b34","user_code_job_started_at":"2026-10-11T21:13:53.802Z","user_code_job_completed_at":"2026-10-11T21:16:55.765Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=a33f2e18052cb80945446f8cd90e4d78b3a03ad55d4613a2603485205f932678","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"822e5538-d659-47bc-a429-cce18a04fd18","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.3.0","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-11T19:56:24.032Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":false,"transpilation_display_status":"pending","fs_sha":"md5-de51c6c96b8a14d67346461a1861b1d6","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":false,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":false,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=822e5538-d659-47bc-a429-cce18a04fd18\u0026file_path=dist%2Findex%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=822e5538-d659-47bc-a429-cce18a04fd18\u0026file_path=dist%2Findex%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=822e5538-d659-47bc-a429-cce18a04fd18\u0026file_path=dist%2Findex%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"3ff431ba-a741-4541-a73d-997a8a31f532","user_code_job_started_at":"2026-10-11T20:01:12.297Z","user_code_job_completed_at":"2026-10-11T20:03:54.466Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=d34f82ffbd919e14dda78b262f614061a9c29594850afdcc914d1a33a0152183","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"ea0979ee-37d7-4c72-982e-9e0ed6944be8","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.2.0","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-11T18:22:48.734Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":false,"transpilation_display_status":"pending","fs_sha":"md5-313841de91b6db5288ca62150f5e3379","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":false,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":false,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=ea0979ee-37d7-4c72-982e-9e0ed6944be8\u0026file_path=dist%2Findex%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=ea0979ee-37d7-4c72-982e-9e0ed6944be8\u0026file_path=dist%2Findex%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=ea0979ee-37d7-4c72-982e-9e0ed6944be8\u0026file_path=dist%2Findex%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"5a222429-a513-4c6e-850c-b5f5603fa9d1","user_code_job_started_at":"2026-10-11T18:27:56.416Z","user_code_job_completed_at":"2026-10-11T18:32:26.693Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=5ca28e92488da98cfc9758568293931fe264c22f5f259d2ad354b74d52c50087","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"16d711f1-49c3-4e57-bc41-400c47a5caa7","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.1.15","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-11T12:52:09.568Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-128543d11ef6429f6ef35bf50308dba1","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":null,"sch_preview_image_url":null,"cad_preview_image_url":null,"package_release_website_url":null,"display_status":"pending","latest_package_build_id":"2a2f4c87-97c6-4852-8e96-2256a2a32825","user_code_job_started_at":"2026-10-11T13:25:15.629Z","user_code_job_completed_at":"2026-10-11T13:55:19.996Z","user_code_job_error":{"message":"Build timed out after 30 minutes","error_code":"user_code_job_timeout"},"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=381c142edb382cf5cd3fa539697c186a114e5d31aab3a638788050494e02cf42","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"85496bd9-63c0-4bef-a852-169f02da154f","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.1.14","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-11T08:50:05.229Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-b8472bb29dc2e51c3b176777807e1549","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":null,"sch_preview_image_url":null,"cad_preview_image_url":null,"package_release_website_url":null,"display_status":"pending","latest_package_build_id":"740a8d6d-60aa-4a3a-b024-a92f0c8b4370","user_code_job_started_at":"2026-10-11T09:01:30.027Z","user_code_job_completed_at":"2026-10-11T09:31:35.297Z","user_code_job_error":{"message":"Build timed out before user code job was created after 30 minutes","error_code":"user_code_job_missing_timeout"},"user_code_job_completed_logs":null,"user_code_job_log_stream_url":null,"ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"a63f0f38-9977-4173-831b-6b195fd03d6a","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.1.13","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-10T08:13:06.560Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-14d347eb3479513ecdcfbfdc4c1e9dff","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=a63f0f38-9977-4173-831b-6b195fd03d6a\u0026file_path=dist%2Findex%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=a63f0f38-9977-4173-831b-6b195fd03d6a\u0026file_path=dist%2Findex%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=a63f0f38-9977-4173-831b-6b195fd03d6a\u0026file_path=dist%2Findex%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"8e9c895e-8581-44c5-a782-e1f9d8a81ab5","user_code_job_started_at":"2026-10-10T08:13:37.908Z","user_code_job_completed_at":"2026-10-10T08:17:35.537Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=ed509e72cbc6bf577f12d96514856397880ea343265a4f25ed986d8f10785455","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"849c3be5-d0c0-4bc7-822c-e75304bd0e4e","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.1.12","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-10T08:00:45.374Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":false,"transpilation_display_status":"pending","fs_sha":"md5-358cc2495b8fd51d171e30725466db9d","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":false,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":false,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=849c3be5-d0c0-4bc7-822c-e75304bd0e4e\u0026file_path=dist%2Findex%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=849c3be5-d0c0-4bc7-822c-e75304bd0e4e\u0026file_path=dist%2Findex%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=849c3be5-d0c0-4bc7-822c-e75304bd0e4e\u0026file_path=dist%2Findex%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"53715674-c8e5-4ad4-99f5-1092a547f269","user_code_job_started_at":"2026-10-10T08:01:58.493Z","user_code_job_completed_at":"2026-10-10T08:05:09.073Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=4c8aa24ee9456886edb06c21a9058c463d8ab0adf74a3d8c6de9deed7ba7697d","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"9216f8ee-bc9c-4158-9a6c-77ac9b297923","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.1.11","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-10T01:30:12.071Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-dfcb3376802a5b6749809cc66ab2b9d8","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=9216f8ee-bc9c-4158-9a6c-77ac9b297923\u0026file_path=dist%2Findex%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=9216f8ee-bc9c-4158-9a6c-77ac9b297923\u0026file_path=dist%2Findex%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=9216f8ee-bc9c-4158-9a6c-77ac9b297923\u0026file_path=dist%2Findex%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"0a8ee00f-2c66-4571-a830-8db5766c8590","user_code_job_started_at":"2026-10-10T01:30:30.273Z","user_code_job_completed_at":"2026-10-10T01:34:17.786Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=15808e2f55521e3fb1edc5cc7b338fec80265c56851bf3637cf5f9ee1721cfd2","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"4c0b41f6-7e6b-42e1-8a15-5af1598c13fe","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.1.10","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-09T22:26:39.717Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-83b588a842f8f55ef23690547568ebc3","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=4c0b41f6-7e6b-42e1-8a15-5af1598c13fe\u0026file_path=dist%2Findex%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=4c0b41f6-7e6b-42e1-8a15-5af1598c13fe\u0026file_path=dist%2Findex%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=4c0b41f6-7e6b-42e1-8a15-5af1598c13fe\u0026file_path=dist%2Findex%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"992beaef-cc84-4cdc-8f89-9259cc48e512","user_code_job_started_at":"2026-10-09T22:26:52.796Z","user_code_job_completed_at":"2026-10-09T22:31:22.704Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=ba2f96c0f6adf723f4bc7137715f9db2e76dfce971a17faa446ac0de2d383534","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"903028a9-857a-4ded-ad63-f9b7fd83ccbf","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.1.9","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-09T19:51:30.261Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":false,"transpilation_display_status":"pending","fs_sha":"md5-e89e820dd077a07921e52b437430f50a","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":false,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":false,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=903028a9-857a-4ded-ad63-f9b7fd83ccbf\u0026file_path=dist%2Findex%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=903028a9-857a-4ded-ad63-f9b7fd83ccbf\u0026file_path=dist%2Findex%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=903028a9-857a-4ded-ad63-f9b7fd83ccbf\u0026file_path=dist%2Findex%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"53a335c3-6ed9-4bf0-81a9-01c7c606b1f5","user_code_job_started_at":"2026-10-09T19:53:25.538Z","user_code_job_completed_at":"2026-10-09T19:57:38.831Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=b13fa0878a6729c198b0463a957ab509c983545e8139d60a47653f65bae1666b","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"40db4c55-74f2-4872-af15-f87bcbc6a0ca","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.1.8","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-09T05:50:37.132Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-5ec9e7fd549f670cbb1b0b70ff5eda16","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=40db4c55-74f2-4872-af15-f87bcbc6a0ca\u0026file_path=dist%2Findex%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=40db4c55-74f2-4872-af15-f87bcbc6a0ca\u0026file_path=dist%2Findex%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=40db4c55-74f2-4872-af15-f87bcbc6a0ca\u0026file_path=dist%2Findex%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"9c5547e5-05c6-460d-b33a-8ef4f1fecf49","user_code_job_started_at":"2026-10-09T05:51:05.471Z","user_code_job_completed_at":"2026-10-09T06:00:40.623Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=04c6388b3c94740ca454b98ed00b320f41b594f5f0f3d2059545bc3084b705d3","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"085e5bdd-8d20-46f6-9ed5-76c801c3f0e1","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.1.7","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":false,"is_pr_preview":false,"created_at":"2026-10-09T05:46:38.576Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":false,"transpilation_display_status":"pending","fs_sha":"md5-6754cd1c97582ef4941b0a191299dfdc","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":false,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":false,"image_generation_display_status":"pending","pcb_preview_image_url":null,"sch_preview_image_url":null,"cad_preview_image_url":null,"package_release_website_url":null,"display_status":"pending","latest_package_build_id":null,"user_code_job_started_at":null,"user_code_job_completed_at":null,"user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":null,"ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"49b909d7-668a-4642-b4b4-8aa9eebd0fa5","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.1.6","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-07T23:56:52.759Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-b910f479e276e512c958f8e64de36715","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=49b909d7-668a-4642-b4b4-8aa9eebd0fa5\u0026file_path=dist%2Findex%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=49b909d7-668a-4642-b4b4-8aa9eebd0fa5\u0026file_path=dist%2Findex%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=49b909d7-668a-4642-b4b4-8aa9eebd0fa5\u0026file_path=dist%2Findex%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"5ce38393-a870-42d1-8635-c2d7349216c7","user_code_job_started_at":"2026-10-07T23:57:15.201Z","user_code_job_completed_at":"2026-10-08T00:00:23.040Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=6e3c1e1de73407d1262f7a80b0980a9538795334836b08a4aeafbbd881477151","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"9ef0e844-32ba-430d-9d1d-5d9f1ede48b8","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.1.5","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-07T23:39:10.189Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-f915d032588b713df92e7078bcf86f7b","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=9ef0e844-32ba-430d-9d1d-5d9f1ede48b8\u0026file_path=dist%2Findex%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=9ef0e844-32ba-430d-9d1d-5d9f1ede48b8\u0026file_path=dist%2Findex%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=9ef0e844-32ba-430d-9d1d-5d9f1ede48b8\u0026file_path=dist%2Findex%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"b28c1ba9-f1cb-4e9b-9373-11e0bdc68d58","user_code_job_started_at":"2026-10-07T23:41:44.891Z","user_code_job_completed_at":"2026-10-08T00:00:08.798Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=f95b646fe872bf93dfb3f2db112c638091288e069825b2366bcb6571a476bbcd","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"e2abd51e-dd4f-49ad-93fd-c6bbc655af21","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.1.4","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":false,"is_pr_preview":false,"created_at":"2026-10-07T23:33:57.522Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":false,"transpilation_display_status":"pending","fs_sha":"md5-2f3cc599544d09a510a9ed567d08bfd7","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":false,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":false,"image_generation_display_status":"pending","pcb_preview_image_url":null,"sch_preview_image_url":null,"cad_preview_image_url":null,"package_release_website_url":null,"display_status":"pending","latest_package_build_id":null,"user_code_job_started_at":null,"user_code_job_completed_at":null,"user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":null,"ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"d98d32ca-4602-492c-97dc-18b553ceb5e6","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.1.2","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-07T23:26:32.131Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-c366b1194e123a9518305b814c877d23","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":null,"sch_preview_image_url":null,"cad_preview_image_url":null,"package_release_website_url":null,"display_status":"pending","latest_package_build_id":"ec167bda-6938-4401-a004-81ea583287a5","user_code_job_started_at":"2026-10-07T23:26:52.275Z","user_code_job_completed_at":"2026-10-07T23:56:54.398Z","user_code_job_error":{"message":"Build timed out after 30 minutes","error_code":"user_code_job_timeout"},"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=be7259c2964b32ab9dac8b7cd24c3947a8e58844358ff3bbdfd79a703e1acb64","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"1972e9c8-46d9-4e2d-aad2-b524ff8addb9","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.1.1","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-07T23:25:47.285Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-2053a12b8c9c6b6656056bf360e7e987","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":null,"sch_preview_image_url":null,"cad_preview_image_url":null,"package_release_website_url":null,"display_status":"pending","latest_package_build_id":"b71f7c62-e613-45c6-9333-b11d11a38cb2","user_code_job_started_at":"2026-10-07T23:26:36.112Z","user_code_job_completed_at":"2026-10-07T23:56:44.345Z","user_code_job_error":{"message":"Build timed out after 30 minutes","error_code":"user_code_job_timeout"},"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=48f067b15cd31e1fd594845a61503378b2260694aa136a5f7d3aff4566bcd850","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"965458d1-b140-4d53-9b55-534752f40383","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.1.0","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-07T23:16:56.433Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-431bb4eb8380d67b5c75cbdd66018982","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":null,"sch_preview_image_url":null,"cad_preview_image_url":null,"package_release_website_url":null,"display_status":"pending","latest_package_build_id":"8e793860-0271-43de-9a81-6fdfb78ba84b","user_code_job_started_at":"2026-10-07T23:17:04.686Z","user_code_job_completed_at":"2026-10-07T23:21:48.578Z","user_code_job_error":{"message":"There was an error running the job on our infrastructure, this is probably not your code, see build logs","error_code":"user_code_job_infrastructure_error"},"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=b40bf4801cd61d8fd709952ed81d9c949c45689f5996e86c4b1a1161f4d9607c","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"93d6c7c7-5e72-4cc6-8917-e05d7f29a754","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.0.8","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-07T22:07:12.540Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-2aedfacd857e16ccd7d5e22afd9d3e9f","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=93d6c7c7-5e72-4cc6-8917-e05d7f29a754\u0026file_path=dist%2Fartifacts%2Fboard%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=93d6c7c7-5e72-4cc6-8917-e05d7f29a754\u0026file_path=dist%2Fartifacts%2Fboard%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=93d6c7c7-5e72-4cc6-8917-e05d7f29a754\u0026file_path=dist%2Fartifacts%2Fboard%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"4d355dac-f7e1-4f68-875c-366be3f0ce1a","user_code_job_started_at":"2026-10-07T22:07:24.266Z","user_code_job_completed_at":"2026-10-07T22:09:06.570Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=551d4229baa102c90387b6ce9d0b8b68c50182bed6943c60786e07be1b11e6a3","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"54d2d21a-b93b-4adc-a32b-2e566cc7665d","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.0.7","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-07T21:24:41.645Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-bbfbce93f694fed95c5206977fc93f64","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=54d2d21a-b93b-4adc-a32b-2e566cc7665d\u0026file_path=dist%2Fartifacts%2Fboard%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=54d2d21a-b93b-4adc-a32b-2e566cc7665d\u0026file_path=dist%2Fartifacts%2Fboard%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=54d2d21a-b93b-4adc-a32b-2e566cc7665d\u0026file_path=dist%2Fartifacts%2Fboard%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"86c09b41-f126-43a8-9ede-ae1f3d22159a","user_code_job_started_at":"2026-10-07T21:24:55.438Z","user_code_job_completed_at":"2026-10-07T21:26:28.191Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=ddc87c93a5e56cbd38061767c742341b704b3465246b8bd8a7515b30d24037f9","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"0b16c84e-69f9-4033-982f-a2b6fe7d558e","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.0.6","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-07T21:23:50.220Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-db7330636dacf1d63ff4fce73350941e","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=0b16c84e-69f9-4033-982f-a2b6fe7d558e\u0026file_path=dist%2Fartifacts%2Fboard%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=0b16c84e-69f9-4033-982f-a2b6fe7d558e\u0026file_path=dist%2Fartifacts%2Fboard%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=0b16c84e-69f9-4033-982f-a2b6fe7d558e\u0026file_path=dist%2Fartifacts%2Fboard%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"b1b31e49-693e-4e21-a0ee-a8810ba06535","user_code_job_started_at":"2026-10-07T21:24:06.494Z","user_code_job_completed_at":"2026-10-07T21:26:07.724Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=4f76f46c113f62d16fd4398d1cb14855ae8cc61d2dbb073a1096d98063bc2bef","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"dd6f1606-2fa1-418d-8255-1d00208cfb12","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.0.5","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-07T21:20:47.375Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-4fcbeeaa91e3b60cd1c010db5a0c5843","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=dd6f1606-2fa1-418d-8255-1d00208cfb12\u0026file_path=dist%2Fartifacts%2Fboard%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=dd6f1606-2fa1-418d-8255-1d00208cfb12\u0026file_path=dist%2Fartifacts%2Fboard%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=dd6f1606-2fa1-418d-8255-1d00208cfb12\u0026file_path=dist%2Fartifacts%2Fboard%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"e8b1e5ec-a3e3-40f3-a8c2-7266cad00afc","user_code_job_started_at":"2026-10-07T21:21:02.749Z","user_code_job_completed_at":"2026-10-07T21:22:34.159Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=02c5bc1c970d2ffaeaa5f677c57444f2643da34e078543906b85386acf626a7e","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"f73d9c35-737f-4d0f-8ed3-cb6ac209dbe9","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.0.4","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":false,"is_pr_preview":false,"created_at":"2026-10-07T21:16:39.357Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":false,"transpilation_display_status":"pending","fs_sha":"md5-07fbfd929eed7db5008ce35176b98c06","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":false,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":false,"image_generation_display_status":"pending","pcb_preview_image_url":null,"sch_preview_image_url":null,"cad_preview_image_url":null,"package_release_website_url":null,"display_status":"pending","latest_package_build_id":null,"user_code_job_started_at":null,"user_code_job_completed_at":null,"user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":null,"ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"708c2737-53bc-4566-9034-f092e79dc3db","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.0.3","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":false,"is_pr_preview":false,"created_at":"2026-10-07T21:15:18.931Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":false,"transpilation_display_status":"pending","fs_sha":"md5-fbf9caa0fc28a31dac30c0a45713df12","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":false,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":false,"image_generation_display_status":"pending","pcb_preview_image_url":null,"sch_preview_image_url":null,"cad_preview_image_url":null,"package_release_website_url":null,"display_status":"pending","latest_package_build_id":null,"user_code_job_started_at":null,"user_code_job_completed_at":null,"user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":null,"ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"00aa36ff-d367-4eec-961f-54d4b6c27440","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.0.2","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-07T20:43:04.686Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-0cec25dd0b37a3d9401591021367710f","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=00aa36ff-d367-4eec-961f-54d4b6c27440\u0026file_path=dist%2Fartifacts%2Fboard%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=00aa36ff-d367-4eec-961f-54d4b6c27440\u0026file_path=dist%2Fartifacts%2Fboard%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=00aa36ff-d367-4eec-961f-54d4b6c27440\u0026file_path=dist%2Fartifacts%2Fboard%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"11ac981b-f8ee-40bf-a738-3a041527ea99","user_code_job_started_at":"2026-10-07T20:43:15.551Z","user_code_job_completed_at":"2026-10-07T20:44:36.715Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=d35aeed880b994e3667c8e751a3c12c11aa79acbf7e62682588c20400772e4c8","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"26daf35b-6179-43fe-9598-04bbd63d25f8","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.0.1","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":true,"is_pr_preview":false,"created_at":"2026-10-07T20:37:54.537Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":true,"transpilation_display_status":"pending","fs_sha":"md5-5fa95f228a0c650fc3a6cf4ccc278579","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":true,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":true,"image_generation_display_status":"pending","pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=26daf35b-6179-43fe-9598-04bbd63d25f8\u0026file_path=dist%2Fartifacts%2Fboard%2Fpcb.svg","sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=26daf35b-6179-43fe-9598-04bbd63d25f8\u0026file_path=dist%2Fartifacts%2Fboard%2Fschematic.svg","cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=26daf35b-6179-43fe-9598-04bbd63d25f8\u0026file_path=dist%2Fartifacts%2Fboard%2F3d.png","package_release_website_url":null,"display_status":"pending","latest_package_build_id":"7080f0dd-cb43-4226-b04e-5d4ed17391df","user_code_job_started_at":"2026-10-07T20:37:58.644Z","user_code_job_completed_at":"2026-10-07T20:39:14.308Z","user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":"https://usercode.tscircuit.com/user_code_jobs/view_log_stream?user_code_job_id=fbf6eb5baf4eac69dea7bab0490c9c8cf699ba6bdece215cd3cf171612b3eaf6","ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null},{"package_release_id":"e0077e53-e19b-4240-a82f-848e49024947","package_id":"2b23defa-64f7-4f3b-82eb-7112eab4ac39","version":"1.0.0","github_commit_sha":null,"is_locked":false,"is_latest":false,"ready_to_build":false,"is_pr_preview":false,"created_at":"2026-10-07T20:36:13.864Z","circuit_json_build_error":null,"circuit_json_build_error_last_updated_at":null,"has_transpiled":false,"transpilation_error":null,"transpilation_logs":null,"transpilation_in_progress":false,"transpilation_started_at":null,"transpilation_completed_at":null,"transpilation_is_stale":false,"transpilation_display_status":"pending","fs_sha":"md5-0ac3c1af8d19796c4189cc4ada15a7f7","circuit_json_build_logs":null,"circuit_json_build_in_progress":false,"circuit_json_build_started_at":null,"circuit_json_build_completed_at":null,"circuit_json_build_is_stale":false,"circuit_json_build_display_status":"pending","image_generation_error":null,"image_generation_error_last_updated_at":null,"image_generation_logs":null,"image_generation_in_progress":false,"image_generation_started_at":null,"image_generation_completed_at":null,"image_generation_is_stale":false,"image_generation_display_status":"pending","pcb_preview_image_url":null,"sch_preview_image_url":null,"cad_preview_image_url":null,"package_release_website_url":null,"display_status":"pending","latest_package_build_id":null,"user_code_job_started_at":null,"user_code_job_completed_at":null,"user_code_job_error":null,"user_code_job_completed_logs":null,"user_code_job_log_stream_url":null,"ai_review_requested":false,"github_pr_number":null,"github_pr_title":null,"github_branch_name":null}]; window.SSR_PACKAGE_BUILDS = []; window.SSR_RELATED_PACKAGES = [{"package_id":"e6f17f50-ed9c-4337-aabe-272a0f91444b","creator_account_id":"84198f66-bb86-4dc1-97f0-cdf2cf2c843a","latest_package_release_id":"34261ad8-6598-40d5-897f-d26d267f0688","last_built_release_id":"34261ad8-6598-40d5-897f-d26d267f0688","latest_package_release_fs_sha":"md5-e76ea95048214f093e9d8c43ca90f422","latest_pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=34261ad8-6598-40d5-897f-d26d267f0688\u0026file_path=dist%2Findex%2Fpcb.svg","latest_sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=34261ad8-6598-40d5-897f-d26d267f0688\u0026file_path=dist%2Findex%2Fschematic.svg","latest_cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=34261ad8-6598-40d5-897f-d26d267f0688\u0026file_path=dist%2Findex%2F3d.png","latest_version":"0.0.1","license":"unset","owner_org_id":"07e44f25-c5d3-4583-9c34-2c7bb568f85b","org_owner_tscircuit_handle":"AnasSarkiz","owner_github_username":"AnasSarkiz","github_repo_full_name":null,"is_source_from_github":false,"description":null,"name":"AnasSarkiz/test","unscoped_name":"test","star_count":0,"created_at":"2026-03-05T20:17:31.247Z","updated_at":"2026-07-06T21:36:25.860Z","ai_description":"Defines a PCB layout with a JST PH 2-pin connector labeled \"J1\".","ai_usage_instructions":null,"is_private":false,"is_unlisted":false,"is_public":true,"public_dist_enabled":false,"has_public_dist":true,"starred_at":null,"default_view":"files","website":null,"github_installation_id":null,"allow_pr_previews":false,"related_type":"same_author","thumbnail_url":"https://api.tscircuit.com/package_files/view?package_release_id=34261ad8-6598-40d5-897f-d26d267f0688\u0026file_path=dist%2Findex%2Fpcb.svg"},{"package_id":"f064ebaf-e000-4825-a7fb-2871976fb32b","creator_account_id":"96f144ef-7dfe-4068-aac0-8753c8ab5f62","latest_package_release_id":"e8d285f7-c3d8-46f5-9a54-344fdde0124e","last_built_release_id":"e8d285f7-c3d8-46f5-9a54-344fdde0124e","latest_package_release_fs_sha":"md5-ccffada3c1cc24d393e7b2485cb701f3","latest_pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=e8d285f7-c3d8-46f5-9a54-344fdde0124e\u0026file_path=dist%2Findex%2Fpcb.svg","latest_sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=e8d285f7-c3d8-46f5-9a54-344fdde0124e\u0026file_path=dist%2Findex%2Fschematic.svg","latest_cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=e8d285f7-c3d8-46f5-9a54-344fdde0124e\u0026file_path=dist%2Findex%2F3d.png","latest_version":"1.0.42","license":"unset","owner_org_id":"719473db-1754-470b-a747-20148ebb82aa","org_owner_tscircuit_handle":"imrishabh18","owner_github_username":"imrishabh18","github_repo_full_name":null,"is_source_from_github":false,"description":null,"name":"imrishabh18/rp2040-motor-controller","unscoped_name":"rp2040-motor-controller","star_count":5,"created_at":"2026-08-07T23:10:26.096Z","updated_at":"2026-10-02T13:30:59.461Z","ai_description":"An RP2040-based NEMA17 stepper-motor controller with USB-C programming and PD motor-power negotiation, DRV8825 dual H-bridge drive, current/temperature telemetry, protected power filtering, status RGB LED, buzzer alarm, and optional magnetic encoder.","ai_usage_instructions":null,"is_private":false,"is_unlisted":false,"is_public":true,"public_dist_enabled":false,"has_public_dist":true,"starred_at":null,"default_view":"files","website":null,"github_installation_id":null,"allow_pr_previews":false,"related_type":"similar_ai_description","thumbnail_url":"https://api.tscircuit.com/package_files/view?package_release_id=e8d285f7-c3d8-46f5-9a54-344fdde0124e\u0026file_path=dist%2Findex%2Fpcb.svg"},{"package_id":"486fb9f1-0aba-4bf5-b67d-b0c235c3ef51","creator_account_id":"63586009-ac32-446c-b5aa-a60ea81a44bf","latest_package_release_id":"e762c166-aeca-4a4c-8db9-a98979f4f6c6","last_built_release_id":"e762c166-aeca-4a4c-8db9-a98979f4f6c6","latest_package_release_fs_sha":"md5-a27f13ce7e9faa6e8ed222edd43371f6","latest_pcb_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=e762c166-aeca-4a4c-8db9-a98979f4f6c6\u0026file_path=dist%2Findex%2Fpcb.svg","latest_sch_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=e762c166-aeca-4a4c-8db9-a98979f4f6c6\u0026file_path=dist%2Findex%2Fschematic.svg","latest_cad_preview_image_url":"https://api.tscircuit.com/package_files/view?package_release_id=e762c166-aeca-4a4c-8db9-a98979f4f6c6\u0026file_path=dist%2Findex%2F3d.png","latest_version":"0.0.1","license":"unset","owner_org_id":"e4b51b30-273d-4e29-92ed-981078150dff","org_owner_tscircuit_handle":"ShiboSoftwareDev","owner_github_username":"ShiboSoftwareDev","github_repo_full_name":null,"is_source_from_github":false,"description":null,"name":"ShiboSoftwareDev/muse-reterminal-e1001-replacement","unscoped_name":"muse-reterminal-e1001-replacement","star_count":0,"created_at":"2026-10-02T21:16:20.644Z","updated_at":"2026-10-02T21:21:04.552Z","ai_description":"A four-layer ESP32-S3 e-paper carrier board with USB-C power, AMS1117 3.3V regulation, 24-pin FFC interface, reset/boot and user buttons, status LED, decoupling passives, test points, mounting holes, and ground/power planes.","ai_usage_instructions":null,"is_private":false,"is_unlisted":false,"is_public":true,"public_dist_enabled":false,"has_public_dist":true,"starred_at":null,"default_view":"files","website":null,"github_installation_id":null,"allow_pr_previews":false,"related_type":"random","thumbnail_url":"https://api.tscircuit.com/package_files/view?package_release_id=e762c166-aeca-4a4c-8db9-a98979f4f6c6\u0026file_path=dist%2Findex%2Fpcb.svg"}]; window.SSR_PACKAGE_ROUTE = {"author":"AnasSarkiz","packageName":"NEMA14_RP2040","packageNameWithScope":"AnasSarkiz/NEMA14_RP2040","version":null,"isLegacyRoute":false,"kind":"file","filePath":"scripts/audit-manufacturing.py"};