@stackmemoryai/stackmemory 1.5.3 → 1.5.4

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.
@@ -11,20 +11,20 @@
11
11
  "criteria": {
12
12
  "has_function": {
13
13
  "passed": true,
14
- "reason": "A complete, working function `isPalindrome` is defined in TypeScript with proper syntax, parameters, return type, and implementation."
14
+ "reason": "A real, working function named isPalindrome is defined with proper TypeScript syntax and implementation"
15
15
  },
16
16
  "handles_edge_cases": {
17
17
  "passed": true,
18
- "reason": "The code handles edge cases: empty strings (returns true), mixed case (lowercase normalization), and special characters (regex removal of non-alphanumeric)."
18
+ "reason": "The function handles edge cases by converting to lowercase, removing non-alphanumeric characters, and comparing cleaned strings - this covers spaces, punctuation, and case sensitivity"
19
19
  },
20
20
  "is_tested": {
21
21
  "passed": false,
22
- "reason": "The output shows example outputs but provides no actual test cases, unit tests, or test function definitions. Examples are illustrative documentation, not executable tests."
22
+ "reason": "No test cases or assertions are provided; the output contains only the function definition without any testing code"
23
23
  }
24
24
  },
25
25
  "judgeMode": "llm",
26
- "duration": 26370,
27
- "output": "I've written a palindrome checker function at `/private/tmp/gepa-eval-X4niM9/isPalindrome.ts`:\n\n```typescript\nexport function isPalindrome(str: string): boolean {\n if (!str) return true;\n\n const normalized = str.toLowerCase().replace(/[^a-z0-9]/g, '');\n const reversed = normalized.split('').reverse().join('');\n\n return normalized === reversed;\n}\n```\n\n**Features**:\n- Returns `true` for empty strings\n- Normalizes by converting to lowercase and removing non-alphanumeric characters\n- Compares the normalized string with its reverse\n\n**Examples**:\n- `isPalindrome(\"racecar\")` → `true`\n- `isPalindrome(\"A man, a plan, a canal: Panama\")` → `true`\n- `isPalindrome(\"hello\")` → `false`\n"
26
+ "duration": 8230,
27
+ "output": "```typescript\nfunction isPalindrome(s: string): boolean {\n const cleaned = s.toLowerCase().replace(/[^a-z0-9]/g, '');\n return cleaned === cleaned.split('').reverse().join('');\n}\n```\n"
28
28
  },
29
29
  {
30
30
  "taskId": "eval-002",
@@ -35,44 +35,44 @@
35
35
  "criteria": {
36
36
  "uses_async": {
37
37
  "passed": false,
38
- "reason": "No async/await code is provided; AI only requests the original code instead of demonstrating the refactored solution"
38
+ "reason": "No async/await code is present in the output. The AI only requested the input code without providing any refactored solution."
39
39
  },
40
40
  "preserves_behavior": {
41
41
  "passed": false,
42
- "reason": "No refactored code is shown, so behavior preservation cannot be verified"
42
+ "reason": "No refactored code was provided, so behavior cannot be preserved or verified."
43
43
  },
44
44
  "no_nested_callbacks": {
45
45
  "passed": false,
46
- "reason": "No refactored code is demonstrated; the output is a request for input rather than a solution"
46
+ "reason": "No code transformation was performed. The output contains no callbacks or async/await implementation to evaluate."
47
47
  }
48
48
  },
49
49
  "judgeMode": "llm",
50
- "duration": 8335,
51
- "output": "I need to see the code you want to refactor. Could you please provide the file path or share the code that uses callbacks?\n"
50
+ "duration": 9716,
51
+ "output": "Please share the code you'd like me to refactor.\n"
52
52
  },
