# Contract: market:catalog partition (memory-api) (v1) The semantic index over published listings. Derived data only — rebuildable from `m2/market-registry` at any time. ## Partition - Namespace: `market:catalog` (memory-api partition, same mechanism as `fedlearn:core-index` design). - Document = one published listing: embedded text = `name + summary + keywords + intent + evidence_summary` (BGE-M3 hybrid dense+sparse); payload = full `listing.json` + `tenant_visibility`. - Endpoint: the stack behind `memory.machinemachine.ai` (split-brain caveat: research.md R4 — pinned until fedlearn T13 resolves; recovery = reindex). ## Writers ONLY `m2-market-indexer`: - `watch` — on registry merge (webhook or poll ≤5 min), upsert changed listings, remove delisted. - `reindex` — drop partition, rebuild from registry `main` (constitution II gate; must complete < 5 min at wedge scale). ## Readers - CLI `m2-market search` → memory-api semantic query, **server-side filter** `tenant_visibility ⊇ {caller tenant | "*"}` (FR-007; Scout edge case "impossible by construction"). - M2 Store front page/search → same query path (via CLI or direct HTTP with desktop creds). - Scout matcher → same query path, additionally thresholded by confidence. ## Query contract (via memory-api HTTP) Request: `{query_text, partition: "market:catalog", tenant, limit}` → Response items: `{listing_id, score, listing: }` ordered by hybrid score. ## Telemetry write-back (FR-012, FR-014) Install + proposal events land as memory records in `market:evidence` partition keyed by listing_id; a periodic indexer pass folds counts into `stats` in the registry (PR-less stats commit or scheduled batch PR — implementation's choice, registry remains truth). ## AS-BUILT AMENDMENT (2026-07-02, analyze finding I1) The live memory-api (agent.memory.system) exposes `/memory/store` + `/memory/search` only — no partition drop, no delete, no upsert-by-id, and its server-side tenant filter is a scalar `tenant_id` (not an array match). The implementation therefore deviates: - Partition = the `agent_id` namespace; documents are memories with the listing in `metadata.listing` and `metadata.listing_id`. - Writer upsert = search-first for `metadata.listing_id`, store only if absent (idempotent fill). Listing UPDATES and delist removal require memory-api delete — until then, delisted/updated listings are filtered/handled at read time. - Reader tenant filter `tenant_visibility ⊇ {caller tenant | "*"}` is enforced in the ONE shared reader client (`cli/src/m2_market/catalog.py`), which every surface uses. - Full rebuild = fresh-partition switch (`MEMORY_API_PARTITION` writer-side, `M2_MARKET_CATALOG_PARTITION` reader-side) — docs/runbook.md. The original section above is retained as the target contract for when memory-api grows partition CRUD (fedlearn T13 follow-up).