Skip to content

fix: dictation clean-up survives a cold local model (1.45.1, D-010) - #6

Open
nkeating-cmd wants to merge 2 commits into
mainfrom
fix/cold-cleanup
Open

nkeating-cmd wants to merge 2 commits into
mainfrom
fix/cold-cleanup

Conversation

@nkeating-cmd

Copy link
Copy Markdown
Owner

What

Kōrero 1.45.1: dictation clean-up no longer fails when the local Ollama model has to load first. Decision D-010 (docs/DECISIONS.md), lesson L-014.

  • A local Ollama clean-up is never cancelled for running late. It runs as its own task. A dictation still waits at most 30 s at the cursor (actions::CURSOR_WAIT, unchanged).
    • If the clean-up isn't back by then, the words are pasted as spoken and the pill says Pasted as spoken · clean-up continues.
    • The clean-up finishes in the background and is filed on that dictation's History entry, but only while the entry still holds the same words and has no clean-up. A correction or re-transcription made in the meantime wins.
    • Cloud and custom providers keep their own 30 s client limit and are waited for as before (can_finish_late).
    • History retry and Notes wait for the answer.
  • The model loads while you speak. When a clean-up dictation starts and the Ollama model isn't loaded at all, Kōrero loads it (prewarm_cleanup_model → warm_if_cold). No transcript text is sent. The context leaves room for about 4,000 characters of dictation, so the request reuses that load.
  • Ollama dictation requests may run 300 s (DICTATION_LIMIT, was 30 s). A pre-warm may run 300 s (was 120 s).
  • Logs keep four earlier files (KeepSome(4), about 2.5 MB) instead of deleting the log at each 500 KB rotation.
  • History stores the per-app routed prompt that was actually used.
  • Version 1.45.1; README.

Why

On 23 Oct, two clean-ups on the main laptop failed at 30.1 s (13:47 and 14:17). Ollama's log shows each request gave up while the model was still loading. Kōrero's log shows loaded=None, then "The local model didn't finish its answer within 30 s".

Probe (23 Oct, main laptop) Result
Cold load of gemma4:12b, about 3 GB RAM free 108 s (14–19 s on 19–20 Oct)
A load is in progress and the request waiting on it disconnects Ollama aborts the load, even with another request still waiting, then starts again from zero
A request arrives while a pre-warm is loading at the same context It joins the load: one load, answered 17.6 s after sending
Transcribing a 30 s clip while a cold load runs (two runs each) 2.55–2.86 s alone, 2.77–3.17 s with the load (+0.2–0.3 s)

No fixed limit at the cursor covers every load, and each give-up also threw away the half-loaded model.

Independent review

A separate agent reviewed f5b87a7, briefed to assume it was wrong. It found no Critical, 3 Major and 8 Minor issues. All were fixed in b7000f9 or recorded as accepted costs in D-010.

  • M1: the late path and its pill text also applied to providers that can never finish late. Now Ollama only, and the pill text is true when it shows.
  • M2: a pre-warm sized for the prompt alone made long dictations load the model twice. Now it warms only a cold model, with room for the dictation.
  • M3: the overlap with transcription was unmeasured. It is now measured (above) and accepted.
  • Minor:
    • the pill mentions History only when there is an entry;
    • re-transcribed entries are guarded;
    • whitespace counts as empty, as on the History page;
    • the routed prompt is stored;
    • a misplaced doc comment is fixed;
    • the docs match the code.
  • Accepted, recorded in D-010:
    • late clean-ups are not capped;
    • a cancelled recording leaves the model loaded for its keep-alive;
    • the new pill text is English only, like the other pill notices.

