Vault-wide replace now runs on mobile.
1.2.2 registered the two vault commands behind !Platform.isMobile. The reason was real: the only protection against a runaway pattern is a worker the main thread can terminate, that path had never run anywhere but the desktop, and if a mobile WebView scheduled things differently the failure mode was a hung app.
Three lines of evidence now say it does not.
- Freezing the page mid-scan takes the renderer from 93% of a core to 0% — the worker stops with the timers, not despite them. On thaw the watchdog fires with exactly the remainder of its 2000ms.
- Blink says why.
DedicatedWorker::ContextLifecycleStateChangedforwardskFrozento the worker and deliberately skipskPaused. Backgrounding an app freezes; it does not pause. - The one API shaped like the dangerous case — Android's
WebView.pauseTimers(), which stops only the main thread's scheduler — is unreachable in Obsidian's own APK, by direct call or by reflection.
No run on real hardware. CONTRIBUTING.md carries the full trace and names the result that should put the guard back: a phone that gets warm while backgrounded mid-scan.
Also in this release
The test suite now tests the code that ships. test.ts copies the functions it exercises out of src/, and two copies had fallen behind: preview and execute predated replacement unescaping and the fix for lookaround in the match list, so neither behaviour had ever been covered. Both are now, and npm test fails when a copy drifts (#19).