← Commit history
docs/completion-plan.md+6−1
@@ -30,10 +30,15 @@ Updated 2026-10-13. Finish the custom electronic-load board through adom-aiflow,  ## Evidence and history -Current public project commit: `69ce780f25efd65845c16d76c5ad0f73cdea4e2b` (Board34/R6 hero and real three-page datasheet). Latest carrier clip commit: `733f9582acdef11fc6fb3b6fa2991eb29de8c133`.+Current public project commit: `f42ada49eafd9d88ffc29bd4357ddb01dcecd968` (R9 narrated review film and docs), following `4daaf8f06e345a5cc33de64a0c8636f2855bdf1d` (R9 model, datasheet and clips).  The prior chronological plan, including superseded Board32 data, is retained in [completion-plan-history-20261013.md](completion-plan-history-20261013.md). Treat it as history, not the current resume target. The run ledger remains append-only.  ## Active thermal alternative study  `mechanical/passive-board34-envelope/` tests a conservative 76.0984 × 76.2 × 50.8 mm Wakefield 125319 three-inch-cut envelope on the same Board34 probing route. It is not adopted; the R9 carrier would require redesign, and catalog resistance is not an installed rating. `probing-preview-passive-envelope` contains the separate check. The existing R9 public model and acceptance are preserved.+++Board34 passive feasibility update: the initial envelope failed with 14 head-collision episodes and three tether snags. The shifted envelope reduced this to one collision at TP16, including the landing, with zero snags; increased travel Z cannot resolve a blocked landing. A rearward envelope is being screened separately. No geometry or thermal credit has been adopted.++The isolated 0.2 mm Fields candidate completed with Q1 case rise 12.062 C and junction rise 14.372 C at 5.5 W, D1 rise 28.626 C, using catalog 1.522 K/W sink resistance and assumed contact/pad paths. This is supplied-parameter feasibility only; installed orientation, convection obstruction, contact spread, retention and sensitivity remain unresolved. Evidence: `checkpoints/board34-passive-thermal-candidate/fields/fields.json`.
docs/side-fan-cooling-review.md+5
@@ -42,3 +42,8 @@ The illustrative rear 8 × 8 mm beam sensitivity uses 10 N at a 43 mm lever, giv - Sunon manufacturer drawing and performance curves: `mechanical/vendor/MF40200V1-performance.pdf`, page 6 for mounting hardware.  No physical prototype, tested power rating or industrial qualification is claimed.+++### Reproducible R9 hardware audit++[Bound audit](../mechanical/side-fan-r9/hardware-audit.json) records 689 pair checks with no intersections, hashes the current board, GLB and generator snapshot, and regenerates into a separate study folder. Run `tools/check_side_fan_hardware.py` with the CAD environment. Nominal clearance is not a tolerance, fastener procurement or physical retention qualification.
mechanical/side-fan-r9/generator-snapshot.py+1−1
@@ -4,7 +4,7 @@ from pathlib import Path import copy, json, math, hashlib, struct import cadquery as cq from glb_shape_helpers import read_glb,write_glb,add_shape-R=Path(__file__).resolve().parents[1]+R=next(p for p in Path(__file__).resolve().parents if (p/'design/spec.json').is_file()) import argparse parser=argparse.ArgumentParser() parser.add_argument('--board-glb',default='probing-flow/design-candidate/probing-board.glb')
mechanical/side-fan-r9/hardware-audit.jsonadded+10
@@ -0,0 +1,10 @@+{+  "status": "nominal-screen-only",+  "pairsChecked": 689,+  "thresholdMm3": 1e-05,+  "unexpectedIntersections": [],+  "generatorSha256": "6fd0d7bee95ca4bb2987f040ad251b86eda8d1a322866ff7a5f0da36ae980a62",+  "boardSha256": "74f8ac20cba6b95db26c40f5369156efec80cb80e35388fe064f6891ff78ff11",+  "publicGlbSha256": "81a25673a6258f34d89a49081e83ac8a2b4292976faad9f70406622002cd273d",+  "limits": "Exact nominal CAD intersections only. Threads, tolerances, assembly sequence, tool clearance, preload and retention remain unqualified."+}
tools/build_passive_rearward_envelope.pyadded+21
@@ -0,0 +1,21 @@+from pathlib import Path+import sys,json,hashlib+R=Path(__file__).resolve().parents[1];sys.path.insert(0,str(R/'tools'))+from glb_shape_helpers import read_glb,write_glb,add_shape+import cadquery as cq+O=R/'mechanical/passive-board34-rearward-envelope';O.mkdir(exist_ok=True)+g,b=read_glb(R/'mechanical/side-fan-r9/side-fan-assembly.glb')+removed=[]+for i,n in enumerate(g['nodes']):+ if n.get('name','').startswith('Heatsink.ATS_'):+  removed.append(i);n.pop('mesh',None);n['children']=[]+assert removed+root=len(g['nodes']);g['nodes'].append({'name':'PassiveSink.ClearanceStudy','children':[]});g['scenes'][0]['nodes'].append(root)+lo=(20,25,12.85);hi=(96.0984,101.2,63.65)+s=cq.Workplane('XY').box(*[hi[i]-lo[i] for i in range(3)],centered=(False,False,False)).translate(lo).val()+add_shape(g,b,s,'PassiveSink.125319_3inch_CLEARANCE_ENVELOPE',(.68,.4,.08),root,'Conservative solid envelope only. Original abstraction, not manufacturer CAD. Thermal and support redesign unaccepted.')+fan=cq.Workplane('XY').box(24,48,48,centered=(False,False,False)).translate((104,0,4.6)).val()+add_shape(g,b,fan,'ShiftedFan.ConservativeEnvelope',(.35,.35,.38),root,'Provisional relocated fan/plate envelope. Original fan retained as extra conservative obstacle. Harness and carrier redesign required.')+write_glb(O/'assembly.glb',g,b)+(O/'review.json').write_text(json.dumps({'status':'unadopted-clearance-study','source':'mechanical/passive-assembly-study/vendor-model-review.json','boundsMm':list(lo)+list(hi),'nominalManufacturerEnvelopeMm':[76.0984,76.2,50.8],'nominalMassG':257.7,'existingCarrierNeedsRedesign':True,'thermalCredit':False,'purpose':'Test whether passive sink alternative can clear complete probe route before detailed mechanical redesign','boardSha256':hashlib.sha256((R/'aiflow/run/board-34.kicad_pcb').read_bytes()).hexdigest()},indent=2)+'\n')+print(O/'assembly.glb')
tools/build_passive_shifted_envelope.pyadded+21
@@ -0,0 +1,21 @@+from pathlib import Path+import sys,json,hashlib+R=Path(__file__).resolve().parents[1];sys.path.insert(0,str(R/'tools'))+from glb_shape_helpers import read_glb,write_glb,add_shape+import cadquery as cq+O=R/'mechanical/passive-board34-shifted-envelope';O.mkdir(exist_ok=True)+g,b=read_glb(R/'mechanical/side-fan-r9/side-fan-assembly.glb')+removed=[]+for i,n in enumerate(g['nodes']):+ if n.get('name','').startswith('Heatsink.ATS_'):+  removed.append(i);n.pop('mesh',None);n['children']=[]+assert removed+root=len(g['nodes']);g['nodes'].append({'name':'PassiveSink.ClearanceStudy','children':[]});g['scenes'][0]['nodes'].append(root)+lo=(20,10,12.85);hi=(96.0984,86.2,63.65)+s=cq.Workplane('XY').box(*[hi[i]-lo[i] for i in range(3)],centered=(False,False,False)).translate(lo).val()+add_shape(g,b,s,'PassiveSink.125319_3inch_CLEARANCE_ENVELOPE',(.68,.4,.08),root,'Conservative solid envelope only. Original abstraction, not manufacturer CAD. Thermal and support redesign unaccepted.')+fan=cq.Workplane('XY').box(24,48,48,centered=(False,False,False)).translate((104,0,4.6)).val()+add_shape(g,b,fan,'ShiftedFan.ConservativeEnvelope',(.35,.35,.38),root,'Provisional relocated fan/plate envelope. Original fan retained as extra conservative obstacle. Harness and carrier redesign required.')+write_glb(O/'assembly.glb',g,b)+(O/'review.json').write_text(json.dumps({'status':'unadopted-clearance-study','source':'mechanical/passive-assembly-study/vendor-model-review.json','boundsMm':list(lo)+list(hi),'nominalManufacturerEnvelopeMm':[76.0984,76.2,50.8],'nominalMassG':257.7,'existingCarrierNeedsRedesign':True,'thermalCredit':False,'purpose':'Test whether passive sink alternative can clear complete probe route before detailed mechanical redesign','boardSha256':hashlib.sha256((R/'aiflow/run/board-34.kicad_pcb').read_bytes()).hexdigest()},indent=2)+'\n')+print(O/'assembly.glb')
tools/check_side_fan_hardware.pyadded+19
@@ -0,0 +1,19 @@+"""Audit R9 nominal fasteners without regenerating the checked assembly in place."""+from pathlib import Path+import runpy,sys,json,hashlib,contextlib,io+R=Path(__file__).resolve().parents[1]+sys.path.insert(0,str(R/'tools'))+source=R/'mechanical/side-fan-r9/generator-snapshot.py'+out=R/'mechanical/hardware-audit-r9-repro';out.mkdir(exist_ok=True)+sys.argv=[str(source),'--board-glb','probing-flow/design-candidate/sidefan-r23-finished.glb','--board','probing-flow/design-candidate/sidefan-dft-r23.kicad_pcb','--out',str(out),'--rear-sink-support','--clear-board34-bodies']+with contextlib.redirect_stdout(io.StringIO()):g=runpy.run_path(str(source))+parts=g['parts'];hits=[];checked=0+for i,(an,a,ak) in enumerate(parts):+ if ak!='fastener':continue+ for j,(bn,b,bk) in enumerate(parts):+  if i==j or (bk=='fastener' and j<i) or bk not in ['fastener','structure','heatsink','interface']:continue+  checked+=1;v=a.intersect(b).Volume()+  if v>1e-5:hits.append({'a':an,'b':bn,'intersectionMm3':v})+hashfile=lambda p:hashlib.sha256(p.read_bytes()).hexdigest()+report={'status':'nominal-screen-only','pairsChecked':checked,'thresholdMm3':1e-5,'unexpectedIntersections':hits,'generatorSha256':hashfile(source),'boardSha256':hashfile(R/'aiflow/run/board-34.kicad_pcb'),'publicGlbSha256':hashfile(R/'mechanical/side-fan-r9/side-fan-assembly.glb'),'limits':'Exact nominal CAD intersections only. Threads, tolerances, assembly sequence, tool clearance, preload and retention remain unqualified.'}+(R/'mechanical/side-fan-r9/hardware-audit.json').write_text(json.dumps(report,indent=2)+'\n');print(json.dumps(report));raise SystemExit(bool(hits))