// test-adjacency: exempt — pure type definitions
/*
Defines types for semantic data structures used throughout the Warpgogol ecosystem.Do not introduce app-specific runtime composition or deployment behavior into this reusable package source file.RFC-0372: Unified SemanticBlock type replaces SemanticAnswerBlock + SemanticContentBlock; SemanticPageModel.blocks replaces answerBlocks/contentBlocks/bodyText.RFC-0912: Added VideoSeoData type and optional SemanticBlock.video field for opted-in content video structured data.RFC-1254: drain latent lint debt — dead imports/vars, no-as-any casts, restricted importsRFC-1282: SemanticPageModel.htmlLang — the BCP 47 tag emitted as (falls back to the lang segment when unset).RFC-0133, RFC-0165, RFC-0328, RFC-0490, RFC-0508
*/
import type { z } from "zod";
import { semanticPageTypeSchema } from "../ontology/schemas/system/page-output.ts";
// RFC-1106: semanticPageTypeSchema (ontology/schemas/system/page-output.ts) is
// the sole declaration of this closed DNA-19 vocabulary. The type and the
// runtime array derive from it — no hand-synced mirror.
export type SemanticPageType = z.infer;
/** Runtime list of the closed vocabulary — derived from the schema's options. */
export const SEMANTIC_PAGE_TYPES: readonly SemanticPageType[] = semanticPageTypeSchema.options;
export type SemanticBreadcrumb = {
name: string;
url: string;
};
/**
* RFC-0372: Unified semantic block — replaces the former SemanticAnswerBlock and SemanticContentBlock.
* Every block in a SemanticPageModel is represented by this single type, regardless of
* whether it was derived from prose parsing or frontmatter block extraction.
*/
/** RFC-0912: video SEO data populated by buildSemanticPageModelWith for opted-in content video blocks. */
export type VideoSeoData = {
seo: { name: string; description: string; uploadDate: string };
manifest: { posterUrl: string; durationSec?: number; contentUrl: string };
};
export type SemanticBlock = {
/** Stable id from frontmatter block.id (required) or slugified heading for prose-derived blocks. */
id: string;
/** Block type from frontmatter (e.g. "hero-decision-card", "markdown") or "prose" for prose-derived blocks. */
blockType?: string;
/** Section heading (H2 in markdown twin). Empty string for no-op blocks; rendering checks `if (block.heading)`. */
heading: string;
/** Lead / subheading text. Counts as substantive content for ART-DEPTH-03. */
summary?: string;
/** Free-form body text (prose paragraphs, descriptions). */
body?: string;
/** Bullet-list facts (from markdown answer blocks). */
facts?: string[];
/** Structured items (from block extractors: cards, comparison rows, etc.). */
items?: Array<{ title: string; description?: string }>;
/** Extractor metadata (absent for prose-derived blocks). */
extractedAt?: string;
extractorVersion?: string;
/** RFC-0912: video SEO data for opted-in content video blocks (seo.videoObject: true). Populated by buildSemanticPageModelWith from the variant manifest. */
video?: VideoSeoData;
};
/* RFC-0142: per-page llms inclusion depth. */
export type SemanticLlmsDepth = "full" | "summary" | "index-only" | "exclude";
export type SemanticLlmsPolicy = {
depth: SemanticLlmsDepth;
sections?: { exclude?: string[] };
};
/* RFC-0143: per-page sitemap projection (resolved). */
export type SitemapProjection = {
include: boolean;
category: string;
lastmod?: string;
includeLastmod: boolean;
};
/* RFC-0165: resolved per-page robots/indexability directive. */
export type RobotsProjection = {
index: boolean;
follow: boolean;
};
/* RFC-0143: resolved per-page `output` projection container. */
export type PageOutputProjection = {
sitemap: SitemapProjection;
llms: SemanticLlmsPolicy;
/* RFC-0165: indexability — drives the robots meta tag and sitemap inclusion. */
robots: RobotsProjection;
/**
* RFC-0165/0167: author-declared per-page content illustration (absolute
* https url). This is the single CLI-knowable source for the image sitemap
* (`image:image`) and the highest-precedence source for `og:image`. When
* present it carries `contentImage: true`. Absent when the page has no
* author-declared illustration.
*/
image?: SemanticImage;
};
/* RFC-0162: a resolved social/OG image (absolute https url + intrinsic size). */
export type SemanticImage = {
url: string;
width?: number;
height?: number;
alt?: string;
/**
* RFC-0165/0167: marks a genuine content illustration (author-declared or
* hero `leadImage`) as opposed to a synthetic fallback (RFC-0150 preview
* screenshot, business logo). Only `contentImage: true` images are eligible
* for the image sitemap (`image:image`); all images may serve `og:image`.
*/
contentImage?: boolean;
};
/* RFC-0162: Open Graph `og:type` discriminator. Defaults to "website"; "article" set by RFC-0167. */
export type OgType = "website" | "article" | "profile";
export type SemanticPostalAddress = {
streetAddress?: string;
postalCode?: string;
addressLocality?: string;
addressCountry?: string;
};
export type SemanticPerson = {
name: string;
role?: string;
description?: string;
isDeceased?: boolean;
/* RFC-0200: governance/presentational affiliations (founder | board | team | patron | author). */
affiliations?: string[];
/* RFC-0200: lifespan → schema.org Person.birthDate / deathDate (ISO or year). */
birthDate?: string;
deathDate?: string;
/* RFC-0200: representative portrait (absolute https url) → Person.image. */
image?: string;
/* RFC-0200: social/profile URLs → Person.sameAs (entity grounding). */
sameAs?: string[];
/* RFC-0200: absolute URL of this person's profile page, when one is live. */
profileUrl?: string;
/* RFC-0512: city-level address for Person JSON-LD (consent-gated at emission). */
address?: { addressLocality: string; addressRegion?: string; addressCountry: string };
/* RFC-0512: professional expertise areas → Person.knowsAbout. */
knowsAbout?: string[];
/* RFC-0512: organization affiliation → Person.affiliation. */
affiliation?: { name: string; url?: string };
};
export type SemanticContactPoint = {
contactType: string;
email?: string;
};
export type SemanticDonationAccount = {
accountHolder?: string;
bankName?: string;
iban?: string;
bic?: string;
accountNumber?: string;
bankCode?: string;
};
export type SemanticInitiative = {
id: string;
name: string;
summary: string;
facts?: string[];
};
export type SemanticService = {
id: string;
name: string;
description?: string;
};
/* RFC-0147/RFC-0148: business offer projection (prices + written guarantees + growth modules + terms). */
export type SemanticGuarantee = {
id: string;
label: string;
detail?: string;
};
export type SemanticPrice = {
id: string;
label: string;
amount: string;
currency?: string;
};
export type SemanticGrowthModule = {
id: string;
label: string;
description?: string;
price?: string;
};
export type SemanticOfferCapacity = {
enabled: boolean;
timezone: string;
startsAt: string;
cadence: "monthly" | "fixed-days";
cadenceDays?: number;
slotRange: { min: number; max: number };
maxSlotsPerWave: number;
availabilityStatus: "unknown";
};
export type SemanticOffer = {
/** RFC-1075: persistent canonical URI for Linked Data @id. */
canonicalUri?: string;
prices?: SemanticPrice[];
guarantees?: SemanticGuarantee[];
growthModules?: SemanticGrowthModule[];
capacity?: SemanticOfferCapacity;
changePrice?: string;
hourlyRate?: string;
billingDay?: string;
};
/* RFC-0148: business location projection (NAP + service area). */
export type SemanticLocation = {
locality?: string;
region?: string;
country?: string;
serviceArea?: string[];
};
/* RFC-0287: business web/domain identity projection (business/{lang}/web.md). */
export type SemanticWeb = {
primaryUrl?: string;
statusUrl?: string;
domains?: { primary?: string; german?: string };
};
export type SemanticFaqEntry = {
id: string;
question: string;
answer: string;
tags?: string[];
serviceSlug?: string;
};
export type SemanticOrganization = {
/** RFC-1075: persistent canonical URI for Linked Data @id. */
canonicalUri?: string;
name: string;
legalName?: string;
description: string;
url: string;
foundingYear?: string;
email?: string;
registration?: string;
representative?: string;
address?: SemanticPostalAddress;
areaServed?: string[];
founders?: SemanticPerson[];
boardMembers?: SemanticPerson[];
contactPoints?: SemanticContactPoint[];
donationAccount?: SemanticDonationAccount;
/* RFC-0147/RFC-0148: projected business catalog (public-visibility schemas). */
offer?: SemanticOffer;
services?: SemanticService[];
location?: SemanticLocation;
sameAs?: string[];
/* RFC-0163: organization logo (absolute https url) → schema.org ImageObject. */
logo?: string;
/* RFC-0163: representative organization image (absolute https url). */
image?: string;
/* RFC-0148: public team members (distinct from governance founders/board). */
team?: SemanticPerson[];
/**
* RFC-0242: explicit schema.org @type override (e.g. `["Organization", "ProfessionalService"]`
* for a Bodenstation studio deployment). Defaults to `["Organization", "NGO"]` when absent.
*/
schemaType?: string[];
};
export type SemanticPageModel = {
type: SemanticPageType;
lang: string;
defaultLanguage?: string;
url: string;
title: string;
description: string;
/** RFC-0377: optional audience override (falls back to SemanticPageType derivation map). */
audience?: string;
heading?: string;
lead?: string;
breadcrumbs: SemanticBreadcrumb[];
/** RFC-0372: unified block array — replaces answerBlocks, contentBlocks, and bodyText. */
blocks: SemanticBlock[];
organization: SemanticOrganization;
people?: SemanticPerson[];
initiatives?: SemanticInitiative[];
faqEntries?: SemanticFaqEntry[];
/**
* RFC-0143/RFC-0142: resolved per-page output projection. Set by the
* semantic loaders via resolvePageOutput(); read by the llms formatters.
* Always resolved (never undefined) once a model leaves the loader.
*/
output?: PageOutputProjection;
/**
* RFC-0162: per-page social preview image (resolved from the RFC-0150
* preview pipeline, with a business-logo fallback). Consumed by
* for og:image / twitter:image and by RFC-0163 for primaryImageOfPage.
*/
primaryImage?: SemanticImage;
/**
* RFC-0209: unresolved hero `leadImage` token ({src, alt}) carried from the
* framework-free page handler to the asset-aware render layer. Set only when
* the page declares a hero `leadImage` and no explicit `output.image`. The
* layout resolves it through the Image Provider Port and promotes it to
* `primaryImage` (ahead of the RFC-0150 preview-screenshot fallback). The
* page handler cannot resolve the token to a URL (Astro content-hashing /
* Image Provider Port run in the render layer), so it ships the raw token.
*/
leadImageToken?: { src: string; alt: string };
/**
* Unresolved token for the page's actual LCP element, carried from the
* framework-free page handler to the asset-aware render layer. Set to the
* hero block's `backgroundImage` when present (full-viewport, fetchpriority
* high), falling back to `leadImage` when visible. Used for `` in ``.
*/
lcpImageToken?: { src: string; alt: string };
/** RFC-0162: Open Graph type. Defaults to "website" when unset. */
ogType?: OgType;
/** RFC-0162: Open Graph locale in `xx_XX` form (from system.md i18n hreflang). */
ogLocale?: string;
/**
* RFC-1282: BCP 47 language tag for the `` attribute — resolved from
* `i18n.supported..tag`, falling back to the lang segment when absent.
*/
htmlLang?: string;
/** RFC-0162: Open Graph alternate locales in `xx_XX` form (other supported languages). */
ogLocaleAlternates?: string[];
/* RFC-0167: article metadata — when present, the page emits an Article/BlogPosting node. */
datePublished?: string;
dateModified?: string;
author?: string;
keywords?: string[];
/**
* RFC-0506: author record reference for ratgeber depth-1 pages. When present,
* buildArticleNode emits a structured Person node with name and optional url
* instead of a plain string author.
*/
authorRecord?: {
name: string;
contactUrl?: string;
};
/** RFC-0506: latest reviewedAt date from article frontmatter, used for dateModified computation. */
reviewedAt?: string;
/** RFC-0506: changelog entries from article frontmatter (RFC-0504), used for dateModified computation. */
changelog?: Array<{ date: string; summary: string; authorId: string }>;
/**
* RFC-0227: stable @id values for all material credit nodes that appear on this page.
* When set, the WebPage node emits associatedMedia references so search engines can link
* disclosed credits to the page entity. Populated by page templates that load credit records.
*/
materialCreditAtIds?: string[];
/**
* RFC-0490: collection items for "collection"-typed pages (e.g. industry links on a pillar hub).
* Each item is a { url, name } pair emitted as a ListItem in the JSON-LD ItemList node.
*/
collectionItems?: Array<{ url: string; name: string }>;
/** RFC-0492: surface identity for depth-gated JSON-LD corrections. */
surfaceId?: string;
/** RFC-0492: surface depth for depth-gated JSON-LD corrections. */
depth?: number;
/**
* RFC-0492/RFC-0498: industry-specific Service node metadata for surface pages where Service is required.
* When present, `buildJsonLd` emits a single industry Service node instead of the
* organization-level Service nodes. Covers website-local depth-1, website-service depth-1,
* and website-local depth-5.
*/
industryService?: {
serviceType: string;
audience?: string;
description?: string;
areaServed?: string;
};
/**
* RFC-0512: extra JSON-LD nodes injected into the @graph for team profile pages.
* AI-agent profile pages inject a SoftwareApplication node; the team hub injects
* a CollectionPage node with hasPart. Human profile pages do not need this —
* the extended Person node is already emitted by buildPersonNode.
*/
extraGraphNodes?: import("./jsonld/types.ts").JsonLdNode[];
};
export type SemanticSiteModel = {
baseUrl: string;
lang: string;
defaultLanguage?: string;
organization: SemanticOrganization;
pages: SemanticPageModel[];
/** RFC-0789: agent block from system.md, populated by the semantic loader. */
agent?: { enabled?: boolean };
/** RFC-1076: projected claims with evidence provenance, loaded by the semantic loader. */
claims?: import("./business-projection.ts").SemanticClaimProvenance[];
};