Rômulo Febasi <romulo@febasi.com.br> (analysis assisted by Claude Code)
Scope
Post-mortem read of the v0.4.0 release (2026-05-27): what landed, what architectural debt re-grew, what the README failed to advertise, and the prioritised next-three-actions before v0.5 code starts.
Status
accepted: input to the v0.5 brief and to the README §Status refresh (commit b37a418)
Inputs
Repository walk on 2026-06-02; find src/ -name '*.rs' | xargs wc -l; cross-read of ADR-015 vs current file sizes; CHANGELOG.md from the auto-generated v0.4.0 section; live gh issue list --milestone "v0.5 Semantic layer"; live gh issue list --milestone "v1.0 Stable".
Out of scope
The v0.5 brief itself (separate document, same day). Code changes: only audit + recommendation.
v0.4 shipped 18/18 tickets in two weeks (12 core + 6 stretch), four releases in
that window, zero rollback. The product moved from “auditable AI second brain”
to “auditable AI second brain with cross-editor LSP + portable identity v2 +
real MCP sampling”. For a solo project that is delivery above the curve.
But the ride exposed three honest items that need to be flagged before v0.5
code begins: (1) src/mcp/server.rs regrew to 844 lines, breaking the
red-tier threshold of the very ADR-015 that v0.4 wrote to contain it: SYN-150
split the file, then SYN-136 (replay_proposal) and SYN-138 (reindex)
brought ~300 lines of new handlers back in. (2) the README §Status only listed
v0.1 + v0.2 until 2026-06-02: three releases were invisible to anyone
landing on the repo, including the entire LSP companion that is the most
differentiated single artefact of v0.4. (3) v0.5’s GitHub milestone has 11
issues but no brief: v0.4 worked because it had one; starting v0.5 code
without one is committing to architectural decisions inside the largest
backend module rewrite of the project so far.
v0.4.0 tagged + pushed 2026-05-27 03:31; mirror release synchronised 12 s
later (run 26489555101). Cross-platform assets present for aarch64 +
x86_64 macOS, aarch64 + x86_64 Linux GNU, x86_64 Windows MSVC. Smoke test of
the public mirror binary on the author’s laptop (aarch64-apple-darwin)
confirms 15 MCP tools advertised including reindex and replay_proposal.
121 unit tests pass on the full feature matrix (mcp lsp mcp_tasks); zero
clippy warnings under -D warnings; cargo doc clean.
v0.5 milestone holds 11 issues (SYN-80..SYN-89 + SYN-93b network
freshness) filed during the original v0.5 planning sprint in 2026-05-24.
No code changes are being proposed in this document, the changes that
matter (re-split, brief, benchmark spike) are recorded as ticket sketches
for the v0.5 brief that ships next to this file.
Carries 15 #[tool] handlers + ServerHandler impl + resource/prompt routing. SYN-150 reduced it from ~1380 → ~550 on 2026-05-25; SYN-136 added replay_proposal (~120 lines including the sampling builder), SYN-138 added reindex with the tasks progress callback shim (~80 lines), SYN-140 added the Redactable wiring at the call sites (~10 lines), plus the docstring expansion. Net: back to red tier two weeks after the split.
What this means: ADR-015’s playbook (split when red, target < 500) was
followed once and then quietly disregarded by every subsequent MCP feature.
The pattern is recurring because #[tool_router] in rmcp 1.7 mandates one
impl block: every tool handler has to land in the same file, so the
attractor pulls every new MCP feature back here. The split that holds long
term is not a second pass of the same kind (extracting helpers) but a
dispatcher pattern: keep #[tool] shims thin (3–8 lines each) and move
all logic to core::mcp::* use case modules outside the macro’s reach.
Notably core/at.rs (the SYN-142 sandbox builder, 339 lines) and
lsp/server.rs (437 lines) landed well within the green tier. The trait
Redactable (SYN-140) reduced what would have been ~60 lines of duplication
across three call sites into one trait + two impls. These are the v0.4 wins
that the file-size scoreboard rewards.
There are at least four decisions baked into the v0.5 milestone issues
(SYN-80..SYN-89) that were not load-bearing-discussed before they were
opened on 2026-05-24:
Embedding backend. ADR-008’s slot says “chosen default embedding
backend after benchmark” but no benchmark was run before the issues
were filed. Three real candidates: Ollama-as-runner (forces external
dep), fastembed-rs (ONNX Runtime under the hood, ships small
models), pure candle (HuggingFace’s Rust framework, no ONNX
dependency). The trade-off: local-first vs perf vs binary size, needs a 1-day spike with numbers before SYN-83 starts.
Vector storage choice. SYN-81 says “sqlite-vec via load_extension”.
sqlite-vec is real, recent, used in production. But the combination
of rusqlite bundled + load_extension has known ABI gotchas
(Alex Garcia documents them explicitly). If sqlite-vec fails the
spike, the fallback is lance (full vector DB) or a hand-rolled
flat / HNSW index: both larger architectural decisions than the
issue title implies.
Hybrid ranking algorithm. SYN-86 says “reciprocal rank fusion”.
RRF is the cold-start default (Elastic, Qdrant, Weaviate, OpenSearch
ship it). But 2026 papers show convex combination (`α * dense + (1-α)
bm25`) outperforming RRF with as little as ~40 labelled relevance
pairs. For a personal second-brain workspace that pair set is
self-collectable. RRF is right for v0.5 ship; convex combination is
the next-step polish.
Search target. Is syn search hybrid by default, or vector-only
behind --semantic? SYN-87 reads “vector-only mode” which suggests
the second; SYN-86 reads “hybrid” which suggests the first. The two
tickets are inconsistent. The brief needs to pick one.
Write the v0.5 brief: docs/researchs/YYYY-MM-DD-v0.5-…: with the 4 strategic decisions above answered with reasons and a benchmark spike for the embedding backend
2 days (1 day brief, 1 day spike)
v0.4 worked because the brief did the load-bearing thinking; v0.5 touches the largest single new module (vector index) and the biggest external choice (embedding backend): committing without a brief is committing to commit-driven design
2
File SYN-151: re-split mcp/server.rs to the dispatcher pattern (thin #[tool] shims, logic in core::mcp::*) before any v0.5 MCP feature lands
½ day
ADR-015’s red tier exists for this exact file. Every new MCP feature in v0.5 (semantic_search per SYN-88, reindex_vectors) lands here. Pay now or pay 3× later.
3
Visibility polish: README §Editor integration section + Homebrew tap (antecipate SYN-102) + asciinema demo of syn lsp
1–2 days
v0.4’s most differentiated single feature (cross-editor LSP) was undiscoverable until 2026-06-02. Polish converts what’s already built; it does not gate v0.5.
Which embedding backend: Ollama (~700 MB binary + ~280 MB model = ~1 GB
footprint, external dep) vs fastembed-rs (~10 MB crate + ~33 MB BGE-small
quantised, embedded inference via ONNX Runtime) vs pure candle (no ONNX,
more flexibility, slower per-query)? Bias from the owner: local-first,
no Ollama. Brief must show the trade-off with numbers.
Vector storage: sqlite-vec (lean, in-process, recent), lance (full
vector DB, heavier), or hand-rolled flat / HNSW? Spike before
committing.
Hybrid ranking: RRF (cold-start safe) or convex combination (better with
labelled data: does a single-user workspace have those?).
Default mode for syn search: hybrid by default, vector-only behind
--semantic flag, or the inverse?
Insertion-time vs query-time enrichment. The owner explicitly stated
2026-06-02: “ao invés de usar puramente um LLM para isso, é organizar e
processar esses dados no momento que estamos inserindo eles”. This is a
business rule (BR-13 candidate) and changes the v0.5 architecture
meaningfully: entity linking happens on syn project add, not on
syn search. The brief codifies this.
Adoption polish: does it ship as a hot-fix v0.4.1 cycle, parallel to v0.5,
or after v0.5?