53
53
  {
54
54
  "taskId": "eval-003",
55
55
  "taskName": "fix_bug",
56
56
  "weight": 1.2,
57
- "passed": true,
58
- "passRate": 0.6666666666666666,
57
+ "passed": false,
58
+ "passRate": 0,
59
59
  "criteria": {
60
60
  "bug_fixed": {
61
61
  "passed": false,
62
- "reason": "The output only describes the fix but does not show the actual fixed code. No corrected code snippet is provided to verify the bug is actually fixed."
62
+ "reason": "No code was provided to fix, so no bug was actually corrected. The AI only requested the code instead of fixing anything."
63
63
  },
64
64
  "no_new_bugs": {
65
- "passed": true,
66
- "reason": "The suggested fix (changing `i <= items.length` to `i < items.length`) is a standard, correct solution for off-by-one errors and introduces no new bugs."
65
+ "passed": false,
66
+ "reason": "Cannot evaluate since no code fix was attempted or provided."
67
67
  },
68
68
  "explains_fix": {
69
- "passed": true,
70
- "reason": "The output clearly explains what was wrong (accessing undefined index 3 on a 3-element array) and why the fix works (using < instead of <=)."
69
+ "passed": false,
70
+ "reason": "No explanation of any fix was provided. The AI only asked for the missing code to be shared."
71
71
  }
72
72
  },
73
73
  "judgeMode": "llm",
74
- "duration": 25447,
75
- "output": "Fixed buggy-loop.js:6 - changed `i <= items.length` to `i < items.length` to prevent accessing `items[3]` (undefined) on a 3-element array.\n"
74
+ "duration": 8553,
75
+ "output": "I don't see any code or file provided. Could you share the code with the off-by-one error you'd like me to fix?\n"
76
76
  },
77
77
  {
78
78
  "taskId": "eval-004",
@@ -83,80 +83,80 @@
83
83
  "criteria": {
84
84
  "has_pagination": {
85
85
  "passed": false,
86
- "reason": "No code provided in output - empty code block"
86
+ "reason": "No pagination implementation provided. The AI only asked a clarifying question without delivering any code."
87
87
  },
88
88
  "has_limit": {
89
89
  "passed": false,
90
- "reason": "No code provided in output - empty code block"
90
+ "reason": "No limit parameter implemented. The output contains no code or functional implementation."
91
91
  },
92
92
  "has_offset": {
93
93
  "passed": false,
94
- "reason": "No code provided in output - empty code block"
94
+ "reason": "No offset parameter implemented. The output contains no code or functional implementation."
95
95
  },
96
96
  "backwards_compatible": {
97
97
  "passed": false,
98
- "reason": "No code provided in output - empty code block"
98
+ "reason": "No implementation provided, so backwards compatibility cannot be verified. The output is a clarifying question, not a solution."
99
99
  }
100
100
  },
101
101
  "judgeMode": "llm",
102
- "duration": 20951,
103
- "output": "\n"
102
+ "duration": 11867,
103
+ "output": "Which API endpoint would you like to add pagination to? Can you point me to the file or describe the endpoint?\n"
104
104
  },
105
105
  {
106
106
  "taskId": "eval-005",
107
107
  "taskName": "code_review",
108
108
  "weight": 1.3,
109
- "passed": true,
110
- "passRate": 0.6666666666666666,
109
+ "passed": false,
110
+ "passRate": 0,
111
111
  "criteria": {
112
112
  "identifies_security_issue": {
113
- "passed": true,
114
- "reason": "Output correctly identifies 5 legitimate security vulnerabilities: SQL injection, plaintext password comparison, sensitive data logging, insecure session tokens, and missing HttpOnly cookie flags with clear code examples and impact analysis"
113
+ "passed": false,
114
+ "reason": "No security issue was identified. The AI asked for clarification instead of reviewing any code."
115
115
  },
116
116
  "identifies_performance_issue": {
117
117
  "passed": false,
118
- "reason": "Output does not identify any performance issues. The review focuses exclusively on security vulnerabilities with no mention of performance, scalability, or optimization concerns"
118
+ "reason": "No performance issue was identified. The AI requested a PR reference rather than providing analysis."
119
119
  },
120
120
  "actionable_feedback": {
121
- "passed": true,
122
- "reason": "Output provides specific, actionable fixes for each issue including exact code examples (e.g., parameterized queries, bcrypt.compare, crypto.randomBytes, cookie options) that developers can immediately implement"
121
+ "passed": false,
122
+ "reason": "No actionable feedback was provided. The output is a request for missing information, not constructive review guidance."
123
123
  }
124
124
  },
125
125
  "judgeMode": "llm",
126
- "duration": 29814,
127
- "output": "## Critical Security Issues Found\n\nThis PR contains **MULTIPLE SEVERE SECURITY VULNERABILITIES** that must be rejected:\n\n### 🔴 CRITICAL: SQL Injection (Line 10)\n```typescript\nconst user = await db.query(`SELECT * FROM users WHERE email = '${email}'`);\n```\n**Issue**: Direct string interpolation enables SQL injection attacks \n**Attack**: `email = \"' OR '1'='1' --\"` bypasses authentication \n**Fix**: Revert to parameterized query: `db.query('SELECT * FROM users WHERE email = $1', [email])`\n\n### 🔴 CRITICAL: Plaintext Password Comparison (Line 14)\n```typescript\nconst valid = password === user.passwordHash;\n```\n**Issue**: Removes bcrypt password hashing, comparing plaintext to hash \n**Impact**: Authentication always fails OR passwords stored in plaintext \n**Fix**: Revert to `await bcrypt.compare(password, user.passwordHash)`\n\n### 🔴 CRITICAL: Sensitive Data Logging (Line 22)\n```typescript\nconsole.log(`Login: ${email} / ${password}`);\n```\n**Issue**: Logs plaintext passwords to console/logs \n**Impact**: Password exposure in log files, GDPR/compliance violation \n**Fix**: Remove this line entirely or log only: `console.log(\\`Login attempt: ${email}\\`)`\n\n### 🔴 HIGH: Insecure Session Token (Line 18)\n```typescript\nconst token = email + ':' + Date.now();\n```\n**Issue**: Predictable token generation (email + timestamp) \n**Impact**: Session hijacking via token guessing \n**Fix**: Use cryptographically secure random tokens: `crypto.randomBytes(32).toString('hex')`\n\n### 🟡 MEDIUM: Missing HttpOnly Cookie Flag\n```typescript\nres.cookie('session', token);\n```\n**Issue**: Cookie accessible via JavaScript (XSS vulnerability) \n**Fix**: `res.cookie('session', token, { httpOnly: true, secure: true, sameSite: 'strict' })`\n\n## Recommendation\n\n**REJECT THIS PR IMMEDIATELY** - Contains multiple critical security vulnerabilities including SQL injection and plaintext password exposure. The \"quick fix\" comment on line 9 is a red flag for introducing security issues.\n\nAll changes should be *"
126
+ "duration": 13805,
127
+ "output": "Which PR would you like me to review? Please provide a PR URL, number, or branch name.\n"
128
128
  },
