openvibers/openvibe.contracts Commits
Contracts 0.100.0: usage-sample resource is the rate-card metric, placement-result may select no candidate, chat.ticket.write (planned) (#43)
OP OpenVibers committed 5 Oct 2026 · tag v0.100 · 0 files, +0 −0
## Changes (file:line)
**1. `resource` = the rate-card metric (usage-sample)**
- `contracts/platform/usage-sample.v1.json:40` — added a `resource` description: it must be the producing service's `platform.rate-card@1` `metric` for that `provider` (never a run/job/object id), and the reading's `unit` must be that metric's unit.
- `fixtures/platform.usage-sample/valid/ai-per-metric.json:1` — new valid AI reading (`service: ai`, `provider: openai`, `resource/unit: tokens`, `operation: chat.completion`, `quantity: 1500`, `cost_estimate`, `free_allowance_used`, all required fields).
- `fixtures/platform.rate-card/valid/ai-tokens.json:1` — **supporting** rate card for that reading. `fixtures/platform.rate-card` had only one metric (`queue-operation-64kb`, provider `example-queues`), which no AI reading could legitimately name; AI's real rate cards use `metric: tokens` (OpenVibe.AI `server/providers/index.js:177`), so I grounded the AI reading with a matching card instead of pairing an AI service with a queue metric.
**2. `selected` may be null (placement-result)**
- `contracts/platform/placement-result.v1.json:16` — `selected` is now `type: ["string","null"]` with a description that null means no eligible candidate.
- `fixtures/platform.placement-result/valid/none.json:1` — new `{"selected":null,"objective":"balanced","candidates":[],"decided_at":"2026-10-05T00:00:00Z"}`.
- `compatibility/corrections.json:11` — recorded correction for `platform.placement-result` against `v0.99.0`. The compat gate treats a type widening as a retype (`scripts/compat.js` compares `type` verbatim), so without this `compat v0.99.0` fails; the recorded reason is that the string-only shape was never sent — openvibe-sdk/placement `plan()` already returns `selected: null` (`OpenVibe.SDK/src/placement.js:146`) and the endpoint is roadmap WS-Z9.
**3. Chat per-ticket conversation**
- `contracts/chat/ticket-conversation.v1.json:1` — new contract: keyed by `ticket_id` + calling `service`, one `message` with `author_kind` (`person|agent|staff`), `author` (subject), `body`, `created_at`.
- `fixtures/chat.ticket-conversation/valid/person-question.json:1`, `valid/agent-answer.json:1`, `invalid/bad-author-kind.json:1`, `invalid/missing-body.json:1`.
- `manifests/capabilities/chat.ticket.write.json:1` — new capability, `owner: chat`, `visibility: first-party`, `status: planned`, `implementedBy: []`, `inputSchema`/`outputSchema: chat.ticket-conversation@1`.
- `manifests/services/chat.json:28` — added `chat.ticket.write`.
- `contracts/catalog.json:4705` — catalog entry, `status: "planned"` (the catalog's not-yet-implemented value; there is no `proposed`).
**Release 0.100.0**
- `package.json:3`, `package-lock.json:3,9` — version `0.100.0`.
- `STATUS.json:10,22` — `contracts` v0.100.0, `updated` 2026-10-05, feature line added.
- `CHANGELOG.md:7` — new `0.100.0 — 2026-10-05` section.
- `generated/` — regenerated and kept (28 files: bundle, TypeScript, 26 OpenAPI docs; the new contract/capability did not add a route since it is planned).
## Test results
- `node scripts/compat.js v0.99.0` → `platform.placement-result is a recorded correction` / `no breaking changes`, exit 0.
- `npm run generate` → written; `node scripts/generate.js --check` → `up to date`, exit 0.
- `git diff --check` → clean, exit 0.
- All 12 test files run directly (`node test/<file>`): capability-schemas, openapi, loyalty-policy, presence-policy, bot-manifest, product-catalog, zones, usage-topics, billing-grace
This commit has no diff to show.