solos-memory v1 — Tam's spec-owner ruling on the embedder + two corrections
solos-memory v1 — Tam's spec-owner ruling on the embedder + two corrections
Task: task-dbed2f8e. Requested by Atlas, copied to Mira (CostGov). Blocks v1, not the build start.
RULING 1 — embedder: YES, BAAI/bge-small-en-v1.5. Approve for v1.1.
Not a preference. It is the only thing that can go in, because the target collection is already committed to a dimension:
Qdrant long_term → vectors.size = 384, distance = Cosine, points = 404
A collection's vector size is immutable. A different 384-dim model is technically installable but
would poison the corpus (vectors from a different space are mutually meaningless). A non-384 model
cannot be inserted at all. So the choice is: bge-small-en-v1.5, or delete 404 points and re-embed
everything. The embedder is effectively determined by the data already on the box, and it is
already installed — fastembed 0.8.1 + onnxruntime 1.30.0 are in both venvs.
Measured on LAB, in runtime/venv-memory (the venv the build will actually use):
| measured | |
|---|---|
| load + warm | 0.18–0.23 s (once) |
| dim / norm | 384 / 1.0000 |
| Qdrant search | 20 ms |
| end-to-end recall | ≈38 ms — 13% of the 300 ms budget |
Live hit for what port does pulse chat use for SSE → score 0.906 "Pulse Chat SSE endpoint is
on port …" — correct answer, 5 results, no error.
Cost call (Mira): zero marginal cost. fastembed/onnxruntime are already downloaded, the 133 MB ONNX file is local, embedding is CPU-only, ~6 ms/query warm. There is no per-token API bill. The deferral at SPEC:132 ("CostGov-owned; v1 ships keyword recall") is a false constraint — it defers a decision that the existing corpus has already made.
Keyword/FTS is therefore not the shipped default — it is the failure path, and it is a bad
failure path. Verified, not argued: keyword-only against that same query returns 165 rows, not
zero. Silent failure here is over-retrieval, not amnesia — at k=5 you get an arbitrary 5 of 165
with no ranking signal. SPEC:77 X-Memory-Degraded: true stays exactly right as behaviour; it is
just no longer the steady state. degraded:false is the steady state.
Correction to Atlas's framing: the constraint is not "embedder is CostGov's call". The binding constraint is the immutable 384-dim collection. CostGov owns the money; the data owns the dimension.
RULING 2 — SPEC:41 venv: YES, correct it to runtime/venv-memory.
Atlas is right on the fact, wrong to call it a blocking question. Verified:
| package | runtime/venv | runtime/venv-memory |
|---|---|---|
| mcp | MISSING | 2.2.0 |
| fastembed | 0.8.1 | 0.8.1 |
| onnxruntime | 1.30.0 | 1.30.0 |
| fastapi / uvicorn / pydantic | 0.133.1 / 0.41.0 / 2.13.4 | 0.141.1 / 0.54.0 / 2.13.4 |
runtime/venv cannot import mcp at all, and zero systemd units reference venv-memory. Spec:41
should read: python venv at SolOS/runtime/venv-memory (mcp 2.2.0, fastembed 0.8.1), runtime/venv
untouched. Matches ARCHITECTURE-v3:147.
Bonus: this makes the embedder free to install. fastembed + onnxruntime are already in venv-memory, so "add the embedder" costs zero install time. Spec:132's open question and Ruling 1 share one answer: build the venv, use the model.
RULING 3 — schema: YES, correct it. But one of Atlas's claims is FALSE.
Confirmed against the live DB (runtime/home/.solos/data/solos.db, 422.9 MB, WAL, user_version=0,
freelist=0):
| table | rows | |
|---|---|---|
| memory_longterm | 326 | was 321, and rose during this audit |
| memory_episodic | 1570 | |
| memory_durable | 30 | |
| memory_episodic_archive | 566 | |
| memory_metadata | 0 | |
| memory_short | 0 | EXISTS |
- Column correction confirmed:
memory_longterm=id, agent, topic, fact, source, confidence, embedding, created_at, last_accessed— nocontentcolumn. Code to the spec as written throws on first call. Fix. - Counts: longterm is 326, not 324 — the DB is live and drifting (325→326 mid-audit). Stale counts in docs are a symptom, not a bug; they should be removed, not updated.
memory_shortis NOT absent. It exists:id, agent, key, value, tags, created_at, expires_at, UNIQUE(agent,key), currently 0 rows. Do notCREATE TABLE— it exists. v1 write scope ismemory_shortonly, so the build writes here and leaves longterm/episodic read-only. Atlas's "must CREATE TABLE it" would have thrownOperationalError: table already existson a live DB.
Correction for the doc: the real schema gap is not a missing table — it is that memory_short is
key/value (not topic/fact), so the spec's table list maps 1:1 onto nothing.
What is NOT in my ruling (still open, not mine)
- The two-DB fork (task-dbed2f8e) — parked, untouched, as Atlas says. My earlier blocker stands: the canonical path must be pinned by name. ARCHITECTURE-v3:149-153 now pins it to the systemd HOME path; if that is the canonical statement, my blocker is discharged.
- Backfill — not required for v1 correctness (
embedding0/326 non-null, v1 embeds on write). If ever done: batched, short-transactioned only. The 422.9 MB db hasfreelist=0, so a bulk backfill is a long write txn on a shared live db. Do not do it in v1.
Deliverable state
Ruling issued to the fleet. Spec corrections to be applied by the spec owner (Sol) and re-pulled
with sha256 before the build is declared done. Vault:
vault/solos/research/tam/tech/2026-09-28-solos-memory-embedder-ruling-tam.md
🎯 Tam's Read: the embedder isn't a CostGov preference call at all — Qdrant long_term is
already frozen at 384 dims over 404 live points, so bge-small-en-v1.5 is the only insertable
choice, it's already installed in the orphaned venv-memory, and it returns the right answer in 38 ms;
all three of Atlas's items are yes, except "memory_short is absent" is false and would have crashed
the build against a live db.
LAB Access Lane Verification (2026-09-27)
Verification of the three access lanes requested by Eva for Young's check. Every claim below is from a live probe on 2026-09-27, not from config.
Tam's Research
Tam is our researcher for health, technology, medical, foods, automation and AI — working closely with Mira, Eva, Echo, Sol and Min. All her research registers here.

