/*
RFC-0783: determinism + shape tests for the API Catalog linkset projection.
- Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only.
- RFC-0783: initial API Catalog projection tests.
- RFC-1113: align agent discovery surface with RFC 9727 and MCP 2026-07-28 stateless era
*/
import { test, expect } from "vitest";
import { buildApiCatalog } from "../api-catalog.ts";
import { buildAgentSurfaceManifest } from "../manifest.ts";
test("buildApiCatalog: empty manifest yields service-meta + service-doc links", () => {
const manifest = buildAgentSurfaceManifest({
generatedAt: "2026-01-01T00:00:00.000Z",
site: "s",
baseUrl: "https://s.example",
languages: { default: "de", supported: ["de"] },
});
const catalog = buildApiCatalog(manifest);
const entry = catalog.linkset[0];
expect(entry.anchor).toBe("https://s.example/");
const serviceMeta = entry["service-meta"] as { href: string }[];
expect(serviceMeta).toHaveLength(1);
expect(serviceMeta[0].href).toBe("/.well-known/agent.json");
const serviceDoc = entry["service-doc"] as { href: string }[];
expect(serviceDoc).toHaveLength(1);
expect(serviceDoc[0].href).toBe("/llms.txt");
});
test("buildApiCatalog: one knowledge ref → one item link", () => {
const manifest = buildAgentSurfaceManifest({
generatedAt: "2026-01-01T00:00:00.000Z",
site: "s",
baseUrl: "https://s.example",
languages: { default: "de", supported: ["de"] },
knowledge: [
{ domain: "offer", url: "/api/agent/v1/offer.json", schema: "gogol.agent.knowledge/offer@1" },
],
});
const catalog = buildApiCatalog(manifest);
const itemLinks = catalog.linkset[0]["item"] as { href: string; type: string; title: string }[];
expect(itemLinks).toHaveLength(1);
expect(itemLinks[0].href).toBe("/api/agent/v1/offer.json");
expect(itemLinks[0].type).toBe("application/json");
expect(itemLinks[0].title).toBe("offer");
});
test("buildApiCatalog: mcp interface adds service-desc + service links", () => {
const manifest = buildAgentSurfaceManifest({
generatedAt: "2026-01-01T00:00:00.000Z",
site: "s",
baseUrl: "https://s.example",
languages: { default: "de", supported: ["de"] },
mcp: { url: "/api/agent/mcp", protocolVersion: "2025-06-18" },
});
const catalog = buildApiCatalog(manifest);
const entry = catalog.linkset[0];
const descHrefs = (entry["service-desc"] as { href: string }[]).map((l) => l.href);
expect(descHrefs).toContain("/.well-known/mcp/server-card.json");
const service = entry["service"] as { href: string }[];
expect(service[0].href).toBe("/api/agent/mcp");
});
test("buildApiCatalog: determinism — same input produces identical output", () => {
const input = {
site: "s",
baseUrl: "https://s.example",
languages: { default: "de", supported: ["de"] },
generatedAt: "2026-01-01T00:00:00.000Z",
knowledge: [
{ domain: "offer", url: "/api/agent/v1/offer.json", schema: "gogol.agent.knowledge/offer@1" },
{ domain: "team", url: "/api/agent/v1/team.json", schema: "gogol.agent.knowledge/team@1" },
],
mcp: { url: "/api/agent/mcp", protocolVersion: "2025-06-18" },
};
const a = buildApiCatalog(buildAgentSurfaceManifest(input));
const b = buildApiCatalog(buildAgentSurfaceManifest(input));
expect(JSON.stringify(a)).toBe(JSON.stringify(b));
});
test("buildApiCatalog: links are sorted by href within each relation", () => {
const manifest = buildAgentSurfaceManifest({
generatedAt: "2026-01-01T00:00:00.000Z",
site: "s",
baseUrl: "https://s.example",
languages: { default: "de", supported: ["de"] },
knowledge: [
{ domain: "zeta", url: "/api/agent/v1/zeta.json", schema: "gogol.agent.knowledge/zeta@1" },
{ domain: "alpha", url: "/api/agent/v1/alpha.json", schema: "gogol.agent.knowledge/alpha@1" },
],
});
const catalog = buildApiCatalog(manifest);
const itemHrefs = (catalog.linkset[0]["item"] as { href: string }[]).map((l) => l.href);
const sorted = [...itemHrefs].sort();
expect(itemHrefs).toEqual(sorted);
});
// ---------------------------------------------------------------------------
// RFC-1171: successor-version links (AC-7)
// ---------------------------------------------------------------------------
test("buildApiCatalog: deprecations[] project successor-version link entries (AC-7)", () => {
const manifest = buildAgentSurfaceManifest({
generatedAt: "2026-01-01T00:00:00.000Z",
site: "s",
baseUrl: "https://s.example",
languages: { default: "de", supported: ["de"] },
actions: [
{
id: "lead.submit",
url: "/api/agent/v1/actions/lead.submit",
title: { de: "Anfrage senden" },
inputSchemaRef: "#/x",
entitlement: "agent.actions",
},
],
});
const catalog = buildApiCatalog(manifest);
const depEntries = catalog.linkset.filter(
(e) => Array.isArray(e["successor-version"]),
);
expect(depEntries).toHaveLength(1);
expect(depEntries[0].anchor).toBe("https://s.example/api/agent/actions/lead.submit");
const links = depEntries[0]["successor-version"] as { href: string }[];
expect(links[0].href).toBe("/api/agent/v1/actions/lead.submit");
});