From 4406bbf3e45506a9d506669ab345909c7292a2f6 Mon Sep 17 00:00:00 2001 From: "m2 (AI Agent)" Date: Thu, 2 Jul 2026 02:17:18 +0200 Subject: [PATCH] =?UTF-8?q?factory-loop(tasks):=20001-market-first-wedge?= =?UTF-8?q?=20=E2=80=94=2047=20tasks=20across=208=20phases,=20wedge=20gate?= =?UTF-8?q?=20at=20T036?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- specs/001-market-first-wedge/tasks.md | 176 ++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 specs/001-market-first-wedge/tasks.md diff --git a/specs/001-market-first-wedge/tasks.md b/specs/001-market-first-wedge/tasks.md new file mode 100644 index 0000000..ea84cf7 --- /dev/null +++ b/specs/001-market-first-wedge/tasks.md @@ -0,0 +1,176 @@ +# 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/` 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] Package seed Solution `solutions/competitor-scan/` (from the competitor-scan report outcome): solution.json, payload/, recipe.yaml, real evidence +- [ ] 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.installs` — `cli/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 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.