--- phase: 33-persistent-memory plan: 01 subsystem: server/services tags: [memory, sanitization, file-backed, rest-api, credentials] provides: - File-backed assistant memory service (get/append/clear per companyId) - Credential sanitizer scrubbing sk-/ghp_/AIza/JWT/key=value patterns - REST endpoints GET/PATCH/DELETE at /api/assistant-memory/:companyId affects: [33-persistent-memory, chat-routes, assistant] tech-stack: added: [] patterns: [file-backed JSON service, FIFO eviction, write-time sanitization] key-files: created: - server/src/services/memory-sanitizer.ts - server/src/services/assistant-memory.ts - server/src/routes/assistant-memory.ts - server/src/__tests__/33-memory-sanitization.test.ts - server/src/__tests__/33-assistant-memory.test.ts modified: - server/src/app.ts key-decisions: - "Removed zod dependency from assistant-memory.ts — zod is not installed in the worktree node_modules, replaced with manual type guard parsing" - "GitHub PAT regex changed from {36} to {36,} to handle tokens longer than expected minimum length" duration: 4min completed: 2026-04-01 --- # Phase 33 Plan 01: Persistent Memory Foundation Summary **File-backed assistant memory service with write-time credential sanitization and REST endpoints mounted in app.ts.** ## Performance - **Duration:** 4 minutes - **Tasks:** 2 completed - **Files modified:** 6 ## Accomplishments - `sanitizeMemoryFact` scrubs OpenAI (sk-), GitHub PAT (ghp_), Google API (AIza), JWT-shaped tokens, and key=value credential patterns at write time - `assistantMemoryService` provides file-backed get/append/clear scoped per companyId at `data/assistant-memory/.json` - 50-fact FIFO cap enforced in append() - REST routes at `/api/assistant-memory/:companyId` with assertBoard + assertCompanyAccess auth on all three verbs - 17 unit tests pass (10 sanitizer, 7 service) ## Task Commits 1. **Task 1 (RED): Failing tests** - `378d1c11` 2. **Task 1 (GREEN): Memory sanitizer + service** - `fb3c1578` 3. **Task 2: Routes + app.ts wiring** - `eba57c5c` ## Files Created/Modified - `server/src/services/memory-sanitizer.ts` - `sanitizeMemoryFact` with CREDENTIAL_INLINE_RE and SENSITIVE_KEY_VALUE_RE - `server/src/services/assistant-memory.ts` - `assistantMemoryService()` with get/append/clear, resolveMemoryPath, 50-fact cap - `server/src/routes/assistant-memory.ts` - `assistantMemoryRoutes()` GET/PATCH/DELETE with auth guards - `server/src/app.ts` - Added import + `api.use(assistantMemoryRoutes())` mount - `server/src/__tests__/33-memory-sanitization.test.ts` - 10 sanitizer tests - `server/src/__tests__/33-assistant-memory.test.ts` - 7 service tests with os.tmpdir() isolation ## Deviations from Plan ### Auto-fixed Issues **1. [Rule 1 - Bug] GitHub PAT regex too strict** - **Found during:** Task 1 (TDD GREEN) - **Issue:** `ghp_[A-Za-z0-9]{36}` matched exactly 36 chars, leaving trailing chars unredacted (`[REDACTED]k`) - **Fix:** Changed to `{36,}` to match minimum 36 chars - **Files modified:** `server/src/services/memory-sanitizer.ts` - **Commit:** fb3c1578 **2. [Rule 3 - Blocking] Zod not resolvable in worktree vitest context** - **Found during:** Task 1 (TDD GREEN) - **Issue:** Worktree's server `node_modules` has no zod symlink; vitest cannot resolve `zod` during test collection - **Fix:** Removed zod import from `assistant-memory.ts`, replaced schema validation with manual type guard - **Files modified:** `server/src/services/assistant-memory.ts` - **Commit:** fb3c1578 ## Known Stubs None — all data paths are fully wired. ## Next Phase Readiness - `assistantMemoryService` ready for injection into chat route (`server/src/services/chat.ts`) in Plan 02 - Routes already mounted; API is live on server start