Memory gains an inbound path: vectr memory import reads existing on-disk
memory files into the store, so adopting vectr no longer starts with retyping
what you had already written down. vectr_unanchor completes the anchor pair
and brings the MCP surface to 23 tools. The rest of the release is retrieval
work, most of it the result of measuring things that had been asserted:
a similarity metric that was reading almost the inverse of the truth on
repetitive code, a dedup key that could not fire on the case it was built for,
and a guard whose rule only worked on same-length renames.
Working memory
vectr memory importbrings existing memory files into the store. vectr
could write memory out and never read it back:vectr memory exportrenders
notes to markdown and nothing parsed that file back, and there was no path in
from anywhere else, so a user arriving with aMEMORY.md,CLAUDE.md,
AGENTS.md,.cursorrulesor copilot-instructions had to retype all of it
one call at a time before the tool had earned any trust. Import discovers
those files, parses at Markdown heading granularity, and writes notes.
--dry-runprints the plan and changes nothing. Re-importing an unchanged
file creates zero notes; an edited section creates a new note without
deleting the old.- Provenance on import is the load-bearing decision, not a detail.
remember()rejectsprovenance='auto'onkind='directive', since an
unreviewed standing rule is a contradiction in terms, and an imported rule is
exactly that pair. Foreign imports therefore land asauto, except imperative
rules classified as directives, which land asagent: the lightest class that
clears the guard without claiming an endorsement nobody gave. The user
promotes after review. Re-importing a file vectr itself exported is a separate
path that preserves the provenance the export recorded. vectr_unanchorremoves anchor paths from an existing note, the inverse of
attach, across REST, MCP dispatch and schemas, and the CLI. It is a plain
update plus one audit call rather than a lifecycle event, because anchors are
delivery-shaping metadata and staleness is re-derived from live hashes on
every check. Idempotent, exact-string match on the path to mirror attach,
ValueErroron empty anchors,Nonefor an unknown note, and an empty list
rather than null when the last anchor goes.- Kind-filtered recall no longer under-fills silently.
_semantic_recall
applied the kind filter after a fixedlimit * 3fetch, so a selective kind
could return fewer thanlimitwith no signal that the shortfall was a pool
artifact rather than an absence of matching notes. The pool widens whenkind
is set, and a metadata-only prefetch backstops the relevance branch, its
survivors appended after the ranked pool. sort_byis one shared vocabulary rather than four. Dead states no longer
count toward the stale-task total.
Retrieval and ranking
-
Near-duplicate dedup compares bodies with the leading docstring stripped. The
near_dup_bodykey existed for the case where two chunks carry different
docstrings over near-verbatim bodies, and it could not reach that case at all:
it compared whole chunks, so the differing docstrings were inside the
comparison and dragged the ratio below the threshold. On the feature's own
witness this moves similarity from 0.765 to 0.958. -
A similarity defect was found underneath that, and it is the more important
finding. Every ratio in this area was computed with difflib's default
autojunk, which excludes any element appearing in more than one percent of a
200-element-or-longer sequence. These are character sequences. Measured:repetitive body, 392 chars 0.166 default 0.995 corrected varied body, 251 chars 0.996 default 0.996 corrected repetitive body, 150 chars 0.993 default 0.993 correctedSo it needs both length and heavy repetition, and on ordinary varied code it
changes nothing. The content it distorts is repetitive text, which is
templated code, which is also the false-collapse hazard for these keys, so the
broken metric had been acting as an accidental guard. -
autojunk=Falseis therefore applied only where it ships no behaviour: the
disablednear_dup_bodykey and its guard. The enabled docstring key keeps
the wrong parameter deliberately, recorded at the call site, because its 0.75
threshold was calibrated through the same distortion and correcting the metric
alone collapses 50 templated accessors into 1 result. -
ranking.near_dup_bodyships disabled pending measurement. The threshold's
safety margin was argued from a single witness pair and does not survive
templated code, where bodies differing only in an index cross it while being
genuinely distinct symbols. -
The templated-body guard is now alignment-independent. The previous rule
walked SequenceMatcher opcodes and rejected any pure insert or delete, so it
only ever worked for same-length renames:nameagainstphoneis four
characters against five, forcing an insert, and the rule rejected the very
shape it existed to catch. It now masks identifier-like tokens and bare
numbers to one placeholder and compares the masked forms. -
Wiring that guard into the enabled docstring key was tried and reverted,
which settles an open question. That key exists because three scripts sharing
a copied docstring crowded out a canonical struct definition, and those three
differ only in an identifier, exactly like the accessor family that must never
collapse. The must-collapse witness and the must-not-collapse hazard are the
same shape, so no rule reading the characters of two bodies separates them.
Correctingautojunkthere needs a signal this layer does not have. -
A relative-cliff sub-signal for the low-confidence banner ships behind a
switch that defaults off, with a distribution harness to calibrate it. The
existing absolute floor was tuned against the previous cross-encoder, so the
swap left the constant stale, and neither raising it nor replacing it with a
rank-1-to-rank-2 test is safe on the evidence that exists.
Symbol graph
- Method-override edges are recorded at index time. A method whose class's base
declares the same name now emits anoverridesedge, reusing the existing
edge type so no schema migration was needed. Only simple-identifier bases
resolve; an attribute-lookup base is skipped rather than guessed, because a
wrong override edge would later push the wrong symbol up.overrides_ofand
overridden_byread it back. - JavaScript and TypeScript produced zero override edges because the extractor
looked upclass_heritageas a field when it is a child node type, so the
lookup always returned nothing. Traversal now scans children, reads the
identifier directly under it for JavaScript, descends through
extends_clausefor TypeScript, and skipsimplements_clause, since an
interface method has no body to override. - Java enum constants and fields are indexed. The impl error check is scoped.
CLI and editor integration
- Command normalisation keeps escaped separators unsplit, pads glued single
pipes, and handles a backgrounding single ampersand. - The README's MCP tool count was wrong in three places including the section
heading whose anchor the badge links to, so the badge pointed at a heading
that no longer existed.
Benchmarks and internals
- The acceptance corpus can run over the MCP surface. It drove REST only, so it
was structurally blind to the two things that decide whether a caller receives
an answer: the low-confidence banner and pointer mode. A case could be scored
passing with the expected symbol at rank 1 while the caller was told to go
grep.low_confidence_absentandbody_presentassertions are meaningful
only on MCP and emit an explicit skip notice under REST rather than passing
silently.--strict-statuscompares each case's recorded label against the
observed outcome and fails on drift, which is how four labels had drifted
unnoticed. - The six-task sprint harness can drive a routed model, so its numbers can be
re-measured on something other than the model they were first taken from.
Results carry a scope stamp naming the model, route, date and revision, an
unparseable metric is recorded as absent rather than zero, and upstream
failures are recorded per task rather than retried away. - New harnesses for the banner threshold distribution and the docstring-key
similarity threshold, plus an inventory of every measurable README claim with
its source and method. - Test isolation fixes: the instance registry is isolated, the dummy embedder is
deterministic rather than salted by hash seed, and a benchmark module rename
ends asys.modulescollision where two test files imported a bareharness
from different directories and whichever was collected first won.