@duffcloudservices/cms 0.13.0 → 0.13.2

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.
@@ -496,5 +496,5 @@ The head-contract audit did not run against anything it could judge. Fix the inp
496
496
  }
497
497
 
498
498
  export { HeadContractError, MIN_EXEMPTION_REASON_LENGTH, assertHeadContract, auditExemptionHosts, auditHeadContract, blankComments, formatExemptionAudit, formatHeadContractReport, hostsNamedIn, normalizeExemption, parseHostProbeHtml };
499
- //# sourceMappingURL=chunk-A5F4C72F.js.map
500
- //# sourceMappingURL=chunk-A5F4C72F.js.map
499
+ //# sourceMappingURL=chunk-OGAJX4KM.js.map
500
+ //# sourceMappingURL=chunk-OGAJX4KM.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/seo/headContract.ts"],"names":["end"],"mappings":"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","file":"chunk-A5F4C72F.js","sourcesContent":["/**\n * THE HEAD-AUTHORITY CONTRACT (C-356) — a source-level audit.\n *\n * WHY THIS EXISTS. One undefined contract produced two OPPOSITE production\n * failures on the same shared composable, measured a day apart:\n *\n * KEPT 28 `applyHead({…})` callers OVERWROTE the baked head.\n * 93 title/description divergences across 49 routes — 100% of\n * routes served one <title> to a non-JS AI crawler and a\n * different one to Google and every human (C-338 matrix,\n * fixed C-341: 51/51, zero divergent).\n * boogie-babies 2 callers, 9 of 11 views that write NOTHING. Hard navigation\n * is correct; the first in-app click leaves the previous\n * route's title/description/canonical in the DOM (measured:\n * /pricing -> /parties still claims canonical /pricing).\n * just-posh 17 raw `useHead({title, meta, link})` blocks that never touch\n * the composable at all — 27 divergences, the fleet's second\n * largest. A contract about `applyHead` alone would not see it.\n *\n * THE CONTRACT, in one line: `.dcs/seo.yaml` is the ONLY writer of the managed\n * head fields, and it must be re-asserted on EVERY route, on EVERY navigation.\n * Full text + reasoning: `.docs/plans/dynamic-site-resolution/README.md`\n * § \"The head-authority contract (C-356)\".\n *\n * WHAT THIS MODULE PROVES AND WHAT IT DOES NOT.\n * - It proves there is exactly ONE WRITER in the source. That is authority.\n * - It does NOT prove the writer told the truth. That is P1\n * (`headHonesty.ts`), which compares the baked head to the rendered head on\n * a real build. Neither replaces the other, and an exemption here buys no\n * amnesty there.\n *\n * Deliberately framework-free and fs-free: it takes source strings, so the same\n * function runs in the package's own vitest fixtures, in a site's test script,\n * and in `cli/head-contract-audit.mjs` against a real repo. There is no second\n * implementation to drift.\n */\n\nimport type { UseSeoReturn } from '../types/seo'\n\n// =============================================================================\n// The compile-time half of the enforcement\n// =============================================================================\n\n/**\n * COMPILE-TIME PIN: `applyHead` must take ZERO parameters.\n *\n * `packages/cms/tsconfig.json` excludes `**\\/*.test.ts`, so a `@ts-expect-error`\n * written in a test file is never evaluated by `pnpm type-check` — it would be a\n * comment that looks like a gate. This pin lives in a checked source file\n * instead: re-add a parameter to `UseSeoReturn['applyHead']` and the assignment\n * below stops compiling, which reds `type-check` in this package and, through\n * the published `.d.ts`, in every site that runs one.\n */\nexport type ApplyHeadTakesNoArguments = Parameters<UseSeoReturn['applyHead']> extends []\n ? true\n : false\n\nexport const APPLY_HEAD_TAKES_NO_ARGUMENTS: ApplyHeadTakesNoArguments = true\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/** Codes that FAIL the contract. */\nexport type HeadContractViolationCode =\n /** `applyHead({…})` — a second writer for a managed field. Never exemptible. */\n | 'override-argument'\n /** `useSEO('x')` where `.dcs/seo.yaml` has no `pages.x.title`. Never exemptible. */\n | 'undeclared-slug'\n /** `useHead` / `useSeoMeta` / `document.title =` — a writer outside the factory. */\n | 'foreign-head-writer'\n /** An exemption whose file no longer violates anything (anti-rot). */\n | 'stale-exemption'\n /** An exemption with no real reason recorded. */\n | 'empty-exemption-reason'\n /** An exemption that names a host but cannot be checked against it (C-420). */\n | 'unprobed-exemption'\n /** A live probe contradicts what the exemption asserts about its host (C-420). */\n | 'exemption-claim-refuted'\n /** The probe of an exemption's host did not complete — never a pass (C-420). */\n | 'exemption-probe-failed'\n /** The audit scanned no files — a pass that checked nothing is not a pass. */\n | 'scan-empty'\n /** No `.dcs/seo.yaml` was supplied, so authority cannot be established. */\n | 'no-seo-config'\n\n/** Codes that are REPORTED but do not fail. */\nexport type HeadContractWarningCode =\n /** A view that never re-asserts the head; SPA navigation to it is stale. */\n | 'uncovered-route'\n /** `useSEO(`blog-${slug}`)` — legal, but only P1 can judge it. */\n | 'dynamic-slug'\n\nexport interface HeadContractSourceFile {\n /** Path as the caller wants it reported (and as exemptions key on). */\n path: string\n source: string\n}\n\n/** The slice of `.dcs/seo.yaml` this audit needs. */\nexport interface HeadContractSeoConfig {\n global?: { titleTemplate?: string; defaultTitle?: string } & Record<string, unknown>\n pages?: Record<string, { title?: string } & Record<string, unknown>>\n}\n\n// =============================================================================\n// Exemptions and their LIVE claims (C-420)\n// =============================================================================\n\n/**\n * WHY EXEMPTIONS CARRY LIVE CLAIMS.\n *\n * An exemption used to be a sentence. A sentence is an assertion, and an\n * assertion nobody re-measures rots into a false premise that the audit then\n * defends: the measured case declared a host as a \"noindex cross-domain\n * handoff\", and every part of that was false in production — the host served\n * `index, follow`, a SELF-referential canonical, a 200 `robots.txt` that allows\n * every crawler, a sitemap and a full independent site. The audit was green\n * BECAUSE of the exemption, so the green was the bug.\n *\n * The discriminator is the exempted host's real response, not the bundle hash.\n * So an exemption that NAMES a host must now say what it expects that host to\n * do, and the caller must supply what the host actually did. A named host with\n * nothing checkable, or with nothing measured, is a VIOLATION — not a skip.\n *\n * This module still never touches the network: it takes observations. The\n * fetching lives in the runner (`cli/head-contract-audit.mjs`), the judging\n * lives here, and `parseHostProbeHtml` below is the shared, testable parser\n * between them so there is no second implementation to drift.\n */\nexport interface HeadContractExemptionExpectation {\n /** HTTP status, measured WITHOUT following redirects (a 301 is not a 200). */\n status?: number\n /** Substring that must appear in `<meta name=\"robots\">` (case-insensitive). */\n robots?: string\n /** Hostname of `<link rel=\"canonical\">` — the self-vs-cross-domain question. */\n canonicalHost?: string\n /** Substring that must appear in `<title>` (case-insensitive). */\n titleContains?: string\n}\n\nexport interface HeadContractExemptionRecord {\n /** Why this file cannot route its head through the factory. */\n reason: string\n /**\n * `host -> claims`. EVERY host the reason names must appear here, and every\n * entry must carry at least one claim, or the exemption is unprobed.\n */\n hosts?: Record<string, HeadContractExemptionExpectation>\n}\n\n/** A bare string is still a legal exemption — it just may not name a host. */\nexport type HeadContractExemptionValue = string | HeadContractExemptionRecord\n\n/** What a caller actually observed at a host. Never produced by this module. */\nexport interface HeadContractHostProbe {\n host: string\n /** `false` = the probe did not complete. A failed probe is never a pass. */\n ok: boolean\n error?: string\n status?: number\n robots?: string | null\n canonical?: string | null\n title?: string | null\n observedAt?: string\n}\n\nexport type HeadContractExemptionVerdict =\n /** Every claim agreed with the live response. */\n | 'live-true'\n /** The live response contradicts at least one claim. */\n | 'refuted'\n /** Names a host but nothing checkable reached the judge. */\n | 'unprobed'\n /** A probe was attempted and did not complete. */\n | 'probe-failed'\n /** Asserts nothing about any host — nothing to probe. */\n | 'no-host-claim'\n\nexport interface HeadContractExemptionCheck {\n host: string\n claim: keyof HeadContractExemptionExpectation\n expected: string\n actual: string\n pass: boolean\n}\n\nexport interface HeadContractExemptionAudit {\n file: string\n reason: string\n /** Hosts the PROSE names — the claim the author made whether or not they meant to. */\n hostsNamedInReason: string[]\n /** Hosts the author declared machine-checkable claims for. */\n hostsDeclared: string[]\n checks: HeadContractExemptionCheck[]\n verdict: HeadContractExemptionVerdict\n}\n\nexport interface HeadContractInput {\n files: HeadContractSourceFile[]\n seo: HeadContractSeoConfig | undefined\n /**\n * `path -> reason | record`. Declares a KNOWN foreign head writer so it stops\n * being a surprise. It is a declaration of debt, not a licence: P1 still\n * measures whether that writer agrees with the baked head, a stale entry is\n * itself a violation, and (C-420) any host the declaration names is measured\n * against its live response.\n */\n exemptions?: Record<string, HeadContractExemptionValue>\n /**\n * `host -> what that host actually did`, supplied by the caller. An exemption\n * that names a host and finds no observation here FAILS: \"not measured\" and\n * \"measured fine\" must never render the same.\n */\n hostProbes?: Record<string, HeadContractHostProbe>\n}\n\nexport interface HeadContractViolation {\n code: HeadContractViolationCode\n file: string\n line: number\n detail: string\n}\n\nexport interface HeadContractWarning {\n code: HeadContractWarningCode\n file: string\n detail: string\n}\n\nexport interface ForeignWriterSite {\n file: string\n line: number\n mechanism: 'useHead' | 'useSeoMeta' | 'document.title'\n exempted: boolean\n reason: string | null\n}\n\nexport interface HeadContractReport {\n /** Execution counts FIRST — a rail that did not run must not read as green. */\n scanned: number\n applyHeadCalls: number\n argumentFreeCalls: number\n /** Slugs written as string literals — checked against `.dcs/seo.yaml`. */\n useSeoSlugs: string[]\n /** Slugs composed at runtime — legal, UNCHECKED here, judged by P1. */\n dynamicSlugs: string[]\n foreignWriters: ForeignWriterSite[]\n /** `useHead({script})` blocks that ADD JSON-LD without restating a managed field. */\n additiveHeadCalls: number\n /**\n * EVERY declared exemption with its live verdict — dumped whether or not it\n * found anything, so \"0 refuted\" is a measurement of a listed set and not an\n * empty listing wearing a zero.\n */\n exemptionAudit: HeadContractExemptionAudit[]\n coverage: {\n /** Files scanned (the caller decides what counts as a routed view). */\n views: number\n /** Files that re-assert the head in some way. */\n asserting: number\n /** Files that write nothing — SPA navigation to them is stale. */\n silent: string[]\n }\n violations: HeadContractViolation[]\n warnings: HeadContractWarning[]\n ok: boolean\n}\n\nexport type HeadContractMode = 'error' | 'warn' | 'off'\n\nexport class HeadContractError extends Error {\n readonly report: HeadContractReport\n constructor(message: string, report: HeadContractReport) {\n super(message)\n this.name = 'HeadContractError'\n this.report = report\n }\n}\n\n/** Minimum characters an exemption reason must carry to count as a reason. */\nexport const MIN_EXEMPTION_REASON_LENGTH = 12\n\n// =============================================================================\n// Source scanning\n// =============================================================================\n\n/**\n * Blank out COMMENTS ONLY — line, block and HTML — tracking string/template\n * literals just well enough not to mistake a `https://…` inside a string for a\n * line comment.\n *\n * Replacement preserves LENGTH and NEWLINES (every removed character becomes a\n * space, newlines survive), so every offset and line number computed on the\n * result is still valid against the original file.\n *\n * WHY COMMENTS ONLY. Two hazards pull in opposite directions and the asymmetry\n * decides it:\n * - boogie-babies' PrivacyView.vue carries a docblock reading \"applyHead takes\n * NO arguments\". Scanning raw source reports it. So comments MUST go.\n * - Blanking string BODIES as well would let a regex literal containing a\n * quote (`/['\"]/`) swallow the following lines and HIDE a real violation.\n * A gate that silently misses is worse than one that occasionally shouts:\n * a false positive is loud and fixed in a minute; a false negative is\n * exactly the class this whole contract exists to kill.\n * So string bodies are left intact, and an `applyHead(` written inside a string\n * literal is deliberately reported.\n */\nexport function blankComments(source: string): string {\n const out = source.split('')\n const n = source.length\n let i = 0\n\n const blank = (from: number, to: number) => {\n for (let k = from; k < to && k < n; k += 1) {\n if (out[k] !== '\\n') out[k] = ' '\n }\n }\n\n while (i < n) {\n const c = source[i]\n const next = source[i + 1]\n\n // HTML comment (Vue SFC <template> / index.html)\n if (c === '<' && source.startsWith('<!--', i)) {\n const end = source.indexOf('-->', i + 4)\n const stop = end === -1 ? n : end + 3\n blank(i, stop)\n i = stop\n continue\n }\n\n // Block comment\n if (c === '/' && next === '*') {\n const end = source.indexOf('*/', i + 2)\n const stop = end === -1 ? n : end + 2\n blank(i, stop)\n i = stop\n continue\n }\n\n // Line comment\n if (c === '/' && next === '/') {\n let end = source.indexOf('\\n', i + 2)\n if (end === -1) end = n\n blank(i, end)\n i = end\n continue\n }\n\n // String / template literal — SKIPPED OVER, never blanked. Tracking it here\n // is only so a `//` inside a URL is not read as a line comment.\n if (c === '\"' || c === \"'\" || c === '`') {\n const quote = c\n let k = i + 1\n while (k < n) {\n if (source[k] === '\\\\') {\n k += 2\n continue\n }\n if (source[k] === quote) break\n // An unterminated single/double quote must not swallow the file.\n if (quote !== '`' && source[k] === '\\n') break\n k += 1\n }\n i = Math.min(k + 1, n)\n continue\n }\n\n i += 1\n }\n\n return out.join('')\n}\n\nfunction lineOf(source: string, index: number): number {\n let line = 1\n for (let i = 0; i < index && i < source.length; i += 1) {\n if (source[i] === '\\n') line += 1\n }\n return line\n}\n\n/** Call-shaped `applyHead(` — never the `const { applyHead } = …` destructure. */\nconst APPLY_HEAD_CALL = /(?<![.\\w$])applyHead\\s*\\(/g\n/** `useSEO(` — the first argument is then inspected by hand (it may not be a literal). */\nconst USE_SEO_CALL = /(?<![.\\w$])useSEO\\s*\\(\\s*/g\n\n/**\n * Read `useSEO`'s first argument.\n *\n * A dynamic route (`/blog/:slug`, `/topics/:topic`) cannot name a static slug —\n * it composes the per-route key the EMITTER uses. That is legal under the\n * contract and it is NOT statically checkable, so it is reported as dynamic and\n * handed to P1, which renders each real route and compares the two heads. What\n * is NOT legal is a dynamic route hand-building its own title string; that shows\n * up here as an override or a foreign writer like any other.\n */\nfunction readUseSeoArgument(\n source: string,\n from: number\n): { kind: 'static'; slug: string } | { kind: 'dynamic'; expression: string } {\n const opener = source[from]\n if (opener === \"'\" || opener === '\"') {\n const end = source.indexOf(opener, from + 1)\n if (end === -1) return { kind: 'dynamic', expression: source.slice(from, from + 40) }\n return { kind: 'static', slug: source.slice(from + 1, end).trim() }\n }\n if (opener === '`') {\n const end = source.indexOf('`', from + 1)\n if (end === -1) return { kind: 'dynamic', expression: source.slice(from, from + 40) }\n const body = source.slice(from + 1, end)\n return body.includes('${')\n ? { kind: 'dynamic', expression: body }\n : { kind: 'static', slug: body.trim() }\n }\n const end = source.indexOf(')', from)\n return { kind: 'dynamic', expression: source.slice(from, end === -1 ? from + 40 : end).trim() }\n}\n\nconst FOREIGN_WRITERS: Array<{ re: RegExp; mechanism: ForeignWriterSite['mechanism'] }> = [\n { re: /(?<![.\\w$])useHead\\s*\\(/g, mechanism: 'useHead' },\n { re: /(?<![.\\w$])useSeoMeta\\s*\\(/g, mechanism: 'useSeoMeta' },\n { re: /document\\s*\\.\\s*title\\s*=(?!=)/g, mechanism: 'document.title' },\n]\n\n/** Head keys whose value the contract reserves for `.dcs/seo.yaml`. */\nconst MANAGED_HEAD_KEYS = /(^|[{,\\s([])(title|titleTemplate|meta|link|templateParams)\\s*:/\n/** The one head key a page may legitimately add on its own. */\nconst ADDITIVE_HEAD_KEYS = /(^|[{,\\s([])script\\s*:/\n/** Cap so a runaway scan cannot walk the whole file. */\nconst ARG_SCAN_LIMIT = 6000\n\n/**\n * Is this `useHead(...)` call ADDITIVE-ONLY?\n *\n * A page may legitimately add JSON-LD that `seo.yaml` cannot express per route —\n * a per-post `BlogPosting`, for instance. `useHead({ script: [...] })` that sets\n * no `title`/`meta`/`link` adds a tag; it does not restate a managed one, and\n * treating it as a violation would push every blog template into the exemption\n * list. An allow-list padded with legal entries is an allow-list nobody reads,\n * so the discrimination belongs here, not in each site's exemption file.\n *\n * Conservative by construction: anything it cannot read as additive-only — a\n * spread, a variable, an unbalanced or over-long argument — is reported.\n */\nfunction isAdditiveOnlyHeadCall(code: string, argStart: number): boolean {\n let depth = 0\n let i = argStart\n const end = Math.min(code.length, argStart + ARG_SCAN_LIMIT)\n for (; i < end; i += 1) {\n const c = code[i]\n if (c === '(' || c === '{' || c === '[') depth += 1\n else if (c === ')' || c === '}' || c === ']') {\n depth -= 1\n if (depth === 0) break\n }\n }\n if (depth !== 0) return false // unbalanced or truncated — do not guess\n const arg = code.slice(argStart, i + 1)\n if (arg.includes('...')) return false // a spread can carry anything\n return ADDITIVE_HEAD_KEYS.test(arg) && !MANAGED_HEAD_KEYS.test(arg)\n}\n\n// =============================================================================\n// Exemption host claims — the live half (C-420)\n// =============================================================================\n\n/**\n * A hostname written in prose. The TLD suffix list is deliberate: a bare\n * `\\w+(\\.\\w+)+` also matches `.dcs/seo.yaml`, `HomeView.vue` and `useSEO().\n * applyHead`, which would turn every exemption into a false host claim.\n */\nconst HOSTNAME_IN_TEXT =\n /\\b(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+(?:com|net|org|io|dev|co|us|ai|app|site|xyz)\\b/gi\n\nfunction normalizeHost(value: string): string {\n return value\n .trim()\n .toLowerCase()\n .replace(/^https?:\\/\\//, '')\n .replace(/\\/.*$/, '')\n .replace(/\\.$/, '')\n}\n\n/** A bare string exemption is a record with no host claims. */\nexport function normalizeExemption(value: HeadContractExemptionValue): HeadContractExemptionRecord {\n if (typeof value === 'string') return { reason: value }\n return { reason: value?.reason ?? '', hosts: value?.hosts }\n}\n\n/** Every host the prose names, deduped and normalised. */\nexport function hostsNamedIn(reason: string): string[] {\n const found = reason.match(HOSTNAME_IN_TEXT) ?? []\n const out: string[] = []\n for (const raw of found) {\n const host = normalizeHost(raw)\n if (!out.includes(host)) out.push(host)\n }\n return out\n}\n\n/**\n * Pull the three head fields an exemption can make a claim about out of a live\n * response body. Shared by the runner and by this module's own tests so the\n * thing that fetches and the thing that judges cannot disagree about what a\n * `robots` meta is.\n */\nexport function parseHostProbeHtml(html: string): {\n robots: string | null\n canonical: string | null\n title: string | null\n} {\n const robots =\n /<meta[^>]+name\\s*=\\s*[\"']robots[\"'][^>]*>/i\n .exec(html)?.[0]\n ?.match(/content\\s*=\\s*[\"']([^\"']*)[\"']/i)?.[1]\n ?.trim() ?? null\n const canonical =\n /<link[^>]+rel\\s*=\\s*[\"']canonical[\"'][^>]*>/i\n .exec(html)?.[0]\n ?.match(/href\\s*=\\s*[\"']([^\"']*)[\"']/i)?.[1]\n ?.trim() ?? null\n const title = /<title[^>]*>([\\s\\S]*?)<\\/title>/i.exec(html)?.[1]?.trim() ?? null\n return { robots, canonical, title }\n}\n\nfunction hostOfUrl(url: string): string {\n const match = /^(?:https?:)?\\/\\/([^/?#]+)/i.exec(url.trim())\n if (match) return normalizeHost(match[1])\n return normalizeHost(url)\n}\n\nfunction claimChecks(\n host: string,\n expect: HeadContractExemptionExpectation,\n probe: HeadContractHostProbe\n): HeadContractExemptionCheck[] {\n const checks: HeadContractExemptionCheck[] = []\n if (typeof expect.status === 'number') {\n checks.push({\n host,\n claim: 'status',\n expected: String(expect.status),\n actual: probe.status === undefined ? '(none)' : String(probe.status),\n pass: probe.status === expect.status,\n })\n }\n if (typeof expect.robots === 'string') {\n const actual = probe.robots ?? '(absent)'\n checks.push({\n host,\n claim: 'robots',\n expected: `contains \"${expect.robots}\"`,\n actual,\n pass: actual.toLowerCase().includes(expect.robots.toLowerCase()),\n })\n }\n if (typeof expect.canonicalHost === 'string') {\n const actual = probe.canonical ? hostOfUrl(probe.canonical) : '(absent)'\n checks.push({\n host,\n claim: 'canonicalHost',\n expected: normalizeHost(expect.canonicalHost),\n actual,\n pass: actual === normalizeHost(expect.canonicalHost),\n })\n }\n if (typeof expect.titleContains === 'string') {\n const actual = probe.title ?? '(absent)'\n checks.push({\n host,\n claim: 'titleContains',\n expected: `contains \"${expect.titleContains}\"`,\n actual,\n pass: actual.toLowerCase().includes(expect.titleContains.toLowerCase()),\n })\n }\n return checks\n}\n\n/**\n * Judge every exemption against the live behaviour of the host it names.\n *\n * Four ways to fail and only one way to pass, because the failure this exists\n * to catch is a green:\n * - the prose names a host that carries no machine-checkable claim\n * - a declared host asserts nothing (a claim block with no claims)\n * - a declared host has no observation (nothing was measured)\n * - an observation disagrees with a claim, or the probe itself did not run\n * Pure: it fetches nothing and reads no files.\n */\nexport function auditExemptionHosts(\n exemptions: Record<string, HeadContractExemptionValue>,\n hostProbes: Record<string, HeadContractHostProbe>\n): { audits: HeadContractExemptionAudit[]; violations: HeadContractViolation[] } {\n const audits: HeadContractExemptionAudit[] = []\n const violations: HeadContractViolation[] = []\n\n // WORST WINS, and \"a claim was contradicted\" is worse than \"a claim was\n // missing\": a multi-host exemption with one dead premise must summarise as\n // REFUTED, or the headline count disagrees with the violations underneath it.\n const RANK: Record<HeadContractExemptionVerdict, number> = {\n refuted: 4,\n 'probe-failed': 3,\n unprobed: 2,\n 'live-true': 1,\n 'no-host-claim': 0,\n }\n\n for (const file of Object.keys(exemptions)) {\n const record = normalizeExemption(exemptions[file])\n const named = hostsNamedIn(record.reason)\n const declaredMap = record.hosts ?? {}\n const declared = Object.keys(declaredMap).map(normalizeHost)\n const checks: HeadContractExemptionCheck[] = []\n let verdict: HeadContractExemptionVerdict = 'no-host-claim'\n const escalate = (next: HeadContractExemptionVerdict) => {\n if (RANK[next] > RANK[verdict]) verdict = next\n }\n\n const undeclared = named.filter((h) => !declared.includes(h))\n if (undeclared.length > 0) {\n escalate('unprobed')\n violations.push({\n code: 'unprobed-exemption',\n file,\n line: 0,\n detail:\n `This exemption's reason names ${undeclared.join(', ')} but declares no claim about ` +\n `it, so nothing checks whether the host still behaves the way the reason says. ` +\n `Add \"hosts\": { \"${undeclared[0]}\": { … } } with at least one of status / robots / ` +\n `canonicalHost / titleContains. An exemption that names a host and is never ` +\n `measured against it is an assertion, not a finding.`,\n })\n }\n\n for (const rawHost of Object.keys(declaredMap)) {\n const host = normalizeHost(rawHost)\n const expect = declaredMap[rawHost] ?? {}\n const claimCount = (\n ['status', 'robots', 'canonicalHost', 'titleContains'] as const\n ).filter((k) => expect[k] !== undefined).length\n\n if (claimCount === 0) {\n escalate('unprobed')\n violations.push({\n code: 'unprobed-exemption',\n file,\n line: 0,\n detail:\n `The exemption declares ${host} but asserts nothing about it. A host entry with ` +\n `no claim is probed into a guaranteed pass — the vacuous green this rail exists ` +\n `to refuse. State what the host must do: status / robots / canonicalHost / ` +\n `titleContains.`,\n })\n continue\n }\n\n const probe = hostProbes[host]\n if (!probe) {\n escalate('unprobed')\n violations.push({\n code: 'unprobed-exemption',\n file,\n line: 0,\n detail:\n `The exemption claims ${claimCount} thing(s) about ${host} and NO observation of ` +\n `that host reached the audit. \"Not measured\" must never render as \"measured ` +\n `fine\": run the audit with host probing enabled, or delete the claim.`,\n })\n continue\n }\n\n if (!probe.ok) {\n escalate('probe-failed')\n violations.push({\n code: 'exemption-probe-failed',\n file,\n line: 0,\n detail:\n `The probe of ${host} did not complete (${probe.error ?? 'no error recorded'}), so ` +\n `this exemption's premise is UNVERIFIED. A probe that could not run is a failure, ` +\n `not a skip — the alternative is an allow-list that goes green whenever the ` +\n `network does.`,\n })\n continue\n }\n\n const hostChecks = claimChecks(host, expect, probe)\n checks.push(...hostChecks)\n for (const check of hostChecks.filter((c) => !c.pass)) {\n escalate('refuted')\n violations.push({\n code: 'exemption-claim-refuted',\n file,\n line: 0,\n detail:\n `DEAD PREMISE. The exemption asserts ${check.host} ${check.claim} ` +\n `${check.expected}; the live host answered \"${check.actual}\". The exemption is ` +\n `why this file passes, so the pass rests on something production stopped doing. ` +\n `Re-word it to what is true, or delete it and the writer it protects.`,\n })\n }\n if (hostChecks.length > 0 && hostChecks.every((c) => c.pass)) escalate('live-true')\n }\n\n audits.push({\n file,\n reason: record.reason,\n hostsNamedInReason: named,\n hostsDeclared: declared,\n checks,\n verdict,\n })\n }\n\n return { audits, violations }\n}\n\n// =============================================================================\n// The audit\n// =============================================================================\n\n/**\n * Audit a set of source files against the head-authority contract.\n *\n * Site-agnostic by construction: there is no site name, no path convention and\n * no per-shape branch anywhere in this function. The three measured shapes\n * (KEPT / boogie-babies / bryans) go through the identical call.\n */\nexport function auditHeadContract(input: HeadContractInput): HeadContractReport {\n const files = input.files ?? []\n const exemptions = input.exemptions ?? {}\n const violations: HeadContractViolation[] = []\n const warnings: HeadContractWarning[] = []\n const foreignWriters: ForeignWriterSite[] = []\n const useSeoSlugs: string[] = []\n const dynamicSlugs: string[] = []\n const silent: string[] = []\n\n let applyHeadCalls = 0\n let additiveHeadCalls = 0\n let argumentFreeCalls = 0\n let asserting = 0\n\n for (const { path, source } of files) {\n const code = blankComments(source)\n let fileAsserts = false\n\n // ── V1 — applyHead must take no arguments ───────────────────────────────\n APPLY_HEAD_CALL.lastIndex = 0\n let m: RegExpExecArray | null\n while ((m = APPLY_HEAD_CALL.exec(code)) !== null) {\n applyHeadCalls += 1\n fileAsserts = true\n const rest = code.slice(m.index + m[0].length)\n if (/^\\s*\\)/.test(rest)) {\n argumentFreeCalls += 1\n } else {\n const preview = source\n .slice(m.index, m.index + 140)\n .replace(/\\s+/g, ' ')\n .trim()\n violations.push({\n code: 'override-argument',\n file: path,\n line: lineOf(source, m.index),\n detail:\n `applyHead() must take no arguments — .dcs/seo.yaml is the only writer of ` +\n `title/description/keywords/canonical/OG/Twitter/JSON-LD. Move the value there ` +\n `and delete the argument. Found: ${preview}…`,\n })\n }\n }\n\n // ── V3 — every STATIC useSEO slug must resolve to a declared page ───────\n USE_SEO_CALL.lastIndex = 0\n while ((m = USE_SEO_CALL.exec(code)) !== null) {\n fileAsserts = true\n const arg = readUseSeoArgument(source, m.index + m[0].length)\n if (arg.kind === 'dynamic') {\n if (!dynamicSlugs.includes(arg.expression)) dynamicSlugs.push(arg.expression)\n warnings.push({\n code: 'dynamic-slug',\n file: path,\n detail:\n `useSEO(${arg.expression.slice(0, 60)}) resolves its page key at runtime, so this ` +\n `audit cannot check it against .dcs/seo.yaml. That is legal — a dynamic route must ` +\n `resolve the SAME per-route key the emitter uses — but it is UNCHECKED HERE. P1 ` +\n `(baked vs rendered, on a real build of every route) is the rail that judges it.`,\n })\n continue\n }\n const slug = arg.slug\n // A slug seen in an earlier file has already been judged; reporting it\n // again would multiply one seo.yaml gap into many identical findings.\n if (!slug || useSeoSlugs.includes(slug)) continue\n useSeoSlugs.push(slug)\n const page = input.seo?.pages?.[slug]\n if (!page || typeof page.title !== 'string' || page.title.trim() === '') {\n violations.push({\n code: 'undeclared-slug',\n file: path,\n line: lineOf(source, m.index),\n detail:\n `useSEO('${slug}') has no pages.${slug}.title in .dcs/seo.yaml. At runtime it ` +\n `collapses to global.defaultTitle while the build-time emitter falls back to the ` +\n `pages.yaml route title — the same baked-vs-rendered divergence wearing a ` +\n `different hat. Declare the entry.`,\n })\n }\n }\n\n // ── V2 — no writer outside the factory ──────────────────────────────────\n for (const { re, mechanism } of FOREIGN_WRITERS) {\n re.lastIndex = 0\n while ((m = re.exec(code)) !== null) {\n fileAsserts = true\n\n // Additive JSON-LD is not a second writer — see isAdditiveOnlyHeadCall.\n if (mechanism === 'useHead' && isAdditiveOnlyHeadCall(code, m.index + m[0].length - 1)) {\n additiveHeadCalls += 1\n continue\n }\n\n const reason = Object.prototype.hasOwnProperty.call(exemptions, path)\n ? normalizeExemption(exemptions[path]).reason\n : null\n const exempted = typeof reason === 'string' && reason.trim().length >= MIN_EXEMPTION_REASON_LENGTH\n foreignWriters.push({\n file: path,\n line: lineOf(source, m.index),\n mechanism,\n exempted,\n reason: reason ?? null,\n })\n if (exempted) continue\n if (reason !== null) {\n violations.push({\n code: 'empty-exemption-reason',\n file: path,\n line: lineOf(source, m.index),\n detail:\n `An exemption for ${path} exists but records no reason (needs >= ` +\n `${MIN_EXEMPTION_REASON_LENGTH} characters). An undocumented exemption is ` +\n `indistinguishable from an accident.`,\n })\n continue\n }\n violations.push({\n code: 'foreign-head-writer',\n file: path,\n line: lineOf(source, m.index),\n detail:\n `${mechanism} writes the head outside the .dcs/seo.yaml factory. Route the value ` +\n `through seo.yaml + useSEO().applyHead(), or declare this file as an exemption ` +\n `with the reason it genuinely cannot. Declaring it does NOT excuse it from P1: ` +\n `the baked head and the rendered head must still agree.`,\n })\n }\n }\n\n if (fileAsserts) asserting += 1\n else silent.push(path)\n }\n\n // ── V4 (warn) — a view that never re-asserts is stale after the first click ─\n for (const file of silent) {\n warnings.push({\n code: 'uncovered-route',\n file,\n detail:\n `This view never re-asserts the head, so an in-app navigation to it leaves the ` +\n `PREVIOUS route's title/description/canonical in the DOM. The baked head is correct ` +\n `exactly once — on the document that was fetched. Reported, not enforced: the fix is ` +\n `a router-level re-assert in the platform, not eleven views remembering.`,\n })\n }\n\n // ── Exemption hygiene — anti-rot (source) AND anti-dead-premise (live) ──\n // The stale check asks \"does this file still violate?\"; the host audit asks\n // \"does the host this exemption NAMES still behave the way it claims?\". The\n // measured failure passed the first and would have failed the second.\n const hostAudit = auditExemptionHosts(exemptions, input.hostProbes ?? {})\n violations.push(...hostAudit.violations)\n\n const violatingFiles = new Set(foreignWriters.map((f) => f.file))\n for (const path of Object.keys(exemptions)) {\n if (!violatingFiles.has(path)) {\n violations.push({\n code: 'stale-exemption',\n file: path,\n line: 0,\n detail:\n `An exemption is declared for ${path} but it writes no head outside the factory. ` +\n `Delete the exemption — a rotting allow-list is how the next real one gets waved ` +\n `through.`,\n })\n }\n }\n\n // ── Execution assertions — a check that checked nothing is a FAILURE ─────\n if (files.length === 0) {\n violations.push({\n code: 'scan-empty',\n file: '(none)',\n line: 0,\n detail:\n 'The head-contract audit SCANNED NOTHING. Zero files reached it, so it proved ' +\n 'nothing about this site. The file walk is broken, not the codebase.',\n })\n }\n if (!input.seo || !input.seo.pages || Object.keys(input.seo.pages).length === 0) {\n violations.push({\n code: 'no-seo-config',\n file: '.dcs/seo.yaml',\n line: 0,\n detail:\n 'No .dcs/seo.yaml pages were supplied. Authority cannot be established without the ' +\n 'authority file, so every slug check silently passes — the vacuous-green shape this ' +\n 'audit exists to refuse.',\n })\n }\n\n return {\n scanned: files.length,\n applyHeadCalls,\n argumentFreeCalls,\n useSeoSlugs,\n dynamicSlugs,\n foreignWriters,\n additiveHeadCalls,\n exemptionAudit: hostAudit.audits,\n coverage: { views: files.length, asserting, silent },\n violations,\n warnings,\n ok: violations.length === 0,\n }\n}\n\n/**\n * Dump the exemption set with a per-entry live verdict.\n *\n * Printed on EVERY run, including the empty one. \"0 refuted\" out of an unlisted\n * set is indistinguishable from a rail that inspected nothing, so the set is\n * always enumerated and the empty case says so in words.\n */\nexport function formatExemptionAudit(report: HeadContractReport): string[] {\n const audits = report.exemptionAudit ?? []\n const lines: string[] = []\n const count = (v: HeadContractExemptionVerdict) => audits.filter((a) => a.verdict === v).length\n\n if (audits.length === 0) {\n lines.push(\n `[head-contract] exemptions: 0 declared — the allow-list is EMPTY, not unchecked ` +\n `(${report.scanned} file(s) scanned, ${report.foreignWriters.length} foreign head ` +\n `writer(s) found, so there was nothing to declare).`\n )\n return lines\n }\n\n lines.push(\n `[head-contract] exemptions: ${audits.length} declared — ${count('live-true')} live-true, ` +\n `${count('refuted')} REFUTED, ${count('unprobed')} unprobed, ` +\n `${count('probe-failed')} probe-failed, ${count('no-host-claim')} host-free`\n )\n for (const audit of audits) {\n const hosts = audit.hostsDeclared.length > 0 ? audit.hostsDeclared.join(', ') : '(no host declared)'\n lines.push(` ${audit.verdict.toUpperCase()} ${audit.file} [${hosts}]`)\n if (audit.hostsNamedInReason.length > 0) {\n lines.push(` reason names: ${audit.hostsNamedInReason.join(', ')}`)\n }\n for (const check of audit.checks) {\n lines.push(\n ` ${check.pass ? 'ok ' : 'FAIL'} ${check.host} ${check.claim}: ` +\n `expected ${check.expected}, live \"${check.actual}\"`\n )\n }\n if (audit.checks.length === 0 && audit.verdict !== 'no-host-claim') {\n lines.push(' (no live check ran — see the violations above)')\n }\n }\n return lines\n}\n\n/** Human-readable report. Execution counts are printed FIRST, always. */\nexport function formatHeadContractReport(report: HeadContractReport): string {\n const lines: string[] = []\n lines.push(\n `[head-contract] scanned ${report.scanned} file(s); ` +\n `${report.applyHeadCalls} applyHead call(s), ${report.argumentFreeCalls} argument-free; ` +\n `${report.useSeoSlugs.length} static useSEO slug(s), ` +\n `${report.dynamicSlugs.length} dynamic (unchecked here — P1 judges those); ` +\n `${report.foreignWriters.length} foreign head writer(s) ` +\n `(${report.foreignWriters.filter((f) => f.exempted).length} declared); ` +\n `${report.additiveHeadCalls} additive JSON-LD useHead call(s)`\n )\n lines.push(\n `[head-contract] SPA coverage: ${report.coverage.asserting}/${report.coverage.views} view(s) ` +\n `re-assert the head; ${report.coverage.silent.length} silent`\n )\n if (report.scanned === 0) {\n lines.push('[head-contract] SCANNED NOTHING this run — this is a failure, not a pass.')\n }\n lines.push(...formatExemptionAudit(report))\n for (const v of report.violations) {\n lines.push(` VIOLATION ${v.code} ${v.file}${v.line ? `:${v.line}` : ''} — ${v.detail}`)\n }\n for (const w of report.warnings) {\n lines.push(` warn ${w.code} ${w.file} — ${w.detail}`)\n }\n if (report.violations.length === 0) {\n lines.push('[head-contract] PASS — .dcs/seo.yaml is the only writer of the managed head.')\n }\n return lines.join('\\n')\n}\n\n/**\n * Assert the contract. `error` throws; `warn` prints; `off` is a no-op — except\n * that `scan-empty` and `no-seo-config` are NEVER downgraded, because \"the rail\n * did not run\" must not be silenceable by the mode that silences findings.\n */\nexport function assertHeadContract(\n input: HeadContractInput,\n mode: HeadContractMode = 'error',\n log: (msg: string) => void = console.warn\n): HeadContractReport {\n const report = auditHeadContract(input)\n const notRun = report.violations.filter(\n (v) => v.code === 'scan-empty' || v.code === 'no-seo-config'\n )\n\n if (notRun.length > 0) {\n throw new HeadContractError(\n `${formatHeadContractReport(report)}\\n\\nThe head-contract audit did not run against ` +\n `anything it could judge. Fix the inputs before reading this as a pass.`,\n report\n )\n }\n\n if (mode === 'off') return report\n if (report.violations.length === 0) return report\n\n if (mode === 'warn') {\n log(formatHeadContractReport(report))\n log('[head-contract] in error mode the above would be RED.')\n return report\n }\n\n throw new HeadContractError(formatHeadContractReport(report), report)\n}\n"]}
1
+ {"version":3,"sources":["../src/seo/headContract.ts"],"names":["end"],"mappings":"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","file":"chunk-OGAJX4KM.js","sourcesContent":["/**\n * THE HEAD-AUTHORITY CONTRACT (C-356) — a source-level audit.\n *\n * WHY THIS EXISTS. One undefined contract produced two OPPOSITE production\n * failures on the same shared composable, measured a day apart:\n *\n * KEPT 28 `applyHead({…})` callers OVERWROTE the baked head.\n * 93 title/description divergences across 49 routes — 100% of\n * routes served one <title> to a non-JS AI crawler and a\n * different one to Google and every human (C-338 matrix,\n * fixed C-341: 51/51, zero divergent).\n * boogie-babies 2 callers, 9 of 11 views that write NOTHING. Hard navigation\n * is correct; the first in-app click leaves the previous\n * route's title/description/canonical in the DOM (measured:\n * /pricing -> /parties still claims canonical /pricing).\n * just-posh 17 raw `useHead({title, meta, link})` blocks that never touch\n * the composable at all — 27 divergences, the fleet's second\n * largest. A contract about `applyHead` alone would not see it.\n *\n * THE CONTRACT, in one line: `.dcs/seo.yaml` is the ONLY writer of the managed\n * head fields, and it must be re-asserted on EVERY route, on EVERY navigation.\n * Full text + reasoning: `.docs/plans/dynamic-site-resolution/README.md`\n * § \"The head-authority contract (C-356)\".\n *\n * WHAT THIS MODULE PROVES AND WHAT IT DOES NOT.\n * - It proves there is exactly ONE WRITER in the source. That is authority.\n * - It does NOT prove the writer told the truth. That is P1\n * (`headHonesty.ts`), which compares the baked head to the rendered head on\n * a real build. Neither replaces the other, and an exemption here buys no\n * amnesty there.\n *\n * Deliberately framework-free and fs-free: it takes source strings, so the same\n * function runs in the package's own vitest fixtures, in a site's test script,\n * and in `cli/head-contract-audit.mjs` against a real repo. There is no second\n * implementation to drift.\n */\n\nimport type { UseSeoReturn } from '../types/seo'\n\n// =============================================================================\n// The compile-time half of the enforcement\n// =============================================================================\n\n/**\n * COMPILE-TIME PIN: `applyHead` must take ZERO parameters.\n *\n * `packages/cms/tsconfig.json` excludes `**\\/*.test.ts`, so a `@ts-expect-error`\n * written in a test file is never evaluated by `pnpm type-check` — it would be a\n * comment that looks like a gate. This pin lives in a checked source file\n * instead: re-add a parameter to `UseSeoReturn['applyHead']` and the assignment\n * below stops compiling, which reds `type-check` in this package and, through\n * the published `.d.ts`, in every site that runs one.\n */\nexport type ApplyHeadTakesNoArguments = Parameters<UseSeoReturn['applyHead']> extends []\n ? true\n : false\n\nexport const APPLY_HEAD_TAKES_NO_ARGUMENTS: ApplyHeadTakesNoArguments = true\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/** Codes that FAIL the contract. */\nexport type HeadContractViolationCode =\n /** `applyHead({…})` — a second writer for a managed field. Never exemptible. */\n | 'override-argument'\n /** `useSEO('x')` where `.dcs/seo.yaml` has no `pages.x.title`. Never exemptible. */\n | 'undeclared-slug'\n /** `useHead` / `useSeoMeta` / `document.title =` — a writer outside the factory. */\n | 'foreign-head-writer'\n /** An exemption whose file no longer violates anything (anti-rot). */\n | 'stale-exemption'\n /** An exemption with no real reason recorded. */\n | 'empty-exemption-reason'\n /** An exemption that names a host but cannot be checked against it (C-420). */\n | 'unprobed-exemption'\n /** A live probe contradicts what the exemption asserts about its host (C-420). */\n | 'exemption-claim-refuted'\n /** The probe of an exemption's host did not complete — never a pass (C-420). */\n | 'exemption-probe-failed'\n /** The audit scanned no files — a pass that checked nothing is not a pass. */\n | 'scan-empty'\n /** No `.dcs/seo.yaml` was supplied, so authority cannot be established. */\n | 'no-seo-config'\n\n/** Codes that are REPORTED but do not fail. */\nexport type HeadContractWarningCode =\n /** A view that never re-asserts the head; SPA navigation to it is stale. */\n | 'uncovered-route'\n /** `useSEO(`blog-${slug}`)` — legal, but only P1 can judge it. */\n | 'dynamic-slug'\n\nexport interface HeadContractSourceFile {\n /** Path as the caller wants it reported (and as exemptions key on). */\n path: string\n source: string\n}\n\n/** The slice of `.dcs/seo.yaml` this audit needs. */\nexport interface HeadContractSeoConfig {\n global?: { titleTemplate?: string; defaultTitle?: string } & Record<string, unknown>\n pages?: Record<string, { title?: string } & Record<string, unknown>>\n}\n\n// =============================================================================\n// Exemptions and their LIVE claims (C-420)\n// =============================================================================\n\n/**\n * WHY EXEMPTIONS CARRY LIVE CLAIMS.\n *\n * An exemption used to be a sentence. A sentence is an assertion, and an\n * assertion nobody re-measures rots into a false premise that the audit then\n * defends: the measured case declared a host as a \"noindex cross-domain\n * handoff\", and every part of that was false in production — the host served\n * `index, follow`, a SELF-referential canonical, a 200 `robots.txt` that allows\n * every crawler, a sitemap and a full independent site. The audit was green\n * BECAUSE of the exemption, so the green was the bug.\n *\n * The discriminator is the exempted host's real response, not the bundle hash.\n * So an exemption that NAMES a host must now say what it expects that host to\n * do, and the caller must supply what the host actually did. A named host with\n * nothing checkable, or with nothing measured, is a VIOLATION — not a skip.\n *\n * This module still never touches the network: it takes observations. The\n * fetching lives in the runner (`cli/head-contract-audit.mjs`), the judging\n * lives here, and `parseHostProbeHtml` below is the shared, testable parser\n * between them so there is no second implementation to drift.\n */\nexport interface HeadContractExemptionExpectation {\n /** HTTP status, measured WITHOUT following redirects (a 301 is not a 200). */\n status?: number\n /** Substring that must appear in `<meta name=\"robots\">` (case-insensitive). */\n robots?: string\n /** Hostname of `<link rel=\"canonical\">` — the self-vs-cross-domain question. */\n canonicalHost?: string\n /** Substring that must appear in `<title>` (case-insensitive). */\n titleContains?: string\n}\n\nexport interface HeadContractExemptionRecord {\n /** Why this file cannot route its head through the factory. */\n reason: string\n /**\n * `host -> claims`. EVERY host the reason names must appear here, and every\n * entry must carry at least one claim, or the exemption is unprobed.\n */\n hosts?: Record<string, HeadContractExemptionExpectation>\n}\n\n/** A bare string is still a legal exemption — it just may not name a host. */\nexport type HeadContractExemptionValue = string | HeadContractExemptionRecord\n\n/** What a caller actually observed at a host. Never produced by this module. */\nexport interface HeadContractHostProbe {\n host: string\n /** `false` = the probe did not complete. A failed probe is never a pass. */\n ok: boolean\n error?: string\n status?: number\n robots?: string | null\n canonical?: string | null\n title?: string | null\n observedAt?: string\n}\n\nexport type HeadContractExemptionVerdict =\n /** Every claim agreed with the live response. */\n | 'live-true'\n /** The live response contradicts at least one claim. */\n | 'refuted'\n /** Names a host but nothing checkable reached the judge. */\n | 'unprobed'\n /** A probe was attempted and did not complete. */\n | 'probe-failed'\n /** Asserts nothing about any host — nothing to probe. */\n | 'no-host-claim'\n\nexport interface HeadContractExemptionCheck {\n host: string\n claim: keyof HeadContractExemptionExpectation\n expected: string\n actual: string\n pass: boolean\n}\n\nexport interface HeadContractExemptionAudit {\n file: string\n reason: string\n /** Hosts the PROSE names — the claim the author made whether or not they meant to. */\n hostsNamedInReason: string[]\n /** Hosts the author declared machine-checkable claims for. */\n hostsDeclared: string[]\n checks: HeadContractExemptionCheck[]\n verdict: HeadContractExemptionVerdict\n}\n\nexport interface HeadContractInput {\n files: HeadContractSourceFile[]\n seo: HeadContractSeoConfig | undefined\n /**\n * `path -> reason | record`. Declares a KNOWN foreign head writer so it stops\n * being a surprise. It is a declaration of debt, not a licence: P1 still\n * measures whether that writer agrees with the baked head, a stale entry is\n * itself a violation, and (C-420) any host the declaration names is measured\n * against its live response.\n */\n exemptions?: Record<string, HeadContractExemptionValue>\n /**\n * `host -> what that host actually did`, supplied by the caller. An exemption\n * that names a host and finds no observation here FAILS: \"not measured\" and\n * \"measured fine\" must never render the same.\n */\n hostProbes?: Record<string, HeadContractHostProbe>\n}\n\nexport interface HeadContractViolation {\n code: HeadContractViolationCode\n file: string\n line: number\n detail: string\n}\n\nexport interface HeadContractWarning {\n code: HeadContractWarningCode\n file: string\n detail: string\n}\n\nexport interface ForeignWriterSite {\n file: string\n line: number\n mechanism: 'useHead' | 'useSeoMeta' | 'document.title'\n exempted: boolean\n reason: string | null\n}\n\nexport interface HeadContractReport {\n /** Execution counts FIRST — a rail that did not run must not read as green. */\n scanned: number\n applyHeadCalls: number\n argumentFreeCalls: number\n /** Slugs written as string literals — checked against `.dcs/seo.yaml`. */\n useSeoSlugs: string[]\n /** Slugs composed at runtime — legal, UNCHECKED here, judged by P1. */\n dynamicSlugs: string[]\n foreignWriters: ForeignWriterSite[]\n /** `useHead({script})` blocks that ADD JSON-LD without restating a managed field. */\n additiveHeadCalls: number\n /**\n * EVERY declared exemption with its live verdict — dumped whether or not it\n * found anything, so \"0 refuted\" is a measurement of a listed set and not an\n * empty listing wearing a zero.\n */\n exemptionAudit: HeadContractExemptionAudit[]\n coverage: {\n /** Files scanned (the caller decides what counts as a routed view). */\n views: number\n /** Files that re-assert the head in some way. */\n asserting: number\n /** Files that write nothing — SPA navigation to them is stale. */\n silent: string[]\n }\n violations: HeadContractViolation[]\n warnings: HeadContractWarning[]\n ok: boolean\n}\n\nexport type HeadContractMode = 'error' | 'warn' | 'off'\n\nexport class HeadContractError extends Error {\n readonly report: HeadContractReport\n constructor(message: string, report: HeadContractReport) {\n super(message)\n this.name = 'HeadContractError'\n this.report = report\n }\n}\n\n/** Minimum characters an exemption reason must carry to count as a reason. */\nexport const MIN_EXEMPTION_REASON_LENGTH = 12\n\n// =============================================================================\n// Source scanning\n// =============================================================================\n\n/**\n * Blank out COMMENTS ONLY — line, block and HTML — tracking string/template\n * literals just well enough not to mistake a `https://…` inside a string for a\n * line comment.\n *\n * Replacement preserves LENGTH and NEWLINES (every removed character becomes a\n * space, newlines survive), so every offset and line number computed on the\n * result is still valid against the original file.\n *\n * WHY COMMENTS ONLY. Two hazards pull in opposite directions and the asymmetry\n * decides it:\n * - boogie-babies' PrivacyView.vue carries a docblock reading \"applyHead takes\n * NO arguments\". Scanning raw source reports it. So comments MUST go.\n * - Blanking string BODIES as well would let a regex literal containing a\n * quote (`/['\"]/`) swallow the following lines and HIDE a real violation.\n * A gate that silently misses is worse than one that occasionally shouts:\n * a false positive is loud and fixed in a minute; a false negative is\n * exactly the class this whole contract exists to kill.\n * So string bodies are left intact, and an `applyHead(` written inside a string\n * literal is deliberately reported.\n */\nexport function blankComments(source: string): string {\n const out = source.split('')\n const n = source.length\n let i = 0\n\n const blank = (from: number, to: number) => {\n for (let k = from; k < to && k < n; k += 1) {\n if (out[k] !== '\\n') out[k] = ' '\n }\n }\n\n while (i < n) {\n const c = source[i]\n const next = source[i + 1]\n\n // HTML comment (Vue SFC <template> / index.html)\n if (c === '<' && source.startsWith('<!--', i)) {\n const end = source.indexOf('-->', i + 4)\n const stop = end === -1 ? n : end + 3\n blank(i, stop)\n i = stop\n continue\n }\n\n // Block comment\n if (c === '/' && next === '*') {\n const end = source.indexOf('*/', i + 2)\n const stop = end === -1 ? n : end + 2\n blank(i, stop)\n i = stop\n continue\n }\n\n // Line comment\n if (c === '/' && next === '/') {\n let end = source.indexOf('\\n', i + 2)\n if (end === -1) end = n\n blank(i, end)\n i = end\n continue\n }\n\n // String / template literal — SKIPPED OVER, never blanked. Tracking it here\n // is only so a `//` inside a URL is not read as a line comment.\n if (c === '\"' || c === \"'\" || c === '`') {\n const quote = c\n let k = i + 1\n while (k < n) {\n if (source[k] === '\\\\') {\n k += 2\n continue\n }\n if (source[k] === quote) break\n // An unterminated single/double quote must not swallow the file.\n if (quote !== '`' && source[k] === '\\n') break\n k += 1\n }\n i = Math.min(k + 1, n)\n continue\n }\n\n i += 1\n }\n\n return out.join('')\n}\n\nfunction lineOf(source: string, index: number): number {\n let line = 1\n for (let i = 0; i < index && i < source.length; i += 1) {\n if (source[i] === '\\n') line += 1\n }\n return line\n}\n\n/** Call-shaped `applyHead(` — never the `const { applyHead } = …` destructure. */\nconst APPLY_HEAD_CALL = /(?<![.\\w$])applyHead\\s*\\(/g\n/** `useSEO(` — the first argument is then inspected by hand (it may not be a literal). */\nconst USE_SEO_CALL = /(?<![.\\w$])useSEO\\s*\\(\\s*/g\n\n/**\n * Read `useSEO`'s first argument.\n *\n * A dynamic route (`/blog/:slug`, `/topics/:topic`) cannot name a static slug —\n * it composes the per-route key the EMITTER uses. That is legal under the\n * contract and it is NOT statically checkable, so it is reported as dynamic and\n * handed to P1, which renders each real route and compares the two heads. What\n * is NOT legal is a dynamic route hand-building its own title string; that shows\n * up here as an override or a foreign writer like any other.\n */\nfunction readUseSeoArgument(\n source: string,\n from: number\n): { kind: 'static'; slug: string } | { kind: 'dynamic'; expression: string } {\n const opener = source[from]\n if (opener === \"'\" || opener === '\"') {\n const end = source.indexOf(opener, from + 1)\n if (end === -1) return { kind: 'dynamic', expression: source.slice(from, from + 40) }\n return { kind: 'static', slug: source.slice(from + 1, end).trim() }\n }\n if (opener === '`') {\n const end = source.indexOf('`', from + 1)\n if (end === -1) return { kind: 'dynamic', expression: source.slice(from, from + 40) }\n const body = source.slice(from + 1, end)\n return body.includes('${')\n ? { kind: 'dynamic', expression: body }\n : { kind: 'static', slug: body.trim() }\n }\n const end = source.indexOf(')', from)\n return { kind: 'dynamic', expression: source.slice(from, end === -1 ? from + 40 : end).trim() }\n}\n\nconst FOREIGN_WRITERS: Array<{ re: RegExp; mechanism: ForeignWriterSite['mechanism'] }> = [\n { re: /(?<![.\\w$])useHead\\s*\\(/g, mechanism: 'useHead' },\n { re: /(?<![.\\w$])useSeoMeta\\s*\\(/g, mechanism: 'useSeoMeta' },\n { re: /document\\s*\\.\\s*title\\s*=(?!=)/g, mechanism: 'document.title' },\n]\n\n/** Head keys whose value the contract reserves for `.dcs/seo.yaml`. */\nconst MANAGED_HEAD_KEYS = /(^|[{,\\s([])(title|titleTemplate|meta|link|templateParams)\\s*:/\n/** The one head key a page may legitimately add on its own. */\nconst ADDITIVE_HEAD_KEYS = /(^|[{,\\s([])script\\s*:/\n/** Cap so a runaway scan cannot walk the whole file. */\nconst ARG_SCAN_LIMIT = 6000\n\n/**\n * Is this `useHead(...)` call ADDITIVE-ONLY?\n *\n * A page may legitimately add JSON-LD that `seo.yaml` cannot express per route —\n * a per-post `BlogPosting`, for instance. `useHead({ script: [...] })` that sets\n * no `title`/`meta`/`link` adds a tag; it does not restate a managed one, and\n * treating it as a violation would push every blog template into the exemption\n * list. An allow-list padded with legal entries is an allow-list nobody reads,\n * so the discrimination belongs here, not in each site's exemption file.\n *\n * Conservative by construction: anything it cannot read as additive-only — a\n * spread, a variable, an unbalanced or over-long argument — is reported.\n */\nfunction isAdditiveOnlyHeadCall(code: string, argStart: number): boolean {\n let depth = 0\n let i = argStart\n const end = Math.min(code.length, argStart + ARG_SCAN_LIMIT)\n for (; i < end; i += 1) {\n const c = code[i]\n if (c === '(' || c === '{' || c === '[') depth += 1\n else if (c === ')' || c === '}' || c === ']') {\n depth -= 1\n if (depth === 0) break\n }\n }\n if (depth !== 0) return false // unbalanced or truncated — do not guess\n const arg = code.slice(argStart, i + 1)\n if (arg.includes('...')) return false // a spread can carry anything\n return ADDITIVE_HEAD_KEYS.test(arg) && !MANAGED_HEAD_KEYS.test(arg)\n}\n\n// =============================================================================\n// Exemption host claims — the live half (C-420)\n// =============================================================================\n\n/**\n * A hostname written in prose. The TLD suffix list is deliberate: a bare\n * `\\w+(\\.\\w+)+` also matches `.dcs/seo.yaml`, `HomeView.vue` and `useSEO().\n * applyHead`, which would turn every exemption into a false host claim.\n */\nconst HOSTNAME_IN_TEXT =\n /\\b(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+(?:com|net|org|io|dev|co|us|ai|app|site|xyz)\\b/gi\n\nfunction normalizeHost(value: string): string {\n return value\n .trim()\n .toLowerCase()\n .replace(/^https?:\\/\\//, '')\n .replace(/\\/.*$/, '')\n .replace(/\\.$/, '')\n}\n\n/** A bare string exemption is a record with no host claims. */\nexport function normalizeExemption(value: HeadContractExemptionValue): HeadContractExemptionRecord {\n if (typeof value === 'string') return { reason: value }\n return { reason: value?.reason ?? '', hosts: value?.hosts }\n}\n\n/** Every host the prose names, deduped and normalised. */\nexport function hostsNamedIn(reason: string): string[] {\n const found = reason.match(HOSTNAME_IN_TEXT) ?? []\n const out: string[] = []\n for (const raw of found) {\n const host = normalizeHost(raw)\n if (!out.includes(host)) out.push(host)\n }\n return out\n}\n\n/**\n * Pull the three head fields an exemption can make a claim about out of a live\n * response body. Shared by the runner and by this module's own tests so the\n * thing that fetches and the thing that judges cannot disagree about what a\n * `robots` meta is.\n */\nexport function parseHostProbeHtml(html: string): {\n robots: string | null\n canonical: string | null\n title: string | null\n} {\n const robots =\n /<meta[^>]+name\\s*=\\s*[\"']robots[\"'][^>]*>/i\n .exec(html)?.[0]\n ?.match(/content\\s*=\\s*[\"']([^\"']*)[\"']/i)?.[1]\n ?.trim() ?? null\n const canonical =\n /<link[^>]+rel\\s*=\\s*[\"']canonical[\"'][^>]*>/i\n .exec(html)?.[0]\n ?.match(/href\\s*=\\s*[\"']([^\"']*)[\"']/i)?.[1]\n ?.trim() ?? null\n const title = /<title[^>]*>([\\s\\S]*?)<\\/title>/i.exec(html)?.[1]?.trim() ?? null\n return { robots, canonical, title }\n}\n\nfunction hostOfUrl(url: string): string {\n const match = /^(?:https?:)?\\/\\/([^/?#]+)/i.exec(url.trim())\n if (match) return normalizeHost(match[1])\n return normalizeHost(url)\n}\n\nfunction claimChecks(\n host: string,\n expect: HeadContractExemptionExpectation,\n probe: HeadContractHostProbe\n): HeadContractExemptionCheck[] {\n const checks: HeadContractExemptionCheck[] = []\n if (typeof expect.status === 'number') {\n checks.push({\n host,\n claim: 'status',\n expected: String(expect.status),\n actual: probe.status === undefined ? '(none)' : String(probe.status),\n pass: probe.status === expect.status,\n })\n }\n if (typeof expect.robots === 'string') {\n const actual = probe.robots ?? '(absent)'\n checks.push({\n host,\n claim: 'robots',\n expected: `contains \"${expect.robots}\"`,\n actual,\n pass: actual.toLowerCase().includes(expect.robots.toLowerCase()),\n })\n }\n if (typeof expect.canonicalHost === 'string') {\n const actual = probe.canonical ? hostOfUrl(probe.canonical) : '(absent)'\n checks.push({\n host,\n claim: 'canonicalHost',\n expected: normalizeHost(expect.canonicalHost),\n actual,\n pass: actual === normalizeHost(expect.canonicalHost),\n })\n }\n if (typeof expect.titleContains === 'string') {\n const actual = probe.title ?? '(absent)'\n checks.push({\n host,\n claim: 'titleContains',\n expected: `contains \"${expect.titleContains}\"`,\n actual,\n pass: actual.toLowerCase().includes(expect.titleContains.toLowerCase()),\n })\n }\n return checks\n}\n\n/**\n * Judge every exemption against the live behaviour of the host it names.\n *\n * Four ways to fail and only one way to pass, because the failure this exists\n * to catch is a green:\n * - the prose names a host that carries no machine-checkable claim\n * - a declared host asserts nothing (a claim block with no claims)\n * - a declared host has no observation (nothing was measured)\n * - an observation disagrees with a claim, or the probe itself did not run\n * Pure: it fetches nothing and reads no files.\n */\nexport function auditExemptionHosts(\n exemptions: Record<string, HeadContractExemptionValue>,\n hostProbes: Record<string, HeadContractHostProbe>\n): { audits: HeadContractExemptionAudit[]; violations: HeadContractViolation[] } {\n const audits: HeadContractExemptionAudit[] = []\n const violations: HeadContractViolation[] = []\n\n // WORST WINS, and \"a claim was contradicted\" is worse than \"a claim was\n // missing\": a multi-host exemption with one dead premise must summarise as\n // REFUTED, or the headline count disagrees with the violations underneath it.\n const RANK: Record<HeadContractExemptionVerdict, number> = {\n refuted: 4,\n 'probe-failed': 3,\n unprobed: 2,\n 'live-true': 1,\n 'no-host-claim': 0,\n }\n\n for (const file of Object.keys(exemptions)) {\n const record = normalizeExemption(exemptions[file])\n const named = hostsNamedIn(record.reason)\n const declaredMap = record.hosts ?? {}\n const declared = Object.keys(declaredMap).map(normalizeHost)\n const checks: HeadContractExemptionCheck[] = []\n let verdict: HeadContractExemptionVerdict = 'no-host-claim'\n const escalate = (next: HeadContractExemptionVerdict) => {\n if (RANK[next] > RANK[verdict]) verdict = next\n }\n\n const undeclared = named.filter((h) => !declared.includes(h))\n if (undeclared.length > 0) {\n escalate('unprobed')\n violations.push({\n code: 'unprobed-exemption',\n file,\n line: 0,\n detail:\n `This exemption's reason names ${undeclared.join(', ')} but declares no claim about ` +\n `it, so nothing checks whether the host still behaves the way the reason says. ` +\n `Add \"hosts\": { \"${undeclared[0]}\": { … } } with at least one of status / robots / ` +\n `canonicalHost / titleContains. An exemption that names a host and is never ` +\n `measured against it is an assertion, not a finding.`,\n })\n }\n\n for (const rawHost of Object.keys(declaredMap)) {\n const host = normalizeHost(rawHost)\n const expect = declaredMap[rawHost] ?? {}\n const claimCount = (\n ['status', 'robots', 'canonicalHost', 'titleContains'] as const\n ).filter((k) => expect[k] !== undefined).length\n\n if (claimCount === 0) {\n escalate('unprobed')\n violations.push({\n code: 'unprobed-exemption',\n file,\n line: 0,\n detail:\n `The exemption declares ${host} but asserts nothing about it. A host entry with ` +\n `no claim is probed into a guaranteed pass — the vacuous green this rail exists ` +\n `to refuse. State what the host must do: status / robots / canonicalHost / ` +\n `titleContains.`,\n })\n continue\n }\n\n const probe = hostProbes[host]\n if (!probe) {\n escalate('unprobed')\n violations.push({\n code: 'unprobed-exemption',\n file,\n line: 0,\n detail:\n `The exemption claims ${claimCount} thing(s) about ${host} and NO observation of ` +\n `that host reached the audit. \"Not measured\" must never render as \"measured ` +\n `fine\": run the audit with host probing enabled, or delete the claim.`,\n })\n continue\n }\n\n if (!probe.ok) {\n escalate('probe-failed')\n violations.push({\n code: 'exemption-probe-failed',\n file,\n line: 0,\n detail:\n `The probe of ${host} did not complete (${probe.error ?? 'no error recorded'}), so ` +\n `this exemption's premise is UNVERIFIED. A probe that could not run is a failure, ` +\n `not a skip — the alternative is an allow-list that goes green whenever the ` +\n `network does.`,\n })\n continue\n }\n\n const hostChecks = claimChecks(host, expect, probe)\n checks.push(...hostChecks)\n for (const check of hostChecks.filter((c) => !c.pass)) {\n escalate('refuted')\n violations.push({\n code: 'exemption-claim-refuted',\n file,\n line: 0,\n detail:\n `DEAD PREMISE. The exemption asserts ${check.host} ${check.claim} ` +\n `${check.expected}; the live host answered \"${check.actual}\". The exemption is ` +\n `why this file passes, so the pass rests on something production stopped doing. ` +\n `Re-word it to what is true, or delete it and the writer it protects.`,\n })\n }\n if (hostChecks.length > 0 && hostChecks.every((c) => c.pass)) escalate('live-true')\n }\n\n audits.push({\n file,\n reason: record.reason,\n hostsNamedInReason: named,\n hostsDeclared: declared,\n checks,\n verdict,\n })\n }\n\n return { audits, violations }\n}\n\n// =============================================================================\n// The audit\n// =============================================================================\n\n/**\n * Audit a set of source files against the head-authority contract.\n *\n * Site-agnostic by construction: there is no site name, no path convention and\n * no per-shape branch anywhere in this function. The three measured shapes\n * (KEPT / boogie-babies / bryans) go through the identical call.\n */\nexport function auditHeadContract(input: HeadContractInput): HeadContractReport {\n const files = input.files ?? []\n const exemptions = input.exemptions ?? {}\n const violations: HeadContractViolation[] = []\n const warnings: HeadContractWarning[] = []\n const foreignWriters: ForeignWriterSite[] = []\n const useSeoSlugs: string[] = []\n const dynamicSlugs: string[] = []\n const silent: string[] = []\n\n let applyHeadCalls = 0\n let additiveHeadCalls = 0\n let argumentFreeCalls = 0\n let asserting = 0\n\n for (const { path, source } of files) {\n const code = blankComments(source)\n let fileAsserts = false\n\n // ── V1 — applyHead must take no arguments ───────────────────────────────\n APPLY_HEAD_CALL.lastIndex = 0\n let m: RegExpExecArray | null\n while ((m = APPLY_HEAD_CALL.exec(code)) !== null) {\n applyHeadCalls += 1\n fileAsserts = true\n const rest = code.slice(m.index + m[0].length)\n if (/^\\s*\\)/.test(rest)) {\n argumentFreeCalls += 1\n } else {\n const preview = source\n .slice(m.index, m.index + 140)\n .replace(/\\s+/g, ' ')\n .trim()\n violations.push({\n code: 'override-argument',\n file: path,\n line: lineOf(source, m.index),\n detail:\n `applyHead() must take no arguments — .dcs/seo.yaml is the only writer of ` +\n `title/description/keywords/canonical/OG/Twitter/JSON-LD. Move the value there ` +\n `and delete the argument. Found: ${preview}…`,\n })\n }\n }\n\n // ── V3 — every STATIC useSEO slug must resolve to a declared page ───────\n USE_SEO_CALL.lastIndex = 0\n while ((m = USE_SEO_CALL.exec(code)) !== null) {\n fileAsserts = true\n const arg = readUseSeoArgument(source, m.index + m[0].length)\n if (arg.kind === 'dynamic') {\n if (!dynamicSlugs.includes(arg.expression)) dynamicSlugs.push(arg.expression)\n warnings.push({\n code: 'dynamic-slug',\n file: path,\n detail:\n `useSEO(${arg.expression.slice(0, 60)}) resolves its page key at runtime, so this ` +\n `audit cannot check it against .dcs/seo.yaml. That is legal — a dynamic route must ` +\n `resolve the SAME per-route key the emitter uses — but it is UNCHECKED HERE. P1 ` +\n `(baked vs rendered, on a real build of every route) is the rail that judges it.`,\n })\n continue\n }\n const slug = arg.slug\n // A slug seen in an earlier file has already been judged; reporting it\n // again would multiply one seo.yaml gap into many identical findings.\n if (!slug || useSeoSlugs.includes(slug)) continue\n useSeoSlugs.push(slug)\n const page = input.seo?.pages?.[slug]\n if (!page || typeof page.title !== 'string' || page.title.trim() === '') {\n violations.push({\n code: 'undeclared-slug',\n file: path,\n line: lineOf(source, m.index),\n detail:\n `useSEO('${slug}') has no pages.${slug}.title in .dcs/seo.yaml. At runtime it ` +\n `collapses to global.defaultTitle while the build-time emitter falls back to the ` +\n `pages.yaml route title — the same baked-vs-rendered divergence wearing a ` +\n `different hat. Declare the entry.`,\n })\n }\n }\n\n // ── V2 — no writer outside the factory ──────────────────────────────────\n for (const { re, mechanism } of FOREIGN_WRITERS) {\n re.lastIndex = 0\n while ((m = re.exec(code)) !== null) {\n fileAsserts = true\n\n // Additive JSON-LD is not a second writer — see isAdditiveOnlyHeadCall.\n if (mechanism === 'useHead' && isAdditiveOnlyHeadCall(code, m.index + m[0].length - 1)) {\n additiveHeadCalls += 1\n continue\n }\n\n const reason = Object.prototype.hasOwnProperty.call(exemptions, path)\n ? normalizeExemption(exemptions[path]).reason\n : null\n const exempted = typeof reason === 'string' && reason.trim().length >= MIN_EXEMPTION_REASON_LENGTH\n foreignWriters.push({\n file: path,\n line: lineOf(source, m.index),\n mechanism,\n exempted,\n reason: reason ?? null,\n })\n if (exempted) continue\n if (reason !== null) {\n violations.push({\n code: 'empty-exemption-reason',\n file: path,\n line: lineOf(source, m.index),\n detail:\n `An exemption for ${path} exists but records no reason (needs >= ` +\n `${MIN_EXEMPTION_REASON_LENGTH} characters). An undocumented exemption is ` +\n `indistinguishable from an accident.`,\n })\n continue\n }\n violations.push({\n code: 'foreign-head-writer',\n file: path,\n line: lineOf(source, m.index),\n detail:\n `${mechanism} writes the head outside the .dcs/seo.yaml factory. Route the value ` +\n `through seo.yaml + useSEO().applyHead(), or declare this file as an exemption ` +\n `with the reason it genuinely cannot. Declaring it does NOT excuse it from P1: ` +\n `the baked head and the rendered head must still agree.`,\n })\n }\n }\n\n if (fileAsserts) asserting += 1\n else silent.push(path)\n }\n\n // ── V4 (warn) — a view that never re-asserts is stale after the first click ─\n for (const file of silent) {\n warnings.push({\n code: 'uncovered-route',\n file,\n detail:\n `This view never re-asserts the head, so an in-app navigation to it leaves the ` +\n `PREVIOUS route's title/description/canonical in the DOM. The baked head is correct ` +\n `exactly once — on the document that was fetched. Reported, not enforced: the fix is ` +\n `a router-level re-assert in the platform, not eleven views remembering.`,\n })\n }\n\n // ── Exemption hygiene — anti-rot (source) AND anti-dead-premise (live) ──\n // The stale check asks \"does this file still violate?\"; the host audit asks\n // \"does the host this exemption NAMES still behave the way it claims?\". The\n // measured failure passed the first and would have failed the second.\n const hostAudit = auditExemptionHosts(exemptions, input.hostProbes ?? {})\n violations.push(...hostAudit.violations)\n\n const violatingFiles = new Set(foreignWriters.map((f) => f.file))\n for (const path of Object.keys(exemptions)) {\n if (!violatingFiles.has(path)) {\n violations.push({\n code: 'stale-exemption',\n file: path,\n line: 0,\n detail:\n `An exemption is declared for ${path} but it writes no head outside the factory. ` +\n `Delete the exemption — a rotting allow-list is how the next real one gets waved ` +\n `through.`,\n })\n }\n }\n\n // ── Execution assertions — a check that checked nothing is a FAILURE ─────\n if (files.length === 0) {\n violations.push({\n code: 'scan-empty',\n file: '(none)',\n line: 0,\n detail:\n 'The head-contract audit SCANNED NOTHING. Zero files reached it, so it proved ' +\n 'nothing about this site. The file walk is broken, not the codebase.',\n })\n }\n if (!input.seo || !input.seo.pages || Object.keys(input.seo.pages).length === 0) {\n violations.push({\n code: 'no-seo-config',\n file: '.dcs/seo.yaml',\n line: 0,\n detail:\n 'No .dcs/seo.yaml pages were supplied. Authority cannot be established without the ' +\n 'authority file, so every slug check silently passes — the vacuous-green shape this ' +\n 'audit exists to refuse.',\n })\n }\n\n return {\n scanned: files.length,\n applyHeadCalls,\n argumentFreeCalls,\n useSeoSlugs,\n dynamicSlugs,\n foreignWriters,\n additiveHeadCalls,\n exemptionAudit: hostAudit.audits,\n coverage: { views: files.length, asserting, silent },\n violations,\n warnings,\n ok: violations.length === 0,\n }\n}\n\n/**\n * Dump the exemption set with a per-entry live verdict.\n *\n * Printed on EVERY run, including the empty one. \"0 refuted\" out of an unlisted\n * set is indistinguishable from a rail that inspected nothing, so the set is\n * always enumerated and the empty case says so in words.\n */\nexport function formatExemptionAudit(report: HeadContractReport): string[] {\n const audits = report.exemptionAudit ?? []\n const lines: string[] = []\n const count = (v: HeadContractExemptionVerdict) => audits.filter((a) => a.verdict === v).length\n\n if (audits.length === 0) {\n lines.push(\n `[head-contract] exemptions: 0 declared — the allow-list is EMPTY, not unchecked ` +\n `(${report.scanned} file(s) scanned, ${report.foreignWriters.length} foreign head ` +\n `writer(s) found, so there was nothing to declare).`\n )\n return lines\n }\n\n lines.push(\n `[head-contract] exemptions: ${audits.length} declared — ${count('live-true')} live-true, ` +\n `${count('refuted')} REFUTED, ${count('unprobed')} unprobed, ` +\n `${count('probe-failed')} probe-failed, ${count('no-host-claim')} host-free`\n )\n for (const audit of audits) {\n const hosts = audit.hostsDeclared.length > 0 ? audit.hostsDeclared.join(', ') : '(no host declared)'\n lines.push(` ${audit.verdict.toUpperCase()} ${audit.file} [${hosts}]`)\n if (audit.hostsNamedInReason.length > 0) {\n lines.push(` reason names: ${audit.hostsNamedInReason.join(', ')}`)\n }\n for (const check of audit.checks) {\n lines.push(\n ` ${check.pass ? 'ok ' : 'FAIL'} ${check.host} ${check.claim}: ` +\n `expected ${check.expected}, live \"${check.actual}\"`\n )\n }\n if (audit.checks.length === 0 && audit.verdict !== 'no-host-claim') {\n lines.push(' (no live check ran — see the violations above)')\n }\n }\n return lines\n}\n\n/** Human-readable report. Execution counts are printed FIRST, always. */\nexport function formatHeadContractReport(report: HeadContractReport): string {\n const lines: string[] = []\n lines.push(\n `[head-contract] scanned ${report.scanned} file(s); ` +\n `${report.applyHeadCalls} applyHead call(s), ${report.argumentFreeCalls} argument-free; ` +\n `${report.useSeoSlugs.length} static useSEO slug(s), ` +\n `${report.dynamicSlugs.length} dynamic (unchecked here — P1 judges those); ` +\n `${report.foreignWriters.length} foreign head writer(s) ` +\n `(${report.foreignWriters.filter((f) => f.exempted).length} declared); ` +\n `${report.additiveHeadCalls} additive JSON-LD useHead call(s)`\n )\n lines.push(\n `[head-contract] SPA coverage: ${report.coverage.asserting}/${report.coverage.views} view(s) ` +\n `re-assert the head; ${report.coverage.silent.length} silent`\n )\n if (report.scanned === 0) {\n lines.push('[head-contract] SCANNED NOTHING this run — this is a failure, not a pass.')\n }\n lines.push(...formatExemptionAudit(report))\n for (const v of report.violations) {\n lines.push(` VIOLATION ${v.code} ${v.file}${v.line ? `:${v.line}` : ''} — ${v.detail}`)\n }\n for (const w of report.warnings) {\n lines.push(` warn ${w.code} ${w.file} — ${w.detail}`)\n }\n if (report.violations.length === 0) {\n lines.push('[head-contract] PASS — .dcs/seo.yaml is the only writer of the managed head.')\n }\n return lines.join('\\n')\n}\n\n/**\n * Assert the contract. `error` throws; `warn` prints; `off` is a no-op — except\n * that `scan-empty` and `no-seo-config` are NEVER downgraded, because \"the rail\n * did not run\" must not be silenceable by the mode that silences findings.\n */\nexport function assertHeadContract(\n input: HeadContractInput,\n mode: HeadContractMode = 'error',\n log: (msg: string) => void = console.warn\n): HeadContractReport {\n const report = auditHeadContract(input)\n const notRun = report.violations.filter(\n (v) => v.code === 'scan-empty' || v.code === 'no-seo-config'\n )\n\n if (notRun.length > 0) {\n throw new HeadContractError(\n `${formatHeadContractReport(report)}\\n\\nThe head-contract audit did not run against ` +\n `anything it could judge. Fix the inputs before reading this as a pass.`,\n report\n )\n }\n\n if (mode === 'off') return report\n if (report.violations.length === 0) return report\n\n if (mode === 'warn') {\n log(formatHeadContractReport(report))\n log('[head-contract] in error mode the above would be RED.')\n return report\n }\n\n throw new HeadContractError(formatHeadContractReport(report), report)\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import * as vue from 'vue';
2
2
  import { ComputedRef, MaybeRefOrGetter, Ref } from 'vue';
3
- import { U as UseSeoReturn, G as GlobalSeoConfig } from './vitepressTransform-JG_zlaux.js';
4
- export { A as AI_BOTS, y as BlogMeta, x as BreadcrumbCrumb, v as BuildLlmsParams, u as BuildRobotsParams, B as BuildSitemapParams, E as ContentConfig, C as CreateSeoTransformPageDataOptions, D as DcsRobotsOptions, F as FaqSource, X as HeadOverrides, P as PageSeoConfig, R as ResolvedPageOverrides, T as ResolvedPageSeo, z as ReviewSource, w as SchemaObject, O as SeoAlternateConfig, I as SeoAuthorConfig, H as SeoConfiguration, K as SeoImagesConfig, L as SeoOpenGraphConfig, S as SeoPageContext, r as SeoPageTypeRule, N as SeoSchemaConfig, J as SeoSocialConfig, M as SeoTwitterConfig, Q as SeoVerificationConfig, W as UseSeoConfig, t as VitePressHeadConfig, V as VitePressPageData, q as absolutizeUrl, j as breadcrumbTrailFromRoute, k as buildBlogPosting, h as buildBreadcrumbList, l as buildFaqPage, g as buildGlobalGraph, f as buildLlmsTxt, m as buildReviewSchemaParts, e as buildRobotsTxt, a as buildSitemapXml, b as buildVitePressSeoHead, c as createSeoTransformPageData, d as defaultRelativePathToRoute, o as filterRealFaq, n as filterRealReviews, p as findReviewItemsForPage, i as isRouteIndexable, s as slugToTitle } from './vitepressTransform-JG_zlaux.js';
5
- export { j as HeadLinkTag, H as HeadMetaTag, k as HeadScriptTag, l as HeadTagOverrides, I as InstallSeoHeadOptions, R as ResolvedHeadTags, o as SeoHeadClientLike, p as SeoHeadEntryLike, q as SeoHeadInput, t as SeoHeadPageRoute, u as SeoHeadPagesManifest, v as SeoHeadResolution, w as SeoHeadResolutionReason, m as SeoHeadRouteLike, S as SeoHeadRouterLike, b as buildHeadTags, h as buildSeoHeadRouteMap, f as escapeJsonLd, g as generateJsonLd, a as generateOpenGraphMeta, c as generateTwitterMeta, i as installSeoHead, n as normalizeSeoHeadPath, d as renderHeadTags, r as resolvePageSeo, s as spliceHeadHtml, e as stripManagedHeadTags } from './installSeoHead-kWQwObez.js';
3
+ import { U as UseSeoReturn, G as GlobalSeoConfig } from './vitepressTransform-Ds5Hff8t.js';
4
+ export { A as AI_BOTS, y as BlogMeta, x as BreadcrumbCrumb, v as BuildLlmsParams, u as BuildRobotsParams, B as BuildSitemapParams, E as ContentConfig, C as CreateSeoTransformPageDataOptions, D as DcsRobotsOptions, F as FaqSource, X as HeadOverrides, P as PageSeoConfig, R as ResolvedPageOverrides, T as ResolvedPageSeo, z as ReviewSource, w as SchemaObject, O as SeoAlternateConfig, I as SeoAuthorConfig, H as SeoConfiguration, K as SeoImagesConfig, L as SeoOpenGraphConfig, S as SeoPageContext, r as SeoPageTypeRule, N as SeoSchemaConfig, J as SeoSocialConfig, M as SeoTwitterConfig, Q as SeoVerificationConfig, W as UseSeoConfig, t as VitePressHeadConfig, V as VitePressPageData, q as absolutizeUrl, j as breadcrumbTrailFromRoute, k as buildBlogPosting, h as buildBreadcrumbList, l as buildFaqPage, g as buildGlobalGraph, f as buildLlmsTxt, m as buildReviewSchemaParts, e as buildRobotsTxt, a as buildSitemapXml, b as buildVitePressSeoHead, c as createSeoTransformPageData, d as defaultRelativePathToRoute, o as filterRealFaq, n as filterRealReviews, p as findReviewItemsForPage, i as isRouteIndexable, s as slugToTitle } from './vitepressTransform-Ds5Hff8t.js';
5
+ export { l as HeadLinkTag, H as HeadMetaTag, m as HeadScriptTag, o as HeadTagOverrides, I as InstallSeoHeadOptions, R as ResolvedHeadTags, q as SeoHeadClientLike, t as SeoHeadEntryLike, u as SeoHeadInput, v as SeoHeadPageRoute, w as SeoHeadPagesManifest, x as SeoHeadResolution, y as SeoHeadResolutionReason, p as SeoHeadRouteLike, S as SeoHeadRouterLike, b as buildHeadTags, k as buildSeoHeadRouteMap, f as escapeJsonLd, g as generateJsonLd, a as generateOpenGraphMeta, c as generateTwitterMeta, j as installSeoHead, h as isManagedLinkRel, i as isManagedMetaTag, n as normalizeSeoHeadPath, d as renderHeadTags, r as resolvePageSeo, s as spliceHeadHtml, e as stripManagedHeadTags } from './installSeoHead-EE0Z7UmK.js';
6
6
  import { ImageContext, ResponsiveImageResult } from '@duffcloudservices/cms-core';
7
7
  export { ImageContext, ResponsiveImageOptions, ResponsiveImageResult, ResponsiveSource, isCdnAssetUrl, resolveResponsiveImage } from '@duffcloudservices/cms-core';
8
8
 
@@ -797,7 +797,7 @@ declare function conversionOptedOut(): boolean;
797
797
  */
798
798
  declare function inFrame(): boolean;
799
799
  /** Reason the installer declined, or `null` when it installed. */
800
- type ConversionInstallSkipReason = 'no-document' | 'already-installed' | 'in-frame' | 'do-not-track' | 'opted-out';
800
+ type ConversionInstallSkipReason = 'no-document' | 'already-installed' | 'in-frame' | 'do-not-track' | 'opted-out' | 'synthetic-capture';
801
801
  /** Result of an {@link installConversionCapture} call. */
802
802
  interface ConversionInstallResult {
803
803
  installed: boolean;
@@ -852,6 +852,57 @@ interface FetchSiteVisitorSessionOptions {
852
852
  /** Optional AbortSignal to cancel an in-flight probe. */
853
853
  signal?: AbortSignal;
854
854
  }
855
+ /**
856
+ * Normalize a parsed `/site-auth/session` BODY into a `SiteVisitor | null`.
857
+ *
858
+ * This is the payload-level answer to "is anyone signed in?" — the question the HTTP
859
+ * status cannot answer, because an anonymous visitor gets `200 { "visitor": null }`
860
+ * (A-35). Use it when your own code already parsed the body; use
861
+ * {@link readSiteVisitorSessionResponse} when you are holding a `Response`.
862
+ *
863
+ * `null` means signed out. Deliberately fail-closed on every ambiguity:
864
+ * - a MISSING `visitor` key yields `null`, never a truthy `undefined` — the trap that
865
+ * made kept's `visitor.value = data.visitor` a latent defect (C-619);
866
+ * - an envelope claiming `authenticated: true` with no visitor object yields `null`;
867
+ * - a visitor object without an email is not a visitor.
868
+ *
869
+ * Accepts the primary/legacy `{ visitor: {...} | null }` envelope and the contracts-spec
870
+ * `{ authenticated, user: {...} }` shape defensively.
871
+ */
872
+ declare function siteVisitorFromSessionPayload(data: unknown): SiteVisitor | null;
873
+ /**
874
+ * Decide "is a visitor signed in?" from a `/site-auth/session` `Response` you already
875
+ * fetched yourself.
876
+ *
877
+ * THIS IS THE SEAM FOR HAND-ROLLED SESSION STORES. {@link useSiteVisitorSession} owns its
878
+ * own fetch, which a site with an existing store (Pinia, caching, in-flight dedup, its own
879
+ * authenticated `apiFetch`) cannot adopt — so it hand-rolls the gate and re-derives the
880
+ * A-35 defect: `if (response.ok) return true`, which reports EVERY anonymous visitor as
881
+ * authenticated because anonymous is `200 { "visitor": null }`. Measured cost when that
882
+ * happened on kept: one member-gated 401 per page view, 346 in a day (C-619).
883
+ *
884
+ * Keep your fetch; hand the `Response` here and read the payload-derived answer:
885
+ *
886
+ * ```ts
887
+ * const response = await apiFetch('/api/v1/site-auth/session')
888
+ * const { visitor: v } = await readSiteVisitorSessionResponse(response)
889
+ * visitor.value = v
890
+ * return v !== null // never `return response.ok`
891
+ * ```
892
+ *
893
+ * Fails CLOSED everywhere: a non-2xx (incl. a legacy `401`), a missing response (your
894
+ * fetch threw), an unparseable body, or a `null` visitor all resolve to signed-out. The
895
+ * status can never on its own produce `authenticated: true` — only a real visitor object
896
+ * in the body can.
897
+ *
898
+ * Silent on every anonymous path. LOUD exactly once when the body was not JSON at all
899
+ * (`apiUnreachable: true`), because "this host does not route `/api/v1/*` to the API" must
900
+ * not masquerade as "signed out" — that ambiguity is how kept ran with nine dead login
901
+ * routes for ~2 weeks (C-261 / C-298 layer 2).
902
+ *
903
+ * Never throws.
904
+ */
905
+ declare function readSiteVisitorSessionResponse(response: Response | null | undefined): Promise<SiteVisitorSessionResult>;
855
906
  /**
856
907
  * Fetch the current site-visitor session. Never throws and never logs for the
857
908
  * anonymous case: any network error, non-OK status (incl. a legacy `401`), or
@@ -883,4 +934,78 @@ interface UseSiteVisitorSessionReturn {
883
934
  */
884
935
  declare function useSiteVisitorSession(options?: UseSiteVisitorSessionOptions): UseSiteVisitorSessionReturn;
885
936
 
886
- export { CONVERSION_CAPTURE_VERSION, CONVERSION_INTERACTION_TYPES, type ConversionEvent, type ConversionInstallResult, type ConversionInstallSkipReason, type ConversionInteractionType, type ConversionSink, type ConversionTracker, type ConversionTrackingOptions, DEFAULT_BOOKING_HOSTS, DEFAULT_SOCIAL_HOSTS, type DcsContentFile, type FetchSiteVisitorSessionOptions, GlobalSeoConfig, type InstallConversionCaptureOptions, type MediaCarouselItem, type ReleaseNote, type ReleaseNotesReturn, type ReviewItem, type SiteVersionReturn, type SiteVisitor, type SiteVisitorSessionResult, type TextContentConfig, type TextContentReturn, type UseMediaCarouselConfig, type UseMediaCarouselReturn, type UseReviewContentConfig, type UseReviewContentReturn, UseSeoReturn, type UseSiteVisitorSessionOptions, type UseSiteVisitorSessionReturn, attachConversionSink, classifyHref, conversionOptedOut, createConversionTracker, createSiteSEO, doNotTrackEnabled, fetchSiteVisitorSession, hashTarget, hrefScheme, inFrame, installConversionCapture, installedConversionTracker, isConversionType, isSubmitControl, redactHref, resetConversionCapture, useConversionTracking, useMediaCarousel, useReleaseNotes, useResponsiveImage, useReviewContent, useSEO, useSiteVersion, useSiteVisitorSession, useTextContent };
937
+ /**
938
+ * Synthetic-capture detection (C-614).
939
+ *
940
+ * WHY THIS EXISTS
941
+ * ---------------
942
+ * The fleet's post-deploy "Capture page snapshots" step drives real Chromium
943
+ * against the LIVE production URL of the site it just deployed. The site's
944
+ * telemetry boots exactly as it would for a visitor, so every page the capture
945
+ * pass walked was recorded as a production pageView — during our own deploy run.
946
+ *
947
+ * Measured on coron8 (the smallest-traffic fleet site) over the 8 days to
948
+ * 2026-08-11: 49 synthetic pageViews against 14 organic — 78% of the entire
949
+ * store. All 49 landed on 08-11 across 5 deploys, against 3 real visits that
950
+ * day, so the owner's chart read 52 where the truth was 3. Every site carrying
951
+ * the C-589 telemetry sink plus a snapshot CI step has this.
952
+ *
953
+ * WHY SUPPRESSION AND NOT TAGGING
954
+ * -------------------------------
955
+ * The alternative was to tag the traffic with a synthetic-source dimension and
956
+ * exclude it in every read path. That is precisely the C-430 preview/localhost
957
+ * blend, which is a recorded UNSOLVED residual rather than a pattern worth
958
+ * copying: it obliges every present and future consumer — the portal analytics
959
+ * query, the MCP `analytics_summary` tool, ad-hoc KQL an owner runs — to
960
+ * remember an exclusion, and a consumer that forgets reports the inflated
961
+ * number with no signal that it did. Declining at the boundary keeps the
962
+ * denominator honest in all of them at once, and matches the choice already
963
+ * made for previews in C-601 (dev/preview telemetry points at the dev
964
+ * component, not the production store).
965
+ *
966
+ * WHY THESE MARKERS
967
+ * -----------------
968
+ * `dcs-hide-ribbon` is not invented here. Every DCS capture tool already
969
+ * appends it to suppress the preview ribbon in screenshots — the shared
970
+ * `packages/cli/src/commands/capture-snapshots.ts`, each site's own
971
+ * `scripts/capture-snapshots.*`, and the portfolio/CWV tooling that
972
+ * `@duffcloudservices/agent-widget`'s suppression module documents. It is
973
+ * consumed by `PreviewRibbon.vue`. Crucially, NO human-navigable link on a
974
+ * fleet site produces it, so the fleet already emits an accurate
975
+ * "this is a machine" marker everywhere and only the honoring half was missing.
976
+ *
977
+ * `dcs-no-telemetry` is the explicit, self-documenting name for the same
978
+ * intent, so future tooling need not overload a presentational parameter. Its
979
+ * second job is to make the fix self-validating: if a site's gate ever fails,
980
+ * the rows that get recorded carry the parameter and say so.
981
+ */
982
+ /** Query parameters that mark a document as an automated capture, not a visit. */
983
+ declare const SYNTHETIC_CAPTURE_PARAMS: readonly ["dcs-hide-ribbon", "dcs-no-telemetry"];
984
+ /** Reason {@link syntheticCaptureDetected} returned true, for logging and skip reporting. */
985
+ type SyntheticCaptureMarker = (typeof SYNTHETIC_CAPTURE_PARAMS)[number];
986
+ /**
987
+ * The marker present on this document, or `null` when this looks like a real visit.
988
+ *
989
+ * Reads `window.location.search` on every call rather than caching: a site that
990
+ * calls this after a client-side route change must see the CURRENT URL, and a
991
+ * cached first-load verdict would either leak suppression into a real user's
992
+ * later navigation or miss a capture pass that navigated in-app.
993
+ *
994
+ * Returns `null` on the server — server rendering emits no browser telemetry,
995
+ * and answering "synthetic" there would be a claim this function cannot support.
996
+ */
997
+ declare function syntheticCaptureMarker(): SyntheticCaptureMarker | null;
998
+ /**
999
+ * Whether this document is an automated capture rather than a visit worth counting.
1000
+ *
1001
+ * Call this BEFORE loading an analytics SDK, so a capture pass never opens a
1002
+ * beacon at all:
1003
+ *
1004
+ * ```ts
1005
+ * if (syntheticCaptureDetected()) return false
1006
+ * const { ApplicationInsights } = await import('@microsoft/applicationinsights-web')
1007
+ * ```
1008
+ */
1009
+ declare function syntheticCaptureDetected(): boolean;
1010
+
1011
+ export { CONVERSION_CAPTURE_VERSION, CONVERSION_INTERACTION_TYPES, type ConversionEvent, type ConversionInstallResult, type ConversionInstallSkipReason, type ConversionInteractionType, type ConversionSink, type ConversionTracker, type ConversionTrackingOptions, DEFAULT_BOOKING_HOSTS, DEFAULT_SOCIAL_HOSTS, type DcsContentFile, type FetchSiteVisitorSessionOptions, GlobalSeoConfig, type InstallConversionCaptureOptions, type MediaCarouselItem, type ReleaseNote, type ReleaseNotesReturn, type ReviewItem, SYNTHETIC_CAPTURE_PARAMS, type SiteVersionReturn, type SiteVisitor, type SiteVisitorSessionResult, type SyntheticCaptureMarker, type TextContentConfig, type TextContentReturn, type UseMediaCarouselConfig, type UseMediaCarouselReturn, type UseReviewContentConfig, type UseReviewContentReturn, UseSeoReturn, type UseSiteVisitorSessionOptions, type UseSiteVisitorSessionReturn, attachConversionSink, classifyHref, conversionOptedOut, createConversionTracker, createSiteSEO, doNotTrackEnabled, fetchSiteVisitorSession, hashTarget, hrefScheme, inFrame, installConversionCapture, installedConversionTracker, isConversionType, isSubmitControl, readSiteVisitorSessionResponse, redactHref, resetConversionCapture, siteVisitorFromSessionPayload, syntheticCaptureDetected, syntheticCaptureMarker, useConversionTracking, useMediaCarousel, useReleaseNotes, useResponsiveImage, useReviewContent, useSEO, useSiteVersion, useSiteVisitorSession, useTextContent };
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import './chunk-A5F4C72F.js';
2
- import { resolvePageSeo, generateJsonLd, buildHeadTags } from './chunk-HVSF23P7.js';
3
- export { AI_BOTS, absolutizeUrl, breadcrumbTrailFromRoute, buildBlogPosting, buildBreadcrumbList, buildFaqPage, buildGlobalGraph, buildHeadTags, buildLlmsTxt, buildReviewSchemaParts, buildRobotsTxt, buildSeoHeadRouteMap, buildSitemapXml, buildVitePressSeoHead, createSeoTransformPageData, defaultRelativePathToRoute, escapeJsonLd, filterRealFaq, filterRealReviews, findReviewItemsForPage, generateJsonLd, generateOpenGraphMeta, generateTwitterMeta, installSeoHead, isRouteIndexable, normalizeSeoHeadPath, renderHeadTags, resolvePageSeo, slugToTitle, spliceHeadHtml, stripManagedHeadTags } from './chunk-HVSF23P7.js';
1
+ import './chunk-OGAJX4KM.js';
2
+ import { resolvePageSeo, generateJsonLd, buildHeadTags } from './chunk-64BUBTW7.js';
3
+ export { AI_BOTS, absolutizeUrl, breadcrumbTrailFromRoute, buildBlogPosting, buildBreadcrumbList, buildFaqPage, buildGlobalGraph, buildHeadTags, buildLlmsTxt, buildReviewSchemaParts, buildRobotsTxt, buildSeoHeadRouteMap, buildSitemapXml, buildVitePressSeoHead, createSeoTransformPageData, defaultRelativePathToRoute, escapeJsonLd, filterRealFaq, filterRealReviews, findReviewItemsForPage, generateJsonLd, generateOpenGraphMeta, generateTwitterMeta, installSeoHead, isManagedLinkRel, isManagedMetaTag, isRouteIndexable, normalizeSeoHeadPath, renderHeadTags, resolvePageSeo, slugToTitle, spliceHeadHtml, stripManagedHeadTags } from './chunk-64BUBTW7.js';
4
4
  import { shallowRef, getCurrentInstance, onMounted, onBeforeUnmount, ref, computed, readonly, toValue, onUnmounted } from 'vue';
5
- import { isCdnAssetUrl, resolveResponsiveImage, platformFetch, isPlatformFetchError } from '@duffcloudservices/cms-core';
5
+ import { isCdnAssetUrl, resolveResponsiveImage, readPlatformJson, isPlatformFetchError, platformFetch } from '@duffcloudservices/cms-core';
6
6
  export { isCdnAssetUrl, resolveResponsiveImage } from '@duffcloudservices/cms-core';
7
7
  import { useHead } from '@unhead/vue';
8
8
 
@@ -327,6 +327,21 @@ function useConversionTracking(options = {}) {
327
327
  return tracker;
328
328
  }
329
329
 
330
+ // src/syntheticCapture.ts
331
+ var SYNTHETIC_CAPTURE_PARAMS = ["dcs-hide-ribbon", "dcs-no-telemetry"];
332
+ function syntheticCaptureMarker() {
333
+ if (typeof window === "undefined") return null;
334
+ try {
335
+ const params = new URLSearchParams(window.location.search);
336
+ return SYNTHETIC_CAPTURE_PARAMS.find((param) => params.has(param)) ?? null;
337
+ } catch {
338
+ return null;
339
+ }
340
+ }
341
+ function syntheticCaptureDetected() {
342
+ return syntheticCaptureMarker() !== null;
343
+ }
344
+
330
345
  // src/conversionAutoInstall.ts
331
346
  var installed = null;
332
347
  function conversionWindow() {
@@ -367,6 +382,7 @@ function installConversionCapture(options = {}) {
367
382
  if (inFrame()) return skip("in-frame");
368
383
  if ((options.respectDoNotTrack ?? true) && doNotTrackEnabled()) return skip("do-not-track");
369
384
  if (conversionOptedOut()) return skip("opted-out");
385
+ if (syntheticCaptureDetected()) return skip("synthetic-capture");
370
386
  const useGtag = options.gtag ?? true;
371
387
  const tracker = createConversionTracker({
372
388
  ...options,
@@ -908,7 +924,7 @@ function useReviewContent(config) {
908
924
  }
909
925
  var SIGNED_OUT = { visitor: null, authenticated: false };
910
926
  var apiBase = (value) => (value ?? "/api/v1").replace(/\/$/u, "");
911
- function extractVisitor(data) {
927
+ function siteVisitorFromSessionPayload(data) {
912
928
  if (!data || typeof data !== "object") {
913
929
  return null;
914
930
  }
@@ -930,6 +946,31 @@ function extractVisitor(data) {
930
946
  createdAt: typeof v.createdAt === "string" ? v.createdAt : void 0
931
947
  };
932
948
  }
949
+ var UNREACHABLE_BODY_CLASSES = /* @__PURE__ */ new Set([
950
+ "spa-html",
951
+ "html",
952
+ "other"
953
+ ]);
954
+ async function readSiteVisitorSessionResponse(response) {
955
+ if (!response) {
956
+ return SIGNED_OUT;
957
+ }
958
+ if (!response.ok) {
959
+ return SIGNED_OUT;
960
+ }
961
+ let data;
962
+ try {
963
+ data = await readPlatformJson(response, { silent: true });
964
+ } catch (e) {
965
+ if (isPlatformFetchError(e) && UNREACHABLE_BODY_CLASSES.has(e.bodyClass)) {
966
+ console.error(e.message);
967
+ return { visitor: null, authenticated: false, apiUnreachable: true };
968
+ }
969
+ return SIGNED_OUT;
970
+ }
971
+ const visitor = siteVisitorFromSessionPayload(data);
972
+ return { visitor, authenticated: visitor !== null };
973
+ }
933
974
  async function fetchSiteVisitorSession(options = {}) {
934
975
  const base = apiBase(options.apiBaseUrl);
935
976
  let response;
@@ -946,17 +987,7 @@ async function fetchSiteVisitorSession(options = {}) {
946
987
  }
947
988
  return SIGNED_OUT;
948
989
  }
949
- if (!response.ok) {
950
- return SIGNED_OUT;
951
- }
952
- let data;
953
- try {
954
- data = await response.json();
955
- } catch {
956
- return SIGNED_OUT;
957
- }
958
- const visitor = extractVisitor(data);
959
- return { visitor, authenticated: visitor !== null };
990
+ return readSiteVisitorSessionResponse(response);
960
991
  }
961
992
  function useSiteVisitorSession(options = {}) {
962
993
  const { fetchOnMount = true, ...fetchOptions } = options;
@@ -983,6 +1014,6 @@ function useSiteVisitorSession(options = {}) {
983
1014
  }
984
1015
  installConversionCapture();
985
1016
 
986
- export { CONVERSION_CAPTURE_VERSION, CONVERSION_INTERACTION_TYPES, DEFAULT_BOOKING_HOSTS, DEFAULT_SOCIAL_HOSTS, attachConversionSink, classifyHref, conversionOptedOut, createConversionTracker, createSiteSEO, doNotTrackEnabled, fetchSiteVisitorSession, hashTarget, hrefScheme, inFrame, installConversionCapture, installedConversionTracker, isConversionType, isSubmitControl, redactHref, resetConversionCapture, useConversionTracking, useMediaCarousel, useReleaseNotes, useResponsiveImage, useReviewContent, useSEO, useSiteVersion, useSiteVisitorSession, useTextContent };
1017
+ export { CONVERSION_CAPTURE_VERSION, CONVERSION_INTERACTION_TYPES, DEFAULT_BOOKING_HOSTS, DEFAULT_SOCIAL_HOSTS, SYNTHETIC_CAPTURE_PARAMS, attachConversionSink, classifyHref, conversionOptedOut, createConversionTracker, createSiteSEO, doNotTrackEnabled, fetchSiteVisitorSession, hashTarget, hrefScheme, inFrame, installConversionCapture, installedConversionTracker, isConversionType, isSubmitControl, readSiteVisitorSessionResponse, redactHref, resetConversionCapture, siteVisitorFromSessionPayload, syntheticCaptureDetected, syntheticCaptureMarker, useConversionTracking, useMediaCarousel, useReleaseNotes, useResponsiveImage, useReviewContent, useSEO, useSiteVersion, useSiteVisitorSession, useTextContent };
987
1018
  //# sourceMappingURL=index.js.map
988
1019
  //# sourceMappingURL=index.js.map