m2-market/specs/S6-proposal-engine-evidence.md
m2 (AI Agent) 8a8db9f2cc specs: m2-market spec discovery — 6 subsystem specs + synthesis index
herdr workforce output (6 codex angle-specialists -> claude synthesis):
S1 ledger/economy, S2 catalog/registry, S3 storefront (cargstore->M2 Store),
S4 Solution Scout (standalone watcher recommended), S5 packaging + 3 seed
Solutions (mm-pdf 25cr, agent-scaffold 35cr, competitor-scan 60cr),
S6 proposal engine + evidence loop.

SPEC-INDEX is the tie-break: 23-row cross-cutting contract table (16 mismatches
resolved, e.g. /v1 ledger paths win, m2store://listing/<id> deep link, one
m2.market.telemetry.v1 envelope, op_<slug> operator ids, tenant ids from m2-gpt),
8 deduped clarifications with defaults, 4-phase build order where the paid-install
wedge does NOT block on fedlearn (local ApplyAdapter until rails land), risk register.

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

23 KiB

S6 — Proposal Engine & Evidence Loop SPEC

1. Scope & non-goals

MVP scope

S6 owns the pull-side proposal engine and pricing evidence loop:

  • Hermes market-propose skill: turns a user intent into build-vs-install-vs-job proposals.
  • Cost-intelligence layer: combines similar past work from memory, real token/time spend from m2-gpt metering/cognition traces, herdr run durations, and market:catalog search.
  • Evidence records: every serious job leaves a scrubbed, tenant-scoped record with wanted/tools/contributors/tokens/time/resources/failed/succeeded/reusable-verdict.
  • Proposal citations: proposals must cite listing evidence, similar job evidence, and cost estimates separately.
  • Harness-agnostic contract: Hermes is the primary surface; OpenAI-wire clients through m2-gpt can call the same tool/API later.

MVP deploys as:

  1. A Hermes skill installed by runtime-sync in desktop home volumes.
  2. A small m2-market-proposer service on Coolify network for deterministic retrieval, estimate aggregation, evidence writes, and proposal JSON.
  3. A gateway-side optional middleware hook that records real usage and exposes it by correlation id; the proposal decision logic stays outside the gateway.

Later

  • Automatic quote negotiation with human operators.
  • Dynamic repricing of listings.
  • Public web marketplace proposal widgets.
  • Full resource-market routing optimizer.
  • Crypto-capable ledger integration beyond internal credits.

Non-goals

  • Ledger schema or payment settlement: S1.
  • Catalog/listing truth, indexing, install flow, and M2 Store UX: S2/S3.
  • Scout push notifications: S4.
  • Packaging/build artifacts: S5.
  • Raw client transcript ingestion. S6 consumes scrubbed summaries only.

2. User stories + acceptance criteria

US-1: Operator asks Hermes what path to take

Given an operator asks Hermes for an outcome such as "automate my eBay listings"
When Hermes invokes market-propose with the current intent and tenant identity
Then the response contains at least one of each applicable path:

  • install_adapt: existing Solution covers enough of the intent.
  • operator_job: a Service/operator can deliver or adapt it.
  • custom_build: no adequate inventory exists or client constraints require custom work.

Acceptance:

  • Every price/time/token estimate has at least one citation or is marked low_confidence.
  • Tenant visibility is enforced before any listing or evidence is returned.
  • Client-derived evidence is never cited unless owner_initiated=true and double_scrubbed=true.

US-2: Proposal cites evidence without leaking data

Given similar past work exists in memory under tenant-private and shared partitions
When a proposal is generated for tenant gst
Then only tenant_id in ["gst", "__fleet__", "m2-core"] and allowed shared records are searched.

Acceptance:

  • Cross-tenant records are impossible to retrieve through the API filter.
  • Citations include stable IDs and short sanitized summaries, not raw transcript text.
  • The API returns evidence_redactions[] explaining omitted records by class, not identity.

US-3: Serious job leaves an evidence record

