Ctrl K
ComunidadGuías…

tests/sdk/sdk.test.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { fakeFetch } from "../helpers/fetch";
import { afterAll, beforeAll, test } from "bun:test";
import assert from "node:assert/strict";
import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { createSqliteDb, openDatabase } from "../../src/runtime/bun/sqlite";
import { serve } from "../../src/runtime/bun/server";
import { TITEN_SDK_TYPED_ROUTES, TitenClient, TitenError } from "../../src/sdk";
import { provisionWith } from "../contract/harness";

/**
 * The published client, driven against a real server over real HTTP.
 *
 * The contract suite proves the service; this proves the client agrees with it.
 * Every method here is one an integrator calls, so a renamed response field or a
 * changed path breaks this file rather than someone's agent.
 */
const directory = mkdtempSync(join(tmpdir(), "titen-sdk-"));
const dbPath = join(directory, "titen.db");

let running: Awaited<ReturnType<typeof serve>>;
let handle: ReturnType<typeof openDatabase>;
let titen: TitenClient;
let orgId: string;

beforeAll(async () => {
  running = await serve({
    dbPath,
    port: 0,
    hostname: "127.0.0.1",
    quiet: true,
    revision: "sdk-test",
  });
  handle = openDatabase(dbPath);
  const provisioned = await provisionWith(createSqliteDb(handle), { scopes: ["*"] });
  titen = new TitenClient({ url: running.url, key: provisioned.key });
  orgId = provisioned.orgId;
});

afterAll(async () => {
  handle.close();
  await running.stop();
  rmSync(directory, { recursive: true, force: true });
});

test("health and readiness resolve through the client", async () => {
  const health = await titen.health();
  assert.equal(health.status, "ok");
  const ready = await titen.ready();
  assert.equal(ready.ready, true);
  assert.equal(ready.capabilities.extraction_response_mode, "disabled");
  assert.equal(ready.checks.enrichment_jobs?.state, "disabled");
});

test("the client drives the whole Level 5 loop", async () => {
  const project = await titen.resolveProject("github.com/RamaAditya49/titen", true);
  assert.equal(project.reference, "ramaaditya49/titen");

  const observation = await titen.observe({
    subject_id: "user_sdk",
    project_id: project.project_id,
    kind: "tool_result",
    content: "Integration smoke returned 200 for the checkout rollback path.",
    source: { type: "tool", ref: "sdk#1" },
    trust: "verified",
  });
  assert.match(observation.observation_id, /^obs_/);

  const consolidated = await titen.consolidate(
    "user_sdk",
    [
      {
        kind: "procedural",
        statement: "Checkout rollback must be smoke tested before release.",
        confidence: 0.93,
        sources: [{ observation_id: observation.observation_id, relation: "supports" }],
      },
    ],
    project.project_id,
  );
  const claimId = consolidated.claims[0].claim_id as string;
  assert.match(claimId, /^claim_/);

  const context = await titen.compile({
    subject_id: "user_sdk",
    project_id: project.project_id,
    task: "checkout rollback smoke before release",
    max_tokens: 900,
  });
  assert.match(context.context_id, /^ctx_/);
  assert.ok(context.budget.used_tokens <= 900);
  assert.match(context.instructions, /untrusted reference data/i);
  const { as_of: asOf, ...scope } = context.scope;
  assert.match(asOf, /^\d{4}-\d{2}-\d{2}T/);
  assert.deepEqual(scope, {
    subject_id: "user_sdk",
    project_id: project.project_id,
    project_mode: "project",
    broad_access_reason: null,
  });
  const selected = context.items.find((item) => item.claim_id === claimId);
  assert.ok(selected, "the client must receive the claim it just wrote");

  const broad = await titen.compile({
    subject_id: "user_sdk",
    task: "checkout rollback smoke before release",
    max_tokens: 900,
    cross_project: true,
  });
  assert.equal(broad.scope.project_mode, "cross_project");
  assert.equal(broad.scope.broad_access_reason, "credential_scope:context:compile:all");
  assert.ok(broad.items.some((item) => item.claim_id === claimId));

  const feedback = await titen.feedback(context.context_id, {
    outcome: "useful",
    claim_id: claimId,
  });
  assert.equal(feedback.outcome, "useful");

  const evidence = await titen.evidence(claimId);
  assert.equal(evidence.evidence.supporting.length, 1);
  assert.equal(
    evidence.evidence.supporting[0].observation_id,
    observation.observation_id,
  );
});

