Sprint 20 closed: tools that answer questions, and traces that prove they do
Until this sprint, Meronq's product tools introduced themselves the way connectors do: by naming the system they talk to. github_sync, memory_search, project_build. Accurate labels — and the wrong unit for a host assistant that is trying to finish a job.
Sprint 20 flips the surface to the question each tool answers, leaves a trace on every call, and finally writes into the two CEM layers that Sprint 19 left empty on purpose.
Tools by intent
Product tool descriptions in @meronq/mcp-core are now questions. Handshake next_steps name the tool to call next, not a vague suggestion. The ListTools payload grew — 12245 → 13285 bytes — because question-form copy is longer; consolidation stays deferred. ADR-0018 prices that trade explicitly: we measured before and after instead of guessing.
memory_search gained a layer filter so the closed axis from ADR-0019 is reachable from chat, not only from the Temperature Map chips.
The empty layers get writers
project_build and project_test used to throw their outcomes away. They now persist bounded CEM entities:
| Tool | Entity | Layer |
|---|---|---|
project_build |
build_result |
artifact |
project_test |
test_run |
validation |
Retention is the latest ten of each kind. Results survive CEM rebuild via extractRuntimeCem, and they are excluded from the archive sweep so a green build does not vanish because nothing touched it for a week.
Instrumentation that can prove it
Every product tool records an access event when a project is resolvable — not only handshake and memory_search. The MCP initialize clientInfo (name + version) is threaded into that context, so later focus-steering work can answer which assistant asked without inventing a side channel.
Scripts under scripts/ capture the cheap metrics this sprint owns: tool-list bytes and accessor / query histograms from the local memory DB.
Init and cold Connect
Two Desktop paths were lying by omission:
- Initialize an empty folder now seeds
docs/roadmap.md(Sprint 0),docs/product/vision.md, and an ADR stub, then scan/syncs so Tasks and the map show a sprint immediately — template CEM until Sprint 21 embeddings. - Cold Connect — a repo that already has docs but no
.meronqstore — materializes.meronq/localviaensureLocalStoreand scan/syncs without inventing docs into a foreign tree. Connecting without a roadmap still creates the store and does not invent a sprint.
Dogfood in a throwaway subfolder covered Initialize, cold Connect, and the negative case; the folder was deleted after green.
Scanner fixes on the same train
Duplicate sprint numbers collapsing into one sprint:{n} entity, and conflicting dependency ranges silently keeping the first while declaredIn listed both, landed on main as #44 (sprintKeys, ranges / rangeByManifest). They ship with this sprint's closure story because they unblock honest intent and resource graphs.
Review notes
Code review on 9f63d3c (architecture focus): no medium+ defects blocking ship. Intentional double-counting remains for handshake / memory_search (richer in-handler rows plus the new tool-level row with client attribution). Tool-list bytes moved the wrong way for "cheaper context" — measured and accepted until a consolidation sprint. Focus steering stays out of scope until these access numbers exist in the wild.
Still open
Sprint 21 takes semantic retrieval (ADR-0020): keyword-first memory_search with a bundled embedding fallback for bilingual miss cases. Focus steering waits on real per-client access histograms from this sprint's substrate.
Principle
Name the question, leave a trace, and fill the layers you claimed were empty — then measure whether the surface got cheaper or just clearer.