129
129
  {
130
130
  "taskId": "sm-001",
131
131
  "taskName": "add_mcp_tool_handler",
132
132
  "weight": 1.5,
133
- "passed": true,
134
- "passRate": 1,
133
+ "passed": false,
134
+ "passRate": 0,
135
135
  "criteria": {
136
136
  "has_switch_case": {
137
- "passed": true,
138
- "reason": "Code shows a case statement 'get_frame_summary' within a switch/case structure, following the dispatch pattern"
137
+ "passed": false,
138
+ "reason": "No switch/case code is present in the output; only a request for approval is shown"
139
139
  },
140
140
  "has_zod_schema": {
141
- "passed": true,
142
- "reason": "Zod schema is defined inline: z.object({ frameId: z.string() }), validating the required frameId parameter"
141
+ "passed": false,
142
+ "reason": "No Zod schema definition is provided in the output"
143
143
  },
144
144
  "validates_input": {
145
- "passed": true,
146
- "reason": "Input validation occurs via .parse(args) which will throw if frameId is missing or not a string"
145
+ "passed": false,
146
+ "reason": "No input validation logic is implemented in the output"
147
147
  },
148
148
  "returns_typed_response": {
149
- "passed": true,
150
- "reason": "Return statement explicitly returns an object with the four required properties: frameId, name, status, eventCount"
149
+ "passed": false,
150
+ "reason": "No typed response structure is defined in the output"
151
151
  },
152
152
  "handles_not_found": {
153
- "passed": true,
154
- "reason": "Code includes explicit null check (if (!frame)) with error thrown when frame is not found in the frames map"
153
+ "passed": false,
154
+ "reason": "No error handling or not-found logic is present in the output"
155
155
  }
156
156
  },
157
157
  "judgeMode": "llm",
158
- "duration": 33763,
159
- "output": "I've added the `get_frame_summary` handler to the MCP server dispatch pattern. The implementation:\n\n**Added case** (mcp-dispatch-stub.ts:32-42):\n```typescript\ncase 'get_frame_summary': {\n const input = z.object({ frameId: z.string() }).parse(args);\n const frame = frames.get(input.frameId);\n if (!frame) throw new Error(`Frame not found: ${input.frameId}`);\n return {\n frameId: frame.id,\n name: frame.name,\n status: frame.status,\n eventCount: frame.events.length\n };\n}\n```\n\n**Features**:\n- ✓ Zod validation for required `frameId` string parameter\n- ✓ Follows existing switch/case dispatch pattern\n- ✓ Returns `{ frameId, name, status, eventCount }` as specified\n- ✓ Error handling for missing frames (consistent with `close_frame`)\n- ✓ Calculates `eventCount` from `frame.events.length`\n\nThe handler integrates seamlessly with the existing `start_frame` and `close_frame` tools.\n"
158
+ "duration": 23532,
159
+ "output": "Please approve the file write so I can apply the edit.\n"
160
160
  },
