13 KiB
Tasks: M2 Marketplace — First Wedge
Input: Design documents from /specs/001-market-first-wedge/
Prerequisites: plan.md, spec.md, research.md, data-model.md, contracts/, quickstart.md
Tests: included where the design demands them (research.md R9: ledger property tests are how SC-003/SC-004 are held; schema validation guards the frozen contract).
Organization: grouped by user story. The wedge gate (SC-001, plan row 7) is reachable at the end of Phase 5 — Store (US4) and Scout (US5) are NOT on that path.
Format: [ID] [P?] [Story] Description
Phase 1: Setup (Shared Infrastructure)
Purpose: monorepo scaffolding per plan.md Project Structure
- T001 Create monorepo skeleton:
schemas/,ledger/,cli/,indexer/,solutions/,scout/,store/README.md(pointer file) per plan.md structure - T002 Initialize uv workspaces:
ledger/pyproject.toml(fastapi, uvicorn, pytest),cli/pyproject.toml(click, httpx, pytest),indexer/pyproject.toml(httpx) — Python 3.12 - T003 [P] Configure ruff + pytest defaults at repo root (
pyproject.tomltool sections shared via workspace)
Phase 2: Foundational (Blocking Prerequisites)
Purpose: the frozen contracts everything else builds against
⚠️ CRITICAL: no user story work until this phase completes
- T004 [P] Author frozen
schemas/solution.schema.jsonv1 per data-model.md Solution table (manifest-core + commercial fields; validation rules incl. evidence non-empty, tenant_scope firewall attestations) - T005 [P] Author frozen
schemas/listing.schema.jsonv1 per data-model.md Listing table (incl.statsconversion-signal fields,statusenum,install_ref) - T006 Write schema validation test fixtures in
schemas/tests/(valid + invalid examples for both schemas; invalid must include: missing evidence, tenant_scope violation, bad price) and ajust validate/ pytest runner - T007 Create Forgejo repo
m2/market-registryper contracts/registry-layout.md: layout dirs, PR template (evidence/price/permissions/rollback), CI validation job (schema-validate listings, content_hash check), veto/approved label protocol — use the forgejo skill/API - T008 [P] Write fedlearn coordination note
docs/fedlearn-coordination.md: frozen solution-schema core fields that the fedlearn manifest must stay superset-compatible with (research.md R3), the commercialize→registry-PR seam (R2), and the m2core-sync adapter swap acceptance (contracts/apply-adapter.md); deliver a copy to /home/m2/m2o/.planning/federated-learning/proposals/ - T009 [P] Define shared config conventions doc
docs/config.md:~/.m2-market/config.tomlkeys, env vars for services, key classes (service/admin) — from contracts/cli.md + ledger-api.md
Checkpoint: schemas frozen, registry live, coordination recorded
Phase 3: User Story 1 — Paid install via CLI (Priority: P1) 🎯 MVP
Goal: search → show → install closes debit→grant→apply on a real machine
Independent test: quickstart.md Scenarios B + C against a deployed ledger with one published listing
Ledger core (contracts/ledger-api.md)
- T010 [P] [US1] Implement tx + grant models and derived-balance queries in
ledger/src/m2_ledger/models.py(SQLite WAL, append-only invariants, data-model.md Transaction/LicenseGrant) - T011 [P] [US1] Implement X-API-Key auth (service/admin key classes) in
ledger/src/m2_ledger/auth.py - T012 [US1] Implement API routes
/health,/balance/{op},/tx/install,/tx/refund,/tx,/license/{op}/{listing}inledger/src/m2_ledger/api.py(402/409 semantics, all-or-nothing install tx, idempotent by ref) - T013 [US1] Ledger unit + property tests in
ledger/tests/test_properties.py: balance==fold(log) under generated sequences; no grant without tx; install atomicity; duplicate-ref 409 - T014 [US1] Dockerfile + Coolify deployment for m2-ledger on the
coolifynetwork inledger/Dockerfile+ledger/README.mddeploy notes; verifyGET /healthfrom the network - T015 [US1] Create
market:catalogpartition and implement indexerindexer/src/m2_market_indexer/reindex.py+watch.pyper contracts/catalog-index.md (registry → memory-api upsert, tenant_visibility payload, delist removal)
CLI (contracts/cli.md)
- T016 [P] [US1] CLI package scaffold + config loading (
~/.m2-market/config.toml, operator mapping) incli/src/m2_market/cli.py(click group,--json, exit-code map) - T017 [P] [US1] Ledger client in
cli/src/m2_market/ledger.py(install/refund/balance/license calls, error mapping to exit codes 3/4) - T018 [P] [US1] Registry client in
cli/src/m2_market/registry.py(fetch listing dirs, download release bundle, verify content_hash) - T019 [P] [US1] Catalog client in
cli/src/m2_market/catalog.py(memory-api semantic query, server-side tenant filter param) - T020 [P] [US1] ApplyAdapter protocol + InstallState in
cli/src/m2_market/apply/base.pyper contracts/apply-adapter.md (Changeset, plan/apply/verify/rollback, state.json read/write) - T021 [US1] Local adapter in
cli/src/m2_market/apply/local.py: recipe.yaml-driven file placement into agent-home, post-install checks, idempotent re-apply, rollback from backups - T022 [US1]
m2core_syncstub adapter incli/src/m2_market/apply/m2core_sync.pyraising RailsNotLanded (exit 6) - T023 [US1]
search+showcommands incli/src/m2_market/cli.py(catalog query → table/JSON; show renders evidence/price/permissions diff) - T024 [US1]
installcommand incli/src/m2_market/cli.py: the FR-005 sequence (confirm → debit → fetch → apply → verify → refund-on-failure → state → entrypoint hint) per contracts/cli.md - T025 [US1]
walletcommand incli/src/m2_market/cli.py(balance + recent tx) - T026 [US1] CLI integration tests in
cli/tests/test_install_flow.pyagainst a local ledger instance + fixture registry/catalog: funded install, insufficient funds (no side effects), idempotent re-run, apply-failure refund
Checkpoint: Scenario B/C pass end-to-end with a fixture listing (SC-003/005 held locally)
Phase 4: User Story 2 — Publish a Solution with evidence (Priority: P1)
Goal: builder → validated listing PR → veto window → published → discoverable
Independent test: quickstart.md Scenario A
- T027 [US2]
publishcommand incli/src/m2_market/cli.py+cli/src/m2_market/publish.py: validate bundle against schemas (exit 5 on violation incl. tenant firewall), pushlisting/<id>branch, open PR via Forgejo API with template - T028 [US2] Registry CI hardening in
m2/market-registryCI config: evidence-required, owner-initiated + double-scrub attestations for tenant-scoped submissions, content_hash-vs-release check (Story 2 AC-2/AC-4 mechanical rejection) - T029 [P] [US2] Package seed Solution
solutions/mm-pdf-report/(from the proven mm-pdf outcome): solution.json, payload/, recipe.yaml, real evidence refs - T030 [P] [US2] Package seed Solution
solutions/agent-scaffold/(from the agent-scaffold skill outcome): solution.json, payload/, recipe.yaml, real evidence - T031 [P] [US2] BLOCKED-ON-OPERATOR: competitor-scan seed has no real evidence (constitution III) — t031 report recommends substituting Parlobyg email-triage (tenant-derived: needs owner-initiated + double-scrub sign-off) or another proven outcome
- T032 [US2] Publish all three seeds through the real protocol (PRs, review, merge), verify each discoverable via
m2-market search(SC-002)
Checkpoint: ≥3 published evidence-backed listings live
Phase 5: User Story 3 — Wallets and starter grants (Priority: P2)
Goal: bootstrapable economy with auditable balances
Independent test: quickstart.md Scenario D + grant flow
- T033 [US3]
/grant/starteradmin endpoint inledger/src/m2_ledger/api.py+ config-driven default amount (100 cr flagged-unconfirmed) with tests inledger/tests/test_grants.py - T034 [US3] Snapshot module
ledger/src/m2_ledger/snapshot.py: balances dump → commitaudit/YYYY-MM-DD.jsonto m2/market-registry via Forgejo API;/snapshotadmin endpoint + daily cron (Coolify scheduled task or in-app scheduler) - T035 [US3] Issue starter grants to the two pilot operators (m2bd, sdjs-operator) and run Scenario D verification (snapshot committed, properties green)
🎯 WEDGE GATE (plan row 7, SC-001):
- T036 [US3] Execute the real paid install between two operators: m2bd buys one seeded listing published by sdjs-operator via
m2-market installon a real desktop; capture ledger rows, grant, applied bundle, and invoke the entrypoint; record evidence in.m2herd/context/and the run report
Phase 6: User Story 4 — M2 Store on canaries (Priority: P3)
Goal: one-click install UI over the same rails (work lands in the cargstore repo,
branch m2-store; contracts referenced from this repo)
Independent test: quickstart.md Scenario F on chris-m2o
- T037 [US4] Fork/branch
m2-storeon github.com/machine-machine/cargstore; swap catalog source from Flatpak JSON tomarket:catalogvia memory-api HTTP (desktop-provisioned creds per research.md R7) in cargstoresrc/catalog service - T038 [US4] Add Solution install backend to cargstore that shells
m2-market install --jsonand renders progress/result truthfully (incl. refund-on-failure path) in cargstoresrc/install manager - T039 [US4] Solution detail page: evidence, price, permissions diff (from
m2-market show --json) in cargstoresrc/UI - T040 [US4] Rebrand Clawdbot→M2 Store and deploy to canaries chris-m2o + gunnar-m2o only; run Scenario F
Phase 7: User Story 5 — Solution Scout v0 (Priority: P3)
Goal: in-the-moment proposals on ONE canary, privacy-guarded
Independent test: quickstart.md Scenario G
- T041 [US5] Scout host exploration spike →
scout/SPIKE.md: compare standalone supervised watcher vs Hermes plugin vs herdr plugin/hook on: summary access, opt-in enforcement point, on-box summarization cost, notification surface, rollout story per image class (research.md R6; operator fork §14.4 "explore") — time-boxed, ends with a decision - T042 [US5] Implement Scout v0 per SPIKE.md winner in
scout/(or plugin location the spike picks): summary ingestion → embed →market:catalogmatch (tenant-scoped) → threshold → toast + deep link; opt-in via pull-policy config; rate cap (default 5/day) - T043 [US5] Proposal outcome recording (shown/dismissed/accepted/suppressed) locally + summarized to
market:evidenceper data-model.md Proposal; conversion counts folded to listing stats via indexer telemetry pass - T044 [US5] Deploy Scout v0 to ONE canary opt-in desktop; run Scenario G (incl. opt-out and rate-cap negative checks)
Phase 8: Polish & Cross-Cutting
- T045 [P] Install telemetry write-back (FR-014): CLI posts install outcome records to
market:evidence; indexer folds into listingstats.installs—cli/src/m2_market/telemetry.py+ indexer pass - T046 [P]
reindexoperational check task: run Scenario E, document recovery runbook indocs/runbook.md(incl. memory-api split-brain caveat from research.md R4) - T047 Run full quickstart.md scenario sweep A–E on canaries; fix gaps; tick spec.md acceptance boxes in a verification note
specs/001-market-first-wedge/VERIFICATION.md
Dependencies
Phase 1 → Phase 2 → { US1 (P3..) , US2 (needs T007 registry; T027 needs T016 CLI scaffold) }
US1 T015 indexer ← T007 registry
US2 T032 discoverability ← US1 T015+T023 (search path)
US3 ← US1 ledger core (T010-T014)
T036 WEDGE GATE ← T024 (install), T032 (real listing), T033/T035 (funded wallets)
US4 ← US1 CLI (T023/T024) + T015 catalog
US5 ← T015 catalog; T042 ← T041 spike
Phase 8 T047 ← everything on its scenario list
Story completion order: US1 → US2 → US3 (gate) → US4 ∥ US5 → Polish. US4 and US5 are independent of each other and of the gate.
Parallel execution examples
- Phase 2: T004, T005, T008, T009 in parallel (disjoint files); T006/T007 after T004+T005.
- US1 wave 1: T010, T011 ∥ T016, T017, T018, T019, T020 (7 workers, disjoint files).
- US1 wave 2 (serial per file): T012→T013→T014; T021→T022 (same dir but disjoint files — T021 and T022 CAN pair if split carefully; keep serial to be safe); T023→T024→T025 (same cli.py — one worker).
- US2 seeds: T029, T030, T031 in parallel (disjoint solution dirs).
- Post-gate: US4 (T037–T040) and US5 (T041–T044) as two parallel workstreams.
Implementation strategy
MVP = Phase 1 + 2 + US1 with a fixture listing (Scenario B/C locally), then US2 seeds make it real, US3 funds it, T036 closes the wedge commercially (SC-001). US4/US5 extend surfaces after the gate — they improve discovery, they don't block the win. fedlearn integration (plan row 10) is intentionally NOT a task here: it becomes its own feature when the rails land, guided by docs/fedlearn-coordination.md and the frozen apply-adapter contract.