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>
136 lines
8.5 KiB
Markdown
136 lines
8.5 KiB
Markdown
# 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).
|