Given an install, operator-assisted job, or custom build runs longer than 10 minutes, spends more than 100k tokens, or creates a reusable artifact
When the job ends or is abandoned
Then m2-market-proposer writes a m2.market.evidence.v1 record to memory and attaches its summary to any relevant listing.

Acceptance:

  • Records validate against the schema below.
  • Failed jobs are recorded; they are usable for estimates but do not raise listing success stats.
  • Reusable verdict is one of create_solution, update_solution, not_reusable, unclear.

US-4: Evidence improves future estimates

Given at least three evidence records exist for a capability or listing
When a later proposal asks for similar work
Then estimates use p50/p80/p95 ranges instead of a single naive value.

Acceptance:

  • Proposal JSON includes estimate_basis.sample_count.
  • Outliers remain in evidence but are downweighted only by explicit rule.
  • Install path estimates cite listing-level install telemetry before generic similar jobs.

3. Interfaces & data contracts

Existing contracts S6 depends on

  • memory-api: live https://memory.machinemachine.ai/health returns ok; search endpoint shape is POST /memory/search with query, agent_id, routing_strategy, limit, tenant_id, and optional filters.
  • m2-gpt: live https://gpt.machinemachine.ai/health returns {"status":"healthy","gateway":"bifrost"}. It already has tenants/agents, tenant_budgets, route_budgets, spend_log, cognition traces, and usage passthrough from Bifrost.
  • market:catalog: existing catalog contract stores published listing payloads under memory partition agent_id="market:catalog".
  • m2.solution.v1 and m2.listing.v1: existing schemas already carry evidence, price, seller, tenant visibility, and stats.
  • m2-ledger: S6 quotes credits but does not debit; install/job settlement remains the ledger contract.

Memory partitions

Use memory-api agent_id as partition:

  • market:catalog: published listing semantic index, owned by S2/S3.
  • market:evidence: job and install evidence records, owned by S6.
  • market:proposals: optional proposal audit summaries, owned by S6.

Tenant scope:

  • Shared evidence uses tenant_id="m2-core" or tenant_id="__fleet__".
  • Tenant-private evidence uses canonical tenant id such as gst, nasr, parlobyg, peter.
  • Queries must pass tenant_id=[caller_tenant, "m2-core", "__fleet__"] unless caller is an operator-admin.

Evidence record schema

Schema id: m2.market.evidence.v1.

{
  "schema_version": "m2.market.evidence.v1",
  "evidence_id": "ev_2026w27_01j2abc",
  "job_id": "job_01j2abc",
  "tenant_id": "m2-core",
  "operator_id": "sdjs-operator",
  "agent_ids": ["chris-m2o"],
  "created_at": "2026-07-02T00:00:00Z",
  "wanted": {
    "intent": "Generate a branded competitor scan report",
    "normalized_capabilities": ["research", "report-generation"],
    "constraints": ["no raw client data in shared catalog"]
  },
  "tools": [
    {"name": "Hermes", "kind": "agent"},
    {"name": "m2-gpt", "kind": "llm_gateway"},
    {"name": "memory-api", "kind": "memory"},
    {"name": "herdr", "kind": "run_capture"}
  ],
  "contributors": [
    {"kind": "operator", "id": "sdjs-operator", "role": "builder"},
    {"kind": "agent", "id": "chris-m2o", "role": "executor"}
  ],
  "metering": {
    "m2_gpt_correlation_ids": ["turn_01j2abc"],
    "prompt_tokens": 120000,
    "completion_tokens": 18000,
    "total_tokens": 138000,
    "cost_usd": 0.42,
    "wall_time_seconds": 2400,
    "active_time_seconds": 1500,
    "herdr_run_ids": ["run_2026-07-02T00-00-00Z"]
  },
  "resources": [
    {"kind": "desktop", "id": "chris-m2o", "seconds": 2400},
    {"kind": "model", "id": "GLM-5.1", "tokens": 138000}
  ],
  "outcome": {
    "status": "succeeded",
    "failed": [
      {"step": "site scraping", "reason": "blocked by login", "recovered": true}
    ],
    "succeeded": [
      {"step": "report generation", "artifact_ref": "forgejo:m2/market-registry/..."}
    ]
  },
  "reusable_verdict": {
    "decision": "create_solution",
    "confidence": 0.82,
    "reason": "Repeatable report workflow with scrubbed inputs"
  },
  "listing_refs": [
    {"listing_id": "lst_competitor-scan", "relationship": "supports_estimate"}
  ],
  "scrub_status": {
    "secrets_redacted": true,
    "pii_redacted": true,
    "double_scrubbed": true,
    "raw_sources_retained": false
  },
  "content_hash": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}

