v0.10.2 — Fix: run-script hang on OpenDoc6 (Roslyn await bounced across ThreadPool workers)
LatestCloses `FR_runscript_opendoc6_hangs_nonpumping_apartment.md` — a bug that made `run-script` `.csx` deadlock on `swApp.OpenDoc6(diskPath, ...)` (and, by generalisation, on any COM API that invokes callbacks during the call). Reported by the SWFormat project 2026-07-16; reproduced live against SW 2026 rev 34.2.1.
What was wrong
A user `.csx` calling `OpenDoc6` from disk hung forever. The document DID open on SW's side, but the call never returned — combridge sat at zero output until killed. Identical `OpenDoc6` from combridge's own typed plugin commands (`list-configs`, `list-components`) worked cleanly in ~3s. Simple reads from the same `.csx` (`RevisionNumber`, `GetFirstDocument`) also worked fine.
Root cause
`ScriptHost.RunAsync` had:
```csharp
var state = await script.RunAsync(globals);
```
Roslyn's `Script.RunAsync` returns a Task whose continuations follow ambient async dispatch. In a console app with no `SynchronizationContext.Current` (combridge's `Main` has no `[STAThread]` — MTA default), that's `TaskScheduler.Default` → ThreadPool. So the script body was executing on arbitrary ThreadPool workers, NOT the thread that constructed the SolidWorks RCW earlier in `plugin.CreateGlobals(comRoot)`.
`OpenDoc6` is thread-affine — SW's out-of-proc server invokes callbacks back to the calling thread during the call. Wrong thread = callback lost = both sides wait forever. Simple reads worked because they don't callback.
Fix
One-line change: force Roslyn to run synchronously on the caller's thread.
```csharp
var state = script.RunAsync(globals).GetAwaiter().GetResult();
```
Preserves COM thread affinity. `ScriptHost.RunAsync`'s outer signature stays `async Task`.
Who benefits
The fix is in plugin-agnostic Core, so every Windows plugin's `run-script` benefits. Affected COM API family: anything that invokes callbacks or shows UI during the call — `OpenDoc6`, `Save3`, `SaveAs3`, `PrintOut4`, `Workbooks.Open` with progress, `PrintPreview`, etc. Users who saw "combridge works for simple reads but hangs on complex operations from .csx" were likely hitting this silently. VBScript path unaffected (IActiveScript is synchronous by design).
Verified
Same reproducer that hung on v0.10.1 now exits 0 on v0.10.2. All other run-script scenarios (typed globals, `ScriptArgs`/`Stdin` channels, exit-code propagation, VBScript engine) still work.
Lesson
`C:\personal_rag\claude_code\lesson_20260716_roslyn_script_runasync_await_bounces_thread_breaks_com_affinity.md` — generalises the finding so the next .NET tool that hosts Roslyn against COM RCWs doesn't re-derive the same 30-second-timeout diagnostic. Rule: never `await` `script.RunAsync(globals)` when the script may call thread-affine COM APIs.