Skip to content

Make learned words count, boundedly, without a second baseline copy - #30

Merged
enaboapps merged 8 commits into
mainfrom
claude/personal-weight
Oct 12, 2026
Merged

enaboapps merged 8 commits into
mainfrom
claude/personal-weight

Conversation

@enaboapps

@enaboapps enaboapps commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Closes #29

Stacked on #28 (base claude/incremental-learning).

Learned counts were added to a copy of the baseline at 5×. That is negligible beside a baseline of millions of words, so a name or care term typed a few times hardly ever surfaced. A first version of this PR raised the fixed multiplier to 500. Review found real problems with that: one misspelling learned once became the top suggestion, heavy use would outgrow the baseline, and crafted counts could overflow. This version fixes all three:

  • Learned counts are kept separate and combined when predicting. The arithmetic is floating point, so stored counts can't overflow when weighted (huge_stored_personal_counts_do_not_overflow).
  • Bounded weight. One learned occurrence counts as 500 / (1 + learned words / 2000). Learned counts approach a bounded share of the baseline however much is learned.
  • New and rare words need two uses. Learned counts of a word are used once it has been learned twice, unless the baseline has it at least three times. The production baseline holds over 9,000 words seen only once or twice, many of them misspellings, so a single misspelling is never boosted: learning "hav" once doesn't suggest it, and twice does. Words the baseline knows well count from their first use.
  • Less memory. The baseline is no longer copied, so peak predictor memory falls from 362 MiB to 134 MiB, with or without a personal database.
  • Speed. What prediction uses of the learned counts (usable counts, per-context totals and the weight) is updated in place when a sentence is learned, and rebuilt only on reload (updating_in_place_matches_rebuilding). Prediction and learning costs match Make personal learning incremental #28 within noise on the production baseline, measured by the ignored test prediction_cost_on_production_baseline and independently against Make personal learning incremental #28 by review:
    • Without learning: about 5 ms for an empty sentence, about 1 ms after a letter.
    • 2,000 new words learned: 9–15 ms per prediction, 17–23 ms per learn.
    • 40,000 new words (an extreme case): 30–40 ms per prediction, about 190 ms per learn, including a learn that makes a new word usable.
  • Unchanged without learning. With no or an empty personal database, predictions are bit-identical (an_empty_personal_database_predicts_exactly_like_none). The schema and API are unchanged, and existing personal databases keep working. Make personal learning incremental #28's incremental learning now merges into the separate counts, and a reload reloads only the personal counts.

Results

These were measured on a synthetic person, neural/fixtures/personal.json, which is not user data. They learned 44 sentences, four of them containing one misspelling each. The 25 held-out sentences reuse their vocabulary: 445 queries, 78 of them on personal words. Measured on this branch:

Weighting Top six Personal words Misspelling suggested
no learning 50.3% 1.3% 0%
500×, new words at once 61.8% 53.8% 0.2%
this PR 60.4% 46.2% 0%

General English was checked with that person's learning present, on 600 frozen-workload queries: 70.3% with no learning, 70.7% light, 70.2% heavy (×10). The differences are within noise.

Offering learned words to the neural generator as candidates was also tried. It added under half a point and nearly doubled generation latency, so it is left out. Details are in docs/personal-learning.md.

Validation

  • cargo fmt --check, cargo clippy --locked --all-targets -D warnings and cargo test --locked pass.
  • New tests cover: a misspelling learned once not being suggested while a new word used twice is; a well-known word counting at once while a rare one waits; an empty personal database predicting exactly like none; scores bit-identical to the interpolation formula without learning; huge stored counts; and the weight halving at saturation. The ignored prediction_cost_on_production_baseline test gives the timings above. The incremental-versus-reload, trigger, schema and concurrency tests from Make personal learning incremental #28 still pass.
  • python -m unittest passes, and scripts/personal_evaluate.py runs end to end.

🤖 Generated with Claude Code

