@volter/twin-cohere 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +224 -0
  2. package/defaults/handlers.json +26 -0
  3. package/dist/defaults/handlers.json +26 -0
  4. package/dist/src/cli.d.ts +2 -0
  5. package/dist/src/cli.js +31 -0
  6. package/dist/src/cohere-budget.d.ts +55 -0
  7. package/dist/src/cohere-budget.js +171 -0
  8. package/dist/src/cohere-capabilities.d.ts +14 -0
  9. package/dist/src/cohere-capabilities.js +1852 -0
  10. package/dist/src/cohere-conformance.d.ts +17 -0
  11. package/dist/src/cohere-conformance.js +464 -0
  12. package/dist/src/cohere-connector.d.ts +150 -0
  13. package/dist/src/cohere-connector.js +625 -0
  14. package/dist/src/cohere-models.d.ts +21 -0
  15. package/dist/src/cohere-models.js +73 -0
  16. package/dist/src/cohere-scenario.d.ts +57 -0
  17. package/dist/src/cohere-scenario.js +176 -0
  18. package/dist/src/cohere-server.d.ts +16 -0
  19. package/dist/src/cohere-server.js +184 -0
  20. package/dist/src/cohere-stub.d.ts +119 -0
  21. package/dist/src/cohere-stub.js +321 -0
  22. package/dist/src/cohere-twin.d.ts +82 -0
  23. package/dist/src/cohere-twin.js +1243 -0
  24. package/dist/src/cohere-types.d.ts +226 -0
  25. package/dist/src/cohere-types.js +40 -0
  26. package/dist/src/index.d.ts +15 -0
  27. package/dist/src/index.js +84 -0
  28. package/package.json +71 -0
  29. package/src/cli.ts +30 -0
  30. package/src/cohere-budget.ts +197 -0
  31. package/src/cohere-capabilities.ts +1855 -0
  32. package/src/cohere-conformance.ts +489 -0
  33. package/src/cohere-connector.ts +709 -0
  34. package/src/cohere-models.ts +79 -0
  35. package/src/cohere-scenario.ts +194 -0
  36. package/src/cohere-server.ts +195 -0
  37. package/src/cohere-stub.ts +337 -0
  38. package/src/cohere-twin.ts +1290 -0
  39. package/src/cohere-types.ts +231 -0
  40. package/src/index.ts +159 -0
