learning-agent 0.2.1 → 0.2.3

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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,95 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.3] - 2026-02-01
11
+
12
+ ### Added
13
+
14
+ - **SQLite Graceful Degradation** (2f0)
15
+ - Works as dev dependency without native bindings failing
16
+ - JSONL-only mode when SQLite unavailable
17
+ - Keyword search falls back gracefully
18
+ - Warning displayed in degraded mode
19
+
20
+ - **Claude Code Integration** (ctv, 8lp, 6nw, 501, 2jp, lfy)
21
+ - Claude Plugin structure (`.claude-plugin/`) with manifest and commands
22
+ - `/learn` slash command for quick lesson capture
23
+ - `/check-plan` slash command for plan-time retrieval
24
+ - Auto-invoke triggers for lesson capture patterns
25
+ - Detection triggers wired to Claude Code workflow
26
+ - AGENTS.md includes reference to CLAUDE.md
27
+
28
+ - **Context Recovery** (gpv)
29
+ - `lna prime` command for context recovery after compaction/clear
30
+ - Outputs workflow rules, commands, and quality gates
31
+
32
+ - **Diagnostics** (qi0)
33
+ - `setup claude --status` shows integration health
34
+ - Displays settings file, hook status, slash command availability
35
+ - JSON output with `--json` flag
36
+
37
+ ### Changed
38
+
39
+ - **Architecture Refactoring** (e73, zpl)
40
+ - Split sqlite.ts (644 lines) into focused modules (<200 lines each)
41
+ - Module imports now use barrel exports (Parnas principles)
42
+ - Cleaner internal boundaries and improved maintainability
43
+
44
+ - **CLI Improvements** (79k, e2r)
45
+ - CLI releases database resources on SIGINT/SIGTERM signals
46
+ - `setup claude --uninstall` removes AGENTS.md section and CLAUDE.md reference
47
+ - Clean uninstall preserves other content
48
+
49
+ ### Fixed
50
+
51
+ - Claude now uses CLI commands instead of editing JSONL directly (0p5)
52
+ - Plan-time lessons now appear via check-plan hook integration (6nw)
53
+
54
+ ## [0.2.2] - 2026-02-01
55
+
56
+ ### Added
57
+
58
+ - **Age-based Temporal Validity** (LANDSCAPE.md: eik)
59
+ - `CompactionLevelSchema` for lesson lifecycle (0=active, 1=flagged, 2=archived)
60
+ - Age distribution display in `stats` command (<30d, 30-90d, >90d)
61
+ - Age warnings in `load-session` for lessons older than 90 days
62
+ - New schema fields: `compactionLevel`, `compactedAt`, `lastRetrieved`
63
+
64
+ - **Manual Invalidation** (LANDSCAPE.md: mov)
65
+ - `learning-agent wrong <id>` - Mark a lesson as invalid/wrong
66
+ - `learning-agent validate <id>` - Re-enable a previously invalidated lesson
67
+ - `list --invalidated` flag to show only invalidated lessons
68
+ - New schema fields: `invalidatedAt`, `invalidationReason`
69
+
70
+ - **Optional Citation Field** (LANDSCAPE.md: tn3)
71
+ - `CitationSchema` for lesson provenance tracking
72
+ - Store file path, line number, and git commit with lessons
73
+ - `learn --citation <file:line>` and `--citation-commit <hash>` flags
74
+
75
+ - **Count Warning** (LANDSCAPE.md: qp9)
76
+ - Warning in `stats` when lesson count exceeds 20 (context pollution prevention)
77
+ - Note in `load-session` when total lessons may degrade retrieval quality
78
+
79
+ ### Changed
80
+
81
+ - Lesson schema now includes optional fields for citation, age-tracking, and invalidation
82
+ - `list` command shows `[INVALID]` marker for invalidated lessons
83
+ - `load-session` JSON output includes `totalCount` field
84
+ - CLI refactored into command modules (`src/commands/`) for maintainability
85
+ - Age calculation logic centralized in `src/utils.ts`
86
+
87
+ ### Fixed
88
+
89
+ - **SQLite schema now stores v0.2.2 fields** (x9y)
90
+ - Added columns: `invalidated_at`, `invalidation_reason`, `citation_*`, `compaction_level`, `compacted_at`
91
+ - `rebuildIndex` preserves all v0.2.2 fields during cache rebuild
92
+ - `rowToLesson` correctly maps all fields back to Lesson objects
93
+
94
+ - **Retrieval paths filter out invalidated lessons** (z8k)
95
+ - `searchKeyword` excludes lessons with `invalidated_at` set
96
+ - `searchVector` skips invalidated lessons during scoring
97
+ - `loadSessionLessons` filters out invalidated high-severity lessons
98
+
10
99
  ## [0.2.1] - 2026-02-01