Evidence (main laptop, Windows)

  • cargo check --locked: pass. The two warnings are already on main.
  • cargo test --locked --lib: 292 passed, 0 failed, 9 ignored (live tests). New tests:
    • cleanup_wait_tests (7), including giving_up_at_the_cursor_does_not_cancel_the_clean_up, only_ollama_clean_up_may_finish_late and the_prewarm_leaves_room_for_a_dictation;
    • late_clean_up_fills_only_an_empty_entry;
    • dictation_and_warm_outlive_a_slow_cold_load.
  • Each new check seen failing. Four deliberate breaks, made one at a time in the test run, were each caught by their own test (4 failed, 288 passed). The tree was restored afterwards. The breaks were:
    • letting any provider finish late;
    • dropping the words guard;
    • aborting the task when the cursor wait runs out (the original bug);
    • a pre-warm with no headroom.
  • Live live_cold_dictation_survives_the_cursor_wait (gemma4:12b, starting cold): passed twice, answered 35.0 s and 16.2 s after sending. Each time Ollama loaded once and aborted nothing; the old 30 s limit fails the first.
  • Frontend: bun test unit-tests 104 pass; tsc 0 errors; ESLint 0 errors (17 warnings already on main); Vite build OK.
  • Safe-publish:
    • gitleaks, all refs: 932 commits, no leaks;
    • personal-data scan of 597 added lines and the commit messages: 0 hits;
    • both commits use the noreply address;
    • no dependency change (cargo deny advisories identical to main);
    • line endings: numstat identical with and without --ignore-cr-at-eol.
  • Installed on the main laptop as an unsigned local build of this branch, after a backup. Data files were unchanged by hash, and there were no errors since start.

Bet: fix (not a product bet, so the docs/PRODUCT.md gate doesn't apply).

Not in this PR

  • The custom provider (LM Studio and similar) has neither the late path nor a pre-warm.
  • Slow loads on the main laptop come from memory pressure on the machine: about 3 GB free of 32 GB, and Ollama loads the whole model into RAM because it doesn't memory-map it under CUDA on Windows. That is the machine, not the app.
  • Releasing 1.45.1 (signed build, tag, GitHub release) is a separate ship step after merge.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EXpf5AYj4BYHJqpHxqLNp2

nkeating-cmd and others added 2 commits October 23, 2026 16:24
Clean-up failed whenever the local Ollama model was not loaded and took
over 30 s to load (twice on 23 Oct on the main laptop; one cold load
measured 108 s with 3 GB of RAM free). The 30 s request limit also had
to cover the load, and giving up cancelled the request, which makes
Ollama abort the half-finished load, so every retry started from zero.

- The clean-up runs as its own task. A dictation waits at most 30 s at
  the cursor (unchanged), then pastes the words as spoken, shows
  "Pasted as spoken - see History" on the pill, and lets the clean-up
  finish; the result is filed on the History entry only if it still has
  none. History retry and Notes wait for the answer.
- Dictation requests to Ollama may run 300 s; a pre-warm 300 s (was
  120 s, under the slowest load seen).
- A clean-up dictation starts loading the Ollama model when recording
  starts (no transcript text sent), so the load runs while you speak.
- Log rotation keeps four earlier files instead of deleting the log.
- Version 1.45.1; README, D-010, L-014.

Tests: cleanup_wait_tests (5), late_clean_up_fills_only_an_empty_entry,
dictation_and_warm_outlive_a_slow_cold_load, and a live test
(live_cold_dictation_survives_the_cursor_wait: cold model answered
35.0 s after sending, one load, no abort).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EXpf5AYj4BYHJqpHxqLNp2
An independent review of f5b87a7 found 3 Major and 8 Minor issues.

Major
- M1: only a local Ollama clean-up may finish late. Cloud and custom
  providers have their own 30 s client limit, so a late result could
  never arrive; they are waited for as before (can_finish_late). The
  pill now says "Pasted as spoken - clean-up continues", which is true
  when it shows.
- M2: the pre-warm loads only a model that is not loaded at all
  (warm_if_cold), at a context with room for about 4,000 characters of
  dictation (PREWARM_TRANSCRIPT_CHARS), so the request reuses that load
  instead of loading the model a second time.
- M3: measured, not assumed. With about 3 GB RAM free, a cold load
  running alongside slowed transcribing a 30 s clip by 0.2-0.3 s
  (2.55-2.86 s alone, 2.77-3.17 s with the load; two runs each).
  Recorded in D-010 as an accepted cost.

Minor
- The pill mentions the late clean-up only when there is a History
  entry for it to land on.
- A late result is filed only while the entry still holds the words it
  cleaned (a Retry may have re-transcribed it), and whitespace-only
  clean-ups count as empty, as they do on the History page.
- History stores the per-app routed prompt that was actually used.
- Doc comment restored to update_post_processed_text.
- README and D-010 say what the code does (Ollama only).

Tests: 292 passed; only_ollama_clean_up_may_finish_late,
the_prewarm_leaves_room_for_a_dictation, and a re-transcribed-entry
case in late_clean_up_fills_only_an_empty_entry. Live cold test:
answered 16.2 s after sending, one load.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EXpf5AYj4BYHJqpHxqLNp2
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