What review found:
- A worker let go (unload) finishes a load under way before it releases its
model and device, but it counted as gone at once: the listener could load
beside it (two models at once on an iPad), and a new download's check
could start a second copy. abbrev.js now keeps every worker let go until
it says it has given its memory back ("stopping"); gpu_busy() counts it;
a new worker starts only after it; make_room() waits for it before the
helper loads; and the listener (and first letters, for the helper and the
listener) lets the other go only once a load under way has finished.
- The listener's and first letters' first-run checks each waited for the
other's CHECKING: two downloads finishing together waited for ever. A
check now waits only for a check that holds the chip (other_check, the
rule the helper already followed); a request still says the other is busy.
- The worker watches device.lost and tells the page, which lets it go; any
error but "superseded" lets the worker go; the first-run check lets the
model go whatever its result.
- Removing one feature no longer deletes the shared runtime while the other
is downloading it (each counts the other's download as using it).
- What is typed is folded as a keyboard types it (NFKC in the browser,
curly quotes straight), in letters() and in the worker.
- Credits carry a link to where each piece is published.
Co-Authored-By: Claude Opus 5.5 <[email protected]>