@@ -0,0 +1,1855 @@
1
+ // Cohere capability manifest — the EXPECTED REAL-PRODUCT SURFACE (the target), authored TOP-DOWN
2
+ // from what the Cohere API actually does — NOT from what this twin has built. This is the honest
3
+ // denominator: most entries start as `todo` and coverage reads LOW until the twin truly reaches
4
+ // 100% of the API. `verify()` (required to count as done) is ground truth; `expected:'done'` only
5
+ // on capabilities we genuinely claim, so a broken one shows as a regression.
6
+ //
7
+ // ── HOW THE DENOMINATOR WAS ENUMERATED (so it is not a self-portrait) ───────────────────
8
+ // Every operation cohere-ai@8.1.0 can issue was extracted during this build, from the SDK's own
9
+ // `reference.md` operation index cross-checked against the `core.url.join(..., "<path>")` literal
10
+ // in each generated client. That is **45 SDK methods over 33 distinct HTTP endpoints**:
11
+ //
12
+ // root client (11) : chat, chatStream, generate, generateStream, embed, rerank, classify,
13
+ // summarize, tokenize, detokenize, checkApiKey
14
+ // v2 (5) : chat, chatStream, parse, embed, rerank
15
+ // batches (4) : list, create, retrieve, cancel
16
+ // connectors (6) : list, create, get, delete, update, oAuthAuthorize
17
+ // datasets (5) : list, create, getUsage, get, delete
18
+ // embedJobs (4) : list, create, get, cancel
19
+ // finetuning (7) : listFinetunedModels, createFinetunedModel, getFinetunedModel,
20
+ // deleteFinetunedModel, updateFinetunedModel, listEvents,
21
+ // listTrainingStepMetrics
22
+ // models (2) : get, list
23
+ // audio (1) : transcriptions.create
24
+ //
25
+ // The twin serves 27 of those 33 endpoints. The six it does NOT serve (`/v1/generate` ×2,
26
+ // `/v1/summarize`, `/v2/parse`, `/v2/audio/transcriptions`, and the seven finetuning paths, plus
27
+ // the four batches paths) are enumerated below as `todo` — they are REAL Cohere surface, and a
28
+ // denominator that omitted them would be a self-portrait. So are the deployment planes the SDK
29
+ // also ships clients for (`AwsClient` / `BedrockClient` / `SagemakerClient`), which are Cohere
30
+ // models served through AWS rather than through api.cohere.com.
31
+ //
32
+ // ── THERE ARE NO CARVE-OUTS ─────────────────────────────────────────────────────────────
33
+ // The twin returns DETERMINISTIC STUBS for model generation, pseudo-vectors for embeddings, a
34
+ // lexical-overlap score for rerank and a hash heuristic for classify — and those ARE the twin's
35
+ // answer, not a shortfall from a "real" one. The protocol envelope (shapes, streaming, tool calls,
36
+ // UPPER-CASE finish reasons, two-level usage) is faithful. Every entry here is done or todo.
37
+ //
38
+ // The tokenizer is a TODO: Cohere's tokenizers are published, downloadable, static JSON artifacts,
39
+ // and this pack already SERVES their URLs from the model catalog, so vendoring one is fully offline
40
+ // and fully deterministic (`cohere.tokenize.bpe_vocabulary`).
41
+ //
42
+ // (Cohere is an API-first vendor: its dashboard is incidental tooling for keys, billing and usage,
43
+ // not where the work happens — docs/contributing/architecture.md C1b — so this pack ships no mirror, and there are
44
+ // no UI capabilities to verify.)
45
+ import { mkdtempSync, rmSync } from 'node:fs';
46
+ import { tmpdir } from 'node:os';
47
+ import { join } from 'node:path';
48
+ import { projectResources } from '@volter/world-core';
49
+ import { checkCapabilities, type CapabilityReport, type CapabilitySpec, verifyBoundary, isInfrastructureError, harnessError } from '@volter/world-tooling';
50
+ import { CohereBudget, CohereBudgetError, cohereCallWeight } from './cohere-budget.ts';
51
+ import { checkCohereConformance } from './cohere-conformance.ts';
52
+ import {
53
+ cohereRequestForAction,
54
+ fullSyncCohere,
55
+ liveCohereExecute,
56
+ mapConnector,
57
+ mapDataset,
58
+ mapEmbedJob,
59
+ pollTimestamp,
60
+ pushPendingCohereActions,
61
+ syncCohereFromReal,
62
+ unpushableReason,
63
+ type CohereExecute,
64
+ } from './cohere-connector.ts';
65
+ import { COHERE_MODELS, COHERE_ENDPOINTS } from './cohere-models.ts';
66
+ import { createCohereScenarioEngine } from './cohere-scenario.ts';
67
+ import { handleCohereTwinRequest, type CohereResponseEnvelope } from './cohere-twin.ts';
68
+ import type { SseEvent } from './cohere-types.ts';
69
+
70
+ // ── API verify: drive REAL requests against a fresh temp root, then assert status/shape ──
71
+ type Step = { m: string; p: string; b?: unknown; h?: Record<string, string>; ro?: boolean };
72
+ type Body = Record<string, any>;
73
+
74
+ /** A FIXED `occurredAt` keeps ids/timestamps deterministic across runs. */
75
+ const PINNED_AT = '2026-08-31T12:00:00.000Z';
76
+
77
+ /** Run a sequence of real Cohere requests against an ISOLATED root; return all responses. The
78
+ * root is threaded EVERYWHERE — an omitted root silently falls back to the operator's real
79
+ * `~/.volter` state dir, which is gitignored, so the verify would pass while poisoning later
80
+ * runs. */
81
+ async function withRoot(steps: (h: (s: Step) => Promise<CohereResponseEnvelope>) => Promise<boolean>): Promise<boolean> {
82
+ const root = mkdtempSync(join(tmpdir(), 'cohere-cap-'));
83
+ const h = (s: Step) => handleCohereTwinRequest({
84
+ method: s.m, path: s.p, root, occurredAt: PINNED_AT,
85
+ ...(s.b === undefined ? {} : { body: JSON.stringify(s.b) }),
86
+ ...(s.h ? { headers: s.h } : {}),
87
+ ...(s.ro ? { readOnly: true } : {}),
88
+ });
89
+ try {
90
+ return await verifyBoundary('cohere.withRoot', () => steps(h));
91
+ } finally {
92
+ rmSync(root, { recursive: true, force: true });
93
+ }
94
+ }
95
+
96
+ /** Collect the streaming events for a request against an isolated root. */
97
+ function withStream(path: string, body: unknown, fn: (events: SseEvent[], final: CohereResponseEnvelope) => boolean): Promise<boolean> {
98
+ return new Promise<boolean>((resolve, reject) => {
99
+ const root = mkdtempSync(join(tmpdir(), 'cohere-cap-'));
100
+ const events: SseEvent[] = [];
101
+ handleCohereTwinRequest({ method: 'POST', path, body: JSON.stringify(body), root, occurredAt: PINNED_AT, sseSink: (e) => events.push(e) })
102
+ .then((final) => resolve(fn(events, final)))
103
+ .catch((err) => { if (isInfrastructureError(err)) reject(harnessError('cohere.withStream', err)); else resolve(false); })
104
+ .finally(() => rmSync(root, { recursive: true, force: true }));
105
+ });
106
+ }
107
+
108
+ /** A connector verify against a recording fake executor + an isolated root. */
109
+ async function withConnector(
110
+ fn: (execute: CohereExecute, calls: Array<{ method: string; path: string; body?: Record<string, unknown> }>, root: string) => Promise<boolean>,
111
+ reply?: (method: string, path: string) => unknown,
112
+ ): Promise<boolean> {
113
+ const root = mkdtempSync(join(tmpdir(), 'cohere-conn-'));
114
+ const calls: Array<{ method: string; path: string; body?: Record<string, unknown> }> = [];
115
+ const execute: CohereExecute = async (method, path, body) => {
116
+ calls.push({ method, path, ...(body ? { body } : {}) });
117
+ return reply ? reply(method, path) : defaultVendorReply(method, path);
118
+ };
119
+ try {
120
+ return await verifyBoundary('cohere.withConnector', () => fn(execute, calls, root));
121
+ } finally {
122
+ rmSync(root, { recursive: true, force: true });
123
+ }
124
+ }
125
+
126
+ // REAL-SHAPED vendor rows. A connector verify green over an input the vendor could not emit has
127
+ // proven fidelity against a client that does not exist, so these carry the FULL field set each
128
+ // mapper reads — every key the vendor's own schema declares required, not the subset a lax `?? null`
129
+ // default would paper over.
130
+ const REAL_DATASET = { id: 'ds-real-1', name: 'real-dataset', created_at: '2026-08-01T00:00:00Z', updated_at: '2026-08-02T00:00:00Z', dataset_type: 'embed-input', validation_status: 'validated', validation_error: null, validation_warnings: [], required_fields: ['text'], preserve_fields: [], dataset_parts: [], schema: null };
131
+ const REAL_CONNECTOR = { id: 'conn-real-1', organization_id: 'org-real', name: 'real-connector', description: 'the real one', url: 'https://real.test/search', created_at: '2026-08-01T00:00:00Z', updated_at: '2026-08-03T00:00:00Z', excludes: ['secret'], auth_type: 'oauth', oauth: { client_id: 'cid', authorize_url: 'https://a.test', token_url: 'https://t.test', scope: null }, auth_status: 'valid', active: true, continue_on_failure: false };
132
+ const REAL_EMBED_JOB = { job_id: 'job-real-1', name: 'real-job', status: 'processing', created_at: '2026-08-04T00:00:00Z', input_dataset_id: 'ds-real-1', output_dataset_id: null, model: 'embed-english-v3.0', truncate: 'END', meta: null };
133
+
134
+ /**
135
+ * The fake vendor's reply, keyed on METHOD **and** path.
136
+ *
137
+ * The method half is load-bearing: a path-only fake would answer `POST /v1/connectors` with the
138
+ * LIST envelope, so `pushCohereAction`'s id extraction would never once be exercised against a
139
+ * realistic create response and would silently fall back to the local subject id on every run —
140
+ * which is precisely the bug the duplicate-on-pull finding turns on. A LIST answers the collection;
141
+ * a CREATE answers the vendor's own (per-type, NON-uniform) create envelope.
142
+ */
143
+ function defaultVendorReply(method: string, path: string): unknown {
144
+ const bare = path.split('?')[0]!;
145
+ if (method === 'GET') {
146
+ if (bare === '/v1/datasets') return { datasets: [REAL_DATASET] };
147
+ if (bare === '/v1/connectors') return { connectors: [REAL_CONNECTOR], total_count: 1 };
148
+ if (bare === '/v1/embed-jobs') return { embed_jobs: [REAL_EMBED_JOB] };
149
+ return {};
150
+ }
151
+ if (method === 'POST') {
152
+ // Three DIFFERENT create envelopes, exactly as the vendor's schemas declare them.
153
+ if (bare === '/v1/connectors') return { connector: { ...REAL_CONNECTOR, id: 'conn-vendor-minted' } };
154
+ if (bare === '/v1/embed-jobs') return { job_id: 'job-vendor-minted', meta: null };
155
+ if (bare === '/v1/datasets') return { id: 'ds-vendor-minted' };
156
+ if (bare.endsWith('/cancel')) return {};
157
+ return {};
158
+ }
159
+ if (method === 'PATCH') return { connector: { ...REAL_CONNECTOR, name: 'patched' } };
160
+ if (method === 'DELETE') return {};
161
+ return {};
162
+ }
163
+
164
+ const ok = (r: CohereResponseEnvelope) => r.status >= 200 && r.status < 300;
165
+ const field = (r: CohereResponseEnvelope, k: string) => (r.body as Body)?.[k];
166
+ const message = (r: CohereResponseEnvelope) => String((r.body as Body)?.message ?? '');
167
+ /** Cohere's error envelope has EXACTLY one key. Asserting the count is what catches a drift toward
168
+ * the OpenAI `{error:{...}}` shape, which no positive assertion on `message` would notice. */
169
+ const bareError = (r: CohereResponseEnvelope, status: number) =>
170
+ r.status === status && !!r.body && typeof r.body === 'object' && Object.keys(r.body as object).join(',') === 'message';
171
+
172
+ // ── shorthands (mirror the anthropic/mistral manifests) ──
173
+ const done = (id: string, area: string, title: string, dimension: CapabilitySpec['dimension'], tier: CapabilitySpec['tier'], verify: CapabilitySpec['verify']): CapabilitySpec => ({ id, area, title, dimension, tier, expected: 'done', verify });
174
+ const todo = (id: string, area: string, title: string, dimension: CapabilitySpec['dimension'], tier: CapabilitySpec['tier']): CapabilitySpec => ({ id, area, title, dimension, tier, expected: 'todo' });
175
+
176
+ /** The multipart `data` part every dataset create must carry — `datasets.create` in cohere-ai
177
+ * unconditionally appends it, so the vendor never sees a fileless create (§9 round 1, finding 6). */
178
+ const DATA_FILE = { content: '{"text":"a"}' };
179
+
180
+ const CHAT = (extra: Record<string, unknown> = {}) => ({ model: 'command-a-03-2025', messages: [{ role: 'user', content: 'hello twin' }], ...extra });
181
+ const TOOL = { type: 'function', function: { name: 'get_weather', description: 'w', parameters: { type: 'object', properties: { city: { type: 'string' }, days: { type: 'integer' } } } } };
182
+
183
+ /**
184
+ * THE AREAS CENSUS (TWIN-87). Enumerated TOP-DOWN from cohere-ai@8.1.0's own client surface — the
185
+ * root client's method groups plus every sub-client directory under `api/resources/`
186
+ * (v2, batches, connectors, datasets, embedJobs, finetuning, models, audio) and the three
187
+ * deployment clients the package also ships (`AwsClient`, `BedrockClient`, `SagemakerClient`) —
188
+ * NOT from this manifest's own `area` values, which would make the bijection a tautology.
189
+ *
190
+ * `connectors` is Cohere's PRODUCT (its RAG connector registry); `connector` is this twin's
191
+ * pull/push plane. Two different things that unfortunately share a word; both are real areas.
192
+ */
193
+ export const COHERE_AREAS = [
194
+ 'audio',
195
+ 'auth',
196
+ 'batches',
197
+ 'chat',
198
+ 'chat_v1',
199
+ 'classify',
200
+ 'conformance',
201
+ 'connector',
202
+ 'connectors',
203
+ 'datasets',
204
+ 'deployments',
205
+ 'determinism',
206
+ 'embed',
207
+ 'embed_jobs',
208
+ 'errors',
209
+ 'finetuning',
210
+ 'generate',
211
+ 'models',
212
+ 'parse',
213
+ 'rerank',
214
+ 'summarize',
215
+ 'tokenize',
216
+ ] as const;
217
+
218
+ export const COHERE_CAPABILITIES: CapabilitySpec[] = [
219
+ // ══ THE HONEST CARVE-OUTS ═════════════════════════════════════════════════════════════
220
+ todo('cohere.tokenize.bpe_vocabulary', 'tokenize', "Tokenize with Cohere's REAL published BPE vocabulary (vendored tokenizer JSON), not a learned word-segment map", 'api', 'common'),
221
+ todo('cohere.deployments.aws_planes', 'deployments', 'Serve the Bedrock and SageMaker planes the cohere-ai SDK also targets (BedrockClient/SagemakerClient/AwsClient, SigV4-signed against AWS hosts), so a regionally-deployed client reaches the twin instead of failing closed', 'api', 'niche'),
222
+
223
+ // ══ CHAT v2 — the protocol envelope, faithful ═════════════════════════════════════════
224
+ done('cohere.chat.create', 'chat', 'v2 chat: the faithful envelope (id/finish_reason/message/usage, and NO `choices`)', 'api', 'core', () =>
225
+ withRoot(async (h) => {
226
+ const r = await h({ m: 'POST', p: '/v2/chat', b: CHAT() });
227
+ if (!ok(r)) return false;
228
+ const b = r.body as Body;
229
+ // The three keys an OpenAI-shaped copy would add, asserted ABSENT. A positive assertion on
230
+ // `message` alone would not notice a `choices` array riding alongside it.
231
+ if (b.choices !== undefined || b.object !== undefined || b.created !== undefined) return false;
232
+ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(String(b.id))) return false;
233
+ if (b.finish_reason !== 'COMPLETE' || b.message?.role !== 'assistant') return false;
234
+ if (b.message?.content?.[0]?.type !== 'text') return false;
235
+ return typeof b.message.content[0].text === 'string' && b.message.content[0].text.includes('hello twin');
236
+ }),
237
+ ),
238
+ done('cohere.chat.stub_labeled', 'chat', 'v2 chat: the stub is clearly labeled as a twin stub (not real output)', 'api', 'core', () =>
239
+ withRoot(async (h) => {
240
+ const r = await h({ m: 'POST', p: '/v2/chat', b: CHAT() });
241
+ const text = (r.body as Body).message?.content?.[0]?.text as string;
242
+ return ok(r) && text.includes('[twin-stub:command-a-03-2025]') && text.includes('no model weights are run');
243
+ }),
244
+ ),
245
+ done('cohere.chat.usage_two_levels', 'chat', 'v2 chat: usage carries BOTH `billed_units` and `tokens` sub-objects', 'api', 'core', () =>
246
+ withRoot(async (h) => {
247
+ const short = await h({ m: 'POST', p: '/v2/chat', b: CHAT() });
248
+ const long = await h({ m: 'POST', p: '/v2/chat', b: CHAT({ messages: [{ role: 'user', content: 'x'.repeat(400) }] }) });
249
+ const a = (short.body as Body).usage;
250
+ const c = (long.body as Body).usage;
251
+ // @ai-sdk/cohere's `cohereUsageSchema` marks `billed_units` nullish but `tokens` REQUIRED,
252
+ // and `convertCohereUsage` reads `usage.tokens.*` — a flat OpenAI-shaped usage dies there.
253
+ if (typeof a?.billed_units?.input_tokens !== 'number' || typeof a?.tokens?.input_tokens !== 'number') return false;
254
+ if (typeof a?.billed_units?.output_tokens !== 'number' || typeof a?.tokens?.output_tokens !== 'number') return false;
255
+ // The count MOVES with the input — a hardcoded constant would satisfy the shape checks above.
256
+ return c.tokens.input_tokens > a.tokens.input_tokens * 5;
257
+ }),
258
+ ),
259
+ done('cohere.chat.tool_calls', 'chat', 'v2 chat: tools → `tool_calls` + `tool_plan` + finish_reason TOOL_CALL', 'api', 'core', () =>
260
+ withRoot(async (h) => {
261
+ const r = await h({ m: 'POST', p: '/v2/chat', b: CHAT({ tools: [TOOL] }) });
262
+ if (!ok(r)) return false;
263
+ const b = r.body as Body;
264
+ if (b.finish_reason !== 'TOOL_CALL') return false;
265
+ if (typeof b.message?.tool_plan !== 'string' || !b.message.tool_plan.includes('get_weather')) return false;
266
+ const call = b.message?.tool_calls?.[0];
267
+ if (call?.type !== 'function' || call?.function?.name !== 'get_weather') return false;
268
+ // `arguments` is a STRING on the wire, and it parses to the tool's declared schema shape.
269
+ const args = JSON.parse(call.function.arguments);
270
+ if (args.city !== '' || args.days !== 0) return false;
271
+ // A tool turn carries NO `content` — Cohere omits the empty half rather than sending null.
272
+ return b.message.content === undefined;
273
+ }),
274
+ ),
275
+ done('cohere.chat.tool_choice_none', 'chat', 'v2 chat: `tool_choice: NONE` forbids a tool call even with tools declared', 'api', 'common', () =>
276
+ withRoot(async (h) => {
277
+ const forced = await h({ m: 'POST', p: '/v2/chat', b: CHAT({ tools: [TOOL] }) });
278
+ const none = await h({ m: 'POST', p: '/v2/chat', b: CHAT({ tools: [TOOL], tool_choice: 'NONE' }) });
279
+ // Both halves: the tool DOES fire without the flag, and does NOT with it. Asserting only the
280
+ // second would pass on a twin that never made tool calls at all.
281
+ return (forced.body as Body).finish_reason === 'TOOL_CALL'
282
+ && (none.body as Body).finish_reason === 'COMPLETE'
283
+ && (none.body as Body).message?.tool_calls === undefined
284
+ && typeof (none.body as Body).message?.content?.[0]?.text === 'string';
285
+ }),
286
+ ),
287
+ done('cohere.chat.thinking', 'chat', 'v2 chat: `thinking: {type:enabled}` prepends a `thinking` content item', 'api', 'common', () =>
288
+ withRoot(async (h) => {
289
+ const off = await h({ m: 'POST', p: '/v2/chat', b: CHAT() });
290
+ const on = await h({ m: 'POST', p: '/v2/chat', b: CHAT({ thinking: { type: 'enabled' } }) });
291
+ const offTypes = ((off.body as Body).message?.content ?? []).map((c: Body) => c.type);
292
+ const onTypes = ((on.body as Body).message?.content ?? []).map((c: Body) => c.type);
293
+ return JSON.stringify(offTypes) === '["text"]' && JSON.stringify(onTypes) === '["thinking","text"]';
294
+ }),
295
+ ),
296
+ done('cohere.chat.stream_events', 'chat', 'v2 chat streaming: the vendor event sequence, terminated by [DONE]', 'api', 'core', () =>
297
+ withStream('/v2/chat', CHAT({ stream: true }), (events, final) => {
298
+ const types = events.filter((e) => !e.done).map((e) => String(e.data!.type));
299
+ if (types[0] !== 'message-start') return false;
300
+ if (!types.includes('content-start') || !types.includes('content-delta') || !types.includes('content-end')) return false;
301
+ if (types[types.length - 1] !== 'message-end') return false;
302
+ // The `[DONE]` terminator cohere-ai's `core.Stream` is constructed to look for.
303
+ if (events[events.length - 1]?.done !== true) return false;
304
+ // `content-start` carries a full content BLOCK; `content-delta` carries just `{text}`. The
305
+ // two shapes DIFFER, and @ai-sdk/cohere's discriminated union rejects a mix-up.
306
+ const start = events.find((e) => e.data?.type === 'content-start')!.data as Body;
307
+ if (start.delta?.message?.content?.type !== 'text' || start.delta.message.content.text !== '') return false;
308
+ const delta = events.find((e) => e.data?.type === 'content-delta')!.data as Body;
309
+ if (delta.delta?.message?.content?.type !== undefined) return false;
310
+ // The reassembled deltas equal the unary answer — the chunking is a SPLIT, not a second
311
+ // generation, which is the property a streaming caller actually relies on.
312
+ const joined = events.filter((e) => e.data?.type === 'content-delta').map((e) => (e.data as Body).delta.message.content.text).join('');
313
+ return joined === (final.body as Body).message.content[0].text;
314
+ }),
315
+ ),
316
+ done('cohere.chat.stream_message_end', 'chat', 'v2 chat streaming: `message-end` carries finish_reason + the full usage', 'api', 'core', () =>
317
+ withStream('/v2/chat', CHAT({ stream: true }), (events, final) => {
318
+ const end = events.find((e) => e.data?.type === 'message-end')?.data as Body | undefined;
319
+ if (!end) return false;
320
+ return end.delta?.finish_reason === 'COMPLETE'
321
+ && end.delta?.usage?.tokens?.output_tokens === (final.body as Body).usage.tokens.output_tokens
322
+ && end.id === (final.body as Body).id;
323
+ }),
324
+ ),
325
+ done('cohere.chat.stream_tool_calls', 'chat', 'v2 chat streaming: tool-plan/tool-call event triple reassembles the call', 'api', 'common', () =>
326
+ withStream('/v2/chat', CHAT({ stream: true, tools: [TOOL] }), (events, final) => {
327
+ const types = events.filter((e) => !e.done).map((e) => String(e.data!.type));
328
+ if (!types.includes('tool-plan-delta') || !types.includes('tool-call-start') || !types.includes('tool-call-delta') || !types.includes('tool-call-end')) return false;
329
+ const start = events.find((e) => e.data?.type === 'tool-call-start')!.data as Body;
330
+ // The START frame carries the id and name with EMPTY arguments; the deltas carry the
331
+ // argument string in pieces, which the caller accumulates.
332
+ if (start.delta?.message?.tool_calls?.function?.name !== 'get_weather') return false;
333
+ if (start.delta.message.tool_calls.function.arguments !== '') return false;
334
+ const args = events.filter((e) => e.data?.type === 'tool-call-delta')
335
+ .map((e) => (e.data as Body).delta.message.tool_calls.function.arguments).join('');
336
+ if (args !== (final.body as Body).message.tool_calls[0].function.arguments) return false;
337
+ const end = events.find((e) => e.data?.type === 'message-end')!.data as Body;
338
+ return end.delta.finish_reason === 'TOOL_CALL';
339
+ }),
340
+ ),
341
+ done('cohere.chat.stream_needs_transport', 'chat', 'v2 chat: `stream:true` with no streaming transport is refused, not silently unary', 'api', 'niche', () =>
342
+ withRoot(async (h) => {
343
+ const r = await h({ m: 'POST', p: '/v2/chat', b: CHAT({ stream: true }) });
344
+ return bareError(r, 400) && message(r).includes('streaming transport');
345
+ }),
346
+ ),
347
+ done('cohere.chat.validation_model', 'chat', 'v2 chat: missing model → the bare `{message}` 400', 'api', 'core', () =>
348
+ withRoot(async (h) => {
349
+ const r = await h({ m: 'POST', p: '/v2/chat', b: { messages: [{ role: 'user', content: 'x' }] } });
350
+ return bareError(r, 400) && message(r) === 'invalid request: model is required';
351
+ }),
352
+ ),
353
+ done('cohere.chat.validation_messages', 'chat', 'v2 chat: missing / empty / bad-role messages each 400 with their own message', 'api', 'core', () =>
354
+ withRoot(async (h) => {
355
+ const missing = await h({ m: 'POST', p: '/v2/chat', b: { model: 'command-a-03-2025' } });
356
+ const empty = await h({ m: 'POST', p: '/v2/chat', b: CHAT({ messages: [] }) });
357
+ const badRole = await h({ m: 'POST', p: '/v2/chat', b: CHAT({ messages: [{ role: 'developer', content: 'x' }] }) });
358
+ return bareError(missing, 400) && message(missing) === 'invalid request: messages is required'
359
+ && bareError(empty, 400) && message(empty) === 'invalid request: messages must not be empty'
360
+ && bareError(badRole, 400) && message(badRole).includes('messages[0].role must be one of');
361
+ }),
362
+ ),
363
+ done('cohere.chat.model_not_found', 'chat', 'v2 chat: unknown model AND wrong-endpoint model both 404 like the vendor', 'api', 'core', () =>
364
+ withRoot(async (h) => {
365
+ const unknown = await h({ m: 'POST', p: '/v2/chat', b: CHAT({ model: 'gpt-4o' }) });
366
+ // The sharper case: a REAL Cohere model that serves a different endpoint. An OpenAI-shaped
367
+ // twin would happily generate from it.
368
+ const wrongEndpoint = await h({ m: 'POST', p: '/v2/chat', b: CHAT({ model: 'embed-v4.0' }) });
369
+ return bareError(unknown, 404) && message(unknown) === "model 'gpt-4o' not found, make sure the correct model ID was used and that you have access to the model."
370
+ && bareError(wrongEndpoint, 404) && message(wrongEndpoint).includes("model 'embed-v4.0' not found");
371
+ }),
372
+ ),
373
+ done('cohere.chat.closed_enums', 'chat', 'v2 chat: `tool_choice` and `safety_mode` are the vendor\'s CLOSED UPPER-CASE sets', 'api', 'common', () =>
374
+ withRoot(async (h) => {
375
+ // The documented sets are literals here, never imported from the handler — an imported
376
+ // constant could not catch the set drifting.
377
+ for (const v of ['REQUIRED', 'NONE']) {
378
+ if (!ok(await h({ m: 'POST', p: '/v2/chat', b: CHAT({ tools: [TOOL], tool_choice: v }) }))) return false;
379
+ }
380
+ for (const v of ['CONTEXTUAL', 'STRICT', 'OFF']) {
381
+ if (!ok(await h({ m: 'POST', p: '/v2/chat', b: CHAT({ safety_mode: v }) }))) return false;
382
+ }
383
+ // …and a value OUTSIDE each set is refused. Cohere's enums are UPPER-CASE, so the
384
+ // lower-case spelling most vendors use is exactly the wrong-looking-plausible input.
385
+ const lowerChoice = await h({ m: 'POST', p: '/v2/chat', b: CHAT({ tools: [TOOL], tool_choice: 'none' }) });
386
+ const badMode = await h({ m: 'POST', p: '/v2/chat', b: CHAT({ safety_mode: 'contextual' }) });
387
+ return bareError(lowerChoice, 400) && bareError(badMode, 400);
388
+ }),
389
+ ),
390
+ todo('cohere.chat.citations', 'chat', 'v2 chat: `documents` + citation_options → grounded citations on the response', 'api', 'core'),
391
+ todo('cohere.chat.response_format_json', 'chat', 'v2 chat: `response_format` json_object / json_schema constrained output', 'api', 'core'),
392
+ todo('cohere.chat.logprobs', 'chat', 'v2 chat: `logprobs: true` → the LogprobItem array on the response', 'api', 'niche'),
393
+ todo('cohere.chat.strict_tools', 'chat', 'v2 chat: `strict_tools` schema-constrained tool arguments', 'api', 'niche'),
394
+ todo('cohere.chat.stop_sequences', 'chat', 'v2 chat: `stop_sequences` → finish_reason STOP_SEQUENCE', 'api', 'core'),
395
+ todo('cohere.chat.max_tokens_truncation', 'chat', 'v2 chat: `max_tokens` truncation → finish_reason MAX_TOKENS', 'api', 'core'),
396
+ todo('cohere.chat.image_content', 'chat', 'v2 chat: image content parts for the vision models (command-a-vision)', 'api', 'common'),
397
+ todo('cohere.chat.priority', 'chat', 'v2 chat: the `priority` request parameter', 'api', 'niche'),
398
+
399
+ // ══ CHAT v1 — a DIFFERENT protocol, not a versioned alias ═════════════════════════════
400
+ done('cohere.chat_v1.create', 'chat_v1', 'v1 chat: flat `text` + chat_history + meta (NOT the v2 envelope)', 'api', 'core', () =>
401
+ withRoot(async (h) => {
402
+ const r = await h({ m: 'POST', p: '/v1/chat', b: { message: 'v1 hello', model: 'command-r-08-2024' } });
403
+ if (!ok(r)) return false;
404
+ const b = r.body as Body;
405
+ // v1 has NO `message` object and NO `usage`; it has `text` and `meta`. A twin that served
406
+ // one envelope for both versions would fail exactly here.
407
+ if (b.message !== undefined || b.usage !== undefined) return false;
408
+ if (typeof b.text !== 'string' || !b.text.includes('[twin-stub:command-r-08-2024]') || !b.text.includes('v1 hello')) return false;
409
+ if (b.finish_reason !== 'COMPLETE') return false;
410
+ return b.meta?.api_version?.version === '1' && b.meta?.billed_units?.input_tokens > 0;
411
+ }),
412
+ ),
413
+ done('cohere.chat_v1.chat_history', 'chat_v1', 'v1 chat: the reply appends USER + CHATBOT turns onto the supplied history', 'api', 'common', () =>
414
+ withRoot(async (h) => {
415
+ const r = await h({ m: 'POST', p: '/v1/chat', b: { message: 'second', chat_history: [{ role: 'USER', message: 'first' }, { role: 'CHATBOT', message: 'reply' }] } });
416
+ const hist = (r.body as Body).chat_history as Body[];
417
+ return ok(r) && hist.length === 4
418
+ && hist[0]!.message === 'first' && hist[1]!.message === 'reply'
419
+ && hist[2]!.role === 'USER' && hist[2]!.message === 'second'
420
+ && hist[3]!.role === 'CHATBOT' && String(hist[3]!.message).includes('[twin-stub:');
421
+ }),
422
+ ),
423
+ done('cohere.chat_v1.validation_message', 'chat_v1', "v1 chat: a v2-shaped `messages` array is refused — v1 requires `message`", 'api', 'core', () =>
424
+ withRoot(async (h) => {
425
+ const v2shaped = await h({ m: 'POST', p: '/v1/chat', b: { messages: [{ role: 'user', content: 'x' }], model: 'command-r-08-2024' } });
426
+ const empty = await h({ m: 'POST', p: '/v1/chat', b: { message: '' } });
427
+ return bareError(v2shaped, 400) && message(v2shaped) === 'invalid request: message is required'
428
+ && bareError(empty, 400);
429
+ }),
430
+ ),
431
+ done('cohere.chat_v1.stream_ndjson', 'chat_v1', 'v1 chat streaming: NDJSON `event_type` frames, a DIFFERENT wire from v2 SSE', 'api', 'common', () =>
432
+ withStream('/v1/chat', { message: 'stream v1', stream: true }, (events, final) => {
433
+ const kinds = events.filter((e) => !e.done).map((e) => String(e.data!.event_type));
434
+ if (kinds[0] !== 'stream-start' || kinds[kinds.length - 1] !== 'stream-end') return false;
435
+ if (!kinds.includes('text-generation')) return false;
436
+ // v1's frames are tagged `event_type`, NOT v2's `type` — the discriminator differs.
437
+ if (events.some((e) => !e.done && e.data!.type !== undefined)) return false;
438
+ const first = events[0]!.data as Body;
439
+ if (first.is_finished !== false) return false;
440
+ const end = events[events.length - 1]!.data as Body;
441
+ if (end.is_finished !== true || end.finish_reason !== 'COMPLETE') return false;
442
+ const joined = events.filter((e) => e.data?.event_type === 'text-generation').map((e) => (e.data as Body).text).join('');
443
+ return joined === (final.body as Body).text && end.response.text === (final.body as Body).text;
444
+ }),
445
+ ),
446
+ todo('cohere.chat_v1.connectors', 'chat_v1', 'v1 chat: `connectors` RAG retrieval → search_queries / search_results / documents', 'api', 'common'),
447
+ todo('cohere.chat_v1.tool_results', 'chat_v1', 'v1 chat: `tools` + `tool_results` multi-step tool loop', 'api', 'common'),
448
+ todo('cohere.chat_v1.citations', 'chat_v1', 'v1 chat: `documents` + citation_quality → the ChatCitation array', 'api', 'common'),
449
+ todo('cohere.chat_v1.prompt_truncation', 'chat_v1', 'v1 chat: `prompt_truncation` AUTO/OFF over an oversized history', 'api', 'niche'),
450
+ todo('cohere.chat_v1.conversation_id', 'chat_v1', 'v1 chat: server-side `conversation_id` history persistence', 'api', 'niche'),
451
+
452
+ // ══ EMBED ═════════════════════════════════════════════════════════════════════════════
453
+ done('cohere.embed.v2_by_type', 'embed', 'v2 embed: vectors keyed BY TYPE, every requested type present and agreeing', 'api', 'core', () =>
454
+ withRoot(async (h) => {
455
+ const r = await h({ m: 'POST', p: '/v2/embed', b: { model: 'embed-v4.0', input_type: 'search_query', texts: ['alpha', 'beta'], embedding_types: ['float', 'int8', 'uint8', 'binary', 'ubinary', 'base64'], output_dimension: 256 } });
456
+ if (!ok(r)) return false;
457
+ const b = r.body as Body;
458
+ if (b.response_type !== 'embeddings_by_type') return false;
459
+ const e = b.embeddings;
460
+ if (e.float?.length !== 2 || e.float[0].length !== 256) return false;
461
+ if (e.int8?.[0]?.length !== 256 || e.uint8?.[0]?.length !== 256) return false;
462
+ // binary packs ONE BIT per dimension, 8 to a byte — so its array is dim/8 long, not dim.
463
+ if (e.binary?.[0]?.length !== 32 || e.ubinary?.[0]?.length !== 32) return false;
464
+ if (typeof e.base64?.[0] !== 'string') return false;
465
+ // binary vs ubinary is a SIGNEDNESS difference over the same packed bytes, and it is the only
466
+ // property separating them. Without this the signing branch could be deleted and every verify
467
+ // would stay green (§9 round two, MINOR 8).
468
+ const bin = e.binary[0] as number[];
469
+ const ubin = e.ubinary[0] as number[];
470
+ for (let i = 0; i < bin.length; i++) {
471
+ if (((bin[i]! + 256) % 256) !== ubin[i]!) return false; // same bits
472
+ if (ubin[i]! < 0 || ubin[i]! > 255) return false; // unsigned range
473
+ if (bin[i]! < -128 || bin[i]! > 127) return false; // signed range
474
+ }
475
+ // …and the two really do DIFFER somewhere, or "signed" would be vacuous over this input.
476
+ if (!bin.some((v, i) => v !== ubin[i])) return false;
477
+ // Every type is a view of the SAME vector, not an independently generated one.
478
+ if (e.int8[0][0] !== Math.max(-128, Math.min(127, Math.round(e.float[0][0] * 127)))) return false;
479
+ if (e.uint8[0][0] !== Math.max(0, Math.min(255, Math.round((e.float[0][0] + 1) * 127.5)))) return false;
480
+ // Distinct inputs give distinct vectors — otherwise "deterministic per input" is vacuous.
481
+ return JSON.stringify(e.float[0]) !== JSON.stringify(e.float[1]) && JSON.stringify(b.texts) === '["alpha","beta"]';
482
+ }),
483
+ ),
484
+ done('cohere.embed.v1_floats_default', 'embed', 'v1 embed: the DEFAULT answer is the FLAT float shape, not the by-type one', 'api', 'core', () =>
485
+ withRoot(async (h) => {
486
+ const flat = await h({ m: 'POST', p: '/v1/embed', b: { model: 'embed-english-v3.0', input_type: 'search_query', texts: ['gamma'] } });
487
+ const byType = await h({ m: 'POST', p: '/v1/embed', b: { model: 'embed-english-v3.0', input_type: 'search_query', texts: ['gamma'], embedding_types: ['float'] } });
488
+ const fb = flat.body as Body;
489
+ const tb = byType.body as Body;
490
+ // cohere-ai models `EmbedResponse` as a union discriminated on `response_type`; always
491
+ // answering by-type would land every default v1 caller in the wrong union arm.
492
+ if (fb.response_type !== 'embeddings_floats' || !Array.isArray(fb.embeddings) || !Array.isArray(fb.embeddings[0])) return false;
493
+ if (fb.embeddings[0].length !== 1024) return false;
494
+ if (tb.response_type !== 'embeddings_by_type' || !Array.isArray(tb.embeddings?.float)) return false;
495
+ // The two shapes carry the SAME vector — asking for a type changes the packaging only.
496
+ return JSON.stringify(tb.embeddings.float[0]) === JSON.stringify(fb.embeddings[0]);
497
+ }),
498
+ ),
499
+ done('cohere.embed.v2_requires_input_type', 'embed', 'v2 embed REQUIRES `input_type`; v1 does not — the sharpest version difference', 'api', 'core', () =>
500
+ withRoot(async (h) => {
501
+ const v2Missing = await h({ m: 'POST', p: '/v2/embed', b: { model: 'embed-v4.0', texts: ['x'] } });
502
+ const v2Present = await h({ m: 'POST', p: '/v2/embed', b: { model: 'embed-v4.0', input_type: 'search_query', texts: ['x'] } });
503
+ // v1 with a LEGACY-shaped call still needs one for a v3 model — that refusal lives in the
504
+ // handler, not the schema, which is why both halves are asserted here.
505
+ const v1MissingV3 = await h({ m: 'POST', p: '/v1/embed', b: { model: 'embed-english-v3.0', texts: ['x'] } });
506
+ return bareError(v2Missing, 400) && message(v2Missing) === 'invalid request: input_type is required'
507
+ && ok(v2Present)
508
+ && bareError(v1MissingV3, 400) && message(v1MissingV3).includes("input_type is required for model 'embed-english-v3.0'");
509
+ }),
510
+ ),
511
+ done('cohere.embed.closed_enums', 'embed', 'embed: embedding_types / input_type / truncate / output_dimension are closed sets', 'api', 'common', () =>
512
+ withRoot(async (h) => {
513
+ const base = { model: 'embed-v4.0', input_type: 'search_query', texts: ['x'] };
514
+ // The documented sets, as LITERALS. Each accepted value is exercised, and one value outside
515
+ // each set is refused — a bijection with the vendor's documented set, not a spot check.
516
+ for (const t of ['float', 'int8', 'uint8', 'binary', 'ubinary', 'base64']) {
517
+ if (!ok(await h({ m: 'POST', p: '/v2/embed', b: { ...base, embedding_types: [t] } }))) return false;
518
+ }
519
+ for (const it of ['search_document', 'search_query', 'classification', 'clustering', 'image']) {
520
+ if (!ok(await h({ m: 'POST', p: '/v2/embed', b: { ...base, input_type: it } }))) return false;
521
+ }
522
+ for (const tr of ['NONE', 'START', 'END']) {
523
+ if (!ok(await h({ m: 'POST', p: '/v2/embed', b: { ...base, truncate: tr } }))) return false;
524
+ }
525
+ for (const d of [256, 512, 1024, 1536]) {
526
+ if (!ok(await h({ m: 'POST', p: '/v2/embed', b: { ...base, output_dimension: d } }))) return false;
527
+ }
528
+ const badType = await h({ m: 'POST', p: '/v2/embed', b: { ...base, embedding_types: ['float16'] } });
529
+ const badInput = await h({ m: 'POST', p: '/v2/embed', b: { ...base, input_type: 'search' } });
530
+ const badTrunc = await h({ m: 'POST', p: '/v2/embed', b: { ...base, truncate: 'end' } });
531
+ const badDim = await h({ m: 'POST', p: '/v2/embed', b: { ...base, output_dimension: 999 } });
532
+ return bareError(badType, 400) && bareError(badInput, 400) && bareError(badTrunc, 400) && bareError(badDim, 400)
533
+ && message(badDim) === 'invalid request: output_dimension must be one of 256, 512, 1024, 1536';
534
+ }),
535
+ ),
536
+ done('cohere.embed.dimensions_by_model', 'embed', 'embed: each model produces its own documented dimensionality', 'api', 'common', () =>
537
+ withRoot(async (h) => {
538
+ const dim = async (model: string) => {
539
+ const r = await h({ m: 'POST', p: '/v1/embed', b: { model, input_type: 'search_query', texts: ['x'] } });
540
+ return ok(r) ? ((r.body as Body).embeddings[0] as number[]).length : -1;
541
+ };
542
+ // The `light` models are 384-dimensional, the full v3 models 1024, embed-v4.0 1536.
543
+ return await dim('embed-english-v3.0') === 1024
544
+ && await dim('embed-english-light-v3.0') === 384
545
+ && await dim('embed-multilingual-light-v3.0') === 384
546
+ && await dim('embed-v4.0') === 1536;
547
+ }),
548
+ ),
549
+ done('cohere.embed.normalized', 'embed', 'embed: the pseudo-vectors are L2-normalized, like real embeddings', 'api', 'niche', () =>
550
+ withRoot(async (h) => {
551
+ const r = await h({ m: 'POST', p: '/v2/embed', b: { model: 'embed-v4.0', input_type: 'search_query', texts: ['norm me'] } });
552
+ const v = (r.body as Body).embeddings.float[0] as number[];
553
+ const norm = Math.sqrt(v.reduce((a, x) => a + x * x, 0));
554
+ return ok(r) && Math.abs(norm - 1) < 1e-9;
555
+ }),
556
+ ),
557
+ done('cohere.embed.validation_inputs', 'embed', 'embed: no texts/images/inputs → 400; wrong-endpoint model → 404', 'api', 'common', () =>
558
+ withRoot(async (h) => {
559
+ const none = await h({ m: 'POST', p: '/v2/embed', b: { model: 'embed-v4.0', input_type: 'search_query' } });
560
+ const chatModel = await h({ m: 'POST', p: '/v2/embed', b: { model: 'command-a-03-2025', input_type: 'search_query', texts: ['x'] } });
561
+ return bareError(none, 400) && message(none).includes('one of texts, images or inputs')
562
+ && bareError(chatModel, 404);
563
+ }),
564
+ ),
565
+ done('cohere.embed.v2_inputs_form', 'embed', 'v2 embed: the structured `inputs` form (content parts), not just `texts`', 'api', 'niche', () =>
566
+ withRoot(async (h) => {
567
+ const viaInputs = await h({ m: 'POST', p: '/v2/embed', b: { model: 'embed-v4.0', input_type: 'search_query', inputs: [{ content: [{ type: 'text', text: 'structured' }] }] } });
568
+ const viaTexts = await h({ m: 'POST', p: '/v2/embed', b: { model: 'embed-v4.0', input_type: 'search_query', texts: ['structured'] } });
569
+ // The two spellings of the same input produce the SAME vector — proof `inputs` is really
570
+ // flattened rather than hashed as a JSON blob.
571
+ return ok(viaInputs)
572
+ && JSON.stringify((viaInputs.body as Body).embeddings.float[0]) === JSON.stringify((viaTexts.body as Body).embeddings.float[0]);
573
+ }),
574
+ ),
575
+ todo('cohere.embed.images', 'embed', 'embed: real image inputs (base64 data URIs) with image_tokens billing', 'api', 'common'),
576
+ todo('cohere.embed.max_tokens', 'embed', 'v2 embed: the `max_tokens` per-input cap and its truncation semantics', 'api', 'niche'),
577
+ todo('cohere.embed.token_limit_refusal', 'embed', 'embed: refuse an input past the model context length when truncate=NONE', 'api', 'core'),
578
+
579
+ // ══ RERANK ════════════════════════════════════════════════════════════════════════════
580
+ done('cohere.rerank.v2_order', 'rerank', 'v2 rerank: results ordered by descending relevance, scores in [0,1]', 'api', 'core', () =>
581
+ withRoot(async (h) => {
582
+ const r = await h({ m: 'POST', p: '/v2/rerank', b: { model: 'rerank-v3.5', query: 'apple pie recipe', documents: ['how to service a car engine', 'a recipe for apple pie', 'apple orchard tours'] } });
583
+ if (!ok(r)) return false;
584
+ const results = (r.body as Body).results as Array<{ index: number; relevance_score: number }>;
585
+ if (results.length !== 3) return false;
586
+ // The lexically-closest document wins, and the order is strictly descending.
587
+ if (results[0]!.index !== 1) return false;
588
+ for (let i = 1; i < results.length; i++) if (results[i]!.relevance_score > results[i - 1]!.relevance_score) return false;
589
+ if (results.some((x) => x.relevance_score < 0 || x.relevance_score > 1)) return false;
590
+ // Rerank is billed in SEARCH UNITS, not tokens.
591
+ return (r.body as Body).meta?.billed_units?.search_units === 1 && (r.body as Body).meta?.billed_units?.input_tokens === undefined;
592
+ }),
593
+ ),
594
+ done('cohere.rerank.v2_strings_only', 'rerank', 'v2 rerank: `documents` must be STRINGS (v1 accepts objects)', 'api', 'core', () =>
595
+ withRoot(async (h) => {
596
+ const objV2 = await h({ m: 'POST', p: '/v2/rerank', b: { model: 'rerank-v3.5', query: 'q', documents: [{ text: 'y' }] } });
597
+ const objV1 = await h({ m: 'POST', p: '/v1/rerank', b: { query: 'q', documents: [{ text: 'y' }] } });
598
+ // Both halves: v2 REFUSES the object form and v1 ACCEPTS it. Asserting only the refusal
599
+ // would pass on a twin that refused object documents everywhere.
600
+ return bareError(objV2, 400) && message(objV2) === 'invalid request: documents[0] must be a string'
601
+ && ok(objV1);
602
+ }),
603
+ ),
604
+ done('cohere.rerank.top_n', 'rerank', 'rerank: `top_n` truncates to the N best, keeping original indices', 'api', 'common', () =>
605
+ withRoot(async (h) => {
606
+ const r = await h({ m: 'POST', p: '/v2/rerank', b: { model: 'rerank-v3.5', query: 'apple pie', documents: ['engine oil', 'apple pie recipe', 'orchard', 'pie crust'], top_n: 2 } });
607
+ const results = (r.body as Body).results as Array<{ index: number }>;
608
+ // The indices are positions in the ORIGINAL document list, not in the truncated result.
609
+ return ok(r) && results.length === 2 && results[0]!.index === 1 && results.every((x) => x.index >= 0 && x.index < 4);
610
+ }),
611
+ ),
612
+ done('cohere.rerank.v1_return_documents', 'rerank', 'v1 rerank: `return_documents` rides the text back; v2 has no such option', 'api', 'common', () =>
613
+ withRoot(async (h) => {
614
+ const withDocs = await h({ m: 'POST', p: '/v1/rerank', b: { query: 'apple', documents: ['apple pie', 'engine'], return_documents: true } });
615
+ const without = await h({ m: 'POST', p: '/v1/rerank', b: { query: 'apple', documents: ['apple pie', 'engine'] } });
616
+ const v2 = await h({ m: 'POST', p: '/v2/rerank', b: { model: 'rerank-v3.5', query: 'apple', documents: ['apple pie', 'engine'], return_documents: true } });
617
+ return (withDocs.body as Body).results[0].document?.text === 'apple pie'
618
+ && (without.body as Body).results[0].document === undefined
619
+ // v2 IGNORES the option rather than honouring an option its schema does not declare.
620
+ && (v2.body as Body).results[0].document === undefined;
621
+ }),
622
+ ),
623
+ done('cohere.rerank.v1_rank_fields', 'rerank', 'v1 rerank: `rank_fields` selects which object fields are scored', 'api', 'niche', () =>
624
+ withRoot(async (h) => {
625
+ const docs = [{ title: 'engine oil', body: 'apple pie recipe' }, { title: 'apple pie recipe', body: 'engine oil' }];
626
+ const onTitle = await h({ m: 'POST', p: '/v1/rerank', b: { query: 'apple pie', documents: docs, rank_fields: ['title'] } });
627
+ const onBody = await h({ m: 'POST', p: '/v1/rerank', b: { query: 'apple pie', documents: docs, rank_fields: ['body'] } });
628
+ // Scoring different fields of the SAME documents must produce different winners, or
629
+ // `rank_fields` is not actually being honoured.
630
+ return (onTitle.body as Body).results[0].index === 1 && (onBody.body as Body).results[0].index === 0;
631
+ }),
632
+ ),
633
+ done('cohere.rerank.validation', 'rerank', 'rerank: missing query / empty documents / wrong-endpoint model each refused', 'api', 'common', () =>
634
+ withRoot(async (h) => {
635
+ const noQuery = await h({ m: 'POST', p: '/v2/rerank', b: { model: 'rerank-v3.5', documents: ['x'] } });
636
+ const noDocs = await h({ m: 'POST', p: '/v2/rerank', b: { model: 'rerank-v3.5', query: 'q', documents: [] } });
637
+ const wrongModel = await h({ m: 'POST', p: '/v2/rerank', b: { model: 'command-a-03-2025', query: 'q', documents: ['x'] } });
638
+ return bareError(noQuery, 400) && bareError(noDocs, 400) && bareError(wrongModel, 404);
639
+ }),
640
+ ),
641
+ todo('cohere.rerank.max_tokens_per_doc', 'rerank', 'v2 rerank: `max_tokens_per_doc` chunking of long documents', 'api', 'niche'),
642
+ todo('cohere.rerank.max_chunks_per_doc', 'rerank', 'v1 rerank: `max_chunks_per_doc` and its billing effect', 'api', 'niche'),
643
+
644
+ // ══ CLASSIFY ══════════════════════════════════════════════════════════════════════════
645
+ done('cohere.classify.create', 'classify', 'classify: the full classification shape, confidences summing to 1', 'api', 'core', () =>
646
+ withRoot(async (h) => {
647
+ const r = await h({ m: 'POST', p: '/v1/classify', b: { inputs: ['a great day', 'a terrible day'], examples: [{ text: 'good', label: 'positive' }, { text: 'bad', label: 'negative' }] } });
648
+ if (!ok(r)) return false;
649
+ const cs = (r.body as Body).classifications as Body[];
650
+ if (cs.length !== 2 || cs[0]!.input !== 'a great day') return false;
651
+ if (!['positive', 'negative'].includes(cs[0]!.prediction)) return false;
652
+ if (cs[0]!.classification_type !== 'single-label') return false;
653
+ // `labels` is a MAP from label to `{confidence}`, and every declared label appears.
654
+ if (Object.keys(cs[0]!.labels).sort().join(',') !== 'negative,positive') return false;
655
+ const sum = Object.values(cs[0]!.labels as Record<string, { confidence: number }>).reduce((a, l) => a + l.confidence, 0);
656
+ if (Math.abs(sum - 1) > 1e-3) return false;
657
+ // The prediction really is the argmax of the label map, not an unrelated pick.
658
+ const best = Object.entries(cs[0]!.labels as Record<string, { confidence: number }>).sort((a, b) => b[1].confidence - a[1].confidence)[0]![0];
659
+ if (best !== cs[0]!.prediction) return false;
660
+ return (r.body as Body).meta?.billed_units?.classifications === 2;
661
+ }),
662
+ ),
663
+ done('cohere.classify.validation', 'classify', 'classify: no inputs / no examples-or-preset / one label each refused', 'api', 'common', () =>
664
+ withRoot(async (h) => {
665
+ const noInputs = await h({ m: 'POST', p: '/v1/classify', b: { examples: [{ text: 'a', label: 'x' }, { text: 'b', label: 'y' }] } });
666
+ const noLabelSpace = await h({ m: 'POST', p: '/v1/classify', b: { inputs: ['x'] } });
667
+ const oneLabel = await h({ m: 'POST', p: '/v1/classify', b: { inputs: ['x'], examples: [{ text: 'a', label: 'only' }, { text: 'b', label: 'only' }] } });
668
+ const noLabel = await h({ m: 'POST', p: '/v1/classify', b: { inputs: ['x'], examples: [{ text: 'a' }] } });
669
+ return bareError(noInputs, 400) && bareError(noLabelSpace, 400) && message(noLabelSpace).includes('examples or preset')
670
+ && bareError(oneLabel, 400) && message(oneLabel).includes('at least 2 unique labels')
671
+ && bareError(noLabel, 400);
672
+ }),
673
+ ),
674
+ done('cohere.classify.preset_is_not_fabricated', 'classify', 'classify: an unmodeled `preset` fails like the vendor — it never invents a label space', 'api', 'core', () =>
675
+ withRoot(async (h) => {
676
+ // §9 round two, m-R2.5. An earlier version accepted ANY preset string and invented
677
+ // ['positive','negative'], returning confident-looking classifications against labels the
678
+ // caller never named — a fake success on a path filed as `cohere.classify.preset`, and the
679
+ // same class the detokenize path treats as a hard rule.
680
+ const r = await h({ m: 'POST', p: '/v1/classify', b: { inputs: ['x'], preset: 'my-saved-preset' } });
681
+ if (!bareError(r, 404) || !message(r).includes("preset 'my-saved-preset' not found")) return false;
682
+ // …and the EXAMPLES path still works, so this is a refusal of the unmodeled option rather
683
+ // than of classification itself.
684
+ const withExamples = await h({ m: 'POST', p: '/v1/classify', b: { inputs: ['x'], examples: [{ text: 'a', label: 'p' }, { text: 'b', label: 'n' }] } });
685
+ return ok(withExamples) && ((withExamples.body as Body).classifications as Body[]).length === 1;
686
+ }),
687
+ ),
688
+ todo('cohere.classify.preset', 'classify', 'classify: a saved `preset` as the label space instead of inline examples', 'api', 'niche'),
689
+ todo('cohere.classify.multi_label', 'classify', 'classify: multi-label classification against a finetuned model', 'api', 'niche'),
690
+ todo('cohere.classify.truncate', 'classify', 'classify: the `truncate` parameter over oversized inputs', 'api', 'niche'),
691
+
692
+ // ══ TOKENIZE / DETOKENIZE ═════════════════════════════════════════════════════════════
693
+ done('cohere.tokenize.round_trip', 'tokenize', 'tokenize → detokenize round-trips the exact input, whitespace included', 'api', 'core', () =>
694
+ withRoot(async (h) => {
695
+ const text = 'hello brave\nnew world ';
696
+ const tok = await h({ m: 'POST', p: '/v1/tokenize', b: { text, model: 'command-a-03-2025' } });
697
+ if (!ok(tok)) return false;
698
+ const tb = tok.body as Body;
699
+ if (tb.tokens.length !== tb.token_strings.length || tb.tokens.length === 0) return false;
700
+ if ((tb.token_strings as string[]).join('') !== text) return false;
701
+ const back = await h({ m: 'POST', p: '/v1/detokenize', b: { tokens: tb.tokens, model: 'command-a-03-2025' } });
702
+ return ok(back) && (back.body as Body).text === text;
703
+ }),
704
+ ),
705
+ done('cohere.tokenize.vocabulary_is_learned', 'tokenize', 'detokenize refuses an id the twin never issued (never fabricates text)', 'api', 'core', () =>
706
+ withRoot(async (h) => {
707
+ // A FRESH root has an empty vocabulary, so ANY id is unknown — the honest answer is a 400,
708
+ // never a placeholder string that the caller would read as real detokenized text.
709
+ const cold = await h({ m: 'POST', p: '/v1/detokenize', b: { tokens: [12345], model: 'command-a-03-2025' } });
710
+ if (!bareError(cold, 400) || !message(cold).includes('unknown token id 12345')) return false;
711
+ await h({ m: 'POST', p: '/v1/tokenize', b: { text: 'known words', model: 'command-a-03-2025' } });
712
+ // …and after a tokenize, an id INSIDE the learned vocabulary works while one outside still
713
+ // does not. Both halves, so "it always 400s" cannot pass.
714
+ const warm = await h({ m: 'POST', p: '/v1/tokenize', b: { text: 'known words', model: 'command-a-03-2025' } });
715
+ const good = await h({ m: 'POST', p: '/v1/detokenize', b: { tokens: (warm.body as Body).tokens, model: 'command-a-03-2025' } });
716
+ const stillBad = await h({ m: 'POST', p: '/v1/detokenize', b: { tokens: [(warm.body as Body).tokens[0], 999_999], model: 'command-a-03-2025' } });
717
+ return ok(good) && (good.body as Body).text === 'known words' && bareError(stillBad, 400);
718
+ }),
719
+ ),
720
+ done('cohere.tokenize.dirty_state_vocabulary', 'tokenize', 'DIRTY STATE: a later tokenize never breaks an earlier call\'s detokenize', 'api', 'core', () =>
721
+ withRoot(async (h) => {
722
+ // A fresh-root verify structurally CANNOT catch this class. The vocabulary is built up over
723
+ // MANY calls, and the hazard is a later segment claiming an id an earlier segment already
724
+ // holds — after which the earlier caller's detokenize silently returns the WRONG text.
725
+ const first = await h({ m: 'POST', p: '/v1/tokenize', b: { text: 'alpha beta gamma', model: 'command-a-03-2025' } });
726
+ const firstTokens = (first.body as Body).tokens as number[];
727
+ // Twenty more tokenizes, growing the vocabulary well past the first call's segments.
728
+ for (let i = 0; i < 20; i++) {
729
+ await h({ m: 'POST', p: '/v1/tokenize', b: { text: `filler${i} words ${i} more`, model: 'command-a-03-2025' } });
730
+ }
731
+ const back = await h({ m: 'POST', p: '/v1/detokenize', b: { tokens: firstTokens, model: 'command-a-03-2025' } });
732
+ if (!ok(back) || (back.body as Body).text !== 'alpha beta gamma') return false;
733
+ // …and the ids are STABLE: re-tokenizing the original text yields the same ids, so a client
734
+ // that cached them is not silently invalidated by other traffic.
735
+ const again = await h({ m: 'POST', p: '/v1/tokenize', b: { text: 'alpha beta gamma', model: 'command-a-03-2025' } });
736
+ return JSON.stringify((again.body as Body).tokens) === JSON.stringify(firstTokens);
737
+ }),
738
+ ),
739
+ done('cohere.tokenize.collision_probe', 'tokenize', 'two segments preferring the same id get DISTINCT ids (no silent overwrite)', 'api', 'common', () =>
740
+ withRoot(async (h) => {
741
+ // Build the collision deliberately rather than hoping for one: every segment's preferred id
742
+ // is a pure hash, so a large vocabulary makes a collision near-certain, and the invariant
743
+ // under test is that EVERY distinct segment maps to its OWN id and back.
744
+ const words: string[] = [];
745
+ for (let i = 0; i < 400; i++) words.push(`w${i}`);
746
+ const text = words.join(' ');
747
+ const tok = await h({ m: 'POST', p: '/v1/tokenize', b: { text, model: 'command-a-03-2025' } });
748
+ if (!ok(tok)) return false;
749
+ const ids = (tok.body as Body).tokens as number[];
750
+ const strings = (tok.body as Body).token_strings as string[];
751
+ // Distinct segments must have distinct ids — a silent overwrite shows up as a duplicate id
752
+ // for two different strings.
753
+ const pairs = new Map<number, string>();
754
+ for (let i = 0; i < ids.length; i++) {
755
+ const prev = pairs.get(ids[i]!);
756
+ if (prev !== undefined && prev !== strings[i]) return false;
757
+ pairs.set(ids[i]!, strings[i]!);
758
+ }
759
+ const back = await h({ m: 'POST', p: '/v1/detokenize', b: { tokens: ids, model: 'command-a-03-2025' } });
760
+ return ok(back) && (back.body as Body).text === text;
761
+ }),
762
+ ),
763
+ done('cohere.tokenize.validation', 'tokenize', 'tokenize/detokenize: `model` is REQUIRED on both (unlike v1 embed/rerank)', 'api', 'common', () =>
764
+ withRoot(async (h) => {
765
+ const noModel = await h({ m: 'POST', p: '/v1/tokenize', b: { text: 'x' } });
766
+ const noText = await h({ m: 'POST', p: '/v1/tokenize', b: { model: 'command-a-03-2025' } });
767
+ const badModel = await h({ m: 'POST', p: '/v1/tokenize', b: { text: 'x', model: 'nope' } });
768
+ const detNoModel = await h({ m: 'POST', p: '/v1/detokenize', b: { tokens: [1] } });
769
+ const detNoTokens = await h({ m: 'POST', p: '/v1/detokenize', b: { model: 'command-a-03-2025' } });
770
+ return bareError(noModel, 400) && message(noModel) === 'invalid request: model is required'
771
+ && bareError(noText, 400) && bareError(badModel, 404)
772
+ && bareError(detNoModel, 400) && bareError(detNoTokens, 400);
773
+ }),
774
+ ),
775
+
776
+ // ══ MODELS ════════════════════════════════════════════════════════════════════════════
777
+ done('cohere.models.list', 'models', 'GET /v1/models: the real catalog with `next_page_token`', 'api', 'core', () =>
778
+ withRoot(async (h) => {
779
+ const r = await h({ m: 'GET', p: '/v1/models' });
780
+ if (!ok(r)) return false;
781
+ const b = r.body as Body;
782
+ if (!Array.isArray(b.models) || b.next_page_token !== null) return false;
783
+ // Real, checkable catalog facts — not just "an array came back".
784
+ const chat = b.models.find((m: Body) => m.name === 'command-a-03-2025');
785
+ const embed = b.models.find((m: Body) => m.name === 'embed-v4.0');
786
+ return chat?.context_length === 256000 && JSON.stringify(chat.endpoints) === '["chat"]'
787
+ && embed?.context_length === 128000 && embed.finetuned === false;
788
+ }),
789
+ ),
790
+ done('cohere.models.filter_by_endpoint', 'models', 'GET /v1/models?endpoint=: filters to models serving that endpoint', 'api', 'common', () =>
791
+ withRoot(async (h) => {
792
+ const all = await h({ m: 'GET', p: '/v1/models' });
793
+ const rerank = await h({ m: 'GET', p: '/v1/models?endpoint=rerank' });
794
+ const chat = await h({ m: 'GET', p: '/v1/models?endpoint=chat' });
795
+ const allN = ((all.body as Body).models as Body[]).length;
796
+ const rr = (rerank.body as Body).models as Body[];
797
+ const ch = (chat.body as Body).models as Body[];
798
+ // A real filter: strictly fewer than the whole catalog, disjoint from the other endpoint,
799
+ // and every row genuinely serves it.
800
+ return rr.length > 0 && rr.length < allN && rr.every((m) => m.endpoints.includes('rerank'))
801
+ && ch.length > 0 && ch.every((m) => m.endpoints.includes('chat'))
802
+ && !rr.some((m) => ch.some((c) => c.name === m.name));
803
+ }),
804
+ ),
805
+ done('cohere.models.get', 'models', 'GET /v1/models/{name}: one card, 404 for an unknown name', 'api', 'core', () =>
806
+ withRoot(async (h) => {
807
+ const one = await h({ m: 'GET', p: '/v1/models/rerank-v3.5' });
808
+ const missing = await h({ m: 'GET', p: '/v1/models/not-a-model' });
809
+ const b = one.body as Body;
810
+ return ok(one) && b.name === 'rerank-v3.5' && b.context_length === 4000
811
+ && String(b.tokenizer_url).startsWith('https://')
812
+ && bareError(missing, 404) && message(missing).includes("model 'not-a-model' not found");
813
+ }),
814
+ ),
815
+ done('cohere.models.closed_endpoint_set', 'models', "every SERVED model's `endpoints` is in Cohere's closed CompatibleEndpoint set", 'api', 'common', () =>
816
+ withRoot(async (h) => {
817
+ // The claim is about what the twin SERVES, so the catalog is read back off the wire rather
818
+ // than out of the module. An earlier version asserted over the imported `COHERE_MODELS`
819
+ // array and had no request on its path at all — the mutation gate reported it as a SURVIVOR,
820
+ // correctly: it would have stayed green with the whole handler deleted.
821
+ const listed = await h({ m: 'GET', p: '/v1/models' });
822
+ if (!ok(listed)) return false;
823
+ const models = (listed.body as Body).models as Body[];
824
+ if (!Array.isArray(models) || models.length === 0) return false;
825
+ // A LITERAL of the vendor's documented set, written here rather than imported from the models
826
+ // module — importing the constant the catalog is built from would be a tautology.
827
+ const documented = new Set(['chat', 'embed', 'classify', 'summarize', 'rerank', 'rate', 'generate']);
828
+ for (const m of models) {
829
+ if (!Array.isArray(m.endpoints) || m.endpoints.length === 0) return false;
830
+ for (const e of m.endpoints) if (!documented.has(String(e))) return false;
831
+ }
832
+ // Every documented endpoint the twin's catalog actually uses is FILTERABLE, and one it does
833
+ // not use returns an empty list rather than the whole catalog — so the served `endpoints`
834
+ // values and the filter agree, in both directions.
835
+ const served = new Set(models.flatMap((m) => m.endpoints as string[]));
836
+ for (const e of served) {
837
+ const filtered = await h({ m: 'GET', p: `/v1/models?endpoint=${e}` });
838
+ const got = (filtered.body as Body).models as Body[];
839
+ if (got.length === 0 || got.length >= models.length) return false;
840
+ if (!got.every((m) => (m.endpoints as string[]).includes(e))) return false;
841
+ }
842
+ for (const e of [...documented].filter((d) => !served.has(d))) {
843
+ if (((await h({ m: 'GET', p: `/v1/models?endpoint=${e}` })).body as Body).models.length !== 0) return false;
844
+ }
845
+ // …and the module's own exported set bijects with the documented one, so a future addition to
846
+ // either side is caught rather than silently diverging.
847
+ return [...COHERE_ENDPOINTS].sort().join(',') === [...documented].sort().join(',');
848
+ }),
849
+ ),
850
+ todo('cohere.models.pagination', 'models', 'GET /v1/models: real `page_token` cursor pagination', 'api', 'niche'),
851
+ todo('cohere.models.finetuned_in_catalog', 'models', 'GET /v1/models: finetuned models appear with finetuned:true and default_endpoints', 'api', 'common'),
852
+ todo('cohere.models.default_only', 'models', 'GET /v1/models?default_only=true filtering', 'api', 'niche'),
853
+
854
+ // ══ DATASETS (stateful) ═══════════════════════════════════════════════════════════════
855
+ done('cohere.datasets.create_read', 'datasets', 'datasets: create → get, with the create answering ONLY `{id}`', 'api', 'core', () =>
856
+ withRoot(async (h) => {
857
+ const created = await h({ m: 'POST', p: '/v1/datasets?name=ds-one&type=embed-input', b: { content: 'a\nb' } });
858
+ if (!ok(created)) return false;
859
+ // The vendor's `DatasetsCreateResponse` is `{ id }` and nothing else — a twin returning the
860
+ // whole dataset here would be more helpful and less faithful.
861
+ if (Object.keys(created.body as object).join(',') !== 'id') return false;
862
+ const id = field(created, 'id') as string;
863
+ const got = await h({ m: 'GET', p: `/v1/datasets/${id}` });
864
+ const d = (got.body as Body).dataset;
865
+ // The dataset is NESTED under `dataset` — `DatasetsGetResponse` is `{ dataset }`.
866
+ return ok(got) && (got.body as Body).id === undefined
867
+ && d?.id === id && d.name === 'ds-one' && d.dataset_type === 'embed-input'
868
+ && d.validation_status === 'validated' && d.created_at === PINNED_AT;
869
+ }),
870
+ ),
871
+ done('cohere.datasets.closed_type_set', 'datasets', "datasets: `type` biject with Cohere's closed DatasetType set", 'api', 'common', () =>
872
+ withRoot(async (h) => {
873
+ // The vendor's documented set as a LITERAL — the oracle that makes "the twin serves surface
874
+ // the vendor does not have" checkable in the ACCEPT direction too, not just the reject one.
875
+ const documented = ['embed-input', 'embed-result', 'cluster-result', 'cluster-outliers', 'reranker-finetune-input', 'single-label-classification-finetune-input', 'chat-finetune-input', 'multi-label-classification-finetune-input', 'batch-chat-input', 'batch-openai-chat-input', 'batch-embed-v2-input', 'batch-chat-v2-input'];
876
+ for (const t of documented) {
877
+ if (!ok(await h({ m: 'POST', p: `/v1/datasets?name=x&type=${t}`, b: DATA_FILE }))) return false;
878
+ }
879
+ const bad = await h({ m: 'POST', p: '/v1/datasets?name=x&type=not-a-real-type', b: DATA_FILE });
880
+ const noType = await h({ m: 'POST', p: '/v1/datasets?name=x', b: DATA_FILE });
881
+ const noName = await h({ m: 'POST', p: '/v1/datasets?type=embed-input', b: DATA_FILE });
882
+ // …and the multipart `data` file the vendor's own client always appends is REQUIRED, so the
883
+ // closed-set oracle above is not resting on a lenient path the vendor would 400
884
+ // (§9 round 1, finding 6).
885
+ const noFile = await h({ m: 'POST', p: '/v1/datasets?name=x&type=embed-input' });
886
+ return bareError(bad, 400) && message(bad).includes('type must be one of')
887
+ && bareError(noType, 400) && bareError(noName, 400)
888
+ && bareError(noFile, 400) && message(noFile) === 'invalid request: the data file is required';
889
+ }),
890
+ ),
891
+ done('cohere.datasets.list_filter', 'datasets', 'datasets: list, filtered by datasetType / validationStatus, with limit+offset', 'api', 'common', () =>
892
+ withRoot(async (h) => {
893
+ await h({ m: 'POST', p: '/v1/datasets?name=a&type=embed-input', b: DATA_FILE });
894
+ await h({ m: 'POST', p: '/v1/datasets?name=b&type=chat-finetune-input', b: DATA_FILE });
895
+ await h({ m: 'POST', p: '/v1/datasets?name=c&type=embed-input', b: DATA_FILE });
896
+ const all = await h({ m: 'GET', p: '/v1/datasets' });
897
+ const embed = await h({ m: 'GET', p: '/v1/datasets?datasetType=embed-input' });
898
+ const paged = await h({ m: 'GET', p: '/v1/datasets?limit=1&offset=1' });
899
+ const badStatus = await h({ m: 'GET', p: '/v1/datasets?validationStatus=nonsense' });
900
+ // The LIST filter honours the same closed DatasetType set the CREATE path does. An earlier
901
+ // version applied `datasetType` raw and answered `200 {datasets:[]}` for a value the vendor
902
+ // rejects — reporting an empty account for what is actually a refused request, and leaving
903
+ // the two paths asymmetric for no reason (§9 round two, MINOR 9).
904
+ const badType = await h({ m: 'GET', p: '/v1/datasets?datasetType=not-a-real-type' });
905
+ if (!bareError(badType, 400) || !message(badType).includes('datasetType must be one of')) return false;
906
+ const names = (r: CohereResponseEnvelope) => ((r.body as Body).datasets as Body[]).map((d) => d.name);
907
+ return names(all).join(',') === 'a,b,c'
908
+ && names(embed).join(',') === 'a,c'
909
+ && names(paged).join(',') === 'b'
910
+ && bareError(badStatus, 400);
911
+ }),
912
+ ),
913
+ done('cohere.datasets.usage', 'datasets', 'datasets: GET /v1/datasets/usage folds real stored bytes (and is not shadowed by /{id})', 'api', 'common', () =>
914
+ withRoot(async (h) => {
915
+ const empty = await h({ m: 'GET', p: '/v1/datasets/usage' });
916
+ if (!ok(empty) || field(empty, 'organization_usage') !== 0) return false;
917
+ await h({ m: 'POST', p: '/v1/datasets?name=a&type=embed-input', b: { content: '12345' } });
918
+ await h({ m: 'POST', p: '/v1/datasets?name=b&type=embed-input', b: { content: '123' } });
919
+ const used = await h({ m: 'GET', p: '/v1/datasets/usage' });
920
+ // A real fold over stored state, not a constant — and `usage` is a literal sibling of
921
+ // `/{id}`, so this also pins the route-ordering that keeps it from being shadowed.
922
+ return ok(used) && field(used, 'organization_usage') === 8 && (used.body as Body).dataset === undefined;
923
+ }),
924
+ ),
925
+ done('cohere.datasets.delete', 'datasets', 'datasets: delete answers `{}` and the row really leaves the list', 'api', 'core', () =>
926
+ withRoot(async (h) => {
927
+ const created = await h({ m: 'POST', p: '/v1/datasets?name=gone&type=embed-input', b: DATA_FILE });
928
+ const id = field(created, 'id') as string;
929
+ const del = await h({ m: 'DELETE', p: `/v1/datasets/${id}` });
930
+ // Cohere's delete answers an EMPTY object, not the `{deleted:true}` envelope most vendors
931
+ // send — and the row must actually be gone, which a status-only assertion would not catch.
932
+ if (!ok(del) || Object.keys(del.body as object).length !== 0) return false;
933
+ const after = await h({ m: 'GET', p: `/v1/datasets/${id}` });
934
+ const list = await h({ m: 'GET', p: '/v1/datasets' });
935
+ const delAgain = await h({ m: 'DELETE', p: `/v1/datasets/${id}` });
936
+ return bareError(after, 404) && ((list.body as Body).datasets as Body[]).length === 0 && bareError(delAgain, 404);
937
+ }),
938
+ ),
939
+ done('cohere.datasets.id_survives_delete', 'datasets', 'DIRTY STATE: a deleted dataset\'s id is never re-issued to a new one', 'api', 'core', () =>
940
+ withRoot(async (h) => {
941
+ // The count-mint bug three packs' §9 reviews each found: delete a row, create a new one, and
942
+ // a row-count-derived id lands back on the tombstone. Only a build-up-then-assert verify can
943
+ // see it; a fresh-root one structurally cannot.
944
+ const a = field(await h({ m: 'POST', p: '/v1/datasets?name=a&type=embed-input', b: DATA_FILE }), 'id') as string;
945
+ const b = field(await h({ m: 'POST', p: '/v1/datasets?name=b&type=embed-input', b: DATA_FILE }), 'id') as string;
946
+ await h({ m: 'DELETE', p: `/v1/datasets/${b}` });
947
+ await h({ m: 'DELETE', p: `/v1/datasets/${a}` });
948
+ const c = field(await h({ m: 'POST', p: '/v1/datasets?name=c&type=embed-input', b: DATA_FILE }), 'id') as string;
949
+ const d = field(await h({ m: 'POST', p: '/v1/datasets?name=d&type=embed-input', b: DATA_FILE }), 'id') as string;
950
+ if (c === a || c === b || d === a || d === b || c === d) return false;
951
+ // …and the live row really is the new one, not a resurrected tombstone.
952
+ const got = await h({ m: 'GET', p: `/v1/datasets/${c}` });
953
+ return ok(got) && (got.body as Body).dataset.name === 'c';
954
+ }),
955
+ ),
956
+ todo('cohere.datasets.validation_pipeline', 'datasets', 'datasets: real upload validation (queued → processing → validated/failed) with row errors', 'api', 'core'),
957
+ todo('cohere.datasets.parts', 'datasets', 'datasets: `dataset_parts` splits (train/eval) and their row counts', 'api', 'common'),
958
+ todo('cohere.datasets.metrics', 'datasets', 'datasets: the `metrics` block (label distribution, token counts)', 'api', 'niche'),
959
+ todo('cohere.datasets.date_filters', 'datasets', 'datasets: the `before` / `after` timestamp list filters', 'api', 'niche'),
960
+ todo('cohere.datasets.csv_and_separators', 'datasets', 'datasets: csv_delimiter / text_separator / keep_fields upload options', 'api', 'niche'),
961
+
962
+ // ══ CONNECTORS (Cohere's RAG connector registry) ══════════════════════════════════════
963
+ done('cohere.connectors.create_read', 'connectors', 'connectors: create → get, both NESTED under `connector`', 'api', 'core', () =>
964
+ withRoot(async (h) => {
965
+ const created = await h({ m: 'POST', p: '/v1/connectors', b: { name: 'search', url: 'https://e.test/s', excludes: ['secret'], description: 'd' } });
966
+ if (!ok(created)) return false;
967
+ const c = (created.body as Body).connector;
968
+ // `CreateConnectorResponse` is `{ connector }` — a bare object would break every SDK caller.
969
+ if ((created.body as Body).id !== undefined || c === undefined) return false;
970
+ if (c.name !== 'search' || c.url !== 'https://e.test/s' || c.description !== 'd') return false;
971
+ // `auth_type`/`auth_status` are DERIVED server-side, not caller-supplied.
972
+ if (c.auth_type !== 'none' || c.auth_status !== 'valid' || c.active !== true) return false;
973
+ const got = await h({ m: 'GET', p: `/v1/connectors/${c.id}` });
974
+ return ok(got) && (got.body as Body).connector?.id === c.id && JSON.stringify((got.body as Body).connector.excludes) === '["secret"]';
975
+ }),
976
+ ),
977
+ done('cohere.connectors.list_total_count', 'connectors', 'connectors: list carries `total_count`, and limit/offset page it', 'api', 'common', () =>
978
+ withRoot(async (h) => {
979
+ for (const n of ['a', 'b', 'c']) await h({ m: 'POST', p: '/v1/connectors', b: { name: n, url: `https://e.test/${n}` } });
980
+ const all = await h({ m: 'GET', p: '/v1/connectors' });
981
+ const paged = await h({ m: 'GET', p: '/v1/connectors?limit=1&offset=1' });
982
+ // `total_count` is the UNPAGED total — a twin returning the page size here would be wrong in
983
+ // exactly the way that breaks a paginating client.
984
+ return ((all.body as Body).connectors as Body[]).length === 3 && (all.body as Body).total_count === 3
985
+ && ((paged.body as Body).connectors as Body[]).length === 1
986
+ && (paged.body as Body).connectors[0].name === 'b'
987
+ && (paged.body as Body).total_count === 3;
988
+ }),
989
+ ),
990
+ done('cohere.connectors.update', 'connectors', 'connectors: PATCH is a partial update — untouched fields survive', 'api', 'core', () =>
991
+ withRoot(async (h) => {
992
+ const created = await h({ m: 'POST', p: '/v1/connectors', b: { name: 'orig', url: 'https://e.test/s', excludes: ['x'] } });
993
+ const id = (created.body as Body).connector.id as string;
994
+ const patched = await h({ m: 'PATCH', p: `/v1/connectors/${id}`, b: { name: 'renamed', active: false } });
995
+ const c = (patched.body as Body).connector;
996
+ // A whole-row replace would lose `url` and `excludes` — the failure a status-only assertion
997
+ // would sail past.
998
+ if (c.name !== 'renamed' || c.active !== false || c.url !== 'https://e.test/s' || JSON.stringify(c.excludes) !== '["x"]') return false;
999
+ const reread = await h({ m: 'GET', p: `/v1/connectors/${id}` });
1000
+ const missing = await h({ m: 'PATCH', p: '/v1/connectors/nope', b: { name: 'x' } });
1001
+ return (reread.body as Body).connector.name === 'renamed' && bareError(missing, 404);
1002
+ }),
1003
+ ),
1004
+ done('cohere.connectors.update_revert_is_not_a_replay', 'connectors', 'A PATCH reverting a field under a FROZEN clock is a real write, not a swallowed replay', 'api', 'core', () =>
1005
+ withRoot(async (h) => {
1006
+ // §9 round 1, finding 4. `applyTwinWrite`'s action id is (content + `occurredAt` millisecond).
1007
+ // A world under a frozen clock (TWIN_WORLD_CLOCK_FILE) gives every request ONE occurredAt, so
1008
+ // A → B → A makes the third action byte-identical to the first: the kernel drops it as
1009
+ // `replayed` while the handler answers 200 carrying B, the value the caller did not ask for.
1010
+ // Every request below shares the same pinned instant, which is exactly that world.
1011
+ const created = await h({ m: 'POST', p: '/v1/connectors', b: { name: 'A', url: 'https://e.test/s' } });
1012
+ const id = (created.body as Body).connector.id as string;
1013
+ // THE SEQUENCE IS ODD-LENGTH ON PURPOSE. `B → A → B` is the shortest revisit whose deduped
1014
+ // outcome DIFFERS from its correct one: the third update is byte-identical to the first, so
1015
+ // a twin without the ordinal drops it as `replayed` and the projection stays at A, while a
1016
+ // correct twin lands B. An EVEN-length cycle (B → A → B → A) ends at A either way — which is
1017
+ // precisely how the first version of this pin came out HOLLOW in the revert matrix: its cell
1018
+ // stayed green with the ordinal removed, because the assertion could not tell the two apart.
1019
+ const toB = await h({ m: 'PATCH', p: `/v1/connectors/${id}`, b: { name: 'B' } });
1020
+ if ((toB.body as Body).connector.name !== 'B') return false;
1021
+ const backToA = await h({ m: 'PATCH', p: `/v1/connectors/${id}`, b: { name: 'A' } });
1022
+ if ((backToA.body as Body).connector.name !== 'A') return false;
1023
+ const againB = await h({ m: 'PATCH', p: `/v1/connectors/${id}`, b: { name: 'B' } });
1024
+ // The reply must say B…
1025
+ if ((againB.body as Body).connector.name !== 'B') return false;
1026
+ // …and so must the STORED state. Reply-and-state disagreeing is the failure mode, and only
1027
+ // the re-read can see it.
1028
+ const reread = await h({ m: 'GET', p: `/v1/connectors/${id}` });
1029
+ if ((reread.body as Body).connector.name !== 'B') return false;
1030
+ // A longer odd cycle, so the ordinal is shown to keep MOVING rather than merely alternating
1031
+ // between two values that would themselves collide on the next revisit.
1032
+ for (const n of ['A', 'B', 'A']) await h({ m: 'PATCH', p: `/v1/connectors/${id}`, b: { name: n } });
1033
+ const final = await h({ m: 'GET', p: `/v1/connectors/${id}` });
1034
+ // The ordinal is twin bookkeeping and must never reach the wire.
1035
+ return (final.body as Body).connector.name === 'A' && (final.body as Body).connector._rev === undefined;
1036
+ }),
1037
+ ),
1038
+ done('cohere.connectors.oauth_authorize', 'connectors', 'connectors: oauth/authorize builds a real redirect, and refuses a non-oauth connector', 'api', 'common', () =>
1039
+ withRoot(async (h) => {
1040
+ const plain = await h({ m: 'POST', p: '/v1/connectors', b: { name: 'plain', url: 'https://e.test/s' } });
1041
+ const plainId = (plain.body as Body).connector.id as string;
1042
+ const refused = await h({ m: 'POST', p: `/v1/connectors/${plainId}/oauth/authorize` });
1043
+ // A connector with no OAuth configuration has nothing to authorize. Answering a fabricated
1044
+ // redirect URL would be a fake success on a path the vendor refuses.
1045
+ if (!bareError(refused, 400) || !message(refused).includes('not configured for oauth')) return false;
1046
+ const oauth = await h({ m: 'POST', p: '/v1/connectors', b: { name: 'oauth', url: 'https://e.test/o', oauth: { client_id: 'cid-9', client_secret: 's', authorize_url: 'https://auth.test/go', token_url: 'https://auth.test/tok' } } });
1047
+ const oc = (oauth.body as Body).connector;
1048
+ if (oc.auth_type !== 'oauth' || oc.auth_status !== 'expired') return false;
1049
+ const authz = await h({ m: 'POST', p: `/v1/connectors/${oc.id}/oauth/authorize?after_token_redirect=https://app.test/done` });
1050
+ const url = field(authz, 'redirect_url') as string;
1051
+ // The redirect is built from the connector's OWN stored configuration, not a constant.
1052
+ return ok(authz) && url.startsWith('https://auth.test/go?')
1053
+ && url.includes('client_id=cid-9')
1054
+ && url.includes('after_token_redirect=https%3A%2F%2Fapp.test%2Fdone')
1055
+ && (await h({ m: 'POST', p: '/v1/connectors/nope/oauth/authorize' })).status === 404;
1056
+ }),
1057
+ ),
1058
+ done('cohere.connectors.delete', 'connectors', 'connectors: delete answers `{}` and the row really leaves the list', 'api', 'common', () =>
1059
+ withRoot(async (h) => {
1060
+ const created = await h({ m: 'POST', p: '/v1/connectors', b: { name: 'gone', url: 'https://e.test/s' } });
1061
+ const id = (created.body as Body).connector.id as string;
1062
+ const del = await h({ m: 'DELETE', p: `/v1/connectors/${id}` });
1063
+ if (!ok(del) || Object.keys(del.body as object).length !== 0) return false;
1064
+ const after = await h({ m: 'GET', p: `/v1/connectors/${id}` });
1065
+ const list = await h({ m: 'GET', p: '/v1/connectors' });
1066
+ return bareError(after, 404) && (list.body as Body).total_count === 0;
1067
+ }),
1068
+ ),
1069
+ done('cohere.connectors.validation', 'connectors', 'connectors: name and url are both required', 'api', 'common', () =>
1070
+ withRoot(async (h) => {
1071
+ const noName = await h({ m: 'POST', p: '/v1/connectors', b: { url: 'https://e.test' } });
1072
+ const noUrl = await h({ m: 'POST', p: '/v1/connectors', b: { name: 'x' } });
1073
+ return bareError(noName, 400) && message(noName) === 'invalid request: name is required'
1074
+ && bareError(noUrl, 400) && message(noUrl) === 'invalid request: url is required';
1075
+ }),
1076
+ ),
1077
+ todo('cohere.connectors.service_auth', 'connectors', 'connectors: `service_auth` bearer/basic configuration and its auth_status', 'api', 'common'),
1078
+ todo('cohere.connectors.oauth_token_exchange', 'connectors', 'connectors: the OAuth callback token exchange that flips auth_status to valid', 'api', 'common'),
1079
+ todo('cohere.connectors.search_invocation', 'connectors', 'connectors: the twin CALLING a connector\'s search URL during a v1 chat', 'api', 'common'),
1080
+ todo('cohere.connectors.continue_on_failure', 'connectors', 'connectors: `continue_on_failure` semantics when a connector search errors', 'api', 'niche'),
1081
+
1082
+ // ══ EMBED JOBS (stateful) ═════════════════════════════════════════════════════════════
1083
+ done('cohere.embed_jobs.create_read', 'embed_jobs', 'embed jobs: create answers `{job_id, meta}`; the job reads back with NO `id`', 'api', 'core', () =>
1084
+ withRoot(async (h) => {
1085
+ const ds = field(await h({ m: 'POST', p: '/v1/datasets?name=in&type=embed-input', b: DATA_FILE }), 'id') as string;
1086
+ const created = await h({ m: 'POST', p: '/v1/embed-jobs', b: { model: 'embed-english-v3.0', dataset_id: ds, input_type: 'search_document', name: 'j1' } });
1087
+ if (!ok(created)) return false;
1088
+ const b = created.body as Body;
1089
+ // A DIFFERENT create envelope again: `job_id`, not `id`, and a `meta` alongside.
1090
+ if (typeof b.job_id !== 'string' || b.id !== undefined || b.meta === undefined) return false;
1091
+ const got = await h({ m: 'GET', p: `/v1/embed-jobs/${b.job_id}` });
1092
+ const j = got.body as Body;
1093
+ // The vendor's EmbedJob schema has NO `id` key at all; emitting one would be invented
1094
+ // surface, and a connector subjecting on `.id` would collapse the whole collection.
1095
+ return ok(got) && j.job_id === b.job_id && j.id === undefined
1096
+ && j.status === 'processing' && j.input_dataset_id === ds && j.model === 'embed-english-v3.0'
1097
+ && j.truncate === 'END' && j.name === 'j1' && j.created_at === PINNED_AT;
1098
+ }),
1099
+ ),
1100
+ done('cohere.embed_jobs.requires_real_dataset', 'embed_jobs', 'embed jobs: `dataset_id` must reference a dataset that exists', 'api', 'core', () =>
1101
+ withRoot(async (h) => {
1102
+ const missing = await h({ m: 'POST', p: '/v1/embed-jobs', b: { model: 'embed-english-v3.0', dataset_id: 'does-not-exist', input_type: 'search_document' } });
1103
+ if (!bareError(missing, 404) || !message(missing).includes("dataset 'does-not-exist' not found")) return false;
1104
+ const ds = field(await h({ m: 'POST', p: '/v1/datasets?name=in&type=embed-input', b: DATA_FILE }), 'id') as string;
1105
+ // …and once the dataset EXISTS the same call succeeds — so the refusal is about the missing
1106
+ // reference, not about the endpoint being broken.
1107
+ const okJob = await h({ m: 'POST', p: '/v1/embed-jobs', b: { model: 'embed-english-v3.0', dataset_id: ds, input_type: 'search_document' } });
1108
+ // A DELETED dataset must fail the same way a never-created one does.
1109
+ await h({ m: 'DELETE', p: `/v1/datasets/${ds}` });
1110
+ const afterDelete = await h({ m: 'POST', p: '/v1/embed-jobs', b: { model: 'embed-english-v3.0', dataset_id: ds, input_type: 'search_document' } });
1111
+ return ok(okJob) && bareError(afterDelete, 404);
1112
+ }),
1113
+ ),
1114
+ done('cohere.embed_jobs.cancel_state_machine', 'embed_jobs', 'embed jobs: cancel moves processing → cancelling, and a terminal job is refused', 'api', 'core', () =>
1115
+ withRoot(async (h) => {
1116
+ const ds = field(await h({ m: 'POST', p: '/v1/datasets?name=in&type=embed-input', b: DATA_FILE }), 'id') as string;
1117
+ const job = field(await h({ m: 'POST', p: '/v1/embed-jobs', b: { model: 'embed-english-v3.0', dataset_id: ds, input_type: 'search_document' } }), 'job_id') as string;
1118
+ const cancel = await h({ m: 'POST', p: `/v1/embed-jobs/${job}/cancel` });
1119
+ // `embedJobs.cancel` is declared `-> void`: an empty body — and the STATE must have moved,
1120
+ // which a status-only assertion would not catch.
1121
+ if (!ok(cancel) || Object.keys(cancel.body as object).length !== 0) return false;
1122
+ const after = await h({ m: 'GET', p: `/v1/embed-jobs/${job}` });
1123
+ if ((after.body as Body).status !== 'cancelling') return false;
1124
+ const again = await h({ m: 'POST', p: `/v1/embed-jobs/${job}/cancel` });
1125
+ const missing = await h({ m: 'POST', p: '/v1/embed-jobs/nope/cancel' });
1126
+ return bareError(again, 400) && message(again).includes('cannot be cancelled') && bareError(missing, 404);
1127
+ }),
1128
+ ),
1129
+ done('cohere.embed_jobs.validation', 'embed_jobs', 'embed jobs: model / dataset_id / input_type required, closed enums enforced', 'api', 'common', () =>
1130
+ withRoot(async (h) => {
1131
+ const ds = field(await h({ m: 'POST', p: '/v1/datasets?name=in&type=embed-input', b: DATA_FILE }), 'id') as string;
1132
+ const base = { model: 'embed-english-v3.0', dataset_id: ds, input_type: 'search_document' };
1133
+ const noModel = await h({ m: 'POST', p: '/v1/embed-jobs', b: { dataset_id: ds, input_type: 'search_document' } });
1134
+ const noDataset = await h({ m: 'POST', p: '/v1/embed-jobs', b: { model: 'embed-english-v3.0', input_type: 'search_document' } });
1135
+ const noInput = await h({ m: 'POST', p: '/v1/embed-jobs', b: { model: 'embed-english-v3.0', dataset_id: ds } });
1136
+ const badInput = await h({ m: 'POST', p: '/v1/embed-jobs', b: { ...base, input_type: 'search' } });
1137
+ const badTrunc = await h({ m: 'POST', p: '/v1/embed-jobs', b: { ...base, truncate: 'middle' } });
1138
+ const chatModel = await h({ m: 'POST', p: '/v1/embed-jobs', b: { ...base, model: 'command-a-03-2025' } });
1139
+ return bareError(noModel, 400) && bareError(noDataset, 400) && bareError(noInput, 400)
1140
+ && bareError(badInput, 400) && bareError(badTrunc, 400) && bareError(chatModel, 404);
1141
+ }),
1142
+ ),
1143
+ done('cohere.embed_jobs.list', 'embed_jobs', 'embed jobs: list under the `embed_jobs` key (not `data`)', 'api', 'common', () =>
1144
+ withRoot(async (h) => {
1145
+ const empty = await h({ m: 'GET', p: '/v1/embed-jobs' });
1146
+ if (!ok(empty) || JSON.stringify((empty.body as Body).embed_jobs) !== '[]' || (empty.body as Body).data !== undefined) return false;
1147
+ const ds = field(await h({ m: 'POST', p: '/v1/datasets?name=in&type=embed-input', b: DATA_FILE }), 'id') as string;
1148
+ const job = field(await h({ m: 'POST', p: '/v1/embed-jobs', b: { model: 'embed-english-v3.0', dataset_id: ds, input_type: 'search_document' } }), 'job_id') as string;
1149
+ const list = await h({ m: 'GET', p: '/v1/embed-jobs' });
1150
+ const jobs = (list.body as Body).embed_jobs as Body[];
1151
+ return jobs.length === 1 && jobs[0]!.job_id === job && jobs[0]!.id === undefined;
1152
+ }),
1153
+ ),
1154
+ todo('cohere.embed_jobs.completion', 'embed_jobs', 'embed jobs: a job actually completing and minting its `output_dataset_id`', 'api', 'common'),
1155
+ todo('cohere.embed_jobs.failure', 'embed_jobs', 'embed jobs: the `failed` terminal state and its error reporting', 'api', 'niche'),
1156
+
1157
+ // ══ SURFACE THE TWIN DOES NOT SERVE (real vendor endpoints, honestly filed) ═══════════
1158
+ todo('cohere.generate.create', 'generate', 'POST /v1/generate: the legacy completion endpoint (deprecated but still served)', 'api', 'niche'),
1159
+ todo('cohere.generate.stream', 'generate', 'POST /v1/generate with stream: the GenerateStreamedResponse wire', 'api', 'niche'),
1160
+ todo('cohere.summarize.create', 'summarize', 'POST /v1/summarize: the legacy summarization endpoint (deprecated but still served)', 'api', 'niche'),
1161
+ todo('cohere.parse.create', 'parse', 'POST /v2/parse: document parsing into structured output', 'api', 'common'),
1162
+ todo('cohere.audio.transcriptions', 'audio', 'POST /v2/audio/transcriptions: multipart audio → transcript', 'api', 'common'),
1163
+ todo('cohere.batches.create', 'batches', 'POST /v2/batches: submit a batch of chat/embed requests', 'api', 'common'),
1164
+ todo('cohere.batches.list', 'batches', 'GET /v2/batches: list batches with their status counts', 'api', 'common'),
1165
+ todo('cohere.batches.retrieve', 'batches', 'GET /v2/batches/{id}: one batch with its output file references', 'api', 'common'),
1166
+ todo('cohere.batches.cancel', 'batches', 'POST /v2/batches/{id}:cancel — note the COLON verb suffix, not a path segment', 'api', 'common'),
1167
+ todo('cohere.finetuning.create', 'finetuning', 'POST /v1/finetuning/finetuned-models: start a finetune from a dataset', 'api', 'common'),
1168
+ todo('cohere.finetuning.list', 'finetuning', 'GET /v1/finetuning/finetuned-models: list finetuned models', 'api', 'common'),
1169
+ todo('cohere.finetuning.get', 'finetuning', 'GET /v1/finetuning/finetuned-models/{id}: one finetuned model and its status', 'api', 'common'),
1170
+ todo('cohere.finetuning.update', 'finetuning', 'PATCH /v1/finetuning/finetuned-models/{id}: rename / re-point a finetune', 'api', 'niche'),
1171
+ todo('cohere.finetuning.delete', 'finetuning', 'DELETE /v1/finetuning/finetuned-models/{id}', 'api', 'niche'),
1172
+ todo('cohere.finetuning.events', 'finetuning', 'GET /v1/finetuning/finetuned-models/{id}/events: the training event log', 'api', 'niche'),
1173
+ todo('cohere.finetuning.metrics', 'finetuning', 'GET /v1/finetuning/finetuned-models/{id}/training-step-metrics', 'api', 'niche'),
1174
+
1175
+ // ══ ERRORS / AUTH / READ-ONLY ═════════════════════════════════════════════════════════
1176
+ done('cohere.auth.check_api_key', 'auth', 'POST /v1/check-api-key: a POST despite the name, answering {valid, organization_id, owner_id}', 'api', 'common', () =>
1177
+ withRoot(async (h) => {
1178
+ // §9 round two, MAJOR 2: this endpoint was served, probed by conformance, driven through the
1179
+ // real SDK and headlined in the README's "asserted by a named capability" table — with NO
1180
+ // manifest entry and no area. The area census could not catch it, because it asserts a
1181
+ // bijection between COHERE_AREAS and the manifest's areas: a surface missing from BOTH sides
1182
+ // passes silently. That is the census's documented blind spot, found live.
1183
+ const r = await h({ m: 'POST', p: '/v1/check-api-key' });
1184
+ if (!ok(r)) return false;
1185
+ const b = r.body as Body;
1186
+ if (b.valid !== true || typeof b.organization_id !== 'string' || typeof b.owner_id !== 'string') return false;
1187
+ // THE VERB IS THE POINT. `checkApiKey()` sends `method: "POST"` in cohere-ai's Client.js —
1188
+ // the name invites a GET, and a twin that served one would break every real caller.
1189
+ const asGet = await h({ m: 'GET', p: '/v1/check-api-key' });
1190
+ if (!bareError(asGet, 404)) return false;
1191
+ // …and it is auth-gated like every other endpoint when an auth surface is present.
1192
+ return bareError(await h({ m: 'POST', p: '/v1/check-api-key', h: {} }), 401);
1193
+ }),
1194
+ ),
1195
+ done('cohere.errors.bare_message_envelope', 'errors', "every error body is Cohere's BARE `{message}` — one key, no wrapper", 'api', 'core', () =>
1196
+ withRoot(async (h) => {
1197
+ // Sample every distinct failure the twin can produce and assert the SHAPE of each. A single
1198
+ // spot check would not notice one path drifting to the OpenAI `{error:{...}}` envelope.
1199
+ const cases: CohereResponseEnvelope[] = [
1200
+ await h({ m: 'POST', p: '/v2/chat', b: {} }),
1201
+ await h({ m: 'POST', p: '/v2/chat', b: CHAT({ model: 'nope' }) }),
1202
+ await h({ m: 'GET', p: '/v1/models/nope' }),
1203
+ await h({ m: 'GET', p: '/v1/datasets/nope' }),
1204
+ await h({ m: 'GET', p: '/v1/nowhere' }),
1205
+ await h({ m: 'GET', p: '/v1/models', h: {} }),
1206
+ await h({ m: 'POST', p: '/v2/chat', b: CHAT(), ro: true }),
1207
+ ];
1208
+ for (const r of cases) {
1209
+ if (r.status < 400) return false;
1210
+ if (!r.body || typeof r.body !== 'object') return false;
1211
+ if (Object.keys(r.body as object).join(',') !== 'message') return false;
1212
+ if (typeof (r.body as Body).message !== 'string' || (r.body as Body).message === '') return false;
1213
+ }
1214
+ // …and the statuses really are the vendor's, not all one code.
1215
+ return cases.map((r) => r.status).join(',') === '400,404,404,404,404,401,405';
1216
+ }),
1217
+ ),
1218
+ done('cohere.errors.auth_401', 'errors', 'auth: a request with an auth SURFACE but no usable bearer token 401s', 'api', 'core', () =>
1219
+ withRoot(async (h) => {
1220
+ const none = await h({ m: 'GET', p: '/v1/models', h: {} });
1221
+ const empty = await h({ m: 'GET', p: '/v1/models', h: { authorization: 'Bearer ' } });
1222
+ const sentinel = await h({ m: 'GET', p: '/v1/models', h: { authorization: 'Bearer invalid' } });
1223
+ const good = await h({ m: 'GET', p: '/v1/models', h: { authorization: 'Bearer sk-anything' } });
1224
+ // The twin cannot validate real keys, so the modeled failure is the CHECKABLE
1225
+ // missing/sentinel case — and a plausible token must still be ACCEPTED, or the twin would be
1226
+ // unusable rather than faithful.
1227
+ return bareError(none, 401) && bareError(empty, 401) && bareError(sentinel, 401) && ok(good);
1228
+ }),
1229
+ ),
1230
+ done('cohere.errors.read_only_405', 'errors', 'readOnly: every POST/PATCH/DELETE is refused 405 while reads still serve', 'api', 'core', () =>
1231
+ withRoot(async (h) => {
1232
+ // Seed with writes ENABLED, then prove the same reads still work read-only while every
1233
+ // mutating VERB is refused. Note the refusal is method-based, so the write-free inference
1234
+ // POSTs (`/v2/chat`, `/v1/tokenize`) are refused too — a read-only Cohere world cannot chat.
1235
+ // That is a defensible D3 reading of "no POSTs" but it is NOT "every mutation", which is why
1236
+ // the title says POST/PATCH/DELETE rather than over-claiming (§9 round 1, finding 8).
1237
+ const ds = field(await h({ m: 'POST', p: '/v1/datasets?name=a&type=embed-input', b: DATA_FILE }), 'id') as string;
1238
+ const writes: Step[] = [
1239
+ { m: 'POST', p: '/v2/chat', b: CHAT(), ro: true },
1240
+ { m: 'POST', p: '/v1/datasets?name=b&type=embed-input', ro: true },
1241
+ { m: 'DELETE', p: `/v1/datasets/${ds}`, ro: true },
1242
+ { m: 'PATCH', p: '/v1/connectors/x', b: { name: 'y' }, ro: true },
1243
+ { m: 'POST', p: '/v1/tokenize', b: { text: 'x', model: 'command-a-03-2025' }, ro: true },
1244
+ ];
1245
+ for (const w of writes) {
1246
+ const r = await h(w);
1247
+ if (!bareError(r, 405)) return false;
1248
+ }
1249
+ const read = await h({ m: 'GET', p: '/v1/datasets', ro: true });
1250
+ return ok(read) && ((read.body as Body).datasets as Body[]).length === 1;
1251
+ }),
1252
+ ),
1253
+ done('cohere.errors.unmodeled_ops_404', 'errors', 'unmodeled operations fail like the vendor (404), never a fake success', 'api', 'core', () =>
1254
+ withRoot(async (h) => {
1255
+ // Real Cohere endpoints this twin does NOT model. Each must 404 rather than fake-succeed —
1256
+ // and each is filed as a `todo` above, so the manifest and the handler agree.
1257
+ const unmodeled: Step[] = [
1258
+ { m: 'POST', p: '/v1/generate', b: { prompt: 'x' } },
1259
+ { m: 'POST', p: '/v1/summarize', b: { text: 'x' } },
1260
+ { m: 'POST', p: '/v2/parse', b: {} },
1261
+ { m: 'POST', p: '/v2/audio/transcriptions', b: {} },
1262
+ { m: 'GET', p: '/v2/batches' },
1263
+ { m: 'POST', p: '/v2/batches' },
1264
+ { m: 'GET', p: '/v1/finetuning/finetuned-models' },
1265
+ { m: 'POST', p: '/v1/finetuning/finetuned-models', b: {} },
1266
+ ];
1267
+ for (const u of unmodeled) {
1268
+ const r = await h(u);
1269
+ if (!bareError(r, 404)) return false;
1270
+ }
1271
+ // …and a method the twin does not serve on a path it DOES is equally a 404, not a silent
1272
+ // fall-through to the GET branch.
1273
+ const wrongMethod = await h({ m: 'DELETE', p: '/v1/models/rerank-v3.5' });
1274
+ return bareError(wrongMethod, 404);
1275
+ }),
1276
+ ),
1277
+ done('cohere.errors.malformed_body', 'errors', 'a malformed JSON body is refused, never treated as an empty object', 'api', 'common', () => {
1278
+ const root = mkdtempSync(join(tmpdir(), 'cohere-cap-'));
1279
+ return verifyBoundary('cohere.malformed', async () => {
1280
+ try {
1281
+ const r = await handleCohereTwinRequest({ method: 'POST', path: '/v2/chat', body: '{not json', root, occurredAt: PINNED_AT });
1282
+ // An unparseable body yields no `model`, so the vendor-shaped required-field refusal is
1283
+ // the correct answer — and a 200 here would mean the twin generated from nothing.
1284
+ return bareError(r, 400) && message(r) === 'invalid request: model is required';
1285
+ } finally {
1286
+ rmSync(root, { recursive: true, force: true });
1287
+ }
1288
+ });
1289
+ }),
1290
+
1291
+ // ══ DETERMINISM — the serve-path invariant ════════════════════════════════════════════
1292
+ done('cohere.determinism.replay_two_roots', 'determinism', 'the served response is byte-identical across two INDEPENDENT state roots', 'api', 'core', () => {
1293
+ const a = mkdtempSync(join(tmpdir(), 'cohere-det-a-'));
1294
+ const b = mkdtempSync(join(tmpdir(), 'cohere-det-b-'));
1295
+ return verifyBoundary('cohere.determinism', async () => {
1296
+ try {
1297
+ const requests: Step[] = [
1298
+ { m: 'POST', p: '/v2/chat', b: CHAT() },
1299
+ { m: 'POST', p: '/v2/chat', b: CHAT({ tools: [TOOL] }) },
1300
+ { m: 'POST', p: '/v1/chat', b: { message: 'v1 det' } },
1301
+ { m: 'POST', p: '/v2/embed', b: { model: 'embed-v4.0', input_type: 'search_query', texts: ['det'], embedding_types: ['float', 'int8', 'base64'] } },
1302
+ { m: 'POST', p: '/v2/rerank', b: { model: 'rerank-v3.5', query: 'q', documents: ['a q', 'b'] } },
1303
+ { m: 'POST', p: '/v1/classify', b: { inputs: ['x'], examples: [{ text: 'a', label: 'p' }, { text: 'b', label: 'n' }] } },
1304
+ { m: 'POST', p: '/v1/tokenize', b: { text: 'det tokens here', model: 'command-a-03-2025' } },
1305
+ ];
1306
+ const run = async (root: string) => {
1307
+ const out: string[] = [];
1308
+ for (const s of requests) {
1309
+ const r = await handleCohereTwinRequest({ method: s.m, path: s.p, root, occurredAt: PINNED_AT, ...(s.b === undefined ? {} : { body: JSON.stringify(s.b) }) });
1310
+ out.push(`${r.status} ${JSON.stringify(r.body)}`);
1311
+ }
1312
+ return out;
1313
+ };
1314
+ const first = await run(a);
1315
+ const second = await run(b);
1316
+ // Two independent roots, same requests, byte-identical answers — and the payloads are
1317
+ // non-trivial, so this cannot pass on a twin that answers `{}` to everything.
1318
+ if (first.join('\n') !== second.join('\n')) return false;
1319
+ if (first.some((s) => s.length < 40)) return false;
1320
+ // Replaying the FIRST root a second time must also be identical: the stored state grew
1321
+ // (the tokenize wrote rows) without perturbing any answer.
1322
+ const third = await run(a);
1323
+ return third.join('\n') === first.join('\n');
1324
+ } finally {
1325
+ rmSync(a, { recursive: true, force: true });
1326
+ rmSync(b, { recursive: true, force: true });
1327
+ }
1328
+ });
1329
+ }),
1330
+ done('cohere.determinism.no_wall_clock', 'determinism', 'no wall-clock or randomness in served content: an unpinned run is stable, and TIMESTAMPS are pinned', 'api', 'core', () => {
1331
+ const root = mkdtempSync(join(tmpdir(), 'cohere-det-c-'));
1332
+ return verifyBoundary('cohere.determinism_clock', async () => {
1333
+ try {
1334
+ // NOTHING here threads `occurredAt`, so anything reading `Date.now()` or `Math.random()` on
1335
+ // the serve path differs between calls.
1336
+ const one = await handleCohereTwinRequest({ method: 'POST', path: '/v2/chat', body: JSON.stringify(CHAT()), root });
1337
+ await new Promise((r) => setTimeout(r, 5));
1338
+ const two = await handleCohereTwinRequest({ method: 'POST', path: '/v2/chat', body: JSON.stringify(CHAT()), root });
1339
+ if (JSON.stringify(one.body) !== JSON.stringify(two.body)) return false;
1340
+ // A DIFFERENT prompt must give a different answer, so "identical" is not trivially true.
1341
+ const other = await handleCohereTwinRequest({ method: 'POST', path: '/v2/chat', body: JSON.stringify(CHAT({ messages: [{ role: 'user', content: 'different' }] })), root });
1342
+ if (JSON.stringify(other.body) === JSON.stringify(one.body)) return false;
1343
+
1344
+ // THE HALF THAT ACTUALLY REFUTES THE CLAIM (§9 round 1, finding 1). `/v2/chat` carries no
1345
+ // timestamp at all, so the three calls above would stay green with `nowIso` rewritten to
1346
+ // `new Date().toISOString()` — the pack's own headline invariant had a surviving mutant.
1347
+ // Datasets are the endpoint that DOES stamp a clock, so an unpinned pair of creates is
1348
+ // where a wall clock becomes visible. Both halves matter: the two timestamps must AGREE
1349
+ // across a real 5ms gap, and they must equal the pinned instant written here as a LITERAL
1350
+ // (importing the handler's own constant could not catch it drifting).
1351
+ const mk = (name: string) => handleCohereTwinRequest({ method: 'POST', path: `/v1/datasets?name=${name}&type=embed-input`, body: JSON.stringify({ content: 'x' }), root });
1352
+ const a = await mk('clock-a');
1353
+ await new Promise((r) => setTimeout(r, 5));
1354
+ const b = await mk('clock-b');
1355
+ const read = async (r: CohereResponseEnvelope) => (await handleCohereTwinRequest({ method: 'GET', path: `/v1/datasets/${(r.body as Body).id}`, root })).body as Body;
1356
+ const rowA = await read(a);
1357
+ const rowB = await read(b);
1358
+ const stamped = rowA.dataset?.created_at as string;
1359
+ if (typeof stamped !== 'string' || stamped !== rowB.dataset?.created_at) return false;
1360
+ if (stamped !== '2027-01-15T08:00:00.000Z') return false;
1361
+ if (rowA.dataset?.updated_at !== stamped) return false;
1362
+ // …and an EXPLICIT occurredAt still wins, so the pin is a default rather than a hardcode.
1363
+ const pinned = await handleCohereTwinRequest({ method: 'POST', path: '/v1/datasets?name=clock-c&type=embed-input', body: JSON.stringify({ content: 'x' }), root, occurredAt: PINNED_AT });
1364
+ const rowC = await read(pinned);
1365
+ return rowC.dataset?.created_at === PINNED_AT;
1366
+ } finally {
1367
+ rmSync(root, { recursive: true, force: true });
1368
+ }
1369
+ });
1370
+ }),
1371
+ done('cohere.determinism.stream_matches_unary', 'determinism', 'the streamed and unary answers to the same request agree exactly', 'api', 'common', () =>
1372
+ withStream('/v2/chat', CHAT({ stream: true, tools: [TOOL] }), (events, final) => {
1373
+ const end = events.find((e) => e.data?.type === 'message-end')?.data as Body | undefined;
1374
+ const start = events.find((e) => e.data?.type === 'message-start')?.data as Body | undefined;
1375
+ const f = final.body as Body;
1376
+ // Ids and usage must be the SAME object the unary path would have produced — a separate
1377
+ // generation for the stream would show up here.
1378
+ return start?.id === f.id && end?.id === f.id
1379
+ && JSON.stringify(end?.delta?.usage) === JSON.stringify(f.usage)
1380
+ && end?.delta?.finish_reason === f.finish_reason;
1381
+ }),
1382
+ ),
1383
+
1384
+ // ══ CONNECTOR (the twin's pull/push plane) ════════════════════════════════════════════
1385
+ done('cohere.connector.pull_all_collections', 'connector', 'Connector: pull folds datasets + connectors + embed jobs into the projection', 'connector', 'core', () =>
1386
+ withConnector(async (execute, calls, root) => {
1387
+ const res = await syncCohereFromReal(execute, { root, occurredAt: PINNED_AT });
1388
+ if (res.observed !== 3 || res.deltasAppended !== 3) return false;
1389
+ // Every modeled collection is actually fetched — a pull that quietly skipped one would still
1390
+ // report a plausible count without this.
1391
+ if (calls.map((c) => `${c.method} ${c.path}`).sort().join('|') !== 'GET /v1/connectors|GET /v1/datasets|GET /v1/embed-jobs') return false;
1392
+ // …and the pulled rows are SERVABLE through the twin's own read paths under the VENDOR's ids.
1393
+ const ds = await handleCohereTwinRequest({ method: 'GET', path: '/v1/datasets/ds-real-1', root });
1394
+ const conn = await handleCohereTwinRequest({ method: 'GET', path: '/v1/connectors/conn-real-1', root });
1395
+ const job = await handleCohereTwinRequest({ method: 'GET', path: '/v1/embed-jobs/job-real-1', root });
1396
+ return (ds.body as Body).dataset?.name === 'real-dataset'
1397
+ && (conn.body as Body).connector?.auth_type === 'oauth'
1398
+ && (job.body as Body).job_id === 'job-real-1' && (job.body as Body).input_dataset_id === 'ds-real-1';
1399
+ }),
1400
+ ),
1401
+ done('cohere.connector.pull_idempotent', 'connector', 'Connector: re-pulling identical state appends NOTHING (shadow-diff)', 'connector', 'core', () =>
1402
+ withConnector(async (execute, _calls, root) => {
1403
+ const first = await syncCohereFromReal(execute, { root, occurredAt: PINNED_AT });
1404
+ const second = await syncCohereFromReal(execute, { root, occurredAt: '2026-08-31T13:00:00.000Z' });
1405
+ if (first.deltasAppended !== 3 || second.deltasAppended !== 0 || second.observed !== 3) return false;
1406
+ // The projection still serves exactly one row per collection — a re-pull that duplicated
1407
+ // would show up here rather than in the delta count.
1408
+ const list = await handleCohereTwinRequest({ method: 'GET', path: '/v1/datasets', root });
1409
+ return ((list.body as Body).datasets as Body[]).length === 1;
1410
+ }),
1411
+ ),
1412
+ done('cohere.connector.pull_refuses_error_envelope', 'connector', "Connector: a REFUSED pull throws — it is never an empty account", 'connector', 'core', () => {
1413
+ const root = mkdtempSync(join(tmpdir(), 'cohere-refuse-'));
1414
+ return verifyBoundary('cohere.pull_refuses', async () => {
1415
+ try {
1416
+ // Each executor is built INLINE rather than through `withConnector`, because the outcome
1417
+ // under test is a THROW: `verifyBoundary` converts a non-infrastructure throw into a
1418
+ // `false`, so a nested helper would swallow the very rejection being asserted.
1419
+ const executorFor = (reply: (m: string, p: string) => unknown): CohereExecute =>
1420
+ async (method, path) => reply(method, path);
1421
+
1422
+ // 1. Cohere answers a failure with its bare `{message}` envelope. Mapping that to "no
1423
+ // resources" would fold an EMPTY account over real observed state and delete the mirror.
1424
+ let refusalMsg = '';
1425
+ try {
1426
+ await syncCohereFromReal(executorFor(() => ({ message: 'rate limited' })), { root, occurredAt: PINNED_AT });
1427
+ } catch (e) { refusalMsg = (e as Error).message; }
1428
+ if (!refusalMsg.includes('pull /v1/datasets failed') || !refusalMsg.includes('rate limited')) return false;
1429
+
1430
+ // 2. An UNRECOGNIZED envelope (no error, but no collection key either) is also a throw,
1431
+ // not a zero-row pull — "I do not understand this response" is not "the account is
1432
+ // empty", and only the throw keeps the two apart.
1433
+ let unknownMsg = '';
1434
+ try {
1435
+ await syncCohereFromReal(executorFor(() => ({ unexpected: [] })), { root, occurredAt: PINNED_AT });
1436
+ } catch (e) { unknownMsg = (e as Error).message; }
1437
+ if (!unknownMsg.includes('no "datasets" key')) return false;
1438
+
1439
+ // 3. …but an EXPLICIT `null` genuinely means empty ON THE COLLECTIONS WHOSE SCHEMA SAYS SO,
1440
+ // and must NOT throw. Without this half the check would pass on a connector that threw
1441
+ // on everything. Nullability is read PER COLLECTION from the vendor's own serializers:
1442
+ // `DatasetsListResponse.datasets` and `ListEmbedJobResponse.embed_jobs` are
1443
+ // `?: Raw[] | null`, so null means empty there.
1444
+ const empty = await syncCohereFromReal(
1445
+ executorFor((m, p) => (m === 'GET' && p === '/v1/datasets' ? { datasets: null } : m === 'GET' && p === '/v1/connectors' ? { connectors: [], total_count: 0 } : { embed_jobs: null })),
1446
+ { root, occurredAt: PINNED_AT },
1447
+ );
1448
+ if (empty.observed !== 0 || empty.deltasAppended !== 0) return false;
1449
+
1450
+ // 3b. …and `ListConnectorsResponse.connectors` is declared REQUIRED and NON-nullable, so a
1451
+ // null THERE is a response the vendor says cannot occur. Treating it as an empty
1452
+ // account would fold an empty list over real observed connector state — the exact
1453
+ // hazard this whole check exists to close, admitted through a door that an earlier
1454
+ // version justified with a premise that was false for this one collection
1455
+ // (§9 round 1, connector m1).
1456
+ let nullConnMsg = '';
1457
+ try {
1458
+ await syncCohereFromReal(executorFor((m, p) => (m === 'GET' && p === '/v1/datasets' ? { datasets: [] } : m === 'GET' && p === '/v1/connectors' ? { connectors: null } : { embed_jobs: [] })), { root, occurredAt: PINNED_AT });
1459
+ } catch (e) { nullConnMsg = (e as Error).message; }
1460
+ if (!nullConnMsg.includes('required and non-nullable')) return false;
1461
+
1462
+ // 4. And a NON-list under the key is a throw too, not a coerced empty.
1463
+ let badListMsg = '';
1464
+ try {
1465
+ await syncCohereFromReal(executorFor(() => ({ datasets: 'nope' })), { root, occurredAt: PINNED_AT });
1466
+ } catch (e) { badListMsg = (e as Error).message; }
1467
+ return badListMsg.includes('is not a list');
1468
+ } finally {
1469
+ rmSync(root, { recursive: true, force: true });
1470
+ }
1471
+ });
1472
+ }),
1473
+ done('cohere.connector.map_shapes', 'connector', 'Connector: the mappers carry every REQUIRED vendor field, and key embed jobs on `job_id`', 'connector', 'core', () =>
1474
+ verifyBoundary('cohere.map_shapes', async () => {
1475
+ const d = mapDataset(REAL_DATASET);
1476
+ const c = mapConnector(REAL_CONNECTOR);
1477
+ const j = mapEmbedJob(REAL_EMBED_JOB);
1478
+ if (d.type !== 'dataset' || d.id !== 'ds-real-1') return false;
1479
+ // Every key the vendor's `Dataset` schema declares REQUIRED — a pulled row missing one is
1480
+ // unparseable by the official SDK the moment the twin serves it back.
1481
+ for (const k of ['name', 'created_at', 'updated_at', 'dataset_type', 'validation_status']) {
1482
+ if (d.fields[k] === undefined || d.fields[k] === null) return false;
1483
+ }
1484
+ if (c.type !== 'connector' || c.id !== 'conn-real-1' || c.fields.auth_type !== 'oauth') return false;
1485
+ for (const k of ['name', 'url', 'created_at', 'updated_at']) if (c.fields[k] === undefined || c.fields[k] === null) return false;
1486
+ // THE EMBED-JOB TRAP: the vendor's schema has NO `id` — subjecting on `.id` would land every
1487
+ // pulled job under the string "undefined" and collapse the collection onto one row.
1488
+ if (j.type !== 'embed_job' || j.id !== 'job-real-1' || j.fields.job_id !== 'job-real-1') return false;
1489
+ // A row with `updated_at` MISSING must fall back rather than emit null: both vendor schemas
1490
+ // declare it required-without-default.
1491
+ const noUpdated = mapDataset({ ...REAL_DATASET, updated_at: undefined });
1492
+ return noUpdated.fields.updated_at === REAL_DATASET.created_at;
1493
+ }),
1494
+ ),
1495
+ done('cohere.connector.push_create_uses_vendor_id', 'connector', 'Connector: push confirms under the VENDOR-minted id, per-type envelope', 'connector', 'core', () =>
1496
+ withConnector(async (execute, calls, root) => {
1497
+ const created = await handleCohereTwinRequest({ method: 'POST', path: '/v1/connectors', body: JSON.stringify({ name: 'local', url: 'https://e.test/s' }), root, occurredAt: PINNED_AT });
1498
+ const localId = (created.body as Body).connector.id as string;
1499
+ const push = await pushPendingCohereActions(execute, { root, occurredAt: PINNED_AT });
1500
+ if (push.pushed !== 1) return false;
1501
+ // The create envelope is NESTED (`{connector:{id}}`) — a generic `res.id` read would fall
1502
+ // back to the local id here and silently serve one account row as two after the next pull.
1503
+ const external = Object.values(push.externalIds)[0];
1504
+ if (external !== 'conn-vendor-minted' || external === localId) return false;
1505
+ if (calls[0]!.method !== 'POST' || calls[0]!.path !== '/v1/connectors') return false;
1506
+ // The payload is the vendor's CREATE schema — derived fields the endpoint does not accept
1507
+ // must not be replayed.
1508
+ if (calls[0]!.body!.name !== 'local' || calls[0]!.body!.auth_type !== undefined || calls[0]!.body!.auth_status !== undefined) return false;
1509
+ // The row now lives under the VENDOR's id, and the superseded local id is tombstoned so the
1510
+ // next mint can never re-issue it.
1511
+ const atVendor = await handleCohereTwinRequest({ method: 'GET', path: '/v1/connectors/conn-vendor-minted', root });
1512
+ const atLocal = await handleCohereTwinRequest({ method: 'GET', path: `/v1/connectors/${localId}`, root });
1513
+ const list = await handleCohereTwinRequest({ method: 'GET', path: '/v1/connectors', root });
1514
+ if (!ok(atVendor) || atLocal.status !== 404 || (list.body as Body).total_count !== 1) return false;
1515
+ // A 404 is equally true of a row that is simply ABSENT, which is what projection suppression
1516
+ // alone produces — so the 404 cannot distinguish "tombstoned" from "gone", and tombstoned is
1517
+ // the whole property (§9 round 1, m4).
1518
+ //
1519
+ // The check that CAN tell them apart reads the PROJECTION, where a tombstone is visible and an
1520
+ // absence is not — and asserts the SUPERSEDE LINK, which is the tombstone's actual value:
1521
+ // an auditable record that this local id became that vendor id. (The revert matrix is what
1522
+ // forced this to be honest: a first attempt asserted that the next mint does not re-issue
1523
+ // `localId`, and its cell stayed GREEN — because `nextId`'s ordinal only ever moves UPWARD
1524
+ // from the row-set size, so the superseded id is not a candidate either way. That claim was
1525
+ // over-stated; this one is the property the tombstone genuinely carries.)
1526
+ const rows = projectResources('cohere', root).filter((r) => r.type === 'connector');
1527
+ const tomb = rows.find((r) => r.id === localId);
1528
+ if (tomb === undefined) return false; // suppressed, not tombstoned
1529
+ if (tomb._deleted !== true) return false; // present but not marked dead
1530
+ if (tomb._superseded_by !== 'conn-vendor-minted') return false; // no provenance link
1531
+ // …and the tombstone is genuinely invisible to every READ path, not just to the id lookup.
1532
+ const listed = ((list.body as Body).connectors as Body[]).map((c) => c.id);
1533
+ return !listed.includes(localId) && listed.includes('conn-vendor-minted');
1534
+ }),
1535
+ ),
1536
+ done('cohere.connector.push_embed_job_key', 'connector', "Connector: an embed-job push reads the vendor id from `job_id`, and renames the dataset FK to the write shape", 'connector', 'core', () =>
1537
+ withConnector(async (execute, calls, root) => {
1538
+ // The dataset is PULLED, so it is vendor-known under its own id. (An earlier version created
1539
+ // it locally and asserted the twin-minted id went out in `dataset_id` — §9 round two found it
1540
+ // was pinning the bug rather than the behaviour.)
1541
+ await syncCohereFromReal(execute, { root, occurredAt: PINNED_AT });
1542
+ await handleCohereTwinRequest({ method: 'POST', path: '/v1/embed-jobs', body: JSON.stringify({ model: 'embed-english-v3.0', dataset_id: 'ds-real-1', input_type: 'search_document' }), root, occurredAt: PINNED_AT });
1543
+ const push = await pushPendingCohereActions(execute, { root, occurredAt: PINNED_AT });
1544
+ if (push.pushed !== 1 || push.refused.length !== 0) return false;
1545
+ if (Object.values(push.externalIds)[0] !== 'job-vendor-minted') return false;
1546
+ const jobCall = calls.find((c) => c.method === 'POST' && c.path === '/v1/embed-jobs')!;
1547
+ // The CREATE schema's field is `dataset_id`; the READ schema's is `input_dataset_id`. A
1548
+ // connector replaying the stored read-shape would send a field the endpoint does not declare.
1549
+ return jobCall.body!.dataset_id === 'ds-real-1' && jobCall.body!.input_dataset_id === undefined
1550
+ && jobCall.body!.input_type === 'search_document';
1551
+ }),
1552
+ ),
1553
+ done('cohere.connector.push_refuses_twin_minted_foreign_key', 'connector', 'Connector: a payload that REFERENCES a twin-minted id is refused, not posted', 'connector', 'core', () =>
1554
+ withConnector(async (execute, calls, root) => {
1555
+ // §9 round two, MAJOR. The identity guard covers `subject.id` — and a FOREIGN KEY carries an
1556
+ // id just as capably. `dataset.create` is an un-pushable multipart gap, so a locally created
1557
+ // dataset is PERMANENTLY vendor-unknown; the embed-job create copied its `input_dataset_id`
1558
+ // straight into the vendor's `dataset_id`, so `{"dataset_id":"<twin-uuid>"}` went to the REAL
1559
+ // account, where Cohere rejects the unknown dataset and the batch wedges exactly as B1 did.
1560
+ const ds = await handleCohereTwinRequest({ method: 'POST', path: '/v1/datasets?name=local&type=embed-input', body: JSON.stringify(DATA_FILE), root, occurredAt: PINNED_AT });
1561
+ const dsId = (ds.body as Body).id as string;
1562
+ await handleCohereTwinRequest({ method: 'POST', path: '/v1/embed-jobs', body: JSON.stringify({ model: 'embed-english-v3.0', dataset_id: dsId, input_type: 'search_document' }), root, occurredAt: PINNED_AT });
1563
+ const push = await pushPendingCohereActions(execute, { root, occurredAt: PINNED_AT });
1564
+ // Both the dataset create (filed multipart gap) and the embed job (twin-minted FK) refuse.
1565
+ if (push.pushed !== 0 || push.refused.length !== 2) return false;
1566
+ const fk = push.refused.find((r) => r.operation === 'embed_job.create');
1567
+ if (!fk || !fk.reason.includes(`references dataset '${dsId}'`)) return false;
1568
+ // NOT ONE REQUEST went out, and the twin-minted id appears nowhere — not in a path, and not
1569
+ // in a BODY, which is the half a path-only assertion cannot see.
1570
+ if (calls.length !== 0) return false;
1571
+ return !JSON.stringify(calls).includes(dsId);
1572
+ }),
1573
+ ),
1574
+ done('cohere.connector.push_refuses_idless_create_response', 'connector', 'Connector: a create response with NO vendor id is an error — never confirmed under the twin\'s own id', 'connector', 'core', () =>
1575
+ withConnector(async (execute, calls, root) => {
1576
+ // §9 round two, m-R2.1. Falling back to the local id would MANUFACTURE a vendor identity:
1577
+ // no supersede tombstone is written, so `vendorIdentity` would afterwards report that id as
1578
+ // vendor-known and every later mutation would push the twin's own UUID at the real account —
1579
+ // re-opening the BLOCKER through a side door.
1580
+ await handleCohereTwinRequest({ method: 'POST', path: '/v1/connectors', body: JSON.stringify({ name: 'x', url: 'https://e.test/s' }), root, occurredAt: PINNED_AT });
1581
+ let msg = '';
1582
+ try {
1583
+ await pushPendingCohereActions(execute, { root, occurredAt: PINNED_AT });
1584
+ } catch (e) { msg = (e as Error).message; }
1585
+ if (!msg.includes('carried no vendor id') || !msg.includes("refusing to confirm under the twin's own id")) return false;
1586
+ // The malformed create WAS sent (this is a response-shape failure, not a refusal to call)…
1587
+ if (calls.length !== 1) return false;
1588
+ // …and nothing was confirmed, so the action is still pending rather than silently "done".
1589
+ const { pendingActions } = await import('@volter/world-core');
1590
+ return pendingActions('cohere', root).length === 1;
1591
+ }, (m, p) => (m === 'POST' && p === '/v1/connectors' ? { connector: { name: 'x' } } : {})),
1592
+ ),
1593
+ done('cohere.connector.push_refuses_unknown_op', 'connector', 'Connector: an operation nobody reasoned about STOPS the run (never a silent skip)', 'connector', 'core', () =>
1594
+ withConnector(async (execute) => {
1595
+ const { pushCohereAction } = await import('./cohere-connector.ts');
1596
+ let msg = '';
1597
+ try {
1598
+ await pushCohereAction(execute, { operation: 'connector.archive', subject: { type: 'connector', id: 'c1' }, fields: {} } as never);
1599
+ } catch (e) { msg = (e as Error).message; }
1600
+ // The SPECIFIC refusal, not merely "something threw" — a dead connector seam's own throw
1601
+ // would otherwise read as a pass and the capability would survive sabotage.
1602
+ if (!msg.includes("unsupported operation 'connector.archive'") || !msg.includes('refusing to silently drop')) return false;
1603
+ // A FILED gap answers with ITS OWN reason instead of the generic one, so a caller can tell a
1604
+ // thought-about gap from a hole nobody has looked at.
1605
+ let filed = '';
1606
+ try {
1607
+ await pushCohereAction(execute, { operation: 'dataset.create', subject: { type: 'dataset', id: 'd1' }, fields: {} } as never);
1608
+ } catch (e) { filed = (e as Error).message; }
1609
+ return filed.includes('cannot faithfully push') && filed.includes('multipart/form-data');
1610
+ }),
1611
+ ),
1612
+ done('cohere.connector.token_type_unpushable', 'connector', 'Connector: the tokenizer vocabulary is refused push-wide, by TYPE not by verb', 'connector', 'core', () =>
1613
+ withConnector(async (execute, calls, root) => {
1614
+ // Tokenize writes `token.observe` rows. A verb-keyed refusal would let a hypothetical
1615
+ // `token.delete` through, and the `/v1/${type}s` fallback would then fire `DELETE
1616
+ // /v1/tokens/<id>` — an endpoint Cohere does not have — at a REAL account.
1617
+ await handleCohereTwinRequest({ method: 'POST', path: '/v1/tokenize', body: JSON.stringify({ text: 'push me', model: 'command-a-03-2025' }), root, occurredAt: PINNED_AT });
1618
+ const push = await pushPendingCohereActions(execute, { root, occurredAt: PINNED_AT });
1619
+ if (push.pushed !== 0 || push.refused.length === 0) return false;
1620
+ if (!push.refused.every((r) => r.reason.includes('no vendor endpoint'))) return false;
1621
+ // NOT ONE REQUEST went out. "It refused" is not proof; the count is what shows nothing
1622
+ // reached the vendor.
1623
+ if (calls.length !== 0) return false;
1624
+ // …and the type-wide rule holds for a verb that IS otherwise pushable.
1625
+ return unpushableReason('token.delete', 'token') !== undefined && unpushableReason('token.create', 'token') !== undefined;
1626
+ }),
1627
+ ),
1628
+ done('cohere.connector.push_request_shape', 'connector', 'Connector: the REST (method, path) for each pushable verb is the vendor\'s', 'connector', 'common', () =>
1629
+ verifyBoundary('cohere.request_shape', async () => {
1630
+ const at = (operation: string, type: string, id: string) => cohereRequestForAction({ operation, subject: { type, id } } as never);
1631
+ const create = at('connector.create', 'connector', 'c1');
1632
+ const update = at('connector.update', 'connector', 'c1');
1633
+ const del = at('dataset.delete', 'dataset', 'd1');
1634
+ const cancel = at('embed_job.cancel', 'embed_job', 'j1');
1635
+ return create.method === 'POST' && create.path === '/v1/connectors'
1636
+ && update.method === 'PATCH' && update.path === '/v1/connectors/c1'
1637
+ && del.method === 'DELETE' && del.path === '/v1/datasets/d1'
1638
+ && cancel.method === 'POST' && cancel.path === '/v1/embed-jobs/j1/cancel';
1639
+ }),
1640
+ ),
1641
+ done('cohere.connector.full_sync_converges', 'connector', 'Connector: push→pull converges — a second full sync is a total no-op', 'connector', 'core', () =>
1642
+ withConnector(async (execute, _calls, root) => {
1643
+ await handleCohereTwinRequest({ method: 'POST', path: '/v1/connectors', body: JSON.stringify({ name: 'local', url: 'https://e.test/s' }), root, occurredAt: PINNED_AT });
1644
+ const first = await fullSyncCohere(execute, { root, occurredAt: PINNED_AT });
1645
+ if (first.pushed !== 1 || first.collections !== 3) return false;
1646
+ const second = await fullSyncCohere(execute, { root, occurredAt: '2026-08-31T14:00:00.000Z' });
1647
+ // Nothing pending and identical real state ⇒ a complete no-op. A push that did not confirm,
1648
+ // or a pull that double-counted, both show up right here.
1649
+ if (second.pushed !== 0 || second.deltasAppended !== 0) return false;
1650
+ const list = await handleCohereTwinRequest({ method: 'GET', path: '/v1/connectors', root });
1651
+ // ONE row, not two: the locally-created connector and the pulled vendor row are the same
1652
+ // account object and must not both be served.
1653
+ return (list.body as Body).total_count === 1 && (list.body as Body).connectors[0].id === 'conn-real-1';
1654
+ }, (m, p) => (m === 'GET' && p === '/v1/datasets' ? { datasets: [] } : m === 'GET' && p === '/v1/connectors' ? { connectors: [REAL_CONNECTOR], total_count: 1 } : m === 'GET' ? { embed_jobs: [] } : m === 'POST' && p === '/v1/connectors' ? { connector: REAL_CONNECTOR } : {})),
1655
+ ),
1656
+ done('cohere.connector.pull_timestamp_moves', 'connector', 'Connector: the default poll timestamp MOVES (a pinned one hides reverting values)', 'connector', 'common', () =>
1657
+ verifyBoundary('cohere.poll_timestamp', async () => {
1658
+ const a = pollTimestamp();
1659
+ const b = pollTimestamp();
1660
+ const c = pollTimestamp();
1661
+ // Strictly increasing WITHIN the process, even when the wall clock has not ticked: the
1662
+ // kernel hashes an observed event over (occurredAt + post-state), so under a fixed poll time
1663
+ // a vendor value that reverts A→B→A collides with its own earlier observation and syncPull
1664
+ // reports a phantom delta while the projection keeps serving the stale value.
1665
+ return a < b && b < c;
1666
+ }),
1667
+ ),
1668
+ done('cohere.connector.budget_refuses_before_calling', 'connector', 'Budget: the ceiling THROWS instead of calling, with the fake\'s count unchanged', 'connector', 'core', () =>
1669
+ verifyBoundary('cohere.budget_ceiling', async () => {
1670
+ const ledger = join(mkdtempSync(join(tmpdir(), 'cohere-budget-')), 'ledger.json');
1671
+ let calls = 0;
1672
+ const fetchImpl = (async () => { calls++; return new Response('{}', { status: 200, headers: { 'content-type': 'application/json' } }); }) as unknown as typeof fetch;
1673
+ // The ledger path is INJECTED: a suite that spent against the operator's real
1674
+ // ~/.volter/cohere file would poison every later run on this machine.
1675
+ const budget = new CohereBudget({ path: ledger, now: () => 1_800_000_000_000 });
1676
+ const execute = liveCohereExecute('k', 'https://api.cohere.com', { fetchImpl, budget });
1677
+ // Ceiling 20 at the tokenize weight of 1 ⇒ exactly 20 calls fit.
1678
+ for (let i = 0; i < 20; i++) await execute('POST', '/v1/tokenize', {});
1679
+ if (calls !== 20) return false;
1680
+ let threw = false;
1681
+ try { await execute('POST', '/v1/tokenize', {}); } catch (e) { threw = e instanceof CohereBudgetError; }
1682
+ // "It threw" is NOT the proof. The COUNT is what shows nothing reached the vendor.
1683
+ return threw && calls === 20;
1684
+ }),
1685
+ ),
1686
+ done('cohere.connector.budget_prices_by_endpoint', 'connector', "Budget: weights reproduce Cohere's own per-endpoint scarcity", 'connector', 'core', () =>
1687
+ verifyBoundary('cohere.budget_weights', async () => {
1688
+ // The published per-minute allowances (trial key) that these weights encode:
1689
+ // embed-jobs 5, rerank 10, chat 20, tokenize 100 — so the prices must be strictly ordered
1690
+ // the other way round.
1691
+ const embedJob = cohereCallWeight('POST', '/v1/embed-jobs');
1692
+ const rerank = cohereCallWeight('POST', '/v2/rerank');
1693
+ const chat = cohereCallWeight('POST', '/v2/chat');
1694
+ const tokenize = cohereCallWeight('POST', '/v1/tokenize');
1695
+ if (!(embedJob > rerank && rerank > chat && chat > tokenize)) return false;
1696
+ // An UNCLASSIFIED endpoint is never free — it costs the default.
1697
+ if (cohereCallWeight('POST', '/v1/anything-else') !== chat) return false;
1698
+ // NORMALIZATION: a lower-case method and a trailing slash are input variations, not attacks,
1699
+ // and either would otherwise slip an expensive call past an anchored rule at the read price.
1700
+ return cohereCallWeight('post', '/v1/embed-jobs') === embedJob
1701
+ && cohereCallWeight('POST', '/v1/embed-jobs/') === embedJob
1702
+ && cohereCallWeight('POST', '/v1/embed-jobs?x=1') === embedJob
1703
+ // …and a LONGER path must not borrow the anchored rule's price.
1704
+ && cohereCallWeight('POST', '/v1/embed-jobs/j1/cancel') === chat;
1705
+ }),
1706
+ ),
1707
+ done('cohere.connector.budget_guard_cannot_be_swapped', 'connector', 'Budget: a duck-typed / subclassed / proxied budget is REFUSED at construction', 'connector', 'core', () =>
1708
+ verifyBoundary('cohere.budget_guard', async () => {
1709
+ const fetchImpl = (async () => new Response('{}', { status: 200 })) as unknown as typeof fetch;
1710
+ const refuses = (budget: unknown) => {
1711
+ try { liveCohereExecute('k', 'https://api.cohere.com', { fetchImpl, budget: budget as CohereBudget }); return false; } catch { return true; }
1712
+ };
1713
+ const duck = { checkBudget: () => ({}), recordCall: () => {} };
1714
+ class Loose extends CohereBudget { override checkBudget(): never { return undefined as never; } }
1715
+ const proxied = new Proxy(new CohereBudget({ path: join(mkdtempSync(join(tmpdir(), 'cb-')), 'l.json') }), { get: (t, k) => (k === 'checkBudget' ? () => ({}) : Reflect.get(t, k)) });
1716
+ // Each is a one-liner that would otherwise hand back a client with NO ceiling.
1717
+ if (!refuses(duck) || !refuses(new Loose({ path: join(mkdtempSync(join(tmpdir(), 'cb-')), 'l.json') })) || !refuses(proxied)) return false;
1718
+ // …and an UNMODIFIED budget is still accepted, so the guard is not simply refusing
1719
+ // everything.
1720
+ const real = new CohereBudget({ path: join(mkdtempSync(join(tmpdir(), 'cb-')), 'l.json') });
1721
+ return typeof liveCohereExecute('k', 'https://api.cohere.com', { fetchImpl, budget: real }) === 'function';
1722
+ }),
1723
+ ),
1724
+ done('cohere.connector.push_remaps_to_vendor_id', 'connector', 'Connector: a create-then-UPDATE push addresses the VENDOR id, never the twin-minted one', 'connector', 'core', () =>
1725
+ withConnector(async (execute, calls, root) => {
1726
+ // §9 round 1 BLOCKER. Create locally, PATCH locally, push once. The create confirms under the
1727
+ // vendor's id — but the QUEUED update still carries the twin-minted id, and the twin's ids are
1728
+ // UUID-SHAPED, so `PATCH /v1/connectors/<twin-uuid>` fired at the REAL account is
1729
+ // indistinguishable from a legitimate request in an operator's logs. Real Cohere 404s, the
1730
+ // batch aborts mid-run, and the update stays PENDING — so every later push re-issues the same
1731
+ // doomed request forever.
1732
+ const created = await handleCohereTwinRequest({ method: 'POST', path: '/v1/connectors', body: JSON.stringify({ name: 'local', url: 'https://e.test/s' }), root, occurredAt: PINNED_AT });
1733
+ const localId = (created.body as Body).connector.id as string;
1734
+ await handleCohereTwinRequest({ method: 'PATCH', path: `/v1/connectors/${localId}`, body: JSON.stringify({ name: 'renamed' }), root, occurredAt: PINNED_AT });
1735
+ const push = await pushPendingCohereActions(execute, { root, occurredAt: PINNED_AT });
1736
+ if (push.pushed !== 2 || push.refused.length !== 0) return false;
1737
+ const paths = calls.map((c) => `${c.method} ${c.path}`);
1738
+ // THE ASSERTION: the PATCH went to the vendor's id.
1739
+ if (paths[0] !== 'POST /v1/connectors' || paths[1] !== 'PATCH /v1/connectors/conn-vendor-minted') return false;
1740
+ // …and the twin-minted id was NEVER put on the wire, in any request.
1741
+ if (calls.some((c) => c.path.includes(localId))) return false;
1742
+ // The PATCH payload is the vendor's UPDATE schema — the twin's own bookkeeping never rides.
1743
+ const patch = calls[1]!.body!;
1744
+ return patch.name === 'renamed' && patch._twin_minted === undefined && patch._rev === undefined && patch.auth_status === undefined;
1745
+ }),
1746
+ ),
1747
+ done('cohere.connector.push_identity_survives_an_aborted_batch', 'connector', 'Connector: the vendor-id mapping is DURABLE — a second push after an abort still addresses the vendor', 'connector', 'core', () =>
1748
+ withConnector(async (execute, calls, root) => {
1749
+ // §9 ROUND TWO, BLOCKER — the two round-one fixes destroying each other. `confirmAction`
1750
+ // suppresses the confirmed create's projection, and the supersede tombstone carries only
1751
+ // `{_deleted,_superseded_by}` — so `_twin_minted` VANISHES with the create it lived on. The
1752
+ // in-loop map was then the only guard, and it dies with the batch:
1753
+ // push #1 confirms the create, the PATCH throws (a budget refusal, a retry-after past the
1754
+ // cap, a network blip, any vendor `{message}`) → the batch aborts, the PATCH stays pending
1755
+ // → push #2 has an EMPTY map and a marker-less tombstone → the twin's own UUID goes to the
1756
+ // real account, every run, forever.
1757
+ // Neither the B1 capability nor its revert-matrix cell could see this: both are single-batch.
1758
+ const created = await handleCohereTwinRequest({ method: 'POST', path: '/v1/connectors', body: JSON.stringify({ name: 'local', url: 'https://e.test/s' }), root, occurredAt: PINNED_AT });
1759
+ const localId = (created.body as Body).connector.id as string;
1760
+ await handleCohereTwinRequest({ method: 'PATCH', path: `/v1/connectors/${localId}`, body: JSON.stringify({ name: 'renamed' }), root, occurredAt: PINNED_AT });
1761
+
1762
+ // PUSH #1 — the create succeeds, then the PATCH throws, aborting the batch mid-run.
1763
+ let aborted = false;
1764
+ const failingOnPatch: CohereExecute = async (method, path, body) => {
1765
+ if (method === 'PATCH') throw new Error('simulated mid-batch failure');
1766
+ return execute(method, path, body);
1767
+ };
1768
+ try {
1769
+ await pushPendingCohereActions(failingOnPatch, { root, occurredAt: PINNED_AT });
1770
+ } catch { aborted = true; }
1771
+ if (!aborted) return false;
1772
+ // The create really did land, and the update really is still pending.
1773
+ const afterFirst = calls.filter((c) => c.method === 'POST' && c.path === '/v1/connectors');
1774
+ if (afterFirst.length !== 1) return false;
1775
+
1776
+ // PUSH #2 — a FRESH call, so the in-memory map is empty. The durable supersede tombstone is
1777
+ // the only thing that can resolve the identity now.
1778
+ calls.length = 0;
1779
+ const second = await pushPendingCohereActions(execute, { root, occurredAt: PINNED_AT });
1780
+ if (second.pushed !== 1 || second.refused.length !== 0) return false;
1781
+ // THE ASSERTION: the vendor's id, and the twin-minted id NOWHERE on the wire.
1782
+ if (calls.length !== 1 || calls[0]!.path !== '/v1/connectors/conn-vendor-minted') return false;
1783
+ return !JSON.stringify(calls).includes(localId);
1784
+ }),
1785
+ ),
1786
+ done('cohere.connector.push_refuses_subject_with_no_vendor_id', 'connector', 'Connector: an action on a subject the vendor has never seen is REFUSED, not fired at the account', 'connector', 'core', () =>
1787
+ withConnector(async (execute, calls, root) => {
1788
+ // §9 round 1 MAJOR, and the sharpest "what did the fix make newly REACHABLE" case in the pack.
1789
+ // `dataset.create` is a FILED multipart gap, so it is skipped rather than aborting the run —
1790
+ // and skipping it is precisely what made the following delete reachable:
1791
+ // `DELETE /v1/datasets/<twin-minted-uuid>` went to the REAL account, addressing whatever (if
1792
+ // anything) happens to carry that id there. Aborting would have prevented it; the skip did not.
1793
+ const ds = await handleCohereTwinRequest({ method: 'POST', path: '/v1/datasets?name=doomed&type=embed-input', body: JSON.stringify(DATA_FILE), root, occurredAt: PINNED_AT });
1794
+ const dsId = (ds.body as Body).id as string;
1795
+ await handleCohereTwinRequest({ method: 'DELETE', path: `/v1/datasets/${dsId}`, root, occurredAt: PINNED_AT });
1796
+ const push = await pushPendingCohereActions(execute, { root, occurredAt: PINNED_AT });
1797
+ // BOTH are refused by name, and NOT ONE REQUEST went out. "It refused" is not the proof; the
1798
+ // call count is what shows nothing reached the vendor.
1799
+ if (push.pushed !== 0 || push.refused.length !== 2 || calls.length !== 0) return false;
1800
+ const del = push.refused.find((r) => r.operation === 'dataset.delete');
1801
+ if (!del || !del.reason.includes('minted by this twin') || del.subjectId !== dsId) return false;
1802
+ // …and the run does NOT abort: the filed create is still reported alongside it.
1803
+ if (!push.refused.some((r) => r.operation === 'dataset.create' && r.reason.includes('multipart'))) return false;
1804
+ // THE OTHER DIRECTION, so this is not just "the connector refuses deletes": a row that came
1805
+ // from a PULL is vendor-known under its own id, and a mutation on it pushes normally.
1806
+ await syncCohereFromReal(execute, { root, occurredAt: PINNED_AT });
1807
+ await handleCohereTwinRequest({ method: 'PATCH', path: '/v1/connectors/conn-real-1', body: JSON.stringify({ name: 'renamed' }), root, occurredAt: PINNED_AT });
1808
+ const second = await pushPendingCohereActions(execute, { root, occurredAt: PINNED_AT });
1809
+ return second.pushed === 1 && calls.some((c) => c.method === 'PATCH' && c.path === '/v1/connectors/conn-real-1');
1810
+ }),
1811
+ ),
1812
+ todo('cohere.connector.pull_finetuned_models', 'connector', 'Connector: pull finetuned models (needs the finetuning endpoints first)', 'connector', 'common'),
1813
+ todo('cohere.connector.pull_batches', 'connector', 'Connector: pull batch jobs (needs the /v2/batches endpoints first)', 'connector', 'common'),
1814
+ todo('cohere.connector.push_dataset_multipart', 'connector', 'Connector: push a dataset create as the multipart/form-data upload the endpoint requires', 'connector', 'common'),
1815
+ todo('cohere.connector.pull_dataset_parts', 'connector', 'Connector: pull a dataset\'s PARTS and validation errors, not just the dataset row', 'connector', 'niche'),
1816
+ todo('cohere.connector.push_connector_oauth', 'connector', 'Connector: push a connector\'s oauth/service_auth configuration on create', 'connector', 'common'),
1817
+
1818
+ // ══ CONFORMANCE ══════════════════════════════════════════════════════════════════════
1819
+ done('cohere.conformance.probes', 'conformance', 'Conformance: every claimed endpoint is probed for a live OUTCOME, not just a dispatch', 'api', 'core', async () =>
1820
+ verifyBoundary('cohere.conformance', async () => {
1821
+ const report = await checkCohereConformance();
1822
+ return report.ok && report.claimed === 27 && report.checksRun >= 58 && report.violations.length === 0;
1823
+ }),
1824
+ ),
1825
+ done('cohere.conformance.scenario_engine_is_the_kernel', 'conformance', 'Scenario scripting runs on THE kernel engine with a pack adapter (never a bespoke one)', 'api', 'common', () =>
1826
+ verifyBoundary('cohere.scenario_kernel', async () => {
1827
+ const engine = createCohereScenarioEngine();
1828
+ const remove = engine.use({ on: { userTextIncludes: 'refund' }, respond: { text: 'scripted refund reply' } });
1829
+ const root = mkdtempSync(join(tmpdir(), 'cohere-scn-'));
1830
+ try {
1831
+ const hit = await handleCohereTwinRequest({ method: 'POST', path: '/v2/chat', body: JSON.stringify(CHAT({ messages: [{ role: 'user', content: 'I need a refund' }] })), root, occurredAt: PINNED_AT, scenarioEngine: engine });
1832
+ const miss = await handleCohereTwinRequest({ method: 'POST', path: '/v2/chat', body: JSON.stringify(CHAT()), root, occurredAt: PINNED_AT, scenarioEngine: engine });
1833
+ remove();
1834
+ const after = await handleCohereTwinRequest({ method: 'POST', path: '/v2/chat', body: JSON.stringify(CHAT({ messages: [{ role: 'user', content: 'I need a refund' }] })), root, occurredAt: PINNED_AT, scenarioEngine: engine });
1835
+ const text = (r: CohereResponseEnvelope) => String((r.body as Body).message?.content?.[0]?.text ?? '');
1836
+ // The scripted turn fires; an unmatched one falls back to the labeled stub AND ledgers the
1837
+ // miss with its features; removing the handler restores the stub.
1838
+ const status = engine.status();
1839
+ return text(hit) === 'scripted refund reply'
1840
+ && text(miss).includes('[twin-stub:') && text(miss).includes('twin-scenario miss')
1841
+ && text(after).includes('[twin-stub:')
1842
+ && status.vendor === 'cohere'
1843
+ // Two misses: the unmatched request, and the refund request AFTER the handler was
1844
+ // removed. The handler row is gone from the status, and it fired exactly once.
1845
+ && status.misses === 2 && status.handlers.length === 0;
1846
+ } finally {
1847
+ rmSync(root, { recursive: true, force: true });
1848
+ }
1849
+ }),
1850
+ ),
1851
+ ];
1852
+
1853
+ export function cohereCapabilities(): Promise<CapabilityReport> {
1854
+ return checkCapabilities('cohere', COHERE_CAPABILITIES);
1855
+ }