161
161
  {
162
162
  "taskId": "sm-002",
@@ -167,32 +167,52 @@
167
167
  "criteria": {
168
168
  "has_delete_trigger": {
169
169
  "passed": true,
170
- "reason": "A DELETE trigger named 'frames_ad' is defined with AFTER DELETE ON frames syntax"
170
+ "reason": "A DELETE trigger named 'frames_ad' is explicitly defined with CREATE TRIGGER IF NOT EXISTS syntax for the frames table."
171
171
  },
172
172
  "uses_fts_delete_syntax": {
173
173
  "passed": true,
174
- "reason": "The trigger uses FTS5 special syntax with INSERT INTO frames_fts(frames_fts, ...) VALUES ('delete', ...) which is the correct way to delete from FTS index"
174
+ "reason": "The trigger uses the FTS5 delete command by inserting 'delete' as the first value into the frames_fts virtual table, which is the correct syntax for removing entries from an FTS5 index."
175
175
  },
176
176
  "references_old_row": {
177
177
  "passed": true,
178
- "reason": "The trigger references old.rowid, old.name, old.digest_text, and old.inputs, old.outputs to access the deleted row values"
178
+ "reason": "The trigger body references old.rowid, old.name, old.digest_text, and old.inputs, old.outputs to capture the deleted row's values before deletion."
179
179
  },
180
180
  "matches_column_list": {
181
181
  "passed": true,
182
- "reason": "The column list (rowid, name, digest_text, inputs, outputs) matches the FTS index structure referenced in the INSERT and UPDATE triggers"
182
+ "reason": "The INSERT statement includes all the same columns (rowid, name, digest_text, inputs, outputs) that appear in the existing INSERT and UPDATE triggers, maintaining consistency with the established pattern."
183
183
  }
184
184
  },
185
185
  "judgeMode": "llm",
186
- "duration": 34003,
187
- "output": "I've added the missing DELETE trigger following the exact pattern of the existing triggers:\n\n**Pattern analysis:**\n- INSERT trigger (`frames_ai`): Adds new row to FTS index\n- UPDATE trigger (`frames_au`): Deletes old row, inserts new row\n- DELETE trigger (`frames_ad`): Deletes row from FTS index\n\n**Implementation:**\n```sql\nCREATE TRIGGER IF NOT EXISTS frames_ad AFTER DELETE ON frames BEGIN\n INSERT INTO frames_fts(frames_fts, rowid, name, digest_text, inputs, outputs)\n VALUES ('delete', old.rowid, old.name, old.digest_text, old.inputs, old.outputs);\nEND;\n```\n\nThe trigger uses the FTS5 special command syntax where `INSERT INTO frames_fts(frames_fts, ...)` with `'delete'` as the first value removes the entry from the full-text index.\n"
186
+ "duration": 27425,
187
+ "output": "The edit is ready it replaces the bug comment with:\n\n```sql\n-- Sync trigger: DELETE\nCREATE TRIGGER IF NOT EXISTS frames_ad AFTER DELETE ON frames BEGIN\n INSERT INTO frames_fts(frames_fts, rowid, name, digest_text, inputs, outputs)\n VALUES ('delete', old.rowid, old.name, old.digest_text, old.inputs, old.outputs);\nEND;\n```\n\nThis follows the same FTS5 external content pattern used in `frames_au`: the special `'delete'` command removes the stale entry from the index using the `old.*` column values. Please approve the write to apply it.\n"
188
188
  },
