openvibers/openvibe.ai Commits

docs: AI Inference Exchange P0 baseline and provider eligibility matrix (#288)

OP OpenVibers committed 9 days ago · da0727e05b · 3 files, +550 −0

- docs/ai-exchange-baseline.md: repo HEAD/version/pin table and per-authority EXISTS/MISSING gap matrix against PLAN.md/CHECKPOINT.md.
- docs/provider-matrix.md + .json: provider API format, existing adapter, BYOK, resale terms quotes/URLs/dates, and access_mode default for all PLAN.md section C candidates.
- No code changes; no deployments; no money enabled.

Changes

ddiff --git a/docs/ai-exchange-baseline.md b/docs/ai-exchange-baseline.md
nnew file mode 100644
iindex 0000000..a70e69d
---- /dev/null
++++ b/docs/ai-exchange-baseline.md
@@@ -0,0 +1,178 @@
++# OpenVibe AI Inference Exchange — P0 Baseline & Gap Matrix
++
++> Research checkpoint: 2026-11-03
++> Source documents: `plan-state-2026-10-22/ai-exchange/PLAN.md` and `CHECKPOINT.md`
++> Scope: documentation-only baseline. No code changes, no deployments, no money enabled.
++
++This document records the current state of the repositories that implement (or will implement) the AI Inference Exchange, and a gap matrix against the PLAN.md / CHECKPOINT.md requirements.
++"EXISTS" means the feature is present in source on `origin/main` at the recorded SHA. "MISSING" means it is not present or is materially incomplete. No inference is made about production deployment.
++
++---
++
++## 1. Repository baseline
++
++| Repository | Default branch | HEAD SHA (`origin/main`) | Version | openvibe-contracts pin | openvibe-sdk pin | openvibe-shared pin |
++|---|---|---|---|---|---|---|
++| OpenVibe.AI | `main` | `c17cabb2e898683a83672d598f1bd00774e8446d` | 0.1.0 | v0.262.0 | v0.82.0 | v4.109.2 |
++| OpenVibe.Billing | `main` | `5dd4d99eb88b10c915a0aeb80274229d32e822db` | 0.1.0 | v0.222.0 | v0.82.0 | v4.109.2 |
++| OpenVibe.Network | `main` | `5c485e66913a2b2123d797b5f66276e7dac9257f` | 1.0.0 | v0.280.0 | v0.82.0 | v4.109.2 |
++| OpenVibe.Services | `main` | `29916bc1fe000536efca3573d88f04c11ed2d604` | 0.1.0 | v0.222.0 | v0.82.0 | v4.109.2 |
++| OpenVibe.SDK | `main` | `8be2ecdce7c7450e48c88cf533fddb259f96960e` | 0.82.0 | — | — | — |
++| OpenVibe.Contracts | `main` | `6ae82ddbdf2927d7c55cc5c0e8d0ba5d48c7a215` | 0.283.0 | — | — | — |
++| OpenVibe.Bench | `main` | `74ee1a527ffb9ff9aa1d9f6dbe06c534efef7335` | 0.1.0 | v0.247.0 | v0.82.0 | v4.109.2 |
++| OpenVibe.Report | `main` | `ecbd3f1f641dd74d5316a5ad8700be90d28e8bb8` | 0.1.0 | v0.275.0 | v0.82.0 | v4.109.2 |
++| OpenVibe.Exchange | `main` | `b562b0fd7d018dfa036219585a7d591330a50f3a` | 0.1.0 | v0.235.0 | v0.82.0 | v4.109.2 |
++| OpenVibe.Host | `main` | `46421d082f7d38c370cd9050df2135d7800e24f8` | 0.3.0 | v0.272.0 | v0.82.0 | v4.109.2 |
++| OpenVibe.Run | `main` | `1bacc978ab25d7294a6f5f75a339645b47fe6406` | 0.1.0 | v0.250.0 | v0.82.0 | v4.109.2 |
++| OpenVibe.Node | `main` | `c8564f0b58f567dd909daaadd2f2a7b91f29a7a7` | v0.38.0 (tag) | N/A (Go) | N/A | N/A |
++| OpenVibe.Watch | `main` | `52bfa57a83fdf3cb1b0879071c02ae6f5c601fa4` | 0.1.0 | v0.222.0 | v0.82.0 | v4.109.2 |
++| OpenVibe.Sources | `main` | `7b40905dd943a7ed33ed7afe4ed637f547f48df5` | 0.1.0 | v0.224.0 | v0.82.0 | v4.109.2 |
++| OpenVibe.Codes | `main` | `f955eebafd2d71c5660037cfe5f98631d4160c65` | 0.7.0 | v0.261.0 | v0.82.0 | v4.109.2 |
++| OpenVibe.Actor | `main` | `41d802a8f1140fa979185a4528ec59d12d888bfa` | 0.1.0 | v0.269.0 | v0.82.0 | v4.109.2 |
++
++Notes:
++- All repos except Node use npm `package.json` versions and tarball pins.
++- Node uses Go modules; the latest tag at refresh was `v0.38.0`.
++- Shared and SDK are pinned uniformly at v4.109.2 and v0.82.0 respectively across the matrix repos that consume them.
++- Contracts pins diverge by repo (Network v0.280.0, AI v0.262.0, Billing/Services v0.222.0, etc.). This is consistent with the PLAN note that repos deliberately pin different versions.
++
++---
++
++## 2. Per-authority EXISTS / MISSING matrix
++
++### 2.1 OpenVibe.AI — Inference authority
++
++| Requirement area | Status | Evidence / citation |
++|---|---|---|
++| OpenAI-compatible `POST /v1/chat/completions` | **EXISTS** | `server/api/openai.js` (lines 121-191) |
++| Anthropic-compatible `POST /v1/messages` | **EXISTS** | `server/api/messages.js` (lines 136-195) |
++| Streaming support with backpressure/abort | **EXISTS** | `server/api/openai.js:createLiveStream` (lines 48-88); `server/api/messages.js:createEventStream` (lines 51-91); `server/providers/index.js` executes with timeout/cancellation |
++| Provider/model registry with versioning and audit | **EXISTS** | `server/registry.js` (providers, models, routes, templates, workflows with append-only versions and audit log) |
++| Provider kinds: stub, openai, responses, anthropic, http, whisper | **EXISTS** | `server/registry.js:16` (`PROVIDER_KINDS`); adapters in `server/providers/{openai,responses,anthropic,gemini,http,whisper,stub}.js` |
++| BYOK / person credentials with AES-256-GCM sealing | **EXISTS** | `server/credentials.js` (seal/open with owner+subject+provider AAD); `server/console/presets.js` for provider defaults; test on save |
++| Project-owned provider via `x_openvibe.provider` | **EXISTS** | `server/api/openai.js:137-138`; `server/runs.js:projectProviderOf` (lines 69-76) |
++| User-owned machine inference (`node`) | **EXISTS** | `server/credentials.js:41-42`; `server/machines.js`; `server/providers/index.js:135` |
++| Routing via `openvibe-sdk/placement` | **EXISTS** | `server/providers/index.js:23,291-395` (`poolCandidates`) |
++| `explain` (objective, selected, rejected candidates, cost, latency) | **EXISTS** | `server/providers/index.js:378-385`; returned as `x_openvibe` in `server/api/openai.js:171` |
++| Circuit breaker per provider | **EXISTS** | `server/providers/index.js:168-191` |
++| Rate cards with provenance (`platform.rate-card@1`) | **EXISTS** | `server/providers/rate-cards.js` |
++| Quotas (pre-call reserve) | **EXISTS** | `server/quota.js` |
++| Tier budgets / governance (Valkey-based, flag off) | **EXISTS** | `server/govern.js` (`AI_GOVERN_TIERS` default off) |
++| Bench integration (`bench.rating.changed` events) | **EXISTS** | `server/bench/events.js`, `server/bench/evidence.js`; `server/providers/index.js:440-447` |
++| Usage samples (`platform.usage-sample@1`) | **EXISTS** | `server/usage-samples.js` |
++| Truthful `GET /v1/models` with real model/revision catalog | **MISSING** | Both `server/api/openai.js:194-196` and `server/api/messages.js:199-201` return only a single synthetic `openvibe` model. No artifact/revision/versioned catalog endpoint exists. |
++| Exact model id `<org>/<model>[:<quant>]@<revision>` | **MISSING** | No exact-id parser or artifact registry in `server/registry.js`. `ModelArtifact`, exact pinning, and SHA256 provenance are not present. |
++| Dynamic aliases (`openvibe/auto`, `economy`, `balanced`, `fast`, `private`) | **MISSING** | The router returns `x_openvibe` metadata but the only public model is `openvibe`; no alias resolution or policy selection logic exists. |
++| `POST /v1/responses` and embeddings | **MISSING** | Only `chat/completions` and `messages` are implemented; no Responses or embeddings endpoints. |
++| Inference-specific sub-cent billing (nano-USD) | **MISSING** | `server/quota.js` and `server/govern.js` still use floating-point USD / Vibes-bit style holds. AI delegates cost to Billing but does not yet use nano-USD precision internally. |
++| `max_cost_usd` / reservation hold coordination with Billing | **MISSING** | Runs accept `max_tokens` but not `max_cost_usd`; no hold/settle protocol with Billing. |
++| Provider commercial-rights eligibility check (`OWN_DEPLOYMENT`, `AUTHORIZED_WHOLESALE`, etc.) | **MISSING** | `registry.js` has `billing_profile` (`metered`, `subscription`, `payg`, `free`, `byok`) but no `provider_access` / commercial-rights field. `poolCandidates` does not filter by resale authority. |
++| Versioned supply vs retail rate cards | **PARTIAL** | `rate-cards.js` builds `platform.rate-card@1` cards with `source`/`verified_at`, but has no `side: supply|retail` or immutable versioned snapshots. |
++| Per-route Bench opt-in and blind/private handling | **PARTIAL** | Routes have `learn_from_bench` / `bench_kind` columns (`server/registry.js:197`) and `bench.select` is called, but private-benchmark isolation is not verified in this baseline. |
++
++### 2.2 OpenVibe.Billing — Financial authority
++
++| Requirement area | Status | Evidence / citation |
++|---|---|---|
++| Production money ledger (Vibes bits) | **EXISTS** | `server/ops/rating.js`, `server/ops/usage.js`, `server/config.js`, `server/ledger.js`; ADR-012 |
++| `chargeFor()` rounds each reading up to one Vibes bit | **EXISTS** | `server/ops/rating.js:52-68` performs rational arithmetic then rounds up once to whole vibes-bits (`(num + den - 1n) / den`). Default `BILLING_BITS_PER_USD=100` in `server/config.js:103`. |
++| `platform.rate-card@1` loading/validation | **EXISTS** | `server/ops/rating.js:245` `loadCards()` validates `platform.rate-card@1`; `migrations/0004_rating.sql:16-31` creates `rate_cards` table. |
++| Promo-allowance / hard-budget integration | **EXISTS** | `server/ops/rating.js:170-190` calls `promo.consume`, `requireFunds`, `spendBudgets` inside serializable `money()` transaction; `usage_budgets` in `migrations/0004_rating.sql:37-47`. |
++| Idempotent usage ingestion | **EXISTS** | `server/ops/usage.js:57` `record()` stores `platform.usage-sample@1` by `idempotency_key`; `usage.js:31` refuses conflicting replays. |
++| Double-entry ledger | **EXISTS** | `server/ledger.js:81` `post()`; `ledger.js:142` `money()` uses serializable isolation; `ledger.js:147` `requireFunds()`. |
++| Sub-cent inference accounting / nano-USD subledger | **MISSING** | Money is integer vibes-bits only; no nano-USD ledger, no `billing.inference-hold@1` / `billing.inference-settlement@1` schemas, no `POST /internal/inference/holds` endpoints. |
++| Reservation/hold/settle/release for inference | **MISSING** | `chargeFor()` is post-hoc; no pre-execution hold, no `max_nano_usd`, no idempotent hold/settle, no separate hold account. |
++| BYOK no-double-bill routing fee | **MISSING** | Rating prices against loaded cards and credits promo/Vibes ledger; no passthrough or zero-rating when caller supplies their own provider key or machine. |
++| Reconciliation / crash recovery leases | **MISSING** | Not present in inspected files. |
++| Automatic rate-card ingestion | **MISSING** | `BILLING_RATING_INTERVAL_MS` defaults to `0` (`server/config.js:175`); card loading is manual/offline. |
++
++### 2.3 OpenVibe.Network — Identity & credential authority
++
++| Requirement area | Status | Evidence / citation |
++|---|---|---|
++| Users, OAuth/OIDC, projects, developer apps | **EXISTS** | `server/developer/routes.js:151-206` mounts project-scoped routes for apps, credentials, grants, quotas, agents, budgets, export tokens. |
++| Apps / OAuth clients | **EXISTS** | `server/developer/store.js:457` `createApp` with `client_id == app_<ULID>`, environment (`sandbox`/`production`), `client_type`; `store.js:513` `revokeApp`. |
++| Project-scoped credentials (secrets hashed) | **EXISTS** | `server/developer/store.js:432` `newSecret()` creates `ovsec_…`; `store.js:436` stores SHA-256 hashes only; `store.js:592` constant-time verification. |
++| Credential rotation / revocation | **EXISTS** | `server/developer/store.js:544` `rotateCredential` with overlap; `store.js:575` `revokeCredential`; app revocation cascades to credentials/agents. |
++| Grants / capability scopes | **EXISTS** | `server/developer/store.js:632` `requestGrant`, `store.js:656` `decideGrant`; `policy.js` defines grantability; `tokens.js:50` `effectiveGrants`; `tokens.js:96` `mint`. |
++| Agent tokens / delegated grants with confirmation | **EXISTS** | `server/developer/agents.js:285` `putGrant` with `auto`/`confirm`; `server/developer/agent-tokens.js:38` mints `agent:agt_…`; `confirmations.js:127` owner-approval flow. |
++| Agent budgets / project quotas | **EXISTS** | `server/developer/agents.js:348` `setBudget` / `agents.js:338` `listBudgets`; `store.js:696` `setQuota` / `store.js:683` `listQuotas`. |
++| Long-lived personal API key resource separate from OAuth | **MISSING** | System is OAuth-client-centric; no standalone personal API key concept. |
++| App-level budgets | **MISSING** | `dev_agent_budgets` exists but no `dev_app_budgets`; routes expose only per-agent budgets. |
++| Fine-grained OAuth scopes separate from capability ids | **PARTIAL** | `scope` is parsed as whitespace-separated capability ids (`tokens.js:67`); no separate scope namespace. |
++
++### 2.4 OpenVibe.Services — Developer portal
++
++| Requirement area | Status | Evidence / citation |
++|---|---|---|
++| Portal pages (projects, apps, credentials, grants, quotas) | **EXISTS** | `server/http/portal.js:180-200` projects list; `portal.js:513-574` ADR-048 resources page; `portal.js:577` usage/cost/quotas via `usageBody`; `portal.js:872-920` playground page. |
++| Playground (Events / Media) | **EXISTS** | `server/domain/playground.js:35` `KINDS = { events, media }`; `playground.js:159` `run()` enforces app active & sandbox, grant check, token mint/verify, SDK call, audit log. |
++| Generic usage/cost views | **EXISTS** | `server/http/portal.js:577` renders Network usage API via `server/render/usage.js`. |
++| Model explorer / AI inference playground | **MISSING** | `playground.js` hard-codes `events` and `media`; no AI/model explorer or inference playground. |
++| Inference-specific usage/cost views (tokens-in/out, per-model, explain) | **MISSING** | Usage page is generic service rollups; no per-model/token-kind/explain breakdown. |
++| BYOK credential / AI budget / fund UI | **MISSING** | No UI for adding provider credentials, setting AI usage budgets, or viewing inference budgets. |
++
++### 2.5 OpenVibe.SDK — Placement engine
++
++| Requirement area | Status | Evidence / citation |
++|---|---|---|
++| Generic `placement` module | **EXISTS** | `src/placement.js:127` `plan()` with hard-constraints → objective → hysteresis; `placement.js:54` `marginalCost()`; `placement.js:70` `ownedLoadCost()` for prepaid/user-owned capacity; `placement.js:258` `TRUST_CLASSES` includes `user-owned`. |
++| Signed plans / plan holder | **EXISTS** | `src/placement.js:214` `signPlan()` / `verifyPlan()`; `placement.js:240` `createPlanHolder()` keeps last valid plan. |
++| Cost estimation helpers | **EXISTS** | `src/cost.js:14` `rateCard()`; `src/cost.js:36` `costSnapshot()`; `src/cost.js:55` `estimate()`. |
++| AI client | **EXISTS** | `src/ai.js:23` `createAiClient()` with runs and direct chat/generate/embed/etc. |
++| Governance / quota primitives | **EXISTS** | `src/govern.js:147` `createGovernor()` with reserve/commit/release/lease; `src/usage.js:40` `usageSample()`; `src/usage.js:124` `createUsageReporter()`. |
++| Hysteresis / stable route affinity | **PARTIAL** | `placement.js:167` hysteresis keeps current placement unless gain ≥ `minGain` (default 0.15) or current ineligible; no adaptive hysteresis by workload class or cost volatility. |
++| Cost-per-successful-task ranking | **PARTIAL** | `placement.js:270+` `place()`, `successOf()`, `learn()` produce cost-per-success explanation; Bench-linked quality confidence and explicit cost-per-solved ranking not verified. |
++| `explain` with excluded reasons | **PARTIAL** | `placement.js:88` `excluded()` gives reasons; `ai.run@1` embeds explain but no standalone `ai.route-explain@1` schema. |
++| AI-specific deployment input transform | **MISSING** | Placement handles generic `platform.workload-requirements@1`; no AI-specific wrapper converting model/provider into requirements. |
++| `explain` client helper in `src/ai.js` | **MISSING** | `ai.js` returns the run object but has no dedicated `ai.route.explain` helper. |
++| Inference-specific units in governor | **MISSING** | `govern.js:24` `UNITS` has `ai-token`/`ai-usd` but no `inference-task` or per-model unit link to model pricing. |
++
++### 2.6 OpenVibe.Contracts — Schema authority
++
++| Requirement area | Status | Evidence / citation |
++|---|---|---|
++| Existing `ai.*`, `billing.*`, `platform.*` schemas | **EXISTS** | `contracts/ai/`, `contracts/billing/`, `contracts/platform/` |
++| `ai.model@1` | **EXISTS** | `contracts/ai/model.v1.json` catalogued as `ai.model` v1.0.0 (provider_key, model_key, type, status, cost, supports). |
++| `ai.model-artifact@1`, `ai.inference-deployment@1`, `ai.route-explain@1` | **MISSING** | No files or catalog entries; `ai.run@1` embeds an `explain` field but it is not a standalone schema. |
++| `billing.inference-hold@1`, `billing.inference-settlement@1` | **MISSING** | Not present in inspected `contracts/billing/`. |
++| `platform.rate-card@1` extended with `side`, `version`, `effective_from/to` | **MISSING** | Existing `platform.rate-card@1` does not include these fields in the inspected version. |
++
++### 2.7 Other authorities (high-level)
++
++| Authority | EXISTS | MISSING |
++|---|---|---|
++| **OpenVibe.Bench** | Pinned evaluation rounds, Elo/Pareto/cost-per-solved rankings, blind judgments, MCP (`docs/api.md`, `docs/benchmarks.md`, `server/pick/pick.js`, `server/rating/*`). | Model-variant family schemas, throughput/TTFT quantitative evidence types, inference-specific benchmark gates. |
++| **OpenVibe.Report** | Time-series/aggregation views, consumes Bench AI boards. | Supply-side profitability summaries tied to the new inference subledger; real model-catalog analytics. |
++| **OpenVibe.Host / Run** | Worker/deployment orchestration, async jobs. | Pinned GGUF/vLLM/SGLang inference worker images, GPU rental orchestration with budget gates. |
++| **OpenVibe.Node / Bot** | Owner-machine inference path in AI (`server/machines.js`). | Commercial node-pool isolation, DNS-rebinding/SSRF tests for node routing. |
++| **OpenVibe.Exchange** | v1 free/swap-only marketplace (`README.md`, `STATUS.json`, migrations). | Paid listing v2; inference API/model-pack marketplace (explicitly out of scope per D6). |
++| **OpenVibe.Codes / Actor** | Coding harness, provider integrations, proof-of-work. | Hosted runner completion; integration with new catalog/aliases. |
++| **OpenVibe.Watch / Sources** | Market-data sourcing, rate/model change alerts. | Official provider price/terms ingestion for inference providers; stale-data warnings. |
++| **OpenVibe.SDK** | Generic placement, cost, AI client, govern/usage reporters (`src/placement.js`, `src/cost.js`, `src/ai.js`, `src/govern.js`, `src/usage.js`). | AI-specific deployment transform, explain client helper, inference task units, adaptive hysteresis. |
++| **OpenVibe.Contracts** | Existing `ai.*`, `billing.*`, `platform.*` schemas; `ai.model@1` exists (`contracts/ai/model.v1.json`). | `ai.model-artifact@1`, `ai.inference-deployment@1`, standalone `ai.route-explain@1`, `billing.inference-hold@1`, `billing.inference-settlement@1`, `platform.rate-card@1` side/version extensions. |
++
++---
++
++## 3. Critical blockers identified
++
++1. **Billing precision (launch blocker per PLAN F and CHECKPOINT D1-D2).** `OpenVibe.Billing/server/ops/rating.js` still rounds each usage reading up to one Vibes bit. A nano-USD inference subledger with reservation/hold/settle is missing.
++2. **Model catalog truth.** `GET /v1/models` lies — it returns a synthetic `openvibe` model. Exact artifact ids, revision pinning, and dynamic aliases are not implemented.
++3. **Commercial eligibility.** No `provider_access` classification (`OWN_DEPLOYMENT`, `AUTHORIZED_WHOLESALE`, etc.) is enforced in routing; paid managed routes cannot be safely enabled.
++4. **Contract schemas.** `ai.model@1` exists, but `ai.model-artifact@1`, `ai.inference-deployment@1`, standalone `ai.route-explain@1`, `billing.inference-hold@1`, `billing.inference-settlement@1`, and the extended `platform.rate-card@1` (with `side`/`version`) do not exist yet.
++
++---
++
++## 4. Next work ordered by dependency
++
++Per PLAN section G and CHECKPOINT jobs:
++
++1. **P1 Contracts** (`cx:aix-p1-contracts`) — add D4 schemas and invalid fixtures.
++2. **P2 Billing** (`dsh:aix-p2-billing`) — nano-USD subledger, holds/settlements, reconciliation proofs.
++3. **P3 Network keys** (`cc:aix-p3-keys`) — one-time reveal, scopes, budgets, rotation.
++4. **P4 AI catalog** (`mm:aix-p4-catalog`) — truthful `/v1/models`, exact ids, aliases.
++5. **P5 Worker** (`pg:aix-p5-worker`) — llama.cpp/vLLM worker image and cost model.
++6. **P1 Placement** (`cm:aix-p1-placement`) — cost-per-success, explain, exclusions.
++7. **P8 Services UX** (Claude/Opus) — model explorer, playground, usage/cost views against fixtures.
++
++This baseline leaves all PRs open for orchestrator review; nothing is deployed or merged.
ddiff --git a/docs/provider-matrix.json b/docs/provider-matrix.json
nnew file mode 100644
iindex 0000000..32b8880
---- /dev/null
++++ b/docs/provider-matrix.json
@@@ -0,0 +1,319 @@
++{
++ "meta": {
++ "checked_date": "2026-11-03",
++ "source": "plan-state-2026-10-22/ai-exchange/PLAN.md section C",
++ "rule": "access_mode defaults to UNVERIFIED unless terms clearly allow resale AND an executed agreement exists. Retail subscriptions and coding-agent plans do not count as transferable wholesale compute."
++ },
++ "providers": [
++ {
++ "provider": "OpenAI",
++ "api_format": "OpenAI",
++ "existing_adapter": "openai",
++ "byok": true,
++ "access_mode_default": "RESTRICTED",
++ "resale_terms_quote": "Customer may not resell or lease access to its Account or any End User Account.",
++ "terms_url": "https://openai.com/policies/business-terms/",
++ "terms_effective": "2026-01-01",
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "Anthropic",
++ "api_format": "Anthropic Messages",
++ "existing_adapter": "anthropic",
++ "byok": true,
++ "access_mode_default": "RESTRICTED",
++ "resale_terms_quote": "resell the Services except as expressly approved by Anthropic",
++ "terms_url": "https://www.anthropic.com/legal/commercial-terms",
++ "terms_effective": "2025-06-17",
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "Google Gemini / Vertex",
++ "api_format": "Gemini / OpenAI-compatible",
++ "existing_adapter": "gemini / openai",
++ "byok": true,
++ "access_mode_default": "RESTRICTED",
++ "resale_terms_quote": "sell, resell, sublicense, transfer, or distribute any or all of the Services",
++ "terms_url": "https://cloud.google.com/terms",
++ "terms_effective": null,
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "Mistral",
++ "api_format": "OpenAI-compatible",
++ "existing_adapter": "openai (BYOK credential)",
++ "byok": true,
++ "access_mode_default": "RESTRICTED",
++ "resale_terms_quote": "nor grant any third party access to the Mistral AI Products without our prior written authorization",
++ "terms_url": "https://legal.mistral.ai/terms/commercial-terms-of-service",
++ "terms_effective": "2026-09-25",
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "xAI / Grok",
++ "api_format": "OpenAI-compatible",
++ "existing_adapter": "openai (BYOK credential)",
++ "byok": true,
++ "access_mode_default": "RESTRICTED",
++ "resale_terms_quote": "Enterprise terms permit Bundled Services to Customer's End Users only; no standalone resale right found.",
++ "terms_url": "https://x.ai/legal/terms-of-service-enterprise",
++ "terms_effective": "2026-10-27",
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "Together AI",
++ "api_format": "OpenAI-compatible",
++ "existing_adapter": "openai (BYOK credential)",
++ "byok": true,
++ "access_mode_default": "RESTRICTED",
++ "resale_terms_quote": "transfer, distribute, resell, lease, license, or assign the Services or otherwise offer the Services on a standalone basis",
++ "terms_url": "https://www.together.ai/terms-of-service",
++ "terms_effective": "2026-05-19",
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "DeepInfra",
++ "api_format": "OpenAI-compatible",
++ "existing_adapter": "openai / http",
++ "byok": true,
++ "byok_note": "custom credential",
++ "access_mode_default": "RESTRICTED",
++ "resale_terms_quote": "resell, sublicense, rent, distribute, or otherwise make the Services available to any third party except as expressly permitted under this Agreement or the applicable Service Order",
++ "terms_url": "https://deepinfra.com/terms",
++ "terms_effective": "2026-10-15",
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "RunPod (serverless)",
++ "api_format": "OpenAI-compatible",
++ "existing_adapter": "openai / http",
++ "byok": false,
++ "access_mode_default": "RESTRICTED",
++ "resale_terms_quote": "Resell any credits purchased through the Service without the prior written consent of Runpod; Marketplace / compute terms restrict commercial exploitation.",
++ "terms_url": "https://www.runpod.io/terms-of-service",
++ "terms_effective": "2026-03-24",
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "Replicate",
++ "api_format": "Replicate API",
++ "existing_adapter": "http",
++ "byok": false,
++ "access_mode_default": "RESTRICTED",
++ "resale_terms_quote": "rent, lease, lend, sell, sublicense, assign, distribute, publish, transfer, or otherwise make available any Services to any person, including ... software as a service",
++ "terms_url": "https://replicate.com/terms",
++ "terms_effective": "2026-04-01",
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "Cloudflare Workers AI",
++ "api_format": "Workers AI REST",
++ "existing_adapter": "http",
++ "byok": false,
++ "access_mode_default": "RESTRICTED",
++ "resale_terms_quote": "rent, lease, loan, export, or sell access to the Services to any third party",
++ "terms_url": "https://www.cloudflare.com/terms/",
++ "terms_effective": "2025-09-12",
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "AWS Bedrock",
++ "api_format": "Bedrock Converse / Invoke",
++ "existing_adapter": "http",
++ "byok": false,
++ "access_mode_default": "RESTRICTED",
++ "resale_terms_quote": "Standard AWS Customer Agreement / Service Terms do not permit resale of managed AI inference; AWS marketplace/partner programs require separate authorization.",
++ "terms_url": "https://aws.amazon.com/service-terms/",
++ "terms_effective": "2026-11-03",
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "Azure OpenAI / Foundry",
++ "api_format": "Azure OpenAI / REST",
++ "existing_adapter": "http",
++ "byok": false,
++ "access_mode_default": "RESTRICTED",
++ "resale_terms_quote": "Microsoft Customer Agreement / Online Subscription Agreement restrict resale; embedding in third-party SaaS requires negotiated terms.",
++ "terms_url": "https://azure.microsoft.com/en-us/support/legal/",
++ "terms_effective": null,
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "Featherless",
++ "api_format": "OpenAI-compatible",
++ "existing_adapter": "openai / http",
++ "byok": false,
++ "access_mode_default": "AUTHORIZED_WHOLESALE",
++ "access_mode_note": "Scale plans only; requires executed Scale agreement.",
++ "resale_terms_quote": "Scale plans are not subject to said limits and may be used in arbitrary applications, including inference resale.",
++ "terms_url": "https://featherless.ai/terms",
++ "terms_effective": "2024-06-10",
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "Chutes",
++ "api_format": "Custom / OpenAI-compatible",
++ "existing_adapter": "http",
++ "byok": false,
++ "access_mode_default": "UNVERIFIED",
++ "resale_terms_quote": "Terms fetched; no explicit resale/wholesale clause found. Subscriptions are for casual/direct use; PAYGO required for production.",
++ "terms_url": "https://chutes.ai/terms",
++ "terms_effective": "2026-03-16",
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "Baseten",
++ "api_format": "OpenAI-compatible",
++ "existing_adapter": "http",
++ "byok": false,
++ "access_mode_default": "UNVERIFIED",
++ "resale_terms_quote": "Terms page did not return readable content in this check.",
++ "terms_url": "https://www.baseten.co/terms-of-service",
++ "terms_effective": null,
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "Venice",
++ "api_format": "OpenAI-compatible",
++ "existing_adapter": "http",
++ "byok": false,
++ "access_mode_default": "UNVERIFIED",
++ "resale_terms_quote": "Terms URL returned 404.",
++ "terms_url": "https://venice.ai/terms-of-service",
++ "terms_effective": null,
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "Nebius",
++ "api_format": "OpenAI-compatible",
++ "existing_adapter": "http",
++ "byok": false,
++ "access_mode_default": "UNVERIFIED",
++ "resale_terms_quote": "Terms URL returned 404.",
++ "terms_url": "https://nebius.com/legal/terms-of-service",
++ "terms_effective": null,
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "Novita",
++ "api_format": "OpenAI-compatible",
++ "existing_adapter": "http",
++ "byok": false,
++ "access_mode_default": "UNVERIFIED",
++ "resale_terms_quote": "Terms URL returned 404.",
++ "terms_url": "https://novita.ai/terms-of-service",
++ "terms_effective": null,
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "Groq",
++ "api_format": "OpenAI-compatible",
++ "existing_adapter": "openai (BYOK credential)",
++ "byok": true,
++ "access_mode_default": "UNVERIFIED",
++ "resale_terms_quote": "/legal/terms-of-service returned 404; consumer terms exist but no clear wholesale/resale clause found.",
++ "terms_url": "https://groq.com/legal/terms-of-service",
++ "terms_effective": null,
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "Cerebras",
++ "api_format": "OpenAI-compatible",
++ "existing_adapter": "openai (BYOK credential)",
++ "byok": true,
++ "access_mode_default": "UNVERIFIED",
++ "resale_terms_quote": "Terms URL returned 404.",
++ "terms_url": "https://www.cerebras.ai/terms-of-use",
++ "terms_effective": null,
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "Fireworks",
++ "api_format": "OpenAI-compatible",
++ "existing_adapter": "openai (BYOK credential)",
++ "byok": true,
++ "access_mode_default": "UNVERIFIED",
++ "resale_terms_quote": "/terms returned 404; PDF at /legal/terms could not be fetched.",
++ "terms_url": "https://fireworks.ai/terms",
++ "terms_effective": null,
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "SiliconFlow",
++ "api_format": "OpenAI-compatible",
++ "existing_adapter": "http",
++ "byok": false,
++ "access_mode_default": "UNVERIFIED",
++ "resale_terms_quote": "Terms URL returned 404.",
++ "terms_url": "https://siliconflow.com/terms-of-service",
++ "terms_effective": null,
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "Refuseless",
++ "api_format": "Unknown",
++ "existing_adapter": null,
++ "byok": false,
++ "access_mode_default": "UNVERIFIED",
++ "resale_terms_quote": "No terms URL located.",
++ "terms_url": null,
++ "terms_effective": null,
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "Opper / Heabsy",
++ "api_format": "Unknown",
++ "existing_adapter": null,
++ "byok": false,
++ "access_mode_default": "UNVERIFIED",
++ "resale_terms_quote": "No terms URL located.",
++ "terms_url": null,
++ "terms_effective": null,
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "Modal",
++ "api_format": "Modal API",
++ "existing_adapter": "http",
++ "byok": false,
++ "access_mode_default": "UNVERIFIED",
++ "resale_terms_quote": "Terms URL returned 404.",
++ "terms_url": "https://modal.com/terms",
++ "terms_effective": null,
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "Beam",
++ "api_format": "REST / custom",
++ "existing_adapter": "http",
++ "byok": false,
++ "access_mode_default": "UNVERIFIED",
++ "resale_terms_quote": "Not fetched.",
++ "terms_url": null,
++ "terms_effective": null,
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "Prime Intellect",
++ "api_format": "REST / custom",
++ "existing_adapter": "http",
++ "byok": false,
++ "access_mode_default": "UNVERIFIED",
++ "resale_terms_quote": "Terms URL returned 404.",
++ "terms_url": "https://www.primeintellect.ai/terms",
++ "terms_effective": null,
++ "checked": "2026-11-03"
++ },
++ {
++ "provider": "Self-hosted vLLM / SGLang / llama.cpp / Ollama",
++ "api_format": "OpenAI-compatible",
++ "existing_adapter": "openai / http",
++ "byok": null,
++ "access_mode_default": "OWN_DEPLOYMENT",
++ "resale_terms_quote": "Open-source runtimes deployed on OpenVibe-owned or customer-authorized infrastructure; no upstream resale constraint.",
++ "terms_url": "Various OS licenses",
++ "terms_effective": null,
++ "checked": "2026-11-03"
++ }
++ ]
++}
ddiff --git a/docs/provider-matrix.md b/docs/provider-matrix.md
nnew file mode 100644
iindex 0000000..40e32da
---- /dev/null
++++ b/docs/provider-matrix.md
@@@ -0,0 +1,53 @@
++# OpenVibe AI Inference Exchange — Provider Eligibility Matrix
++
++> Checked: 2026-11-03
++> Source: `plan-state-2026-10-22/ai-exchange/PLAN.md` section C and public provider terms.
++> Rule: `access_mode` defaults to `UNVERIFIED` unless the terms **clearly allow resale** **and** an executed agreement exists. Retail subscriptions and coding-agent plans do **not** count as transferable wholesale compute.
++
++## Legend
++
++- `access_mode` values: `OWN_DEPLOYMENT`, `AUTHORIZED_WHOLESALE`, `CUSTOMER_BYOK`, `RESTRICTED`, `UNVERIFIED`.
++- **BYOK** = OpenVibe.AI can route using the customer's own API key (stored via `server/credentials.js`).
++- **Adapter** = the OpenVibe.AI provider kind that would serve this provider today.
++- **Resale quote** = exact wording from the provider's terms that governs resale / embedding in a third-party product.
++- **UNVERIFIED** means we could not locate a current public term that clearly permits managed resale; paid forwarding must not be enabled without executed approval.
++
++## Matrix
++
++| Provider | API format | Existing adapter | BYOK | access_mode default | Resale terms / quote | Terms URL | Checked |
++|---|---|---|---|---|---|---|---|
++| OpenAI | OpenAI | `openai` | Yes | `RESTRICTED` | "Customer may not resell or lease access to its Account or any End User Account." (OpenAI Services Agreement §3.1, effective 2026-01-01) | https://openai.com/policies/business-terms/ | 2026-11-03 |
++| Anthropic | Anthropic Messages | `anthropic` | Yes | `RESTRICTED` | "resell the Services except as expressly approved by Anthropic" (Commercial Terms §D.4, effective 2025-06-17) | https://www.anthropic.com/legal/commercial-terms | 2026-11-03 |
++| Google Gemini / Vertex | Gemini / OpenAI-compatible | `gemini` / `openai` | Yes | `RESTRICTED` | "sell, resell, sublicense, transfer, or distribute any or all of the Services" (Google Cloud Terms §3.3(c)) | https://cloud.google.com/terms | 2026-11-03 |
++| Mistral | OpenAI-compatible | `openai` (BYOK credential) | Yes | `RESTRICTED` | "nor grant any third party access to the Mistral AI Products without our prior written authorization" (Commercial Terms §2.2(i), effective 2026-09-25) | https://legal.mistral.ai/terms/commercial-terms-of-service | 2026-11-03 |
++| xAI / Grok | OpenAI-compatible | `openai` (BYOK credential) | Yes | `RESTRICTED` | Enterprise terms permit Bundled Services to Customer's End Users only; no standalone resale right found. | https://x.ai/legal/terms-of-service-enterprise | 2026-11-03 |
++| Together AI | OpenAI-compatible | `openai` (BYOK credential) | Yes | `RESTRICTED` | "transfer, distribute, resell, lease, license, or assign the Services or otherwise offer the Services on a standalone basis" (Terms §4.3, updated 2026-05-19) | https://www.together.ai/terms-of-service | 2026-11-03 |
++| DeepInfra | OpenAI-compatible | `openai` / `http` | Yes (custom) | `RESTRICTED` | "resell, sublicense, rent, distribute, or otherwise make the Services available to any third party except as expressly permitted under this Agreement or the applicable Service Order" (Terms §11(a)(viii), modified 2026-10-15) | https://deepinfra.com/terms | 2026-11-03 |
++| RunPod (serverless) | OpenAI-compatible | `openai` / `http` | No | `RESTRICTED` | "Resell any credits purchased through the Service without the prior written consent of Runpod"; Marketplace / compute terms restrict commercial exploitation. | https://www.runpod.io/terms-of-service | 2026-11-03 |
++| Replicate | Replicate API | `http` | No | `RESTRICTED` | "rent, lease, lend, sell, sublicense, assign, distribute, publish, transfer, or otherwise make available any Services to any person, including ... software as a service" (Terms §2.7(c)(iii), updated 2026-04-01) | https://replicate.com/terms | 2026-11-03 |
++| Cloudflare Workers AI | Workers AI REST | `http` | No | `RESTRICTED` | "rent, lease, loan, export, or sell access to the Services to any third party" (Self-Serve Subscription Agreement §2.2.1(a), updated 2025-09-12) | https://www.cloudflare.com/terms/ | 2026-11-03 |
++| AWS Bedrock | Bedrock Converse / Invoke | `http` | No | `RESTRICTED` | Standard AWS Customer Agreement / Service Terms do not permit resale of managed AI inference; AWS marketplace/partner programs require separate authorization. | https://aws.amazon.com/service-terms/ | 2026-11-03 |
++| Azure OpenAI / Foundry | Azure OpenAI / REST | `http` | No | `RESTRICTED` | Microsoft Customer Agreement / Online Subscription Agreement restrict resale; embedding in third-party SaaS requires negotiated terms. | https://azure.microsoft.com/en-us/support/legal/ | 2026-11-03 |
++| Featherless | OpenAI-compatible | `openai` / `http` | No | `AUTHORIZED_WHOLESALE` (Scale only) | "Scale plans are not subject to said limits and may be used in arbitrary applications, including inference resale." (Terms §3, last updated 2024-06-10) **Requires executed Scale agreement.** | https://featherless.ai/terms | 2026-11-03 |
++| Chutes | Custom / OpenAI-compatible | `http` | No | `UNVERIFIED` | Terms fetched; no explicit resale/wholesale clause found. Subscriptions are for casual/direct use; PAYGO required for production. | https://chutes.ai/terms | 2026-11-03 |
++| Baseten | OpenAI-compatible | `http` | No | `UNVERIFIED` | Terms page did not return readable content in this check. | https://www.baseten.co/terms-of-service | 2026-11-03 |
++| Venice | OpenAI-compatible | `http` | No | `UNVERIFIED` | Terms URL returned 404. | https://venice.ai/terms-of-service (404) | 2026-11-03 |
++| Nebius | OpenAI-compatible | `http` | No | `UNVERIFIED` | Terms URL returned 404. | https://nebius.com/legal/terms-of-service (404) | 2026-11-03 |
++| Novita | OpenAI-compatible | `http` | No | `UNVERIFIED` | Terms URL returned 404. | https://novita.ai/terms-of-service (404) | 2026-11-03 |
++| Groq | OpenAI-compatible | `openai` (BYOK credential) | Yes | `UNVERIFIED` | `/legal/terms-of-service` returned 404; consumer terms exist but no clear wholesale/resale clause found. | https://groq.com/legal/terms-of-service (404) | 2026-11-03 |
++| Cerebras | OpenAI-compatible | `openai` (BYOK credential) | Yes | `UNVERIFIED` | Terms URL returned 404. | https://www.cerebras.ai/terms-of-use (404) | 2026-11-03 |
++| Fireworks | OpenAI-compatible | `openai` (BYOK credential) | Yes | `UNVERIFIED` | `/terms` returned 404; PDF at `/legal/terms` could not be fetched. | https://fireworks.ai/terms (404) | 2026-11-03 |
++| SiliconFlow | OpenAI-compatible | `http` | No | `UNVERIFIED` | Terms URL returned 404. | https://siliconflow.com/terms-of-service (404) | 2026-11-03 |
++| Refuseless | Unknown | — | No | `UNVERIFIED` | No terms URL located. | — | 2026-11-03 |
++| Opper / Heabsy | Unknown | — | No | `UNVERIFIED` | No terms URL located. | — | 2026-11-03 |
++| Modal | Modal API | `http` | No | `UNVERIFIED` | Terms URL returned 404. | https://modal.com/terms (404) | 2026-11-03 |
++| Beam | REST / custom | `http` | No | `UNVERIFIED` | Not fetched. | — | 2026-11-03 |
++| Prime Intellect | REST / custom | `http` | No | `UNVERIFIED` | Terms URL returned 404. | https://www.primeintellect.ai/terms (404) | 2026-11-03 |
++| Self-hosted vLLM / SGLang / llama.cpp / Ollama | OpenAI-compatible | `openai` / `http` | N/A | `OWN_DEPLOYMENT` | Open-source runtimes deployed on OpenVibe-owned or customer-authorized infrastructure; no upstream resale constraint. | Various OS licenses | 2026-11-03 |
++
++## Notes
++
++1. **BYOK in OpenVibe.AI today**: `server/credentials.js` and `server/console/presets.js` support stored credentials for `anthropic`, `openai`, `gemini`, `deepseek`, `mistral`, `xai`, `groq`, `cerebras`, `together`, `fireworks`, `openrouter`, `minimax`, and `custom`. Any OpenAI-compatible provider can also be reached via the `openai` adapter with a custom `base_url` and `x_openvibe.provider` / credential.
++2. **Managed resale is blocked by default**. Only `OWN_DEPLOYMENT` and `AUTHORIZED_WHOLESALE` (with executed agreement) may be used for paid managed routes. `CUSTOMER_BYOK` is allowed where the customer is billed directly by the upstream.
++3. **Unknown providers** are listed as `UNVERIFIED`. Before enabling any paid forwarding, obtain current terms, an executed commercial agreement, and legal review.
++4. Prices are **not** recorded in this matrix per PLAN instructions; they must be obtained as live quotes from official sources and versioned in `platform.rate-card@1` before use.