test("checkpoints round-trip through the client", async () => {
  const saved = await titen.saveCheckpoint({
    subject_id: "user_sdk",
    kind: "task_state",
    state: { step: 2, pending: ["verify"] },
    ttl_seconds: 600,
  });
  assert.match(saved.checkpoint_id, /^ckpt_/);

  const loaded = await titen.getCheckpoint("user_sdk", "task_state");
  assert.deepEqual(loaded.state, { step: 2, pending: ["verify"] });

  const removed = await titen.deleteCheckpoint(saved.checkpoint_id);
  assert.equal(removed.deleted, true);
});

test("claim lifecycle calls resolve through the client", async () => {
  const observation = await titen.observe({
    subject_id: "user_sdk_lifecycle",
    kind: "user_statement",
    content: "The old retry budget was three attempts.",
    source: { type: "chat", ref: "contract://sdk" },
    trust: "verified",
  });
  const first = await titen.consolidate("user_sdk_lifecycle", [
    {
      kind: "procedural",
      statement: "Retry budget is three attempts.",
      sources: [{ observation_id: observation.observation_id, relation: "supports" }],
    },
  ]);
  const second = await titen.consolidate("user_sdk_lifecycle", [
    {
      kind: "procedural",
      statement: "Retry budget is two attempts, then escalate.",
      sources: [{ observation_id: observation.observation_id, relation: "supports" }],
    },
  ]);

  const superseded = await titen.supersede(
    first.claims[0].claim_id,
    second.claims[0].claim_id,
    1,
    "measured under load",
  );
  assert.equal(superseded.status, "superseded");

  const revoked = await titen.revoke(second.claims[0].claim_id, 1, "policy change");
  assert.equal(revoked.status, "revoked");
});

test("expire resolves through the client and a stale version is a typed conflict", async () => {
  const observation = await titen.observe({
    subject_id: "user_sdk_expire",
    kind: "user_statement",
    content: "The staging freeze ends on Friday.",
    source: { type: "chat", ref: "contract://sdk-expire" },
    trust: "verified",
  });
  const created = await titen.consolidate("user_sdk_expire", [
    { kind: "procedural", statement: "Staging is frozen until Friday.",
      sources: [{ observation_id: observation.observation_id, relation: "supports" }] },
  ]);
  const claimId = created.claims[0].claim_id;
  await assert.rejects(titen.expire(claimId, 7, "stale version"), (error: unknown) =>
    error instanceof TitenError && error.status === 409 && error.code === "CONFLICT");
  const expired = await titen.expire(claimId, 1, "freeze lifted");
  assert.equal(expired.claim_id, claimId);
  assert.equal(expired.status, "expired");
  assert.equal(typeof expired.valid_to, "string");
});

test("leases acquire, renew, conflict across principals, and release through the client", async () => {
  const lease = { resource_type: "subject", resource_id: "user_sdk_lease", purpose: "sdk round trip", ttl_seconds: 60 };
  const first = await titen.acquireLease(lease);
  assert.match(first.lease_id, /^lease_/);
  assert.equal(first.renewed, false);
  const renewed = await titen.acquireLease(lease);
  assert.equal(renewed.lease_id, first.lease_id);
  assert.equal(renewed.renewed, true);

  const other = await provisionWith(createSqliteDb(handle), { orgId, scopes: ["*"], principalId: "sdk_lease_rival" });
  const rival = new TitenClient({ url: running.url, key: other.key });
  await assert.rejects(rival.acquireLease(lease), (error: unknown) =>
    error instanceof TitenError && error.status === 409 && error.code === "CONFLICT");

  const released = await titen.releaseLease(first.lease_id);
  assert.equal(released.lease_id, first.lease_id);
  assert.equal(typeof released.released_at, "string");
  const taken = await rival.acquireLease(lease);
  assert.equal(taken.renewed, false);
});

