app
SOLIDWORKS Bridge
Public Made by Adomby adom
Launch, model and quit SOLIDWORKS from any Adom container. Nothing is ever lost.
← Commit history
docs: 0.7.4–0.7.6 — per-type floors, unknown kind never defaults to part, runtime naming fallback, per-file reopen hints; 28 adversary passes
4 files changed
+70−8
README.md+49−3@@ -312,8 +312,9 @@ Before any of that, the sweep asks whether it **fits**. Marker and floor catch a empty file and a foreign one; neither catches *the right file, cut short* — the marker sits at offset 4, so every prefix of a real document carries it, and a truncation past 16 KB clears the floor. The format offers nothing cheap that-would catch it. So the sweep estimates what the session will write (on-disk sizes-for documents it can measure, an upward estimate for the rest) and **refuses to+would catch it. So the sweep estimates what the session will write — on-disk sizes for documents+it can measure, and for the rest a floor that depends on the document's KIND,+because an assembly is about thirty times the median part — and **refuses to begin** when the recovery volume has less than twice that free: `insufficient_headroom`, naming free bytes, needed bytes and the shortfall, with nothing written and nothing closed. It asks again before *every* save, because@@ -433,7 +434,52 @@ not. ## Roadmap -- v0.7.3 (this): **it refuses to start a sweep it cannot fit.** Pass 24 found the+- v0.7.6 (this): **ask the evidence already in hand, and tell the user how to+ reopen what was rescued.** When `GetType` fails, the document's OWN PATH is now+ consulted before its title — the path is the user's file as SOLIDWORKS named it,+ while a title often has no extension at all (Explorer hides known types by+ default). That narrows the neutral `.sldrecover` name to the only case with no+ extension anywhere: a pathless document whose type could not be read. Asking the+ path is not the circularity 0.7.5 removed — the path describes the document; the+ recovery file's name is chosen by the sweep FROM the kind, so reading a kind out+ of THAT can only repeat an assumption. If SOLIDWORKS refuses to write the+ neutral name (`SaveAs3` dispatches its writer on the extension, and this bridge+ does not assume what it does with one it has never seen), the document is+ re-saved as `.SLDPRT` and the record says `unknownKindNamedAsPart` — the+ verification does NOT soften, because the kind is still unknown and the name is+ only a label. And `swx_recover_list` now gives every file its own `howToOpen`: a+ `.sldrecover` file says rename it and to what, rather than "reopen with+ swx_open", which is the one instruction that cannot work for it. 341 tests.+- v0.7.5: **the classifier can say "I do not know".** Pass 26 found a+ data-loss path that only 0.7.4's per-kind floors made reachable, and it is+ circular: `GetType` failing on a document being closed under memory pressure —+ the condition the sweep exists for — became "part" via `unwrap_or(1)`; the+ recovery file was then NAMED `.SLDPRT` from that; and the verification read the+ kind back out of the name it had just produced. A derived value cannot check the+ thing it was derived from, and a 30 KB truncated assembly cleared the 24 KB part+ floor (the smallest real assembly measured here is 95,492 bytes). The kind is now+ carried from the COM read all the way to the verdict: an unreadable type is+ UNKNOWN, an unknown gets a neutral `.sldrecover` name rather than a guessed one,+ and it is verified against the strictest floor plus — when the document had a+ file of its own — at least what that file weighed. Classification is by file+ EXTENSION only, so a recovery folder called `…\Drawings\` no longer reclassifies+ every part under it as a drawing. A title is read as a title: `Assem1` is an+ assembly, not a part. Refusing to close is the safe error, and the doc comment+ that argued the opposite is gone. 336 tests.+- v0.7.4: **sizes by kind, because the three kinds are not the same size.**+ The 0.7.3 estimator costed a document it could not measure at twice the largest+ it could, which is not monotone: one measurable 29 KB part beside a pathless+ assembly LOWERED that assembly's assumed cost from 1 MB to 58 KB — learning+ something small about a session made the guess about the rest of it smaller, and+ that same number gates the check before every save. An unknown document now+ costs at least a floor set by its kind (part 256 KB, assembly 8 MB, drawing+ 4 MB, each above the measured median), so a measured neighbour can never lower+ it. The recovery floor splits by kind too — part 24 KB, assembly 80 KB, drawing+ 256 KB, each just under the smallest real document of its kind measured here+ (29,130 / 95,492 / 319,803) — because one floor for all three has to be the+ lowest of them, which would let an assembly stop at a third of its size and+ still pass. 330 tests.+- v0.7.3: **it refuses to start a sweep it cannot fit.** Pass 24 found the gap the 0.7.2 checks structurally cannot close: the container marker lives at offset 4, so ANY prefix of a real document carries it, and a write that reaches 20 KB of a 500 KB assembly clears the 16 KB floor too. Marker and floor catch
SKILL.md+11−3@@ -30,7 +30,8 @@ adom-bridge --ai-thread "<your thread>" swx_bom '{"path":"C:\\designs\\gearbox.s then edited is copied into recovery under a new name; their file on disk is untouched and their unsaved changes still survive. - **It refuses to start a sweep that will not fit.** Before writing anything it- estimates the session and compares it with free space on the recovery volume;+ estimates the session — by document kind, since an assembly is about thirty+ times the median part — and compares it with free space on the recovery volume; if there is less than twice the estimate it answers `insufficient_headroom` with the numbers, having written and closed NOTHING. Free some space, or point `recoveryDir` at a volume with room. It re-checks before every save, so a disk@@ -39,7 +40,10 @@ adom-bridge --ai-thread "<your thread>" swx_bom '{"path":"C:\\designs\\gearbox.s reply. The reason is a truncation nobody can detect afterwards: a recovery file can be the RIGHT document CUT SHORT and nothing in the file would show it. - **"On disk" is checked structurally.** Each recovery file must LOOK like a- SOLIDWORKS document (the container marker at its head) and be at least 16 KB;+ SOLIDWORKS document (the container marker at its head) and be at least as big as+ the smallest real document of its kind (part 24 KB, assembly 80 KB, drawing+ 256 KB — and if the bridge could not establish the kind, the strictest of the+ three plus at least the size of the document's own previous file); both are reported per document as `recoverySignatureOk` and `recoveryBytes`. A full disk leaves zero-byte and truncated files that `exists()` and any byte floor accept; those are not saves, and the document stays open. The check fails@@ -60,7 +64,11 @@ adom-bridge --ai-thread "<your thread>" swx_bom '{"path":"C:\\designs\\gearbox.s - **`swx_close_all_safely {reason}`** is the same sweep without the quit, for when the user wants an empty session rather than no SOLIDWORKS. - **`swx_recover_list`** shows what every sweep preserved and where, newest first.- Tell the user this path when you close their work; `swx_open` reopens any of it.+ Tell the user this path when you close their work. FOLLOW EACH FILE'S OWN+ `howToOpen`: most say `swx_open`, but a file named `.sldrecover` is the rescue of+ a document whose kind could not be established, and SOLIDWORKS will not open it+ until it is renamed to `.SLDPRT`, `.SLDASM` or `.SLDDRW`. Never tell the user to+ `swx_open` one of those. - **`swx_shutdown` is idempotent.** SOLIDWORKS not running answers `success:true, alreadyStopped:true`. It is the last thing you do, and the last thing should be safe to repeat.
docs/ECOSYSTEM-TABLE.md+1−1@@ -111,7 +111,7 @@ templates**, alisamsam **22**. | 43 | **Import / resource lifecycle — no leaked temps, drainable, enumeration never wedges** | ✗ | **✓ 0.5.0** — enumeration degrades above a cap (`{count,truncated,sample}`, never a 30s timeout+kill); `swx_close_import_temps` drains STEP/IGES `…\Temp\swx<pid>\IC~~\…` temps in the DEFAULT posture (path is the ownership proof, survives a pid change); import asserts a net +1. Root-caused a live 1342-doc / 8 GB leak. **0.5.3**: the resolved `%TEMP%` is the WHOLE location proof (8.3-aware, no shape-test fallback), and with no resolved root the drain refuses (`temp_root_unknown`) instead of closing nothing quietly. **0.5.4**: the report says which root it compared against (`tempRoot`) and counts documents that carry the launcher's tail but sit elsewhere (`importTempsElsewhere` + a sample), so a drain that matched nothing can no longer claim it drained everything. **0.5.6**: the victim is CLOSED by the path it was chosen by (it was closed by TITLE, which `CloseDoc` resolves by name without prompting — a live session held temps sharing a saved file's title), a shared title is refused and reported, and every close is verified by path — the mismatch case is real, because ab's `%TEMP%` need not be the one SOLIDWORKS used | ✗ | ✗ | ✗ | ✗ | ✗ | | 44 | **Graceful QUIT that is measured, not assumed** (never a kill, never answers a dialog, proves the exit from the process census) | ✗ | **⚠ 0.5.3 mock-proven, UNPROVEN LIVE** — a rung ladder (a `ExitApp` → f Restart Manager *without* `RmForceShutdown`), pinned at rung (a); 7 re-measured preconditions where UNKNOWN refuses and `force` waives the UNSAVED question ONLY; every COM reference released before and after each rung, with outstanding refs named in the report; success = *this pid AND this creation time* absent from the census, never `GetActiveObject`; per-session children reaped while the documented platform daemons are left alone; a dialog stops the ladder permanently and is never answered; nothing disowned until the exit is verified. every precondition re-measured before EVERY rung (a mid-ladder refusal is a real outcome), the exit POLLED to the rung's budget rather than sampled once (a real `ExitApp` returns before the process goes), the dialog census covering the `swCefSubProc` web-view children by parentage, the count cross-checked against the enumeration, and the message rungs re-verifying window ownership before they send. `tools/quit-gate.py` proves the session was bridge-launched and has not been run | ✗ | ✗ | ✗ | ✗ | ✗ | -| 45 | **Closes its own documents without asking — and loses nothing doing it** (preserve-then-close: every open document written to a recovery folder and verified there BEFORE anything closes) | ✗ | **⚠ 0.7.3 mock-proven, first live close PENDING** — `swx_shutdown {reason}` / `swx_close_all_safely {reason}` save every open document into `…\exports\recovery\<timestamp>\`, verify it, close parents before children, then quit; no write opt-in, no per-document confirmation (Drew, 2026-09-11: *"I despise every time you ask for help closing"*). The authorization is to CLOSE, not to lose anything, so the consent question is replaced by checkable rules: the sweep REFUSES TO START when the recovery volume cannot hold the session it is about to write (`insufficient_headroom` with free/needed/shortfall, nothing written, nothing closed), re-checked before every save, with `headroomBytesBefore` and `estimatedWriteBytes` always reported — because a recovery file can be the RIGHT document CUT SHORT and no check on the file can tell (the marker is at offset 4, so every prefix carries it); the recovery file is verified STRUCTURALLY — it must be a recognised SOLIDWORKS container AND at least 16 KB, published as `recoverySignatureOk` + `recoveryBytes`, and it fails CLOSED (`exists()` passes a zero-byte file and any byte floor passes a truncated one; both are what a full disk leaves). The container marker was MEASURED on 166 real documents from three hardware repositories, because the signature every reference names for a SOLIDWORKS document (OLE compound file) appears in NONE of them — verifying that, as pass 23 specified, would have refused to close every document on a modern install; a document that could not be written is left OPEN and named in `remaining`; the user's saved-then-edited file is copied to recovery under a new name and their original is asserted byte-for-byte unchanged; `SaveAs3` uses `swSaveAsOptions_Silent` ALONE so the document RE-POINTS at the recovery file and the close key is read from the document after the save; a dialog stops the sweep and is never answered, with the census taken before EVERY save and EVERY close (a save can raise a prompt of its own, which a per-batch census could not see until the closes had happened); and an UNREADABLE window census is its own outcome — saves proceed, nothing closes, `stoppedBy:"dialogCensusUnknown"`. Ordering is proven from a journal, not from the end state. Every rule is mutation-verified (disable it and exactly one test fails). **No live run yet** — first live use is `swx_close_all_safely` alone | ✗ | ✗ | ✗ | ✗ | ✗ |+| 45 | **Closes its own documents without asking — and loses nothing doing it** (preserve-then-close: every open document written to a recovery folder and verified there BEFORE anything closes) | ✗ | **⚠ 0.7.6 mock-proven, first live close PENDING** — `swx_shutdown {reason}` / `swx_close_all_safely {reason}` save every open document into `…\exports\recovery\<timestamp>\`, verify it, close parents before children, then quit; no write opt-in, no per-document confirmation (Drew, 2026-09-11: *"I despise every time you ask for help closing"*). The authorization is to CLOSE, not to lose anything, so the consent question is replaced by checkable rules: the sweep REFUSES TO START when the recovery volume cannot hold the session it is about to write (`insufficient_headroom` with free/needed/shortfall, nothing written, nothing closed), re-checked before every save, with `headroomBytesBefore` and `estimatedWriteBytes` always reported — because a recovery file can be the RIGHT document CUT SHORT and no check on the file can tell (the marker is at offset 4, so every prefix carries it); the recovery file is verified STRUCTURALLY — it must be a recognised SOLIDWORKS container AND at least as big as the smallest real document of its KIND (part 24 KB, assembly 80 KB, drawing 256 KB — one floor for all three would have to be the lowest of them, letting an assembly stop at a third of its size), with the KIND carried from the COM read to the verdict and NEVER re-derived from the recovery file's name, because that name is chosen from the kind and so cannot check it; an unreadable document type falls back to the document's OWN PATH and then its title (evidence about the document, not names this sweep chose) and only then to UNKNOWN, which takes a neutral `.sldrecover` name and the strictest floor — and if SOLIDWORKS refuses to write that name the file is re-saved as `.SLDPRT` with the fallback RECORDED and the unknown-kind verification unchanged; `swx_recover_list` gives every rescue its own `howToOpen`, because SOLIDWORKS will not open a `.sldrecover` file until it is renamed, published as `recoverySignatureOk` + `recoveryBytes`, and it fails CLOSED (`exists()` passes a zero-byte file and any byte floor passes a truncated one; both are what a full disk leaves). The container marker was MEASURED on 166 real documents from three hardware repositories, because the signature every reference names for a SOLIDWORKS document (OLE compound file) appears in NONE of them — verifying that, as pass 23 specified, would have refused to close every document on a modern install; a document that could not be written is left OPEN and named in `remaining`; the user's saved-then-edited file is copied to recovery under a new name and their original is asserted byte-for-byte unchanged; `SaveAs3` uses `swSaveAsOptions_Silent` ALONE so the document RE-POINTS at the recovery file and the close key is read from the document after the save; a dialog stops the sweep and is never answered, with the census taken before EVERY save and EVERY close (a save can raise a prompt of its own, which a per-batch census could not see until the closes had happened); and an UNREADABLE window census is its own outcome — saves proceed, nothing closes, `stoppedBy:"dialogCensusUnknown"`. Ordering is proven from a journal, not from the end state. Every rule is mutation-verified (disable it and exactly one test fails). **No live run yet** — first live use is `swx_close_all_safely` alone | ✗ | ✗ | ✗ | ✗ | ✗ | *(45 numbered rows; rows 29–31 are the N/A block that accounts for most of the Fusion verb-count gap. Rows 36–42 added 2026-09-08 from the crate build and the launch-resilience rounds; rows 43–45 from the import-leak, quit and safe-close work — the bar is "significantly more powerful than the MCP servers", so every robustness capability gets a row with its evidence level, not a slogan.)*
docs/QUIT-INVESTIGATION.md+9−1@@ -1705,7 +1705,15 @@ carries its own rules, each one checkable and each one mutation-verified: bridge could not detect afterwards is one it declines to cause. - **Nothing closes before it is on disk**, verified per document, and "on disk" is a STRUCTURAL question: the recovery file must be a recognised SOLIDWORKS- container and at least 16 KB (`recoverySignatureOk` and `recoveryBytes` in the+ container and at least as big as the smallest real document of its KIND — part+ 24 KB, assembly 80 KB, drawing 256 KB, and the strictest of those (plus the+ original file's size) when the kind could not be established. The kind is+ carried from the COM read to the verdict, never re-derived from the recovery+ file's name: that name is CHOSEN from the kind, so reading it back checks+ nothing. When `GetType` fails the document's own PATH is consulted, then its+ title — both describe the document rather than repeating this sweep's own+ assumption — and only a pathless document with no extension anywhere is written+ under the neutral `.sldrecover` name (`recoverySignatureOk` and `recoveryBytes` in the reply). `exists()` accepts a zero-byte file and a byte floor accepts a truncated one; both are what a full disk leaves behind. The check fails CLOSED. *Measured, 2026-09-11: of 166 real documents from three hardware repositories,