app
Fusion - the Fusion 360 Bridge
Public Made by Adomby adom
Drive Autodesk Fusion 360 from the cloud via Adom Bridge: component libraries, IPC package generation, board layout, exports (STEP/Gerbers/BOM/CPL), fast APS cloud search, and parametric modeling.
← Commit history
Add bounded obstacle planning and live calculations using the Adom activity palette
70 files changed
+4614−42
.gitignore+5BRIDGE_VERSION+1−1addin/AdomBridge/commands/activity_palette.py+17−2bridge.json+3−2contracts/describe.json+30demo/routing/README.md+8demo/routing/call.py+1−1demo/routing/crossbar/render_crossbar.py+2−2demo/routing/live_panel.py+76demo/routing/obstacles/README.md+103demo/routing/obstacles/delivery.json+13demo/routing/obstacles/fusion-obstacle-lab-v2.brd+113demo/routing/obstacles/fusion-obstacle-lab-v3.brd+113demo/routing/obstacles/fusion-obstacle-lab.brd+113demo/routing/obstacles/fusion-obstacle-live-1x.ass+15demo/routing/obstacles/fusion-obstacle-live-1x.edit.json+17demo/routing/obstacles/fusion-obstacle-live-1x.mp4demo/routing/obstacles/fusion-obstacle-live-3x.ass+15demo/routing/obstacles/fusion-obstacle-live-3x.edit.json+17demo/routing/obstacles/fusion-obstacle-live-3x.mp4demo/routing/obstacles/install-v4.json+11demo/routing/obstacles/install.json+11demo/routing/obstacles/live-planning-probes.json+249demo/routing/obstacles/player-verification.json+29demo/routing/obstacles/player-windows.json+24demo/routing/obstacles/record_obstacles.py+78demo/routing/obstacles/render_obstacles.py+35demo/routing/obstacles/requirements.json+29demo/routing/obstacles/take-01/before.json+217demo/routing/obstacles/take-01/calls.json.gzdemo/routing/obstacles/take-01/plan-1.json+122demo/routing/obstacles/take-01/plan-2.json+125demo/routing/obstacles/take-01/record-start.json+31demo/routing/obstacles/take-01/record-stop.json+28demo/routing/obstacles/take-02/calls.json.gzdemo/routing/obstacles/take-03/before.json+217demo/routing/obstacles/take-03/calls.json.gzdemo/routing/obstacles/take-03/final.json+318demo/routing/obstacles/take-03/fusion-obstacle-routed.brd+413demo/routing/obstacles/take-03/fusion-obstacle-routed.fbrddemo/routing/obstacles/take-03/plan-1.json+122demo/routing/obstacles/take-03/plan-2.json+125demo/routing/obstacles/take-03/plan-3.json+65demo/routing/obstacles/take-03/record-start.json+31demo/routing/obstacles/take-04/before.json+217demo/routing/obstacles/take-04/calls.json.gzdemo/routing/obstacles/take-04/final.json+318demo/routing/obstacles/take-04/fusion-obstacle-live-routed.brd+413demo/routing/obstacles/take-04/fusion-obstacle-live-routed.fbrddemo/routing/obstacles/take-04/panel-events.jsonl+23demo/routing/obstacles/take-04/panel-record-start.json+31demo/routing/obstacles/take-04/panel-record-stop.json+28demo/routing/obstacles/take-04/plan-1.json+122demo/routing/obstacles/take-04/plan-2.json+125demo/routing/obstacles/take-04/plan-3.json+65demo/routing/obstacles/take-04/record-start.json+31demo/routing/obstacles/take-04/record-stop.json+28demo/routing/obstacles/video-verification.json+31demo/routing/prepare_live_panel.py+23describe.py+3package.json+1−1rust/Cargo.lock+5−5rust/Cargo.toml+1−1rust/bridge/src/routing.rs+2−2rust/bridge/src/routing_planner.py+106rust/bridge/src/routing_script.py+31−21server.py+2−2skills/fusion-routing/SKILL.md+23−1tests/test_routing.py+42tools/install-routing-dev.ps1+1−1.gitignore+5@@ -15,3 +15,8 @@ demo/routing/videos/window-*.mp4 # Preserve raw crossover take and full call log locally; publish compressed evidence. demo/routing/crossbar/take-*/window-*.mp4 demo/routing/crossbar/take-*/calls.json++# Raw board and palette captures remain local; final videos and compact evidence are versioned.+demo/routing/obstacles/take-*/window-*.mp4+demo/routing/obstacles/take-*/calls.json+demo/routing/obstacles/*screenshot*.json
BRIDGE_VERSION+1−1@@ -1 +1 @@-1.10.0-dev.routing.2+1.10.0-dev.routing.4
addin/AdomBridge/commands/activity_palette.py+17−2@@ -83,7 +83,7 @@ def _html(title, detail, percent, eta_sec, tone): } -def _shell_html(initial_payload=None):+def _shell_html(initial_payload=None, event_stream_url=None): """The banner page, written ONCE. Every later update arrives through palette.sendInfoToHTML("update", json) and is applied by the page's own script. @@ -109,12 +109,18 @@ def _shell_html(initial_payload=None): .meta{display:flex;justify-content:space-between;font-size:11px;color:#8b949e;font-variant-numeric:tabular-nums} .warn{margin-top:10px;padding:8px 10px;border-left:3px solid #00b8b1;background:#161b22;border-radius:6px;font-size:12px} .warn[hidden]{display:none}+ .routing[hidden]{display:none}+ .routing{border-top:1px solid #30363d;margin-top:12px;padding-top:4px}+ .routing h2{font-size:12px;color:#00b8b1;margin:10px 0 3px}+ .routing p{font-size:13px;white-space:pre-line;margin:0;color:#c9d1d9}+ .connection{color:#8b949e;font-size:11px;margin-top:8px} </style></head><body><div class="wrap"> <div class="brand"><span class="mark">%(logo)s</span><span class="dot" id="dot"></span><span class="brandtxt">is driving Fusion</span></div> <h1 id="title">Working</h1> <div class="detail" id="detail"></div> <div class="track"><div class="fill" id="fill"></div></div> <div class="meta"><span id="pct">0%%</span><span id="eta"></span></div>+ <div class="routing" id="routing" hidden><h2>Selected connection</h2><p id="routeConnection"></p><h2>Calculated route</h2><p id="routePlan"></p><h2>Measured checks</h2><p id="routeChecks"></p><h2>Recent operations</h2><p id="routeEvents"></p><div class="connection" id="streamStatus"></div></div> <div class="warn" id="warn">Please do not click, type or close documents in Fusion until this finishes. Your other apps are unaffected.</div> </div> <script>@@ -123,6 +129,9 @@ def _shell_html(initial_payload=None): var c=COLORS[d.tone]||COLORS.working; document.getElementById('title').textContent=d.title||'Working'; document.getElementById('detail').textContent=d.detail||'';+ var route=d.routing||{};+ document.getElementById('routing').hidden=!d.routing;+ ['Connection','Plan','Checks','Events'].forEach(function(k){document.getElementById('route'+k).textContent=route[k.toLowerCase()]||'';}); var pct=Math.max(0,Math.min(100,parseInt(d.percent||0,10)||0)); var fill=document.getElementById('fill'); fill.style.width=pct+'%%'; fill.style.background=c; document.getElementById('dot').style.background=c;@@ -135,7 +144,13 @@ def _shell_html(initial_payload=None): return 'OK'; }}; try{ apply(%(initial)s); }catch(e){}- </script></body></html>""" % {"logo": ADOM_LOGO_SVG, "initial": (initial_payload or "{}").replace("</", "<\\/")}+ var streamUrl=%(stream_url)s;+ if(streamUrl){+ var stream=new EventSource(streamUrl);+ stream.onmessage=function(e){try{var d=JSON.parse(e.data);apply(d);document.getElementById('streamStatus').textContent='Live from Adom container / event '+d.sequence;fetch('ack',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({sequence:d.sequence})});}catch(err){document.getElementById('streamStatus').textContent='Display error: '+err;}};+ stream.onerror=function(){document.getElementById('streamStatus').textContent='Connection interrupted; reconnecting. Results may be stale.';};+ }+ </script></body></html>""" % {"logo": ADOM_LOGO_SVG, "initial": (initial_payload or "{}").replace("</", "<\\/"), "stream_url": __import__("json").dumps(event_stream_url)} def _payload(title, detail, percent, eta_sec, tone):
bridge.json+3−2@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "fusion360", "displayName": "Autodesk Fusion 360",- "version": "1.10.0-dev.routing.2",+ "version": "1.10.0-dev.routing.4", "description": "Drive Autodesk Fusion 360 from the cloud: launch Fusion, electronics board layout, design rules, exports (STEP/IGES/STL/3MF/USDZ/OBJ/DXF/DWG/Gerbers/BOM/CPL), fast APS server-indexed cloud search plus browse/recent/file-info/versions, cloud file download/upload and folder creation, and in-app parametric modeling (fusion_run_modeling_script). Never-charge: APS calls are capped to the free tier.", "homepage": "https://wiki.adom.inc/adom/fusion-bridge", "author": "Adom Inc.",@@ -80,7 +80,8 @@ "fusion_show_schematic", "fusion_start", "fusion_stop",- "fusion_walk_cloud_tree"+ "fusion_walk_cloud_tree",+ "fusion_plan_route" ], "dependencies": {}, "category": "CAD",
contracts/describe.json+30@@ -1868,6 +1868,36 @@ "summary": "PRE-FLIGHT for a library import: does NO work and changes nothing. Reports whether Fusion is installed, running, or needs its add-in loaded (with a plain-language message you can show the user), plus a per-stage plan with MEASURED per-machine time estimates scaled to the number of parts you are sending - a multi-part library does one STEP import per part, which is the slowest stage, so the estimate grows with the library. Call this FIRST so the wiki can render the summary and the progress bar's steps, then run the import and poll fusion_prove_result, which reports the SAME stage names.", "timeoutSeconds": 20 },+ {+ "example": {},+ "input": {+ "allowVias": "bool default true",+ "boardId": "required str",+ "expectDocument": "required str",+ "expectedRevision": "required str",+ "fromPad": "required str",+ "grid": "mm 0.1..5 default 0.5",+ "maxNodes": "int 1..100000 default 25000",+ "net": "required str",+ "timeoutMs": "int 10..5000 default 3000",+ "toPad": "required str",+ "viaCost": "mm-equivalent cost default 5",+ "viaDiameter": "mm default 0.6",+ "viaDrill": "mm default 0.3",+ "width": "mm default 0.25"+ },+ "longRunning": false,+ "name": "fusion_plan_route",+ "output": {+ "mutated": "false",+ "plan": "{items,route,planner}",+ "revision": "str",+ "success": "bool"+ },+ "statusVerb": "fusion_routing_state",+ "summary": "Calculate a read-only, bounded orthogonal A* path between two pads on a live two-layer board. Uses existing copper and the shared conservative clearance model. Returns explicit route args for route_net; native DRC is still required after mutation.",+ "timeoutSeconds": 60+ }, { "example": { "libraryPath": "C:/Temp/PART.lbr"
demo/routing/README.md+8@@ -141,3 +141,11 @@ The adjacent `.ass` and `.edit.json` preserve captions and edit provenance. The renderer checks the output dimensions and duration and fully decodes it; results are in `evidence/showcase-video-validation.json`. Delivery target: `C:/Users/john/Documents/Adom Routing Demos/fusion-routing-showcase-3x.mp4`.++## Obstacle-aware planning extension++Development build `1.10.0-dev.routing.4` adds `fusion_plan_route`, a bounded+read-only orthogonal A* planner using the same two-layer clearance model.+It calculates waypoints from live pads and existing copper. See+`obstacles/README.md` for inputs, limits, native insertion regression and+the three-case live demonstration. This extends the explicit-route APIs above.
demo/routing/call.py+1−1@@ -7,7 +7,7 @@ ROOT=Path(__file__).resolve().parents[2] def call(verb,args,target='AdomLapper',script_transport=False): if script_transport:- source=(ROOT/'rust/bridge/src/routing_script.py').read_text()+ source='\n'.join((ROOT/'rust/bridge/src'/name).read_text() for name in ('routing_script.py','routing_planner.py')) script='import json\nexec('+repr(source)+')\nresult=handle(app,json.loads('+repr(json.dumps(args))+'),'+repr(verb.removeprefix('fusion_'))+')\n' verb='fusion_run_modeling_script'; args={'script':script,'expectDocument':args.get('expectDocument')} cp=subprocess.run(['adom-bridge','--target',target,'--ai-thread','Fusion trace routing',verb,json.dumps(args)],capture_output=True,text=True,timeout=190)
demo/routing/crossbar/render_crossbar.py+2−2@@ -15,13 +15,13 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text ''' def stamp(t): cs=round(t*100);return f'{cs//360000}:{cs//6000%60:02d}:{cs//100%60:02d}.{cs%100:02d}'-def render(name,source,start,end,cues,side,title,hold=4,keep=None,action_seconds=None,frame_ranges=None):+def render(name,source,start,end,cues,side,title,hold=4,keep=None,action_seconds=None,frame_ranges=None,capture_note="Idle waits trimmed"): duration=(action_seconds if action_seconds is not None else (sum(b-a for a,b in keep) if keep else end-start)/3)+hold events=[] def text(t0,t1,s):events.append(f'Dialogue: 0,{stamp(t0)},{stamp(t1)},Main,,0,0,0,,{s}') text(0,duration,r'{\an7\pos(34,16)\fs38\b1\c&H00E5CF65&}CODEX ASTRA IN ADOM HYDROGEN'+r'{\c&H00FFFFFF&} / '+title) text(0,duration,r'{\an7\pos(1490,125)\fs48\b1\c&H00E5CF65&}3x SPEED')- text(0,duration,r'{\an7\pos(1490,197)\fs28}Native Fusion capture\NIdle waits trimmed')+ text(0,duration,r'{\an7\pos(1490,197)\fs28}Native Fusion capture\N'+capture_note) for y,heading,body in side: text(0,duration,fr'{{\an7\pos(1490,{y})\fs32\b1\c&H00E5CF65&}}'+heading) text(0,duration,fr'{{\an7\pos(1490,{y+46})\fs27}}'+body)
demo/routing/live_panel.pyadded+76@@ -0,0 +1,76 @@+"""Container-hosted SSE for the existing Adom activity palette, with DOM acknowledgments."""+import ast,json,threading,time+from http.server import BaseHTTPRequestHandler,ThreadingHTTPServer+from pathlib import Path+from urllib.request import Request,urlopen+ROOT=Path(__file__).resolve().parents[2]+PORT=8893+URL=f'http://localhost:{PORT}/'++def shell_html():+ # Reuse the bridge's branding/component without importing adsk in the container.+ tree=ast.parse((ROOT/'addin/AdomBridge/commands/activity_palette.py').read_text())+ nodes=[n for n in tree.body if isinstance(n,ast.FunctionDef) and n.name=='_shell_html' or isinstance(n,ast.Assign) and any(isinstance(t,ast.Name) and t.id=='ADOM_LOGO_SVG' for t in n.targets)]+ ns={};exec(compile(ast.Module(body=nodes,type_ignores=[]),'<activity palette>','exec'),ns)+ return ns['_shell_html'](json.dumps({'title':'Connecting to Astra routing','detail':'Waiting for measured results','tone':'done'}),'events').encode()++class Feed:+ def __init__(self):+ self.state={};self.sequence=0;self.ack=0;self.changed=threading.Condition();self.page=shell_html()+ def update(self,state):+ with self.changed:+ self.sequence+=1;self.state={**state,'sequence':self.sequence};self.changed.notify_all();return self.sequence+feed=Feed()+class Handler(BaseHTTPRequestHandler):+ def log_message(self,*args):pass+ def do_GET(self):+ if self.path=='/events':+ self.send_response(200);self.send_header('Content-Type','text/event-stream');self.send_header('Cache-Control','no-cache');self.end_headers();last=-1+ try:+ while True:+ with feed.changed:+ if last==feed.sequence:feed.changed.wait(10)+ state=feed.state.copy();seq=feed.sequence+ self.wfile.write(('data: '+json.dumps(state)+'\n\n').encode() if seq!=last else b': heartbeat\n\n');self.wfile.flush();last=seq+ except (BrokenPipeError,ConnectionResetError):pass+ return+ data=json.dumps({'sequence':feed.sequence,'ack':feed.ack,'state':feed.state}).encode() if self.path=='/state' else feed.page+ self.send_response(200);self.send_header('Content-Type','application/json' if self.path=='/state' else 'text/html; charset=utf-8');self.send_header('Content-Length',str(len(data)));self.end_headers();self.wfile.write(data)+ def do_POST(self):+ data=json.loads(self.rfile.read(int(self.headers['Content-Length'])))+ if self.path=='/ack':+ with feed.changed:feed.ack=max(feed.ack,int(data['sequence']));feed.changed.notify_all()+ out={'ack':feed.ack}+ elif self.path=='/state':out={'sequence':feed.update(data)}+ else:self.send_error(404);return+ body=json.dumps(out).encode();self.send_response(200);self.send_header('Content-Length',str(len(body)));self.end_headers();self.wfile.write(body)++def publish(state,wait=True):+ seq=json.load(urlopen(Request(URL+'state',data=json.dumps(state).encode(),headers={'Content-Type':'application/json'}),timeout=3))['sequence']+ if wait:+ end=time.monotonic()+5+ while time.monotonic()<end:+ status=json.load(urlopen(URL+'state',timeout=2))+ if status['ack']>=seq:return {'success':True,'sequence':seq,'domAcknowledged':True}+ time.sleep(.05)+ raise RuntimeError(f'Adom palette did not acknowledge event {seq}; stop before next copper edit')+ return {'success':True,'sequence':seq}++class LivePanel:+ def __init__(self,invoke,document,events_path=None,palette_hwnd=None):self.invoke=invoke;self.document=document;self.state={};self.events=[];self.events_path=events_path;self.palette_hwnd=palette_hwnd+ def update(self,create=False,event=None,**state):+ if self.palette_hwnd is not None:+ windows=self.invoke('desktop_list_windows',{})['windows']+ window=next((w for w in windows if w['hwnd']==self.palette_hwnd),None)+ if window is None or window['minimized']:raise RuntimeError('Adom palette was closed or minimized; stop this demo')+ self.state.update(state)+ if event:self.events.append(event)+ self.state['events']='\n'.join(self.events[-2:])+ payload={'title':'Astra: '+self.state.get('status','Routing'),'detail':'Codex Astra in Adom Hydrogen / bounded two-layer A*','percent':self.state.get('percent',0),'tone':'failed' if self.state.get('failed') else 'done' if self.state.get('percent')==100 else 'working','routing':{k:self.state.get(k,'') for k in ['connection','plan','checks','events']}}+ start=time.time();result=publish(payload)+ if self.events_path:+ with Path(self.events_path).open('a') as f:f.write(json.dumps({'start':start,'end':time.time(),'payload':payload,'result':result})+'\n')+ return result++if __name__=='__main__':+ print(URL,flush=True);ThreadingHTTPServer(('0.0.0.0',PORT),Handler).serve_forever()
demo/routing/obstacles/README.mdadded+103@@ -0,0 +1,103 @@+# Live obstacle-aware Fusion routing++The new `fusion_plan_route` verb calculates an explicit path between two named+pads from a fresh snapshot of the active Fusion board. It runs bounded,+orthogonal two-layer A* using the same conservative clearance model as+`fusion_route_net`. It does not use Freerouting or another external router.+Planning is read-only and returns the input revision plus `plan.route` and+`plan.items`; commits still use the existing revision-guarded mutation verb.++Required inputs: `expectDocument`, `boardId`, `expectedRevision`, `net`,+`fromPad`, `toPad`. Defaults: 0.25 mm trace, 0.6 mm via / 0.3 mm drill,+0.5 mm grid, vias allowed, via cost equivalent to 5 mm of trace, 25,000+expanded nodes and 3,000 ms time limit. Grid ranges from 0.1 to 5 mm; limits+are capped at 100,000 nodes / 5,000 ms. `allowVias:false` finds a same-layer+route. Returned paths are validated again with the shared geometric preflight.++The isolated test board has three SMD pad pairs and two existing copper+barriers on different layers. No routing waypoints are supplied to the planner.+The first pair demonstrates a same-layer detour; the second allows vias; the+third has a clear direct route. Both original barriers must remain unchanged.++## Native insertion regression++The first live take stopped at a read-back mismatch: inserting a nominal 0.6 mm+via at x=21, y=20 beside a 1 mm top-layer barrier at x=22 caused Fusion to push+the barrier. The failure was retained in `take-01/`; no mutation was replayed.++The corrected build sets `CHANGE DRILL` before `VIA`, instead of inserting a+via using the previous drill setting and changing it afterward. It also uses a+conservative via insertion radius of `max(diameter/2, drill+0.3 mm)` for the+preflight and search. This reserves extra space for native insertion behavior.+The regression test rejects the original tight insertion point. Exact copper+read-back remains essential: nominal exported dimensions alone do not model+every aspect of Fusion's native router or effective design-rule dimensions.++Autodesk documents the [shared drill setting and design-rule-dependent via+size](https://help.autodesk.com/cloudhelp/ENU/Fusion-ECAD/files/ECD-CLI-V.htm).+This source supports the drill-setting change; the observed shove and extra+clearance regression come from the live test evidence.++## Scope++This is a bounded two-pad path planner, not a full PCB autorouter. It does not+rip up or shove existing copper, optimize routing order across all nets, route+differential pairs, tune lengths, or model polygons and arbitrary stackups.+It retains the rectangular, two-layer, straight-copper restrictions of the+existing preflight. It may reject legal paths conservatively or exhaust its+grid/node/time budget. Final acceptance always uses native Autodesk DRC.++The planner's grid search can find different paths at different resolutions;+it does not guarantee the globally best manufacturable layout. A failed+mutation can leave partial copper or a native shove, so inspect current state+before deciding how to recover. Planning failures do not create copper.++## Verified live result and videos++`take-04/final.json` records all three pad pairs connected, 10 total segments+(8 added, 2 original barriers), 2 vias and native Autodesk DRC with zero+errors, warnings and airwires. The calculated lengths were 54, 40 and 40 mm.+`take-03` also passed routing; its recorder failed because the Fusion window+was minimized. The runner now checks window and capture dimensions before+creating copper and finalizes both recordings in `finally`.++`fusion-obstacle-live-3x.mp4` is the 19.93-second share cut;+`fusion-obstacle-live-1x.mp4` is the 49.83-second version for reading live+results. Both are 1920×1080, 30 fps and fully decoded successfully. Both were+delivered to `C:/Users/john/Documents/Adom Routing Demos`; the normal-speed+file was opened and visually verified in Windows Media Player.++The existing **AdomActivityPalette** is reused, including its branding and+close handler. Its shared `_shell_html` component has optional routing fields+and an SSE feed. `../live_panel.py` hosts that page and feed in the container;+Windows Fusion reaches it at the verified `http://localhost:8893/` endpoint.+The native message API returned empty acknowledgments on this Fusion instance,+so the demo uses SSE instead of repeated page reloads. Each displayed event+acknowledges DOM application before the next copper edit. A missing acknowledgment+stops the demo. This is presentation evidence, separate from native PCB validation.++AB records the Fusion editor and its owned palette as two native window captures,+then the renderer aligns them using call-start timestamps. Initialization can+introduce a fraction-of-a-second offset; the edit manifest records this limit.+The live text is recorded video, not reconstructed captions. The short take+keeps calculation/check displays, trims part of the completed-state tail and+adds a five-second final hold. `take-04/panel-events.jsonl` is a polling record+started during this take; future runs log every publish and acknowledgment.++To reproduce after preparing an isolated unrouted board and discovering HWNDs:++```sh+python3 demo/routing/live_panel.py+# In another terminal:+python3 demo/routing/prepare_live_panel.py --document YOUR_EXACT_BOARD+python3 demo/routing/obstacles/record_obstacles.py \+ --document YOUR_EXACT_BOARD --take YOUR_NEW_TAKE \+ --hwnd FUSION_HWND --palette-hwnd ADOM_PALETTE_HWND+```++Verify both windows visually and fit the palette beside the board before recording.+`prepare_live_panel.py` changes the existing palette URL once and preserves its+close behavior. Keep the container server alive while that display is in use.+The optional component changes do not require replacing the loaded add-in or+restarting Fusion. The installed native routing runtime remains+`1.10.0-dev.routing.4`, pinned for development.
demo/routing/obstacles/delivery.jsonadded+13@@ -0,0 +1,13 @@+{+ "_hint": "Wrote 2 file(s) to the LAPTOP (Windows host), NOT to your container/WSL. Folder: C:/Users/john/Documents/Adom Routing Demos \u00b7 exact paths are in destinationPaths[]. VERIFY: adom-bridge list_dir '{\"path\":\"C:/Users/john/Documents/Adom Routing Demos\"}' READ ONE BACK: adom-bridge pull_file '{\"path\":\"C:/Users/john/Documents/Adom Routing Demos/fusion-obstacle-live-3x.mp4\"}'. To control where files land, pass dest:'C:/abs/path' (absolute) or destinationFolder:'subdir' (relative to the laptop Downloads default). NOTE: send_files only COPIES bytes \u2014 it does NOT install or register a bridge. To make a bridge appear (capsule in the ab GUI + verbs routable), use bridge_install '{\"manifestUrl\":\"https://wiki.adom.inc/...<bridge>-manifest.json\"}', then confirm with bridge_list.",+ "destinationPaths": [+ "C:/Users/john/Documents/Adom Routing Demos/fusion-obstacle-live-3x.mp4",+ "C:/Users/john/Documents/Adom Routing Demos/fusion-obstacle-live-1x.mp4"+ ],+ "durationMs": 63,+ "error": null,+ "filesReceived": 2,+ "savedToDir": "C:/Users/john/Documents/Adom Routing Demos",+ "status": "ok",+ "success": true+}
demo/routing/obstacles/fusion-obstacle-lab-v2.brdadded+113@@ -0,0 +1,113 @@+<?xml version="1.0" encoding="utf-8"?>+<!DOCTYPE eagle SYSTEM "eagle.dtd">+<eagle version="9.6.2">+ <drawing>+ <settings />+ <grid distance="0.1" unitdist="mm" unit="mm" style="lines" multiple="1" display="no" altdistance="0.01" altunitdist="mm" altunit="mm" />+ <layers>+ <layer number="1" name="Top" color="4" fill="1" visible="yes" active="yes" />+ <layer number="16" name="Bottom" color="1" fill="1" visible="yes" active="yes" />+ <layer number="17" name="Pads" color="2" fill="1" visible="yes" active="yes" />+ <layer number="18" name="Vias" color="2" fill="1" visible="yes" active="yes" />+ <layer number="19" name="Unrouted" color="6" fill="1" visible="yes" active="yes" />+ <layer number="20" name="Dimension" color="15" fill="1" visible="yes" active="yes" />+ <layer number="21" name="tPlace" color="7" fill="1" visible="yes" active="yes" />+ <layer number="22" name="bPlace" color="7" fill="1" visible="yes" active="yes" />+ <layer number="23" name="tOrigins" color="15" fill="1" visible="yes" active="yes" />+ <layer number="24" name="bOrigins" color="15" fill="1" visible="yes" active="yes" />+ <layer number="25" name="tNames" color="7" fill="1" visible="yes" active="yes" />+ <layer number="26" name="bNames" color="7" fill="1" visible="yes" active="yes" />+ <layer number="27" name="tValues" color="7" fill="1" visible="yes" active="yes" />+ <layer number="28" name="bValues" color="7" fill="1" visible="yes" active="yes" />+ <layer number="29" name="tStop" color="7" fill="3" visible="no" active="yes" />+ <layer number="30" name="bStop" color="7" fill="6" visible="no" active="yes" />+ <layer number="31" name="tCream" color="7" fill="4" visible="no" active="yes" />+ <layer number="32" name="bCream" color="7" fill="5" visible="no" active="yes" />+ <layer number="33" name="tFinish" color="6" fill="3" visible="no" active="yes" />+ <layer number="34" name="bFinish" color="6" fill="6" visible="no" active="yes" />+ <layer number="35" name="tGlue" color="7" fill="4" visible="no" active="yes" />+ <layer number="36" name="bGlue" color="7" fill="5" visible="no" active="yes" />+ <layer number="37" name="tTest" color="7" fill="1" visible="no" active="yes" />+ <layer number="38" name="bTest" color="7" fill="1" visible="no" active="yes" />+ <layer number="39" name="tKeepout" color="4" fill="11" visible="no" active="yes" />+ <layer number="40" name="bKeepout" color="1" fill="11" visible="no" active="yes" />+ <layer number="41" name="tRestrict" color="4" fill="10" visible="no" active="yes" />+ <layer number="42" name="bRestrict" color="1" fill="10" visible="no" active="yes" />+ <layer number="43" name="vRestrict" color="2" fill="10" visible="no" active="yes" />+ <layer number="44" name="Drills" color="7" fill="1" visible="no" active="yes" />+ <layer number="45" name="Holes" color="7" fill="1" visible="no" active="yes" />+ <layer number="46" name="Milling" color="3" fill="1" visible="no" active="yes" />+ <layer number="47" name="Measures" color="7" fill="1" visible="no" active="yes" />+ <layer number="48" name="Document" color="7" fill="1" visible="yes" active="yes" />+ <layer number="49" name="Reference" color="7" fill="1" visible="yes" active="yes" />+ <layer number="91" name="Nets" color="2" fill="1" visible="yes" active="yes" />+ <layer number="92" name="Busses" color="1" fill="1" visible="yes" active="yes" />+ <layer number="93" name="Pins" color="2" fill="1" visible="no" active="yes" />+ <layer number="94" name="Symbols" color="4" fill="1" visible="yes" active="yes" />+ <layer number="95" name="Names" color="7" fill="1" visible="yes" active="yes" />+ <layer number="96" name="Values" color="7" fill="1" visible="yes" active="yes" />+ <layer number="97" name="Info" color="7" fill="1" visible="yes" active="yes" />+ <layer number="98" name="Guide" color="6" fill="1" visible="yes" active="yes" />+ </layers>+ <board>+ <plain>+ <wire x1="0" y1="0" x2="50" y2="0" width="0" layer="20" />+ <wire x1="50" y1="0" x2="50" y2="40" width="0" layer="20" />+ <wire x1="50" y1="40" x2="0" y2="40" width="0" layer="20" />+ <wire x1="0" y1="40" x2="0" y2="0" width="0" layer="20" />+ <text x="7" y="36" size="1.5" layer="21">FUSION / OBSTACLE ROUTING</text>+ </plain>+ <libraries>+ <library name="ObstacleLab">+ <packages>+ <package name="SMD_TESTPOINT">+ <smd name="1" x="0" y="0" dx="1.5" dy="1.5" layer="1" roundness="20" />+ </package>+ </packages>+ </library>+ </libraries>+ <attributes />+ <variantdefs />+ <classes>+ <class number="0" name="default" width="0.25" drill="0.3" />+ </classes>+ <designrules name="RoutingFixture">+ <param name="layerSetup" value="(1*16)" />+ <param name="mdWireWire" value="0.2mm" />+ <param name="mdWirePad" value="0.2mm" />+ <param name="mdWireVia" value="0.2mm" />+ <param name="msWidth" value="0.2mm" />+ <param name="msDrill" value="0.3mm" />+ <param name="mdCopperDimension" value="0.5mm" />+ </designrules>+ <elements>+ <element name="L1" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="5" y="8" />+ <element name="R1" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="45" y="8" />+ <element name="L2" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="5" y="20" />+ <element name="R2" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="45" y="20" />+ <element name="L3" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="5" y="32" />+ <element name="R3" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="45" y="32" />+ </elements>+ <signals>+ <signal name="ROUTE_1">+ <contactref element="L1" pad="1" />+ <contactref element="R1" pad="1" />+ </signal>+ <signal name="ROUTE_2">+ <contactref element="L2" pad="1" />+ <contactref element="R2" pad="1" />+ </signal>+ <signal name="ROUTE_3">+ <contactref element="L3" pad="1" />+ <contactref element="R3" pad="1" />+ </signal>+ <signal name="TOP_BARRIER">+ <wire x1="22" y1="2" x2="22" y2="28" width="1" layer="1" />+ </signal>+ <signal name="BOTTOM_BARRIER">+ <wire x1="32" y1="12" x2="32" y2="37" width="1" layer="16" />+ </signal>+ </signals>+ </board>+ </drawing>+</eagle>
demo/routing/obstacles/fusion-obstacle-lab-v3.brdadded+113@@ -0,0 +1,113 @@+<?xml version="1.0" encoding="utf-8"?>+<!DOCTYPE eagle SYSTEM "eagle.dtd">+<eagle version="9.6.2">+ <drawing>+ <settings />+ <grid distance="0.1" unitdist="mm" unit="mm" style="lines" multiple="1" display="no" altdistance="0.01" altunitdist="mm" altunit="mm" />+ <layers>+ <layer number="1" name="Top" color="4" fill="1" visible="yes" active="yes" />+ <layer number="16" name="Bottom" color="1" fill="1" visible="yes" active="yes" />+ <layer number="17" name="Pads" color="2" fill="1" visible="yes" active="yes" />+ <layer number="18" name="Vias" color="2" fill="1" visible="yes" active="yes" />+ <layer number="19" name="Unrouted" color="6" fill="1" visible="yes" active="yes" />+ <layer number="20" name="Dimension" color="15" fill="1" visible="yes" active="yes" />+ <layer number="21" name="tPlace" color="7" fill="1" visible="yes" active="yes" />+ <layer number="22" name="bPlace" color="7" fill="1" visible="yes" active="yes" />+ <layer number="23" name="tOrigins" color="15" fill="1" visible="yes" active="yes" />+ <layer number="24" name="bOrigins" color="15" fill="1" visible="yes" active="yes" />+ <layer number="25" name="tNames" color="7" fill="1" visible="yes" active="yes" />+ <layer number="26" name="bNames" color="7" fill="1" visible="yes" active="yes" />+ <layer number="27" name="tValues" color="7" fill="1" visible="yes" active="yes" />+ <layer number="28" name="bValues" color="7" fill="1" visible="yes" active="yes" />+ <layer number="29" name="tStop" color="7" fill="3" visible="no" active="yes" />+ <layer number="30" name="bStop" color="7" fill="6" visible="no" active="yes" />+ <layer number="31" name="tCream" color="7" fill="4" visible="no" active="yes" />+ <layer number="32" name="bCream" color="7" fill="5" visible="no" active="yes" />+ <layer number="33" name="tFinish" color="6" fill="3" visible="no" active="yes" />+ <layer number="34" name="bFinish" color="6" fill="6" visible="no" active="yes" />+ <layer number="35" name="tGlue" color="7" fill="4" visible="no" active="yes" />+ <layer number="36" name="bGlue" color="7" fill="5" visible="no" active="yes" />+ <layer number="37" name="tTest" color="7" fill="1" visible="no" active="yes" />+ <layer number="38" name="bTest" color="7" fill="1" visible="no" active="yes" />+ <layer number="39" name="tKeepout" color="4" fill="11" visible="no" active="yes" />+ <layer number="40" name="bKeepout" color="1" fill="11" visible="no" active="yes" />+ <layer number="41" name="tRestrict" color="4" fill="10" visible="no" active="yes" />+ <layer number="42" name="bRestrict" color="1" fill="10" visible="no" active="yes" />+ <layer number="43" name="vRestrict" color="2" fill="10" visible="no" active="yes" />+ <layer number="44" name="Drills" color="7" fill="1" visible="no" active="yes" />+ <layer number="45" name="Holes" color="7" fill="1" visible="no" active="yes" />+ <layer number="46" name="Milling" color="3" fill="1" visible="no" active="yes" />+ <layer number="47" name="Measures" color="7" fill="1" visible="no" active="yes" />+ <layer number="48" name="Document" color="7" fill="1" visible="yes" active="yes" />+ <layer number="49" name="Reference" color="7" fill="1" visible="yes" active="yes" />+ <layer number="91" name="Nets" color="2" fill="1" visible="yes" active="yes" />+ <layer number="92" name="Busses" color="1" fill="1" visible="yes" active="yes" />+ <layer number="93" name="Pins" color="2" fill="1" visible="no" active="yes" />+ <layer number="94" name="Symbols" color="4" fill="1" visible="yes" active="yes" />+ <layer number="95" name="Names" color="7" fill="1" visible="yes" active="yes" />+ <layer number="96" name="Values" color="7" fill="1" visible="yes" active="yes" />+ <layer number="97" name="Info" color="7" fill="1" visible="yes" active="yes" />+ <layer number="98" name="Guide" color="6" fill="1" visible="yes" active="yes" />+ </layers>+ <board>+ <plain>+ <wire x1="0" y1="0" x2="50" y2="0" width="0" layer="20" />+ <wire x1="50" y1="0" x2="50" y2="40" width="0" layer="20" />+ <wire x1="50" y1="40" x2="0" y2="40" width="0" layer="20" />+ <wire x1="0" y1="40" x2="0" y2="0" width="0" layer="20" />+ <text x="7" y="36" size="1.5" layer="21">FUSION / OBSTACLE ROUTING</text>+ </plain>+ <libraries>+ <library name="ObstacleLab">+ <packages>+ <package name="SMD_TESTPOINT">+ <smd name="1" x="0" y="0" dx="1.5" dy="1.5" layer="1" roundness="20" />+ </package>+ </packages>+ </library>+ </libraries>+ <attributes />+ <variantdefs />+ <classes>+ <class number="0" name="default" width="0.25" drill="0.3" />+ </classes>+ <designrules name="RoutingFixture">+ <param name="layerSetup" value="(1*16)" />+ <param name="mdWireWire" value="0.2mm" />+ <param name="mdWirePad" value="0.2mm" />+ <param name="mdWireVia" value="0.2mm" />+ <param name="msWidth" value="0.2mm" />+ <param name="msDrill" value="0.3mm" />+ <param name="mdCopperDimension" value="0.5mm" />+ </designrules>+ <elements>+ <element name="L1" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="5" y="8" />+ <element name="R1" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="45" y="8" />+ <element name="L2" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="5" y="20" />+ <element name="R2" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="45" y="20" />+ <element name="L3" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="5" y="32" />+ <element name="R3" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="45" y="32" />+ </elements>+ <signals>+ <signal name="ROUTE_1">+ <contactref element="L1" pad="1" />+ <contactref element="R1" pad="1" />+ </signal>+ <signal name="ROUTE_2">+ <contactref element="L2" pad="1" />+ <contactref element="R2" pad="1" />+ </signal>+ <signal name="ROUTE_3">+ <contactref element="L3" pad="1" />+ <contactref element="R3" pad="1" />+ </signal>+ <signal name="TOP_BARRIER">+ <wire x1="22" y1="2" x2="22" y2="28" width="1" layer="1" />+ </signal>+ <signal name="BOTTOM_BARRIER">+ <wire x1="32" y1="12" x2="32" y2="37" width="1" layer="16" />+ </signal>+ </signals>+ </board>+ </drawing>+</eagle>
demo/routing/obstacles/fusion-obstacle-lab.brdadded+113@@ -0,0 +1,113 @@+<?xml version="1.0" encoding="utf-8"?>+<!DOCTYPE eagle SYSTEM "eagle.dtd">+<eagle version="9.6.2">+ <drawing>+ <settings />+ <grid distance="0.1" unitdist="mm" unit="mm" style="lines" multiple="1" display="no" altdistance="0.01" altunitdist="mm" altunit="mm" />+ <layers>+ <layer number="1" name="Top" color="4" fill="1" visible="yes" active="yes" />+ <layer number="16" name="Bottom" color="1" fill="1" visible="yes" active="yes" />+ <layer number="17" name="Pads" color="2" fill="1" visible="yes" active="yes" />+ <layer number="18" name="Vias" color="2" fill="1" visible="yes" active="yes" />+ <layer number="19" name="Unrouted" color="6" fill="1" visible="yes" active="yes" />+ <layer number="20" name="Dimension" color="15" fill="1" visible="yes" active="yes" />+ <layer number="21" name="tPlace" color="7" fill="1" visible="yes" active="yes" />+ <layer number="22" name="bPlace" color="7" fill="1" visible="yes" active="yes" />+ <layer number="23" name="tOrigins" color="15" fill="1" visible="yes" active="yes" />+ <layer number="24" name="bOrigins" color="15" fill="1" visible="yes" active="yes" />+ <layer number="25" name="tNames" color="7" fill="1" visible="yes" active="yes" />+ <layer number="26" name="bNames" color="7" fill="1" visible="yes" active="yes" />+ <layer number="27" name="tValues" color="7" fill="1" visible="yes" active="yes" />+ <layer number="28" name="bValues" color="7" fill="1" visible="yes" active="yes" />+ <layer number="29" name="tStop" color="7" fill="3" visible="no" active="yes" />+ <layer number="30" name="bStop" color="7" fill="6" visible="no" active="yes" />+ <layer number="31" name="tCream" color="7" fill="4" visible="no" active="yes" />+ <layer number="32" name="bCream" color="7" fill="5" visible="no" active="yes" />+ <layer number="33" name="tFinish" color="6" fill="3" visible="no" active="yes" />+ <layer number="34" name="bFinish" color="6" fill="6" visible="no" active="yes" />+ <layer number="35" name="tGlue" color="7" fill="4" visible="no" active="yes" />+ <layer number="36" name="bGlue" color="7" fill="5" visible="no" active="yes" />+ <layer number="37" name="tTest" color="7" fill="1" visible="no" active="yes" />+ <layer number="38" name="bTest" color="7" fill="1" visible="no" active="yes" />+ <layer number="39" name="tKeepout" color="4" fill="11" visible="no" active="yes" />+ <layer number="40" name="bKeepout" color="1" fill="11" visible="no" active="yes" />+ <layer number="41" name="tRestrict" color="4" fill="10" visible="no" active="yes" />+ <layer number="42" name="bRestrict" color="1" fill="10" visible="no" active="yes" />+ <layer number="43" name="vRestrict" color="2" fill="10" visible="no" active="yes" />+ <layer number="44" name="Drills" color="7" fill="1" visible="no" active="yes" />+ <layer number="45" name="Holes" color="7" fill="1" visible="no" active="yes" />+ <layer number="46" name="Milling" color="3" fill="1" visible="no" active="yes" />+ <layer number="47" name="Measures" color="7" fill="1" visible="no" active="yes" />+ <layer number="48" name="Document" color="7" fill="1" visible="yes" active="yes" />+ <layer number="49" name="Reference" color="7" fill="1" visible="yes" active="yes" />+ <layer number="91" name="Nets" color="2" fill="1" visible="yes" active="yes" />+ <layer number="92" name="Busses" color="1" fill="1" visible="yes" active="yes" />+ <layer number="93" name="Pins" color="2" fill="1" visible="no" active="yes" />+ <layer number="94" name="Symbols" color="4" fill="1" visible="yes" active="yes" />+ <layer number="95" name="Names" color="7" fill="1" visible="yes" active="yes" />+ <layer number="96" name="Values" color="7" fill="1" visible="yes" active="yes" />+ <layer number="97" name="Info" color="7" fill="1" visible="yes" active="yes" />+ <layer number="98" name="Guide" color="6" fill="1" visible="yes" active="yes" />+ </layers>+ <board>+ <plain>+ <wire x1="0" y1="0" x2="50" y2="0" width="0" layer="20" />+ <wire x1="50" y1="0" x2="50" y2="40" width="0" layer="20" />+ <wire x1="50" y1="40" x2="0" y2="40" width="0" layer="20" />+ <wire x1="0" y1="40" x2="0" y2="0" width="0" layer="20" />+ <text x="7" y="36" size="1.5" layer="21">FUSION / OBSTACLE ROUTING</text>+ </plain>+ <libraries>+ <library name="ObstacleLab">+ <packages>+ <package name="SMD_TESTPOINT">+ <smd name="1" x="0" y="0" dx="1.5" dy="1.5" layer="1" roundness="20" />+ </package>+ </packages>+ </library>+ </libraries>+ <attributes />+ <variantdefs />+ <classes>+ <class number="0" name="default" width="0.25" drill="0.3" />+ </classes>+ <designrules name="RoutingFixture">+ <param name="layerSetup" value="(1*16)" />+ <param name="mdWireWire" value="0.2mm" />+ <param name="mdWirePad" value="0.2mm" />+ <param name="mdWireVia" value="0.2mm" />+ <param name="msWidth" value="0.2mm" />+ <param name="msDrill" value="0.3mm" />+ <param name="mdCopperDimension" value="0.5mm" />+ </designrules>+ <elements>+ <element name="L1" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="5" y="8" />+ <element name="R1" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="45" y="8" />+ <element name="L2" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="5" y="20" />+ <element name="R2" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="45" y="20" />+ <element name="L3" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="5" y="32" />+ <element name="R3" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="45" y="32" />+ </elements>+ <signals>+ <signal name="ROUTE_1">+ <contactref element="L1" pad="1" />+ <contactref element="R1" pad="1" />+ </signal>+ <signal name="ROUTE_2">+ <contactref element="L2" pad="1" />+ <contactref element="R2" pad="1" />+ </signal>+ <signal name="ROUTE_3">+ <contactref element="L3" pad="1" />+ <contactref element="R3" pad="1" />+ </signal>+ <signal name="TOP_BARRIER">+ <wire x1="22" y1="2" x2="22" y2="28" width="1" layer="1" />+ </signal>+ <signal name="BOTTOM_BARRIER">+ <wire x1="32" y1="12" x2="32" y2="37" width="1" layer="16" />+ </signal>+ </signals>+ </board>+ </drawing>+</eagle>
demo/routing/obstacles/fusion-obstacle-live-1x.assadded+15@@ -0,0 +1,15 @@+[Script Info]+ScriptType: v4.00++PlayResX: 1920+PlayResY: 1080+WrapStyle: 2+[V4+ Styles]+Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding+Style: Main,Liberation Sans,34,&H00FFFFFF,&H00FFFFFF,&H00130F0A,&H00130F0A,0,0,0,0,100,100,0,0,1,1,0,2,30,30,22,1+[Events]+Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text+Dialogue: 0,0:00:00.00,0:00:49.83,Main,,0,0,0,,{\an7\pos(36,18)\fs36\b1\c&H00E5CF65&}CODEX ASTRA IN ADOM HYDROGEN / LIVE FUSION ROUTING+Dialogue: 0,0:00:00.00,0:00:49.83,Main,,0,0,0,,{\an7\pos(1455,75)\fs25}1x playback / live SSE panel+Dialogue: 0,0:00:00.00,0:00:49.83,Main,,0,0,0,,{\an7\pos(36,75)\fs25}Native AB capture / board + live Adom palette+Dialogue: 0,0:00:00.00,0:00:44.83,Main,,0,0,0,,{\an2\pos(960,1034)\fs28}fusion_plan_route calculates paths; fusion_route_net creates and verifies copper.\NThe Adom palette displays actual results during routing. No external router.+Dialogue: 0,0:00:44.83,0:00:49.83,Main,,0,0,0,,{\an2\pos(960,1034)\fs30}3 connections / 8 new segments / 2 vias / both barriers preserved.\Nfusion_routing_drc: 0 errors / 0 warnings / 0 airwires.
demo/routing/obstacles/fusion-obstacle-live-1x.edit.jsonadded+17@@ -0,0 +1,17 @@+{+ "sources": [+ "/home/adom/project/fusion-trace-routing/demo/routing/obstacles/take-04/window-8916576-20260905-223500.mp4",+ "/home/adom/project/fusion-trace-routing/demo/routing/obstacles/take-04/window-11280636-20260905-223501.mp4"+ ],+ "boardOffsetSeconds": 0.5224201679229736,+ "synchronization": "Call-start timestamps; first-frame timing can differ by capture initialization latency",+ "commonSourceSeconds": [+ 0,+ 44.8333+ ],+ "trimmedCompletedTailSeconds": 3.0,+ "speed": 1,+ "finalHoldSeconds": 5,+ "durationSeconds": 49.8333,+ "livePanel": "Original native Adom palette video; no reconstructed status text"+}
demo/routing/obstacles/fusion-obstacle-live-1x.mp4added⋯ 1 unchanged line ⋯
demo/routing/obstacles/fusion-obstacle-live-3x.assadded+15@@ -0,0 +1,15 @@+[Script Info]+ScriptType: v4.00++PlayResX: 1920+PlayResY: 1080+WrapStyle: 2+[V4+ Styles]+Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding+Style: Main,Liberation Sans,34,&H00FFFFFF,&H00FFFFFF,&H00130F0A,&H00130F0A,0,0,0,0,100,100,0,0,1,1,0,2,30,30,22,1+[Events]+Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text+Dialogue: 0,0:00:00.00,0:00:19.94,Main,,0,0,0,,{\an7\pos(36,18)\fs36\b1\c&H00E5CF65&}CODEX ASTRA IN ADOM HYDROGEN / LIVE FUSION ROUTING+Dialogue: 0,0:00:00.00,0:00:19.94,Main,,0,0,0,,{\an7\pos(1455,75)\fs25}3x playback / live SSE panel+Dialogue: 0,0:00:00.00,0:00:19.94,Main,,0,0,0,,{\an7\pos(36,75)\fs25}Native AB capture / board + live Adom palette+Dialogue: 0,0:00:00.00,0:00:14.94,Main,,0,0,0,,{\an2\pos(960,1034)\fs28}fusion_plan_route calculates paths; fusion_route_net creates and verifies copper.\NThe Adom palette displays actual results during routing. No external router.+Dialogue: 0,0:00:14.94,0:00:19.94,Main,,0,0,0,,{\an2\pos(960,1034)\fs30}3 connections / 8 new segments / 2 vias / both barriers preserved.\Nfusion_routing_drc: 0 errors / 0 warnings / 0 airwires.
demo/routing/obstacles/fusion-obstacle-live-3x.edit.jsonadded+17@@ -0,0 +1,17 @@+{+ "sources": [+ "/home/adom/project/fusion-trace-routing/demo/routing/obstacles/take-04/window-8916576-20260905-223500.mp4",+ "/home/adom/project/fusion-trace-routing/demo/routing/obstacles/take-04/window-11280636-20260905-223501.mp4"+ ],+ "boardOffsetSeconds": 0.5224201679229736,+ "synchronization": "Call-start timestamps; first-frame timing can differ by capture initialization latency",+ "commonSourceSeconds": [+ 0,+ 44.8333+ ],+ "trimmedCompletedTailSeconds": 3.0,+ "speed": 3,+ "finalHoldSeconds": 5,+ "durationSeconds": 19.944433333333336,+ "livePanel": "Original native Adom palette video; no reconstructed status text"+}
demo/routing/obstacles/fusion-obstacle-live-3x.mp4added⋯ 1 unchanged line ⋯
demo/routing/obstacles/install-v4.jsonadded+11@@ -0,0 +1,11 @@+{+ "durationMs": 791,+ "exitCode": 0,+ "ok": true,+ "status": "ok",+ "stderr": "",+ "stdout": "{\r\n \"sha256\": \"21AADF575771DEFFF9D66F79518A1645A739516441C574E2B0E8EAA700C60DA7\",\r\n \"backup\": \"C:/Users/john/AppData/Local/Adom Bridge/bridges-cache/fusion360/routing-backup-20260905-171248\",\r\n \"version\": \"1.10.0-dev.routing.4\"\r\n}\r\n",+ "success": true,+ "timedOut": false,+ "timeoutSeconds": 75+}
demo/routing/obstacles/install.jsonadded+11@@ -0,0 +1,11 @@+{+ "durationMs": 761,+ "exitCode": 0,+ "ok": true,+ "status": "ok",+ "stderr": "",+ "stdout": "{\r\n \"version\": \"1.10.0-dev.routing.3\",\r\n \"sha256\": \"51E5A67E137CD0AB363C7D1060F7D7F769E2151855DA65682B46931046A8DA14\",\r\n \"backup\": \"C:/Users/john/AppData/Local/Adom Bridge/bridges-cache/fusion360/routing-backup-20260905-170439\"\r\n}\r\n",+ "success": true,+ "timedOut": false,+ "timeoutSeconds": 75+}
demo/routing/obstacles/live-planning-probes.jsonadded+249@@ -0,0 +1,249 @@+{+ "False": {+ "_timeoutHint": "ab waits up to 60s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `fusion_get_app_state` until it reports done.",+ "boardId": "5f0f9666-6d7f-4ba4-a128-fbb97d8fab0c",+ "bridgeVersion": "1.10.0-dev.routing.3",+ "documentName": "fusion-obstacle-lab",+ "durationMs": 221,+ "error": "",+ "mutated": false,+ "plan": {+ "clearance": 0.2,+ "items": [+ {+ "end": [+ 21.0,+ 8.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 5.0,+ 8.0+ ],+ "width": 0.25+ },+ {+ "end": [+ 21.0,+ 1.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 21.0,+ 8.0+ ],+ "width": 0.25+ },+ {+ "end": [+ 45.0,+ 1.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 21.0,+ 1.0+ ],+ "width": 0.25+ },+ {+ "end": [+ 45.0,+ 8.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 45.0,+ 1.0+ ],+ "width": 0.25+ }+ ],+ "net": "ROUTE_1",+ "planner": {+ "algorithm": "bounded orthogonal two-layer A*",+ "elapsedMs": 16.616,+ "expandedNodes": 1795,+ "externalRouter": false,+ "grid": 0.5,+ "lengthMm": 54.0,+ "viaCount": 0+ },+ "preflight": "Conservative geometry only; run native Autodesk DRC after edits",+ "route": {+ "clearance": 0.2,+ "layer": 1,+ "net": "ROUTE_1",+ "points": [+ {+ "layer": 1,+ "x": 5.0,+ "y": 8.0+ },+ {+ "layer": 1,+ "x": 21.0,+ "y": 8.0+ },+ {+ "layer": 1,+ "x": 21.0,+ "y": 1.0+ },+ {+ "layer": 1,+ "x": 45.0,+ "y": 1.0+ },+ {+ "layer": 1,+ "x": 45.0,+ "y": 8.0+ }+ ],+ "viaDiameter": 0.6,+ "viaDrill": 0.3,+ "width": 0.25+ }+ },+ "revision": "81c6352daaf69b82f94ae175dcfccc3579bf4875bbef60182fb2ca730703a048",+ "shell": "rust",+ "status": "ok",+ "statusVerb": "fusion_get_app_state",+ "success": true,+ "timeoutSeconds": 60+ },+ "True": {+ "_timeoutHint": "ab waits up to 60s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `fusion_get_app_state` until it reports done.",+ "boardId": "5f0f9666-6d7f-4ba4-a128-fbb97d8fab0c",+ "bridgeVersion": "1.10.0-dev.routing.3",+ "documentName": "fusion-obstacle-lab",+ "durationMs": 213,+ "error": "",+ "mutated": false,+ "plan": {+ "clearance": 0.2,+ "items": [+ {+ "end": [+ 21.0,+ 8.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 5.0,+ 8.0+ ],+ "width": 0.25+ },+ {+ "at": [+ 21.0,+ 8.0+ ],+ "diameter": 0.6,+ "drill": 0.3,+ "extent": "1-16",+ "kind": "via",+ "net": "ROUTE_1"+ },+ {+ "end": [+ 43.0,+ 8.0+ ],+ "kind": "segment",+ "layer": 16,+ "net": "ROUTE_1",+ "start": [+ 21.0,+ 8.0+ ],+ "width": 0.25+ },+ {+ "at": [+ 43.0,+ 8.0+ ],+ "diameter": 0.6,+ "drill": 0.3,+ "extent": "1-16",+ "kind": "via",+ "net": "ROUTE_1"+ },+ {+ "end": [+ 45.0,+ 8.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 43.0,+ 8.0+ ],+ "width": 0.25+ }+ ],+ "net": "ROUTE_1",+ "planner": {+ "algorithm": "bounded orthogonal two-layer A*",+ "elapsedMs": 15.618,+ "expandedNodes": 911,+ "externalRouter": false,+ "grid": 0.5,+ "lengthMm": 40.0,+ "viaCount": 2+ },+ "preflight": "Conservative geometry only; run native Autodesk DRC after edits",+ "route": {+ "clearance": 0.2,+ "layer": 1,+ "net": "ROUTE_1",+ "points": [+ {+ "layer": 1,+ "x": 5.0,+ "y": 8.0+ },+ {+ "layer": 16,+ "x": 21.0,+ "y": 8.0+ },+ {+ "layer": 1,+ "x": 43.0,+ "y": 8.0+ },+ {+ "layer": 1,+ "x": 45.0,+ "y": 8.0+ }+ ],+ "viaDiameter": 0.6,+ "viaDrill": 0.3,+ "width": 0.25+ }+ },+ "revision": "81c6352daaf69b82f94ae175dcfccc3579bf4875bbef60182fb2ca730703a048",+ "shell": "rust",+ "status": "ok",+ "statusVerb": "fusion_get_app_state",+ "success": true,+ "timeoutSeconds": 60+ }+}
demo/routing/obstacles/player-verification.jsonadded+29@@ -0,0 +1,29 @@+{+ "window": [+ {+ "className": "ApplicationFrameWindow",+ "enabled": true,+ "hung": false,+ "hwnd": 18812610,+ "image": "ApplicationFrameHost.exe",+ "kind": "normal",+ "maximized": false,+ "minimized": false,+ "owner": 0,+ "pid": 15016,+ "rect": {+ "bottom": 1434,+ "height": 1338,+ "left": 118,+ "right": 2241,+ "top": 96,+ "width": 2123+ },+ "title": "Media Player",+ "z": 0+ }+ ],+ "screenshot": "/home/adom/project/screenshots/adom-bridge/window/2026-09-05T22-40-10.744-18812610.safe.png",+ "verifiedFile": "fusion-obstacle-live-1x.mp4",+ "pauseButtonSeen": true+}
demo/routing/obstacles/player-windows.jsonadded+24@@ -0,0 +1,24 @@+[+ {+ "className": "ApplicationFrameWindow",+ "enabled": true,+ "hung": false,+ "hwnd": 18812610,+ "image": "ApplicationFrameHost.exe",+ "kind": "normal",+ "maximized": false,+ "minimized": false,+ "owner": 0,+ "pid": 15016,+ "rect": {+ "bottom": 1434,+ "height": 1338,+ "left": 118,+ "right": 2241,+ "top": 96,+ "width": 2123+ },+ "title": "Media Player",+ "z": 13+ }+]
demo/routing/obstacles/record_obstacles.pyadded+78@@ -0,0 +1,78 @@+"""Plan from the live obstacle board, then record every verified copper edit."""+import argparse,json,sys,time+from pathlib import Path+sys.path.insert(0,str(Path(__file__).resolve().parents[1]))+from call import call+from live_panel import LivePanel+ROOT=Path(__file__).resolve().parent+p=argparse.ArgumentParser();p.add_argument('--document',required=True);p.add_argument('--take',required=True);p.add_argument('--hwnd',type=int,required=True);p.add_argument('--palette-hwnd',type=int,required=True);options=p.parse_args()+TAKE=ROOT/options.take;TAKE.mkdir(exist_ok=False)+log=[]+def invoke(v,a,expected_failure=False):+ start=time.time();r=call(v,{**a,'reason':'Plan and show obstacle-aware routing in Fusion'})+ log.append({'verb':v,'args':a,'start':start,'end':time.time(),'result':r})+ (TAKE/'calls.json').write_text(json.dumps(log,indent=2)+'\n')+ if not expected_failure and not r.get('success',r.get('ok')):raise RuntimeError(json.dumps(r))+ return r+s=invoke('fusion_routing_state',{'expectDocument':options.document})+assert s['bridgeVersion']=='1.10.0-dev.routing.4' and s['segmentCount']==2 and s['viaCount']==0+assert {i['net'] for i in s['segments']}=={'TOP_BARRIER','BOTTOM_BARRIER'}+(TAKE/'before.json').write_text(json.dumps(s,indent=2)+'\n')+def guard():return {'expectDocument':options.document,'boardId':s['boardId'],'expectedRevision':s['revision']}+panel=LivePanel(invoke,options.document,TAKE/'panel-events.jsonl',options.palette_hwnd)+panel.update(create=True,status='Ready to route',connection='3 pad pairs / 2 copper barriers',plan='0.50 mm grid / 0.25 mm traces',checks='Fresh board: 2 existing segments, no vias.')+windows=invoke('desktop_list_windows',{})['windows']+w=next(w for w in windows if w['hwnd']==options.hwnd)+assert not w['minimized'] and w['rect']['width']>=800 and w['rect']['height']>=600,'Fusion window is too small or minimized'+blocked=invoke('fusion_route_net',{**guard(),'net':'ROUTE_1','points':[{'pad':'L1.1'},{'pad':'R1.1'}],'dryRun':True},True)+assert blocked.get('errorCode')=='clearance_violation' and not blocked['mutationAttempted']+invoke('fusion_execute_text_command',{'command':'Electron.ImmediateRepaint /full','expectDocument':options.document})+panel_rec=None+rec=invoke('desktop_record_window_start',{'hwnd':options.hwnd,'fps':30,'audio':False,'maxDurationMs':180000})+(TAKE/'record-start.json').write_text(json.dumps(rec,indent=2)+'\n')+try:+ panel_rec=invoke('desktop_record_window_start',{'hwnd':options.palette_hwnd,'fps':30,'audio':False,'maxDurationMs':180000})+ (TAKE/'panel-record-start.json').write_text(json.dumps(panel_rec,indent=2)+'\n')+ assert panel_rec['width']>=400 and panel_rec['height']>=600+ assert rec['width']>=800 and rec['height']>=600,'Capture dimensions are too small'+ panel.update(status='Direct path rejected safely',connection='ROUTE_1: L1.1 → R1.1',checks='Direct top-layer line crosses existing copper.\nNo mutation attempted.',event='fusion_route_net dryRun: clearance_violation')+ time.sleep(3)+ for n in range(1,4):+ panel.update(percent=(n-1)*33,status=f'Calculating connection {n} of 3',connection=f'ROUTE_{n}: L{n}.1 → R{n}.1\n(5, {8+12*(n-1)}) → (45, {8+12*(n-1)}) mm',plan='0.50 mm grid / 0.25 mm width\n'+('Top only: vias disabled' if n==1 else 'Top + bottom: vias permitted'),checks='Searching live copper obstacles; board unchanged.',event='fusion_plan_route: read-only A* search')+ p=invoke('fusion_plan_route',{**guard(),'net':f'ROUTE_{n}','fromPad':f'L{n}.1','toPad':f'R{n}.1','allowVias':n!=1})+ assert p['revision']==s['revision'] and not p['mutated']+ (TAKE/f'plan-{n}.json').write_text(json.dumps(p,indent=2)+'\n')+ stats=p['plan']['planner']+ plan_text=f"{stats['lengthMm']:g} mm / {stats['viaCount']} vias\n{stats['expandedNodes']} nodes / {stats['elapsedMs']:g} ms\nClearance {p['plan']['clearance']:g} mm"+ panel.update(status='Route calculated and preflight passed',plan=plan_text,checks='Revision unchanged by planning.\nExplicit path cleared against live copper.')+ time.sleep(3)+ for step,i in enumerate(p['plan']['items'],1):+ detail=(f"Layer {i['layer']}: {i['start']} → {i['end']}" if i['kind']=='segment' else f"Via at {i['at']}: top ↔ bottom")+ panel.update(status=f"Creating {i['kind']} {step}/{len(p['plan']['items'])}",checks=detail+'\nWaiting for native copper read-back.',event='fusion_route_net: '+i['kind'])+ if i['kind']=='segment':a={'net':i['net'],'width':i['width'],'layer':i['layer'],'points':[i['start'],i['end']]}+ else:+ xy=i['at'];a={'net':i['net'],'viaDiameter':i['diameter'],'viaDrill':i['drill'],'points':[xy,{'x':xy[0],'y':xy[1],'layer':16}]}+ s=invoke('fusion_route_net',{**guard(),**a});assert s['verified'] and s['mutated']+ panel.update(status=f"Verified {i['kind']} {step}/{len(p['plan']['items'])}",checks='Native copper matches requested edit.\nRevision advanced; existing copper preserved.')+ time.sleep(.8)+ panel.update(status='Running native Autodesk DRC',checks='Measuring errors, warnings and airwires.',event='fusion_routing_drc')+ s=invoke('fusion_routing_drc',guard());assert s['drc']['checked'] and not s['drc']['errorCount'] and not s['drc']['warningCount'],s['drc']+ panel.update(percent=n*33,status=f'Connection {n} verified',checks=f"DRC: {s['drc']['errorCount']} errors / {s['drc']['warningCount']} warnings\n{s['drc'].get('airwireCount','?')} airwires / {len(s['remainingNets'])} nets remaining",event='Native DRC completed')+ time.sleep(2)+ print(n,p['plan']['planner'],len(s['remainingNets']),'remaining',flush=True)+ assert not s['remainingNets'] and s['drc']['clean']+ assert [i for i in s['segments'] if i['net'] in {'TOP_BARRIER','BOTTOM_BARRIER'}]==json.loads((TAKE/'before.json').read_text())['segments']+ (TAKE/'final.json').write_text(json.dumps(s,indent=2)+'\n');panel.update(percent=100,status='All 3 connections complete',connection='6 pads connected / 8 new segments / 2 vias',checks='Native DRC: 0 errors / 0 warnings / 0 airwires\nBoth original copper barriers unchanged.',event='Final board geometry verified');time.sleep(5)+except Exception as exc:+ try:panel.update(status='STOPPED: operation failed',checks=str(exc)[:400],failed=True,event='No automatic mutation retry')+ except Exception:pass+ raise+finally:+ if panel_rec:+ panel_stop=invoke('desktop_record_window_stop',{'recordingId':panel_rec['recordingId']},True)+ (TAKE/'panel-record-stop.json').write_text(json.dumps(panel_stop,indent=2)+'\n')+ stop=invoke('desktop_record_window_stop',{'recordingId':rec['recordingId']},True)+ (TAKE/'record-stop.json').write_text(json.dumps(stop,indent=2)+'\n')+assert stop.get('success',stop.get('ok')) and stop.get('bytes',0)>0,stop+invoke('pull_file',{'filePaths':[stop['path'],panel_stop['path']],'saveTo':str(TAKE)})+print('PASS: live obstacle planning, copper preserved, native DRC clean',flush=True)
demo/routing/obstacles/render_obstacles.pyadded+35@@ -0,0 +1,35 @@+"""Compose synchronized native Fusion and Adom-palette captures; preserve actual live text."""+from pathlib import Path+import json,subprocess,sys+ROOT=Path(__file__).resolve().parent+sys.path.insert(0,str(ROOT.parent/'crossbar'))+from render_crossbar import HEADER,stamp+TAKE=ROOT/'take-04'+board=next(TAKE.glob('window-8916576-*.mp4'));panel=next(TAKE.glob('window-11280636-*.mp4'))+final=json.loads((TAKE/'final.json').read_text());assert final['drc']['clean'] and not final['remainingNets']+calls=json.loads((TAKE/'calls.json').read_text());starts=[c for c in calls if c['verb']=='desktop_record_window_start']+offset=starts[1]['start']-starts[0]['start']+def probe(f):return json.loads(subprocess.check_output(['ffprobe','-v','error','-show_streams','-of','json',str(f)]))['streams'][0]+b,p=probe(board),probe(panel)+assert b['r_frame_rate']==p['r_frame_rate']=='30/1'+# Trim the long completed-state tail; final hold in output is five seconds.+common=min(float(b['duration'])-offset,float(p['duration']))+end=common-3+for speed in [3,1]:+ name=f'fusion-obstacle-live-{speed}x';duration=end/speed+5+ events=[]+ def text(a,z,t):events.append(f'Dialogue: 0,{stamp(a)},{stamp(z)},Main,,0,0,0,,{t}')+ text(0,duration,r'{\an7\pos(36,18)\fs36\b1\c&H00E5CF65&}CODEX ASTRA IN ADOM HYDROGEN / LIVE FUSION ROUTING')+ text(0,duration,fr'{{\an7\pos(1455,75)\fs25}}{speed}x playback / live SSE panel')+ text(0,duration,r'{\an7\pos(36,75)\fs25}Native AB capture / board + live Adom palette')+ text(0,end/speed,r'{\an2\pos(960,1034)\fs28}fusion_plan_route calculates paths; fusion_route_net creates and verifies copper.\NThe Adom palette displays actual results during routing. No external router.')+ text(end/speed,duration,r'{\an2\pos(960,1034)\fs30}3 connections / 8 new segments / 2 vias / both barriers preserved.\Nfusion_routing_drc: 0 errors / 0 warnings / 0 airwires.')+ ass=ROOT/(name+'.ass');ass.write_text(HEADER+'\n'.join(events)+'\n')+ # Board crop retains editor toolbar + all board copper. Panel crop removes unused lower area.+ vf=(f'[0:v]trim=start={offset}:end={offset+end},setpts=(PTS-STARTPTS)/{speed},fps=30,crop=1700:1440:0:0,scale=1062:900,pad=1370:900:154:0:color=0x0a0f13[b];'+ f'[1:v]trim=start=0:end={end},setpts=(PTS-STARTPTS)/{speed},fps=30,crop=570:850:0:0,scale=570:850,pad=570:900:0:0:color=0x0a0f13[p];'+ f'[b][p]hstack=inputs=2,crop=1920:900:0:0,pad=1920:1080:0:110:color=0x0a0f13,tpad=stop_mode=clone:stop_duration=5,ass={ass}[v]')+ out=ROOT/(name+'.mp4')+ subprocess.run(['ffmpeg','-v','warning','-i',str(board),'-i',str(panel),'-filter_complex',vf,'-map','[v]','-an','-c:v','libx264','-preset','fast','-crf','19','-pix_fmt','yuv420p','-movflags','+faststart','-y',str(out)],check=True)+ (ROOT/(name+'.edit.json')).write_text(json.dumps({'sources':[str(board),str(panel)],'boardOffsetSeconds':offset,'synchronization':'Call-start timestamps; first-frame timing can differ by capture initialization latency','commonSourceSeconds':[0,end],'trimmedCompletedTailSeconds':common-end,'speed':speed,'finalHoldSeconds':5,'durationSeconds':duration,'livePanel':'Original native Adom palette video; no reconstructed status text'},indent=2)+'\n')+ print(out,flush=True)
demo/routing/obstacles/requirements.jsonadded+29@@ -0,0 +1,29 @@+{+ "purpose": "Independent obstacle-aware routing fixture",+ "terminals": [+ {+ "net": "ROUTE_1",+ "from": "L1.1",+ "to": "R1.1"+ },+ {+ "net": "ROUTE_2",+ "from": "L2.1",+ "to": "R2.1"+ },+ {+ "net": "ROUTE_3",+ "from": "L3.1",+ "to": "R3.1"+ }+ ],+ "width": 0.25,+ "expectedStraightLineBlockedNets": [+ "ROUTE_1",+ "ROUTE_2"+ ],+ "preserveExistingCopper": [+ "TOP_BARRIER",+ "BOTTOM_BARRIER"+ ]+}
demo/routing/obstacles/take-01/before.jsonadded+217@@ -0,0 +1,217 @@+{+ "_timeoutHint": "ab waits up to 60s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `fusion_get_app_state` until it reports done.",+ "airwireCount": 3,+ "boardId": "5f0f9666-6d7f-4ba4-a128-fbb97d8fab0c",+ "bridgeVersion": "1.10.0-dev.routing.3",+ "connectivitySource": "Fusion exported airwires; mutation paths recompute RATSNEST",+ "documentName": "fusion-obstacle-lab",+ "drc": {+ "checked": false,+ "note": "Use fusion_routing_drc for a fresh Autodesk DRC"+ },+ "durationMs": 227,+ "error": "",+ "nets": [+ {+ "airwireCount": 1,+ "airwires": [+ {+ "end": [+ 45.0,+ 8.0+ ],+ "start": [+ 5.0,+ 8.0+ ]+ }+ ],+ "name": "ROUTE_1",+ "pads": [+ "L1.1",+ "R1.1"+ ],+ "segments": 0,+ "vias": 0+ },+ {+ "airwireCount": 1,+ "airwires": [+ {+ "end": [+ 45.0,+ 20.0+ ],+ "start": [+ 5.0,+ 20.0+ ]+ }+ ],+ "name": "ROUTE_2",+ "pads": [+ "L2.1",+ "R2.1"+ ],+ "segments": 0,+ "vias": 0+ },+ {+ "airwireCount": 1,+ "airwires": [+ {+ "end": [+ 45.0,+ 32.0+ ],+ "start": [+ 5.0,+ 32.0+ ]+ }+ ],+ "name": "ROUTE_3",+ "pads": [+ "L3.1",+ "R3.1"+ ],+ "segments": 0,+ "vias": 0+ },+ {+ "airwireCount": 0,+ "airwires": [],+ "name": "TOP_BARRIER",+ "pads": [],+ "segments": 1,+ "vias": 0+ },+ {+ "airwireCount": 0,+ "airwires": [],+ "name": "BOTTOM_BARRIER",+ "pads": [],+ "segments": 1,+ "vias": 0+ }+ ],+ "pads": [+ {+ "at": [+ 5.0,+ 8.0+ ],+ "layers": [+ 1+ ],+ "name": "L1.1",+ "net": "ROUTE_1",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 45.0,+ 8.0+ ],+ "layers": [+ 1+ ],+ "name": "R1.1",+ "net": "ROUTE_1",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 5.0,+ 20.0+ ],+ "layers": [+ 1+ ],+ "name": "L2.1",+ "net": "ROUTE_2",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 45.0,+ 20.0+ ],+ "layers": [+ 1+ ],+ "name": "R2.1",+ "net": "ROUTE_2",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 5.0,+ 32.0+ ],+ "layers": [+ 1+ ],+ "name": "L3.1",+ "net": "ROUTE_3",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 45.0,+ 32.0+ ],+ "layers": [+ 1+ ],+ "name": "R3.1",+ "net": "ROUTE_3",+ "radius": 1.0606601717798212+ }+ ],+ "remainingNets": [+ "ROUTE_1",+ "ROUTE_2",+ "ROUTE_3"+ ],+ "revision": "81c6352daaf69b82f94ae175dcfccc3579bf4875bbef60182fb2ca730703a048",+ "segmentCount": 2,+ "segments": [+ {+ "curve": 0.0,+ "end": [+ 22.0,+ 28.0+ ],+ "layer": 1,+ "net": "TOP_BARRIER",+ "start": [+ 22.0,+ 2.0+ ],+ "width": 1.0+ },+ {+ "curve": 0.0,+ "end": [+ 32.0,+ 37.0+ ],+ "layer": 16,+ "net": "BOTTOM_BARRIER",+ "start": [+ 32.0,+ 12.0+ ],+ "width": 1.0+ }+ ],+ "shell": "rust",+ "status": "ok",+ "statusVerb": "fusion_get_app_state",+ "success": true,+ "timeoutSeconds": 60,+ "units": "mm",+ "viaCount": 0,+ "vias": []+}
demo/routing/obstacles/take-01/calls.json.gzadded⋯ 1 unchanged line ⋯
demo/routing/obstacles/take-01/plan-1.jsonadded+122@@ -0,0 +1,122 @@+{+ "_timeoutHint": "ab waits up to 60s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `fusion_get_app_state` until it reports done.",+ "boardId": "5f0f9666-6d7f-4ba4-a128-fbb97d8fab0c",+ "bridgeVersion": "1.10.0-dev.routing.3",+ "documentName": "fusion-obstacle-lab",+ "durationMs": 291,+ "error": "",+ "mutated": false,+ "plan": {+ "clearance": 0.2,+ "items": [+ {+ "end": [+ 21.0,+ 8.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 5.0,+ 8.0+ ],+ "width": 0.25+ },+ {+ "end": [+ 21.0,+ 1.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 21.0,+ 8.0+ ],+ "width": 0.25+ },+ {+ "end": [+ 45.0,+ 1.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 21.0,+ 1.0+ ],+ "width": 0.25+ },+ {+ "end": [+ 45.0,+ 8.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 45.0,+ 1.0+ ],+ "width": 0.25+ }+ ],+ "net": "ROUTE_1",+ "planner": {+ "algorithm": "bounded orthogonal two-layer A*",+ "elapsedMs": 23.879,+ "expandedNodes": 1795,+ "externalRouter": false,+ "grid": 0.5,+ "lengthMm": 54.0,+ "viaCount": 0+ },+ "preflight": "Conservative geometry only; run native Autodesk DRC after edits",+ "route": {+ "clearance": 0.2,+ "layer": 1,+ "net": "ROUTE_1",+ "points": [+ {+ "layer": 1,+ "x": 5.0,+ "y": 8.0+ },+ {+ "layer": 1,+ "x": 21.0,+ "y": 8.0+ },+ {+ "layer": 1,+ "x": 21.0,+ "y": 1.0+ },+ {+ "layer": 1,+ "x": 45.0,+ "y": 1.0+ },+ {+ "layer": 1,+ "x": 45.0,+ "y": 8.0+ }+ ],+ "viaDiameter": 0.6,+ "viaDrill": 0.3,+ "width": 0.25+ }+ },+ "revision": "81c6352daaf69b82f94ae175dcfccc3579bf4875bbef60182fb2ca730703a048",+ "shell": "rust",+ "status": "ok",+ "statusVerb": "fusion_get_app_state",+ "success": true,+ "timeoutSeconds": 60+}
demo/routing/obstacles/take-01/plan-2.jsonadded+125@@ -0,0 +1,125 @@+{+ "_timeoutHint": "ab waits up to 60s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `fusion_get_app_state` until it reports done.",+ "boardId": "5f0f9666-6d7f-4ba4-a128-fbb97d8fab0c",+ "bridgeVersion": "1.10.0-dev.routing.3",+ "documentName": "fusion-obstacle-lab",+ "durationMs": 284,+ "error": "",+ "mutated": false,+ "plan": {+ "clearance": 0.2,+ "items": [+ {+ "end": [+ 21.0,+ 20.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_2",+ "start": [+ 5.0,+ 20.0+ ],+ "width": 0.25+ },+ {+ "at": [+ 21.0,+ 20.0+ ],+ "diameter": 0.6,+ "drill": 0.3,+ "extent": "1-16",+ "kind": "via",+ "net": "ROUTE_2"+ },+ {+ "end": [+ 31.0,+ 20.0+ ],+ "kind": "segment",+ "layer": 16,+ "net": "ROUTE_2",+ "start": [+ 21.0,+ 20.0+ ],+ "width": 0.25+ },+ {+ "at": [+ 31.0,+ 20.0+ ],+ "diameter": 0.6,+ "drill": 0.3,+ "extent": "1-16",+ "kind": "via",+ "net": "ROUTE_2"+ },+ {+ "end": [+ 45.0,+ 20.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_2",+ "start": [+ 31.0,+ 20.0+ ],+ "width": 0.25+ }+ ],+ "net": "ROUTE_2",+ "planner": {+ "algorithm": "bounded orthogonal two-layer A*",+ "elapsedMs": 21.667,+ "expandedNodes": 883,+ "externalRouter": false,+ "grid": 0.5,+ "lengthMm": 40.0,+ "viaCount": 2+ },+ "preflight": "Conservative geometry only; run native Autodesk DRC after edits",+ "route": {+ "clearance": 0.2,+ "layer": 1,+ "net": "ROUTE_2",+ "points": [+ {+ "layer": 1,+ "x": 5.0,+ "y": 20.0+ },+ {+ "layer": 16,+ "x": 21.0,+ "y": 20.0+ },+ {+ "layer": 1,+ "x": 31.0,+ "y": 20.0+ },+ {+ "layer": 1,+ "x": 45.0,+ "y": 20.0+ }+ ],+ "viaDiameter": 0.6,+ "viaDrill": 0.3,+ "width": 0.25+ }+ },+ "revision": "4aa61a4df5254069ea5e916bb39990758fb66ca4c72f4b3ffa2851b146c86234",+ "shell": "rust",+ "status": "ok",+ "statusVerb": "fusion_get_app_state",+ "success": true,+ "timeoutSeconds": 60+}
demo/routing/obstacles/take-01/record-start.jsonadded+31@@ -0,0 +1,31 @@+{+ "_hint": "Native window recording (WGC): background-capturable, no picker. Stop with desktop_record_stop {recordingId}; pull the MP4 with pull_file.",+ "audio": false,+ "audioNote": null,+ "audioRate": 0,+ "codec": "h264",+ "durationMs": 542,+ "encoder": "NVIDIA H.264 Encoder MFT",+ "error": "",+ "fps": 30,+ "hardwareEncoder": true,+ "height": 1540,+ "hwnd": 8916576,+ "kind": "window",+ "maxDurationMs": 180000,+ "path": "C:/Users/john/AppData/Local/Temp/adom-bridge-recordings/window-8916576-20260905-220618.mp4",+ "recordingId": "rec-510ecca35d9246089857e69896d1f1d1",+ "status": "ok",+ "success": true,+ "timeoutSeconds": 15,+ "title": "fusion-obstacle-lab* (jlauerhub) - Autodesk Fusion (Trial ends in 16 days) ",+ "width": 2564,+ "data": {+ "height": 1540,+ "kind": "window",+ "path": "C:\\Users\\john\\AppData\\Local\\Temp\\adom-bridge-recordings\\window-8916576-20260905-220618.mp4",+ "recordingId": "rec-510ecca35d9246089857e69896d1f1d1",+ "width": 2564+ },+ "message": "Recording window \"fusion-obstacle-lab* (jlauerhub) - Autodesk Fusion (Trial ends in 16 days) \" -> C:\\Users\\john\\AppData\\Local\\Temp\\adom-bridge-recordings\\window-8916576-20260905-220618.mp4 (2564x1540 @ 30fps h264)"+}
demo/routing/obstacles/take-01/record-stop.jsonadded+28@@ -0,0 +1,28 @@+{+ "_hint": "The MP4 is finalized (moov written). pull_file {path} brings it to the caller; the janitor prunes the recordings dir by age/size, so pull it promptly.",+ "audio": false,+ "audioFrames": 0,+ "autoStopped": false,+ "bytes": 11565120,+ "durationMs": 501,+ "elapsedMs": 9221,+ "error": "",+ "fileExists": true,+ "frames": 258,+ "height": 1540,+ "kind": "window",+ "path": "C:/Users/john/AppData/Local/Temp/adom-bridge-recordings/window-8916576-20260905-220618.mp4",+ "recordingId": "rec-510ecca35d9246089857e69896d1f1d1",+ "status": "ok",+ "success": true,+ "timeoutSeconds": 30,+ "width": 2564,+ "data": {+ "bytes": 11565120,+ "elapsedMs": 9221,+ "frames": 258,+ "path": "C:\\Users\\john\\AppData\\Local\\Temp\\adom-bridge-recordings\\window-8916576-20260905-220618.mp4",+ "recordingId": "rec-510ecca35d9246089857e69896d1f1d1"+ },+ "message": "Stopped recording rec-510ecca35d9246089857e69896d1f1d1: 258 frames, 9221 ms, 11565120 bytes -> C:\\Users\\john\\AppData\\Local\\Temp\\adom-bridge-recordings\\window-8916576-20260905-220618.mp4"+}
demo/routing/obstacles/take-02/calls.json.gzadded⋯ 1 unchanged line ⋯
demo/routing/obstacles/take-03/before.jsonadded+217@@ -0,0 +1,217 @@+{+ "_timeoutHint": "ab waits up to 60s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `fusion_get_app_state` until it reports done.",+ "airwireCount": 3,+ "boardId": "533f7a6b-1e47-4e31-9a8a-b839c5ad45f8",+ "bridgeVersion": "1.10.0-dev.routing.4",+ "connectivitySource": "Fusion exported airwires; mutation paths recompute RATSNEST",+ "documentName": "fusion-obstacle-lab-v2",+ "drc": {+ "checked": false,+ "note": "Use fusion_routing_drc for a fresh Autodesk DRC"+ },+ "durationMs": 213,+ "error": "",+ "nets": [+ {+ "airwireCount": 1,+ "airwires": [+ {+ "end": [+ 45.0,+ 8.0+ ],+ "start": [+ 5.0,+ 8.0+ ]+ }+ ],+ "name": "ROUTE_1",+ "pads": [+ "L1.1",+ "R1.1"+ ],+ "segments": 0,+ "vias": 0+ },+ {+ "airwireCount": 1,+ "airwires": [+ {+ "end": [+ 45.0,+ 20.0+ ],+ "start": [+ 5.0,+ 20.0+ ]+ }+ ],+ "name": "ROUTE_2",+ "pads": [+ "L2.1",+ "R2.1"+ ],+ "segments": 0,+ "vias": 0+ },+ {+ "airwireCount": 1,+ "airwires": [+ {+ "end": [+ 45.0,+ 32.0+ ],+ "start": [+ 5.0,+ 32.0+ ]+ }+ ],+ "name": "ROUTE_3",+ "pads": [+ "L3.1",+ "R3.1"+ ],+ "segments": 0,+ "vias": 0+ },+ {+ "airwireCount": 0,+ "airwires": [],+ "name": "TOP_BARRIER",+ "pads": [],+ "segments": 1,+ "vias": 0+ },+ {+ "airwireCount": 0,+ "airwires": [],+ "name": "BOTTOM_BARRIER",+ "pads": [],+ "segments": 1,+ "vias": 0+ }+ ],+ "pads": [+ {+ "at": [+ 5.0,+ 8.0+ ],+ "layers": [+ 1+ ],+ "name": "L1.1",+ "net": "ROUTE_1",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 45.0,+ 8.0+ ],+ "layers": [+ 1+ ],+ "name": "R1.1",+ "net": "ROUTE_1",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 5.0,+ 20.0+ ],+ "layers": [+ 1+ ],+ "name": "L2.1",+ "net": "ROUTE_2",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 45.0,+ 20.0+ ],+ "layers": [+ 1+ ],+ "name": "R2.1",+ "net": "ROUTE_2",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 5.0,+ 32.0+ ],+ "layers": [+ 1+ ],+ "name": "L3.1",+ "net": "ROUTE_3",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 45.0,+ 32.0+ ],+ "layers": [+ 1+ ],+ "name": "R3.1",+ "net": "ROUTE_3",+ "radius": 1.0606601717798212+ }+ ],+ "remainingNets": [+ "ROUTE_1",+ "ROUTE_2",+ "ROUTE_3"+ ],+ "revision": "6f38e486788364627c73ee1d62f8b5affc9d296ba8c7b3d562f260a96f1c279e",+ "segmentCount": 2,+ "segments": [+ {+ "curve": 0.0,+ "end": [+ 22.0,+ 28.0+ ],+ "layer": 1,+ "net": "TOP_BARRIER",+ "start": [+ 22.0,+ 2.0+ ],+ "width": 1.0+ },+ {+ "curve": 0.0,+ "end": [+ 32.0,+ 37.0+ ],+ "layer": 16,+ "net": "BOTTOM_BARRIER",+ "start": [+ 32.0,+ 12.0+ ],+ "width": 1.0+ }+ ],+ "shell": "rust",+ "status": "ok",+ "statusVerb": "fusion_get_app_state",+ "success": true,+ "timeoutSeconds": 60,+ "units": "mm",+ "viaCount": 0,+ "vias": []+}
demo/routing/obstacles/take-03/calls.json.gzadded⋯ 1 unchanged line ⋯
demo/routing/obstacles/take-03/final.jsonadded+318@@ -0,0 +1,318 @@+{+ "_timeoutHint": "ab waits up to 60s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `fusion_get_app_state` until it reports done.",+ "airwireCount": 0,+ "boardId": "533f7a6b-1e47-4e31-9a8a-b839c5ad45f8",+ "bridgeVersion": "1.10.0-dev.routing.4",+ "connectivitySource": "Fusion exported airwires; mutation paths recompute RATSNEST",+ "documentName": "fusion-obstacle-lab-v2",+ "drc": {+ "airwireCount": 0,+ "checked": true,+ "clean": true,+ "errorCount": 0,+ "errors": [],+ "source": "Autodesk DRC + UL_BOARD.errors",+ "warningCount": 0+ },+ "durationMs": 451,+ "error": "",+ "nets": [+ {+ "airwireCount": 0,+ "airwires": [],+ "name": "ROUTE_1",+ "pads": [+ "L1.1",+ "R1.1"+ ],+ "segments": 4,+ "vias": 0+ },+ {+ "airwireCount": 0,+ "airwires": [],+ "name": "ROUTE_2",+ "pads": [+ "L2.1",+ "R2.1"+ ],+ "segments": 3,+ "vias": 2+ },+ {+ "airwireCount": 0,+ "airwires": [],+ "name": "ROUTE_3",+ "pads": [+ "L3.1",+ "R3.1"+ ],+ "segments": 1,+ "vias": 0+ },+ {+ "airwireCount": 0,+ "airwires": [],+ "name": "TOP_BARRIER",+ "pads": [],+ "segments": 1,+ "vias": 0+ },+ {+ "airwireCount": 0,+ "airwires": [],+ "name": "BOTTOM_BARRIER",+ "pads": [],+ "segments": 1,+ "vias": 0+ }+ ],+ "pads": [+ {+ "at": [+ 5.0,+ 8.0+ ],+ "layers": [+ 1+ ],+ "name": "L1.1",+ "net": "ROUTE_1",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 45.0,+ 8.0+ ],+ "layers": [+ 1+ ],+ "name": "R1.1",+ "net": "ROUTE_1",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 5.0,+ 20.0+ ],+ "layers": [+ 1+ ],+ "name": "L2.1",+ "net": "ROUTE_2",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 45.0,+ 20.0+ ],+ "layers": [+ 1+ ],+ "name": "R2.1",+ "net": "ROUTE_2",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 5.0,+ 32.0+ ],+ "layers": [+ 1+ ],+ "name": "L3.1",+ "net": "ROUTE_3",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 45.0,+ 32.0+ ],+ "layers": [+ 1+ ],+ "name": "R3.1",+ "net": "ROUTE_3",+ "radius": 1.0606601717798212+ }+ ],+ "remainingNets": [],+ "revision": "b599e9aa4d2ff83a24577dea0076ca2a8451f8e7db05400040d901f77ec450b4",+ "segmentCount": 10,+ "segments": [+ {+ "curve": 0.0,+ "end": [+ 21.0,+ 8.0+ ],+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 5.0,+ 8.0+ ],+ "width": 0.25+ },+ {+ "curve": 0.0,+ "end": [+ 21.0,+ 1.0+ ],+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 21.0,+ 8.0+ ],+ "width": 0.25+ },+ {+ "curve": 0.0,+ "end": [+ 45.0,+ 1.0+ ],+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 21.0,+ 1.0+ ],+ "width": 0.25+ },+ {+ "curve": 0.0,+ "end": [+ 45.0,+ 8.0+ ],+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 45.0,+ 1.0+ ],+ "width": 0.25+ },+ {+ "curve": 0.0,+ "end": [+ 20.5,+ 20.0+ ],+ "layer": 1,+ "net": "ROUTE_2",+ "start": [+ 5.0,+ 20.0+ ],+ "width": 0.25+ },+ {+ "curve": 0.0,+ "end": [+ 30.5,+ 20.0+ ],+ "layer": 16,+ "net": "ROUTE_2",+ "start": [+ 20.5,+ 20.0+ ],+ "width": 0.25+ },+ {+ "curve": 0.0,+ "end": [+ 45.0,+ 20.0+ ],+ "layer": 1,+ "net": "ROUTE_2",+ "start": [+ 30.5,+ 20.0+ ],+ "width": 0.25+ },+ {+ "curve": 0.0,+ "end": [+ 45.0,+ 32.0+ ],+ "layer": 1,+ "net": "ROUTE_3",+ "start": [+ 5.0,+ 32.0+ ],+ "width": 0.25+ },+ {+ "curve": 0.0,+ "end": [+ 22.0,+ 28.0+ ],+ "layer": 1,+ "net": "TOP_BARRIER",+ "start": [+ 22.0,+ 2.0+ ],+ "width": 1.0+ },+ {+ "curve": 0.0,+ "end": [+ 32.0,+ 37.0+ ],+ "layer": 16,+ "net": "BOTTOM_BARRIER",+ "start": [+ 32.0,+ 12.0+ ],+ "width": 1.0+ }+ ],+ "shell": "rust",+ "status": "ok",+ "statusVerb": "fusion_get_app_state",+ "success": true,+ "timeoutSeconds": 60,+ "units": "mm",+ "viaCount": 2,+ "vias": [+ {+ "at": [+ 20.5,+ 20.0+ ],+ "diameter": 0.6,+ "drill": 0.3,+ "extent": "1-16",+ "net": "ROUTE_2"+ },+ {+ "at": [+ 30.5,+ 20.0+ ],+ "diameter": 0.6,+ "drill": 0.3,+ "extent": "1-16",+ "net": "ROUTE_2"+ }+ ]+}
demo/routing/obstacles/take-03/fusion-obstacle-routed.brdadded+413@@ -0,0 +1,413 @@+<?xml version="1.0" encoding="utf-8"?>+<!DOCTYPE eagle SYSTEM "eagle.dtd">+<eagle version="9.7.0">+<drawing>+<settings>+<setting alwaysvectorfont="no"/>+<setting verticaltext="up"/>+<setting violationmode="Push"/>+<drillsymbolsettings symboldiameter="650240" symbolwidth="8128">+<drill diameter="64000" />+<drill diameter="80000" />+<drill diameter="96000" />+<drill diameter="112000" />+<drill diameter="128000" />+<drill diameter="144000" />+<drill diameter="160000" />+<drill diameter="176000" />+<drill diameter="192000" />+<drill diameter="208000" />+<drill diameter="224000" />+<drill diameter="240000" />+<drill diameter="256000" />+<drill diameter="272000" />+<drill diameter="288000" />+<drill diameter="320000" />+</drillsymbolsettings>+</settings>+<grid distance="1" unitdist="mm" unit="mm" style="lines" multiple="1" display="no" altdistance="0.1" altunitdist="mm" altunit="mm"/>+<layers>+<layer number="1" name="Top" blackcolor="0xc8ff4164" whitecolor="0xccc90d0c" coloredcolor="0xccc90d0c" blackhighlight="0xccff0000" whitehighlight="0xb4ff0000" coloredhighlight="0xb4ff0000" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="16" name="Bottom" blackcolor="0xc80696d7" whitecolor="0xcc0696d7" coloredcolor="0xcc0696d7" blackhighlight="0xb40000ff" whitehighlight="0xcc8252c2" coloredhighlight="0xcc8252c2" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="17" name="Pads" blackcolor="0xb462d987" whitecolor="0xb462d987" coloredcolor="0xcc0dab76" blackhighlight="0xb400ff00" whitehighlight="0xb400ff00" coloredhighlight="0xb400ff00" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="18" name="Vias" blackcolor="0xb462d987" whitecolor="0xb462d987" coloredcolor="0xccffcd07" blackhighlight="0xb462d987" whitehighlight="0xb462d987" coloredhighlight="0xccffcd07" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="19" name="Unrouted" blackcolor="0xccd9d9d9" whitecolor="0xbbc8c832" coloredcolor="0xbbc8c832" blackhighlight="0xb462d987" whitehighlight="0xb462d987" coloredhighlight="0xccffcd07" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="20" name="Dimension" blackcolor="0xb462d986" whitecolor="0xb462d986" coloredcolor="0xcceec643" blackhighlight="0xb462d986" whitehighlight="0xb462d986" coloredhighlight="0xcceec643" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="21" name="tPlace" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd134" coloredhighlight="0xccafd134" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="22" name="bPlace" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd134" coloredhighlight="0xccafd134" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="23" name="tOrigins" blackcolor="0xc8ffffff" whitecolor="0xccafd134" coloredcolor="0xccafd134" blackhighlight="0xc8ffffff" whitehighlight="0xccafd134" coloredhighlight="0xccafd134" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="24" name="bOrigins" blackcolor="0xc8ffffff" whitecolor="0xccafd134" coloredcolor="0xccafd134" blackhighlight="0xc8ffffff" whitehighlight="0xccafd134" coloredhighlight="0xccafd134" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="25" name="tNames" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd134" coloredhighlight="0xccafd134" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="26" name="bNames" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd134" coloredhighlight="0xccafd134" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="27" name="tValues" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd135" coloredhighlight="0xccafd135" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="28" name="bValues" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd136" coloredhighlight="0xccafd136" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="29" name="tStop" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd137" coloredhighlight="0xccafd137" fill="3" visible="no" active="yes" locked="no"/>+<layer number="30" name="bStop" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd138" coloredhighlight="0xccafd138" fill="6" visible="no" active="yes" locked="no"/>+<layer number="31" name="tCream" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd139" coloredhighlight="0xccafd139" fill="4" visible="no" active="yes" locked="no"/>+<layer number="32" name="bCream" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd140" coloredhighlight="0xccafd140" fill="5" visible="no" active="yes" locked="no"/>+<layer number="33" name="tFinish" blackcolor="0xccd9d9d9" whitecolor="0xbbc8c832" coloredcolor="0xbbc8c832" blackhighlight="0xb462d987" whitehighlight="0xb462d987" coloredhighlight="0xccffcd07" fill="3" visible="no" active="yes" locked="no"/>+<layer number="34" name="bFinish" blackcolor="0xccd9d9d9" whitecolor="0xbbc8c832" coloredcolor="0xbbc8c832" blackhighlight="0xb462d987" whitehighlight="0xb462d987" coloredhighlight="0xccffcd07" fill="6" visible="no" active="yes" locked="no"/>+<layer number="35" name="tGlue" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd140" coloredhighlight="0xccafd140" fill="4" visible="no" active="yes" locked="no"/>+<layer number="36" name="bGlue" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd140" coloredhighlight="0xccafd140" fill="5" visible="no" active="yes" locked="no"/>+<layer number="37" name="tTest" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd140" coloredhighlight="0xccafd140" fill="1" visible="no" active="yes" locked="no"/>+<layer number="38" name="bTest" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd140" coloredhighlight="0xccafd140" fill="1" visible="no" active="yes" locked="no"/>+<layer number="39" name="tKeepout" blackcolor="0xc8ff4164" whitecolor="0xccc90d0c" coloredcolor="0xccc90d0c" blackhighlight="0xccff0000" whitehighlight="0xb4ff0000" coloredhighlight="0xb4ff0000" fill="11" visible="no" active="yes" locked="no"/>+<layer number="40" name="bKeepout" blackcolor="0xc80696d7" whitecolor="0xcc0696d7" coloredcolor="0xcc0696d7" blackhighlight="0xb40000ff" whitehighlight="0xcc8252c2" coloredhighlight="0xcc8252c2" fill="11" visible="no" active="yes" locked="no"/>+<layer number="41" name="RestrictCopper" blackcolor="0xc8ff4164" whitecolor="0xccc90d0c" coloredcolor="0xccc90d0c" blackhighlight="0xccff0000" whitehighlight="0xb4ff0000" coloredhighlight="0xb4ff0000" fill="10" visible="no" active="yes" locked="no"/>+<layer number="42" name="bRestrict" blackcolor="0xc80696d7" whitecolor="0xcc0696d7" coloredcolor="0xcc0696d7" blackhighlight="0xb40000ff" whitehighlight="0xcc8252c2" coloredhighlight="0xcc8252c2" fill="10" visible="no" active="yes" locked="no"/>+<layer number="43" name="vRestrict" blackcolor="0xb462d987" whitecolor="0xb462d987" coloredcolor="0xcc0dab76" blackhighlight="0xb400ff00" whitehighlight="0xb400ff00" coloredhighlight="0xb400ff00" fill="10" visible="no" active="yes" locked="no"/>+<layer number="44" name="Drills" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd140" coloredhighlight="0xccafd140" fill="1" visible="no" active="yes" locked="no"/>+<layer number="45" name="Holes" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd140" coloredhighlight="0xccafd140" fill="1" visible="no" active="yes" locked="no"/>+<layer number="46" name="Milling" blackcolor="0xcc32c8c8" whitecolor="0xb432c8c8" coloredcolor="0xb432c8c8" blackhighlight="0xb400ffff" whitehighlight="0xb400ffff" coloredhighlight="0xb400ffff" fill="1" visible="no" active="yes" locked="no"/>+<layer number="47" name="Measures" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd140" coloredhighlight="0xccafd140" fill="1" visible="no" active="yes" locked="no"/>+<layer number="48" name="Document" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd141" coloredhighlight="0xccafd141" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="49" name="Reference" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd142" coloredhighlight="0xccafd142" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="91" name="Nets" blackcolor="0xdc009292" whitecolor="0xdc009292" coloredcolor="0xc8e3e3e3" blackhighlight="0xdc009292" whitehighlight="0xdc009292" coloredhighlight="0xc8e3e3e3" fill="1" visible="no" active="no" locked="no"/>+<layer number="92" name="Busses" blackcolor="0xdc009292" whitecolor="0xdc009292" coloredcolor="0xc8d62525" blackhighlight="0xdc009292" whitehighlight="0xdc009292" coloredhighlight="0xc8d62525" fill="1" visible="no" active="no" locked="no"/>+<layer number="93" name="Pins" blackcolor="0xdcbbbbbb" whitecolor="0xdcbbbbbb" coloredcolor="0xc839d437" blackhighlight="0xdcbbbbbb" whitehighlight="0xdcbbbbbb" coloredhighlight="0xc839d437" fill="1" visible="no" active="no" locked="no"/>+<layer number="94" name="Symbols" blackcolor="0xdcfac36e" whitecolor="0xdcf57c10" coloredcolor="0xc8e6e600" blackhighlight="0xdcfac36e" whitehighlight="0xdcf57c10" coloredhighlight="0xc8e6e600" fill="1" visible="no" active="no" locked="no"/>+<layer number="95" name="Names" blackcolor="0xf0b2b2b2" whitecolor="0xc8757575" coloredcolor="0xc82c7bce" blackhighlight="0xf0b2b2b2" whitehighlight="0xc8757575" coloredhighlight="0xc82c7bce" fill="1" visible="no" active="no" locked="no"/>+<layer number="96" name="Values" blackcolor="0xf0b2b2b2" whitecolor="0xc8757575" coloredcolor="0xc82c7bce" blackhighlight="0xf0b2b2b2" whitehighlight="0xc8757575" coloredhighlight="0xc82c7bce" fill="1" visible="no" active="no" locked="no"/>+<layer number="97" name="Info" blackcolor="0xf0b2b2b2" whitecolor="0xc8757575" coloredcolor="0xc89526de" blackhighlight="0xf0b2b2b2" whitehighlight="0xc8757575" coloredhighlight="0xc89526de" fill="1" visible="no" active="no" locked="no"/>+<layer number="98" name="Guide" blackcolor="0xf0b2b2b2" whitecolor="0xc8757575" coloredcolor="0xc89526de" blackhighlight="0xf0b2b2b2" whitehighlight="0xc8757575" coloredhighlight="0xc89526de" fill="1" visible="no" active="no" locked="no"/>+</layers>+<board>+<plain>+<wire x1="0" y1="0" x2="50" y2="0" width="0" layer="20"/>+<wire x1="50" y1="0" x2="50" y2="40" width="0" layer="20"/>+<wire x1="50" y1="40" x2="0" y2="40" width="0" layer="20"/>+<wire x1="0" y1="40" x2="0" y2="0" width="0" layer="20"/>+<text x="7" y="36" size="1.5" layer="21">FUSION / OBSTACLE ROUTING</text>+</plain>+<namedviews>+</namedviews>+<libraries>+<library name="ObstacleLab">+<packages>+<package name="SMD_TESTPOINT" use_placeholder="yes">+<smd name="1" x="0" y="0" dx="1.5" dy="1.5" layer="1" roundness="20"/>+</package>+</packages>+</library>+</libraries>+<attributes>+</attributes>+<variantdefs>+</variantdefs>+<classes>+<class number="0" name="default" width="0.25" drill="0.3">+</class>+</classes>+<designrules name="RoutingFixture" version="V1">+<rules>+<rulecategory type="Copper Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Keepout Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Solder-Mask Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Dimension Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Drill Distance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Restrict Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Minimum Drill Size" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Minimum Copper Width" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Acute Angle" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Air-Wire" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Small Gap" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Wire Stub" manualdrc="yes" livedrc="no"/>+ <rulecategory type="Matched Lengths" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Via Restrict Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Teardrop" manualdrc="no" livedrc="no"/>+ <rule type="Minimum Copper Width" enabled="yes" priority="0" onescope="class=0" value="0.25mm" preferredvalue="0.25mm" check_polywidth="no" name="minimum-copper-width-1"/>+ <rule type="Minimum Copper Width" builtin_ruleid="14" enabled="yes" priority="1" value="0.2mm" preferredvalue="0.2mm" check_polywidth="no" name="minimum-copper-width-2"/>+ <rule type="Teardrop" builtin_ruleid="22" enabled="yes" priority="0" onescope="is_via" lengthratio="0.5" widthratio="0.7" curved_sides="no" auto_generate="no" name="teardrop-1"/>+ <rule type="Teardrop" builtin_ruleid="23" enabled="yes" priority="1" onescope="is_pad" lengthratio="0.5" widthratio="0.7" curved_sides="no" auto_generate="no" name="teardrop-2"/>+ <rule type="Teardrop" builtin_ruleid="24" enabled="yes" priority="2" onescope="is_smd" lengthratio="0.5" widthratio="0.7" curved_sides="no" auto_generate="no" name="teardrop-3"/>+ <rule type="Teardrop" builtin_ruleid="25" enabled="yes" priority="3" onescope="is_wire_polygon" lengthratio="0.5" widthratio="0.9" curved_sides="no" auto_generate="no" name="teardrop-4"/>+ <rule type="Minimum Drill Size" enabled="yes" priority="0" onescope="class=0" value="0.3mm" preferredvalue="0.3mm" name="minimum-drill-size-1"/>+ <rule type="Minimum Drill Size" builtin_ruleid="15" enabled="yes" priority="1" value="0.3mm" preferredvalue="0.3mm" name="minimum-drill-size-2"/>+ <rule type="Acute Angle" builtin_ruleid="16" enabled="no" priority="0" name="acute-angle-1"/>+ <rule type="Wire Stub" builtin_ruleid="17" enabled="yes" priority="0" name="wire-stub-1"/>+ <rule type="Air-Wire" builtin_ruleid="19" enabled="yes" priority="0" name="air-wire-1"/>+ <rule type="Matched Lengths" builtin_ruleid="20" enabled="yes" priority="0" tolerance="10mm" gapfactor="2.5" name="matched-lengths-1"/>+ <rule type="Copper Clearance" builtin_ruleid="0" enabled="yes" priority="0" onescope="is_wire_polygon" otherscope="is_wire_polygon" value="0.2mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-1"/>+ <rule type="Copper Clearance" builtin_ruleid="1" enabled="yes" priority="1" onescope="is_wire_polygon" otherscope="is_pad_smd" value="0.2mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-2"/>+ <rule type="Copper Clearance" builtin_ruleid="2" enabled="yes" priority="2" onescope="is_wire_polygon" otherscope="is_via" value="0.2mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-3"/>+ <rule type="Copper Clearance" builtin_ruleid="3" enabled="yes" priority="3" onescope="is_pad_smd" otherscope="is_pad_smd" value="6mil" preferredvalue="6mil" samesignal="no" name="copper-clearance-4"/>+ <rule type="Copper Clearance" builtin_ruleid="4" enabled="yes" priority="4" onescope="is_pad_smd" otherscope="is_via" value="6mil" preferredvalue="6mil" samesignal="no" name="copper-clearance-5"/>+ <rule type="Copper Clearance" builtin_ruleid="5" enabled="yes" priority="5" onescope="is_via" otherscope="is_via" value="6mil" preferredvalue="6mil" samesignal="no" name="copper-clearance-6"/>+ <rule type="Copper Clearance" builtin_ruleid="6" enabled="yes" priority="6" onescope="is_smd" otherscope="is_pad" value="6mil" preferredvalue="6mil" samesignal="yes" name="copper-clearance-7"/>+ <rule type="Copper Clearance" builtin_ruleid="7" enabled="yes" priority="7" onescope="is_smd" otherscope="is_via" value="6mil" preferredvalue="6mil" samesignal="yes" name="copper-clearance-8"/>+ <rule type="Copper Clearance" builtin_ruleid="8" enabled="yes" priority="8" onescope="is_smd" otherscope="is_smd" value="6mil" preferredvalue="6mil" samesignal="yes" name="copper-clearance-9"/>+ <rule type="Dimension Clearance" builtin_ruleid="9" enabled="yes" priority="0" value="0.5mm" preferredvalue="0.5mm" name="dimension-clearance-1"/>+ <rule type="Via Restrict Clearance" builtin_ruleid="21" enabled="yes" priority="0" value="0mil" preferredvalue="0mil" name="via-restrict-clearance-1"/>+ <rule type="Restrict Clearance" builtin_ruleid="10" enabled="yes" priority="0" value="0mil" preferredvalue="0mil" name="restrict-clearance-1"/>+ <rule type="Small Gap" builtin_ruleid="18" enabled="yes" priority="0" name="small-gap-1"/>+ <rule type="Solder-Mask Clearance" builtin_ruleid="11" enabled="no" priority="0" value="0mil" preferredvalue="0mil" check_name="yes" check_value="no" name="solder-mask-clearance-1"/>+ <rule type="Drill Distance" builtin_ruleid="12" enabled="yes" priority="0" value="6mil" preferredvalue="6mil" name="drill-distance-1"/>+ <rule type="Keepout Clearance" builtin_ruleid="13" enabled="yes" priority="0" value="0mil" preferredvalue="0mil" name="keepout-clearance-1"/>+ </rules>+<param name="mdWireWire" value="0.2mm"/>+<param name="mdWirePad" value="0.2mm"/>+<param name="mdWireVia" value="0.2mm"/>+<param name="mdPadPad" value="6mil"/>+<param name="mdPadVia" value="6mil"/>+<param name="mdViaVia" value="6mil"/>+<param name="mdSmdPad" value="6mil"/>+<param name="mdSmdVia" value="6mil"/>+<param name="mdSmdSmd" value="6mil"/>+<param name="mdCopperDimension" value="0.5mm"/>+<param name="mdDrill" value="6mil"/>+<param name="msWidth" value="0.2mm"/>+<param name="msDrill" value="0.3mm"/>+<param name="dpMaxLengthDifference" value="10mm"/>+<param name="dpGapFactor" value="2.5"/>+<description language="en"><b>Fusion Electronics Design Rules</b>+<p>+The default Design Rules have been set to cover+a wide range of applications. Your particular design+may have different requirements, so please make the+necessary adjustments and save your customized+design rules under a new name.+</description>+<param name="layerSetup" value="(1*16)"/>+<param name="mtCopper" value="0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm"/>+<param name="mtIsolate" value="1.5mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm"/>+<param name="mdViaViaSameLayer" value="6mil"/>+<param name="mnLayersViaInSmd" value="2"/>+<param name="mdSmdStop" value="0mil"/>+<param name="msMicroVia" value="9.99mm"/>+<param name="msBlindViaRatio" value="0.5"/>+<param name="rvPadTop" value="0.25"/>+<param name="rvPadInner" value="0.25"/>+<param name="rvPadBottom" value="0.25"/>+<param name="rvViaOuter" value="0.25"/>+<param name="rvViaInner" value="0.25"/>+<param name="rvMicroViaOuter" value="0.25"/>+<param name="rvMicroViaInner" value="0.25"/>+<param name="rlMinPadTop" value="10mil"/>+<param name="rlMaxPadTop" value="20mil"/>+<param name="rlMinPadInner" value="10mil"/>+<param name="rlMaxPadInner" value="20mil"/>+<param name="rlMinPadBottom" value="10mil"/>+<param name="rlMaxPadBottom" value="20mil"/>+<param name="rlMinViaOuter" value="8mil"/>+<param name="rlMaxViaOuter" value="20mil"/>+<param name="rlMinViaInner" value="8mil"/>+<param name="rlMaxViaInner" value="20mil"/>+<param name="rlMinMicroViaOuter" value="4mil"/>+<param name="rlMaxMicroViaOuter" value="20mil"/>+<param name="rlMinMicroViaInner" value="4mil"/>+<param name="rlMaxMicroViaInner" value="20mil"/>+<param name="psTop" value="-1"/>+<param name="psBottom" value="-1"/>+<param name="psFirst" value="-1"/>+<param name="psElongationLong" value="100"/>+<param name="psElongationOffset" value="100"/>+<param name="mvStopFrame" value="1"/>+<param name="mvCreamFrame" value="0"/>+<param name="mlMinStopFrame" value="4mil"/>+<param name="mlMaxStopFrame" value="4mil"/>+<param name="mlMinCreamFrame" value="0mil"/>+<param name="mlMaxCreamFrame" value="0mil"/>+<param name="mlViaStopLimit" value="9999mil"/>+<param name="srRoundness" value="0"/>+<param name="srMinRoundness" value="0mil"/>+<param name="srMaxRoundness" value="0mil"/>+<param name="slThermalIsolate" value="10mil"/>+<param name="slThermalsForVias" value="0"/>+<param name="checkAngle" value="0"/>+<param name="checkRestrict" value="1"/>+<param name="checkStop" value="0"/>+<param name="checkValues" value="0"/>+<param name="checkNames" value="1"/>+<param name="checkWireStubs" value="1"/>+<param name="checkPolygonWidth" value="0"/>+<param name="useDiameter" value="13"/>+<param name="removeAnnularRing" value="0"/>+<param name="flattenRefDes" value="0"/>+<param name="maxErrors" value="999999"/>+<layerstackup name="Default Layer Stack" type="Standard Stackup" display_unit="mic" roughness_model="0">+ <layerdef type="Signal" id="{226fbb53-3ea5-4bcd-b528-5e263f8d800e}" layer="1" name="Top" locally_modified_material="yes">+ <material name="User Defined" thickness="0.035mm" weight="1oz" process="Electro Deposited" source="User"/>+</layerdef>+ <layerdef type="Core" id="{67c846d1-478c-423c-8354-73209f33e701}" layer="1" name="Dielectric-1" locally_modified_material="yes">+ <material name="User Defined" construction="" thickness="1.5mm" resin="50%" dielectric_constant_1g="4.5" dissipation_factor_1g="0.02" glass_transition_temperature="125degC" source="User"/>+</layerdef>+ <layerdef type="Signal" id="{8905b0d7-6f87-4373-9db3-00363a553149}" layer="16" name="Bottom" locally_modified_material="yes">+ <material name="User Defined" thickness="0.035mm" weight="1oz" process="Electro Deposited" source="User"/>+</layerdef>+ <viadef name="Thru 1:16" startlayer="1" stoplayer="16" complement="no"/>+ </layerstackup>+ </designrules>+<autorouter>+<pass name="Default">+<param name="RoutingGrid" value="50mil"/>+<param name="AutoGrid" value="1"/>+<param name="Efforts" value="0"/>+<param name="TopRouterVariant" value="1"/>+<param name="tpViaShape" value="round"/>+<param name="PrefDir.1" value="a"/>+<param name="PrefDir.2" value="0"/>+<param name="PrefDir.3" value="0"/>+<param name="PrefDir.4" value="0"/>+<param name="PrefDir.5" value="0"/>+<param name="PrefDir.6" value="0"/>+<param name="PrefDir.7" value="0"/>+<param name="PrefDir.8" value="0"/>+<param name="PrefDir.9" value="0"/>+<param name="PrefDir.10" value="0"/>+<param name="PrefDir.11" value="0"/>+<param name="PrefDir.12" value="0"/>+<param name="PrefDir.13" value="0"/>+<param name="PrefDir.14" value="0"/>+<param name="PrefDir.15" value="0"/>+<param name="PrefDir.16" value="a"/>+<param name="cfVia" value="8"/>+<param name="cfNonPref" value="5"/>+<param name="cfChangeDir" value="2"/>+<param name="cfOrthStep" value="2"/>+<param name="cfDiagStep" value="3"/>+<param name="cfExtdStep" value="0"/>+<param name="cfBonusStep" value="1"/>+<param name="cfMalusStep" value="1"/>+<param name="cfPadImpact" value="4"/>+<param name="cfSmdImpact" value="4"/>+<param name="cfBusImpact" value="0"/>+<param name="cfHugging" value="3"/>+<param name="cfAvoid" value="4"/>+<param name="cfPolygon" value="10"/>+<param name="cfBase.1" value="0"/>+<param name="cfBase.2" value="1"/>+<param name="cfBase.3" value="1"/>+<param name="cfBase.4" value="1"/>+<param name="cfBase.5" value="1"/>+<param name="cfBase.6" value="1"/>+<param name="cfBase.7" value="1"/>+<param name="cfBase.8" value="1"/>+<param name="cfBase.9" value="1"/>+<param name="cfBase.10" value="1"/>+<param name="cfBase.11" value="1"/>+<param name="cfBase.12" value="1"/>+<param name="cfBase.13" value="1"/>+<param name="cfBase.14" value="1"/>+<param name="cfBase.15" value="1"/>+<param name="cfBase.16" value="0"/>+<param name="mnVias" value="20"/>+<param name="mnSegments" value="9999"/>+<param name="mnExtdSteps" value="9999"/>+<param name="mnRipupLevel" value="10"/>+<param name="mnRipupSteps" value="100"/>+<param name="mnRipupTotal" value="100"/>+</pass>+<pass name="Follow-me" refer="Default" active="yes">+</pass>+<pass name="Busses" refer="Default" active="yes">+<param name="cfNonPref" value="4"/>+<param name="cfBusImpact" value="4"/>+<param name="cfHugging" value="0"/>+<param name="mnVias" value="0"/>+</pass>+<pass name="Route" refer="Default" active="yes">+</pass>+<pass name="Optimize1" refer="Default" active="yes">+<param name="cfVia" value="99"/>+<param name="cfExtdStep" value="10"/>+<param name="cfHugging" value="1"/>+<param name="mnExtdSteps" value="1"/>+<param name="mnRipupLevel" value="0"/>+</pass>+<pass name="Optimize2" refer="Optimize1" active="yes">+<param name="cfNonPref" value="0"/>+<param name="cfChangeDir" value="6"/>+<param name="cfExtdStep" value="0"/>+<param name="cfBonusStep" value="2"/>+<param name="cfMalusStep" value="2"/>+<param name="cfPadImpact" value="2"/>+<param name="cfSmdImpact" value="2"/>+<param name="cfHugging" value="0"/>+</pass>+<pass name="Optimize3" refer="Optimize2" active="yes">+<param name="cfChangeDir" value="8"/>+<param name="cfPadImpact" value="0"/>+<param name="cfSmdImpact" value="0"/>+</pass>+<pass name="Optimize4" refer="Optimize3" active="yes">+<param name="cfChangeDir" value="25"/>+</pass>+</autorouter>+<elements>+<element name="L1" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="5" y="8" smashed="yes">+</element>+<element name="R1" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="45" y="8" smashed="yes">+</element>+<element name="L2" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="5" y="20" smashed="yes">+</element>+<element name="R2" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="45" y="20" smashed="yes">+</element>+<element name="L3" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="5" y="32" smashed="yes">+</element>+<element name="R3" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="45" y="32" smashed="yes">+</element>+</elements>+<signals>+<signal name="ROUTE_1">+<contactref element="L1" pad="1"/>+<contactref element="R1" pad="1"/>+<wire x1="5" y1="8" x2="21" y2="8" width="0.25" layer="1"/>+<wire x1="21" y1="8" x2="21" y2="1" width="0.25" layer="1"/>+<wire x1="21" y1="1" x2="45" y2="1" width="0.25" layer="1"/>+<wire x1="45" y1="1" x2="45" y2="8" width="0.25" layer="1"/>+</signal>+<signal name="ROUTE_2">+<contactref element="L2" pad="1"/>+<contactref element="R2" pad="1"/>+<wire x1="5" y1="20" x2="20.5" y2="20" width="0.25" layer="1"/>+<via x="20.5" y="20" extent="1-16" drill="0.3" diameter="0.6" solderMask="auto">+</via>+<wire x1="20.5" y1="20" x2="30.5" y2="20" width="0.25" layer="16"/>+<via x="30.5" y="20" extent="1-16" drill="0.3" diameter="0.6" solderMask="auto">+</via>+<wire x1="30.5" y1="20" x2="45" y2="20" width="0.25" layer="1"/>+</signal>+<signal name="ROUTE_3">+<contactref element="L3" pad="1"/>+<contactref element="R3" pad="1"/>+<wire x1="5" y1="32" x2="45" y2="32" width="0.25" layer="1"/>+</signal>+<signal name="TOP_BARRIER">+<wire x1="22" y1="2" x2="22" y2="28" width="1" layer="1"/>+</signal>+<signal name="BOTTOM_BARRIER">+<wire x1="32" y1="12" x2="32" y2="37" width="1" layer="16"/>+</signal>+</signals>+<mfgpreviewcolors>+<mfgpreviewcolor name="soldermaskcolor" color="0xC8008000"/>+<mfgpreviewcolor name="silkscreencolor" color="0xFFFEFEFE"/>+<mfgpreviewcolor name="backgroundcolor" color="0xFF282828"/>+<mfgpreviewcolor name="coppercolor" color="0xFFFFBF00"/>+<mfgpreviewcolor name="substratecolor" color="0xFF786E46"/>+</mfgpreviewcolors>+</board>+</drawing>+<compatibility>+<note version="9.7" severity="warning">+Since Fusion, design files support named views saved in design. +Named views found in the design will not be understood with this version. +</note>+<note version="9.7" minversion="9.7.0" severity="warning">+Since Version 9.7.0 new layer stackup definition has been added,+which will not be loaded with this version.+</note>+<note version="9.7" minversion="9.7.0" severity="warning">+Since Version 9.7.0 new active CAMJOB file name has been added,+which will not be loaded with this version.+</note>+<note version="9.7" minversion="9.7.0" severity="warning">+Since Version 9.7.0 board construction lines has been added,+which will not be loaded with this version.+</note>+<note version="9.7" minversion="9.7.0" severity="warning">+Since Version 9.7.0 new design rule definitions have been added,+which will not be loaded with this version.+</note>+</compatibility>+</eagle>
demo/routing/obstacles/take-03/fusion-obstacle-routed.fbrdadded⋯ 1 unchanged line ⋯
demo/routing/obstacles/take-03/plan-1.jsonadded+122@@ -0,0 +1,122 @@+{+ "_timeoutHint": "ab waits up to 60s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `fusion_get_app_state` until it reports done.",+ "boardId": "533f7a6b-1e47-4e31-9a8a-b839c5ad45f8",+ "bridgeVersion": "1.10.0-dev.routing.4",+ "documentName": "fusion-obstacle-lab-v2",+ "durationMs": 244,+ "error": "",+ "mutated": false,+ "plan": {+ "clearance": 0.2,+ "items": [+ {+ "end": [+ 21.0,+ 8.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 5.0,+ 8.0+ ],+ "width": 0.25+ },+ {+ "end": [+ 21.0,+ 1.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 21.0,+ 8.0+ ],+ "width": 0.25+ },+ {+ "end": [+ 45.0,+ 1.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 21.0,+ 1.0+ ],+ "width": 0.25+ },+ {+ "end": [+ 45.0,+ 8.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 45.0,+ 1.0+ ],+ "width": 0.25+ }+ ],+ "net": "ROUTE_1",+ "planner": {+ "algorithm": "bounded orthogonal two-layer A*",+ "elapsedMs": 22.255,+ "expandedNodes": 1795,+ "externalRouter": false,+ "grid": 0.5,+ "lengthMm": 54.0,+ "viaCount": 0+ },+ "preflight": "Conservative geometry only; run native Autodesk DRC after edits",+ "route": {+ "clearance": 0.2,+ "layer": 1,+ "net": "ROUTE_1",+ "points": [+ {+ "layer": 1,+ "x": 5.0,+ "y": 8.0+ },+ {+ "layer": 1,+ "x": 21.0,+ "y": 8.0+ },+ {+ "layer": 1,+ "x": 21.0,+ "y": 1.0+ },+ {+ "layer": 1,+ "x": 45.0,+ "y": 1.0+ },+ {+ "layer": 1,+ "x": 45.0,+ "y": 8.0+ }+ ],+ "viaDiameter": 0.6,+ "viaDrill": 0.3,+ "width": 0.25+ }+ },+ "revision": "6f38e486788364627c73ee1d62f8b5affc9d296ba8c7b3d562f260a96f1c279e",+ "shell": "rust",+ "status": "ok",+ "statusVerb": "fusion_get_app_state",+ "success": true,+ "timeoutSeconds": 60+}
demo/routing/obstacles/take-03/plan-2.jsonadded+125@@ -0,0 +1,125 @@+{+ "_timeoutHint": "ab waits up to 60s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `fusion_get_app_state` until it reports done.",+ "boardId": "533f7a6b-1e47-4e31-9a8a-b839c5ad45f8",+ "bridgeVersion": "1.10.0-dev.routing.4",+ "documentName": "fusion-obstacle-lab-v2",+ "durationMs": 252,+ "error": "",+ "mutated": false,+ "plan": {+ "clearance": 0.2,+ "items": [+ {+ "end": [+ 20.5,+ 20.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_2",+ "start": [+ 5.0,+ 20.0+ ],+ "width": 0.25+ },+ {+ "at": [+ 20.5,+ 20.0+ ],+ "diameter": 0.6,+ "drill": 0.3,+ "extent": "1-16",+ "kind": "via",+ "net": "ROUTE_2"+ },+ {+ "end": [+ 30.5,+ 20.0+ ],+ "kind": "segment",+ "layer": 16,+ "net": "ROUTE_2",+ "start": [+ 20.5,+ 20.0+ ],+ "width": 0.25+ },+ {+ "at": [+ 30.5,+ 20.0+ ],+ "diameter": 0.6,+ "drill": 0.3,+ "extent": "1-16",+ "kind": "via",+ "net": "ROUTE_2"+ },+ {+ "end": [+ 45.0,+ 20.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_2",+ "start": [+ 30.5,+ 20.0+ ],+ "width": 0.25+ }+ ],+ "net": "ROUTE_2",+ "planner": {+ "algorithm": "bounded orthogonal two-layer A*",+ "elapsedMs": 21.654,+ "expandedNodes": 882,+ "externalRouter": false,+ "grid": 0.5,+ "lengthMm": 40.0,+ "viaCount": 2+ },+ "preflight": "Conservative geometry only; run native Autodesk DRC after edits",+ "route": {+ "clearance": 0.2,+ "layer": 1,+ "net": "ROUTE_2",+ "points": [+ {+ "layer": 1,+ "x": 5.0,+ "y": 20.0+ },+ {+ "layer": 16,+ "x": 20.5,+ "y": 20.0+ },+ {+ "layer": 1,+ "x": 30.5,+ "y": 20.0+ },+ {+ "layer": 1,+ "x": 45.0,+ "y": 20.0+ }+ ],+ "viaDiameter": 0.6,+ "viaDrill": 0.3,+ "width": 0.25+ }+ },+ "revision": "cb6d0e2d4d171ecc977186e2d9355d1eb0edbac7ee70016f141883bc7527191c",+ "shell": "rust",+ "status": "ok",+ "statusVerb": "fusion_get_app_state",+ "success": true,+ "timeoutSeconds": 60+}
demo/routing/obstacles/take-03/plan-3.jsonadded+65@@ -0,0 +1,65 @@+{+ "_timeoutHint": "ab waits up to 60s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `fusion_get_app_state` until it reports done.",+ "boardId": "533f7a6b-1e47-4e31-9a8a-b839c5ad45f8",+ "bridgeVersion": "1.10.0-dev.routing.4",+ "documentName": "fusion-obstacle-lab-v2",+ "durationMs": 229,+ "error": "",+ "mutated": false,+ "plan": {+ "clearance": 0.2,+ "items": [+ {+ "end": [+ 45.0,+ 32.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_3",+ "start": [+ 5.0,+ 32.0+ ],+ "width": 0.25+ }+ ],+ "net": "ROUTE_3",+ "planner": {+ "algorithm": "bounded orthogonal two-layer A*",+ "elapsedMs": 3.4,+ "expandedNodes": 81,+ "externalRouter": false,+ "grid": 0.5,+ "lengthMm": 40.0,+ "viaCount": 0+ },+ "preflight": "Conservative geometry only; run native Autodesk DRC after edits",+ "route": {+ "clearance": 0.2,+ "layer": 1,+ "net": "ROUTE_3",+ "points": [+ {+ "layer": 1,+ "x": 5.0,+ "y": 32.0+ },+ {+ "layer": 1,+ "x": 45.0,+ "y": 32.0+ }+ ],+ "viaDiameter": 0.6,+ "viaDrill": 0.3,+ "width": 0.25+ }+ },+ "revision": "ab4ed3405141445e7586948225c1d56e11e2a31052a5bc6a2df1cac7d0087328",+ "shell": "rust",+ "status": "ok",+ "statusVerb": "fusion_get_app_state",+ "success": true,+ "timeoutSeconds": 60+}
demo/routing/obstacles/take-03/record-start.jsonadded+31@@ -0,0 +1,31 @@+{+ "_hint": "Native window recording (WGC): background-capturable, no picker. Stop with desktop_record_stop {recordingId}; pull the MP4 with pull_file.",+ "audio": false,+ "audioNote": null,+ "audioRate": 0,+ "codec": "h264",+ "durationMs": 955,+ "encoder": "NVIDIA H.264 Encoder MFT",+ "error": "",+ "fps": 30,+ "hardwareEncoder": true,+ "height": 38,+ "hwnd": 8916576,+ "kind": "window",+ "maxDurationMs": 180000,+ "path": "C:/Users/john/AppData/Local/Temp/adom-bridge-recordings/window-8916576-20260905-221449.mp4",+ "recordingId": "rec-ffedbbb17d5f434bb0aca783f706c2ad",+ "status": "ok",+ "success": true,+ "timeoutSeconds": 15,+ "title": "fusion-obstacle-lab-v2* (jlauerhub) - Autodesk Fusion (Trial ends in 16 days) ",+ "width": 218,+ "data": {+ "height": 38,+ "kind": "window",+ "path": "C:\\Users\\john\\AppData\\Local\\Temp\\adom-bridge-recordings\\window-8916576-20260905-221449.mp4",+ "recordingId": "rec-ffedbbb17d5f434bb0aca783f706c2ad",+ "width": 218+ },+ "message": "Recording window \"fusion-obstacle-lab-v2* (jlauerhub) - Autodesk Fusion (Trial ends in 16 days) \" -> C:\\Users\\john\\AppData\\Local\\Temp\\adom-bridge-recordings\\window-8916576-20260905-221449.mp4 (218x38 @ 30fps h264)"+}
demo/routing/obstacles/take-04/before.jsonadded+217@@ -0,0 +1,217 @@+{+ "_timeoutHint": "ab waits up to 60s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `fusion_get_app_state` until it reports done.",+ "airwireCount": 3,+ "boardId": "388efa26-6c67-4cc1-860e-4d4579cd896f",+ "bridgeVersion": "1.10.0-dev.routing.4",+ "connectivitySource": "Fusion exported airwires; mutation paths recompute RATSNEST",+ "documentName": "fusion-obstacle-lab-v3",+ "drc": {+ "checked": false,+ "note": "Use fusion_routing_drc for a fresh Autodesk DRC"+ },+ "durationMs": 216,+ "error": "",+ "nets": [+ {+ "airwireCount": 1,+ "airwires": [+ {+ "end": [+ 45.0,+ 8.0+ ],+ "start": [+ 5.0,+ 8.0+ ]+ }+ ],+ "name": "ROUTE_1",+ "pads": [+ "L1.1",+ "R1.1"+ ],+ "segments": 0,+ "vias": 0+ },+ {+ "airwireCount": 1,+ "airwires": [+ {+ "end": [+ 45.0,+ 20.0+ ],+ "start": [+ 5.0,+ 20.0+ ]+ }+ ],+ "name": "ROUTE_2",+ "pads": [+ "L2.1",+ "R2.1"+ ],+ "segments": 0,+ "vias": 0+ },+ {+ "airwireCount": 1,+ "airwires": [+ {+ "end": [+ 45.0,+ 32.0+ ],+ "start": [+ 5.0,+ 32.0+ ]+ }+ ],+ "name": "ROUTE_3",+ "pads": [+ "L3.1",+ "R3.1"+ ],+ "segments": 0,+ "vias": 0+ },+ {+ "airwireCount": 0,+ "airwires": [],+ "name": "TOP_BARRIER",+ "pads": [],+ "segments": 1,+ "vias": 0+ },+ {+ "airwireCount": 0,+ "airwires": [],+ "name": "BOTTOM_BARRIER",+ "pads": [],+ "segments": 1,+ "vias": 0+ }+ ],+ "pads": [+ {+ "at": [+ 5.0,+ 8.0+ ],+ "layers": [+ 1+ ],+ "name": "L1.1",+ "net": "ROUTE_1",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 45.0,+ 8.0+ ],+ "layers": [+ 1+ ],+ "name": "R1.1",+ "net": "ROUTE_1",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 5.0,+ 20.0+ ],+ "layers": [+ 1+ ],+ "name": "L2.1",+ "net": "ROUTE_2",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 45.0,+ 20.0+ ],+ "layers": [+ 1+ ],+ "name": "R2.1",+ "net": "ROUTE_2",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 5.0,+ 32.0+ ],+ "layers": [+ 1+ ],+ "name": "L3.1",+ "net": "ROUTE_3",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 45.0,+ 32.0+ ],+ "layers": [+ 1+ ],+ "name": "R3.1",+ "net": "ROUTE_3",+ "radius": 1.0606601717798212+ }+ ],+ "remainingNets": [+ "ROUTE_1",+ "ROUTE_2",+ "ROUTE_3"+ ],+ "revision": "55e607daca93bdd86250dfaa24e95179cad8a7ced289ba309cc56f634d94ba36",+ "segmentCount": 2,+ "segments": [+ {+ "curve": 0.0,+ "end": [+ 22.0,+ 28.0+ ],+ "layer": 1,+ "net": "TOP_BARRIER",+ "start": [+ 22.0,+ 2.0+ ],+ "width": 1.0+ },+ {+ "curve": 0.0,+ "end": [+ 32.0,+ 37.0+ ],+ "layer": 16,+ "net": "BOTTOM_BARRIER",+ "start": [+ 32.0,+ 12.0+ ],+ "width": 1.0+ }+ ],+ "shell": "rust",+ "status": "ok",+ "statusVerb": "fusion_get_app_state",+ "success": true,+ "timeoutSeconds": 60,+ "units": "mm",+ "viaCount": 0,+ "vias": []+}
demo/routing/obstacles/take-04/calls.json.gzadded⋯ 1 unchanged line ⋯
demo/routing/obstacles/take-04/final.jsonadded+318@@ -0,0 +1,318 @@+{+ "_timeoutHint": "ab waits up to 60s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `fusion_get_app_state` until it reports done.",+ "airwireCount": 0,+ "boardId": "388efa26-6c67-4cc1-860e-4d4579cd896f",+ "bridgeVersion": "1.10.0-dev.routing.4",+ "connectivitySource": "Fusion exported airwires; mutation paths recompute RATSNEST",+ "documentName": "fusion-obstacle-lab-v3",+ "drc": {+ "airwireCount": 0,+ "checked": true,+ "clean": true,+ "errorCount": 0,+ "errors": [],+ "source": "Autodesk DRC + UL_BOARD.errors",+ "warningCount": 0+ },+ "durationMs": 743,+ "error": "",+ "nets": [+ {+ "airwireCount": 0,+ "airwires": [],+ "name": "ROUTE_1",+ "pads": [+ "L1.1",+ "R1.1"+ ],+ "segments": 4,+ "vias": 0+ },+ {+ "airwireCount": 0,+ "airwires": [],+ "name": "ROUTE_2",+ "pads": [+ "L2.1",+ "R2.1"+ ],+ "segments": 3,+ "vias": 2+ },+ {+ "airwireCount": 0,+ "airwires": [],+ "name": "ROUTE_3",+ "pads": [+ "L3.1",+ "R3.1"+ ],+ "segments": 1,+ "vias": 0+ },+ {+ "airwireCount": 0,+ "airwires": [],+ "name": "TOP_BARRIER",+ "pads": [],+ "segments": 1,+ "vias": 0+ },+ {+ "airwireCount": 0,+ "airwires": [],+ "name": "BOTTOM_BARRIER",+ "pads": [],+ "segments": 1,+ "vias": 0+ }+ ],+ "pads": [+ {+ "at": [+ 5.0,+ 8.0+ ],+ "layers": [+ 1+ ],+ "name": "L1.1",+ "net": "ROUTE_1",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 45.0,+ 8.0+ ],+ "layers": [+ 1+ ],+ "name": "R1.1",+ "net": "ROUTE_1",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 5.0,+ 20.0+ ],+ "layers": [+ 1+ ],+ "name": "L2.1",+ "net": "ROUTE_2",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 45.0,+ 20.0+ ],+ "layers": [+ 1+ ],+ "name": "R2.1",+ "net": "ROUTE_2",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 5.0,+ 32.0+ ],+ "layers": [+ 1+ ],+ "name": "L3.1",+ "net": "ROUTE_3",+ "radius": 1.0606601717798212+ },+ {+ "at": [+ 45.0,+ 32.0+ ],+ "layers": [+ 1+ ],+ "name": "R3.1",+ "net": "ROUTE_3",+ "radius": 1.0606601717798212+ }+ ],+ "remainingNets": [],+ "revision": "66d0eea7f9b13ecf7e454ea4527556ae1845308bf20311cfdc1914c1b95e64d5",+ "segmentCount": 10,+ "segments": [+ {+ "curve": 0.0,+ "end": [+ 21.0,+ 8.0+ ],+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 5.0,+ 8.0+ ],+ "width": 0.25+ },+ {+ "curve": 0.0,+ "end": [+ 21.0,+ 1.0+ ],+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 21.0,+ 8.0+ ],+ "width": 0.25+ },+ {+ "curve": 0.0,+ "end": [+ 45.0,+ 1.0+ ],+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 21.0,+ 1.0+ ],+ "width": 0.25+ },+ {+ "curve": 0.0,+ "end": [+ 45.0,+ 8.0+ ],+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 45.0,+ 1.0+ ],+ "width": 0.25+ },+ {+ "curve": 0.0,+ "end": [+ 20.5,+ 20.0+ ],+ "layer": 1,+ "net": "ROUTE_2",+ "start": [+ 5.0,+ 20.0+ ],+ "width": 0.25+ },+ {+ "curve": 0.0,+ "end": [+ 30.5,+ 20.0+ ],+ "layer": 16,+ "net": "ROUTE_2",+ "start": [+ 20.5,+ 20.0+ ],+ "width": 0.25+ },+ {+ "curve": 0.0,+ "end": [+ 45.0,+ 20.0+ ],+ "layer": 1,+ "net": "ROUTE_2",+ "start": [+ 30.5,+ 20.0+ ],+ "width": 0.25+ },+ {+ "curve": 0.0,+ "end": [+ 45.0,+ 32.0+ ],+ "layer": 1,+ "net": "ROUTE_3",+ "start": [+ 5.0,+ 32.0+ ],+ "width": 0.25+ },+ {+ "curve": 0.0,+ "end": [+ 22.0,+ 28.0+ ],+ "layer": 1,+ "net": "TOP_BARRIER",+ "start": [+ 22.0,+ 2.0+ ],+ "width": 1.0+ },+ {+ "curve": 0.0,+ "end": [+ 32.0,+ 37.0+ ],+ "layer": 16,+ "net": "BOTTOM_BARRIER",+ "start": [+ 32.0,+ 12.0+ ],+ "width": 1.0+ }+ ],+ "shell": "rust",+ "status": "ok",+ "statusVerb": "fusion_get_app_state",+ "success": true,+ "timeoutSeconds": 60,+ "units": "mm",+ "viaCount": 2,+ "vias": [+ {+ "at": [+ 20.5,+ 20.0+ ],+ "diameter": 0.6,+ "drill": 0.3,+ "extent": "1-16",+ "net": "ROUTE_2"+ },+ {+ "at": [+ 30.5,+ 20.0+ ],+ "diameter": 0.6,+ "drill": 0.3,+ "extent": "1-16",+ "net": "ROUTE_2"+ }+ ]+}
demo/routing/obstacles/take-04/fusion-obstacle-live-routed.brdadded+413@@ -0,0 +1,413 @@+<?xml version="1.0" encoding="utf-8"?>+<!DOCTYPE eagle SYSTEM "eagle.dtd">+<eagle version="9.7.0">+<drawing>+<settings>+<setting alwaysvectorfont="no"/>+<setting verticaltext="up"/>+<setting violationmode="Push"/>+<drillsymbolsettings symboldiameter="650240" symbolwidth="8128">+<drill diameter="64000" />+<drill diameter="80000" />+<drill diameter="96000" />+<drill diameter="112000" />+<drill diameter="128000" />+<drill diameter="144000" />+<drill diameter="160000" />+<drill diameter="176000" />+<drill diameter="192000" />+<drill diameter="208000" />+<drill diameter="224000" />+<drill diameter="240000" />+<drill diameter="256000" />+<drill diameter="272000" />+<drill diameter="288000" />+<drill diameter="320000" />+</drillsymbolsettings>+</settings>+<grid distance="1" unitdist="mm" unit="mm" style="lines" multiple="1" display="no" altdistance="0.1" altunitdist="mm" altunit="mm"/>+<layers>+<layer number="1" name="Top" blackcolor="0xc8ff4164" whitecolor="0xccc90d0c" coloredcolor="0xccc90d0c" blackhighlight="0xccff0000" whitehighlight="0xb4ff0000" coloredhighlight="0xb4ff0000" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="16" name="Bottom" blackcolor="0xc80696d7" whitecolor="0xcc0696d7" coloredcolor="0xcc0696d7" blackhighlight="0xb40000ff" whitehighlight="0xcc8252c2" coloredhighlight="0xcc8252c2" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="17" name="Pads" blackcolor="0xb462d987" whitecolor="0xb462d987" coloredcolor="0xcc0dab76" blackhighlight="0xb400ff00" whitehighlight="0xb400ff00" coloredhighlight="0xb400ff00" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="18" name="Vias" blackcolor="0xb462d987" whitecolor="0xb462d987" coloredcolor="0xccffcd07" blackhighlight="0xb462d987" whitehighlight="0xb462d987" coloredhighlight="0xccffcd07" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="19" name="Unrouted" blackcolor="0xccd9d9d9" whitecolor="0xbbc8c832" coloredcolor="0xbbc8c832" blackhighlight="0xb462d987" whitehighlight="0xb462d987" coloredhighlight="0xccffcd07" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="20" name="Dimension" blackcolor="0xb462d986" whitecolor="0xb462d986" coloredcolor="0xcceec643" blackhighlight="0xb462d986" whitehighlight="0xb462d986" coloredhighlight="0xcceec643" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="21" name="tPlace" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd134" coloredhighlight="0xccafd134" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="22" name="bPlace" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd134" coloredhighlight="0xccafd134" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="23" name="tOrigins" blackcolor="0xc8ffffff" whitecolor="0xccafd134" coloredcolor="0xccafd134" blackhighlight="0xc8ffffff" whitehighlight="0xccafd134" coloredhighlight="0xccafd134" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="24" name="bOrigins" blackcolor="0xc8ffffff" whitecolor="0xccafd134" coloredcolor="0xccafd134" blackhighlight="0xc8ffffff" whitehighlight="0xccafd134" coloredhighlight="0xccafd134" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="25" name="tNames" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd134" coloredhighlight="0xccafd134" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="26" name="bNames" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd134" coloredhighlight="0xccafd134" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="27" name="tValues" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd135" coloredhighlight="0xccafd135" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="28" name="bValues" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd136" coloredhighlight="0xccafd136" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="29" name="tStop" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd137" coloredhighlight="0xccafd137" fill="3" visible="no" active="yes" locked="no"/>+<layer number="30" name="bStop" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd138" coloredhighlight="0xccafd138" fill="6" visible="no" active="yes" locked="no"/>+<layer number="31" name="tCream" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd139" coloredhighlight="0xccafd139" fill="4" visible="no" active="yes" locked="no"/>+<layer number="32" name="bCream" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd140" coloredhighlight="0xccafd140" fill="5" visible="no" active="yes" locked="no"/>+<layer number="33" name="tFinish" blackcolor="0xccd9d9d9" whitecolor="0xbbc8c832" coloredcolor="0xbbc8c832" blackhighlight="0xb462d987" whitehighlight="0xb462d987" coloredhighlight="0xccffcd07" fill="3" visible="no" active="yes" locked="no"/>+<layer number="34" name="bFinish" blackcolor="0xccd9d9d9" whitecolor="0xbbc8c832" coloredcolor="0xbbc8c832" blackhighlight="0xb462d987" whitehighlight="0xb462d987" coloredhighlight="0xccffcd07" fill="6" visible="no" active="yes" locked="no"/>+<layer number="35" name="tGlue" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd140" coloredhighlight="0xccafd140" fill="4" visible="no" active="yes" locked="no"/>+<layer number="36" name="bGlue" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd140" coloredhighlight="0xccafd140" fill="5" visible="no" active="yes" locked="no"/>+<layer number="37" name="tTest" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd140" coloredhighlight="0xccafd140" fill="1" visible="no" active="yes" locked="no"/>+<layer number="38" name="bTest" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd140" coloredhighlight="0xccafd140" fill="1" visible="no" active="yes" locked="no"/>+<layer number="39" name="tKeepout" blackcolor="0xc8ff4164" whitecolor="0xccc90d0c" coloredcolor="0xccc90d0c" blackhighlight="0xccff0000" whitehighlight="0xb4ff0000" coloredhighlight="0xb4ff0000" fill="11" visible="no" active="yes" locked="no"/>+<layer number="40" name="bKeepout" blackcolor="0xc80696d7" whitecolor="0xcc0696d7" coloredcolor="0xcc0696d7" blackhighlight="0xb40000ff" whitehighlight="0xcc8252c2" coloredhighlight="0xcc8252c2" fill="11" visible="no" active="yes" locked="no"/>+<layer number="41" name="RestrictCopper" blackcolor="0xc8ff4164" whitecolor="0xccc90d0c" coloredcolor="0xccc90d0c" blackhighlight="0xccff0000" whitehighlight="0xb4ff0000" coloredhighlight="0xb4ff0000" fill="10" visible="no" active="yes" locked="no"/>+<layer number="42" name="bRestrict" blackcolor="0xc80696d7" whitecolor="0xcc0696d7" coloredcolor="0xcc0696d7" blackhighlight="0xb40000ff" whitehighlight="0xcc8252c2" coloredhighlight="0xcc8252c2" fill="10" visible="no" active="yes" locked="no"/>+<layer number="43" name="vRestrict" blackcolor="0xb462d987" whitecolor="0xb462d987" coloredcolor="0xcc0dab76" blackhighlight="0xb400ff00" whitehighlight="0xb400ff00" coloredhighlight="0xb400ff00" fill="10" visible="no" active="yes" locked="no"/>+<layer number="44" name="Drills" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd140" coloredhighlight="0xccafd140" fill="1" visible="no" active="yes" locked="no"/>+<layer number="45" name="Holes" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd140" coloredhighlight="0xccafd140" fill="1" visible="no" active="yes" locked="no"/>+<layer number="46" name="Milling" blackcolor="0xcc32c8c8" whitecolor="0xb432c8c8" coloredcolor="0xb432c8c8" blackhighlight="0xb400ffff" whitehighlight="0xb400ffff" coloredhighlight="0xb400ffff" fill="1" visible="no" active="yes" locked="no"/>+<layer number="47" name="Measures" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd140" coloredhighlight="0xccafd140" fill="1" visible="no" active="yes" locked="no"/>+<layer number="48" name="Document" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd141" coloredhighlight="0xccafd141" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="49" name="Reference" blackcolor="0xccc8c8c8" whitecolor="0xbb808080" coloredcolor="0xbb808080" blackhighlight="0xc8ffffff" whitehighlight="0xccafd142" coloredhighlight="0xccafd142" fill="1" visible="yes" active="yes" locked="no"/>+<layer number="91" name="Nets" blackcolor="0xdc009292" whitecolor="0xdc009292" coloredcolor="0xc8e3e3e3" blackhighlight="0xdc009292" whitehighlight="0xdc009292" coloredhighlight="0xc8e3e3e3" fill="1" visible="no" active="no" locked="no"/>+<layer number="92" name="Busses" blackcolor="0xdc009292" whitecolor="0xdc009292" coloredcolor="0xc8d62525" blackhighlight="0xdc009292" whitehighlight="0xdc009292" coloredhighlight="0xc8d62525" fill="1" visible="no" active="no" locked="no"/>+<layer number="93" name="Pins" blackcolor="0xdcbbbbbb" whitecolor="0xdcbbbbbb" coloredcolor="0xc839d437" blackhighlight="0xdcbbbbbb" whitehighlight="0xdcbbbbbb" coloredhighlight="0xc839d437" fill="1" visible="no" active="no" locked="no"/>+<layer number="94" name="Symbols" blackcolor="0xdcfac36e" whitecolor="0xdcf57c10" coloredcolor="0xc8e6e600" blackhighlight="0xdcfac36e" whitehighlight="0xdcf57c10" coloredhighlight="0xc8e6e600" fill="1" visible="no" active="no" locked="no"/>+<layer number="95" name="Names" blackcolor="0xf0b2b2b2" whitecolor="0xc8757575" coloredcolor="0xc82c7bce" blackhighlight="0xf0b2b2b2" whitehighlight="0xc8757575" coloredhighlight="0xc82c7bce" fill="1" visible="no" active="no" locked="no"/>+<layer number="96" name="Values" blackcolor="0xf0b2b2b2" whitecolor="0xc8757575" coloredcolor="0xc82c7bce" blackhighlight="0xf0b2b2b2" whitehighlight="0xc8757575" coloredhighlight="0xc82c7bce" fill="1" visible="no" active="no" locked="no"/>+<layer number="97" name="Info" blackcolor="0xf0b2b2b2" whitecolor="0xc8757575" coloredcolor="0xc89526de" blackhighlight="0xf0b2b2b2" whitehighlight="0xc8757575" coloredhighlight="0xc89526de" fill="1" visible="no" active="no" locked="no"/>+<layer number="98" name="Guide" blackcolor="0xf0b2b2b2" whitecolor="0xc8757575" coloredcolor="0xc89526de" blackhighlight="0xf0b2b2b2" whitehighlight="0xc8757575" coloredhighlight="0xc89526de" fill="1" visible="no" active="no" locked="no"/>+</layers>+<board>+<plain>+<wire x1="0" y1="0" x2="50" y2="0" width="0" layer="20"/>+<wire x1="50" y1="0" x2="50" y2="40" width="0" layer="20"/>+<wire x1="50" y1="40" x2="0" y2="40" width="0" layer="20"/>+<wire x1="0" y1="40" x2="0" y2="0" width="0" layer="20"/>+<text x="7" y="36" size="1.5" layer="21">FUSION / OBSTACLE ROUTING</text>+</plain>+<namedviews>+</namedviews>+<libraries>+<library name="ObstacleLab">+<packages>+<package name="SMD_TESTPOINT" use_placeholder="yes">+<smd name="1" x="0" y="0" dx="1.5" dy="1.5" layer="1" roundness="20"/>+</package>+</packages>+</library>+</libraries>+<attributes>+</attributes>+<variantdefs>+</variantdefs>+<classes>+<class number="0" name="default" width="0.25" drill="0.3">+</class>+</classes>+<designrules name="RoutingFixture" version="V1">+<rules>+<rulecategory type="Copper Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Keepout Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Solder-Mask Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Dimension Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Drill Distance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Restrict Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Minimum Drill Size" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Minimum Copper Width" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Acute Angle" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Air-Wire" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Small Gap" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Wire Stub" manualdrc="yes" livedrc="no"/>+ <rulecategory type="Matched Lengths" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Via Restrict Clearance" manualdrc="yes" livedrc="yes"/>+ <rulecategory type="Teardrop" manualdrc="no" livedrc="no"/>+ <rule type="Minimum Copper Width" enabled="yes" priority="0" onescope="class=0" value="0.25mm" preferredvalue="0.25mm" check_polywidth="no" name="minimum-copper-width-1"/>+ <rule type="Minimum Copper Width" builtin_ruleid="14" enabled="yes" priority="1" value="0.2mm" preferredvalue="0.2mm" check_polywidth="no" name="minimum-copper-width-2"/>+ <rule type="Teardrop" builtin_ruleid="22" enabled="yes" priority="0" onescope="is_via" lengthratio="0.5" widthratio="0.7" curved_sides="no" auto_generate="no" name="teardrop-1"/>+ <rule type="Teardrop" builtin_ruleid="23" enabled="yes" priority="1" onescope="is_pad" lengthratio="0.5" widthratio="0.7" curved_sides="no" auto_generate="no" name="teardrop-2"/>+ <rule type="Teardrop" builtin_ruleid="24" enabled="yes" priority="2" onescope="is_smd" lengthratio="0.5" widthratio="0.7" curved_sides="no" auto_generate="no" name="teardrop-3"/>+ <rule type="Teardrop" builtin_ruleid="25" enabled="yes" priority="3" onescope="is_wire_polygon" lengthratio="0.5" widthratio="0.9" curved_sides="no" auto_generate="no" name="teardrop-4"/>+ <rule type="Minimum Drill Size" enabled="yes" priority="0" onescope="class=0" value="0.3mm" preferredvalue="0.3mm" name="minimum-drill-size-1"/>+ <rule type="Minimum Drill Size" builtin_ruleid="15" enabled="yes" priority="1" value="0.3mm" preferredvalue="0.3mm" name="minimum-drill-size-2"/>+ <rule type="Acute Angle" builtin_ruleid="16" enabled="no" priority="0" name="acute-angle-1"/>+ <rule type="Wire Stub" builtin_ruleid="17" enabled="yes" priority="0" name="wire-stub-1"/>+ <rule type="Air-Wire" builtin_ruleid="19" enabled="yes" priority="0" name="air-wire-1"/>+ <rule type="Matched Lengths" builtin_ruleid="20" enabled="yes" priority="0" tolerance="10mm" gapfactor="2.5" name="matched-lengths-1"/>+ <rule type="Copper Clearance" builtin_ruleid="0" enabled="yes" priority="0" onescope="is_wire_polygon" otherscope="is_wire_polygon" value="0.2mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-1"/>+ <rule type="Copper Clearance" builtin_ruleid="1" enabled="yes" priority="1" onescope="is_wire_polygon" otherscope="is_pad_smd" value="0.2mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-2"/>+ <rule type="Copper Clearance" builtin_ruleid="2" enabled="yes" priority="2" onescope="is_wire_polygon" otherscope="is_via" value="0.2mm" preferredvalue="0.2mm" samesignal="no" name="copper-clearance-3"/>+ <rule type="Copper Clearance" builtin_ruleid="3" enabled="yes" priority="3" onescope="is_pad_smd" otherscope="is_pad_smd" value="6mil" preferredvalue="6mil" samesignal="no" name="copper-clearance-4"/>+ <rule type="Copper Clearance" builtin_ruleid="4" enabled="yes" priority="4" onescope="is_pad_smd" otherscope="is_via" value="6mil" preferredvalue="6mil" samesignal="no" name="copper-clearance-5"/>+ <rule type="Copper Clearance" builtin_ruleid="5" enabled="yes" priority="5" onescope="is_via" otherscope="is_via" value="6mil" preferredvalue="6mil" samesignal="no" name="copper-clearance-6"/>+ <rule type="Copper Clearance" builtin_ruleid="6" enabled="yes" priority="6" onescope="is_smd" otherscope="is_pad" value="6mil" preferredvalue="6mil" samesignal="yes" name="copper-clearance-7"/>+ <rule type="Copper Clearance" builtin_ruleid="7" enabled="yes" priority="7" onescope="is_smd" otherscope="is_via" value="6mil" preferredvalue="6mil" samesignal="yes" name="copper-clearance-8"/>+ <rule type="Copper Clearance" builtin_ruleid="8" enabled="yes" priority="8" onescope="is_smd" otherscope="is_smd" value="6mil" preferredvalue="6mil" samesignal="yes" name="copper-clearance-9"/>+ <rule type="Dimension Clearance" builtin_ruleid="9" enabled="yes" priority="0" value="0.5mm" preferredvalue="0.5mm" name="dimension-clearance-1"/>+ <rule type="Via Restrict Clearance" builtin_ruleid="21" enabled="yes" priority="0" value="0mil" preferredvalue="0mil" name="via-restrict-clearance-1"/>+ <rule type="Restrict Clearance" builtin_ruleid="10" enabled="yes" priority="0" value="0mil" preferredvalue="0mil" name="restrict-clearance-1"/>+ <rule type="Small Gap" builtin_ruleid="18" enabled="yes" priority="0" name="small-gap-1"/>+ <rule type="Solder-Mask Clearance" builtin_ruleid="11" enabled="no" priority="0" value="0mil" preferredvalue="0mil" check_name="yes" check_value="no" name="solder-mask-clearance-1"/>+ <rule type="Drill Distance" builtin_ruleid="12" enabled="yes" priority="0" value="6mil" preferredvalue="6mil" name="drill-distance-1"/>+ <rule type="Keepout Clearance" builtin_ruleid="13" enabled="yes" priority="0" value="0mil" preferredvalue="0mil" name="keepout-clearance-1"/>+ </rules>+<param name="mdWireWire" value="0.2mm"/>+<param name="mdWirePad" value="0.2mm"/>+<param name="mdWireVia" value="0.2mm"/>+<param name="mdPadPad" value="6mil"/>+<param name="mdPadVia" value="6mil"/>+<param name="mdViaVia" value="6mil"/>+<param name="mdSmdPad" value="6mil"/>+<param name="mdSmdVia" value="6mil"/>+<param name="mdSmdSmd" value="6mil"/>+<param name="mdCopperDimension" value="0.5mm"/>+<param name="mdDrill" value="6mil"/>+<param name="msWidth" value="0.2mm"/>+<param name="msDrill" value="0.3mm"/>+<param name="dpMaxLengthDifference" value="10mm"/>+<param name="dpGapFactor" value="2.5"/>+<description language="en"><b>Fusion Electronics Design Rules</b>+<p>+The default Design Rules have been set to cover+a wide range of applications. Your particular design+may have different requirements, so please make the+necessary adjustments and save your customized+design rules under a new name.+</description>+<param name="layerSetup" value="(1*16)"/>+<param name="mtCopper" value="0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm"/>+<param name="mtIsolate" value="1.5mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm"/>+<param name="mdViaViaSameLayer" value="6mil"/>+<param name="mnLayersViaInSmd" value="2"/>+<param name="mdSmdStop" value="0mil"/>+<param name="msMicroVia" value="9.99mm"/>+<param name="msBlindViaRatio" value="0.5"/>+<param name="rvPadTop" value="0.25"/>+<param name="rvPadInner" value="0.25"/>+<param name="rvPadBottom" value="0.25"/>+<param name="rvViaOuter" value="0.25"/>+<param name="rvViaInner" value="0.25"/>+<param name="rvMicroViaOuter" value="0.25"/>+<param name="rvMicroViaInner" value="0.25"/>+<param name="rlMinPadTop" value="10mil"/>+<param name="rlMaxPadTop" value="20mil"/>+<param name="rlMinPadInner" value="10mil"/>+<param name="rlMaxPadInner" value="20mil"/>+<param name="rlMinPadBottom" value="10mil"/>+<param name="rlMaxPadBottom" value="20mil"/>+<param name="rlMinViaOuter" value="8mil"/>+<param name="rlMaxViaOuter" value="20mil"/>+<param name="rlMinViaInner" value="8mil"/>+<param name="rlMaxViaInner" value="20mil"/>+<param name="rlMinMicroViaOuter" value="4mil"/>+<param name="rlMaxMicroViaOuter" value="20mil"/>+<param name="rlMinMicroViaInner" value="4mil"/>+<param name="rlMaxMicroViaInner" value="20mil"/>+<param name="psTop" value="-1"/>+<param name="psBottom" value="-1"/>+<param name="psFirst" value="-1"/>+<param name="psElongationLong" value="100"/>+<param name="psElongationOffset" value="100"/>+<param name="mvStopFrame" value="1"/>+<param name="mvCreamFrame" value="0"/>+<param name="mlMinStopFrame" value="4mil"/>+<param name="mlMaxStopFrame" value="4mil"/>+<param name="mlMinCreamFrame" value="0mil"/>+<param name="mlMaxCreamFrame" value="0mil"/>+<param name="mlViaStopLimit" value="9999mil"/>+<param name="srRoundness" value="0"/>+<param name="srMinRoundness" value="0mil"/>+<param name="srMaxRoundness" value="0mil"/>+<param name="slThermalIsolate" value="10mil"/>+<param name="slThermalsForVias" value="0"/>+<param name="checkAngle" value="0"/>+<param name="checkRestrict" value="1"/>+<param name="checkStop" value="0"/>+<param name="checkValues" value="0"/>+<param name="checkNames" value="1"/>+<param name="checkWireStubs" value="1"/>+<param name="checkPolygonWidth" value="0"/>+<param name="useDiameter" value="13"/>+<param name="removeAnnularRing" value="0"/>+<param name="flattenRefDes" value="0"/>+<param name="maxErrors" value="999999"/>+<layerstackup name="Default Layer Stack" type="Standard Stackup" display_unit="mic" roughness_model="0">+ <layerdef type="Signal" id="{435c7b45-797f-495b-a9ac-f715ba9ba68f}" layer="1" name="Top" locally_modified_material="yes">+ <material name="User Defined" thickness="0.035mm" weight="1oz" process="Electro Deposited" source="User"/>+</layerdef>+ <layerdef type="Core" id="{d0cf59fe-462b-410b-86b4-d721a58dc03c}" layer="1" name="Dielectric-1" locally_modified_material="yes">+ <material name="User Defined" construction="" thickness="1.5mm" resin="50%" dielectric_constant_1g="4.5" dissipation_factor_1g="0.02" glass_transition_temperature="125degC" source="User"/>+</layerdef>+ <layerdef type="Signal" id="{33d420e8-9e1e-4898-8539-f51b8f157dfa}" layer="16" name="Bottom" locally_modified_material="yes">+ <material name="User Defined" thickness="0.035mm" weight="1oz" process="Electro Deposited" source="User"/>+</layerdef>+ <viadef name="Thru 1:16" startlayer="1" stoplayer="16" complement="no"/>+ </layerstackup>+ </designrules>+<autorouter>+<pass name="Default">+<param name="RoutingGrid" value="50mil"/>+<param name="AutoGrid" value="1"/>+<param name="Efforts" value="0"/>+<param name="TopRouterVariant" value="1"/>+<param name="tpViaShape" value="round"/>+<param name="PrefDir.1" value="a"/>+<param name="PrefDir.2" value="0"/>+<param name="PrefDir.3" value="0"/>+<param name="PrefDir.4" value="0"/>+<param name="PrefDir.5" value="0"/>+<param name="PrefDir.6" value="0"/>+<param name="PrefDir.7" value="0"/>+<param name="PrefDir.8" value="0"/>+<param name="PrefDir.9" value="0"/>+<param name="PrefDir.10" value="0"/>+<param name="PrefDir.11" value="0"/>+<param name="PrefDir.12" value="0"/>+<param name="PrefDir.13" value="0"/>+<param name="PrefDir.14" value="0"/>+<param name="PrefDir.15" value="0"/>+<param name="PrefDir.16" value="a"/>+<param name="cfVia" value="8"/>+<param name="cfNonPref" value="5"/>+<param name="cfChangeDir" value="2"/>+<param name="cfOrthStep" value="2"/>+<param name="cfDiagStep" value="3"/>+<param name="cfExtdStep" value="0"/>+<param name="cfBonusStep" value="1"/>+<param name="cfMalusStep" value="1"/>+<param name="cfPadImpact" value="4"/>+<param name="cfSmdImpact" value="4"/>+<param name="cfBusImpact" value="0"/>+<param name="cfHugging" value="3"/>+<param name="cfAvoid" value="4"/>+<param name="cfPolygon" value="10"/>+<param name="cfBase.1" value="0"/>+<param name="cfBase.2" value="1"/>+<param name="cfBase.3" value="1"/>+<param name="cfBase.4" value="1"/>+<param name="cfBase.5" value="1"/>+<param name="cfBase.6" value="1"/>+<param name="cfBase.7" value="1"/>+<param name="cfBase.8" value="1"/>+<param name="cfBase.9" value="1"/>+<param name="cfBase.10" value="1"/>+<param name="cfBase.11" value="1"/>+<param name="cfBase.12" value="1"/>+<param name="cfBase.13" value="1"/>+<param name="cfBase.14" value="1"/>+<param name="cfBase.15" value="1"/>+<param name="cfBase.16" value="0"/>+<param name="mnVias" value="20"/>+<param name="mnSegments" value="9999"/>+<param name="mnExtdSteps" value="9999"/>+<param name="mnRipupLevel" value="10"/>+<param name="mnRipupSteps" value="100"/>+<param name="mnRipupTotal" value="100"/>+</pass>+<pass name="Follow-me" refer="Default" active="yes">+</pass>+<pass name="Busses" refer="Default" active="yes">+<param name="cfNonPref" value="4"/>+<param name="cfBusImpact" value="4"/>+<param name="cfHugging" value="0"/>+<param name="mnVias" value="0"/>+</pass>+<pass name="Route" refer="Default" active="yes">+</pass>+<pass name="Optimize1" refer="Default" active="yes">+<param name="cfVia" value="99"/>+<param name="cfExtdStep" value="10"/>+<param name="cfHugging" value="1"/>+<param name="mnExtdSteps" value="1"/>+<param name="mnRipupLevel" value="0"/>+</pass>+<pass name="Optimize2" refer="Optimize1" active="yes">+<param name="cfNonPref" value="0"/>+<param name="cfChangeDir" value="6"/>+<param name="cfExtdStep" value="0"/>+<param name="cfBonusStep" value="2"/>+<param name="cfMalusStep" value="2"/>+<param name="cfPadImpact" value="2"/>+<param name="cfSmdImpact" value="2"/>+<param name="cfHugging" value="0"/>+</pass>+<pass name="Optimize3" refer="Optimize2" active="yes">+<param name="cfChangeDir" value="8"/>+<param name="cfPadImpact" value="0"/>+<param name="cfSmdImpact" value="0"/>+</pass>+<pass name="Optimize4" refer="Optimize3" active="yes">+<param name="cfChangeDir" value="25"/>+</pass>+</autorouter>+<elements>+<element name="L1" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="5" y="8" smashed="yes">+</element>+<element name="R1" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="45" y="8" smashed="yes">+</element>+<element name="L2" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="5" y="20" smashed="yes">+</element>+<element name="R2" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="45" y="20" smashed="yes">+</element>+<element name="L3" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="5" y="32" smashed="yes">+</element>+<element name="R3" library="ObstacleLab" package="SMD_TESTPOINT" value="LAB" x="45" y="32" smashed="yes">+</element>+</elements>+<signals>+<signal name="ROUTE_1">+<contactref element="L1" pad="1"/>+<contactref element="R1" pad="1"/>+<wire x1="5" y1="8" x2="21" y2="8" width="0.25" layer="1"/>+<wire x1="21" y1="8" x2="21" y2="1" width="0.25" layer="1"/>+<wire x1="21" y1="1" x2="45" y2="1" width="0.25" layer="1"/>+<wire x1="45" y1="1" x2="45" y2="8" width="0.25" layer="1"/>+</signal>+<signal name="ROUTE_2">+<contactref element="L2" pad="1"/>+<contactref element="R2" pad="1"/>+<wire x1="5" y1="20" x2="20.5" y2="20" width="0.25" layer="1"/>+<via x="20.5" y="20" extent="1-16" drill="0.3" diameter="0.6" solderMask="auto">+</via>+<wire x1="20.5" y1="20" x2="30.5" y2="20" width="0.25" layer="16"/>+<via x="30.5" y="20" extent="1-16" drill="0.3" diameter="0.6" solderMask="auto">+</via>+<wire x1="30.5" y1="20" x2="45" y2="20" width="0.25" layer="1"/>+</signal>+<signal name="ROUTE_3">+<contactref element="L3" pad="1"/>+<contactref element="R3" pad="1"/>+<wire x1="5" y1="32" x2="45" y2="32" width="0.25" layer="1"/>+</signal>+<signal name="TOP_BARRIER">+<wire x1="22" y1="2" x2="22" y2="28" width="1" layer="1"/>+</signal>+<signal name="BOTTOM_BARRIER">+<wire x1="32" y1="12" x2="32" y2="37" width="1" layer="16"/>+</signal>+</signals>+<mfgpreviewcolors>+<mfgpreviewcolor name="soldermaskcolor" color="0xC8008000"/>+<mfgpreviewcolor name="silkscreencolor" color="0xFFFEFEFE"/>+<mfgpreviewcolor name="backgroundcolor" color="0xFF282828"/>+<mfgpreviewcolor name="coppercolor" color="0xFFFFBF00"/>+<mfgpreviewcolor name="substratecolor" color="0xFF786E46"/>+</mfgpreviewcolors>+</board>+</drawing>+<compatibility>+<note version="9.7" severity="warning">+Since Fusion, design files support named views saved in design. +Named views found in the design will not be understood with this version. +</note>+<note version="9.7" minversion="9.7.0" severity="warning">+Since Version 9.7.0 new layer stackup definition has been added,+which will not be loaded with this version.+</note>+<note version="9.7" minversion="9.7.0" severity="warning">+Since Version 9.7.0 new active CAMJOB file name has been added,+which will not be loaded with this version.+</note>+<note version="9.7" minversion="9.7.0" severity="warning">+Since Version 9.7.0 board construction lines has been added,+which will not be loaded with this version.+</note>+<note version="9.7" minversion="9.7.0" severity="warning">+Since Version 9.7.0 new design rule definitions have been added,+which will not be loaded with this version.+</note>+</compatibility>+</eagle>
demo/routing/obstacles/take-04/fusion-obstacle-live-routed.fbrdadded⋯ 1 unchanged line ⋯
demo/routing/obstacles/take-04/panel-events.jsonladded+23@@ -0,0 +1,23 @@+{"time": 1788647718.47554, "sequence": 14, "ack": 14, "state": {"title": "Astra: Running native Autodesk DRC", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 0, "tone": "working", "routing": {"connection": "ROUTE_1: L1.1 \u2192 R1.1\n(5, 8) \u2192 (45, 8) mm", "plan": "54 mm / 0 vias\n1795 nodes / 24.19 ms\nClearance 0.2 mm", "checks": "Measuring errors, warnings and airwires.", "events": "fusion_route_net: segment\nfusion_routing_drc"}, "sequence": 14}}+{"time": 1788647718.7369845, "sequence": 15, "ack": 14, "state": {"title": "Astra: Connection 1 verified", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 33, "tone": "working", "routing": {"connection": "ROUTE_1: L1.1 \u2192 R1.1\n(5, 8) \u2192 (45, 8) mm", "plan": "54 mm / 0 vias\n1795 nodes / 24.19 ms\nClearance 0.2 mm", "checks": "DRC: 0 errors / 0 warnings\n2 airwires / 2 nets remaining", "events": "fusion_routing_drc\nNative DRC completed"}, "sequence": 15}}+{"time": 1788647721.106747, "sequence": 16, "ack": 15, "state": {"title": "Astra: Calculating connection 2 of 3", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 33, "tone": "working", "routing": {"connection": "ROUTE_2: L2.1 \u2192 R2.1\n(5, 20) \u2192 (45, 20) mm", "plan": "0.50 mm grid / 0.25 mm width\nTop + bottom: vias permitted", "checks": "Searching live copper obstacles; board unchanged.", "events": "Native DRC completed\nfusion_plan_route: read-only A* search"}, "sequence": 16}}+{"time": 1788647721.6333609, "sequence": 17, "ack": 16, "state": {"title": "Astra: Route calculated and preflight passed", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 33, "tone": "working", "routing": {"connection": "ROUTE_2: L2.1 \u2192 R2.1\n(5, 20) \u2192 (45, 20) mm", "plan": "40 mm / 2 vias\n882 nodes / 15.684 ms\nClearance 0.2 mm", "checks": "Revision unchanged by planning.\nExplicit path cleared against live copper.", "events": "Native DRC completed\nfusion_plan_route: read-only A* search"}, "sequence": 17}}+{"time": 1788647724.93677, "sequence": 18, "ack": 17, "state": {"title": "Astra: Creating segment 1/5", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 33, "tone": "working", "routing": {"connection": "ROUTE_2: L2.1 \u2192 R2.1\n(5, 20) \u2192 (45, 20) mm", "plan": "40 mm / 2 vias\n882 nodes / 15.684 ms\nClearance 0.2 mm", "checks": "Layer 1: [5.0, 20.0] \u2192 [20.5, 20.0]\nWaiting for native copper read-back.", "events": "fusion_plan_route: read-only A* search\nfusion_route_net: segment"}, "sequence": 18}}+{"time": 1788647725.9307346, "sequence": 19, "ack": 18, "state": {"title": "Astra: Verified segment 1/5", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 33, "tone": "working", "routing": {"connection": "ROUTE_2: L2.1 \u2192 R2.1\n(5, 20) \u2192 (45, 20) mm", "plan": "40 mm / 2 vias\n882 nodes / 15.684 ms\nClearance 0.2 mm", "checks": "Native copper matches requested edit.\nRevision advanced; existing copper preserved.", "events": "fusion_plan_route: read-only A* search\nfusion_route_net: segment"}, "sequence": 19}}+{"time": 1788647727.087905, "sequence": 20, "ack": 19, "state": {"title": "Astra: Creating via 2/5", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 33, "tone": "working", "routing": {"connection": "ROUTE_2: L2.1 \u2192 R2.1\n(5, 20) \u2192 (45, 20) mm", "plan": "40 mm / 2 vias\n882 nodes / 15.684 ms\nClearance 0.2 mm", "checks": "Via at [20.5, 20.0]: top \u2194 bottom\nWaiting for native copper read-back.", "events": "fusion_route_net: segment\nfusion_route_net: via"}, "sequence": 20}}+{"time": 1788647728.3001559, "sequence": 21, "ack": 20, "state": {"title": "Astra: Verified via 2/5", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 33, "tone": "working", "routing": {"connection": "ROUTE_2: L2.1 \u2192 R2.1\n(5, 20) \u2192 (45, 20) mm", "plan": "40 mm / 2 vias\n882 nodes / 15.684 ms\nClearance 0.2 mm", "checks": "Native copper matches requested edit.\nRevision advanced; existing copper preserved.", "events": "fusion_route_net: segment\nfusion_route_net: via"}, "sequence": 21}}+{"time": 1788647729.455454, "sequence": 22, "ack": 21, "state": {"title": "Astra: Creating segment 3/5", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 33, "tone": "working", "routing": {"connection": "ROUTE_2: L2.1 \u2192 R2.1\n(5, 20) \u2192 (45, 20) mm", "plan": "40 mm / 2 vias\n882 nodes / 15.684 ms\nClearance 0.2 mm", "checks": "Layer 16: [20.5, 20.0] \u2192 [30.5, 20.0]\nWaiting for native copper read-back.", "events": "fusion_route_net: via\nfusion_route_net: segment"}, "sequence": 22}}+{"time": 1788647730.506698, "sequence": 23, "ack": 22, "state": {"title": "Astra: Verified segment 3/5", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 33, "tone": "working", "routing": {"connection": "ROUTE_2: L2.1 \u2192 R2.1\n(5, 20) \u2192 (45, 20) mm", "plan": "40 mm / 2 vias\n882 nodes / 15.684 ms\nClearance 0.2 mm", "checks": "Native copper matches requested edit.\nRevision advanced; existing copper preserved.", "events": "fusion_route_net: via\nfusion_route_net: segment"}, "sequence": 23}}+{"time": 1788647731.6647859, "sequence": 24, "ack": 23, "state": {"title": "Astra: Creating via 4/5", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 33, "tone": "working", "routing": {"connection": "ROUTE_2: L2.1 \u2192 R2.1\n(5, 20) \u2192 (45, 20) mm", "plan": "40 mm / 2 vias\n882 nodes / 15.684 ms\nClearance 0.2 mm", "checks": "Via at [30.5, 20.0]: top \u2194 bottom\nWaiting for native copper read-back.", "events": "fusion_route_net: segment\nfusion_route_net: via"}, "sequence": 24}}+{"time": 1788647732.770199, "sequence": 25, "ack": 24, "state": {"title": "Astra: Verified via 4/5", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 33, "tone": "working", "routing": {"connection": "ROUTE_2: L2.1 \u2192 R2.1\n(5, 20) \u2192 (45, 20) mm", "plan": "40 mm / 2 vias\n882 nodes / 15.684 ms\nClearance 0.2 mm", "checks": "Native copper matches requested edit.\nRevision advanced; existing copper preserved.", "events": "fusion_route_net: segment\nfusion_route_net: via"}, "sequence": 25}}+{"time": 1788647733.922635, "sequence": 26, "ack": 25, "state": {"title": "Astra: Creating segment 5/5", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 33, "tone": "working", "routing": {"connection": "ROUTE_2: L2.1 \u2192 R2.1\n(5, 20) \u2192 (45, 20) mm", "plan": "40 mm / 2 vias\n882 nodes / 15.684 ms\nClearance 0.2 mm", "checks": "Layer 1: [30.5, 20.0] \u2192 [45.0, 20.0]\nWaiting for native copper read-back.", "events": "fusion_route_net: via\nfusion_route_net: segment"}, "sequence": 26}}+{"time": 1788647734.9749937, "sequence": 27, "ack": 26, "state": {"title": "Astra: Verified segment 5/5", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 33, "tone": "working", "routing": {"connection": "ROUTE_2: L2.1 \u2192 R2.1\n(5, 20) \u2192 (45, 20) mm", "plan": "40 mm / 2 vias\n882 nodes / 15.684 ms\nClearance 0.2 mm", "checks": "Native copper matches requested edit.\nRevision advanced; existing copper preserved.", "events": "fusion_route_net: via\nfusion_route_net: segment"}, "sequence": 27}}+{"time": 1788647736.133687, "sequence": 28, "ack": 27, "state": {"title": "Astra: Running native Autodesk DRC", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 33, "tone": "working", "routing": {"connection": "ROUTE_2: L2.1 \u2192 R2.1\n(5, 20) \u2192 (45, 20) mm", "plan": "40 mm / 2 vias\n882 nodes / 15.684 ms\nClearance 0.2 mm", "checks": "Measuring errors, warnings and airwires.", "events": "fusion_route_net: segment\nfusion_routing_drc"}, "sequence": 28}}+{"time": 1788647736.975922, "sequence": 29, "ack": 28, "state": {"title": "Astra: Connection 2 verified", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 66, "tone": "working", "routing": {"connection": "ROUTE_2: L2.1 \u2192 R2.1\n(5, 20) \u2192 (45, 20) mm", "plan": "40 mm / 2 vias\n882 nodes / 15.684 ms\nClearance 0.2 mm", "checks": "DRC: 0 errors / 0 warnings\n1 airwires / 1 nets remaining", "events": "fusion_routing_drc\nNative DRC completed"}, "sequence": 29}}+{"time": 1788647739.349041, "sequence": 30, "ack": 29, "state": {"title": "Astra: Calculating connection 3 of 3", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 66, "tone": "working", "routing": {"connection": "ROUTE_3: L3.1 \u2192 R3.1\n(5, 32) \u2192 (45, 32) mm", "plan": "0.50 mm grid / 0.25 mm width\nTop + bottom: vias permitted", "checks": "Searching live copper obstacles; board unchanged.", "events": "Native DRC completed\nfusion_plan_route: read-only A* search"}, "sequence": 30}}+{"time": 1788647739.8774328, "sequence": 31, "ack": 30, "state": {"title": "Astra: Route calculated and preflight passed", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 66, "tone": "working", "routing": {"connection": "ROUTE_3: L3.1 \u2192 R3.1\n(5, 32) \u2192 (45, 32) mm", "plan": "40 mm / 0 vias\n81 nodes / 3.204 ms\nClearance 0.2 mm", "checks": "Revision unchanged by planning.\nExplicit path cleared against live copper.", "events": "Native DRC completed\nfusion_plan_route: read-only A* search"}, "sequence": 31}}+{"time": 1788647743.1823676, "sequence": 32, "ack": 31, "state": {"title": "Astra: Creating segment 1/1", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 66, "tone": "working", "routing": {"connection": "ROUTE_3: L3.1 \u2192 R3.1\n(5, 32) \u2192 (45, 32) mm", "plan": "40 mm / 0 vias\n81 nodes / 3.204 ms\nClearance 0.2 mm", "checks": "Layer 1: [5.0, 32.0] \u2192 [45.0, 32.0]\nWaiting for native copper read-back.", "events": "fusion_plan_route: read-only A* search\nfusion_route_net: segment"}, "sequence": 32}}+{"time": 1788647744.3477757, "sequence": 33, "ack": 32, "state": {"title": "Astra: Verified segment 1/1", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 66, "tone": "working", "routing": {"connection": "ROUTE_3: L3.1 \u2192 R3.1\n(5, 32) \u2192 (45, 32) mm", "plan": "40 mm / 0 vias\n81 nodes / 3.204 ms\nClearance 0.2 mm", "checks": "Native copper matches requested edit.\nRevision advanced; existing copper preserved.", "events": "fusion_plan_route: read-only A* search\nfusion_route_net: segment"}, "sequence": 33}}+{"time": 1788647745.5086503, "sequence": 34, "ack": 33, "state": {"title": "Astra: Running native Autodesk DRC", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 66, "tone": "working", "routing": {"connection": "ROUTE_3: L3.1 \u2192 R3.1\n(5, 32) \u2192 (45, 32) mm", "plan": "40 mm / 0 vias\n81 nodes / 3.204 ms\nClearance 0.2 mm", "checks": "Measuring errors, warnings and airwires.", "events": "fusion_route_net: segment\nfusion_routing_drc"}, "sequence": 34}}+{"time": 1788647746.6294773, "sequence": 35, "ack": 34, "state": {"title": "Astra: Connection 3 verified", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 99, "tone": "working", "routing": {"connection": "ROUTE_3: L3.1 \u2192 R3.1\n(5, 32) \u2192 (45, 32) mm", "plan": "40 mm / 0 vias\n81 nodes / 3.204 ms\nClearance 0.2 mm", "checks": "DRC: 0 errors / 0 warnings\n0 airwires / 0 nets remaining", "events": "fusion_routing_drc\nNative DRC completed"}, "sequence": 35}}+{"time": 1788647749.0173635, "sequence": 36, "ack": 35, "state": {"title": "Astra: All 3 connections complete", "detail": "Codex Astra in Adom Hydrogen / bounded two-layer A*", "percent": 100, "tone": "done", "routing": {"connection": "6 pads connected / 8 new segments / 2 vias", "plan": "40 mm / 0 vias\n81 nodes / 3.204 ms\nClearance 0.2 mm", "checks": "Native DRC: 0 errors / 0 warnings / 0 airwires\nBoth original copper barriers unchanged.", "events": "Native DRC completed\nFinal board geometry verified"}, "sequence": 36}}
demo/routing/obstacles/take-04/panel-record-start.jsonadded+31@@ -0,0 +1,31 @@+{+ "_hint": "Native window recording (WGC): background-capturable, no picker. Stop with desktop_record_stop {recordingId}; pull the MP4 with pull_file.",+ "audio": false,+ "audioNote": null,+ "audioRate": 0,+ "codec": "h264",+ "durationMs": 293,+ "encoder": "NVIDIA H.264 Encoder MFT",+ "error": "",+ "fps": 30,+ "hardwareEncoder": true,+ "height": 1150,+ "hwnd": 11280636,+ "kind": "window",+ "maxDurationMs": 180000,+ "path": "C:/Users/john/AppData/Local/Temp/adom-bridge-recordings/window-11280636-20260905-223501.mp4",+ "recordingId": "rec-44cb63c67ae04a228aa6b45799559294",+ "status": "ok",+ "success": true,+ "timeoutSeconds": 15,+ "title": "ADOM",+ "width": 590,+ "data": {+ "height": 1150,+ "kind": "window",+ "path": "C:\\Users\\john\\AppData\\Local\\Temp\\adom-bridge-recordings\\window-11280636-20260905-223501.mp4",+ "recordingId": "rec-44cb63c67ae04a228aa6b45799559294",+ "width": 590+ },+ "message": "Recording window \"ADOM\" -> C:\\Users\\john\\AppData\\Local\\Temp\\adom-bridge-recordings\\window-11280636-20260905-223501.mp4 (590x1150 @ 30fps h264)"+}
demo/routing/obstacles/take-04/panel-record-stop.jsonadded+28@@ -0,0 +1,28 @@+{+ "_hint": "The MP4 is finalized (moov written). pull_file {path} brings it to the caller; the janitor prunes the recordings dir by age/size, so pull it promptly.",+ "audio": false,+ "audioFrames": 0,+ "autoStopped": false,+ "bytes": 11912935,+ "durationMs": 76,+ "elapsedMs": 52687,+ "error": "",+ "fileExists": true,+ "frames": 1435,+ "height": 1150,+ "kind": "window",+ "path": "C:/Users/john/AppData/Local/Temp/adom-bridge-recordings/window-11280636-20260905-223501.mp4",+ "recordingId": "rec-44cb63c67ae04a228aa6b45799559294",+ "status": "ok",+ "success": true,+ "timeoutSeconds": 30,+ "width": 590,+ "data": {+ "bytes": 11912935,+ "elapsedMs": 52687,+ "frames": 1435,+ "path": "C:\\Users\\john\\AppData\\Local\\Temp\\adom-bridge-recordings\\window-11280636-20260905-223501.mp4",+ "recordingId": "rec-44cb63c67ae04a228aa6b45799559294"+ },+ "message": "Stopped recording rec-44cb63c67ae04a228aa6b45799559294: 1435 frames, 52687 ms, 11912935 bytes -> C:\\Users\\john\\AppData\\Local\\Temp\\adom-bridge-recordings\\window-11280636-20260905-223501.mp4"+}
demo/routing/obstacles/take-04/plan-1.jsonadded+122@@ -0,0 +1,122 @@+{+ "_timeoutHint": "ab waits up to 60s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `fusion_get_app_state` until it reports done.",+ "boardId": "388efa26-6c67-4cc1-860e-4d4579cd896f",+ "bridgeVersion": "1.10.0-dev.routing.4",+ "documentName": "fusion-obstacle-lab-v3",+ "durationMs": 204,+ "error": "",+ "mutated": false,+ "plan": {+ "clearance": 0.2,+ "items": [+ {+ "end": [+ 21.0,+ 8.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 5.0,+ 8.0+ ],+ "width": 0.25+ },+ {+ "end": [+ 21.0,+ 1.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 21.0,+ 8.0+ ],+ "width": 0.25+ },+ {+ "end": [+ 45.0,+ 1.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 21.0,+ 1.0+ ],+ "width": 0.25+ },+ {+ "end": [+ 45.0,+ 8.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_1",+ "start": [+ 45.0,+ 1.0+ ],+ "width": 0.25+ }+ ],+ "net": "ROUTE_1",+ "planner": {+ "algorithm": "bounded orthogonal two-layer A*",+ "elapsedMs": 24.19,+ "expandedNodes": 1795,+ "externalRouter": false,+ "grid": 0.5,+ "lengthMm": 54.0,+ "viaCount": 0+ },+ "preflight": "Conservative geometry only; run native Autodesk DRC after edits",+ "route": {+ "clearance": 0.2,+ "layer": 1,+ "net": "ROUTE_1",+ "points": [+ {+ "layer": 1,+ "x": 5.0,+ "y": 8.0+ },+ {+ "layer": 1,+ "x": 21.0,+ "y": 8.0+ },+ {+ "layer": 1,+ "x": 21.0,+ "y": 1.0+ },+ {+ "layer": 1,+ "x": 45.0,+ "y": 1.0+ },+ {+ "layer": 1,+ "x": 45.0,+ "y": 8.0+ }+ ],+ "viaDiameter": 0.6,+ "viaDrill": 0.3,+ "width": 0.25+ }+ },+ "revision": "55e607daca93bdd86250dfaa24e95179cad8a7ced289ba309cc56f634d94ba36",+ "shell": "rust",+ "status": "ok",+ "statusVerb": "fusion_get_app_state",+ "success": true,+ "timeoutSeconds": 60+}
demo/routing/obstacles/take-04/plan-2.jsonadded+125@@ -0,0 +1,125 @@+{+ "_timeoutHint": "ab waits up to 60s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `fusion_get_app_state` until it reports done.",+ "boardId": "388efa26-6c67-4cc1-860e-4d4579cd896f",+ "bridgeVersion": "1.10.0-dev.routing.4",+ "documentName": "fusion-obstacle-lab-v3",+ "durationMs": 202,+ "error": "",+ "mutated": false,+ "plan": {+ "clearance": 0.2,+ "items": [+ {+ "end": [+ 20.5,+ 20.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_2",+ "start": [+ 5.0,+ 20.0+ ],+ "width": 0.25+ },+ {+ "at": [+ 20.5,+ 20.0+ ],+ "diameter": 0.6,+ "drill": 0.3,+ "extent": "1-16",+ "kind": "via",+ "net": "ROUTE_2"+ },+ {+ "end": [+ 30.5,+ 20.0+ ],+ "kind": "segment",+ "layer": 16,+ "net": "ROUTE_2",+ "start": [+ 20.5,+ 20.0+ ],+ "width": 0.25+ },+ {+ "at": [+ 30.5,+ 20.0+ ],+ "diameter": 0.6,+ "drill": 0.3,+ "extent": "1-16",+ "kind": "via",+ "net": "ROUTE_2"+ },+ {+ "end": [+ 45.0,+ 20.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_2",+ "start": [+ 30.5,+ 20.0+ ],+ "width": 0.25+ }+ ],+ "net": "ROUTE_2",+ "planner": {+ "algorithm": "bounded orthogonal two-layer A*",+ "elapsedMs": 15.684,+ "expandedNodes": 882,+ "externalRouter": false,+ "grid": 0.5,+ "lengthMm": 40.0,+ "viaCount": 2+ },+ "preflight": "Conservative geometry only; run native Autodesk DRC after edits",+ "route": {+ "clearance": 0.2,+ "layer": 1,+ "net": "ROUTE_2",+ "points": [+ {+ "layer": 1,+ "x": 5.0,+ "y": 20.0+ },+ {+ "layer": 16,+ "x": 20.5,+ "y": 20.0+ },+ {+ "layer": 1,+ "x": 30.5,+ "y": 20.0+ },+ {+ "layer": 1,+ "x": 45.0,+ "y": 20.0+ }+ ],+ "viaDiameter": 0.6,+ "viaDrill": 0.3,+ "width": 0.25+ }+ },+ "revision": "15a0e8a1a309d06e202274eece33ee3b192efe6f27732343dc682579cc98dd6c",+ "shell": "rust",+ "status": "ok",+ "statusVerb": "fusion_get_app_state",+ "success": true,+ "timeoutSeconds": 60+}
demo/routing/obstacles/take-04/plan-3.jsonadded+65@@ -0,0 +1,65 @@+{+ "_timeoutHint": "ab waits up to 60s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `fusion_get_app_state` until it reports done.",+ "boardId": "388efa26-6c67-4cc1-860e-4d4579cd896f",+ "bridgeVersion": "1.10.0-dev.routing.4",+ "documentName": "fusion-obstacle-lab-v3",+ "durationMs": 174,+ "error": "",+ "mutated": false,+ "plan": {+ "clearance": 0.2,+ "items": [+ {+ "end": [+ 45.0,+ 32.0+ ],+ "kind": "segment",+ "layer": 1,+ "net": "ROUTE_3",+ "start": [+ 5.0,+ 32.0+ ],+ "width": 0.25+ }+ ],+ "net": "ROUTE_3",+ "planner": {+ "algorithm": "bounded orthogonal two-layer A*",+ "elapsedMs": 3.204,+ "expandedNodes": 81,+ "externalRouter": false,+ "grid": 0.5,+ "lengthMm": 40.0,+ "viaCount": 0+ },+ "preflight": "Conservative geometry only; run native Autodesk DRC after edits",+ "route": {+ "clearance": 0.2,+ "layer": 1,+ "net": "ROUTE_3",+ "points": [+ {+ "layer": 1,+ "x": 5.0,+ "y": 32.0+ },+ {+ "layer": 1,+ "x": 45.0,+ "y": 32.0+ }+ ],+ "viaDiameter": 0.6,+ "viaDrill": 0.3,+ "width": 0.25+ }+ },+ "revision": "b90a0d2f4b58d266aa4c13511d7cc6f1a77a469f645fec95efba93d8bb7e59be",+ "shell": "rust",+ "status": "ok",+ "statusVerb": "fusion_get_app_state",+ "success": true,+ "timeoutSeconds": 60+}
demo/routing/obstacles/take-04/record-start.jsonadded+31@@ -0,0 +1,31 @@+{+ "_hint": "Native window recording (WGC): background-capturable, no picker. Stop with desktop_record_stop {recordingId}; pull the MP4 with pull_file.",+ "audio": false,+ "audioNote": null,+ "audioRate": 0,+ "codec": "h264",+ "durationMs": 518,+ "encoder": "NVIDIA H.264 Encoder MFT",+ "error": "",+ "fps": 30,+ "hardwareEncoder": true,+ "height": 1540,+ "hwnd": 8916576,+ "kind": "window",+ "maxDurationMs": 180000,+ "path": "C:/Users/john/AppData/Local/Temp/adom-bridge-recordings/window-8916576-20260905-223500.mp4",+ "recordingId": "rec-034529ebf72241179a167c8c56d41114",+ "status": "ok",+ "success": true,+ "timeoutSeconds": 15,+ "title": "fusion-obstacle-lab-v3* (jlauerhub) - Autodesk Fusion (Trial ends in 16 days) ",+ "width": 2564,+ "data": {+ "height": 1540,+ "kind": "window",+ "path": "C:\\Users\\john\\AppData\\Local\\Temp\\adom-bridge-recordings\\window-8916576-20260905-223500.mp4",+ "recordingId": "rec-034529ebf72241179a167c8c56d41114",+ "width": 2564+ },+ "message": "Recording window \"fusion-obstacle-lab-v3* (jlauerhub) - Autodesk Fusion (Trial ends in 16 days) \" -> C:\\Users\\john\\AppData\\Local\\Temp\\adom-bridge-recordings\\window-8916576-20260905-223500.mp4 (2564x1540 @ 30fps h264)"+}
demo/routing/obstacles/take-04/record-stop.jsonadded+28@@ -0,0 +1,28 @@+{+ "_hint": "The MP4 is finalized (moov written). pull_file {path} brings it to the caller; the janitor prunes the recordings dir by age/size, so pull it promptly.",+ "audio": false,+ "audioFrames": 0,+ "autoStopped": false,+ "bytes": 70773238,+ "durationMs": 499,+ "elapsedMs": 53070,+ "error": "",+ "fileExists": true,+ "frames": 1464,+ "height": 1540,+ "kind": "window",+ "path": "C:/Users/john/AppData/Local/Temp/adom-bridge-recordings/window-8916576-20260905-223500.mp4",+ "recordingId": "rec-034529ebf72241179a167c8c56d41114",+ "status": "ok",+ "success": true,+ "timeoutSeconds": 30,+ "width": 2564,+ "data": {+ "bytes": 70773238,+ "elapsedMs": 53070,+ "frames": 1464,+ "path": "C:\\Users\\john\\AppData\\Local\\Temp\\adom-bridge-recordings\\window-8916576-20260905-223500.mp4",+ "recordingId": "rec-034529ebf72241179a167c8c56d41114"+ },+ "message": "Stopped recording rec-034529ebf72241179a167c8c56d41114: 1464 frames, 53070 ms, 70773238 bytes -> C:\\Users\\john\\AppData\\Local\\Temp\\adom-bridge-recordings\\window-8916576-20260905-223500.mp4"+}
demo/routing/obstacles/video-verification.jsonadded+31@@ -0,0 +1,31 @@+[+ {+ "file": "fusion-obstacle-live-3x.mp4",+ "fullDecodePassed": true,+ "width": 1920,+ "height": 1080,+ "fps": "30/1",+ "duration": 19.933333,+ "bytes": 976138,+ "sha256": "0104fae34e4654065a2e772a59aefb3f753cf74e266da4336297f8c890645426",+ "sampledFramesReviewedSeconds": [+ 0,+ 2,+ 5,+ 9,+ 13,+ 18+ ]+ },+ {+ "file": "fusion-obstacle-live-1x.mp4",+ "fullDecodePassed": true,+ "width": 1920,+ "height": 1080,+ "fps": "30/1",+ "duration": 49.833333,+ "bytes": 1589166,+ "sha256": "c76e5eae815b61743307c500b6f0cae4fd5d5a16c12eced9cf2041b8227a3e16",+ "sampledFramesReviewedSeconds": []+ }+]
demo/routing/prepare_live_panel.pyadded+23@@ -0,0 +1,23 @@+"""Attach the container SSE page to the bridge's existing activity palette. Run server first."""+import argparse,json+from call import call+from live_panel import URL+p=argparse.ArgumentParser();p.add_argument('--document',required=True);args=p.parse_args()+def invoke(v,a):+ r=call(v,a)+ if not r.get('success'):raise RuntimeError(json.dumps(r))+ return r+invoke('fusion_routing_state',{'expectDocument':args.document})+invoke('fusion_activity_banner',{'action':'show','title':'Astra routing: connecting live display','detail':'Using the existing Adom palette with container SSE.','percent':0,'tone':'working'})+script='''import urllib.request+url=URL_VALUE+body=urllib.request.urlopen(url,timeout=5).read().decode('utf-8')+assert 'routeChecks' in body+p=app.userInterface.palettes.itemById('AdomActivityPalette')+assert p and p.isVisible+p.htmlFileURL=url+result={'containerPageVerified':True,'paletteId':p.id,'visible':p.isVisible}+'''.replace('URL_VALUE',repr(URL))+print(json.dumps(invoke('fusion_run_modeling_script',{'expectDocument':args.document,'script':script}),indent=2))+# The existing close handler stays attached. No new palette or Fusion restart.+print(json.dumps([w for w in invoke('desktop_list_windows',{})['windows'] if w['image']=='Fusion360.exe' and w['title'].upper()=='ADOM'],indent=2))
describe.py+3@@ -16,6 +16,9 @@ _T = [ ("fusion_routing_state", "Read the live board's identity, geometry revision, pads, copper and per-net airwires from a fresh Fusion export.", {"expectDocument":"required exact active board name","boardId":"optional document creationId guard"}, {"boardId":"str","revision":"str","nets":"list","pads":"list","segments":"list","vias":"list","remainingNets":"list"},60,"fusion_routing_state",False,{"expectDocument":"fusion-routing"}),+ ("fusion_plan_route", "Calculate a read-only, bounded orthogonal A* path between two pads on a live two-layer board. Uses existing copper and the shared conservative clearance model. Returns explicit route args for route_net; native DRC is still required after mutation.",+ {"expectDocument":"required str","boardId":"required str","expectedRevision":"required str","net":"required str","fromPad":"required str","toPad":"required str","width":"mm default 0.25","viaDiameter":"mm default 0.6","viaDrill":"mm default 0.3","grid":"mm 0.1..5 default 0.5","allowVias":"bool default true","viaCost":"mm-equivalent cost default 5","maxNodes":"int 1..100000 default 25000","timeoutMs":"int 10..5000 default 3000"},+ {"success":"bool","mutated":"false","revision":"str","plan":"{items,route,planner}"},60,"fusion_routing_state",False,{}), ("fusion_route_net", "Create explicit net copper in the live Fusion canvas. Conservative clearance preflight, board/revision guards and exact copper readback. One or several trace segments per call; no general autorouting. Use routing_drc for native DRC.", {"expectDocument":"required exact board name","boardId":"required from routing_state","expectedRevision":"required from routing_state","net":"required exact name","points":"waypoints [x,y] or {pad} or {x,y,layer}","paths":"optional list of paths instead of points","width":"mm, default .25","layer":"1 or 16, default 1","viaDiameter":"mm, default .6","viaDrill":"mm, default .3","clearance":"mm lower bound, default .2","dryRun":"optional bool"}, {"success":"bool","mutated":"bool","verified":"bool","revision":"str","plan":"obj","remainingNets":"list"},120,"fusion_routing_state",False,{}),
package.json+1−1@@ -1,6 +1,6 @@ { "slug": "fusion-bridge",- "version": "1.10.0-dev.routing.2",+ "version": "1.10.0-dev.routing.4", "type": "app", "description": "This package installs the bridge's SKILLS into your container so your AI knows how to drive it; Adom Bridge loads the bridge runtime itself from the release zip.", "dependencies": {
rust/Cargo.lock+5−5@@ -10,7 +10,7 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "adom-fusion-bridge"-version = "1.10.0-dev.routing.2"+version = "1.10.0-dev.routing.4" dependencies = [ "base64", "chrono",@@ -273,7 +273,7 @@ dependencies = [ [[package]] name = "fusion-core"-version = "1.10.0-dev.routing.2"+version = "1.10.0-dev.routing.4" dependencies = [ "serde", "serde_json",@@ -283,7 +283,7 @@ dependencies = [ [[package]] name = "fusion-lbr"-version = "1.10.0-dev.routing.2"+version = "1.10.0-dev.routing.4" dependencies = [ "regex", "roxmltree",@@ -295,14 +295,14 @@ dependencies = [ [[package]] name = "fusion-os-mac"-version = "1.10.0-dev.routing.2"+version = "1.10.0-dev.routing.4" dependencies = [ "fusion-core", ] [[package]] name = "fusion-os-win"-version = "1.10.0-dev.routing.2"+version = "1.10.0-dev.routing.4" dependencies = [ "fusion-core", "windows-sys 0.59.0",
rust/Cargo.toml+1−1@@ -4,7 +4,7 @@ members = ["core", "lbr", "os-win", "os-mac", "bridge"] # One version for the whole bridge, in lockstep with BRIDGE_VERSION (tools/release.sh bumps both). [workspace.package]-version = "1.10.0-dev.routing.2"+version = "1.10.0-dev.routing.4" edition = "2021" license = "MIT"
rust/bridge/src/routing.rs+2−2@@ -1,8 +1,8 @@ //! Routing operations execute together on Fusion's main thread through the existing //! script transport. Embedding the implementation avoids replacing a loaded add-in. use serde_json::{json, Value};-const SOURCE: &str = include_str!("routing_script.py");-pub fn owns(cmd: &str) -> bool { matches!(cmd, "routing_state" | "route_net" | "routing_drc") }+const SOURCE: &str = concat!(include_str!("routing_script.py"), "\n", include_str!("routing_planner.py"));+pub fn owns(cmd: &str) -> bool { matches!(cmd, "routing_state" | "route_net" | "routing_drc" | "plan_route") } pub fn call(cmd: &str, args: &Value, pass: &dyn Fn(&str, Value) -> Value) -> Value { let script = format!("import json\nexec({})\nresult=handle(app,json.loads({}),{})\n", serde_json::to_string(SOURCE).unwrap(),
rust/bridge/src/routing_planner.pyadded+106@@ -0,0 +1,106 @@+"""Bounded two-layer orthogonal A* over the shared conservative copper model.++Executed after routing_script.py in the same namespace. Planning never mutates.+"""+import heapq+import time+++def automatic_plan(board,args):+ began=time.monotonic()+ net=identifier(args.get('net'));nets,pads,_,_=objects(board)+ if net not in nets:fail('unknown_net','Unknown net '+net)+ ends=[]+ for key in ('fromPad','toPad'):+ p=pads.get(args.get(key))+ if p is None:fail('unknown_pad',key+' must name an existing pad')+ if p['net']!=net:fail('net_mismatch',key+' does not belong to '+net)+ ends.append(p)+ if ends[0]['name']==ends[1]['name']:fail('invalid_path','Choose two different pads')+ width=number(args.get('width',.25),True)+ dia=number(args.get('viaDiameter',.6),True);drill=number(args.get('viaDrill',.3),True)+ if drill>=dia:fail('invalid_geometry','Via drill must be smaller than diameter')+ grid=number(args.get('grid',.5),True)+ if not .1<=grid<=5:fail('invalid_args','grid must be 0.1..5 mm')+ allow=args.get('allowVias',True)+ if not isinstance(allow,bool):fail('invalid_args','allowVias must be boolean')+ via_cost=number(args.get('viaCost',5),True)+ max_nodes=args.get('maxNodes',25000);timeout=args.get('timeoutMs',3000)+ for v,lo,hi,label in [(max_nodes,1,100000,'maxNodes'),(timeout,10,5000,'timeoutMs')]:+ if type(v)!=int or not lo<=v<=hi:fail('invalid_args',label+' outside supported bounds')+ ctx=routing_context(board,args,net,width,drill)+ clearance=ctx['clearance'];edge=ctx['edgeClearance'];xmin,xmax,ymin,ymax=ctx['bounds']+ def axis(lo,hi,coordinates):+ n=math.floor((hi-lo)/grid)+ return sorted(set([round(lo+i*grid,6) for i in range(n+1)]+coordinates))+ if ((xmax-xmin)/grid+3)*((ymax-ymin)/grid+3)*2>250000:+ fail('search_budget','Grid has too many cells; use a coarser grid')+ xs=axis(xmin,xmax,[p['at'][0] for p in ends]);ys=axis(ymin,ymax,[p['at'][1] for p in ends])+ startxy=(xs.index(ends[0]['at'][0]),ys.index(ends[0]['at'][1]))+ goalxy=(xs.index(ends[1]['at'][0]),ys.index(ends[1]['at'][1]))+ layers=[1,16] if allow else sorted(set(ends[0]['layers'])&set(ends[1]['layers']))+ if not layers:fail('no_route','Endpoints need a via but allowVias is false')+ obstacles=[]+ for other,c,d,r,ls in ctx['obstacles']:+ if other==net:continue+ obstacles.append((c,d,r,set(ls),(min(c[0],d[0])-r-clearance,max(c[0],d[0])+r+clearance,min(c[1],d[1])-r-clearance,max(c[1],d[1])+r+clearance)))+ cache={}+ def clear(a,b,radius,ls,via=False):+ if any(not(xmin+edge+radius<=p[0]<=xmax-edge-radius and ymin+edge+radius<=p[1]<=ymax-edge-radius) for p in (a,b)):return False+ ax,bx=min(a[0],b[0])-radius,max(a[0],b[0])+radius+ ay,by=min(a[1],b[1])-radius,max(a[1],b[1])+radius+ for c,d,r,ol,bounds in obstacles:+ if not ls.intersection(ol):continue+ if bx<bounds[0] or ax>bounds[1] or by<bounds[2] or ay>bounds[3]:continue+ if distance(a,b,c,d)<radius+r+clearance-1e-6:return False+ # Avoid placing new vias inside pads, including same-net SMD terminals.+ if via and any(math.dist(a,p['at'])<radius+p['radius']+clearance for p in pads.values()):return False+ return True+ def edge_clear(u,v):+ key=tuple(sorted((u,v)))+ if key not in cache:+ a=(xs[u[0]],ys[u[1]]);b=(xs[v[0]],ys[v[1]])+ via=u[2]!=v[2]+ cache[key]=clear(a,b,max(dia/2,drill+.3) if via else width/2,set(layers) if via else {u[2]},via)+ return cache[key]+ def heuristic(u):+ return abs(xs[u[0]]-ends[1]['at'][0])+abs(ys[u[1]]-ends[1]['at'][1])+(0 if u[2] in ends[1]['layers'] else via_cost)+ queue=[];costs={};parents={};serial=0+ for l in ends[0]['layers']:+ if l not in layers:continue+ u=(*startxy,l);costs[u]=0;heapq.heappush(queue,(heuristic(u),0,serial,u));serial+=1+ visited=set();goal=None+ while queue:+ if len(visited)>=max_nodes or time.monotonic()-began>timeout/1000:+ fail('search_budget','No route found within the node/time budget; no copper was changed')+ _,g,_,u=heapq.heappop(queue)+ if u in visited:continue+ visited.add(u)+ if u[:2]==goalxy and u[2] in ends[1]['layers']:goal=u;break+ x,y,l=u;neighbors=[]+ for dx,dy in ((1,0),(0,1),(-1,0),(0,-1)):+ nx,ny=x+dx,y+dy+ if 0<=nx<len(xs) and 0<=ny<len(ys):neighbors.append((nx,ny,l))+ if allow:neighbors.append((x,y,17-l))+ for v in neighbors:+ if v in visited or not edge_clear(u,v):continue+ step=via_cost if l!=v[2] else abs(xs[x]-xs[v[0]])+abs(ys[y]-ys[v[1]])+ ng=g+step+ if ng>=costs.get(v,float('inf'))-1e-9:continue+ costs[v]=ng;parents[v]=u;heapq.heappush(queue,(ng+heuristic(v),ng,serial,v));serial+=1+ if goal is None:fail('no_route','No legal route exists on the requested grid; no copper was changed')+ path=[goal]+ while path[-1] in parents:path.append(parents[path[-1]])+ path.reverse();simple=[path[0]]+ for a,b,c in zip(path,path[1:],path[2:]):+ if a[2]==b[2]==c[2] and ((a[0]==b[0]==c[0]) or (a[1]==b[1]==c[1])):continue+ simple.append(b)+ simple.append(path[-1]);points=[]+ for x,y,l in simple:+ xy=[xs[x],ys[y]]+ if points and [points[-1]['x'],points[-1]['y']]==xy:points[-1]['layer']=l+ else:points.append({'x':xy[0],'y':xy[1],'layer':l})+ route={'net':net,'width':width,'layer':path[0][2],'viaDiameter':dia,'viaDrill':drill,'clearance':clearance,'points':points}+ candidate=plan(board,route) # Same authoritative preflight used by the mutation verb.+ length=sum(math.dist(i['start'],i['end']) for i in candidate['items'] if i['kind']=='segment')+ return {**candidate,'route':route,'planner':{'algorithm':'bounded orthogonal two-layer A*','grid':grid,'expandedNodes':len(visited),'elapsedMs':round((time.monotonic()-began)*1000,3),'lengthMm':round(length,6),'viaCount':sum(i['kind']=='via' for i in candidate['items']),'externalRouter':False}}
rust/bridge/src/routing_script.py+31−21@@ -147,15 +147,6 @@ def plan(board,args): nets,pads,wires,vias=objects(board) net=identifier(args.get('net')) if net not in nets: fail('unknown_net','No exact net named '+net)- setup=board.find("designrules/param[@name='layerSetup']")- if setup is None or setup.get('value') != '(1*16)':- fail('unsupported_board','Initial routing supports two-layer (1*16) boards')- # Do not silently overlook obstacles this conservative preflight cannot represent.- if board.findall('.//polygon') or any(w['curve'] for w in wires):- fail('unsupported_board','Polygons and curved copper require a richer clearance preflight')- for n in board.findall('plain/*') + board.findall('libraries/library/packages/package/*'):- if n.tag not in ('pad','smd') and n.get('layer') in ('1','16','41','42','43','46'):- fail('unsupported_board','Copper, restrict or milling artwork is not supported by this preflight') def layer(v): if isinstance(v,bool) or v not in (1,16): fail('invalid_layer','Only copper layers 1 and 16 are supported') return int(v)@@ -197,6 +188,33 @@ def plan(board,args): unique.append(item) planned=unique if not planned or len(planned)>512: fail('invalid_path','Need 1..512 nonzero copper items')+ ctx=routing_context(board,args,net,width,drill)+ clearance=ctx['clearance']; obstacles=ctx['obstacles']+ xmin,xmax,ymin,ymax=ctx['bounds']+ for item in planned:+ via=item['kind']=='via'; a=item['at'] if via else item['start']; b=a if via else item['end']+ radius=max(item['diameter']/2,item['drill']+.3) if via else item['width']/2; layers=[1,16] if via else [item['layer']]+ margin=ctx['edgeClearance']+radius+ if any(not(xmin+margin<=p[0]<=xmax-margin and ymin+margin<=p[1]<=ymax-margin) for p in (a,b)):+ fail('clearance_violation','Candidate copper violates the board-edge margin')+ for other,c,d,r,ls in obstacles:+ if other==net or not set(layers).intersection(ls): continue+ gap=distance(a,b,c,d)-radius-r+ if gap<clearance-1e-6: fail('clearance_violation','Candidate copper approaches another net or hole closer than %.3f mm'%clearance)+ return {'net':net,'items':planned,'clearance':clearance,'preflight':'Conservative geometry only; run native Autodesk DRC after edits'}+++def routing_context(board,args,net,width,drill):+ nets,pads,wires,vias=objects(board)+ setup=board.find("designrules/param[@name='layerSetup']")+ if setup is None or setup.get('value') != '(1*16)':+ fail('unsupported_board','Initial routing supports two-layer (1*16) boards')+ # Do not silently overlook obstacles this conservative preflight cannot represent.+ if board.findall('.//polygon') or any(w['curve'] for w in wires):+ fail('unsupported_board','Polygons and curved copper require a richer clearance preflight')+ for n in board.findall('plain/*') + board.findall('libraries/library/packages/package/*'):+ if n.tag not in ('pad','smd') and n.get('layer') in ('1','16','41','42','43','46'):+ fail('unsupported_board','Copper, restrict or milling artwork is not supported by this preflight') def rule(name,default): node=board.find("designrules/param[@name='%s']"%name) if node is None: return default@@ -230,17 +248,7 @@ def plan(board,args): xy=[float(h.get('x')),float(h.get('y'))]; obstacles.append((None,xy,xy,float(h.get('drill'))/2,[1,16])) if board.findall('libraries/library/packages/package/hole'): fail('unsupported_board','Footprint mounting holes require transformed obstacle support')- for item in planned:- via=item['kind']=='via'; a=item['at'] if via else item['start']; b=a if via else item['end']- radius=item['diameter']/2 if via else item['width']/2; layers=[1,16] if via else [item['layer']]- margin=rule('mdCopperDimension',0.5)+radius- if any(not(xmin+margin<=p[0]<=xmax-margin and ymin+margin<=p[1]<=ymax-margin) for p in (a,b)):- fail('clearance_violation','Candidate copper violates the board-edge margin')- for other,c,d,r,ls in obstacles:- if other==net or not set(layers).intersection(ls): continue- gap=distance(a,b,c,d)-radius-r- if gap<clearance-1e-6: fail('clearance_violation','Candidate copper approaches another net or hole closer than %.3f mm'%clearance)- return {'net':net,'items':planned,'clearance':clearance,'preflight':'Conservative geometry only; run native Autodesk DRC after edits'}+ return {'clearance':clearance,'edgeClearance':rule('mdCopperDimension',0.5),'bounds':(xmin,xmax,ymin,ymax),'obstacles':obstacles,'pads':pads} def native_drc(app):@@ -297,6 +305,8 @@ def handle(app,args,action): if action=='routing_state': return {'success':True,**state(board,meta)} if args.get('boardId')!=meta['boardId']: fail('board_mismatch','Mutations/checks require boardId from fusion_routing_state') if args.get('expectedRevision')!=meta['revision']: fail('stale_board','expectedRevision must match the current live board')+ if action=='plan_route':+ return {'success':True,'mutated':False,**meta,'plan':automatic_plan(board,args)} if action=='routing_drc': app.executeTextCommand('Electron.run RATSNEST;') report=native_drc(app)@@ -314,7 +324,7 @@ def handle(app,args,action): a,b=item['start'],item['end'] command="LAYER %d; LINE '%s' %.6fmm (%.6fmm %.6fmm) (%.6fmm %.6fmm);"%(item['layer'],candidate['net'],item['width'],*a,*b) else:- command="VIA '%s' %.6fmm ROUND 1-16 (%.6fmm %.6fmm); CHANGE DRILL %.6fmm (%.6fmm %.6fmm);"%(candidate['net'],item['diameter'],*item['at'],item['drill'],*item['at'])+ command="CHANGE DRILL %.6fmm; VIA '%s' %.6fmm ROUND 1-16 (%.6fmm %.6fmm);"%(item['drill'],candidate['net'],item['diameter'],*item['at']) attempted=True app.executeTextCommand('Electron.run '+command) commands.append(command)
server.py+2−2@@ -15756,9 +15756,9 @@ def _dispatch_command_inner(command: str, args: dict, caller_identity: dict = No return _orchestrate_board_stackup(args) # Add-in proxy commands- if command in ("routing_state", "route_net", "routing_drc"):+ if command in ("routing_state", "route_net", "routing_drc", "plan_route"): import pathlib- source = (pathlib.Path(__file__).parent / "rust/bridge/src/routing_script.py").read_text()+ source = "\n".join((pathlib.Path(__file__).parent / "rust/bridge/src" / name).read_text() for name in ("routing_script.py", "routing_planner.py")) script = "import json\nexec(%r)\nresult=handle(app,json.loads(%r),%r)\n" % (source, json.dumps(args), command) reply = _proxy_to_addin("run_modeling_script", {"script":script, "expectDocument":args.get("expectDocument")}, timeout=120) return reply.get("data", {}).get("result", reply)
skills/fusion-routing/SKILL.md+23−1@@ -1,6 +1,6 @@ --- name: fusion-routing-description: Use when asked to route explicit net paths live in Fusion or record trace creation using fusion_routing_state, fusion_route_net and fusion_routing_drc. Development feature with two-layer geometric preflight and native final DRC.+description: Use when asked to route explicit net paths live in Fusion or record trace creation using fusion_routing_state, fusion_route_net and fusion_routing_drc. Use fusion_plan_route for bounded obstacle-aware path calculation. Development feature with two-layer geometric preflight and native final DRC. --- Parent skill: [fusion-bridge](../../SKILL.md).@@ -34,3 +34,25 @@ See `demo/routing/README.md` for the tested scope, fixture, recorder and evidenc For the 24-net crossover, see `demo/routing/crossbar/README.md`. Identical via transitions shared by branches of one request produce one planned via.++For obstacle-aware planning, call `fusion_plan_route` with the same document,+board and revision guards plus `net`, `fromPad`, and `toPad`. It returns a+read-only `plan.route` for `fusion_route_net` and `plan.items` for visible+per-item commits. Grid, via cost, allowVias and bounded node/time limits are+optional. It is a two-pad orthogonal A* planner, not an all-net autorouter.+Use a fresh plan after intervening edits. See `demo/routing/obstacles/README.md`.++## Showing live calculations during a demo++Reuse `AdomActivityPalette`, its branding and close behavior. The repo's+`demo/routing/live_panel.py` serves the shared activity-palette component and SSE+from the container; `prepare_live_panel.py` attaches it to the existing palette.+Show pad endpoints, measured planner output, primitive creation, copper read-back+and native DRC results as they occur. Do not claim every operation has a live UI+unless the caller actually publishes these events. A lost DOM acknowledgment+stops the demo before the next mutation; do not reopen a user-closed palette.++Fusion palettes can be owned popup windows omitted by parent-window capture.+Inspect the popup screenshots and capture its HWND separately if necessary.+Check that both windows are visible, unminimized and large enough before recording.+Preserve raw takes and record synchronization limits when composing two captures.
tests/test_routing.py+42@@ -7,6 +7,7 @@ import xml.etree.ElementTree as ET ROOT=Path(__file__).resolve().parents[1] spec=importlib.util.spec_from_file_location('routing',ROOT/'rust/bridge/src/routing_script.py') r=importlib.util.module_from_spec(spec);spec.loader.exec_module(r)+exec((ROOT/'rust/bridge/src/routing_planner.py').read_text(),r.__dict__) class RoutingTests(unittest.TestCase): def setUp(self):@@ -39,6 +40,47 @@ class RoutingTests(unittest.TestCase): ET.SubElement(signal,'via',x=str(item['at'][0]),y=str(item['at'][1]),diameter=str(item['diameter']),drill=str(item['drill']),extent=item['extent']) self.assertEqual({'segment':120,'via':48},totals) + def test_obstacle_planner_chooses_vias(self):+ b=ET.parse(ROOT/'demo/routing/obstacles/fusion-obstacle-lab.brd').find('drawing/board')+ args={'net':'ROUTE_1','fromPad':'L1.1','toPad':'R1.1','timeoutMs':5000}+ before=ET.tostring(b)+ p=r.automatic_plan(b,args)+ self.assertEqual(2,p['planner']['viaCount'])+ self.assertEqual(40,p['planner']['lengthMm'])+ self.assertEqual(before,ET.tostring(b))+ self.assertFalse(p['planner']['externalRouter'])++ def test_obstacle_planner_same_layer_detour(self):+ b=ET.parse(ROOT/'demo/routing/obstacles/fusion-obstacle-lab.brd').find('drawing/board')+ p=r.automatic_plan(b,{'net':'ROUTE_1','fromPad':'L1.1','toPad':'R1.1','allowVias':False,'timeoutMs':5000})+ self.assertEqual(0,p['planner']['viaCount'])+ self.assertGreater(p['planner']['lengthMm'],40)+ self.assertTrue(all(i.get('layer')==1 for i in p['items']))++ def test_planner_budget_is_read_only(self):+ b=ET.parse(ROOT/'demo/routing/obstacles/fusion-obstacle-lab.brd').find('drawing/board');before=ET.tostring(b)+ with self.assertRaises(r.RoutingError) as e:+ r.automatic_plan(b,{'net':'ROUTE_1','fromPad':'L1.1','toPad':'R1.1','maxNodes':1})+ self.assertEqual('search_budget',e.exception.code);self.assertEqual(before,ET.tostring(b))++ def test_via_insertion_margin_rejects_native_shove_trigger(self):+ b=ET.parse(ROOT/'demo/routing/obstacles/fusion-obstacle-lab.brd').find('drawing/board')+ with self.assertRaises(r.RoutingError) as e:+ r.plan(b,{'net':'ROUTE_2','points':[[21,20],{'x':21,'y':20,'layer':16}]})+ self.assertEqual('clearance_violation',e.exception.code)++ def test_no_route_when_same_layer_is_partitioned(self):+ b=ET.parse(ROOT/'demo/routing/obstacles/fusion-obstacle-lab.brd').find('drawing/board')+ barrier=b.find("signals/signal[@name='TOP_BARRIER']/wire");barrier.set('y1','0');barrier.set('y2','40')+ with self.assertRaises(r.RoutingError) as e:+ r.automatic_plan(b,{'net':'ROUTE_1','fromPad':'L1.1','toPad':'R1.1','allowVias':False,'timeoutMs':5000})+ self.assertEqual('no_route',e.exception.code)++ def test_planner_wrong_net(self):+ with self.assertRaises(r.RoutingError) as e:+ r.automatic_plan(self.board,{'net':'NET_1','fromPad':'J1.1','toPad':'J2.2'})+ self.assertEqual('net_mismatch',e.exception.code)+ def test_wrong_net_pad(self): self.args['points'][0]={'pad':'J1.2'};self.rejected('net_mismatch') def test_injected_command(self):
tools/install-routing-dev.ps1+1−1@@ -1,7 +1,7 @@ param( [Parameter(Mandatory=$true)][string]$Cache, [Parameter(Mandatory=$true)][string]$Staged,- [string]$Version='1.10.0-dev.routing.2'+ [string]$Version='1.10.0-dev.routing.4' ) $ErrorActionPreference='Stop' if (!(Test-Path "$cache/.dev-pin")) { throw 'Fusion bridge is not dev-pinned' }