test("compileView reaches the neighborhood and workspace_graph lenses without casts", async () => {
  const observation = await titen.observe({
    subject_id: "user_sdk_view",
    kind: "user_statement",
    content: "Deploys need a rollback plan.",
    source: { type: "chat", ref: "contract://sdk-view" },
    trust: "verified",
    visibility: "organization",
  });
  await titen.consolidate("user_sdk_view", [
    { kind: "procedural", statement: "Every deploy needs a rollback plan.",
      sources: [{ observation_id: observation.observation_id, relation: "supports" }] },
  ]);
  const neighborhood = await titen.compileView("neighborhood", { subject_id: "user_sdk_view" });
  assert.equal(neighborhood.lens, "neighborhood");
  assert.ok(neighborhood.nodes.some((node) => node.type === "claim"));
  const graph = await titen.compileView("workspace_graph", { workspace_id: null, max_nodes: 25 });
  assert.equal(graph.lens, "workspace_graph");
  assert.ok(Array.isArray(graph.nodes));
  assert.equal(graph.metadata.workspace_id, null);
  await assert.rejects(titen.compileView("workspace_graph", { max_nodes: 10 }), (error: unknown) =>
    error instanceof TitenError && error.status === 400);
});

test("key management round-trips and a scoped key is enforced", async () => {
  const created = await titen.createKey({
    label: "sdk-reader",
    scopes: ["context:compile", "handoffs:read", "handoffs:write"],
    max_trust: "asserted",
    principal_id: "agent_sdk_reader",
    principal_kind: "agent",
  });
  assert.match(created.api_key, /^titen_sk_/);
  assert.equal(created.principal_id, "agent_sdk_reader");
  assert.equal(created.principal_kind, "agent");

  const reader = new TitenClient({ url: running.url, key: created.api_key });
  const compiled = await reader.compile({
    subject_id: "user_sdk",
    task: "anything at all",
    max_tokens: 300,
  });
  assert.ok(compiled.context_id);

  const handoff = await titen.createHandoff({
    to_principal: created.principal_id,
    subject_id: "user_sdk_handoff",
    message: "Continue with the returned principal identity.",
  });
  const handoffs = await reader.listHandoffs("pending");
  assert.ok(handoffs.handoffs.some((entry) => entry.handoff_id === handoff.handoff_id));
  const accepted = await reader.resolveHandoff(handoff.handoff_id, "accepted");
  assert.equal(accepted.status, "accepted");

  // The client must surface a refusal as a typed error, not a silent result.
  await assert.rejects(
    () =>
      reader.observe({
        subject_id: "user_sdk",
        kind: "tool_result",
        content: "This write is not permitted for a compile-only key.",
        source: { type: "tool", ref: "contract://sdk" },
      }),
    (error: unknown) => {
      assert.ok(error instanceof TitenError, "the SDK must throw TitenError");
      assert.equal(error.status, 403);
      assert.equal(error.code, "FORBIDDEN");
      return true;
    },
  );

  const listed = await titen.listKeys();
  assert.ok(!JSON.stringify(listed).includes(created.api_key), "listing leaks no key");
  const firstPage = await titen.listKeys({ limit: 1 });
  assert.equal(firstPage.keys.length, 1);
  assert.equal(typeof firstPage.next_cursor, "string");
  const secondPage = await titen.listKeys({ limit: 1, cursor: firstPage.next_cursor! });
  assert.notEqual(secondPage.keys[0]?.key_id, firstPage.keys[0]?.key_id);
  const mine = await titen.listKeys({ principal_id: created.principal_id, status: "active" });
  assert.deepEqual(mine.keys.map((key) => key.key_id), [created.key_id]);
  await assert.rejects(() => titen.listKeys({ limit: 0 }), TypeError);
  const revoked = await titen.revokeKey(created.key_id);
  assert.equal(revoked.revoked, true);

  await assert.rejects(
    () => reader.compile({ subject_id: "user_sdk", task: "after revocation", max_tokens: 300 }),
    (error: unknown) => (error as TitenError).status === 401,
  );
});

