Skip to content

v0.42.1

Choose a tag to compare

@github-actions github-actions released this 13 Sep 12:35
· 36 commits to master since this release

v0.42.1

Migration / breaking

  • No shared database schema change; the fence stays at 84.
  • Search query embeddings gain a model-family instruction prefix. Instruction-tuned embedding models (Qwen3-Embedding, gte-Qwen instruct, e5 instruct) now receive their published query instruction on ctx_search queries only; stored document vectors are unchanged and no re-embedding runs. Models with a symmetric recipe (nomic-embed-text) gain both prefixes, which rotates their vector identity once and re-embeds locally on the next drain. embedding.query_instruction (string or false) and embedding.document_prefix override the defaults.
  • The Rust module (ck-mc) carries a store migration (53). The module-store guard triggers read a durable privilege row instead of connection-local functions, so doctor, the dashboard, and repair scripts can write guarded tables. An older ck-mc binary opened against a migrated store fails closed on ownership-sensitive note writes; roll the module forward and back only as a matched pair.

Dropped-input guard reachable on OpenCode (#431)

v0.42.0 registered the dropped-input execution guard but the plugin entry never forwarded tool.execute.before to it, so a model that copied a [dropped N] placeholder into a new call could still execute it on OpenCode. The entry now delegates the hook, a source fence keeps the wrapper and the runtime hook set in lockstep, and an end-to-end test drives a placeholder-bearing call through a live OpenCode and asserts it is refused. Pi and OMP were unaffected (their guard registers directly on the event bus). Reported with an exact trace by @Sugaroverdose.

Search precision: instructed query embeddings

ctx_search was sending raw query text to instruction-tuned embedding models with no instruction, which the model cards document as off-recipe. A paired blind-judged study on one project's real query traffic (298 agent queries, one shared label set, order-permutation noise floor reported beside every table) measured production dense precision@10 rising from 0.25 to 0.53 once the Qwen3 instruction was applied, with the plain-encoder control arm byte-identical across runs; the effect concentrates on results that share no vocabulary with the query. That is a single corpus and a single judge, so treat the figure as a measurement, not a general property; the separate effect of phrasing queries as questions (guidance added in v0.42.0) measured about two points and sits under the noise floor, so it is unresolved rather than confirmed.

Compartment embeddings scoped to their own text

Compartments published together from one historian chunk were embedded from the whole chunk's text, so several compartments shared identical vectors and later re-drains flagged them as stale. Each compartment now embeds only its own message range; an unattributable merged line rejects the in-memory chunk and the compartment is rebuilt from the message index. Window numbering is unified (0-based); existing 1-based rows are renumbered in place under the drain lease rather than re-embedded, and status reads stay write-free.

User-facing failure codes and a readable /ctx-status

Every user-visible failure now renders as one calm sentence, one action, and a stable code (MC-H, MC-R, MC-D, MC-E, MC-S, MC-C families); raw provider and exception text goes to the log beside the code. /ctx-status shows a short summary (context, cache lifetime with its source, automatic-compression threshold, history compression, reclaimable outputs, memory, search indexing, warnings) and /ctx-status diagnostics keeps the full dump. Summary and diagnostics render from one snapshot. /ctx-wrapup no longer prints boundary diagnostics into chat, and /ctx-recomp no longer claims to regenerate facts.

Rust module fixes

  • Historian-promoted memories are stamped with their publish time; two seed paths that wrote zero timestamps are fixed and all write sites were audited. A one-off repair script backfills existing zero rows from the module store or the nearest dated neighbour.
  • OpenCode and Pi ingress share one decoded-boundary classifier for nested tool-result content; malformed children fall to opaque with their raw bytes replayed instead of being re-serialized. The representation change rides a per-profile epoch (one priced pass per affected session).
  • Test builds no longer enable a serde_json feature that production does not use, so number-serialization goldens exercise the release serializer; a fence checks the resolved feature graph.

Tests and tooling

  • The slow-historian end-to-end invariant is expressed against the historian's pending window instead of a wall-clock budget.
  • The D5 tail-preservation specimen and redeem-vector fixtures (Claude Code lane) land as test-only fixtures with a total precedence oracle; no runtime behavior ships from them in this release.