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>
668 lines
23 KiB
Markdown
668 lines
23 KiB
Markdown
# 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`.
|
|
|
|
```json
|
|
{
|
|
"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:
|
|
|
|
```json
|
|
{
|
|
"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`.
|
|
|
|
```json
|
|
{
|
|
"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`.
|
|
|
|
```json
|
|
{
|
|
"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:
|
|
|
|
```json
|
|
{"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:
|
|
|
|
```json
|
|
{"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:
|
|
|
|
```json
|
|
{
|
|
"tenant_id": "m2-core",
|
|
"intent": "build competitor scan report",
|
|
"listing_ids": ["lst_competitor-scan"],
|
|
"capabilities": ["research", "report-generation"],
|
|
"confidence_floor": 0.6
|
|
}
|
|
```
|
|
|
|
Response:
|
|
|
|
```json
|
|
{
|
|
"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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```text
|
|
market-propose/
|
|
SKILL.md
|
|
skill.json
|
|
scripts/propose.py
|
|
scripts/evidence_capture.py
|
|
```
|
|
|
|
`skill.json`:
|
|
|
|
```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:
|
|
|
|
```json
|
|
{
|
|
"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:
|
|
|
|
```json
|
|
{
|
|
"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.
|
|
|
|
### Option C: Proposer service + Hermes skill adapter (recommended)
|
|
|
|
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?
|
|
|