At 5x, learned counts were negligible beside the baseline: on a synthetic
person, learned words reached the six slots for 16.7% of queries. At 500x
they reach 53.8%, while general English with that learning present is
unchanged (71.0% without learning, 71.5% and 71.3% light and heavy).
Adds the synthetic fixture and evaluator to reproduce this.

Closes #29

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@enaboapps enaboapps added this to the v0.2.2 milestone Oct 12, 2026
Learned counts were added to a copy of the baseline at a fixed weight. A
fixed 500x let one misspelling become the top suggestion, let heavy use
outgrow the baseline, and could overflow on crafted counts. Now:

- learned counts are kept apart and combined when predicting, in floating
  point, so stored counts cannot overflow when weighted;
- one learned occurrence counts as 500 / (1 + learned words / 2000), so
  learned counts approach a bounded share of the baseline;
- a word the baseline lacks is suggested once learned twice;
- the baseline is no longer copied: peak predictor memory falls from
  362 MiB to 134 MiB, with or without a personal database.

With no or an empty personal database, predictions are bit-identical.
On the synthetic person with four misspellings, top six rises from 50.3% to
60.4%, personal words from 1.3% to 46.2%, and no misspelling is suggested.

Refs #29

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@enaboapps enaboapps changed the title Weight learned words 500 times so they are suggested Make learned words count, boundedly, without a second baseline copy Oct 12, 2026
OwenMcGirr and others added 4 commits October 12, 2026 15:52
Prediction was about twice as slow because every candidate and learned entry
was checked on each call. What prediction uses of the learned counts, with
per-context totals and the current weight, is now rebuilt only when they
change: an empty-sentence prediction takes 5.3 ms against 7.5 ms before.

The baseline itself holds thousands of rare misspellings, so learned counts
of a word are used once it is learned twice unless the baseline has it at
least three times. Learning "hav" once no longer suggests it.

Adds an exact bit-for-bit check of the no-learning formula and a timing test.

Refs #29

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebuilding every usable learned count on each learn cost about 350 ms at
40,000 learned words. A learned sentence now adds its usable counts in place,
and a word reaching its second use adds its existing counts in one pass;
counts are whole numbers, so totals equal a full rebuild, which a test checks.
One learn at 40,000 learned words takes 190-270 ms against 180 ms before #30.

The timing test now learns letter-only words, since digits split words, and
the docs state measured costs instead of a claimed speedup.

Refs #29

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The in-place update test now covers words the baseline trusts, an import
and a duplicate import. The timing test also times a learn that makes a new
word usable. Measured against #28 on the same workload, prediction and
learning costs match within noise, so the docs say so.

Refs #29

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #29

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@enaboapps enaboapps mentioned this pull request Oct 12, 2026
Both tests that claimed to cover trusted words passed with the trusted path
disabled, because the word had already been learned once. They now check a
word's first learned use, and fail if trust is ignored.

Refs #29

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
enaboapps pushed a commit to switchifyapp/switchify-pc that referenced this pull request Oct 12, 2026
switchifyapp/switchify-prediction#30 keeps learned counts apart from the
baseline. One learned use counts as up to 500 baseline uses, less as more is
learned, and a word the baseline lacks or has seen fewer than three times
counts once learned twice. On a synthetic person, learned words reach the
suggestions for 46% of queries instead of 1%, with no misspelling suggested.
The library no longer copies the English model, so the prediction worker's
peak memory falls from about 362 MiB to 134 MiB. Worker assets are unchanged.

Refs #1029

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #29

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@enaboapps
enaboapps marked this pull request as ready for review October 12, 2026 16:49
@enaboapps
enaboapps changed the base branch from claude/incremental-learning to main October 12, 2026 17:09
@enaboapps
enaboapps merged commit 31f2f34 into main Oct 12, 2026
15 checks passed
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.

Weight learned words strongly enough to be suggested

2 participants