Before anything got built, I commissioned two research passes rather than trusting the design conversation’s own confidence. The first covered the overall architecture, tooling and hardware landscape; the second, retrieval evaluation for a store this small, plus entity resolution and dedup at write time. Both were run because reasoning from a chat’s own prior notes just regenerates its own errors — the same discipline that later caught the bitemporal bug covered in theme-bitemporal-supersession.
The embedding model question
The headline candidate was EmbeddingGemma-300M — small, multilingual, competitive on MTEB alongside snowflake-arctic-embed-m-v2.0 and gte-modernbert-base. It stayed the candidate to earn its way in, not the default. The actual pick for the store as it exists is bge-base-en-v1.5, with EmbeddingGemma held as a later, gated A/B — Decision G’s own framing was explicit that the spread between leaderboard entries was a few points, and the golden set, not the leaderboard, is the real arbiter.
The hardware constraint that shaped this: the Quadro P400 is a Pascal-generation card, and Pascal has a well-known fp16 landmine — running a modern embedding model natively on it directly hits that wall. The workaround, surfaced by the research rather than discovered by trial and error at the keyboard, was to run everything through Ollama-served GGUF quantised builds, which sidestep the fp16 problem entirely. One genuine papercut the research caught in advance: the exact base-en-v1.5 tag isn’t published cleanly by Ollama — the off-the-shelf tags skew to large and zh variants — so it needed pulling the CompendiumLabs GGUF and wrapping it in a one-line Ollama Modelfile rather than a clean ollama pull. Finding that in a search rather than at the keyboard was exactly the point of running the pass at all; I hit that step for real later and it was a non-event.
The P400 versus CPU question got its own small research verdict: acceleration buys nothing perceptible at thirteen nodes. The reason to use the GPU anyway isn’t speed, it’s the DNS-degradation problem from 02-architecture-decisions — keeping embedding load off the contended Xeon.
Retrieval evaluation and entity resolution
The second pass looked at how existing tools do fuzzy matching and deduplication at write time, and the finding shaped the write gate almost as much as the human-approval decision itself: real record-linkage machinery, the kind used in scientific data-matching, is serious overkill for one person’s project history. What I actually wanted was simpler and more disciplined — candidate matches surfaced automatically at two tiers, a closer-match band and a weaker “worth a look” band, with a human deciding anything above the threshold. Never an automatic, silent merge. That’s the shape mem-local’s entity resolution took, and it’s a direct answer to one of the seven failure modes named in 01-origin-and-requirements: conflating similar entities.
Worth being precise about the word here, because the store has two unrelated things both called “confidence.” This candidate-matching score (cosine similarity blended with fuzzy string matching) is real and does something — it’s what ranks merge candidates at the approval gate. The confidence column on every stored assertion is a different thing entirely, and it does nothing: the write-gate page covers why.
The comparison against off-the-shelf personal-memory tools done in this window is the same material behind theme-comparison-home-lab-patterns — most tools either never forget (unbounded accumulation, ranked by similarity at query time) or forget silently (an opaque summarisation pass that quietly rewrites history into something shorter and less precise). Neither gives append-only, bi-temporal truth.
The fork base, checked rather than trusted
Part of this stage was verification, not just research: before the build spec got written, the fast-moving facts underneath it got checked against reality rather than assumed. Five of six checks were routine confirmations (sqlite-vec had started shipping alpha ANN indexes, which didn’t matter at this scale but corrected a stale note; the Streamable HTTP transport choice was current and Origin-header validation turned out to be spec-mandated rather than optional; the embedding-model landscape hadn’t shifted enough to reopen anything). The sixth — the memorygraphMCP fork base — failed outright, and that failure is significant enough to have its own page: the archived write-up and the fuller story in theme-graph-not-vector-dump.
What this stage actually bought
Both research passes ran before commitment, which is the only point of running them. The embedding papercut got found in a search instead of at the keyboard. The fork base’s failure got found by reading source instead of trusting a README. And neither pass reopened anything that was actually load-bearing in the Stage 1 requirements — a decent sign the requirements-first ordering in 01-origin-and-requirements was doing its job. Anything that didn’t serve a named gap stood out as over-build and got dropped before it cost anything.
Sources: File review and prompt execution, 18 Jun 2026; Project planning and workflow development, 18 Jun 2026; Bitemporal personal memory system design review, 19 Jun 2026; Why we rejected basic memory, 19 Jun 2026; earlier, unpublished notes verification-pass-fork-base-fails; Decision G (chat:ai-memory-system-oversight-2026-07-20).