memorix 1.4.1 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,434 @@
1
+ # Memorix 1.4.2: Evidence-Governed Memory and CodeGraph
2
+
3
+ Status: implementation complete; release verification recorded in v1.4.2
4
+ Branch: `codex/1.4.2-evidence-governor`
5
+ Baseline: `v1.4.1`
6
+ Updated: 2026-08-06
7
+
8
+ ## One-Sentence Product Contract
9
+
10
+ Memorix should give an agent the smallest useful set of **current, source-backed
11
+ project knowledge**, and should say "do not use memory here" when it cannot
12
+ justify a useful answer.
13
+
14
+ This is not a new prompt wrapper or a second knowledge store. It is the policy
15
+ layer that unifies existing observations, claims, workflows, CodeGraph evidence,
16
+ Git state, and verification results before they reach an agent.
17
+
18
+ ## Why This Release Exists
19
+
20
+ The product already has much of the necessary foundation:
21
+
22
+ - source-backed claims and code-reference freshness;
23
+ - versioned CodeGraph snapshots and bounded Worksets;
24
+ - retention, archive, workflow, and background-maintenance primitives;
25
+ - project context through MCP and CLI.
26
+
27
+ Those pieces currently answer related questions in different modules. A memory
28
+ can be relevant but old, source-backed but never verified, or compact but still
29
+ harmful for the current task. 1.4.2 makes the final decision explicit,
30
+ consistent, inspectable, and shared by CLI, MCP, hooks, and dashboard surfaces.
31
+
32
+ ## Research Constraints
33
+
34
+ This release follows published findings without overstating what they prove.
35
+
36
+ 1. Similar retrieved experiences can cause agents to imitate prior outputs,
37
+ including wrong or misaligned ones. Memory quality and deletion policy are
38
+ product safety concerns, not cleanup cosmetics.
39
+ 2. Long-horizon memory needs indexing, retrieval, reading, temporal updates,
40
+ and abstention. Retrieval quality alone is not enough.
41
+ 3. Dynamic note links and hierarchical storage are useful only when the source,
42
+ freshness, and revision path remain visible.
43
+ 4. Persistent memory is a privacy boundary. Retrieval must preserve scope,
44
+ visibility, and provenance instead of treating all stored text as promptable.
45
+
46
+ The primary research references are listed at the end of this document. Recent
47
+ 2026 preprints may guide investigation but do not become product truth without
48
+ reproducible local tests.
49
+
50
+ ## Terms
51
+
52
+ | Term | Meaning |
53
+ | --- | --- |
54
+ | Candidate | Any possible context item: observation, claim, workflow, code fact, Git fact, test result, or wiki page. |
55
+ | Evidence | A source that can be checked later: file/symbol hash, CodeGraph snapshot, commit, test/run result, document, or explicit user action. |
56
+ | Qualification | The deterministic check that decides whether a candidate is current enough, visible to this caller, and safe enough to use. |
57
+ | Context plan | The bounded answer to: inject nothing, inject a compact card, inject selected evidence, or schedule more work. |
58
+ | Outcome signal | A later, auditable fact such as a focused test passing, a claim being corrected, or a memory helping a verified task. |
59
+ | Observation period | The period after capture before a memory is promoted to trusted reusable knowledge. |
60
+
61
+ ## Non-Negotiable Invariants
62
+
63
+ 1. **No automatic context dump.** Existing memory is not a reason to inject it.
64
+ 2. **No silent truth rewrite.** A model may propose a link, summary, or
65
+ promotion; it cannot overwrite evidence-backed claims without an auditable
66
+ transition.
67
+ 3. **No model-only authority.** Test, Git, code, and explicit user signals outrank
68
+ a generated confidence score.
69
+ 4. **No new default MCP tool explosion.** `memorix_project_context` remains the
70
+ primary agent surface. Advanced diagnostics stay grouped and opt-in.
71
+ 5. **CLI and MCP parity.** Both construct the same context plan from the same
72
+ policy. Hooks only trigger the plan; they do not own a separate policy.
73
+ 6. **Foreground stays fast.** Context assembly may schedule refresh or analysis,
74
+ but never waits for a corpus scan, remote provider, or LLM synthesis.
75
+ 7. **Code facts are versioned.** A narrative cannot claim that code is current
76
+ without a matching snapshot or an explicit caution.
77
+ 8. **Scope is enforced before relevance.** Personal, project, team, and public
78
+ knowledge do not mix merely because embeddings are similar.
79
+
80
+ ## Target Architecture
81
+
82
+ ```text
83
+ observations / claims / workflows / wiki / Git / tests / CodeGraph
84
+ |
85
+ v
86
+ candidate collection
87
+ |
88
+ v
89
+ evidence qualification gate
90
+ scope -> provenance -> freshness -> conflict -> quality
91
+ |
92
+ v
93
+ budgeted context planner
94
+ abstain | compact card | selected detail
95
+ |
96
+ v
97
+ MCP / CLI / hook / dashboard explain view
98
+ |
99
+ v
100
+ verified outcomes feed lifecycle and CodeGraph links
101
+ ```
102
+
103
+ The governor is deliberately a pure, deterministic core. Storage adapters and
104
+ renderers call it; it does not import an MCP server, hook implementation, or UI.
105
+
106
+ ## Data Contracts
107
+
108
+ ### 1. Context Candidate
109
+
110
+ ```text
111
+ ContextCandidate
112
+ id, kind, projectId, scope, visibility
113
+ title, compactText, sourceRefs
114
+ capturedAt, observedAt
115
+ freshness current | suspect | stale | unknown
116
+ conflict none | possible | confirmed
117
+ quality probation | verified | degraded | blocked
118
+ relevanceSignals lexical, semantic, task-lens, code-link
119
+ estimatedTokens
120
+ ```
121
+
122
+ Existing records are adapted into candidates. This is not a duplicated store.
123
+
124
+ ### 2. Qualification Result
125
+
126
+ ```text
127
+ QualificationResult
128
+ candidateId
129
+ disposition include | compact | defer | exclude
130
+ reasons[] stable machine-readable reason codes
131
+ evidenceSummary[] source type, id, snapshot/revision, locator
132
+ qualitySignals[] verified test, successful reuse, user pin, correction
133
+ freshness
134
+ tokenCost
135
+ ```
136
+
137
+ An excluded item is visible in diagnostics only. It is never silently presented
138
+ as if it had not existed.
139
+
140
+ ### 3. Context Plan
141
+
142
+ ```text
143
+ ContextPlan
144
+ task, taskLens, projectState
145
+ mode abstain | card | workset
146
+ selected[] QualificationResult
147
+ deferred[] bounded follow-up suggestions
148
+ cautions[]
149
+ budget requested, used, remaining
150
+ scheduledMaintenance[]
151
+ explanationId
152
+ ```
153
+
154
+ `abstain` is a successful result. It means Memorix did not find sufficiently
155
+ qualified context and recommends normal repository inspection instead.
156
+
157
+ ### 4. Outcome Signal
158
+
159
+ ```text
160
+ MemoryOutcomeSignal
161
+ id, candidateId, projectId, kind
162
+ kind test-pass | test-fail | verified-reuse |
163
+ user-pin | user-correction | source-changed |
164
+ conflict-confirmed | manual-review
165
+ sourceRef, snapshotId, observedAt
166
+ detail sanitized, bounded explanation
167
+ ```
168
+
169
+ Outcome signals are append-only audit facts. They update a derived quality
170
+ state; they do not erase the original memory. A generic manual review is
171
+ auditable but does not by itself raise quality: verification or an explicit
172
+ user pin is still required.
173
+
174
+ ## Lifecycle Policy
175
+
176
+ 1. **Capture:** new observations remain usable as local session material but are
177
+ labelled `probation` for durable retrieval.
178
+ 2. **Qualify:** source and scope are checked. Code-bound items are matched to a
179
+ snapshot; unbound assertions remain lower confidence.
180
+ 3. **Promote:** explicit user pin, review approval, successful verified reuse,
181
+ or source-backed test/Git evidence can promote a candidate.
182
+ 4. **Degrade:** changed/deleted source, failing verification, contradiction, or
183
+ a user correction downgrades the derived quality state.
184
+ 5. **Archive:** retention rules continue to govern cleanup, but archive decisions
185
+ consume this shared state instead of copying their own freshness formula.
186
+ 6. **Recover:** an archived fact can be revisited with its original evidence;
187
+ archive never means invisible deletion by default.
188
+
189
+ No score alone can cause destructive deletion. A score can only suggest a
190
+ review or make a candidate ineligible for automatic injection.
191
+
192
+ ## CodeGraph Upgrade
193
+
194
+ ### Product Goal
195
+
196
+ CodeGraph becomes the code evidence service for the governor. It should answer
197
+ four practical questions quickly:
198
+
199
+ 1. What files and symbols are relevant to this task now?
200
+ 2. What changed since this memory or workflow was formed?
201
+ 3. What may be affected if this symbol or file changes?
202
+ 4. How complete and trustworthy is that structural answer?
203
+
204
+ ### New Capabilities
205
+
206
+ #### A. Snapshot Diff
207
+
208
+ The first 1.4.2 slice adds a hash-only **file** manifest to each completed
209
+ snapshot. It can report added, modified, and removed indexed files between two
210
+ complete snapshots. It stores paths and hashes, never a second copy of source.
211
+
212
+ Symbol and relation history are not yet retained per snapshot, so this release
213
+ does **not** pretend to provide historical symbol/edge diffs. Current graph
214
+ relations are used only for the bounded impact slice below.
215
+
216
+ Target shape for later schema evolution:
217
+
218
+ ```text
219
+ CodeStateDiff
220
+ fromSnapshotId, toSnapshotId
221
+ added/changed/removed files
222
+ added/changed/removed symbols
223
+ added/changed/removed relations
224
+ completeness delta
225
+ affected observation/claim/workflow references
226
+ ```
227
+
228
+ This must report unknowns from incomplete scans. It is not allowed to label an
229
+ unscanned path as unchanged.
230
+
231
+ #### B. Impact Slice
232
+
233
+ Given a file or symbol, return a bounded, explainable graph slice:
234
+
235
+ ```text
236
+ ImpactSlice
237
+ root references
238
+ inbound and outbound relations
239
+ direct test/config/workflow references when available
240
+ confidence, coverage, traversal limit, and reasons
241
+ ```
242
+
243
+ The first release supports direct edges and a small bounded traversal only. It
244
+ does not claim whole-program call-graph precision.
245
+
246
+ #### Implemented Slice
247
+
248
+ - `memorix codegraph diff` compares the newest two snapshots by default, or
249
+ accepts explicit `--from` and `--to` snapshot ids.
250
+ - `memorix codegraph impact --path <relative-source-path>` exposes the same
251
+ bounded current one-hop graph slice to CLI-only agents. It rejects paths that
252
+ are not in the current index instead of reporting a misleading empty result.
253
+ - A diff is refused when either snapshot is incomplete or predates the manifest
254
+ schema. The result explains why instead of treating absent data as unchanged.
255
+ - The impact view resolves both file edges and symbol edges to current files,
256
+ follows only one hop, and caps relation traversal. It is an inspection aid,
257
+ not a guarantee of complete impact coverage.
258
+ - Lite deterministically resolves local relative import paths, including the
259
+ Node ESM `.js`-from-`.ts` convention. It still does not claim semantic symbol
260
+ resolution or whole-program call-graph precision.
261
+ - A continuation Workset reports how many stale memory bindings point directly
262
+ at the changed snapshot files. It does not attribute unrelated old stale
263
+ memory to the current change.
264
+ - The Workset governor now filters optional claims, workflows, durable memory,
265
+ and code-bound memory before prompt rendering. Its receipt records the safe
266
+ disposition and reason without exposing hidden content. In this first slice,
267
+ task facts, Git state, current code state, and safety cautions remain outside
268
+ the optional-evidence gate so an abstention never hides current source facts.
269
+
270
+ #### C. Test and Verification Links
271
+
272
+ Workflow runs now record an append-only pass/fail signal for their selected
273
+ claims and durable memories. The newest signal is applied only as a delivery
274
+ qualification: a failed verification degrades optional context instead of
275
+ silently rewriting or deleting the original record. A later code change can
276
+ then downgrade the confidence of a memory that says "this is verified" rather
277
+ than leaving an old green test as permanent proof. File/symbol references on
278
+ individual test outcomes remain a later extension.
279
+
280
+ #### D. Provider Coverage Contract
281
+
282
+ Every provider returns:
283
+
284
+ ```text
285
+ ProviderCoverage
286
+ provider, parserMode, supportedLanguages
287
+ indexedFiles, skippedFiles, skippedReasons
288
+ relationTypes, confidencePolicy
289
+ snapshotCompleteness
290
+ ```
291
+
292
+ CodeGraph Lite remains a mandatory local fallback. Parser-backed or external
293
+ providers are optional accelerators and may only add normalized facts through
294
+ this contract. They cannot bypass project scope, source epoch, or secret rules.
295
+
296
+ #### E. Claim-to-Code Requalification
297
+
298
+ Existing claim and observation code references should consume snapshot diffs:
299
+
300
+ - removed source -> `blocked` or `needs-review`;
301
+ - changed bound source -> `degraded` until rechecked;
302
+ - current source plus fresh verification -> `verified`;
303
+ - incomplete provider coverage -> `unknown`, never falsely `current`.
304
+
305
+ ## Retrieval Policy
306
+
307
+ The governor collects candidates first, then applies this order:
308
+
309
+ 1. project identity, scope, visibility, and secret policy;
310
+ 2. hard exclusions: deleted evidence, forbidden scope, confirmed contradiction;
311
+ 3. source freshness and provider completeness;
312
+ 4. task lens and direct code/Git/test links;
313
+ 5. quality signals and explicit user review;
314
+ 6. relevance ranking and diversity;
315
+ 7. strict section and total token budgets.
316
+
317
+ Default delivery is progressive:
318
+
319
+ - **abstain:** no qualified advantage; return normal start files only;
320
+ - **card:** one compact "where we were / what changed / what to verify" card;
321
+ - **workset:** selected details with source references and cautions;
322
+ - **defer:** schedule a refresh or requalification without blocking the agent.
323
+
324
+ ## Public Experience
325
+
326
+ Normal users still say a natural-language task, for example:
327
+
328
+ > Continue the auth migration. What remains and what must be checked first?
329
+
330
+ They receive a short, useful answer. They do not see score arithmetic.
331
+
332
+ An explicit diagnostic path can answer:
333
+
334
+ ```text
335
+ Why did Memorix include or skip this memory?
336
+ Which code snapshot supports it?
337
+ What changed since it was verified?
338
+ How much context budget did it consume?
339
+ ```
340
+
341
+ This diagnostic output is grouped under existing context/knowledge diagnostics;
342
+ it is not a new default tool for every graph operation.
343
+
344
+ ## Delivery Phases
345
+
346
+ ### Phase 0: Baseline and Compatibility
347
+
348
+ - Inventory all existing context ranking, retention, claim, freshness, and
349
+ CodeGraph paths.
350
+ - Add a behavior matrix covering current output and no-regression fixtures.
351
+ - Establish deterministic context-plan fixtures: abstain, compact card, stale
352
+ code caution, conflict exclusion, and incomplete graph coverage.
353
+
354
+ ### Phase 1: Governor Core
355
+
356
+ - Implement candidate adapters and pure qualification/context-plan modules.
357
+ - Route `project_context`, `context_pack`, and CLI context/resume through the
358
+ same plan builder without changing their stable output contracts.
359
+ - Add explicit abstention and reason codes.
360
+
361
+ ### Phase 2: Outcome and Lifecycle Unification
362
+
363
+ - Add append-only outcome signals and derived candidate quality.
364
+ - Route retention report, HTTP/dashboard status, archive eligibility, and
365
+ claim requalification through one lifecycle evaluation path.
366
+ - Treat test/Git/source changes as higher-quality signals than model estimates.
367
+
368
+ ### Phase 3: CodeGraph Evidence Upgrade
369
+
370
+ - Add snapshot diffs, bounded impact slices, coverage reporting, and test/run
371
+ reference links.
372
+ - Requalify claim/observation references from diffs.
373
+ - Add fixture coverage for changed symbol, removed file, incomplete scan, and
374
+ uncertain relation handling.
375
+
376
+ ### Phase 4: Explainability and Operator UX
377
+
378
+ - Add context-plan explanations to CLI JSON and grouped diagnostics.
379
+ - Add dashboard views for quality state, source freshness, impact slice, and
380
+ exclusion reason without leaking hidden/private evidence.
381
+ - Keep the normal agent path quiet.
382
+
383
+ ### Phase 5: Verification and Release Gate
384
+
385
+ - Run unit, SQLite reopen, provider fallback, CLI, MCP, hook, and packaged
386
+ installation checks.
387
+ - Run isolated agent smoke tests with qualified context, stale context, and
388
+ abstention scenarios.
389
+ - Measure first-turn latency, token usage, stale-context catches, and false
390
+ inclusion/exclusion rates against Phase 0 fixtures.
391
+
392
+ ## Acceptance Criteria
393
+
394
+ 1. Every automatic inclusion has a machine-readable reason and at least one
395
+ visible source or explicit `unknown` caution.
396
+ 2. A changed or deleted code source changes the retrieval disposition without a
397
+ human rediscovering the mismatch.
398
+ 3. A task with no qualified memory returns less context, not a generic summary.
399
+ 4. CLI, MCP, and hooks select the same qualified evidence for the same task and
400
+ project state.
401
+ 5. An incomplete CodeGraph provider result can never be formatted as complete
402
+ code truth.
403
+ 6. Test failure, user correction, and source change can lower reusable-memory
404
+ quality; no score-only path deletes a memory.
405
+ 7. Existing stored observations, claims, workflows, context commands, and lite
406
+ MCP profile remain backward compatible.
407
+ 8. Default MCP tool count does not increase.
408
+
409
+ ## Explicit Non-Goals
410
+
411
+ - A remote graph database requirement.
412
+ - Silent LLM rewriting of a project's wiki or workflow.
413
+ - Claiming exact whole-program impact analysis from CodeGraph Lite.
414
+ - Replacing a real language server, CodeGraph product, Git, or test runner.
415
+ - Auto-capturing all conversations, screenshots, or tool outputs.
416
+ - Treating a visual graph as proof of a maintained semantic knowledge graph.
417
+
418
+ ## Research References
419
+
420
+ - Xiong et al., "How Memory Management Impacts LLM Agents: An Empirical Study
421
+ of Experience-Following Behavior," ACL 2026.
422
+ https://aclanthology.org/2026.acl-long.27/
423
+ - Wu et al., "LongMemEval: Benchmarking Chat Assistants on Long-Term
424
+ Interactive Memory," ICLR 2025.
425
+ https://iclr.cc/virtual/2025/poster/28290
426
+ - Xu et al., "A-MEM: Agentic Memory for LLM Agents," NeurIPS 2025.
427
+ https://neurips.cc/virtual/2025/poster/119020
428
+ - Kang et al., "Memory OS of AI Agent," EMNLP 2025.
429
+ https://aclanthology.org/2025.emnlp-main.1318
430
+ - Tan et al., "MemBench: Towards More Comprehensive Evaluation on the Memory
431
+ of LLM-based Agents," Findings of ACL 2025.
432
+ https://aclanthology.org/2025.findings-acl.989.pdf
433
+ - Wang et al., "Unveiling Privacy Risks in LLM Agent Memory," ACL 2025.
434
+ https://aclanthology.org/2025.acl-long.1227.pdf
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "memorix",
3
3
  "mcpName": "io.github.AVIDS2/memorix",