test("a validation failure arrives as a typed error", async () => {
  await assert.rejects(
    () =>
      titen.compile({ subject_id: "user_sdk", task: "budget too small", max_tokens: 4 }),
    (error: unknown) => {
      assert.ok(error instanceof TitenError);
      assert.equal(error.status, 400);
      assert.equal(error.code, "VALIDATION_ERROR");
      return true;
    },
  );
});

test("constructor configuration fails early with stable field errors", () => {
  const cases: [unknown, RegExp][] = [
    [undefined, /config is required/],
    [{}, /url is required/],
    [{ url: "", key: "k" }, /url is required/],
    [{ url: "not a url", key: "k" }, /url is required/],
    [{ url: "file:///tmp/titen", key: "k" }, /absolute http\(s\) URL/],
    [{ url: "http://example.test", key: undefined }, /key is required/],
    [{ url: "http://example.test", key: "" }, /key is required/],
    [{ url: "http://example.test", key: "k", fetch: null }, /fetch must be a function/],
    [{ url: "http://example.test", key: "secret-value", fetch: 0 }, /fetch must be a function/],
    [{ url: "http://example.test", key: "k", timeoutMs: 0 }, /timeoutMs must be a positive/],
    [{ url: "http://example.test", key: "k", timeoutMs: 1.5 }, /timeoutMs must be a positive/],
  ];
  for (const [config, message] of cases)
    assert.throws(
      () => new TitenClient(config as never),
      (error: unknown) => {
        assert.ok(error instanceof TypeError);
        assert.match(error.message, message);
        assert.doesNotMatch(error.message, /secret-value/);
        return true;
      },
    );

  assert.doesNotThrow(
    () => new TitenClient({ url: "https://example.test/", key: "k", fetch }),
  );
});

test("requests compose caller cancellation with a timeout and never auto-retry", async () => {
  let calls = 0;
  const waitingFetch: typeof fetch = fakeFetch(async (_input, init) => {
    calls += 1;
    const signal = init?.signal;
    return new Promise<Response>((_resolve, reject) => {
      const abort = () => reject(signal?.reason);
      if (signal?.aborted) abort();
      else signal?.addEventListener("abort", abort, { once: true });
    });
  });
  const local = new TitenClient({
    url: "http://example.test",
    key: "test",
    fetch: waitingFetch,
    timeoutMs: 1_000,
  });
  const controller = new AbortController();
  const reason = new Error("caller stopped");
  const pending = local.request("GET", "/healthz", { signal: controller.signal });
  controller.abort(reason);
  await assert.rejects(() => pending, (error: unknown) => error === reason);
  assert.equal(calls, 1);

  calls = 0;
  const timed = new TitenClient({
    url: "http://example.test",
    key: "test",
    fetch: waitingFetch,
    timeoutMs: 5,
  });
  await assert.rejects(
    () => timed.health(),
    (error: unknown) => error instanceof DOMException && error.name === "TimeoutError",
  );
  assert.equal(calls, 1, "a timeout must not retry the request");

  let unavailableCalls = 0;
  const unavailable = new TitenClient({
    url: "http://example.test",
    key: "test",
    fetch: fakeFetch(async () => {
      unavailableCalls += 1;
      return Response.json(
        { error: { code: "UNAVAILABLE", message: "Try later." } },
        { status: 503 },
      );
    }),
  });
  await assert.rejects(
    () => unavailable.health(),
    (error: unknown) => error instanceof TitenError && error.code === "UNAVAILABLE",
  );
  assert.equal(unavailableCalls, 1, "503 responses are returned without an SDK retry");
});