Required fields:

schema_version, evidence_id, job_id, tenant_id, created_at, wanted, tools, contributors, metering, resources, outcome, reusable_verdict, scrub_status, content_hash.

Memory store payload:

{
  "content": "Wanted: branded competitor scan report. Outcome: succeeded. Reusable: create_solution. Time: 40m. Tokens: 138k.",
  "agent_id": "market:evidence",
  "tenant_id": "m2-core",
  "metadata": {
    "schema_version": "m2.market.evidence.v1",
    "evidence_id": "ev_2026w27_01j2abc",
    "job_id": "job_01j2abc",
    "listing_ids": ["lst_competitor-scan"],
    "capabilities": ["research", "report-generation"],
    "status": "succeeded",
    "reusable_decision": "create_solution",
    "tokens_total": 138000,
    "wall_time_seconds": 2400,
    "content_hash": "sha256:..."
  }
}

Proposal request schema

Schema id: m2.market.proposal-request.v1.

{
  "schema_version": "m2.market.proposal-request.v1",
  "request_id": "prq_01j2abc",
  "tenant_id": "m2-core",
  "operator_id": "m2bd",
  "agent_id": "chris-m2o",
  "harness": "hermes",
  "intent": "I want to automate eBay listings",
  "context_summary": "User has product photos and wants listing drafts.",
  "constraints": {
    "max_credits": 150,
    "deadline": "2026-07-03",
    "data_sensitivity": "tenant_private",
    "allowed_inventory_types": ["solution", "service", "resource", "capability"]
  },
  "current_tools": ["browser", "filesystem", "m2-market"],
  "correlation_id": "turn_01j2abc"
}

Proposal response schema

Schema id: m2.market.proposal.v1.

{
  "schema_version": "m2.market.proposal.v1",
  "proposal_id": "prop_01j2abc",
  "request_id": "prq_01j2abc",
  "tenant_id": "m2-core",
  "generated_at": "2026-07-02T00:00:00Z",
  "intent_summary": "Automate eBay listing creation from product inputs.",
  "paths": [
    {
      "path_id": "path_install_adapt_1",
      "kind": "install_adapt",
      "title": "Install eBay Listing Workflow and adapt prompts",
      "recommendation": "recommended",
      "coverage": 0.72,
      "credits": {"min": 40, "expected": 60, "max": 90, "currency": "m2cr"},
      "time": {"p50_seconds": 7200, "p80_seconds": 14400},
      "tokens": {"p50": 600000, "p80": 1200000},
      "resources": [{"kind": "desktop", "quantity": 1}],
      "next_action": {
        "type": "install",
        "listing_id": "lst_ebay-listing-workflow",
        "deeplink": "m2store://listing/lst_ebay-listing-workflow"
      },
      "citations": [
        {"kind": "listing", "id": "lst_ebay-listing-workflow", "claim": "catalog match"},
        {"kind": "evidence", "id": "ev_2026w26_01x", "claim": "similar workflow completed in 2h"}
      ],
      "risks": ["Needs credentialed browser session", "May require image style adaptation"],
      "estimate_basis": {"sample_count": 4, "method": "listing_install_p80"}
    }
  ],
  "evidence_redactions": [
    {"reason": "tenant_not_visible", "count": 3},
    {"reason": "not_double_scrubbed", "count": 1}
  ],
  "audit": {
    "catalog_query_id": "memq_01j2abc",
    "evidence_query_id": "memq_01j2abd",
    "m2_gpt_correlation_id": "turn_01j2abc"
  }
}

