Skip to content

fix(memory): the stress dictionary loads on first use instead of at every boot - #965

Merged
alex-mextner merged 1 commit into
mainfrom
lazy-stress-dict-20261104
Nov 4, 2026
Merged

alex-mextner merged 1 commit into
mainfrom
lazy-stress-dict-20261104

Conversation

@alex-mextner

Copy link
Copy Markdown
Owner

What this changes

The bot used to parse the 555,461-entry Russian stress dictionary (data/dictionaries/stress-dict.json, 27 MB) at every start. Production never speaks Russian through Silero (SILERO_PYTHON_PATH is unset) and the MTProto service tier is off, so the only reader there is the lookup_stress AI tool. In a bare bun process that parse takes RSS from 51 MB to 362 MB at the peak and leaves 190 MB, on a 1 GiB container that shares an overcommitted, swapping 3.7 GB odroid.

Now StressDictionary.lazyFromFile registers the file and ensureLoaded() reads it once (concurrent callers share one load). lookup_stress, the voice reply, the settings voice route and the voice-call TTS await it before marking stress; an unloaded dictionary throws instead of reporting every word unknown. With SILERO_PYTHON_PATH set the file is still read at startup, so an unreadable file keeps Silero off as before. A missing file leaves the dictionary absent at startup, as before.

The runbook (Deploy, resource limits) now records what was measured about the container's memory: a fresh container is flat at 449-461 MiB over 16 minutes, the module-load footprint is identical on ff93220 and e4185dd, and the 138-163 MiB seen on the old container was the host swapping its idle part out.

Refs #800, #963

Evidence

Review

Single-seat Opus via omp (review diff --staged --task 963 --pool 1 -m omp:anthropic/claude-opus-5-5), two rounds. Round 1 found a request-time load stall when Silero is configured, an unstressed-Silero case when the file cannot be parsed, a stale README and a missing Silero-path test: all fixed. Round 2 found no actionable bug. The version was moved from 0.3.5 to 0.3.4 after round 2 (two lines, accepted by the commit gate's trivial-delta rule). This is a single-seat review; the full-roster pass is owed in #961.

…ead of at every boot (Refs #800, #963)

Production parsed data/dictionaries/stress-dict.json at every start although it never speaks
Russian through Silero (SILERO_PYTHON_PATH unset) and the MTProto service tier is off: in a bare bun
process that file takes RSS from 51 MB to 362 MB at the peak and leaves 190 MB, on a container that
shares an overcommitted, swapping 3.7 GB odroid. StressDictionary.lazyFromFile registers the file
and ensureLoaded() reads it once, shared by concurrent callers; lookup_stress, the voice reply, the
settings voice route and the voice-call TTS await it before marking stress, and an unloaded
dictionary throws instead of reporting every word unknown. With SILERO_PYTHON_PATH set the file is
read at startup as before, so an unreadable file keeps Silero off. The runbook records the measured
steady state of the container (flat at 449-461 MiB, not a leak, same module-load footprint on
ff93220 and e4185dd).

Review: single-seat Opus via omp (two rounds; round 1 found the Silero request-time stall, the
unstressed-Silero case, a stale README and a missing Silero-path test, all fixed; round 2 none).
This is a single-seat review: the full-roster pass is owed in #961.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant