m2-market/specs/001-market-first-wedge/research.md
m2 (AI Agent) 8757c6b620 factory-loop(plan): 001-market-first-wedge — plan, research, data model, 5 contracts, quickstart
Rail-independence is the plan's spine: fedlearn rails verified NOT landed
(no m2/m2-core, no capture/curator CLIs), so the wedge builds against frozen
interfaces — m2/market-registry as registry of record, ApplyAdapter seam with
local adapter now / m2core-sync stub, schemas frozen here with a fedlearn
coordination note. Constitution check passed (1 justified deviation).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 02:15:24 +02:00

8.5 KiB

Research — 001-market-first-wedge (Phase 0)

All NEEDS CLARIFICATION items from Technical Context resolved below. Sources: CONCEPT.md v0.2, context/SYSTEM-MAP.md (verified 2026-07-01), live probes 2026-07-02, operator steer (README §open-forks edit 2026-07-02), Constitution v1.0.0.

R1. Ledger substrate

  • Decision: standalone m2-ledger — FastAPI + SQLite (WAL), single-writer Coolify app on the coolify network, X-API-Key auth (same pattern as memory-api). Ledger API kept strictly separable from storage (repository layer) so a future migration into extended m2-gpt billing — including the operator's noted crypto-ledger direction — is a backend swap, not an API break.
  • Rationale: operator confirmed standalone-now (README steer); m2-gpt gateway already meters tokens/tenants, so the ledger federates (reads identity, later maybe settlement) rather than duplicating; SQLite is constitution-VII-simple and one service is the only sanctioned new component.
  • Alternatives considered: extend m2-gpt billing (rejected for v1: couples marketplace release cadence to gateway deploys; revisit post-wedge per operator note); Forgejo-as-ledger (rejected: git is the audit trail, not a transactional store — race conditions on concurrent installs).

R2. Registry of record (fedlearn absence)

  • Decision: create Forgejo repo m2/market-registry: listings/<listing_id>/ directories (listing.json + evidence/ + bundle ref), Solution bundles attached as repo releases (<listing_id>-v<semver>), review = PR, veto = labels (veto, approved), merge = published. Daily ledger snapshots commit to audit/ in the same repo.
  • Rationale: verified 2026-07-02 that m2/m2-core does not exist and the fedlearn herd has not started (fleet busy on m2-gpt work) — blocking on it would stall the wedge. Listings are commercial artifacts; a dedicated registry keeps the free-core/paid-market boundary physical (constitution IV). Forgejo is live today (forgejo skill available for API access).
  • Alternatives considered: wait for m2/m2-core (rejected: unlanded dependency); listings inside m2-core (rejected: erodes commons boundary); one-repo-per-listing (rejected for v1: heavier to administer; releases-in-one-repo suffices at this scale).
  • Integration seam: when fedlearn's curation pipeline lands, its commercialize disposition emits a PR against m2/market-registry — the registry's PR/veto protocol is the frozen interface (contracts/registry-layout.md).

R3. Schema freeze order (manifest superset problem)

  • Decision: freeze solution.schema.json v1 in this repo now, embedding the manifest-shaped core fields observed in the fedlearn plan's submission example (schema_version, applicability{image_classes,roles,tool_requirements}, tenant_scope, evidence[], content_hash, scrub status) plus commercial fields (price, seller, license, revenue_split). File a coordination note to the fedlearn effort: its final manifest must remain field-compatible with this core, or a v1→v2 schema migration is planned at integration.
  • Rationale: the spec (FR-001) requires a frozen contract; fedlearn's own schema task (their Task 1.1) is unexecuted, so "superset of the manifest" is only satisfiable by freezing our side and coordinating. Frozen interfaces are exactly how the constitution says to sequence around unlanded rails.
  • Alternatives considered: wait for fedlearn's freeze (rejected: unbounded wait); schema-less v1 (rejected: FR-001/FR-002 are explicit).