Path kinds:

  • install_adapt: buy/install Solution and adapt locally.
  • operator_job: engage operator/service through job-based pricing.
  • custom_build: build from scratch.
  • resource_route: rent internal resource/capacity when it is the dominant cost.
  • defer: no acceptable path under constraints.

HTTP API: m2-market-proposer

Service: m2-market-proposer, Coolify app on coolify network. Base internal URL: http://m2-market-proposer:8000.

Auth:

  • X-API-Key: service key injected at runtime.
  • Optional Authorization: Bearer <m2-gpt tenant key> for direct harness calls after gateway identity forwarding lands.

GET /health

Response:

{"status":"healthy","memory":"ok","m2_gpt":"ok"}

POST /v1/proposals

Body: m2.market.proposal-request.v1.
Response: m2.market.proposal.v1.

Required behavior:

  1. Normalize intent into capability tags.
  2. Query market:catalog with tenant visibility.
  3. Query market:evidence with tenant scope [caller, "m2-core", "__fleet__"].
  4. Fetch m2-gpt spend/time by correlation_id where available.
  5. Build ranked paths with citations.
  6. Store proposal audit summary in market:proposals unless dry_run=true.

POST /v1/evidence

Body: m2.market.evidence.v1.
Response:

{"evidence_id":"ev_2026w27_01j2abc","stored":true,"attached_listing_ids":["lst_competitor-scan"]}

Behavior:

  • Validate schema.
  • Enforce scrub gate before shared write.
  • Store semantic summary in memory partition market:evidence.
  • Emit listing-attachment event for S2/S3 indexer.

GET /v1/evidence/{evidence_id}

Returns sanitized evidence record if caller tenant can see it; 404 for not found or forbidden to avoid existence leaks.

POST /v1/estimates

Body:

{
  "tenant_id": "m2-core",
  "intent": "build competitor scan report",
  "listing_ids": ["lst_competitor-scan"],
  "capabilities": ["research", "report-generation"],
  "confidence_floor": 0.6
}

Response:

{
  "sample_count": 5,
  "tokens": {"p50": 300000, "p80": 800000, "p95": 2000000},
  "time_seconds": {"p50": 1800, "p80": 7200, "p95": 172800},
  "credits": {"p50": 30, "p80": 90, "p95": 300},
  "method": "similar_evidence_weighted",
  "citations": [{"kind":"evidence","id":"ev_..."}]
}

CLI verbs

Add to existing m2-market CLI surface:

m2-market propose "<intent>" --tenant <tenant> --operator <operator_id> --json
m2-market evidence capture --job-id <job_id> --from-herdr <run_id> --correlation-id <turn_id>
m2-market evidence submit evidence.json
m2-market evidence show <evidence_id> --json

Exit codes follow existing CLI contract: 0 ok, 1 usage, 2 not found, 5 validation/firewall rejection.

Hermes skill: market-propose

Install path:

  • Primus: /home/developer/.hermes/skills/market-propose/
  • Agent-latest/OpenClaw-compatible fallback assets: /home/developer/.m2-core/skills/market-propose/
  • Distributed by runtime-sync/m2-core-sync only; no baked secrets.

Skill files:

market-propose/
  SKILL.md
  skill.json
  scripts/propose.py
  scripts/evidence_capture.py

skill.json:

{
  "name": "market-propose",
  "version": "0.1.0",
  "runtime": "python3",
  "commands": {
    "propose": "python3 scripts/propose.py",
    "evidence_capture": "python3 scripts/evidence_capture.py"
  },
  "env": [
    "M2_MARKET_PROPOSER_URL",
    "M2_MARKET_API_KEY",
    "M2_GPT_CORRELATION_ID",
    "M2_TENANT_ID",
    "M2_OPERATOR_ID"
  ]
}

Hermes behavior:

  • Invoke propose when the user asks for cost, build/install choice, "is there a package", "can someone do this", or "estimate this job".
  • Render concise human prose, but preserve machine-readable proposal JSON in an attached block or local state file.
  • Do not install or spend credits without explicit user approval.

m2-gpt metering contract