11
100
 
12
101
  ### Added
@@ -141,7 +230,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
141
230
  - Vitest test suite
142
231
  - tsup build configuration
143
232
 
144
- [Unreleased]: https://github.com/Nathandela/learning_agent/compare/v0.2.1...HEAD
233
+ [Unreleased]: https://github.com/Nathandela/learning_agent/compare/v0.2.3...HEAD
234
+ [0.2.3]: https://github.com/Nathandela/learning_agent/compare/v0.2.2...v0.2.3
235
+ [0.2.2]: https://github.com/Nathandela/learning_agent/compare/v0.2.1...v0.2.2
145
236
  [0.2.1]: https://github.com/Nathandela/learning_agent/compare/v0.2.0...v0.2.1
146
237
  [0.2.0]: https://github.com/Nathandela/learning_agent/compare/v0.1.0...v0.2.0
147
238
  [0.1.0]: https://github.com/Nathandela/learning_agent/releases/tag/v0.1.0
package/README.md CHANGED
@@ -49,6 +49,27 @@ pnpm test
49
49
  pnpm download-model
50
50
  ```
51
51
 
52
+ ## Development
53
+
54
+ ### Test Scripts
55
+
56
+ | Script | Duration | Tests | Use Case |
57
+ |--------|----------|-------|----------|
58
+ | `pnpm test:fast` | ~6s | 385 | **Rapid feedback during development** |
59
+ | `pnpm test` | ~60s | 653 | Full suite before committing |
60
+ | `pnpm test:changed` | varies | varies | Only tests affected by recent changes |
61
+ | `pnpm test:watch` | - | - | Watch mode for TDD workflow |
62
+ | `pnpm test:all` | ~60s | 653 | Full suite with model download |
63
+
64
+ **Recommended workflow:**
65
+ 1. Use `pnpm test:fast` while coding for rapid feedback
66
+ 2. Run `pnpm test` before committing
67
+ 3. CI runs the full suite
68
+
69
+ ### Why test:fast is fast
70
+
71
+ The CLI integration tests spawn Node.js processes (~400ms overhead each) and account for 95% of test time. `test:fast` skips these, running only unit tests that verify all business logic.
72
+
52
73
  ## Architecture
53
74
 
54
75
  ```
@@ -93,18 +114,30 @@ pnpm download-model
93
114
  # Capture a lesson manually
94
115
  pnpm learn "Use Polars for large files, not pandas"
95
116
 
117
+ # Capture with citation (file:line provenance)
118
+ learning-agent learn "API requires auth header" --citation src/api.ts:42
119
+
96
120
  # Search lessons
97
121
  learning-agent search "data processing"
98
122
 
99
- # Rebuild index from JSONL
100
- learning-agent rebuild
101
-
102
123
  # List all lessons
103
124
  learning-agent list
104
125
 
105
- # Show database stats
126
+ # List only invalidated lessons
127
+ learning-agent list --invalidated
128
+
129
+ # Mark a lesson as wrong/invalid
130
+ learning-agent wrong L12345678 --reason "This advice was incorrect"
131
+
132
+ # Re-enable an invalidated lesson
133
+ learning-agent validate L12345678
134
+
135
+ # Show database stats (includes age distribution)
106
136
  learning-agent stats
107
137
 
138
+ # Rebuild index from JSONL
139
+ learning-agent rebuild
140
+
108
141
  # Compact and archive old lessons
109
142
  learning-agent compact
