app
SOLIDWORKS Bridge
Public Made by Adomby adom
Launch, model and quit SOLIDWORKS from any Adom container. Nothing is ever lost.
main
Closing, quitting and recovery — swx
Read this before closing any document, quitting SOLIDWORKS, draining leaked imports, or telling the user where their closed work is. Part of the solidworks-bridge skill — SKILL.md beside this folder has the rules that never bend. Trust each verb's own reply (_hint, errorCode) over anything written here.
Closing and quitting: never ask the user to do it
- The bridge never asks you to close.
swx_shutdown {reason}saves every open document into a recovery folder, closes them all, and quits SOLIDWORKS. No write opt-in, no per-document confirmation, no environment flag — the user has already authorized this standingly. It needs a reason, because the reason is written for them. - The safety property is a SEQUENCE, not a question: nothing closes before it is
on disk. Every document — theirs or the bridge's, saved or not — is written to
%LOCALAPPDATA%\adom-solidworks-bridge\recovery\<timestamp>\and verified there before anything is closed. A document that could NOT be written is not closed, and the response names it inremaining. - 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.
- It refuses to start a sweep that will not fit. Before writing anything it
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_headroomwith the numbers, having written and closed NOTHING. Free some space, or pointrecoveryDirat a volume with room. It re-checks before every save, so a disk that fills mid-sweep stops it too — what was already written stays written and nothing is closed.headroomBytesBeforeandestimatedWriteBytesare in every 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 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
recoverySignatureOkandrecoveryBytes. A full disk leaves zero-byte and truncated files thatexists()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",dialogCensusReadable:false,done:false. The work is already safe in the recovery folder; tell the user that, and run it again whenswx_statusshows the session is readable. 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_listshows what every sweep preserved and where, newest first. Tell the user this path when you close their work. CHECKverifiedON EVERY FILE — and notesource:"manifest"is the sweep's own verdict,"reverified"is this bridge re-checking a folder that left no record, whereverified:nullmeans UNKNOWN rather than good.verified:falsemeans the sweep refused to close against those bytes and the document was left OPEN — that work is still in SOLIDWORKS, and telling the user it was rescued would be false. Then FOLLOW EACH FILE'S OWNhowToOpen: most sayswx_open, but a file named.sldrecoveris the rescue of a document whose kind could not be established, and SOLIDWORKS will not open it until it is renamed to.SLDPRT,.SLDASMor.SLDDRW. Never tell the user toswx_openone of those.- A clean, saved document gets no copy — and is still listed. Its own file is
its preservation, so the sweep closes it at its own path and never writes to
that file. Each sweep's
closedInPlacelists those documents withoriginalPath,closed,presentanduntouched(the file measured against what the sweep recorded). When the user asks where such a file went, answer from that entry: "closed at its own path, untouched" is only true whenuntouchedistrue;falsemeans something saved it afterwards, andpresent:falsemeans it is no longer at that path — say which. - Older locations are listed too, and say what can take them. Before 0.9.1
the data lived inside ab's directories: 0.8.x in the bridge cache, which every
bridge update re-extracts (
location:"legacyInstallCache",atRiskFromUpdate:true), and 0.9.0 inAdom Bridge\solidworks-data, which ab's installer and uninstaller own (location:"legacyDataRoot"). Both carryatRisk:true. If a sweep'scopiedTois set, use that copy; if it is null, that folder is the only copy, and the user should hear that before anything updates or reinstalls. In the data root, a file markednotCopiedYetexists only at itslegacyPath(same warning); one markedpartialCopyis an interrupted copy — incomplete, never a rescue — and the file it was copying sayspartialCopyOnly. A filecopiedBeside(<name>.legacy-<stamp>) is a DIFFERENT version ofbesideOfthat an older location held after the first copy;migration.changedSinceCopylists every such change. Check both before relying on either. - The ledger and the ownership registry are MERGED, not picked. When two
versions exist — one in each older location, or one that changed after it was
copied — the live
ledger.jsonlholds every line of both (once each, inatorder) and the liveowned-docs.jsonevery claim of both; both versions are kept beside it andmigration.mergedsays where. Soswx_action_ledgershows every era of history, including a rollback's. A version that could not be merged is undermigration.mergeFailed, kept beside, never dropped. - Three refusals that wrote and closed NOTHING, and are not save problems:
recovery_inside_install_dir(the data root was pointed inside the install directory, ab's own directory, or an older bridge's location),data_root_is_temp(neither LOCALAPPDATA nor USERPROFILE was set, so the data root fell back to the OS temp directory, which Windows empties on a schedule), andrecovery_dir_unwritable(the recovery folder could not be created — permissions, a quota, a file where the folder must go; the reply names the cause once, before any document was saved). Say what the reply says; do not retry until the cause is fixed. host_app_gonemeans SOLIDWORKS died during the sweep — not a dialog, not a disk problem. The reply says how many documents were preserved (each verified) and closed before it went, and quotes the crash markers SOLIDWORKS wrote in its performance log (crashEvidence). Tell the user what was preserved (swx_recover_list), and wait forsolidworks.readyafter they restart it.lockFilesin a listed sweep are SOLIDWORKS'~$lock files: not rescues.- A quit declined on an empty session may be PRIMED. MEASURED 2026-10-01: a
session that has never held a document can decline ExitApp until one has been
opened and closed. Under
userAuthorized, on an empty session with no dialog,swx_stopcreates and closes one bridge-owned scratch part and asks again; the second attempt inrungsTriedsaysprimed:true. Nothing is ever primed while a document is open.swx_status.solidworks.sessionHistoryis ADVISORY — it predicts, it never decides; the prime fires on the declined empty quit itself. - A NOTIFICATION does not stop anything. A window is judged by measured
modality and by its words: it blocks when its title or text names a save,
recovery or import prompt, its owner frame is disabled, or it offers a choice
(a Button control, or two or more captions like Save / Don't Save / Cancel in
any control); a tool window over an enabled frame with nothing to click is a
notification(an owner frame that reads disabled only for an instant is re-read first —ownerDisabledTransiently:true) (kind:"notification",blocking:false) — reported undernotificationswith itsevidence, never answered, and the quit, sweep or import goes ahead. The 3DEXPERIENCE "Connected to …" notice is one (measured 2026-10-01).textIsTemplatePlaceholder:truemeans the captions read were a template's ("Title", "Description", …), not what the window shows — do not quote them to the user as its message. user_is_active— the session is the user's. Every quit and sweep measures presence first (SOLIDWORKS in front with recent input, documents the bridge did not open, or an earlier take-over) and refuses with the evidence underuserPresence. A document is the bridge's only if a bridge verb opened or created it — in a session the user launched, every document is theirs, so a quit or sweep there always needs their explicit say-so. Leave the session alone.swx_user_presencereads the same measurement;userPresentOverride:true(withuserAuthorized:trueand a reason) is only for the user's own explicit request.- Assemblies close first; components go with them. The sweep preserves
every document, then closes assemblies (the active one first) before parts; a
component still held by an open assembly is deferred, and one that went out
with its parent is listed in
closedByParent. A long sweep answers inside ab's budget withdone:false— pollswx_progress(itsdetailhas the stage and counts) and call the sweep again. swx_shutdownis idempotent. SOLIDWORKS not running answerssuccess:true, alreadyStopped:true. It is the last thing you do, and the last thing should be safe to repeat.- What did NOT change.
swx_stopstill quits only a session with zero documents open; the ladder still refuses on a dialog, still measures the exit from the process census, and still never kills anything. The authorization moved the consent question, not the data-safety guarantees.
Quitting, draining and flooded sessions
swx_close_all_documentsaccounts for everything it leaves open. Itsskippedarray names every document still open when it returns, with why — and a document whose dirtiness SOLIDWORKS will not report is treated as UNSAVED, not clean. Reaching this verb at all needs the write opt-in, since it ends the user's session; a refusal closes nothing.swx_stopquits ONLY an empty session, and proves the exit from the process census. It is a measured ladder, pinned at rung (a) (UserControl=false; ExitApp; release every COM reference); rungs (b)-(f) exist and need an explicitmaxRung, and none of them has ever run against a real SOLIDWORKS. Before it tries anything it re-measures seven preconditions, and any one of them coming back UNKNOWN refuses (stop_preconditions_unknown) — an unanswerable question is not permission. The commonest refusal isopen_documents_present: documents open means no, andforcedoes not waive it (forcewaives the UNSAVED question only). Success is this pid with this creation time absent from the census — never whatExitAppreturned — and nothing the bridge owns is disowned until that is true, so a declined quit leaves you still able to save and close your own documents. If a dialog appears the ladder stops permanently and reports it (stop_blocked_by_save_prompt/stop_blocked_by_dialog): this bridge never answers a dialog — show the userswx_state's background screenshot and let them answer. A decline issuccess:falsewitherrorCode:"host_app_stop_declined"and the wholerungsTriedlist. Do not reach forswx_kill: it discards exactly the work the dialog is asking about, and on a Connected edition relaunching takes 1-3 minutes and can fail.expectedSurvivorsAlive(the 3DEXPERIENCE tray daemons,ENOPLMCSAClient,EdmServerV6) is CONSENT, not a leak — never end one. Every precondition is re-measured before EVERY rung, so a multi-rung ladder can refuse in the middle (refusedMidLadder:true) if a document appears while a rung is settling, and it never continues against a different process (stop_identity_changed).- On a flooded session, every list is a SAMPLE and says so. Above the
enumeration cap
swx_docsreturns{count, truncated:true, sample, importTempsInSample, importTempsInSampleOf}and NOdocslist — it walks ten documents, it does not enumerate thousands (doing that killed the com host on a live 2144-document session).swx_close_all_documentson such a session still closes, but reportsclosed/remainingas null with counts, and names the unknown inskipped. Never read a null list as "nothing there". close_outcome_unknownmeans a HUMAN has to look. It is the drain's third outcome: a close reported success, the document is still open, and the count could not be read — so it cannot be told whether nothing closed or something else did. The drain stops. Do not retry it; ask the user what is on their screen, and readcloseFailedfor the path and the count immediately before the close.- A drain that says
done:falseis not finished — readwalkStop. The drain looks at a bounded WINDOW per call (documentsScanned), anddone:truemeans the walk reached the END of the session with nothing left.walkStopisreachedEnd/hitMax/timedOut/iterationFailed, andtitleCollisionsCheckedOversays how many documents the collision check actually covered — a same-titled document beyond the window is not in that list. Call it again untildone:true. - The drain never closes a document whose title another open one shares —
compared the way
CloseDocresolves a name, which on Windows is case-insensitively. If the open set cannot be enumerated it does not attempt the registry sweep at all (ownedUnsavedSweepBlind:true,done:false): it cannot tell whether a title is shared, and a title-only document can only be closed by name. It closes by full path and verifies each close, butCloseDocresolves by name — so a shared title is refused and reported intitleCollisions(with every path that shares it) rather than letting SOLIDWORKS pick. The user decides: close it themselves, or save the other document under another name.done:falsewhile any collision stands. swx_close_import_tempsneeds a resolved%TEMP%, and says so. The drain identifies a temp by its LOCATION under this user's resolved temp directory — that path is the whole proof, because the close does not prompt. A path that merely looks like a temp (a restored profile backup, another user's profile) is not enough, and when%TEMP%cannot be resolved the verb refuses withtemp_root_unknownrather than reporting that it found nothing to close. ReadtempRootandimportTempsElsewherein the reply:closed:0withimportTempsElsewhere:Nmeans N documents look like leaked temporaries but sit under a directory this bridge could not resolve (ab can run under a different profile or a redirected TEMP), so the drain is NOT done —done:false— and the hint says how to point it at the right root.
# Closing, quitting and recovery — swx
Read this before closing any document, quitting SOLIDWORKS, draining leaked imports, or telling the user where their closed work is. Part of the `solidworks-bridge` skill — `SKILL.md` beside this folder has the rules that never bend. Trust each verb's own reply (`_hint`, `errorCode`) over anything written here.
## Closing and quitting: never ask the user to do it
- **The bridge never asks you to close.** `swx_shutdown {reason}` saves every open
document into a recovery folder, closes them all, and quits SOLIDWORKS. No write
opt-in, no per-document confirmation, no environment flag — the user has already
authorized this standingly. It needs a reason, because the reason is written for
them.
- **The safety property is a SEQUENCE, not a question: nothing closes before it is
on disk.** Every document — theirs or the bridge's, saved or not — is written to
`%LOCALAPPDATA%\adom-solidworks-bridge\recovery\<timestamp>\` and verified there before
anything is closed. A document that could NOT be written is not closed, and the
response names it in `remaining`.
- **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.
- **It refuses to start a sweep that will not fit.** Before writing anything it
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
that fills mid-sweep stops it too — what was already written stays written and
nothing is closed. `headroomBytesBefore` and `estimatedWriteBytes` are in every
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 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
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"`,
`dialogCensusReadable:false`, `done:false`. The work is already safe in the
recovery folder; tell the user that, and run it again when `swx_status` shows
the session is readable.
- **`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. **CHECK `verified` ON EVERY
FILE** — and note `source`: `"manifest"` is the sweep's own verdict, `"reverified"`
is this bridge re-checking a folder that left no record, where `verified:null`
means UNKNOWN rather than good. `verified:false` means the sweep refused to close against those bytes and
the document was left OPEN — that work is still in SOLIDWORKS, and telling the
user it was rescued would be false. Then 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.
- **A clean, saved document gets no copy — and is still listed.** Its own file is
its preservation, so the sweep closes it at its own path and never writes to
that file. Each sweep's `closedInPlace` lists those documents with
`originalPath`, `closed`, `present` and `untouched` (the file measured against
what the sweep recorded). When the user asks where such a file went, answer from
that entry: "closed at its own path, untouched" is only true when `untouched` is
`true`; `false` means something saved it afterwards, and `present:false` means it
is no longer at that path — say which.
- **Older locations are listed too, and say what can take them.** Before 0.9.1
the data lived inside ab's directories: 0.8.x in the bridge cache, which every
bridge update re-extracts (`location:"legacyInstallCache"`,
`atRiskFromUpdate:true`), and 0.9.0 in `Adom Bridge\solidworks-data`, which
ab's installer and uninstaller own (`location:"legacyDataRoot"`). Both carry
`atRisk:true`. If a sweep's `copiedTo` is set, use that copy; if it is null,
that folder is the only copy, and the user should hear that before anything
updates or reinstalls. In the data root, a file marked `notCopiedYet` exists
only at its `legacyPath` (same warning); one marked `partialCopy` is an
interrupted copy — incomplete, never a rescue — and the file it was copying
says `partialCopyOnly`. A file `copiedBeside` (`<name>.legacy-<stamp>`) is a
DIFFERENT version of `besideOf` that an older location held after the first
copy; `migration.changedSinceCopy` lists every such change. Check both before
relying on either.
- **The ledger and the ownership registry are MERGED, not picked.** When two
versions exist — one in each older location, or one that changed after it was
copied — the live `ledger.jsonl` holds every line of both (once each, in `at`
order) and the live `owned-docs.json` every claim of both; both versions are
kept beside it and `migration.merged` says where. So `swx_action_ledger`
shows every era of history, including a rollback's. A version that could not
be merged is under `migration.mergeFailed`, kept beside, never dropped.
- **Three refusals that wrote and closed NOTHING, and are not save problems:**
`recovery_inside_install_dir` (the data root was pointed inside the install
directory, ab's own directory, or an older bridge's location),
`data_root_is_temp` (neither LOCALAPPDATA nor USERPROFILE was set, so the data
root fell back to the OS temp directory, which Windows empties on a schedule),
and `recovery_dir_unwritable` (the recovery folder could not be created —
permissions, a quota, a file where the folder must go; the reply names the
cause once, before any document was saved). Say what the reply says; do not
retry until the cause is fixed.
- **`host_app_gone` means SOLIDWORKS died during the sweep** — not a dialog, not a
disk problem. The reply says how many documents were preserved (each verified)
and closed before it went, and quotes the crash markers SOLIDWORKS wrote in its
performance log (`crashEvidence`). Tell the user what was preserved
(`swx_recover_list`), and wait for `solidworks.ready` after they restart it.
`lockFiles` in a listed sweep are SOLIDWORKS' `~$` lock files: not rescues.
- **A quit declined on an empty session may be PRIMED.** MEASURED 2026-10-01: a
session that has never held a document can decline ExitApp until one has been
opened and closed. Under `userAuthorized`, on an empty session with no dialog,
`swx_stop` creates and closes one bridge-owned scratch part and asks again; the
second attempt in `rungsTried` says `primed:true`. Nothing is ever primed while
a document is open. `swx_status.solidworks.sessionHistory` is ADVISORY — it
predicts, it never decides; the prime fires on the declined empty quit itself.
- **A NOTIFICATION does not stop anything.** A window is judged by measured
modality and by its words: it blocks when its title or text names a save,
recovery or import prompt, its owner frame is disabled, or it offers a choice
(a Button control, or two or more captions like Save / Don't Save / Cancel in
any control); a tool window over an enabled frame with nothing to click is a
`notification` (an owner frame that reads disabled only for an instant is
re-read first — `ownerDisabledTransiently:true`) (`kind:"notification"`, `blocking:false`)
— reported under `notifications` with its `evidence`, never answered, and the
quit, sweep or import goes ahead. The 3DEXPERIENCE "Connected to …" notice is
one (measured 2026-10-01). `textIsTemplatePlaceholder:true` means the captions
read were a template's ("Title", "Description", …), not what the window shows —
do not quote them to the user as its message.
- **`user_is_active` — the session is the user's.** Every quit and sweep
measures presence first (SOLIDWORKS in front with recent input, documents the
bridge did not open, or an earlier take-over) and refuses with the evidence
under `userPresence`. A document is the bridge's only if a bridge verb opened
or created it — in a session the user launched, every document is theirs, so
a quit or sweep there always needs their explicit say-so. Leave the session
alone. `swx_user_presence` reads the
same measurement; `userPresentOverride:true` (with `userAuthorized:true` and
a reason) is only for the user's own explicit request.
- **Assemblies close first; components go with them.** The sweep preserves
every document, then closes assemblies (the active one first) before parts; a
component still held by an open assembly is deferred, and one that went out
with its parent is listed in `closedByParent`. A long sweep answers inside
ab's budget with `done:false` — poll `swx_progress` (its `detail` has the
stage and counts) and call the sweep again.
- **`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.
- **What did NOT change.** `swx_stop` still quits only a session with zero
documents open; the ladder still refuses on a dialog, still measures the exit
from the process census, and still never kills anything. The authorization moved
the consent question, not the data-safety guarantees.
## Quitting, draining and flooded sessions
- **`swx_close_all_documents` accounts for everything it leaves open.** Its
`skipped` array names every document still open when it returns, with why —
and a document whose dirtiness SOLIDWORKS will not report is treated as
UNSAVED, not clean. Reaching this verb at all needs the write opt-in, since
it ends the user's session; a refusal closes nothing.
- **`swx_stop` quits ONLY an empty session, and proves the exit from the process
census.** It is a measured ladder, pinned at rung (a) (`UserControl=false;
ExitApp; release every COM reference`); rungs (b)-(f) exist and need an
explicit `maxRung`, and none of them has ever run against a real SOLIDWORKS.
Before it tries anything it re-measures seven preconditions, and **any one of
them coming back UNKNOWN refuses** (`stop_preconditions_unknown`) — an
unanswerable question is not permission. The commonest refusal is
`open_documents_present`: **documents open means no**, and `force` does not
waive it (`force` waives the UNSAVED question only). Success is *this pid with
this creation time absent from the census* — never what `ExitApp` returned —
and nothing the bridge owns is disowned until that is true, so a declined quit
leaves you still able to save and close your own documents. If a dialog
appears the ladder stops permanently and reports it
(`stop_blocked_by_save_prompt` / `stop_blocked_by_dialog`): **this bridge never
answers a dialog** — show the user `swx_state`'s background screenshot and let
them answer. A decline is `success:false` with
`errorCode:"host_app_stop_declined"` and the whole `rungsTried` list. **Do not
reach for `swx_kill`**: it discards exactly the work the dialog is asking
about, and on a Connected edition relaunching takes 1-3 minutes and can fail.
`expectedSurvivorsAlive` (the 3DEXPERIENCE tray daemons, `ENOPLMCSAClient`,
`EdmServerV6`) is CONSENT, not a leak — never end one. Every precondition is
re-measured before EVERY rung, so a multi-rung ladder can refuse in the middle
(`refusedMidLadder:true`) if a document appears while a rung is settling, and it
never continues against a different process (`stop_identity_changed`).
- **On a flooded session, every list is a SAMPLE and says so.** Above the
enumeration cap `swx_docs` returns `{count, truncated:true, sample,
importTempsInSample, importTempsInSampleOf}` and NO `docs` list — it walks ten
documents, it does not enumerate thousands (doing that killed the com host on a
live 2144-document session). `swx_close_all_documents` on such a session still
closes, but reports `closed`/`remaining` as **null** with counts, and names the
unknown in `skipped`. Never read a null list as "nothing there".
- **`close_outcome_unknown` means a HUMAN has to look.** It is the drain's third
outcome: a close reported success, the document is still open, and the count could
not be read — so it cannot be told whether nothing closed or something else did.
The drain stops. Do not retry it; ask the user what is on their screen, and read
`closeFailed` for the path and the count immediately before the close.
- **A drain that says `done:false` is not finished — read `walkStop`.** The drain
looks at a bounded WINDOW per call (`documentsScanned`), and `done:true` means the
walk reached the END of the session with nothing left. `walkStop` is
`reachedEnd` / `hitMax` / `timedOut` / `iterationFailed`, and
`titleCollisionsCheckedOver` says how many documents the collision check actually
covered — a same-titled document beyond the window is not in that list. Call it
again until `done:true`.
- **The drain never closes a document whose title another open one shares** —
compared the way `CloseDoc` resolves a name, which on Windows is
case-insensitively. If the open set cannot be enumerated it does not attempt the
registry sweep at all (`ownedUnsavedSweepBlind:true`, `done:false`): it cannot
tell whether a title is shared, and a title-only document can only be closed by
name. It
closes by full path and verifies each close, but `CloseDoc` resolves by name — so
a shared title is refused and reported in `titleCollisions` (with every path that
shares it) rather than letting SOLIDWORKS pick. The user decides: close it
themselves, or save the other document under another name. `done:false` while any
collision stands.
- **`swx_close_import_temps` needs a resolved `%TEMP%`, and says so.** The drain
identifies a temp by its LOCATION under this user's resolved temp directory —
that path is the whole proof, because the close does not prompt. A path that
merely looks like a temp (a restored profile backup, another user's profile) is
not enough, and when `%TEMP%` cannot be resolved the verb refuses with
`temp_root_unknown` rather than reporting that it found nothing to close. Read
`tempRoot` and `importTempsElsewhere` in the reply: `closed:0` with
`importTempsElsewhere:N` means N documents look like leaked temporaries but sit
under a directory this bridge could not resolve (ab can run under a different
profile or a redirected TEMP), so the drain is NOT done — `done:false` — and the
hint says how to point it at the right root.