/** * ChatgptUiScrapeParser — PURE, network-free transform from raw scraped * ChatGPT-UI answer-page markdown into a normalized `ParsedAnswer` (in-house- * ai-visibility, Sprint 10; arch-20260717-in-house-oss-ai-visibility- * architecture.md:139-141,250-251,281). * * This module has ZERO dependencies on damcrawler, egress, or any network * primitive — it is a synchronous, deterministic markdown -> data mapping, * mirroring `DeterministicMentionCitationExtractor`'s "PURE, synchronous, * network-free transform" contract (`./mention-citation-extractor.ts:8`). * `ScrapeArmEngineProvider` is the ONLY caller, and it invokes `.parse()` * strictly AFTER the raw scraped markdown has already passed through the * fail-closed `ContentSanitizer` at the network->in-process boundary * (sc-10-2, Sprint-9 F1 lesson) — this parser never sees unsanitized text * in production, but it does not (and must not) assume that; it never * throws regardless of input. * * ChatGPT's exported/rendered answer-page markdown is NOT a stable, fully * documented format — this parser degrades gracefully on drift: "parser * drift => empty answerText => downstream observation counts as not- * mentioned" (arch:281) is the explicit contract, not a bug to fix later. * Empty/whitespace/malformed input always yields `{ answerText: "", * citations: [] }` — this class NEVER fabricates a positive observation. * * Extraction strategy (deterministic, markdown-shape heuristics only): * 1. `answerText` — the raw markdown with any trailing "Sources"/ * "Citations" section (and any markdown link syntax) stripped, then * trimmed. A ChatGPT-UI answer page renders the assistant's prose * followed by an optional sources block; this parser treats everything * before that block (or the whole trimmed text, when no block is * found) as the answer. * 2. `citations` — markdown links (`[title](url)`) found ANYWHERE in the * raw markdown, deduplicated by URL, mapped to `GroundedCitation` * `{ url, title }`. A bare autolink (``) or a bare URL is * also captured with its url as its own title (no better title is * derivable). Malformed/empty href or link text never crashes the * parser — such candidates are simply skipped. */ import type { GroundedCitation } from "../../providers/grounded-search.js"; /** Raw scraped page handed to the parser — already sanitized by the caller (sc-10-2). */ export type RawScrape = { url: string; markdown: string; links?: string[]; }; /** Normalized parse result. `citations` reuses the locked `GroundedCitation` shape. */ export type ParsedAnswer = { answerText: string; citations: GroundedCitation[]; }; export interface EngineScrapeParser { parse(raw: RawScrape): ParsedAnswer; } /** * `EngineScrapeParser` for the `"chatgpt-ui"` scrape engine. PURE, * synchronous, dependency-free; never throws; empty/malformed input yields * `{ answerText: "", citations: [] }`. */ export declare class ChatgptUiScrapeParser implements EngineScrapeParser { parse(raw: RawScrape): ParsedAnswer; } //# sourceMappingURL=engine-scrape-parser-chatgpt.d.ts.map