/* Maintains packages/share/src/semantic/jsonld/service.ts as an authored share authored module so agents can evolve it without rediscovering local boundaries. Do not validate service input data. RFC-0498: extend buildServiceNodes to gate Service emission by per-depth policy for all surface depths (website-local depth-1, website-service depth-1, website-local depth-5). RFC-1097: step 6 — compass.migrate codemod run Mechanical v1 to v2 header migration across the workspace: 942 files rewritten — CHANGE_SUMMARY windows collapsed into history, forbidden v1 blocks stripped, KEY_DECISIONS seeded from @ai-invariant comments (5 files) or TODO placeholders (103 files), blocks reordered to canonical order. RFC-1097: sweep — werkstatt-engine clean Sweep batch 4: 73 Compass headers on headerless engine files (certification, component-runtime, isolation, evolution, testing), real KEY_DECISIONS on 75 files (kernel, cache, dht, swim, gitmesh, runtime), ~80 purpose expansions (CONTRACT-02/PURPOSE-02), non-goals on 13 CONTRACT-03 files, CS-07 history literal fix repo-wide (253 files). Policy: .template.ts/.template.astro excludedPaths. werkstatt-engine now 0 diagnostics. */ import type { JsonLdContext } from "./context.ts"; import type { JsonLdNode } from "./types.ts"; import type { SemanticService } from "../models.ts"; function buildServiceNode(context: JsonLdContext, service: SemanticService): JsonLdNode { const { ids } = context; return { "@type": "Service", "@id": ids.service(service.name), name: service.name, ...(service.description ? { description: service.description } : {}), provider: { "@id": ids.organization }, }; } /** * RFC-0492: build the industry-specific Service node for depth-1 `website-local` pages. * Replaces the organization-level Service nodes with a single node carrying * `serviceType`, `audience`, and `provider`. */ function buildIndustryServiceNode(context: JsonLdContext): JsonLdNode | null { const { page, ids } = context; if (!page.industryService) return null; return { "@type": "Service", "@id": `${ids.organization}/service-industry`, name: page.industryService.serviceType, serviceType: page.industryService.serviceType, provider: { "@id": ids.organization }, ...(page.industryService.audience ? { audience: { "@type": "Audience", name: page.industryService.audience } } : {}), ...(page.industryService.description ? { description: page.industryService.description } : {}), ...(page.industryService.areaServed ? { areaServed: { "@type": "City", name: page.industryService.areaServed } } : {}), }; } /** * RFC-0492/RFC-0498: for surface pages where Service is required (website-local depth-1, * website-service depth-1, website-local depth-5), suppress organization-level Service nodes * and emit a single industry-specific Service node instead. * For surface pages where Service is prohibited (depth-0, 2, 3, 4), emit no Service nodes. * For non-surface pages, emit organization-level Service nodes as before. */ export function buildServiceNodes(context: JsonLdContext): JsonLdNode[] { const { page } = context; // RFC-0498: surface pages with industryService get the industry-specific Service node. // This covers website-local depth-1, website-service depth-1, and website-local depth-5. if (page.industryService) { const industryNode = buildIndustryServiceNode(context); return industryNode ? [industryNode] : []; } // RFC-0498: surface pages without industryService and where Service is prohibited emit no Service nodes. // Depth-0, 2, 3, 4 in website-local have Service in prohibitedTypes. if (page.surfaceId && page.depth !== undefined && page.depth !== 1 && page.depth !== 5) { return []; } return (page.organization.services ?? []).map((service) => buildServiceNode(context, service)); }