R4. Catalog partition mechanics

  • Decision: market:catalog as a memory-api partition (agent_id-style namespace, same BGE-M3 hybrid path as fedlearn:core-index was designed for). Writes go only through m2-market-indexer, which reads merged listings from m2/market-registry; reindex rebuilds the partition from scratch (constitution II rebuildability). Tenant filtering applied at query time via listing tenant_scope payload field.
  • Rationale: SYSTEM-MAP confirms memory-api live with partition model; one more partition is the assembly move. Known risk: the memory-api split-brain (two Coolify stacks) — fedlearn task T13 was to resolve it; until then the indexer targets the stack behind memory.machinemachine.ai and reindex makes recovery cheap.
  • Alternatives considered: separate Qdrant collection managed directly (rejected: bypasses memory-api auth + embedding pipeline); SQL full-text in the ledger DB (rejected: no semantic match, Scout needs embeddings).

R5. Install/apply path without m2-core-sync

  • Decision: define AdapterProtocol (contracts/apply-adapter.md): plan(bundle) → changeset, apply(changeset) → result, verify(bundle) → bool, rollback(changeset), all idempotent. v1 ships the local adapter: bundle = tarball release containing solution.json + payload/ + recipe.yaml (declarative file placements + post-install checks) applied into the operator's home/agent volume, with a state file (~/.m2-market/state.json) mirroring the fedlearn state.json design. m2core_sync adapter is a stub that errors with "fedlearn rails not landed".
  • Rationale: runtime-sync is the only universal path fleet-wide, but its implementation (m2-core-sync) doesn't exist yet; the adapter seam lets the wedge close SC-001 with the local adapter and swap in m2-core-sync without touching CLI or Store.
  • Alternatives considered: implement m2-core-sync ourselves (rejected: forks fedlearn's in-plan work, constitution's "consume, not fork"); flatpak-style backend from cargstore (rejected: desktop-app-shaped, not agent-bundle-shaped).

R6. Scout host (operator: "explore")

  • Decision: DEFERRED to a time-boxed spike (task in Phase 2; output scout/SPIKE.md) comparing: (a) standalone supervised watcher (hermes-gateway pattern), (b) Hermes plugin, (c) herdr plugin/hook. Spike evaluates: access to structured run summaries, opt-in policy enforcement point, on-box summarization cost, notification surface, and update/rollout story on both image classes. Scout v0 implements the spike's winner on ONE canary.
  • Rationale: operator explicitly marked this fork "explore"; Scout is P3/last-sequenced so the spike doesn't block the wedge gate (SC-001).

R7. Store surface

  • Decision: fork-branch m2-store on cargstore; keep Electron+React shell, replace Flatpak catalog source with market:catalog (via memory-api HTTP) and add an install backend that shells to m2-market install (one code path for FR-005 semantics). Auth: desktop's existing m2-gpt-issued credentials pattern (operator steer) — the store reads the same key material provisioned on the desktop, never stores its own secrets.
  • Rationale: operator steer ("MVP electron app... credentials from m2-gpt"); reusing the CLI for install guarantees ledger semantics are implemented once.
  • Alternatives considered: web-first (deferred per steer); re-implementing install in the store's Node side (rejected: two implementations of debit→grant→apply invites drift).

R8. Identity & wallets

  • Decision: operator_id = the operator identity from fleet.json tenancy (e.g. m2bd, sdjs-operator); wallets keyed by operator_id in m2-ledger; machine→operator resolution shipped as a small mapping in the CLI config (provisioned, not guessed). Starter grants issued via an admin-authenticated ledger endpoint (default 100 cr — UNCONFIRMED default, flagged).
  • Rationale: fleet.json is the existing identity substrate (constitution I); v1 needs no new auth system — API keys per service, operator mapping per machine.

R9. Testing strategy

  • Decision: pytest for ledger (property-style tests on derived balances: balance == fold(tx log) under generated tx sequences) and CLI (integration against a real local ledger instance + recorded Forgejo/memory-api fixtures); a scripted quickstart (quickstart.md) as the canary E2E gate; schema validation tests for all seeded bundles.
  • Rationale: SC-003/SC-004 are audit properties — property tests are the cheap way to hold them; canary E2E is the constitution-VI rollout gate.

Open coordination items (not blockers)

  1. Coordination note → fedlearn effort: manifest/schema field-compat with frozen solution.schema.json v1 core (R3).
  2. memory-api split-brain (fedlearn T13): until resolved, indexer pins the public endpoint; reindex is the recovery path (R4).
  3. Operator confirmations outstanding: platform cut 10%, starter grant 100 cr (spec Assumptions; ledger ships them as config, not constants).