test("object-style consolidate misuse fails locally before fetch", async () => {
  let called = false;
  const local = new TitenClient({
    url: "http://example.test",
    key: "test",
    fetch: fakeFetch(async () => {
      called = true;
      return Response.json({ data: {} });
    }),
  });
  const consolidate = local.consolidate.bind(local) as unknown as (
    value: unknown,
  ) => Promise<unknown>;
  await assert.rejects(
    () => consolidate({ subject_id: "subject", claims: [] }),
    /consolidate\(\) takes \(subject_id, claims\)/,
  );
  assert.equal(called, false);
});

test("TitenError preserves safe metadata and request ids", async () => {
  await assert.rejects(
    () => titen.resolveProject("Rama/SDK-Missing"),
    (error: unknown) => {
      assert.ok(error instanceof TitenError);
      assert.equal(error.status, 404);
      assert.equal(error.code, "NOT_FOUND");
      assert.equal(error.requestId, error.meta?.request_id);
      assert.equal(error.meta?.reason, "project_not_registered");
      assert.equal(error.meta?.reference, "rama/sdk-missing");
      assert.equal(error.meta?.can_create, true);
      assert.deepEqual(error.meta?.support, {
        classification: "expected",
        action: "Retry with create=true only after an authorized operator approves project creation.",
        docs_url: "https://titen.dev/docs/agent-integrations#project-resolution",
      });
      return true;
    },
  );

  const local = new TitenClient({
    url: "http://example.test",
    key: "test",
    fetch: fakeFetch(async () => Response.json(
      {
        error: {
          code: "UNAVAILABLE",
          message: "Dependency unavailable.",
          meta: { retryable: true, operation: "index_drain" },
        },
        meta: { request_id: "req_body", dependency: "embedder", retryable: true },
      },
      { status: 503, headers: { "x-request-id": "req_header" } },
    )),
  });
  await assert.rejects(
    () => local.health(),
    (error: unknown) => {
      assert.ok(error instanceof TitenError);
      assert.equal(error.requestId, "req_body");
      assert.deepEqual(error.meta, {
        request_id: "req_body",
        dependency: "embedder",
        retryable: true,
        operation: "index_drain",
      });
      return true;
    },
  );

  const headerOnly = new TitenClient({
    url: "http://example.test",
    key: "test",
    fetch: fakeFetch(async () => Response.json(
      { error: { code: "FORBIDDEN", message: "No." } },
      { status: 403, headers: { "x-request-id": "req_header_only" } },
    )),
  });
  await assert.rejects(
    () => headerOnly.health(),
    (error: unknown) => {
      assert.ok(error instanceof TitenError);
      assert.equal(error.requestId, "req_header_only");
      assert.deepEqual(error.meta, { request_id: "req_header_only" });
      return true;
    },
  );
});

test("empty and non-JSON responses never leak parser or gateway details", async () => {
  const call = async (response: Response) =>
    new TitenClient({
      url: "http://example.test",
      key: "test",
      fetch: fakeFetch(async () => response),
    }).health();

  assert.equal(await call(new Response(null, { status: 204 })), undefined);
  assert.equal(await call(new Response(null, { status: 200 })), undefined);

  const failures: [Response, number, string][] = [
    [new Response(null, { status: 500 }), 500, "HTTP_ERROR"],
    [
      new Response("<h1>private upstream detail</h1>", {
        status: 502,
        headers: { "content-type": "text/html" },
      }),
      502,
      "HTTP_ERROR",
    ],
    [
      new Response("{bad", {
        status: 503,
        headers: { "content-type": "application/json" },
      }),
      503,
      "HTTP_ERROR",
    ],
    [
      Response.json(
        { error: { code: "UPSTREAM_DOWN", message: "Dependency unavailable." } },
        { status: 503 },
      ),
      503,
      "UPSTREAM_DOWN",
    ],
  ];
  for (const [response, status, code] of failures)
    await assert.rejects(
      () => call(response),
      (error: unknown) => {
        assert.ok(error instanceof TitenError);
        assert.equal(error.status, status);
        assert.equal(error.code, code);
        assert.doesNotMatch(error.message, /private upstream detail|Unexpected token|JSON/);
        return true;
      },
    );

  await assert.rejects(
    () =>
      call(
        new Response("{bad", {
          status: 200,
          headers: { "content-type": "application/json" },
        }),
      ),
    (error: unknown) =>
      error instanceof TitenError && error.status === 200 && error.code === "INVALID_RESPONSE",
  );
});

