#14 (CRIT): ContextBuilder.selfAwarePreamble names search_memory + forget_fact with explicit cue 'call search_memory FIRST. Never claim to remember without searching.' #16 (HIGH): MemoryQueries.sanitizeFTS5Query strips non-alphanumeric, quotes tokens; HybridSearch.searchFacts calls it before binding to MATCH ?. Embedding still runs on raw query. #12 (CRIT): MemoryStore.init accepts optional embedder; insertNewFact writes facts_vec after the facts commit. Vec failures log + leave FTS row (no rollback). installMemory shares one embedder between writer + reader. #15 (HIGH): drop stableHash; pass sentinel 0 as sourceTurnId (option 1 per audit — smaller change surface than threading real rowid through 5 files). Schema comment updated. #13 (CRIT): two-layer fix. Layer 1: AppDelegate owns a per-process sentinel TurnID; installAgent writes the matching turns row after beginSession; AppDelegateMemoryReplaySink attributes events to it. Layer 2: ReplayLog.flushPending retries failed batches event-by-event so one poisoned row only drops itself. Memory 98 + Replay 34 + AgentCore 243 tests pass; all 18 boundary gates green.
Replay
Per-turn NDJSON log under ~/Library/Application Support/Jarvis/replay/. Every turn writes a full transcript of LLM events, tool calls (pre- and post-sanitize bytes both, per SEC-07), memory mutations, and stop reason. The replayer is a developer tool, not user-facing.
Key public types
| Type | Purpose |
|---|---|
ReplayLog (actor) |
The single writer; rotated per session |
ReplayEvent |
NDJSON event union — turnStart, userInput, tokenDelta, toolCallRequested, toolResult, memoryRetrieval, memoryFactAdded, memoryFactUpdated, memoryFactForgotten, turnEnd |
ReplaySession |
Session-level rollup (multiple turns) |
ReplayPaths |
Path resolver |
Depends on
AgentCore, Config, Logging. External: swift-log.
Used by
App/AppDelegate, packages/AgentCore (AgentOrchestrator is the primary writer), packages/Memory (writes mutation + retrieval events), App/MCP/ReplayingToolResultObserver.swift (writes pre/post sanitize bytes).
Key invariants / contracts
ReplayLogis the single writer per session file. Multi-writer is undefined.turnNonceis persisted in replay rows but never on the bus (SEC-06).- Pre- and post-sanitize bytes both go to replay (SEC-07). The model only sees post-sanitize.
replayLog.beginSessionis called before any turn. Pre-audit BLOCKER fixed (audit-2026-05-04).- NDJSON format. Each line is one event, JSON-encoded. Newline-delimited; no leading/trailing whitespace within events.
Tests
XCTest. Round-trip serialization tests, session rollover, file-handle leak detection (packages/Harness/FDLeakDetector SEC-08).
Notable files
Sources/Replay/ReplayLog.swift— the writer actorSources/Replay/ReplayEvent.swift— event unionSources/Replay/ReplaySession.swift— session rollup