main
John Lauer Add duplicate conductor GLB audit and neighboring connector service clearance guidance f50f838 4d ago
use serde_json::{Value,json};
use std::{env,fs,process};
fn lint(v:&Value)->Value{
 let mut issues=Vec::new();
 let mut add=|id:&str,check:&str,hint:&str|issues.push(json!({"id":id,"check":check,"severity":"error","hint":hint}));
 let harnesses=v["harnesses"].as_array();
 if harnesses.map_or(true,|a|a.is_empty()){add("inventory","missing","Inventory every installed harness; distinguish factory leads from added wiring.");}
 for h in harnesses.into_iter().flatten(){
  let id=h["id"].as_str().unwrap_or("unnamed");
  for (k,hint) in [("pinColorEvidence","Verify actual supplier wire colors and contact numbering from the mating-face view; do not infer colors from conventions."),("terminalFitEvidence","Verify exact crimp contact, housing and header compatibility, wire AWG, insulation OD, strip length and tooling."),("releaseEvidence","Identify housing latch release separately from terminal depinning; specify tools and safe grip points."),("forceEvidence","Record supplier or measured mating/unmating force in newtons and test conditions. Unknown force is unresolved; do not invent it."),("sweptClearanceEvidence","Verify insertion and extraction travel, latch/tool/finger envelopes, and cable motion against the current assembly."),("bendEvidence","Verify supplier minimum bend radius, insulation envelope, slack and terminal strain relief."),("retentionEvidence","Specify cable clips or printed holders, attachment, edge protection, temperature compatibility and service release."),("neighborServiceClearanceEvidence","Check every neighboring connector mating, withdrawal and latch/tool corridor against wire envelopes, including sag and tolerances."),("revisionEvidence","Bind this review to board, assembly and harness revision hashes.")]{
   if h[k].as_str().map_or(true,|s|s.trim().is_empty()){add(id,k,hint)}
  }
  let wires=h["wires"].as_array();
  if wires.map_or(true,|a|a.is_empty()){add(id,"wires","List each conductor with net, color, source pin and destination pin.");}
  let mut ids=std::collections::HashSet::new();
  let mut endpoints=std::collections::HashSet::new();
  if h["expectedConductorCount"].as_u64().map_or(true,|n|n as usize != wires.map_or(0,|w|w.len())) {add(id,"conductorCount","Match physical conductor count to the connector pin inventory; reject duplicate decorative leads.");}
  for w in wires.into_iter().flatten(){
   match w["physicalId"].as_str(){Some(k) if !k.is_empty()=>{if !ids.insert(k){add(id,"duplicateConductor","A physical conductor ID occurs twice. Remove duplicate wire geometry.");}},_=>add(id,"physicalId","Assign one stable physical ID per conductor and reference its scene nodes.")}
   if let (Some(a),Some(b))=(w["sourcePin"].as_str(),w["destinationPin"].as_str()){if !endpoints.insert((a,b)){add(id,"duplicateEndpoints","Two conductor records connect the same endpoints; investigate duplicate geometry or explicitly model real parallel wires.");}}
   for key in ["continuousGeometryEvidence","entryAxisEvidence","housingIntersectionEvidence","bendRadiusEvidence"]{if w[key].as_str().map_or(true,|s|s.trim().is_empty()){add(id,key,"Verify one continuous insulated conductor, aligned straight crimp entry, no housing-wall penetration or self-intersection, and minimum bend radius. Inspect actual scene geometry, not only the manifest.");}}
   for k in ["net","color","sourcePin","destinationPin"]{if w[k].as_str().map_or(true,|s|s.trim().is_empty()){add(id,k,"Every conductor needs an unambiguous pin-to-pin and color map.");}}}
  match (h["requiredLengthMm"].as_f64(),h["minimumAvailableLengthMm"].as_f64()){
   (Some(r),Some(a)) if r.is_finite()&&a.is_finite()&&r>0.&&a>=r=>{},
   _=>add(id,"length","Required cut length including service slack and termination allowances must fit minimum supplied length.")
  }
 }
 json!({"schemaVersion":1,"passed":issues.is_empty(),"findings":issues,"animationRequired":false,"qualification":"Review completeness only; evidence paths require independent review, not proof of physical fit."})
}
fn audit_glb(path:&str)->Result<Value,String>{
 let b=fs::read(path).map_err(|e|e.to_string())?;
 if b.len()<20 || &b[0..4]!=b"glTF" {return Err("Not a GLB".into())}
 let n=u32::from_le_bytes(b[12..16].try_into().unwrap()) as usize;
 if &b[16..20]!=b"JSON" || n>b.len()-20 {return Err("Invalid JSON chunk".into())}
 let g:Value=serde_json::from_slice(&b[20..20+n]).map_err(|e|e.to_string())?;
 let mut ids:std::collections::BTreeMap<String,Vec<String>>=std::collections::BTreeMap::new();
 for node in g["nodes"].as_array().into_iter().flatten(){
  if let Some(id)=node["extras"]["physicalConductorId"].as_str(){ids.entry(id.into()).or_default().push(node["name"].as_str().unwrap_or("unnamed").into());}
 }
 let duplicates:Vec<_>=ids.iter().filter(|(_,n)|n.len()>1).map(|(id,n)|json!({"id":id,"nodes":n})).collect();
 Ok(json!({"schemaVersion":1,"passed":!ids.is_empty()&&duplicates.is_empty(),"physicalConductors":ids,"duplicates":duplicates,"hint":"Tag exactly one conductor root with extras.physicalConductorId per installed wire. Child primitives stay untagged. This detects duplicate roots, not geometric intersections or viewer scene accumulation; inspect the live scene separately."}))
}
fn main(){let a:Vec<_>=env::args().collect();if a.len()==3 && a[1]=="audit-glb" {match audit_glb(&a[2]){Ok(v)=>{println!("{}",serde_json::to_string_pretty(&v).unwrap());process::exit(if v["passed"]==true{0}else{1})},Err(e)=>{eprintln!("ERROR: {e}");process::exit(2)}}} if a.len()!=3||a[1]!="lint"{eprintln!("Usage: adom-aiflow-wiring lint wiring.json | audit-glb assembly.glb");process::exit(2)}let r=fs::read_to_string(&a[2]).map_err(|e|e.to_string()).and_then(|s|serde_json::from_str(&s).map_err(|e|e.to_string()));match r{Ok(v)=>{let o=lint(&v);println!("{}",serde_json::to_string_pretty(&o).unwrap());if o["passed"]!=true{process::exit(1)}},Err(e)=>{eprintln!("ERROR: {e}");process::exit(2)}}}
#[cfg(test)]mod tests{use super::*;#[test]fn unknowns_fail(){let r=lint(&json!({"harnesses":[{"id":"fan","requiredLengthMm":151,"minimumAvailableLengthMm":150}]}));assert_eq!(r["passed"],false);assert!(r["findings"].as_array().unwrap().iter().any(|v|v["check"]=="length"));assert!(r["findings"].as_array().unwrap().iter().any(|v|v["check"]=="forceEvidence"));}#[test]fn empty_fails(){assert_eq!(lint(&json!({}))["passed"],false)}}

#[cfg(test)] mod geometry_tests {
 use super::*;
 #[test] fn duplicate_conductors_and_service_gaps_are_reported() {
  let wire=json!({"physicalId":"w1","sourcePin":"fan.red","destinationPin":"J9.1","net":"5V_AUX","color":"red"});
  let r=lint(&json!({"harnesses":[{"id":"fan","expectedConductorCount":4,"wires":[wire.clone(),wire]}]}));
  let a=r["findings"].as_array().unwrap();
  for name in ["duplicateConductor","duplicateEndpoints","conductorCount","neighborServiceClearanceEvidence","entryAxisEvidence"] {assert!(a.iter().any(|x|x["check"]==name),"{name}");}
 }
}