test("successful JSON responses require an object envelope", async () => {
  const invalid: Array<[string, unknown]> = [
    ["array", []],
    ["null", null],
    ["string", "ok"],
    ["number", 1],
    ["boolean", true],
  ];
  const calls: Array<[
    string,
    (client: TitenClient) => Promise<unknown>,
  ]> = [
    ["requestWithMeta", (client) => client.requestWithMeta("GET", "/healthz")],
    ["health", (client) => client.health()],
  ];

  for (const [shape, value] of invalid) {
    for (const [method, call] of calls) {
      const requestId = `req-${shape}-${method}`;
      const client = new TitenClient({
        url: "http://example.test",
        key: "test",
        fetch: fakeFetch(async () =>
          Response.json(value, { headers: { "x-request-id": requestId } })),
      });
      await assert.rejects(
        () => call(client),
        (error: unknown) => {
          assert.ok(error instanceof TitenError, `${method} accepted ${shape}`);
          assert.equal(error.code, "INVALID_RESPONSE");
          assert.equal(error.status, 200);
          assert.equal(error.requestId, requestId);
          assert.deepEqual(error.meta, { request_id: requestId });
          return true;
        },
      );
    }
  }

  const client = new TitenClient({
    url: "http://example.test",
    key: "test",
    fetch: fakeFetch(async () =>
      Response.json(
        {
          data: { status: "ok", runtime: "test", revision: "valid" },
          meta: { replayed: true },
        },
        { headers: { "x-request-id": "req-valid" } },
      )),
  });
  assert.deepEqual(await client.requestWithMeta("GET", "/healthz"), {
    data: { status: "ok", runtime: "test", revision: "valid" },
    meta: { replayed: true, request_id: "req-valid" },
  });
  assert.deepEqual(await client.health(), {
    status: "ok",
    runtime: "test",
    revision: "valid",
  });
});

test("mutation idempotency reaches the server and preserves replay semantics", async () => {
  const idempotencyKey = `sdk-retry-${crypto.randomUUID()}`;
  const observation = {
    subject_id: `user_sdk_retry_${crypto.randomUUID()}`,
    kind: "tool_result" as const,
    content: "Retry-safe SDK observation.",
    source: { type: "tool", ref: "sdk-retry" },
  };
  const first = await titen.requestWithMeta<{ observation_id: string }>(
    "POST",
    "/v1/observations",
    { json: observation, idempotencyKey },
  );
  const replay = await titen.requestWithMeta<{ observation_id: string }>(
    "POST",
    "/v1/observations",
    { json: observation, idempotencyKey },
  );
  assert.equal(replay.data.observation_id, first.data.observation_id);
  assert.equal(first.meta.replayed, false);
  assert.equal(replay.meta.replayed, true);
  assert.match(first.meta.request_id as string, /^req_/);

  await assert.rejects(
    () =>
      titen.observe(
        { ...observation, content: "Changed retry body." },
        { idempotencyKey },
      ),
    (error: unknown) =>
      error instanceof TitenError && error.status === 409 && error.code === "CONFLICT",
  );
});

test("generic JSON and raw access preserve auth without allowing overrides", async () => {
  const events = await titen.listEvents({ limit: 1 });
  assert.ok(Array.isArray(events.events));

  const exported = await titen.requestRaw(
    "GET",
    "/v1/export?type=observations&limit=1",
  );
  assert.match(exported.headers.get("content-type") ?? "", /application\/x-ndjson/);
  const firstLine = (await exported.text()).split("\n")[0]!;
  assert.equal(JSON.parse(firstLine).type, "titen.export.header");

  let called = false;
  const local = new TitenClient({
    url: "http://example.test",
    key: "configured-key",
    fetch: fakeFetch(async () => {
      called = true;
      return Response.json({ data: {} });
    }),
  });
  await assert.rejects(
    () =>
      local.request("GET", "/v1/events", {
        headers: { authorization: "Bearer attacker-selected" },
      }),
    /authorization cannot be overridden/,
  );
  await assert.rejects(
    () => local.request("GET", "//attacker.example/v1/events"),
    /path must be an absolute API path/,
  );
  assert.equal(called, false, "an invalid generic request must fail before network I/O");
});

