m2-market/specs/001-market-first-wedge/tasks.md
m2 (AI Agent) e244050ff9 wedge: T040/T042-T044 done — M2 Store live on canary (real UI purchase), Scout v0 proposing on canary
- Store: deployed chris-m2o (+gunnar staged); UI install executed a real
  debit->grant->apply, with a truthful auto-refunded failure first
- Scout: Hermes plugin discovered+enabled (39 found/33 enabled), hooks
  manifest fixed, thresholds calibrated on LIVE scores (0.60/0.30 —
  defaults 0.78/0.55 gated out the correct match), proposal recorded to
  outbox, opt-out + rate-cap verified live
- Fleet issues surfaced: chris m2-gpt key 401 (blocks real LLM turns),
  root-owned ~/.claude on chris (fixed via chown)

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

13 KiB
Raw Permalink Blame History

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.toml tool 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.json v1 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.json v1 per data-model.md Listing table (incl. stats conversion-signal fields, status enum, 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 a just validate / pytest runner
  • T007 Create Forgejo repo m2/market-registry per 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.toml keys, 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} in ledger/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 coolify network in ledger/Dockerfile + ledger/README.md deploy notes; verify GET /health from the network
  • T015 [US1] Create market:catalog partition and implement indexer indexer/src/m2_market_indexer/reindex.py + watch.py per 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) in cli/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.py per 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_sync stub adapter in cli/src/m2_market/apply/m2core_sync.py raising RailsNotLanded (exit 6)
  • T023 [US1] search + show commands in cli/src/m2_market/cli.py (catalog query → table/JSON; show renders evidence/price/permissions diff)
  • T024 [US1] install command in cli/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] wallet command in cli/src/m2_market/cli.py (balance + recent tx)
  • T026 [US1] CLI integration tests in cli/tests/test_install_flow.py against 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] publish command in cli/src/m2_market/cli.py + cli/src/m2_market/publish.py: validate bundle against schemas (exit 5 on violation incl. tenant firewall), push listing/<id> branch, open PR via Forgejo API with template
  • T028 [US2] Registry CI hardening in m2/market-registry CI 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/starter admin endpoint in ledger/src/m2_ledger/api.py + config-driven default amount (100 cr flagged-unconfirmed) with tests in ledger/tests/test_grants.py
  • T034 [US3] Snapshot module ledger/src/m2_ledger/snapshot.py: balances dump → commit audit/YYYY-MM-DD.json to m2/market-registry via Forgejo API; /snapshot admin 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 install on 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-store on github.com/machine-machine/cargstore; swap catalog source from Flatpak JSON to market:catalog via memory-api HTTP (desktop-provisioned creds per research.md R7) in cargstore src/ catalog service
  • T038 [US4] Add Solution install backend to cargstore that shells m2-market install --json and renders progress/result truthfully (incl. refund-on-failure path) in cargstore src/ install manager
  • T039 [US4] Solution detail page: evidence, price, permissions diff (from m2-market show --json) in cargstore src/ 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:catalog match (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:evidence per 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 listing stats.installscli/src/m2_market/telemetry.py + indexer pass
  • T046 [P] reindex operational check task: run Scenario E, document recovery runbook in docs/runbook.md (incl. memory-api split-brain caveat from research.md R4)
  • T047 Run full quickstart.md scenario sweep AE 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 (T037T040) and US5 (T041T044) 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.