S6 consumes existing gateway data instead of duplicating metering:

  • spend_log: tenant, route/model, recorded time, prompt/completion/total tokens where present, cost.
  • cognition trace/audit v2: tenant_id, agent_id, turn_id/correlation id, model, tokens, tool, status, latency/time.
  • Bifrost OpenAI response usage: passthrough source for token counts.

Add read-only internal endpoint in m2-gpt:

GET /internal/v1/metering/turn/{correlation_id}

Auth: service key, internal network only.

Response:

{
  "correlation_id": "turn_01j2abc",
  "tenant_id": "m2-core",
  "agent_id": "chris-m2o",
  "started_at": "2026-07-02T00:00:00Z",
  "ended_at": "2026-07-02T00:12:00Z",
  "model_calls": [
    {
      "route_id": "spark-glm",
      "model": "GLM-5.1",
      "prompt_tokens": 120000,
      "completion_tokens": 18000,
      "total_tokens": 138000,
      "cost_usd": 0.42,
      "status": "ok"
    }
  ],
  "totals": {
    "prompt_tokens": 120000,
    "completion_tokens": 18000,
    "total_tokens": 138000,
    "cost_usd": 0.42,
    "wall_time_seconds": 720
  }
}

This endpoint is a gateway concern but S6 defines it as the minimum metering read needed for evidence capture. If not available in MVP, evidence_capture records m2_gpt_correlation_ids and tokens_unknown=true.

Events

S6 emits JSONL-compatible events to stdout and optional webhook for S2/S3:

{
  "event_type": "market.evidence.created",
  "event_version": "v1",
  "ts": "2026-07-02T00:00:00Z",
  "evidence_id": "ev_2026w27_01j2abc",
  "tenant_id": "m2-core",
  "listing_ids": ["lst_competitor-scan"],
  "reusable_decision": "create_solution"
}

Other events:

  • market.proposal.generated
  • market.proposal.accepted
  • market.proposal.dismissed
  • market.evidence.attached_to_listing

Storage and attachment

Authoritative evidence storage:

  • Memory semantic copy: agent_id="market:evidence" in memory-api.
  • Audit copy: JSONL at proposer service volume /var/lib/m2-market-proposer/evidence/YYYY-Www.jsonl.
  • Listing attachment: S6 does not mutate listing truth directly. It emits market.evidence.attached_to_listing; S2/S3 indexer updates listing.evidence_summary, listing stats, and optional registry audit PR/commit.

Proposal audits:

  • Stored as summaries under agent_id="market:proposals" with tenant_id scoped to caller.
  • TTL/default retention: 90 days for tenant-private, indefinite for shared scrubbed proposal statistics.

4. Integration contract with other subsystems

S1 ledger

Inputs from S1:

  • Current price for install/job/resource.
  • Job escrow/quote status when path kind is operator_job.
  • Platform cut defaults only for display; S6 does not settle.

Outputs to S1:

  • Approved path metadata may become ledger reason=route|install|job ref.
  • Proposal id should be included in ledger refs where possible: prop_...:path_....

S2 catalog

Inputs from S2:

  • market:catalog searchable listing payloads.
  • Listing stats: installs, rating, proposals_shown, proposals_accepted.
  • Tenant visibility policy.

Outputs to S2:

  • market.proposal.generated/accepted/dismissed events.
  • Evidence attachment events by listing id.
  • Suggested new capability tags from proposal normalization.

S3 store/install

Inputs from S3:

  • M2 Store deep links: m2store://listing/<listing_id>.
  • Install state and permission diff when available.

Outputs to S3:

  • Proposal path next actions with listing ids.
  • Evidence of install success/failure for listing stats.

S4 Scout

Shared contracts:

  • S4 can call POST /v1/proposals with harness="scout" and a session summary.
  • S4 owns push timing/UI; S6 owns proposal construction and estimate basis.
  • Proposal/dismissal telemetry uses the same events.

S5 packaging

Inputs from S5:

  • Build/package evidence created during solution packaging.
  • Manifest ids, release refs, tool requirements.

Outputs to S5:

  • Reusable verdicts: create_solution and update_solution.
  • Evidence citations that should be included in a future solution.evidence[].

