@@ -6,6 +6,55 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66
77## [ Unreleased]
88
9+ ## [ 1.1.0] - 2026-07-15
10+
11+ ### Added
12+
13+ - ** ` IMemoryIsolationPolicy ` — a library-wide strict multi-tenant isolation mode (#100 ).** A new central
14+ policy abstraction with three modes via ` MemoryOptions.Isolation.Mode ` : ` SingleTenant ` (default,
15+ today's exact backward-compatible behavior), ` WarnOnUnscoped ` (structured log when a tenant-facing call
16+ resolves unscoped), and ` StrictMultiTenant ` (throws ` MemoryOwnerScopeRequiredException ` before any
17+ Neo4j call when no owner scope is present, instead of silently falling back to global/shared). Wired
18+ into the primary recall/extraction/reasoning Core services and 6 MCP entry points
19+ (` memory_entities ` /` memory_preferences ` /` memory_conversations ` /` memory_context ` /` memory_invalidate ` /
20+ ` memory_supersede ` ). Several other MCP tools that accept a ` userId ` are not yet gated by this toggle —
21+ a disclosed, tracked follow-up, not silently dropped (see ` docs/getting-started.md ` and
22+ ` docs/security/threat-model.md ` TT-01/TT-02 for the exact coverage boundary).
23+ - ** ` MemoryOwnerScopingAgent ` / ` AIAgent.WithMemoryOwnerScoping(...) ` — guaranteed owner scoping across
24+ the complete MAF invocation (#90 ).** Wrapping an agent with ` .WithMemoryOwnerScoping(serviceProvider) `
25+ guarantees the owner scope spans passive recall, the model call, the full tool-calling loop, and
26+ automatic persistence as one unbroken async chain — closing a real gap where ` Neo4jMemoryContextProvider ` 's
27+ own pre-run hook could not, on its own, guarantee a value it set survived into tool calls that run after
28+ it returns (the hook suspends on real I/O, breaking ` AsyncLocal ` propagation). Replaces manually
29+ wrapping every ` agent.RunAsync(...) ` call in ` ownerContext.BeginOwnerScope(userId) ` . Also adds
30+ ` AgentSessionMemoryExtensions.GetMemoryIdentity(...) ` (single-source-of-truth session-identity reader)
31+ and ` IWritableMemoryStoreContext.BeginStoreScope(...) ` (mirrors the existing ` BeginOwnerScope ` ).
32+ - ** A minimal trust boundary for recalled memory rendered into MAF context (#92 , Phase 1 of a larger
33+ issue).** Recalled entities/facts/preferences/reasoning-traces/GraphRAG content is no longer injected as
34+ a raw, unrestricted system message: each block is now delimited and angle-bracket-escaped
35+ (` <recalled_memory category="...">...</recalled_memory> ` ), and the default context prefix explicitly
36+ tells the model this content is untrusted reference data, not instructions to follow. This defeats
37+ boundary forgery specifically; it does not (yet) detect general instruction-like content or cover
38+ recalled conversation history — the full #92 issue (trust metadata, an admission policy, configurable
39+ message roles, instruction-like-content detection) remains open.
40+
41+ ### Fixed
42+
43+ - ** Native MAF recall ignored configured ` RecallOptions ` (#87 ).** ` Neo4jMemoryContextProvider ` built its
44+ ` RecallRequest ` without assigning ` .Options ` , so a customized ` MinSimilarityScore ` , per-section limit,
45+ or ` BlendMode ` had no effect on automatic recall even though it worked correctly for a direct
46+ ` IMemoryService.RecallAsync ` call. Configured retrieval tuning now reaches native recall; a configured
47+ ` RecallOptions.Scope ` is explicitly never allowed to override the invocation's authenticated owner.
48+ - ** Automatic extraction only saw the assistant's response, never the user's request (#89 ).** A turn like
49+ "User: I prefer window seats. / Assistant: Got it." previously only ran extraction over "Got it." — a
50+ user-stated preference was invisible unless the assistant repeated it. Extraction now considers the
51+ complete turn. ` Neo4jChatHistoryProvider ` (which already persisted both request and response messages)
52+ gained full-provenance extraction from both at no new risk. ` Neo4jMemoryContextProvider ` deliberately
53+ does not start persisting request messages as new ` :Message ` nodes (there is no idempotency mechanism to
54+ avoid duplicating what a chat-history provider/store may already persist) — captured facts/preferences
55+ are correct, but their provenance link to the literal source message is best-effort in that path, not
56+ guaranteed; documented, not silently accepted.
57+
958## [ 1.0.3] - 2026-07-14
1059
1160### Fixed
0 commit comments