The RAG section still described the pipeline as originally specced, not the
one that runs: fixed-size chunking, keyword-only retrieval, a schema without
kind or content_hash, and an `Indexer` type that does not exist. Someone
reading it to understand the retrieval path would have been wrong about every
part of it.
Section 4, rewritten:
- 4.1 documents both source kinds, the README skip, the frontmatter exclusion
and the ### sub-split, each with the failure that motivated it.
- 4.2 replaces the BM25-only pipeline with hybrid retrieval, and explains why
RRF rather than a weighted blend, what happens when the embedder is down,
and why vectors carry a content hash.
- 4.3 swaps the fictional code sketch for the real schema plus an API table.
- 4.4 documents prompt assembly in the order the code does it, why there is
exactly one system message, and the three attempts it took to get the
language right.
- The banner at the top listed four decisions as pending. All four are now
made and measured, including the one it got wrong: BM25 was strong on the
corpus but the questions arrive in Spanish, which is a translation problem
a trigram tokenizer does not solve.
- 4.5 claimed a ~3k-token system prompt leaving room for 2–3 turns. Measured,
the largest prompt is 1255 tokens and compaction never fired in the whole
benchmark.
Elsewhere:
- §2 adds the embeddings server and internal/embed; the stack table said
qwen2.5:1.5b while the config ships 3b.
- §6.1 and §8.1 did not deploy the architecture being described: no embedder,
no --device none, no --parallel 1, no sampling flags, and a systemd unit
that started only the bot. §8.1 now has all three units and the memory
budget.
- §9.4 lists the retrieval tests, since a regression there is silent.
- §11 marks the phases that are done, records where the widget deliberately
diverged from the plan (vanilla JS, not React + Tailwind), and keeps the
three known unfixed answer-quality issues.
- §12.1 replaces aspirational targets with measured numbers, and says plainly
that TTFT <500ms and end-to-end <3s are not met on 2 CPU cores and why that
is the accepted trade.
Both language editions updated in step.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>