m2-gpt

Touchpoints:

  • Tenant/agent identity from bearer key.
  • m2-gpt spend_log and cognition traces by correlation_id.
  • Optional gateway middleware/tool-dispatch registration so all OpenAI-wire harnesses can call proposal tool.

No S6 secrets are baked into images. M2_MARKET_API_KEY and M2_GPT_API_KEY are runtime-injected.

memory-api

Touchpoints:

  • POST /memory/search with agent_id="market:catalog" and agent_id="market:evidence".
  • Store via existing memory write path once auth is enforced.
  • Tenant/principal filters must be passed on every query.

m2o/herdr

Touchpoints:

  • herdr run summaries supply active time, failed/succeeded steps, tools invoked.
  • Desktop identity from fleet/herdr config supplies agent_id.
  • Runtime-sync installs the Hermes skill across primus and agent-latest without image rebuild.

5. Options compared

Option A: Hermes skill only

Pros:

  • Fastest MVP.
  • Fits primary agent surface.
  • Can render proposals conversationally.

Cons:

  • Duplicates retrieval/estimate logic if OpenClaw or Store needs it.
  • Harder to centralize evidence writes and audit.

Option B: m2-gpt middleware/tool only

Pros:

  • Harness-agnostic by default for anything OpenAI-wire.
  • Already sees identity, tokens, model usage, and budgets.

Cons:

  • Bloats latency-sensitive gateway.
  • Proposal logic depends on catalog and ledger services, which should not be in the critical chat-completion path.
  • Harder to evolve independently.

Pros:

  • Keeps deterministic business logic and evidence writes centralized.
  • Hermes gets a thin local skill; OpenClaw/Store/Scout can call the same API.
  • m2-gpt only provides identity/metering and optional tool exposure.
  • Can be canary-deployed as a Coolify app and rolled back independently.

Cons:

  • One new small service to operate.
  • Requires service keys and network ACLs.

Recommendation: Option C for MVP. Add gateway middleware only for two narrow functions: expose market.propose as an OpenAI tool later, and provide read-only metering by correlation id.

Cost estimate method

Compared:

  • Static price table: simple but ignores real work history.
  • LLM-estimated effort: flexible but unverifiable.
  • Evidence-weighted estimates: uses real prior tokens/time/outcomes and listing telemetry.

Recommendation: evidence-weighted estimates. Fall back to static seed values only when sample_count < 2, and mark as low_confidence.

6. Risks/edge cases

  • Tenant leakage: all memory searches must include tenant filters; forbidden evidence returns 404, not 403.
  • Client-derived commercialization: shared evidence requires owner_initiated=true and double_scrubbed=true; otherwise tenant-private only.
  • Secrets in evidence: evidence capture uses the fedlearn scrubber policy and fails closed on high-entropy strings.
  • Bad estimates from tiny samples: responses must expose sample_count, method, and confidence.
  • Failed jobs hidden from pricing: failed evidence is required because it improves estimates; proposals must distinguish success evidence from failure evidence.
  • Gateway fragility: do not put catalog search inside the hot chat-completion path; proposer service is called explicitly by skill/tool.
  • Abuse/spam proposals: proposal audits are rate-limited per operator and do not auto-spend credits.
  • Split-brain memory-api: indexer/proposer must use the live endpoint resolver until fedlearn T13 is complete; evidence JSONL audit copy allows replay.
  • Clock/correlation mismatch: if m2-gpt turn id is missing, evidence can still record herdr run ids and tokens_unknown=true; later backfill may attach metering.
  • Cross-harness UX drift: Hermes prose is non-authoritative; proposal JSON is the contract.

7. [NEEDS CLARIFICATION]

  1. What exact m2-gpt correlation id is guaranteed to be available inside Hermes skill execution: turn_id, correlation_id, or a new M2_GPT_CORRELATION_ID env var?
  2. Who is allowed to mark tenant-private evidence as owner_initiated=true and double_scrubbed=true: tenant admin, platform operator, or both?
  3. What is the first static fallback conversion from USD/token cost to M2 credits for estimates before ledger/resource pricing data is available?