← Commit history

Merge PR #124: Wait for recreated tour frames and document small-component marking checks

John Lauer ·924644899c ·19d ago ·parent 21fbf36
2 files changed +19−3
docs/library-tours.md+14
@@ -15,3 +15,17 @@ as distinct visits. `libraries` covers native symbol/pad/model binding; `models` checks the board's actual selected models; `library-tour` records their visual review. An existing schematic's library repair is different from later requirements-driven part selection. These are AI-owned steps, not new automated qualification gates.++When marking small components, verify the actual text bounds and surface: a+successful etcher job may still overflow a 0402 body or choose a raised terminal.+Fit to the upper body with pin-1/polarity and terminal clearance, compare both+orientations, preserve the source document's materials, and retain a separate+plain model. Never impose a minimum font size that pushes text outside the part.+Narrow annular contacts may only support tiny identification text; state that limit.+Keep generated lettering as a separate STEP layer when base redistribution rights+are unresolved; do not call an etched restricted model independently authored.++After opening or recreating a Hydrogen tour tab, retry a missing frame during the+bounded readiness wait. A frame-not-found result before mounting is not a renderer+failure. Actual loading/recording errors must still fail; verify decoded frames+and advancing playback time on the published wiki video.
tools/library-tour.py+5−3
@@ -27,11 +27,13 @@ elif a.action=='serve':  print(f'Library tour serving on http://localhost:{a.port}/',flush=True);http.server.ThreadingHTTPServer(('127.0.0.1',a.port),Handler).serve_forever() elif a.action=='record':  control=pathlib.Path.home()/'.adom/hydrogen-control-url';assert control.exists(),'Hydrogen control unavailable; open the tour in Pup and use the recording controls, then verify';base=control.read_text().strip();url=f'http://localhost:{a.port}/';subprocess.run(['adom-cli','hydrogen','webview','open-or-refresh','--name','Component library tour','--url',url],check=True)- def evaluate(js):-  q={'target':url,'js':js};r=json.load(urllib.request.urlopen(urllib.request.Request(base+'/eval-in',data=json.dumps(q).encode(),headers={'Content-Type':'application/json'}),timeout=20));assert r.get('ok'),r;return r.get('value')+ def evaluate(js,waitForFrame=False):+  q={'target':url,'js':js};r=json.load(urllib.request.urlopen(urllib.request.Request(base+'/eval-in',data=json.dumps(q).encode(),headers={'Content-Type':'application/json'}),timeout=20));+  if not r.get('ok') and waitForFrame and 'frame/context not found' in str(r.get('error')):return {'ready':False}+  assert r.get('ok'),r;return r.get('value')  deadline=time.monotonic()+180  while time.monotonic()<deadline:-  state=evaluate('window.libraryTour?.stats?.() || {ready:false,error:window.libraryTour?.error}')+  state=evaluate('window.libraryTour?.stats?.() || {ready:false,error:window.libraryTour?.error}',True)   if state and state.get('error'):raise RuntimeError(state)   if state and state.get('ready'):break   time.sleep(2)