test("typed event iteration stops on empty pages and rejects broken cursors", async () => {
  const event = (id: string) => ({
    id,
    kind: "claim.materialized",
    actor_id: "agent_test",
    resource_type: "claim",
    resource_id: `claim_${id}`,
    payload: {},
    created_at: "2026-08-01T00:00:00.000Z",
  });
  const collect = async (client: TitenClient) => {
    const rows = [];
    for await (const row of client.iterateEvents({ limit: 1 })) rows.push(row);
    return rows;
  };
  const pages = [
    { events: [event("evt_1")], cursor: "evt_1" },
    { events: [event("evt_2")], cursor: "evt_2" },
    // The service deliberately echoes the incoming cursor when exhausted.
    { events: [], cursor: "evt_2" },
  ];
  let calls = 0;
  const local = new TitenClient({
    url: "http://example.test",
    key: "test",
    fetch: fakeFetch(async () => Response.json({ data: pages[calls++] })),
  });
  assert.deepEqual((await collect(local)).map(({ id }) => id), ["evt_1", "evt_2"]);
  assert.equal(calls, 3, "an exact page boundary needs one terminal empty poll");

  let emptyCalls = 0;
  const empty = new TitenClient({
    url: "http://example.test",
    key: "test",
    fetch: fakeFetch(async () => {
      emptyCalls += 1;
      return Response.json({ data: { events: [], cursor: null } });
    }),
  });
  assert.deepEqual(await collect(empty), []);
  assert.equal(emptyCalls, 1);

  for (const brokenPages of [
    [{ events: [event("evt_same")], cursor: "evt_same" }, { events: [event("evt_next")], cursor: "evt_same" }],
    [{ events: [event("evt_duplicate")], cursor: "cursor_1" }, { events: [event("evt_duplicate")], cursor: "cursor_2" }],
    [{ events: [event("evt_null_cursor")], cursor: null }],
    [{ events: [event("evt_numeric_cursor")], cursor: 42 }],
  ]) {
    let index = 0;
    const broken = new TitenClient({
      url: "http://example.test",
      key: "test",
      fetch: fakeFetch(async () => Response.json({ data: brokenPages[index++] })),
    });
    await assert.rejects(
      () => collect(broken),
      (error: unknown) => error instanceof TitenError && error.code === "INVALID_RESPONSE",
    );
  }

  const controller = new AbortController();
  controller.abort();
  // A caller can cancel before the iterator's first list request.
  const aborted = (async () => {
    for await (const _event of local.iterateEvents({ signal: controller.signal })) void _event;
  })();
  await assert.rejects(() => aborted, (error: unknown) => error === controller.signal.reason);
});

test("typed mutation sends one idempotency header and the capability matrix stays live", async () => {
  let headers = new Headers();
  const local = new TitenClient({
    url: "http://example.test",
    key: "configured-key",
    fetch: fakeFetch(async (_input, init) => {
      headers = new Headers(init?.headers);
      return Response.json({ data: { observation_id: "obs_test" } });
    }),
  });
  await local.observe(
    {
      subject_id: "subject",
      kind: "tool_result",
      content: "captured",
      source: { type: "test", ref: "contract://sdk" },
    },
    { idempotencyKey: "retry-one" },
  );
  assert.equal(headers.get("authorization"), "Bearer configured-key");
  assert.equal(headers.get("idempotency-key"), "retry-one");
  assert.equal(
    [...headers.keys()].filter((name) => name === "idempotency-key").length,
    1,
  );

  for (const [method] of TITEN_SDK_TYPED_ROUTES)
    assert.equal(
      typeof (TitenClient.prototype as unknown as Record<string, unknown>)[method],
      "function",
      `${method} is documented but missing`,
    );
});