Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,90 @@ the `mimir-mem` crate, and the on-disk schema move together.

## [Unreleased]
### Added
- **`--confidence certain|likely|unsure` separates how sure the author was
from how often the memory gets used.** `strength` conflated the two: a
guess recalled enough times outranked things that had been checked, with
nothing left to show it was ever uncertain. Confidence is author-declared
at capture, on the same argument `expires_at` and `resolves_when` are
built on — the person writing it is the only one who knows, they know it
at write time, and nobody backfills. A level inferred later by a model
would be exactly the unfalsifiable label this replaces: computed from the
text, so incapable of contradicting it. Absent is a real state and is
**not** a synonym for `likely`; an unparseable level is rejected before
anything is written. Shown in full on `get`, and on the compact recall
line only when `unsure` — that line is what an agent acts from, so the
case worth a token is the one where acting without checking is a mistake.
Does not gate and does not score: the drift-eval baseline is byte-identical.
- **`mimir grounding` — which memories are attached to something Mimir can
re-check, and which of those attachments have broken.** A memory linked
to an indexed artifact (code symbol, source chunk, doc chunk, file) makes
a claim that code can test: the indexer and `graph build` soft-delete
what stops existing, so "this note is about `retry_with_backoff`" becomes
*stale* the moment the symbol goes. Unlike strength, marks or type
priors — all opinions computed from how people treated a claim — this is
the one signal on a memory that Mimir can prove wrong about itself.
Surfaced in `doctor`, in `mimir grounding --stale`, and inline on `get`
(so an agent reading the memory sees it too). Stale does **not** mean
wrong: a note about a renamed function is usually still good. It means
nothing has revisited it since the ground moved, which is why it is
reported and deliberately **not** scored — making grounding a ranking
input is a separate decision that would need the drift-eval baseline
re-cut, not smuggled in behind a display field.
- **`mimir refusals` — an audit trail for the secret guard that is not
itself a pile of secrets.** Refusals now record a blake3 fingerprint of
what was offered, the detector's label, the surface, and first/last seen
with a count — never the value. Repeat offers increment one row rather
than inserting, because one secret offered forty times is an agent in a
loop and forty rows would hide that. `doctor` says so when offers exceed
distinct values. Guarded by a test that sweeps every column of every
table for the plaintext: a record of a leak must never become a second
copy of it.

### Fixed
- **`mimir remember --link <symbol>` now resolves symbol names.** Both the
CLI and MCP advertise "a code symbol or node", but the CLI only ever
called `resolve_ref`, which resolves ids — so linking a memory to
`retry_with_backoff` failed with "no node matching" and the only links
anyone could make by hand were between things they already had ids for.
MCP had the fallback already; the CLI is now at parity. Found while
building grounding, which this is the main path into: shipping it broken
would have repeated the anchors-at-zero-adoption failure exactly.
- **The retrieval eval is now a gate, not just a report.** The hermetic
corpus was committed and deterministic but nothing failed when the
numbers moved: the only assertions were well-formedness checks with an
`MRR > 0.2` floor, and every actual baseline was `#[ignore]`d. Two tests
now run on plain `cargo test` — a committed per-set baseline that must
reproduce **exactly** (in both directions, so an improvement also has to
be written down), and an ablation asserting each scoring knob still beats
its own absence. Verified by zeroing `type_prior_alpha`: previously
green, now two failures naming the metric and the delta.
- Fell out of writing it: **`scoring.code_damp` changes nothing on the
corpus** — same numbers in every category, including the
`code-vs-memory` scenario that exists to guard it, whose single
question ranks the memory first either way. Pinned by a test rather
than papered over, so authoring a fixture that finally exercises the
knob will fail loudly and move it into the ablation where it belongs.

- **`mimir anchor <ref> --pattern ...`** sets guard anchors on an
*existing* memory. `remember --anchor` only covered capture time, which
is why anchor adoption sits at zero in practice: by the time you know
which file a memory guards, the memory already exists. Patterns replace
the existing set.

### Fixed
- **A forgotten memory can no longer come back on its own.** `forget` set a
tombstone, but duplicate detection only ever looked at live nodes — so
offering the same text again created a fresh node with no warning, and
the deletion left nothing behind that could catch it. An importer re-run,
an extractor re-reading an unchanged source, or an agent that saw the
fact twice would each quietly undo the delete. `remember` now refuses
with the date it was forgotten on, and takes `--force` to override; the
MCP tool has no `force` parameter at all, so an agent cannot resurrect
something a human deleted. Matching is by exact normalized hash *and* by
token overlap, because a reword is the common shape of re-extraction.
Decay-archived nodes (`meta.archived`) are deliberately excluded — nobody
decided those, and refusing them would train everyone to pass `--force`
by reflex.
- **The CLI no longer overflows the stack on Windows.** Windows gives the
main thread a 1 MiB stack where Linux and macOS give 8, and clap's
derived builder for Mimir's ~50 subcommands outgrew it in debug builds:
Expand Down
Loading