End-to-end smoke against the live coolify memory stack surfaced three
gaps between the spec and what memory-api actually writes:
1. memory-api wraps the /ingest payload under `metadata.*` in Qdrant —
our domain fields (fact_type, scope.states, …) don't live at the top
of the payload, they're nested. `build_qdrant_filter` now auto-prefixes
any non-top-level key with `metadata.`. Callers can write
`{"fact_type": "legal"}` and it just works; top-level fields
(`agent_id`, `memory_type`, `source`, …) pass through unprefixed.
2. The deployed BGE-M3 TEI image doesn't serve /embed_sparse (returns
424 Failed Dependency). Stored points have `has_sparse=false`.
`BGEClient.embed_sparse` now returns `{}` on 4xx and logs a warning;
`QdrantReader.hybrid_query` falls back to a dense-only query when
sparse is empty. RRF fusion is skipped in that path.
3. `scripts/smoke.sh` had a missing `shift` after reading the limit
positional arg — caused arg leakage onto the CLI (`--limit 5 5`).
The cleanup hint also referenced a stale agent_id; now reads from
$ARTENSCHUTZ_AGENT_ID.
Smoke is now green end-to-end: 18 records ingested across bnatschg /
mhbasp / biotopwertliste(BY) / state-berlin under
agent_id=gruenstifter_smoketest, hybrid + payload-filter searches all
return hits. 24/24 unit tests pass.
Companion fixes pushed to github.com/machine-machine/agent.memory.system:
d0e9529 fix: /memory/store passed wrong kwarg name to AgentMemory
ebc896c fix: don't close caller-supplied clients in AgentMemory.close()