Repository navigation
v1.5.1 — Trust Boundaries
Trust-boundaries hardening release. No new features; every change tightens an
existing guarantee.
Fixed
- Project isolation enforced end-to-end.
memory_readpreviously returned
project-scoped entries of ALL projects (no directory filter); theproject
inspector view listed other projects' entries;memory_clear(scope="project")
deleted every project's memories, not just the current project's;
memory_update/memory_forget/ feedback tools could mutate another
project's entries by id or text match. All lookups now go through a single
visibility policy (readableEntries/readQuery/clearProjectEntriesin
core.ts): global + current project only. Regression-tested with two
distinct directories plus global entries. - DREAM cross-project contamination. Consolidation dedup searched the whole
store: a fact extracted in project A could refresh/rewrite project B's
dreamed entry, be suppressed by B's explicit entry via similarity or topic
clash, or update/supersede/flag entries it was never shown. All consolidation
lookups are now restricted to the consolidating session's visible set. memory_writerewrite targeting. A write with an explicit scope could
overwrite a semantically similar entry from a DIFFERENT scope/project;
rewrite-dedup is now same-scope + same-project only (global and equivalent
project facts coexist by design).- Relevance gate silently defeated. The word "user" (and "utente") was not
in the retrieval stopword list while nearly every stored fact contains it, so
any query mentioning "user" matched every entry and the keyword relevance
gate introduced in 1.5.0 never actually gated anything. Found by the new
falsifiable benchmark (negative-query FP rate dropped from 76.3% to 39.5%
after the fix, Recall unchanged at 100%).
Changed
- Surfacing no longer refreshes recency. Automatic exposure used to bump
lastSeen, letting frequently surfaced memories stay artificially fresh
(a self-reinforcing retrieval loop, immortal under pruning). Exposure is now
recorded separately (lastSurfaced,surfacedCount) and never affects the
score; only explicit confirmation (memory_useful, writes,
consolidation refreshes) resets decay. Negative feedback never touches
recency. - Semantic reranker can abstain. With
OPENCODE_MEMORY_RERANK=1the
reranker may answer{"order":[]}when no candidate answers the question;
abstention surfaces nothing beyond the core slot instead of forcing a
ranking. Unparseable output still falls back to the deterministic lexical
order. Rerank orphan children are now garbage-collected like consolidation
ones. - Falsifiable benchmark.
bench/run.tsrewritten around a pure harness:
the old "false-surface rate" counted unsupported surfacing AFTER the keyword
gate had already filtered those entries (0.0% by construction). The suite now
has 38 negative scenarios across six categories that can genuinely fail
(clean no-match, hard lexical negatives, semantic distractors, cross-language
collisions, project-isolation negatives, core-only queries) and reports
separately candidate quality (Recall@5, MRR), surface precision, false-
positive / abstention rate and context overhead. Positive scenarios are
unchanged.
Security
- DREAM child sessions run with zero tools. The headless consolidation,
semantic-dedup and rerank sessions previously disabled only the five memory
tools by name — shell, filesystem, network fetch, MCP and subagent tools
remained available to a session processing untrusted conversation text.
They are now created with a single wildcard denial (tools: {"*": false}),
verified against OpenCode server source v1.18.0–v1.18.20 to remove the
entire toolset from the model-visible request (allow-none). Crash recovery,
orphan GC and at-least-once semantics are unchanged. A contract test pins
the deny-all shape so per-tool enumerations cannot creep back. - Honest
local-onlyprivacy contract. The previous claim "never leave
the machine" was not enforceable:memory_readreturned local-only entries
as tool output (which reaches the provider), and the DREAM dedup prompt
included them among existing entries. Local-only entries are now excluded
from EVERY model-visible path: SURFACE injection, DREAM entries and dedup
prompts, rerank candidates, all tool responses (memory_read,
memory_why,memory_inspect) and all mutating tools. The documented
access path is direct human inspection ofOPENCODE_MEMORY_DIR; remaining
limitations (the write call itself, prior transcript exposure, summary
generation by the provider) are documented in the README threat model.