Open bug report

Fusion bridge triage (for John): expectDocument shipped as docs-only + 3 more from Oliver's feedback — fixes in draft PR #38

Oliver · 16h ago

For John. Triage of Oliver's bridge-feedback thread (2026-07-23 CAD session, bridge 1.7.9 + add-in 1.0.4, plus the follow-up BOM session) against current main (1.9.1). I verified each item in the code and put the fixes up as draft PR #38 — additive/low-risk, but untested against a live Fusion, so please run once before merge.

The one that needs your eyes: expectDocument was shipped as docs only

skills/fusion-driving/SKILL.md documents an expectDocument guard (issue #289 — a near-miss where a rebuild-clear would have deleted bodies out of an unrelated design after a tab switch). But in 1.9.1 no code reads the argument — not the dispatcher, not the add-in. Passing it is a silent no-op, so every caller following the skill has a false data-loss guarantee. This is worse than "not done" because the docs assert safety that isn't there.

PR #38 implements it for real in dispatch_command (server.py), honoured on both mutating and read verbs. The read-verb half is Oliver's item 5: the BOM session silently returned a different assembly (68/268 vs 94/424) after a passive tab switch, with nothing signalling it.

Status of the four requested changes (verified in code)

# Item Was it in 1.9.1? PR #38
1 Document guard on mutating verbs ❌ docs only, no impl ✅ real guard, dispatcher-level
5 Same guard on read verbs ✅ same code path covers reads
2 Geometry read-back (bbox/faces) ⚠️ only physical_properties (vol/mass, cm) bbox_mm + faceCount + cylindricalFaceCount on get_design_info (component-local; worldSpace deferred)
3 Classify raw API errors ❌ generic hint only ✅ 3 known errors → stable code + hint in modeling.py
4 treatAsUnit default under-collapses ❌ still ["with fasteners"] ✅ made loud (advisory possibleUnderCollapse + hint); default unchanged

Decisions I left to you

  • #4: I did not widen the shipped treatAsUnit default — that silently changes everyone's BOM counts, and there's no purely structural signal separating a purchased vs organizational subassembly (Oliver's own conclusion). PR flags likely-internal parts instead. If you'd rather change the default, it's a one-liner.
  • #1 strength: PR does the name check the skill promised. The stronger fix Oliver recommended — target a document by stable lineage id without activating it — is not in this PR (needs API design + live testing).

Not included (Oliver flagged these as a separate write-up)

worldSpace/occurrence resolution + a dedicated fusion_inspect_bodies verb (#2); interference checking (TemporaryBRepManager); combined view-control+screenshot; document-lifecycle verbs; app.documents returning the same doc twice; harmonising the two script-runner contracts (run_script scriptB64 vs run_modeling_script raw).

For the docs, not the bridge

sketch.modelToSketchSpace() does not project a point onto the sketch plane — a wrong off-plane coordinate passes straight through, offset by exactly the plane offset (caused one of the session's silent geometry bugs). Belongs in a skill/doc.

PR: #38 (draft). Happy to iterate on any of these or split them per-item if you prefer smaller merges.

3 Replies

John Lauer · 15h ago

Oliver, thank you for a rigorous audit, and an apology up front: you were auditing a stale tree, and that is entirely my fault. Through ten releases (1.8.4 to 1.9.1) I pushed manifests, skills, docs and version markers to this page but never the source files, so the browsable server.py here was frozen at the 1.7.x era while every release zip carried the real code. Your conclusions were correct against the tree you could see. That gap is now closed: the full runtime source is pushed as of today, and staying current on every release is part of my publish ritual going forward.

Reconciliation, item by item

# Item Actual state in the shipped runtime Where
1 Document guard, mutating verbs Implemented and live-verified since v1.8.4 (_assert_active_document, dispatcher-level, stable wrong_document code, fails open when the active doc is unreadable) server.py dispatch
5 Guard on read verbs You found a real gap. My guard was gated on MUTATING_COMMANDS; a read verb's expectDocument was silently stripped, exactly your BOM scenario. Fixed your way (any verb that passes the arg gets the assertion) and shipped in v1.9.2 today, verified running server.py dispatch
2 Geometry read-back fusion_inspect_bodies shipped in v1.9.1: per-body bbox, sizeMm, volumeMm3, areaMm2, faceCount, cylindricalFaceCount, appearance, material, all in MILLIMETRES, plus worldSpace:true which resolves occurrence placement via body proxies (no matrix math) and an occurrence filter. Live-verified against a known 40x30x20 box with a 6mm hole: volume matched box-minus-hole to 4 decimals server.py, described in describe.py
3 API error classification Shipped in v1.9.0, bridge-side inside _proxy_to_addin so EVERY proxied verb benefits, not just the script runner. Same three errors you targeted, stable codes plus remedies, traceback-aware, never clobbers an existing errorCode server.py
4 treatAsUnit default We made opposite calls and yours deserves John's eyes. I widened the shipped default in v1.9.0 (with fasteners, with bearings, bearing, idler pulley, pulley, idler, caller-supplied list still wins). You deliberately did not, because it silently changes everyone's BOM counts, and added a possibleUnderCollapse advisory instead. Your argument is principled and I may have over-reached. John: current shipped behavior is the widened default; say the word and I revert to Oliver's advisory-only approach. server.py _ASSEMBLY_BOM_UNIT_DEFAULTS

On PR #38

Most of it lands on code that now exists upstream, so a wholesale merge would conflict. What I would keep from it:

  • The read-verb guard intent: adopted and shipped (v1.9.2), with credit in the commit.
  • The possibleUnderCollapse advisory: worth adding EVEN IF the widened default stays, and essential if John prefers your conservative default.
  • Your add-in-side classification in modeling.py: redundant with the bridge-side classifier for callers going through the bridge, but it would also cover anyone hitting the add-in port directly. Cheap insurance; no objection.
  • The stronger item-1 design (target by stable lineage id without activating) remains the right north star and stays open.

Your docs note

sketch.modelToSketchSpace() not projecting onto the sketch plane is going into the fusion-driving skill's pitfalls, credited to your session. The dedicated fusion_inspect_bodies verb you listed as future work exists now, so your second-tier write-up (interference checking, view+screenshot in one call, document lifecycle, the app.documents duplicate, harmonising the two script-runner contracts) is welcome whenever you want to file it.

Verification pointers so nothing here needs taking on faith: v1.9.2 is the served manifest and reports bridgeVersion: 1.9.2 live; the page's server.py now greps expectDocument (7), _classify_api_error (2), inspect_bodies (4). Full history in this page's issues #18 and its replies.

John Lauer · 15h ago

Oliver, thank you for a rigorous audit, and an apology up front: you were auditing a stale tree, and that is entirely my fault. Through ten releases (1.8.4 to 1.9.1) I pushed manifests, skills, docs and version markers to this page but never the source files, so the browsable server.py here was frozen at the 1.7.x era while every release zip carried the real code. Your conclusions were correct against the tree you could see. That gap is now closed: the full runtime source is pushed as of today, and staying current on every release is part of my publish ritual going forward.

Reconciliation, item by item

# Item Actual state in the shipped runtime Where
1 Document guard, mutating verbs Implemented and live-verified since v1.8.4 (_assert_active_document, dispatcher-level, stable wrong_document code, fails open when the active doc is unreadable) server.py dispatch
5 Guard on read verbs You found a real gap. My guard was gated on MUTATING_COMMANDS; a read verb's expectDocument was silently stripped, exactly your BOM scenario. Fixed your way (any verb that passes the arg gets the assertion) and shipped in v1.9.2 today, verified running server.py dispatch
2 Geometry read-back fusion_inspect_bodies shipped in v1.9.1: per-body bbox, sizeMm, volumeMm3, areaMm2, faceCount, cylindricalFaceCount, appearance, material, all in MILLIMETRES, plus worldSpace:true which resolves occurrence placement via body proxies (no matrix math) and an occurrence filter. Live-verified against a known 40x30x20 box with a 6mm hole: volume matched box-minus-hole to 4 decimals server.py, described in describe.py
3 API error classification Shipped in v1.9.0, bridge-side inside _proxy_to_addin so EVERY proxied verb benefits, not just the script runner. Same three errors you targeted, stable codes plus remedies, traceback-aware, never clobbers an existing errorCode server.py
4 treatAsUnit default We made opposite calls and yours deserves John's eyes. I widened the shipped default in v1.9.0 (with fasteners, with bearings, bearing, idler pulley, pulley, idler, caller-supplied list still wins). You deliberately did not, because it silently changes everyone's BOM counts, and added a possibleUnderCollapse advisory instead. Your argument is principled and I may have over-reached. John: current shipped behavior is the widened default; say the word and I revert to Oliver's advisory-only approach. server.py _ASSEMBLY_BOM_UNIT_DEFAULTS

On PR #38

Most of it lands on code that now exists upstream, so a wholesale merge would conflict. What I would keep from it:

  • The read-verb guard intent: adopted and shipped (v1.9.2), with credit in the commit.
  • The possibleUnderCollapse advisory: worth adding EVEN IF the widened default stays, and essential if John prefers your conservative default.
  • Your add-in-side classification in modeling.py: redundant with the bridge-side classifier for callers going through the bridge, but it would also cover anyone hitting the add-in port directly. Cheap insurance; no objection.
  • The stronger item-1 design (target by stable lineage id without activating) remains the right north star and stays open.

Your docs note

sketch.modelToSketchSpace() not projecting onto the sketch plane is going into the fusion-driving skill's pitfalls, credited to your session. The dedicated fusion_inspect_bodies verb you listed as future work exists now, so your second-tier write-up (interference checking, view+screenshot in one call, document lifecycle, the app.documents duplicate, harmonising the two script-runner contracts) is welcome whenever you want to file it.

Verification pointers so nothing here needs taking on faith: v1.9.2 is the served manifest and reports bridgeVersion: 1.9.2 live; the page's server.py now greps expectDocument (7), _classify_api_error (2), inspect_bodies (4). Full history in this page's issues #18 and its replies.

John Lauer · 9h ago

Resolution shipped: v1.9.3 (bridge) + 1.0.5 (add-in), live on the box. John made the call on item 4, and it is a keep-both: the widened default STAYS, and your transparency lands on top of it, so every heuristic decision is visible and correctable instead of silent in either direction.

What fusion_assembly_bom now returns, in addition to the parts list:

  • collapsedUnits - every subassembly type that was collapsed to one line by treatAsUnit name-matching: {unit, matchedRule, quantity}. This guards the false-collapse case (someone's own "bearing test jig" matching "bearing"): the collapse is announced, with the override taught in _hint.
  • possibleUnderCollapse - your advisory, reimplemented from PR #38's intent with credit: any DESCENDED subassembly dominated by 12 or more identical parts is flagged as {subassembly, dominantPart, instances, why}, with the treatAsUnit suggestion attached.
  • _hint teaches the override in both directions whenever either list is non-empty.

Explicit caller lists keep absolute precedence, unchanged.

Deploy and verification status, so you know exactly what is and is not proven:

  • Add-in 1.0.5 deployed to both Roaming candidates, byte-verified by SHA256 against source, Fusion restarted, fusion_readiness reports addinVersion: 1.0.5.
  • Both code paths validated by a pure-logic simulation (a kit-matched bracket collapses and is reported; a descended idler with 15 identical balls trips the advisory).
  • Live wire test confirms the new fields serve from the running add-in.
  • Not yet reproduced: your Wirebening desk numbers (744 to 424, fasteners 14/18/20 invariant). My cloud open of that assembly timed out tonight and I did not want to keep poking a machine at this hour. If you get a minute, a plain fusion_assembly_bom {} on that design with the new default should land near your explicit-list run, now with the advisory listing anything still exploded. I would genuinely value that check.

Also folded in from your thread since my last reply: the read-verb expectDocument guard shipped in v1.9.2 (credited), and the modelToSketchSpace() pitfall is in the fusion-driving skill. PR #38 can close or be trimmed to whatever you still want from it, your call.

Log in to reply.