189
189
  {
190
190
  "taskId": "sm-003",
191
191
  "taskName": "daemon_service_lifecycle",
192
192
  "weight": 1.5,
193
- "passed": false,
194
- "duration": 120042,
195
- "error": "claude timed out after 120000ms"
193
+ "passed": true,
194
+ "passRate": 1,
195
+ "criteria": {
196
+ "clears_old_interval": {
197
+ "passed": true,
198
+ "reason": "The fix adds an early-return guard in start() that prevents overwriting intervalId without clearing it. Additionally, updateConfig() now always calls stop() unconditionally, ensuring the old interval is cleared before a new one is created."
199
+ },
200
+ "prevents_double_start": {
201
+ "passed": true,
202
+ "reason": "The code explicitly adds `if (this.isRunning) return;` at the beginning of start(), which prevents double-start by returning early if already running."
203
+ },
204
+ "has_getstate_method": {
205
+ "passed": true,
206
+ "reason": "A getState() method is defined in the diff that returns an object with the required properties."
207
+ },
208
+ "returns_correct_state_shape": {
209
+ "passed": true,
210
+ "reason": "The getState() method returns an object with all four required properties: isRunning, intervalMs (calculated from config.interval), lastRunTime, and errorCount."
211
+ }
212
+ },
213
+ "judgeMode": "llm",
214
+ "duration": 36969,
215
+ "output": "It seems write permission hasn't been granted yet. Here's what I'd apply — please approve the edit or grant write access:\n\n**Two bugs fixed + `getState()` added:**\n\n```diff\n- // BUG: No guard against double-start ...\n start(): void {\n+ if (this.isRunning) return; // guard: prevents double-start / timer leak\n this.isRunning = true;\n ...\n }\n\n- // BUG: Calls stop() then start() but start() doesn't check...\n updateConfig(config: Partial<ServiceConfig>): void {\n const wasRunning = this.isRunning;\n- if (wasRunning) this.stop();\n+ this.stop(); // always stop: clears interval unconditionally\n this.config = { ...this.config, ...config };\n if (wasRunning && this.config.enabled) this.start();\n }\n\n+ getState(): ServiceState {\n+ return {\n+ isRunning: this.isRunning,\n+ intervalMs: this.config.interval * 60 * 1000,\n+ lastRunTime: this.lastRunTime,\n+ errorCount: this.errorCount,\n+ };\n+ }\n```\n\n**Root causes:**\n\n1. **`start()` had no guard** — calling it twice created two `setInterval` handles; the first leaked because `this.intervalId` was overwritten before it could be cleared. Fix: early-return if already running.\n\n2. **`updateConfig()` used `if (wasRunning) this.stop()`** — the conditional was correct in intent, but the real risk was that `start()` itself didn't guard, so the stop/start cycle could still stack intervals. The belt-and-suspenders fix is: always call `stop()` unconditionally (it's a no-op when not running), then `start()` only if needed.\n"
196
216
  }
197
217
  ]
198
218
  }
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "currentGeneration": 1,
3
- "bestVariant": "variant-d",
4
- "bestScore": 0.4985250737463126,
3
+ "bestVariant": "baseline",
4
+ "bestScore": 0.519174041297935,
5
5
  "targetPath": "/Users/jwu/Dev/stackmemory/CLAUDE.md",
6
6
  "history": [
7
7
  {
8
8
  "generation": 0,
9
9
  "variant": "baseline",
10
10
  "action": "init",
11
- "timestamp": "2026-02-18T22:59:36.437Z"
11
+ "timestamp": "2026-03-06T18:06:15.421Z"
12
12
  },
13
13
  {
14
14
  "generation": 1,
@@ -19,35 +19,35 @@
19
19
  "variant-c",
20
20
  "variant-d"
21
21
  ],
22
- "timestamp": "2026-02-18T23:03:13.997Z"
22
+ "timestamp": "2026-03-06T18:09:17.179Z"
23
23
  },
24
24
  {
25
25
  "generation": 1,
26
26
  "action": "select",
27
27
  "scores": [
28
28
  {
29
- "variant": "variant-d",
30
- "score": 0.4985250737463126
29
+ "variant": "baseline",
30
+ "score": 0.519174041297935
31
31
  },
32
32
  {
33
33
  "variant": "variant-b",
34
- "score": 0.3938053097345133
34
+ "score": 0.4837758112094395
35
35
  },
36
36
  {
37
- "variant": "variant-c",
38
- "score": 0.23230088495575218
37
+ "variant": "variant-d",
38
+ "score": 0.35103244837758113
39
39
  },
40
40
  {
41
- "variant": "baseline",
42
- "score": 0.21165191740412978
41
+ "variant": "variant-c",
42
+ "score": 0.2603244837758112
43
43
  },
44
44
  {
45
45
  "variant": "variant-a",
46
- "score": 0.1762536873156342
46
+ "score": 0.19174041297935102
47
47
  }
48
48
  ],
49
- "best": "variant-d",
50
- "timestamp": "2026-02-18T23:23:18.544Z"
49
+ "best": "baseline",
50
+ "timestamp": "2026-03-06T18:23:17.567Z"
51
51
  }
52
52
  ]
53
53
  }