110
143
  ```
@@ -184,118 +217,87 @@ See [examples/](examples/) for usage examples.
184
217
 
185
218
  ## Lesson Schema
186
219
 
187
- Lessons are stored in JSONL format with Zod validation. Understanding the schema is critical for correct usage.
220
+ Lessons are stored as JSONL records with the following schema:
188
221
 
189
222
  ### Required Fields
190
223
 
191
- Every lesson **must** have these fields:
224
+ All lessons must have these fields:
192
225
 
193
226
  | Field | Type | Description |
194
227
  |-------|------|-------------|
195
- | `id` | string | Unique identifier (e.g., "L1a2b3c4d") |
196
- | `type` | "quick" \| "full" | Lesson quality tier (see below) |
197
- | `trigger` | string | What caused this lesson to be learned |
198
- | `insight` | string | The actual lesson content |
199
- | `tags` | string[] | Categorization tags (can be empty) |
200
- | `source` | enum | How it was captured: "user_correction", "self_correction", "test_failure", "manual" |
201
- | `context` | object | `{ tool: string, intent: string }` - what was happening |
202
- | `created` | string | ISO8601 timestamp |
203
- | `confirmed` | boolean | Whether user confirmed this lesson |
204
- | `supersedes` | string[] | IDs of lessons this replaces (can be empty) |
205
- | `related` | string[] | IDs of related lessons (can be empty) |
228
+ | `id` | string | Unique identifier (e.g., "L12345678") |
229
+ | `type` | "quick" \| "full" | Lesson complexity level |
230
+ | `trigger` | string | What caused the lesson (context/situation) |
231
+ | `insight` | string | What was learned (the takeaway) |
232
+ | `tags` | string[] | Categorization tags |
233
+ | `source` | string | How it was captured (user_correction, self_correction, test_failure, manual) |
234
+ | `context` | object | Tool/intent context |
235
+ | `created` | ISO string | Creation timestamp |
236
+ | `confirmed` | boolean | Whether user confirmed the lesson |
206
237
 
207
238
  ### Optional Fields
208
239
 
209
240
  | Field | Type | Description |
210
241
  |-------|------|-------------|
211
- | `evidence` | string | Supporting evidence (typically for "full" type) |
212
- | `severity` | "high" \| "medium" \| "low" | Importance level |
213
- | `pattern` | object | `{ bad: string, good: string }` - code pattern |
214
- | `deleted` | boolean | Tombstone marker for deletions |
215
- | `retrievalCount` | number | Times this lesson was retrieved |
216
-
217
- ### Type vs Severity (Important!)
218
-
219
- **`type`** and **`severity`** are **separate** fields:
242
+ | `evidence` | string | Supporting evidence (full lessons only) |
243
+ | `severity` | "high" \| "medium" \| "low" | Importance level (separate from type) |
244
+ | `citation` | object | File/line reference (file, line, commit) |
220
245
 
221
- - **`type`**: Quality tier of the lesson
222
- - `"quick"` - Minimal capture, fast to create
223
- - `"full"` - Detailed lesson with evidence/patterns
224
-
225
- - **`severity`**: Importance level (optional field)
226
- - `"high"` - Critical, loaded at every session start
227
- - `"medium"` - Important, retrieved when relevant
228
- - `"low"` - Minor, lower retrieval priority
229
-
230
- **Common mistake**: Using `type: "high"` instead of `type: "full"` with `severity: "high"`.
246
+ **Note**: The `severity` field is separate from `type`. A quick lesson can have high severity, and a full lesson can have low severity.
231
247
 
232
248
  ### Session-Start Loading
233
249
 
234
- High-severity lessons are automatically loaded at session start. For a lesson to load:
250
+ At session start, lessons are loaded based on:
251
+ - **High severity** lessons are always loaded
252
+ - **Confirmed** lessons are prioritized
253
+ - Only non-invalidated lessons are included
235
254
 
236
- 1. `type` must be `"full"`
237
- 2. `severity` must be `"high"`
238
- 3. `confirmed` must be `true`
255
+ ### Complete JSON Example
239
256
 
240
- ### Complete Examples
257
+ ```json
258
+ {
259
+ "id": "L12345678",
260
+ "type": "full",
261
+ "trigger": "API returned 401 despite valid JWT token",
262
+ "insight": "Auth API requires X-Request-ID header in all requests",
263
+ "evidence": "Traced in network tab, discovered missing header requirement",
264
+ "severity": "high",
265
+ "tags": ["api", "auth", "headers"],
266
+ "source": "test_failure",
267
+ "context": { "tool": "fetch", "intent": "API authentication" },
268
+ "created": "2024-01-15T10:30:00.000Z",
269
+ "confirmed": true,
270
+ "citation": { "file": "src/api/client.ts", "line": 42 }
271
+ }
272
+ ```
241
273
 
242
- #### Quick Lesson (minimal)
274
+ ## Lesson Types
243
275
 
276
+ ### Quick Lesson (fast capture)
244
277
  ```json
