- spec-kit initialized (claude integration; /speckit.* skills in .claude/skills/) - constitution: 7 principles from CONCEPT.md v0.2 + inherited fleet constraints - spec 001-market-first-wedge: 5 prioritized stories, FR-001..015, SC-001..007 - operator steer from README §open-forks folded into assumptions (ledger standalone now / m2-gpt-billing crypto later, fixed pricing + job headroom, Electron MVP store, Scout host = explore spike) - .m2herd/ context fabric initialized (gitignored) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
281 lines
16 KiB
Markdown
281 lines
16 KiB
Markdown
# Feature Specification: M2 Marketplace — First Wedge
|
||
|
||
**Feature Branch**: `001-market-first-wedge`
|
||
|
||
**Created**: 2026-07-02
|
||
|
||
**Status**: Draft
|
||
|
||
**Input**: User description: "M2 Marketplace first wedge: schemas, m2-ledger, commercialize curation, market:catalog + m2-market CLI, cargstore revival to M2 Store, 3-5 seeded Solutions, Solution Scout v0, one real paid install between two operators" (CONCEPT.md v0.2 §12)
|
||
|
||
## User Scenarios & Testing *(mandatory)*
|
||
|
||
### User Story 1 - Paid install via CLI (Priority: P1)
|
||
|
||
An operator (buyer) searches the catalog for a capability they need, inspects a listing's
|
||
evidence and price, and installs it. The install debits their credit wallet, credits the
|
||
seller (minus platform cut), grants a license, and applies the Solution bundle to their
|
||
machine through the existing sync/apply path. This is the commercial loop's spine — every
|
||
other story feeds it.
|
||
|
||
**Why this priority**: Without buy→debit→grant→apply working end-to-end, nothing else in the
|
||
marketplace has meaning. It is independently valuable: even with zero storefront UI and zero
|
||
Scout, two operators can transact via CLI.
|
||
|
||
**Independent Test**: On a machine with a funded wallet, run `m2-market search <term>`,
|
||
`m2-market show <listing>`, `m2-market install <listing>`; verify ledger shows the debit and
|
||
seller credit, a license grant exists, and the bundle's files/config are applied and
|
||
invocable.
|
||
|
||
**Acceptance Scenarios**:
|
||
|
||
1. **Given** a listed Solution priced at 40 credits and a buyer wallet holding ≥40 credits,
|
||
**When** the buyer runs `m2-market install <listing-id>`, **Then** the ledger records a
|
||
debit of 40 from the buyer, a credit of 36 to the seller and 4 to the platform (10% cut),
|
||
a license grant is recorded, and the bundle is applied idempotently to the buyer's machine.
|
||
2. **Given** a buyer wallet holding fewer credits than the listing price, **When** they
|
||
attempt install, **Then** the install is refused before any apply happens and no ledger
|
||
transaction or license grant is created.
|
||
3. **Given** a completed install, **When** the same install is re-run, **Then** the apply is
|
||
idempotent (no duplicate debit; re-apply is safe or a no-op with the existing license).
|
||
4. **Given** an applied Solution, **When** the operator invokes its documented entrypoint,
|
||
**Then** the packaged outcome executes on their machine.
|
||
|
||
---
|
||
|
||
### User Story 2 - Publish a Solution with evidence (Priority: P1)
|
||
|
||
A builder packages a proven outcome (e.g. the mm-pdf branded-report generator) as a Solution:
|
||
a manifest-superset bundle with price, seller, license, and provenance evidence. They submit
|
||
it for listing; it passes the curation pipeline (scored PR, human veto) with the
|
||
`commercialize` disposition and lands in the registry of record and the semantic catalog.
|
||
|
||
**Why this priority**: Supply side of the loop. Story 1 cannot demo without at least one real
|
||
listing; seeding 3–5 Solutions from proven outcomes is part of this wedge.
|
||
|
||
**Independent Test**: Package one existing proven outcome, submit it, approve the listing PR,
|
||
and verify it is retrievable via `m2-market search` with its evidence and price visible.
|
||
|
||
**Acceptance Scenarios**:
|
||
|
||
1. **Given** a valid Solution bundle with price and provenance, **When** the builder submits
|
||
it for listing, **Then** a review PR is created carrying evidence, price, permissions, and
|
||
rollback info, and the listing is NOT discoverable until the PR is merged.
|
||
2. **Given** a submitted listing missing provenance evidence, **When** it enters curation,
|
||
**Then** it is rejected by validation before human review.
|
||
3. **Given** a merged listing, **When** any operator searches the catalog semantically,
|
||
**Then** the listing is returned with name, summary, price, rating placeholder, and
|
||
evidence summary.
|
||
4. **Given** tenant-derived work, **When** submission is attempted by anyone other than the
|
||
owning operator, **Then** the submission is refused (tenant firewall).
|
||
|
||
---
|
||
|
||
### User Story 3 - Credit wallets and starter grants (Priority: P2)
|
||
|
||
Each operator has a wallet. The platform issues starter grants to active operators so the
|
||
economy can bootstrap. Balances derive from an append-only transaction log; a daily snapshot
|
||
is committed to the registry host for audit.
|
||
|
||
**Why this priority**: Story 1 needs wallets to debit, but a minimal hardcoded grant would
|
||
suffice for the very first transaction; full wallet lifecycle is its own increment.
|
||
|
||
**Independent Test**: Issue a starter grant to a fresh operator id; verify balance query
|
||
returns the grant amount; verify the daily snapshot job writes a balance file into version
|
||
control.
|
||
|
||
**Acceptance Scenarios**:
|
||
|
||
1. **Given** a new operator id, **When** a starter grant (default 100 cr) is issued, **Then**
|
||
their balance reflects it and the grant appears as an append-only transaction with reason
|
||
`grant`.
|
||
2. **Given** any sequence of transactions, **When** balances are queried, **Then** they equal
|
||
the fold of the transaction log (no stored balance drifts from derived balance).
|
||
3. **Given** a day with ≥1 transaction, **When** the snapshot job runs, **Then** a balance
|
||
snapshot is committed to the audit repo.
|
||
|
||
---
|
||
|
||
### User Story 4 - M2 Store (cargstore revival) on canaries (Priority: P3)
|
||
|
||
An operator on a canary desktop opens the M2 Store app, browses the catalog rendered from
|
||
`market:catalog`, opens a Solution page showing evidence, price, and permissions diff, and
|
||
installs with one click — same ledger + apply path as the CLI.
|
||
|
||
**Why this priority**: The storefront makes the loop humane but the CLI already closes it.
|
||
Canary-only (chris-m2o, gunnar-m2o) per the constitution's deployment principle.
|
||
|
||
**Independent Test**: On one canary desktop, open the store, find a seeded listing, click
|
||
install, and verify the same post-conditions as Story 1's scenario 1.
|
||
|
||
**Acceptance Scenarios**:
|
||
|
||
1. **Given** the store app pointed at the live catalog, **When** it renders the front page,
|
||
**Then** seeded listings appear with name, summary, category, price.
|
||
2. **Given** a Solution page, **When** the operator clicks Install, **Then** the identical
|
||
debit→grant→apply sequence of Story 1 executes and the UI reports success/failure
|
||
truthfully.
|
||
3. **Given** an install failure after debit, **When** the failure is detected, **Then** the
|
||
operator sees a clear error and a compensating refund transaction is recorded.
|
||
|
||
---
|
||
|
||
### User Story 5 - Solution Scout v0 on one canary (Priority: P3)
|
||
|
||
While an operator works, a per-desktop watcher summarizes session intent from structured
|
||
lifecycle/run summaries (never raw keystrokes), matches it against tenant-allowed catalog
|
||
listings, and — on a high-confidence hit — shows a non-blocking proposal with a deep link to
|
||
the listing. Propose-only, opt-in, rate-limited.
|
||
|
||
**Why this priority**: Demand-side engine; valuable but the wedge's success criterion only
|
||
requires discovery "via Scout **or** Hermes/CLI". Ships last, on one canary.
|
||
|
||
**Independent Test**: On an opted-in canary, run a session that resembles a seeded listing's
|
||
intent; verify a proposal appears within the session with a working deep link, and that
|
||
opting out or exceeding the daily rate cap suppresses proposals.
|
||
|
||
**Acceptance Scenarios**:
|
||
|
||
1. **Given** an opted-in desktop and a session whose summary semantically matches a listing
|
||
above threshold, **When** the match fires, **Then** a non-blocking notification with the
|
||
listing's name, rating, coverage, and price appears with an install deep link.
|
||
2. **Given** an opted-out desktop, **When** the same session runs, **Then** no session data
|
||
leaves the machine and no proposal is shown.
|
||
3. **Given** N proposals already shown today (rate cap), **When** another match fires,
|
||
**Then** it is suppressed.
|
||
4. **Given** a proposal, **When** the operator dismisses or accepts it, **Then** the outcome
|
||
is recorded as listing-quality evidence (conversion signal).
|
||
|
||
---
|
||
|
||
### Edge Cases
|
||
|
||
- Install interrupted between ledger debit and apply completion → apply must be resumable or
|
||
a compensating refund recorded; never a paid-but-not-applied end state without a visible
|
||
remediation path.
|
||
- Listing updated (new version) after purchase → existing license covers which versions?
|
||
(v1: license covers the purchased major version; updates within it are free re-applies.)
|
||
- Seller delists a purchased Solution → existing licenses and installed bundles remain valid.
|
||
- Two installs of the same listing racing on one machine → second is a no-op under the
|
||
existing idempotent apply semantics.
|
||
- Catalog index diverges from registry of record → registry wins; index must be rebuildable
|
||
from it (constitution II).
|
||
- Buyer and seller are the same operator (self-purchase) → allowed but flagged; conversion
|
||
signals from self-purchases are excluded from listing quality metrics.
|
||
- Scout matches against a listing the tenant may not see → must be impossible by
|
||
construction: matching runs against tenant-allowed listings only.
|
||
|
||
## Requirements *(mandatory)*
|
||
|
||
### Functional Requirements
|
||
|
||
- **FR-001**: The system MUST define a frozen v1 `solution.schema.json` as a superset of the
|
||
fedlearn manifest, adding at minimum: price, seller/operator id, license terms, and
|
||
revenue-split fields.
|
||
- **FR-002**: The system MUST define a frozen v1 `listing.schema.json` covering catalog
|
||
presentation: id, name, summary, category, keywords, price, seller, evidence references,
|
||
rating/conversion placeholders, and install reference.
|
||
- **FR-003**: The system MUST provide an append-only credit ledger recording transactions
|
||
`{ts, from, to, amount, reason: install|payout|grant|route|earn, ref}` with balances always
|
||
derived from the log.
|
||
- **FR-004**: The ledger MUST authenticate API callers (per-key auth) and MUST commit a daily
|
||
balance snapshot to the version-controlled audit location.
|
||
- **FR-005**: Installing a listing MUST atomically-in-effect: verify funds, debit the buyer,
|
||
credit the seller minus the platform cut (default 10%, configurable), record a license
|
||
grant, then trigger the existing sync/apply path; on apply failure a compensating refund
|
||
transaction MUST be recorded.
|
||
- **FR-006**: The curation pipeline MUST support a third disposition `commercialize`
|
||
alongside promote-to-core and reject/park, using the existing PR + human-veto flow, with a
|
||
listing PR template requiring evidence, price, permissions, and rollback notes.
|
||
- **FR-007**: The system MUST index merged listings into a semantic catalog partition
|
||
(`market:catalog`) searchable by meaning, scoped to tenant-allowed listings, and fully
|
||
rebuildable from the registry of record.
|
||
- **FR-008**: The system MUST provide an `m2-market` CLI with at minimum `search`, `show`,
|
||
and `install` commands, where `install` performs the FR-005 sequence.
|
||
- **FR-009**: Operators MUST have wallets keyed to operator identity (fleet tenancy model),
|
||
and the platform MUST be able to issue starter grants (default 100 cr).
|
||
- **FR-010**: The storefront (M2 Store, evolved from cargstore) MUST render the catalog,
|
||
show listing detail with evidence/price/permissions, and drive installs through the same
|
||
ledger + apply path as the CLI; deployment is canary-only in this wedge.
|
||
- **FR-011**: The Solution Scout MUST run per-desktop, opt-in via desktop policy config,
|
||
consume only structured session/run summaries (never raw keystrokes or raw client data),
|
||
summarize on-box before any egress, match only tenant-allowed listings, be rate-limited
|
||
(default: max 5 proposals/day), and be propose-only (install always requires a human
|
||
click).
|
||
- **FR-012**: Accepted and dismissed Scout proposals MUST be recorded as listing quality
|
||
evidence (proposal→install conversion).
|
||
- **FR-013**: At least 3 Solutions packaged from already-proven outcomes MUST be listed with
|
||
real evidence (proposed set: mm-pdf branded-report generator, agent-scaffold workspace
|
||
generator, competitor-scan report).
|
||
- **FR-014**: Install telemetry (who/when/machine/outcome) MUST land back in the memory
|
||
system as pricing/quality evidence attached to the listing.
|
||
- **FR-015**: Tenant-derived work MUST be commercializable only when owner-initiated and
|
||
doubly-scrubbed; submissions violating the tenant firewall MUST be rejected automatically.
|
||
|
||
### Key Entities
|
||
|
||
- **Solution**: installable bundle — intent, agent behavior, tools, runtime refs, memory
|
||
schema, permissions, deployment recipe, price, evidence. Conforms to
|
||
`solution.schema.json`; versioned in the registry of record.
|
||
- **Listing**: the catalog-facing record of a Solution (or other inventory type) —
|
||
presentation + commercial fields + evidence refs. Conforms to `listing.schema.json`;
|
||
truth in the registry, indexed in `market:catalog`.
|
||
- **Operator**: human identity over N machines (fleet tenancy); may act as buyer, builder,
|
||
seller, resource owner. Owns exactly one wallet in v1.
|
||
- **Wallet / Transaction**: operator's credit position, derived from append-only transactions
|
||
`{ts, from, to, amount, reason, ref}`.
|
||
- **License Grant**: record tying an operator to a purchased listing version, checked by the
|
||
install/apply path.
|
||
- **Proposal**: a Scout suggestion event — listing, confidence, shown/dismissed/accepted,
|
||
feeding conversion metrics.
|
||
|
||
## Success Criteria *(mandatory)*
|
||
|
||
### Measurable Outcomes
|
||
|
||
- **SC-001**: One real paid install completes between two distinct operators (e.g. m2bd buys
|
||
sdjs-operator's package): discovered via CLI/Hermes/Scout, bought with credits, applied via
|
||
the standard path, ledger reflecting debit/credit/cut — the loop closes commercially once.
|
||
- **SC-002**: ≥3 Solutions listed with real provenance evidence, each passing curation review.
|
||
- **SC-003**: 100% of installs have a matching ledger transaction and license grant; zero
|
||
applies without a recorded debit (audited from the daily snapshot).
|
||
- **SC-004**: Ledger balances recomputed from the transaction log match reported balances
|
||
exactly at every daily snapshot.
|
||
- **SC-005**: An operator can go from `m2-market search` to an invocable installed Solution
|
||
in under 10 minutes on a canary desktop.
|
||
- **SC-006**: Scout v0 on one canary produces ≥1 correct proposal (matching listing shown for
|
||
a genuinely related session) with zero raw-input egress, honoring opt-in and rate caps.
|
||
- **SC-007**: Install telemetry from SC-001's install is queryable as evidence on the listing
|
||
afterward.
|
||
|
||
## Assumptions
|
||
|
||
Recorded per constitution: recommended defaults from CONCEPT.md §14 open forks are ASSUMED
|
||
here and flagged until the operator confirms (also mirrored in `.m2herd/overview.json`
|
||
open_questions):
|
||
|
||
- **Ledger substrate** (operator steer, README 2026-07-02): standalone `m2-ledger` service
|
||
(SQLite, API-key auth) NOW; recorded future direction — it may evolve into a crypto-style
|
||
ledger managed inside extended m2-gpt billing. v1 interfaces must not preclude that
|
||
migration (keep ledger API separable from storage).
|
||
- **Pricing v1** (operator steer): fixed price per install as the default; the operator
|
||
notes that sometimes another m2o takes a *job* for a solution — service-style fulfillment
|
||
pricing. v1 transacts fixed-price installs only, but `listing.schema.json` must not
|
||
preclude a job/service fulfillment variant (reason codes `route|earn` already exist).
|
||
- **Storefront path** (operator steer): MVP Electron app (cargstore revival) that connects
|
||
to Coolify and other platform parts using credentials issued via m2-gpt; `web/` variant
|
||
deferred.
|
||
- **Scout host**: OPEN — operator marked "explore solution" (§14.4). Plan phase must carry a
|
||
short exploration spike (standalone supervised watcher vs Hermes plugin vs herdr plugin)
|
||
before Scout implementation; Scout v0 remains last-sequenced so this does not block the
|
||
wedge.
|
||
- **First Solutions**: mm-pdf, agent-scaffold, competitor-scan (§14.5 proposed).
|
||
- **Economics**: platform cut 10%, starter grant 100 cr, both configurable (§14.6 defaults).
|
||
- **Dependency**: fedlearn MVP rails (manifest schema, `m2/m2-core` registry, capture CLI,
|
||
curation PR/veto, `m2-core-sync` apply, memory partitions) are in herd execution NOW and
|
||
land before or during this wedge; where a rail is not yet landed, the plan phase must
|
||
sequence around it or stub against its frozen interface.
|
||
- Payout to fiat/external money is out of scope; payouts are manually reconciled.
|
||
- Resource/Service inventory types are catalog-schema-ready but not transacted in this wedge;
|
||
only Solutions are bought/sold.
|
||
- Public web marketplace, external payments, and public coin/exchange are out of scope.
|