Skip to content

v0.41.2

Choose a tag to compare

@github-actions github-actions released this 03 Sep 03:36
· 423 commits to master since this release

v0.41.2

Patch release. Two regressions from v0.41.1 and a cache-stability fix that affected every signed-thinking Anthropic session.

Fixed

Embedding drains could freeze the whole process (v0.41.1 regression). The compartment-chunk embedding loader read chunk text through an FTS5 content scan of message_history_fts (the session and ordinal columns were unindexed), synchronously on the main thread. The scan had been there since June; it stayed invisible because the old coverage predicate almost never re-drained old chunks. v0.41.1's honest coverage predicate scheduled a backlog proportional to database size, and on multi-gigabyte databases every session on the shared server stalled. Chunk reads now go through a (session, ordinal) → FTS rowid map and are b-tree point lookups (migration v83; EXPLAIN QUERY PLAN assertions in tests so a scan cannot silently return). Existing rows are mapped by a windowed, resumable background backfill; the drain skips unmapped spans instead of scanning; each sweep embeds at most 8 chunks with yields. Session deletion and the orphan sweep, which used the same scan, are fixed with it.

Repeated "embedding N compartments" notices every turn. The session auto-embed lane announced, hit the project-level backfill's drain lock, and reset its own once-per-process latch, so it repeated every turn for as long as the backfill ran. The auto lane is now a silent bootstrap trigger: no pre-announcement, one notice only when a drain actually embedded something, and the latch survives any terminal outcome. Manual /ctx-embed keeps its explicit replies.

Cache bust on every turn of signed-thinking Anthropic sessions. Magic Context replaces an assistant's step-start/step-finish parts with empty sentinels, and OpenCode serializes an empty text part as " " on signed-reasoning assistants. The trailing-blank strip decision exempted the newest assistant, so its trailing sentinel was served on the first pass of the next turn (where the new assistant shell is still wire-invisible) and stripped on the second — a byte change on a defer pass, once per turn. The cost depended on breakpoint geometry: from ~1k tokens up to a full tail rewrite (88k measured). Strip now applies uniformly, and a persisted strip is absorbing: a harness blank that arrives after first serve is stripped forever, so an assistant's served suffix is monotonic from streaming through history. Same fix on the Rust module.

Reasoning-effort changes on Claude Fable 5.1 no longer bust the prompt cache. Fable 5.1 changes effort per turn without touching the cached prefix, but Magic Context's Anthropic-family rule still flushed pending mutations on any variant change (a 120k-token rewrite per effort flip, measured). The flush predicate is model-aware: on Fable 5.1 a variant change defers; pending work rides the next natural bust.

Claude Fable 5.1 thinking-block binding mismatches recover instead of wedging. Accounts under Fable 5.1's prefix-binding enforcement return a 400 when a thinking block is replayed against a changed prefix; retrying replays the same block and 400s again, permanently. Magic Context classifies that error, strips the dead block on the recovery pass, and the next response mints a freshly bound one. Grandfathered accounts are unaffected.

Curate could archive project memories as "redundant with the user profile". The weekly curate task treated the user profile as deduplication material for project memory and archived rules with no surviving successor (445 across three runs on the development workstation, a third of them high-importance). Curate archives now require a named active successor in the same project and category; user-profile redundancy can never justify archiving a project-scoped memory; directive-shaped rules and >50% content-loss rewrites are refused (as verify already did). Curate no longer sees the user profile. packages/plugin/scripts/restore-curate-archives.ts restores affected memories (dry-run by default) and bumps each project's memory epoch so live sessions pick them up.

Model-change detection could pin the previous model. Late usage updates on the previous assistant interleaved with the new assistant's shell and fired "model changed" three times in 35ms, leaving the live model recorded as the old one — the input to synthetic-user model pinning. Only the newest assistant's events may update it now.

Local embeddings on Intel Macs and other hosts without a native ONNX binding (#404). onnxruntime-node ≥ 1.24 ships no darwin/x64 binding, and the WASM fallback bundle was built for browsers without filesystem access. A Node-target WASM build with real model persistence is selected by runtime host detection (the browser build stays for OpenCode Desktop); /ctx-embed names the classified failure; doctor reports the platform honestly and documents the onnxruntime-node@1.23.0 pin as the native-speed option.

Pi historian failures showed source-context noise instead of the error (#407). The subagent stderr capture kept the first 500 characters of Node's uncaught-exception output, which for a crash inside a minified extension bundle is the source line, never the message. The capture keeps the tail and surfaces the error line and stack frames.

Pi: /ctx-wrapup followed by /ctx-flush produced two cache misses. The flush pass rendered the new compartment but still served the raw messages it covers; the following pass trimmed them — a second full-prefix miss. The busting pass now trims the covered span itself, and when Pi's native compaction marker cannot resolve the first kept entry it falls back to the next resolvable one and logs the skip instead of dropping the marker silently.

Pi: ctx_memory is no longer offered to the model when memory.enabled is false (#410). It is removed from the active tool set at session start from the resolved project config; a config flip takes effect at the next session without restarting Pi.

Windows OMP/Pi could never migrate the shared database (#411). The migration guard's Windows process scan saw only image names, so the session's own omp.exe/pi.exe launcher shim (the parent of the process the plugin runs in) was always counted as an unverifiable live harness, and "restart the blocking process" could never succeed. The guard now reads full process facts on Windows (pid, parent, command line, start time via one CIM query), excludes the session's own ancestor chain on every platform, verifies a harness by its command line rather than a bare image name, and treats image-only matches as inconclusive (migration proceeds with a warning) instead of blocking. Windows also gains a real process start time, so the PID-reuse check from v0.34.1 works there. Thanks to @Qiiks for the complete diagnosis.

OMP hosts without a standalone pi lost every subagent (historian, dreamer, wrapup) since v0.41.1 (#413). The v0.41.1 launcher resolution accepted only a bin.pi manifest entry; @oh-my-pi/pi-coding-agent declares bin.omp, so resolution fell through to spawning a bare pi that does not exist. The resolver now accepts bin.omp as well, with regression fixtures for both layouts. Fix by @Qiiks.

Changed

  • packages/plugin/scripts/analyze-cache-busts.ts derives its verdict from the provider's usage meter (cache read vs. previous total) and keeps the byte diff as attribution, with a LATENCY class for short reads with no divergence. It recognizes the current dump filename layout.
  • Rust module: reclaim hints and Channel-1 copy, mid-turn refusal, and duplicate tool_use guards carried from earlier patch work are included in the rebuilt module.

Upgrade notes

Migration v83 adds message_fts_rowid_map and a backfill watermark; the migration itself does not scan existing rows. Sessions on databases with large histories will see a background backfill run for a while after upgrade; nothing blocks on it. Restart all Magic Context hosts sharing a database together, as usual for a migration.