245
278
  {
246
- "id": "L1a2b3c4d",
279
+ "id": "L001",
247
280
  "type": "quick",
248
281
  "trigger": "Used pandas for 500MB file",
249
- "insight": "Polars is 10x faster for large files",
282
+ "insight": "Polars 10x faster",
250
283
  "tags": ["performance", "polars"],
251
- "source": "user_correction",
252
- "context": { "tool": "edit", "intent": "optimize CSV processing" },
253
- "created": "2025-01-30T14:00:00Z",
254
- "confirmed": true,
255
- "supersedes": [],
256
- "related": []
284
+ "source": "user_correction"
257
285
  }
258
286
  ```
259
287
 
260
- #### Full Lesson with High Severity (loads at session start)
261
-
288
+ ### Full Lesson (detailed, high-severity)
262
289
  ```json
263
290
  {
264
- "id": "L5e6f7g8h",
291
+ "id": "L002",
265
292
  "type": "full",
266
293
  "trigger": "Auth API returned 401 despite valid token",
267
294
  "insight": "API requires X-Request-ID header",
268
- "evidence": "Traced in network tab, header was missing",
269
- "tags": ["api", "auth"],
295
+ "evidence": "Traced in network tab, header missing",
270
296
  "severity": "high",
271
- "source": "test_failure",
272
- "context": { "tool": "bash", "intent": "run auth integration tests" },
273
- "created": "2025-01-30T15:30:00Z",
274
- "confirmed": true,
275
- "supersedes": [],
276
- "related": ["L1a2b3c4d"],
277
- "pattern": {
278
- "bad": "requests.get(url, headers={'Authorization': token})",
279
- "good": "requests.get(url, headers={'Authorization': token, 'X-Request-ID': uuid4()})"
280
- }
297
+ "source": "test_failure"
281
298
  }
282
299
  ```
283
300
 
284
- ### Creating Lessons via CLI
285
-
286
- Always use the CLI to create lessons (never edit JSONL directly):
287
-
288
- ```bash
289
- # Quick lesson
290
- npx lna learn "Use Polars for large files"
291
-
292
- # Full lesson with high severity (loads at session start)
293
- npx lna learn "API requires X-Request-ID header" --severity high
294
-
295
- # With trigger context
296
- npx lna learn "Use uv not pip" --trigger "pip was slow" --severity medium
297
- ```
298
-
299
301
  ## Technology Stack
300
302
 
301
303
  | Component | Technology |
@@ -324,7 +326,7 @@ pnpm lint
324
326
 
325
327
  ## Project Status
326
328
 
327
- Version 0.2.1 - Bug fixes and documentation improvements. See [doc/SPEC.md](doc/SPEC.md) for the full specification and [CHANGELOG.md](CHANGELOG.md) for recent changes.
329
+ Version 0.2.2 - Hardening release with quality gates based on [LANDSCAPE.md](doc/LANDSCAPE.md) reviewer feedback. Adds age-based validity warnings, manual invalidation commands, optional citation tracking, and context pollution warnings. See [CHANGELOG.md](CHANGELOG.md) for details.
328
330
 
329
331
  ## Documentation
330
332
 
@@ -335,6 +337,32 @@ Version 0.2.1 - Bug fixes and documentation improvements. See [doc/SPEC.md](doc/
335
337
  | [doc/PLAN.md](doc/PLAN.md) | Implementation plan |
336
338
  | [AGENTS.md](AGENTS.md) | Agent instructions overview |
337
339
  | [.claude/CLAUDE.md](.claude/CLAUDE.md) | Claude Code project instructions |
340
+ | [doc/test-optimization-baseline.md](doc/test-optimization-baseline.md) | Test performance metrics |
341
+
342
+ ## Testing
343
+
344
+ ### Test Organization
345
+
346
+ Tests are organized for parallelization:
347
+
348
+ ```
349
+ src/
350
+ ├── *.test.ts # Unit tests (fast)
351
+ ├── cli/ # CLI integration tests (split by command)
352
+ │ ├── cli-test-utils.ts # Shared utilities
353
+ │ ├── learn.test.ts
354
+ │ ├── search.test.ts
355
+ │ └── ...
356
+ ├── storage/ # Storage layer tests
357
+ ├── embeddings/ # Embedding model tests (skipped if model unavailable)
358
+ └── ...
359
+ ```
360
+
361
+ ### Known Limitations
362
+
363
+ **Embedding concurrency**: The `node-llama-cpp` native addon may crash under heavy parallel load. This is a known limitation of the underlying C++ library. Tests pass reliably under normal conditions.
364
+
365
+ **Timing-based tests**: Some tests verify performance thresholds. These use generous limits (5000ms) to avoid flakiness on slow CI machines.
338
366
 
339
367
  ## License
340
368