-
Notifications
You must be signed in to change notification settings - Fork 0
fix: handle undefined content in memory query (GIT-96) #71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
eb9875c
ad93729
720533f
7a5d725
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -202,13 +202,27 @@ export function buildGitMemConfig(): Record<string, unknown> { | |
| threshold: 3, | ||
| }, | ||
| promptSubmit: { | ||
| enabled: false, | ||
| enabled: true, | ||
| recordPrompts: false, | ||
| surfaceContext: true, | ||
| extractIntent: true, | ||
| intentTimeout: 3000, | ||
| minWords: 5, | ||
| memoryLimit: 20, | ||
| includeCommitMessages: true, | ||
| }, | ||
| postCommit: { | ||
| enabled: true, | ||
| }, | ||
| commitMsg: { | ||
| enabled: true, | ||
| autoAnalyze: true, | ||
| inferTags: true, | ||
| requireType: false, | ||
| defaultLifecycle: 'project', | ||
| enrich: true, | ||
| enrichTimeout: 8000, | ||
| }, | ||
|
Comment on lines
+205
to
+225
|
||
| }, | ||
| }; | ||
| } | ||
|
|
@@ -293,7 +307,8 @@ export async function initHooksCommand(options: IInitHooksOptions, logger?: ILog | |
| console.log('\nHooks configured:'); | ||
| console.log(' SessionStart — Load memories into Claude context on startup'); | ||
| console.log(' Stop — Capture memories from session commits on exit'); | ||
| console.log(' UserPromptSubmit — Surface relevant memories per prompt (disabled by default)'); | ||
| console.log(' UserPromptSubmit — Surface relevant memories per prompt'); | ||
| console.log(' CommitMsg — Analyze commits and add AI trailers'); | ||
|
|
||
| console.log('\nNext steps:'); | ||
| console.log(' 1. Start Claude Code in this repo: claude'); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -85,7 +85,7 @@ export class MemoryRepository implements IMemoryRepository { | |
| } | ||
|
|
||
| if (options?.tag) { | ||
| filtered = filtered.filter(m => m.tags.includes(options.tag!)); | ||
| filtered = filtered.filter(m => m.tags?.includes(options.tag!) ?? false); | ||
| } | ||
|
|
||
| if (options?.since) { | ||
|
|
@@ -96,8 +96,8 @@ export class MemoryRepository implements IMemoryRepository { | |
| if (options?.query) { | ||
| const q = options.query.toLowerCase(); | ||
| filtered = filtered.filter(m => | ||
| m.content.toLowerCase().includes(q) || | ||
| m.tags.some(t => t.toLowerCase().includes(q)) | ||
| (m.content?.toLowerCase().includes(q) ?? false) || | ||
| (m.tags?.some(t => t?.toLowerCase().includes(q)) ?? false) | ||
| ); | ||
|
Comment on lines
96
to
101
|
||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -198,6 +198,36 @@ describe('MemoryService', () => { | |
| const result = service.recall('nonexistent-xyz-query', { cwd: repoDir }); | ||
| assert.equal(result.memories.length, 0); | ||
| }); | ||
|
|
||
| it('should handle query on memories with undefined content gracefully (GIT-96)', () => { | ||
| // Regression test: inject actual malformed data with missing content/tags | ||
| const malformedFile = join(repoDir, 'git-96-memsvc-malformed.txt'); | ||
| writeFileSync(malformedFile, 'malformed memory service test'); | ||
| git(['add', 'git-96-memsvc-malformed.txt'], repoDir); | ||
| git(['commit', '-m', 'git-96 memsvc malformed memory'], repoDir); | ||
| const malformedSha = git(['rev-parse', 'HEAD'], repoDir); | ||
|
|
||
| // Write a malformed note payload (missing content and tags fields) | ||
| const malformedPayload = JSON.stringify({ | ||
| memories: [{ | ||
| id: 'git-96-memsvc-malformed-id', | ||
| type: 'gotcha', | ||
| sha: malformedSha, | ||
| confidence: 'medium', | ||
| source: 'user-explicit', | ||
| lifecycle: 'project', | ||
| // Intentionally omit content and tags to simulate malformed data | ||
| createdAt: new Date().toISOString(), | ||
| updatedAt: new Date().toISOString(), | ||
| }], | ||
| }); | ||
|
|
||
| git(['notes', '--ref', 'refs/notes/mem', 'add', '-f', '-m', malformedPayload, malformedSha], repoDir); | ||
|
|
||
| // Query should not throw even with malformed data | ||
| const result = service.recall('test-query', { cwd: repoDir }); | ||
| assert.ok(Array.isArray(result.memories)); | ||
| }); | ||
|
coderabbitai[bot] marked this conversation as resolved.
Comment on lines
+202
to
+230
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This unit test uses real git operations; prefer mocks or move to integration tests. The new regression test relies on As per coding guidelines: "Unit tests must be fast, isolated, and mock all dependencies. Integration tests should use real backends and test contracts." 🤖 Prompt for AI Agents |
||
| }); | ||
|
|
||
| describe('unified recall (notes + trailers)', () => { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -119,6 +119,41 @@ describe('MemoryRepository', () => { | |
| const result = repo.query({ limit: 1, cwd: repoDir }); | ||
| assert.ok(result.memories.length <= 1); | ||
| }); | ||
|
|
||
| it('should handle query on memories with undefined content gracefully (GIT-96)', () => { | ||
| // Regression test: inject actual malformed data with missing content/tags | ||
| // to verify the defensive guards work | ||
| const malformedFile = join(repoDir, 'git-96-malformed.txt'); | ||
| writeFileSync(malformedFile, 'malformed memory test'); | ||
| git(['add', 'git-96-malformed.txt'], repoDir); | ||
| git(['commit', '-m', 'git-96 malformed memory'], repoDir); | ||
| const malformedSha = git(['rev-parse', 'HEAD'], repoDir); | ||
|
|
||
| // Write a malformed note payload (missing content and tags fields) | ||
| const malformedPayload = JSON.stringify({ | ||
| memories: [{ | ||
| id: 'git-96-malformed-id', | ||
| type: 'decision', | ||
| sha: malformedSha, | ||
| confidence: 'high', | ||
| source: 'user-explicit', | ||
| lifecycle: 'project', | ||
| // Intentionally omit content and tags to simulate malformed data | ||
| createdAt: new Date().toISOString(), | ||
| updatedAt: new Date().toISOString(), | ||
| }], | ||
| }); | ||
|
|
||
| git(['notes', '--ref', 'refs/notes/mem', 'add', '-f', '-m', malformedPayload, malformedSha], repoDir); | ||
|
|
||
| // Query with text search should not throw | ||
| const queryResult = repo.query({ query: 'test-search', cwd: repoDir }); | ||
| assert.ok(Array.isArray(queryResult.memories)); | ||
|
|
||
| // Query with tag filter should not throw | ||
| const tagResult = repo.query({ tag: 'some-tag', cwd: repoDir }); | ||
| assert.ok(Array.isArray(tagResult.memories)); | ||
|
Comment on lines
+123
to
+155
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unit test should not depend on real git operations. This regression test uses real As per coding guidelines: "Unit tests must be fast, isolated, and mock all dependencies. Integration tests should use real backends and test contracts." 🤖 Prompt for AI Agents |
||
| }); | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| }); | ||
|
|
||
| describe('delete', () => { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.