← Commit history

docs: 0.7.2 — recovery file verified by the measured SOLIDWORKS marker (not CFBF) + 16 KB floor; census between every save and close; 24 adversary passes

Drew Owens ·ac56d2da45 ·1mo ago ·parent 40a1231
4 files changed +67−18
README.md+38−5
@@ -292,10 +292,27 @@ too. Because every document is clean by the time a close happens, a save prompt cannot appear; if any dialog does appear, the sweep stops and reports it rather than answering it. -"On disk" is measured in **bytes**, not existence. A full disk leaves a zero-byte-file behind and `exists()` says yes to it, so each recovery write is checked-against a minimum size and the size is published per document as `recoveryBytes`.-A file that holds nothing is not a save, and the document stays open.+"On disk" is checked **structurally**, not by existence and not by size alone. A+full disk leaves a zero-byte file behind and `exists()` says yes to it; it also+leaves truncated ones, which any byte floor admits. So each recovery file is+verified to *be* a SOLIDWORKS document — the container marker at the head of the+file — and then to be at least 16 KB. The reply publishes both,+`recoverySignatureOk` and `recoveryBytes`, per document. The check **fails+closed**: anything unreadable or unrecognised leaves the document open.++What the container marker is was **measured, not looked up**. 166 real+`.SLDPRT`/`.SLDASM`/`.SLDDRW` files from three hardware repositories: **none**+begins with the OLE compound-document signature every reference names for+SOLIDWORKS, and **all 166** carry `00 00 00 04` at offset 4. Modern SOLIDWORKS is+not a compound file. Both are accepted — an older document from an archive really+is one — and the real headers are pinned in the suite, because a check on a format+this bridge does not own is only as good as its samples.++The dialog census runs **before every save and before every close**, not once per+batch. A save can raise a prompt of its own (a missing external reference, a+rebuild question), and under a per-batch check a dialog raised by the first save+stayed invisible until every other document had already been closed. `batch` is+now only a bound on round trips and wall time.  The dialog check has a third answer besides *yes* and *no*: **unknown**. If the window census cannot be read, this bridge cannot say whether a prompt is on@@ -404,7 +421,23 @@ not.  ## Roadmap -- v0.7.1 (this): **the close sweep, adversary-hardened.** Four things stood+- v0.7.2 (this): **the format check, measured.** Pass 23 asked for the recovery+  file to be verified against the OLE compound-document signature+  `D0 CF 11 E0 A1 B1 1A E1` — the answer every reference gives for what a SLDPRT+  is. Measured against 166 real documents from three hardware repositories on this+  machine: **zero** of them begin with it, and it appears nowhere in the first+  4 MB of any of them; **all 166** carry `00 00 00 04` at offset 4. Shipping the+  signature as specified would have rejected every document on a modern install —+  failing closed, so nothing lost, and the sweep would have preserved everything+  and closed nothing for ever, which is the feature. The check now accepts either+  container, fails closed on anything else, and is pinned by real captured+  headers; the byte floor rises from 1 KB to 16 KB, below the smallest real+  document observed (a 29,130-byte part) and far above what a failed write leaves.+  The dialog census also moved from once per batch to before every save and before+  every close, because a save can raise a prompt of its own and a per-batch check+  could not see it until the closes had already happened; the host now does one+  document per call and `batch` is only a round-trip bound. 324 tests.+- v0.7.1: **the close sweep, adversary-hardened.** Four things stood   between "nothing is lost" and a claim anyone could check. The recovery write is   now verified by SIZE through a constant both backends share, and the size is   published as `recoveryBytes` — a zero-byte file is what a full disk produces and
SKILL.md+13−7
@@ -29,13 +29,19 @@ adom-bridge --ai-thread "<your thread>" swx_bom '{"path":"C:\\designs\\gearbox.s - **The user's own files are never written over.** A document they had saved and   then edited is copied into recovery under a new name; their file on disk is   untouched and their unsaved changes still survive.-- **"On disk" is measured in bytes.** Each recovery file is checked against a-  minimum size and the size is reported per document as `recoveryBytes`. A full-  disk leaves a zero-byte file that `exists()` accepts; that is not a save, and-  the document stays open.-- **A save prompt cannot appear**, because nothing is unsaved by the time a close-  happens. If ANY dialog appears the sweep stops, reports it in `stoppedByDialog`,-  and closes nothing further. It is never answered.+- **"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;+  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+  CLOSED — anything unrecognised leaves the document open rather than closing it+  against a file nobody can vouch for.+- **A save prompt cannot appear** for the reason a close would raise one, because+  nothing is unsaved by the time a close happens. But a SAVE can raise one of its+  own (a missing external reference, a rebuild question), so the window census+  runs before EVERY save and before EVERY close. If ANY dialog appears the sweep+  stops where it is, reports it in `stoppedByDialog`, and does nothing further.+  It is never answered. Everything already written stays written. - **If the window census cannot be READ, nothing closes.** Unknown is not "no   dialog". The saves still run — saving loses nothing — but no document is closed   and the reply carries `stoppedBy:"dialogCensusUnknown"`,
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.1 mock-proven, NOT RUN LIVE** — `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 recovery write is verified by SIZE against a shared constant and published as `recoveryBytes` (a zero-byte file is what a full disk leaves and `exists()` passes it); 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; 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.2 mock-proven, NOT RUN LIVE** — `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 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 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+15−5
@@ -1698,8 +1698,15 @@ The consent question moves; the data-safety guarantees do not. The new sequence carries its own rules, each one checkable and each one mutation-verified:  - **Nothing closes before it is on disk**, verified per document, and "on disk" is-  measured in BYTES against a shared constant (`recoveryBytes` in the reply) — a-  zero-byte file is what a full disk leaves behind and `exists()` accepts it.+  a STRUCTURAL question: the recovery file must be a recognised SOLIDWORKS+  container and at least 16 KB (`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,+  NONE begins with the OLE compound-document signature the references name for+  SOLIDWORKS, and all 166 carry `00 00 00 04` at offset 4. Verifying CFBF as+  originally 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 own file is never written over.** `SaveAs3` with   `swSaveAsOptions_Silent` ALONE re-points the document at the recovery file, so@@ -1707,9 +1714,12 @@ carries its own rules, each one checkable and each one mutation-verified:   recovery path. - **Parents close before children**, because a component cannot close while its   assembly holds it — proven from an ordering journal, not from the end state.-- **A dialog stops the sweep and is never answered** (§5.6's rule, unchanged), and-  a dialog census that cannot be READ is its own outcome: saves proceed, nothing-  closes, `stoppedBy:"dialogCensusUnknown"`. UNKNOWN still refuses.+- **A dialog stops the sweep and is never answered** (§5.6's rule, unchanged),+  and the census is taken before EVERY save and before EVERY close — a save can+  raise a prompt of its own, and a per-batch census could not see it until the+  closes had already happened. A dialog census that cannot be READ is its own+  outcome: saves proceed, nothing closes, `stoppedBy:"dialogCensusUnknown"`.+  UNKNOWN still refuses.  Under `userAuthorized:true` the ladder also no longer requires a launch attribution — the user may quit a session this bridge did not start — and the