4
- "version": "1.4.1",
4
+ "version": "1.4.2",
5
5
  "description": "Local-first shared memory layer for AI coding agents across MCP clients, Git history, reasoning context, and project sessions.",
6
6
  "type": "module",
7
7
  "sideEffects": false,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://anthropic.com/claude-code/plugin.schema.json",
3
3
  "name": "memorix",
4
- "version": "1.4.1",
4
+ "version": "1.4.2",
5
5
  "description": "Shared workspace memory for Claude Code and other AI coding agents.",
6
6
  "author": {
7
7
  "name": "AVIDS2",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memorix",
3
- "version": "1.4.1",
3
+ "version": "1.4.2",
4
4
  "description": "Shared workspace memory for Codex and other AI coding agents.",
5
5
  "author": {
6
6
  "name": "AVIDS2",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memorix",
3
- "version": "1.4.1",
3
+ "version": "1.4.2",
4
4
  "description": "Shared local workspace memory for GitHub Copilot CLI and other AI coding agents.",
5
5
  "author": {
6
6
  "name": "AVIDS2",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memorix",
3
- "version": "1.4.1",
3
+ "version": "1.4.2",
4
4
  "mcpServers": {
5
5
  "memorix": {
6
6
  "command": "memorix",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memorix-omp-package",
3
- "version": "1.4.1",
3
+ "version": "1.4.2",
4
4
  "description": "Memorix shared workspace memory package for Oh-my-Pi.",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memorix",
3
- "version": "1.4.1",
3
+ "version": "1.4.2",
4
4
  "description": "Shared workspace memory for OpenClaw and other AI coding agents.",
5
5
  "author": {
6
6
  "name": "AVIDS2",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memorix-pi-package",
3
- "version": "1.4.1",
3
+ "version": "1.4.2",
4
4
  "description": "Memorix shared workspace memory package for Pi coding agent.",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
package/server.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "url": "https://github.com/AVIDS2/memorix",
8
8
  "source": "github"
9
9
  },
10
- "version": "1.4.1",
10
+ "version": "1.4.2",
11
11
  "websiteUrl": "https://github.com/AVIDS2/memorix#readme",
12
12
  "icons": [
13
13
  {
@@ -22,7 +22,7 @@
22
22
  {
23
23
  "registryType": "npm",
24
24
  "identifier": "memorix",
25
- "version": "1.4.1",
25
+ "version": "1.4.2",
26
26
  "runtimeHint": "npx",
27
27
  "packageArguments": [
28
28
  {
@@ -58,12 +58,52 @@ function formatUsageHint(): string {
58
58
  'Usage:',
59
59
  ' memorix codegraph refresh',
60
60
  ' memorix codegraph status --json',
61
+ ' memorix codegraph diff [--from <snapshot>] [--to <snapshot>]',
62
+ ' memorix codegraph impact --path <relative-source-path>',
61
63
  ' memorix codegraph context-pack --task "continue auth bug"',
62
64
  '',
63
65
  'Tip: use `memorix context "..."` for new work or `memorix resume "..."` for prior work.',
64
66
  ].join('\n');
65
67
  }
66
68
 
69
+ function formatDiff(diff: ReturnType<CodeGraphStore['diffSnapshots']>, impact: ReturnType<CodeGraphStore['impactSlice']>): string {
70
+ if (!diff.available) {
71
+ return `CodeGraph diff is unavailable: ${diff.reason ?? 'unknown reason'}. Refresh twice to establish comparable snapshots.`;
72
+ }
73
+ const summary = diff.changes.reduce((counts, change) => {
74
+ counts[change.kind] += 1;
75
+ return counts;
76
+ }, { added: 0, modified: 0, removed: 0 });
77
+ const lines = [
78
+ `CodeGraph diff: ${diff.fromSnapshotId} -> ${diff.toSnapshotId}`,
79
+ `- Changed files: ${diff.changes.length} (${summary.added} added, ${summary.modified} modified, ${summary.removed} removed)`,
80
+ ];
81
+ for (const change of diff.changes.slice(0, 20)) lines.push(`- ${change.kind}: ${change.path}`);
82
+ if (diff.changes.length > 20) lines.push(`- ${diff.changes.length - 20} additional file change(s) omitted`);
83
+ if (impact.directlyConnectedPaths.length > 0) {
84
+ lines.push('', 'Current one-hop structural impact');
85
+ for (const path of impact.directlyConnectedPaths.slice(0, 20)) lines.push(`- ${path}`);
86
+ }
87
+ if (impact.relationCount === 0) lines.push('', 'No current file-edge relation was found for the changed paths.');
88
+ if (impact.truncated) lines.push('- Impact relation limit reached; inspect the graph before assuming coverage.');
89
+ return lines.join('\n');
90
+ }
91
+
92
+ function formatImpact(impact: ReturnType<CodeGraphStore['impactSlice']>): string {
93
+ const lines = [
94
+ `CodeGraph current one-hop impact: ${impact.changedPaths.join(', ')}`,
95
+ `- Relations inspected: ${impact.relationCount}`,
96
+ ];
97
+ if (impact.directlyConnectedPaths.length > 0) {
98
+ lines.push('- Directly connected paths:');
99
+ for (const path of impact.directlyConnectedPaths) lines.push(` - ${path}`);
100
+ } else {
101
+ lines.push('- No current file-edge relation was found for this indexed path.');
102
+ }
103
+ if (impact.truncated) lines.push('- Impact relation limit reached; inspect the graph before assuming coverage.');
104
+ return lines.join('\n');
105
+ }
106
+
67
107
  function compactFacts(project: { rootPath: string }): { facts: string[]; dirty: boolean } {
68
108
  const current = collectCurrentProjectFacts({ project, now: new Date() });
69
109
  const facts: string[] = [];
@@ -82,9 +122,13 @@ export default defineCommand({
82
122
  description: 'Inspect and refresh CodeGraph Memory for the current project',
83
123
  },
84
124
  args: {
85
- action: { type: 'string', description: 'Action: status, refresh, or context-pack' },
125
+ action: { type: 'string', description: 'Action: status, refresh, diff, impact, or context-pack' },
86
126
  task: { type: 'string', description: 'Task text for context-pack' },
127
+ path: { type: 'string', description: 'Indexed relative source path for impact' },
87
128
  limit: { type: 'string', description: 'Max active memories to inspect for context-pack' },
129
+ from: { type: 'string', description: 'Earlier CodeGraph snapshot id for diff' },
130
+ to: { type: 'string', description: 'Later CodeGraph snapshot id for diff' },
131
+ impactLimit: { type: 'string', description: 'Maximum graph relations to inspect for diff impact' },
88
132
  json: { type: 'boolean', description: 'Emit machine-readable JSON output' },
89
133
  },
90
134
  run: async ({ args }) => {
@@ -162,6 +206,43 @@ export default defineCommand({
162
206
  return;
163
207
  }
164
208
 
209
+ case 'diff': {
210
+ const snapshots = store.listSnapshots(project.id, 2);
211
+ const fromSnapshotId = (args.from as string | undefined)?.trim() || snapshots[1]?.id;
212
+ const toSnapshotId = (args.to as string | undefined)?.trim() || snapshots[0]?.id;
213
+ if (!fromSnapshotId || !toSnapshotId) {
214
+ emitError('two completed CodeGraph snapshots are required; run "memorix codegraph refresh" again after a code change.', asJson);
215
+ return;
216
+ }
217
+ const diff = store.diffSnapshots(project.id, fromSnapshotId, toSnapshotId);
218
+ const impact = store.impactSlice(
219
+ project.id,
220
+ diff.changes.map(change => change.path),
221
+ parsePositiveInt(args.impactLimit as string | undefined, 24),
222
+ );
223
+ emitResult({ project, diff, impact }, formatDiff(diff, impact), asJson);
224
+ return;
225
+ }
226
+
227
+ case 'impact': {
228
+ const sourcePath = (args.path as string | undefined)?.trim() || positional.slice(1).join(' ').trim();
229
+ if (!sourcePath) {
230
+ emitError('path is required for "memorix codegraph impact"', asJson);
231
+ return;
232
+ }
233
+ if (!store.getFile(project.id, sourcePath)) {
234
+ emitError(`path is not in the current CodeGraph index: ${sourcePath}. Run "memorix codegraph refresh" and retry.`, asJson);
235
+ return;
236
+ }
237
+ const impact = store.impactSlice(
238
+ project.id,
239
+ [sourcePath],
240
+ parsePositiveInt(args.impactLimit as string | undefined, 24),
241
+ );
242
+ emitResult({ project, impact }, formatImpact(impact), asJson);
243
+ return;
244
+ }
245
+
165
246
  case 'context-pack': {
166
247
  const task = (args.task as string | undefined)?.trim() || positional.slice(1).join(' ').trim();
167
248
  if (!task) {
@@ -224,7 +305,7 @@ export default defineCommand({
224
305
  }
225
306
 
226
307
  default:
227
- emitError(`unknown codegraph action "${action}". Use "status", "refresh", or "context-pack".`, asJson);
308
+ emitError(`unknown codegraph action "${action}". Use "status", "refresh", "diff", "impact", or "context-pack".`, asJson);
228
309
  }
229
310
  } catch (error) {
230
311
  emitError(error instanceof Error ? error.message : String(error), asJson);
@@ -259,6 +259,25 @@ export async function buildAutoProjectContext(input: {
259
259
  const overview = explain.overview;
260
260
  const currentFacts = collectCurrentProjectFacts({ project: input.project, now });
261
261
  const latestSnapshot = overview.code.latestSnapshot;
262
+ let codeEvolution: TaskWorkset['codeEvolution'];
263
+ if (continuationRequested && latestSnapshot?.previousSnapshotId && latestSnapshot.changedPathCount > 0) {
264
+ const diff = store.diffSnapshots(input.project.id, latestSnapshot.previousSnapshotId, latestSnapshot.id);
265
+ if (diff.available && diff.changes.length > 0) {
266
+ const impact = store.impactSlice(input.project.id, diff.changes.map(change => change.path));
267
+ const changedFileIds = new Set([
268
+ ...store.listSnapshotFiles(diff.fromSnapshotId),
269
+ ...store.listSnapshotFiles(diff.toSnapshotId),
270
+ ].filter(file => diff.changes.some(change => change.path === file.path)).map(file => file.fileId));
271
+ codeEvolution = {
272
+ fromSnapshotId: diff.fromSnapshotId,
273
+ toSnapshotId: diff.toSnapshotId,
274
+ changes: diff.changes.slice(0, 5).map(change => ({ path: change.path, kind: change.kind })),
275
+ directlyConnectedPaths: impact.directlyConnectedPaths.slice(0, 3),
276
+ affectedMemoryCount: store.countStaleObservationRefsForFiles(input.project.id, [...changedFileIds]),
277
+ truncated: impact.truncated || diff.changes.length > 5,
278
+ };
279
+ }
280
+ }
262
281
  const sourceSets = lensSourceSets({ task, lens, explain });
263
282
  let externalOutline: ExternalCodeGraphOutline | undefined;
264
283
  let externalCaution: string | undefined;
@@ -348,6 +367,7 @@ export async function buildAutoProjectContext(input: {
348
367
  currentFacts: worksetFactLines(currentFacts),
349
368
  ...(continuation ? { continuation } : {}),
350
369
  codeState: codeStateLine(overview),
370
+ ...(codeEvolution ? { codeEvolution } : {}),
351
371
  reliableMemory: sourceSets.reliableSources
352
372
  .slice(0, lens.sourceLimit)
353
373
  .map(source => ({