@ai-react-markdown/engine 2.8.1 → 2.9.0

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/fixtures/scenarios.ts","../src/components/markdown/processor.ts","../src/components/markdown/stages.ts","../src/components/markdown/transform.ts","../src/components/markdown/urlTransform.ts","../src/components/incrementalParse/computeFreezeBoundary.ts","../src/components/incrementalParse/mdLineText.ts","../src/components/incrementalParse/referenceTaint.ts","../src/components/incrementalParse/spliceParse.ts","../src/components/hastPredicates.ts","../src/components/incrementalParse/attributeHastChildren.ts","../src/components/incrementalParse/advanceIncrementalParse.ts","../src/components/incrementalParse/codePointSnapshots.ts","../src/components/collectDefLabels.ts","../src/components/normalizeId.ts","../src/components/extractDefBodiesFromHast.ts","../src/components/extractContributions.ts","../src/components/remarkInjectPhantomDefs.ts","../src/components/documentRegistry.ts","../src/components/pluginChain.ts","../src/components/rehypeUnwrapCrossChunkImages.ts","../src/components/rehypeRebaseHashLinks.ts","../src/components/rehypeFooterAdorn.ts","../src/components/customMdastHandlers.ts","../src/components/crossChunkUrlSanitize.ts","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_listCacheClear.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/eq.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_assocIndexOf.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_listCacheDelete.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_listCacheGet.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_listCacheHas.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_listCacheSet.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_ListCache.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_stackClear.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_stackDelete.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_stackGet.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_stackHas.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_freeGlobal.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_root.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_Symbol.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_getRawTag.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_objectToString.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseGetTag.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isObject.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isFunction.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_coreJsData.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_isMasked.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_toSource.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseIsNative.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_getValue.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_getNative.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_Map.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_nativeCreate.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_hashClear.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_hashDelete.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_hashGet.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_hashHas.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_hashSet.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_Hash.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_mapCacheClear.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_isKeyable.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_getMapData.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_mapCacheDelete.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_mapCacheGet.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_mapCacheHas.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_mapCacheSet.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_MapCache.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_stackSet.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_Stack.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_arrayEach.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_defineProperty.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseAssignValue.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_assignValue.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_copyObject.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseTimes.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isObjectLike.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseIsArguments.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isArguments.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isArray.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/stubFalse.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isBuffer.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_isIndex.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isLength.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseIsTypedArray.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseUnary.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_nodeUtil.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isTypedArray.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_arrayLikeKeys.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_isPrototype.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_overArg.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_nativeKeys.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseKeys.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isArrayLike.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/keys.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseAssign.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_nativeKeysIn.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseKeysIn.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/keysIn.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseAssignIn.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_cloneBuffer.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_copyArray.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_arrayFilter.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/stubArray.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_getSymbols.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_copySymbols.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_arrayPush.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_getPrototype.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_getSymbolsIn.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_copySymbolsIn.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseGetAllKeys.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_getAllKeys.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_getAllKeysIn.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_DataView.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_Promise.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_Set.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_WeakMap.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_getTag.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_initCloneArray.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_Uint8Array.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_cloneArrayBuffer.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_cloneDataView.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_cloneRegExp.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_cloneSymbol.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_cloneTypedArray.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_initCloneByTag.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseCreate.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_initCloneObject.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseIsMap.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isMap.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseIsSet.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isSet.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseClone.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/cloneDeep.js","../src/components/sanitizeSchema.ts","../src/plugins/defs.ts","../src/plugins/catalog.ts","../src/components/shortenDocumentId.ts","../src/components/devStageTimings.ts","../src/components/extendSanitizeSchema.ts","../src/components/smoothStream/controller.ts","../src/preprocessors/latex.ts","../src/preprocessors/index.ts","../src/preprocessors/remend.ts"],"sourcesContent":["/**\n * Streaming stress-payload fixtures, extracted verbatim from core's\n * stories/streaming/scenarios.ts (boundary action ⑦): the engine's\n * equivalence/sensitivity test batteries consume DEFAULT_PAYLOAD/withDefs,\n * and stories keep using them through the engine entry — one source, no\n * drifting copies.\n *\n * @module fixtures/scenarios\n */\n\nconst DEFAULT_BLOCKS = [\n '# Stress payload\\n\\n',\n 'Streaming markdown with mixed token boundaries — code, math, tables, admonitions — all incomplete during transit.\\n\\n',\n '```ts\\nconst fib = (n: number): number => (n < 2 ? n : fib(n - 1) + fib(n - 2));\\nconst result = Array.from({ length: 12 }, (_, i) => fib(i));\\n```\\n\\n',\n '$$\\n\\\\int_0^\\\\infty e^{-x^2}\\\\,dx = \\\\frac{\\\\sqrt{\\\\pi}}{2}\\n$$\\n\\n',\n 'Inline math like $E = mc^2$ and $\\\\frac{a}{b}$ keeps appearing.\\n\\n',\n '| Lang | Year | Stable |\\n| --- | --- | --- |\\n| JavaScript | 1995 | yes |\\n| TypeScript | 2012 | yes |\\n| Rust | 2010 | yes |\\n\\n',\n '> The hard part is **incomplete tokens** — code fences, LaTeX delimiters, table rows mid-emission.\\n\\n',\n '- bullet one with `inline code`\\n- bullet two with [link](https://example.com)\\n- bullet three closes the test payload.\\n',\n];\n\nexport const DEFAULT_PAYLOAD = DEFAULT_BLOCKS.join('');\n\n/** Definition-bearing tail appended by {@link withDefs}: footnote and\n * link-reference defs WITH in-text references. */\nconst DEFS_TAIL =\n 'References[^n1] appear mid-prose[^n2], along with [reference links][spec] and [another one][gfm].\\n\\n' +\n '[^n1]: First footnote body with `code` and a [link](https://example.com/fn).\\n' +\n '[^n2]: Second footnote body, plain text.\\n\\n' +\n '[spec]: https://spec.commonmark.org\\n' +\n '[gfm]: https://github.github.com/gfm/ \"GFM spec\"\\n';\n\n/**\n * Append the definitions tail to a payload (any payload — including the\n * ALREADY-SCALED one; apply after `.repeat()` so one tail serves the whole\n * document and no repeat seam glues a def line onto the next repetition).\n *\n * What this exercises — and what it does NOT: the default payload contains\n * zero definitions, so without this tail the def-label scanner runs on a\n * best-case input and the aggregate footnote footer never renders. With\n * it, def lines stream through the scanner's active region (its full-parse\n * slow path) and the footer assembles. It does NOT exercise the\n * cross-chunk PHANTOM path: each benchmark side is a single chunk, so no\n * label is ever defined \"elsewhere\" and the phantom candidate set stays\n * empty — measuring that needs a second chunk contributing definitions\n * the first one references.\n */\nexport function withDefs(payload: string): string {\n const sep = payload.endsWith('\\n\\n') ? '' : payload.endsWith('\\n') ? '\\n' : '\\n\\n';\n return payload + sep + DEFS_TAIL;\n}\n","/**\n * Unified processor and VFile setup. Ported 1:1 from react-markdown\n * v10 `createProcessor` and `createFile`.\n *\n * @module components/markdown/processor\n */\n\nimport { unreachable } from 'devlop';\nimport type { Root as HastRoot } from 'hast';\nimport type { Root as MdastRoot } from 'mdast';\nimport remarkParse from 'remark-parse';\nimport remarkRehype, { type Options as RemarkRehypeOptions } from 'remark-rehype';\nimport { type PluggableList, type Processor, unified } from 'unified';\nimport { VFile } from 'vfile';\nimport type { PipelineOptions } from './types';\n\nconst emptyPlugins: PluggableList = [];\nconst emptyRemarkRehypeOptions: Readonly<RemarkRehypeOptions> = { allowDangerousHtml: true };\n\n/**\n * Build the unified processor: remark-parse → remarkPlugins → remark-rehype →\n * rehypePlugins. Returns an unfrozen processor — caller is expected to call\n * `.parse()` and `.runSync()` (or `.run()`) on it.\n */\nexport function createProcessor(\n options: Readonly<PipelineOptions>\n): Processor<MdastRoot, MdastRoot, HastRoot, undefined, undefined> {\n const rehypePlugins = options.rehypePlugins || emptyPlugins;\n const remarkPlugins = options.remarkPlugins || emptyPlugins;\n const remarkRehypeOptions = options.remarkRehypeOptions\n ? { ...options.remarkRehypeOptions, ...emptyRemarkRehypeOptions }\n : emptyRemarkRehypeOptions;\n\n return unified().use(remarkParse).use(remarkPlugins).use(remarkRehype, remarkRehypeOptions).use(rehypePlugins);\n}\n\n/**\n * Wrap the markdown string in a VFile so plugins that consume `file.value`\n * work. Mirrors react-markdown: in dev `unreachable` throws an AssertionError\n * for non-string `children`; in prod it silently no-ops, leaving `file.value`\n * undefined and unified treating the input as empty.\n */\nexport function createFile(options: Readonly<PipelineOptions>): VFile {\n const children = options.children || '';\n const file = new VFile();\n\n if (typeof children === 'string') {\n file.value = children;\n } else {\n unreachable('Unexpected value `' + String(children) + '` for `children` prop, expected `string`');\n }\n\n return file;\n}\n","/**\n * The pure pipeline stages, lifted verbatim from core's Markdown.tsx\n * (boundary action ②): parseStage / transformStage are framework-agnostic\n * (mdast/hast in, hast out) and are consumed by the incremental-parse\n * engine, so they live engine-side; renderHastSubtree and the `<Markdown>`\n * component stay in core.\n *\n * The deprecation table and validation travel with parseStage — every\n * caller (React or not) must get identical validation semantics.\n *\n * @module components/markdown/stages\n */\n\nimport { unreachable } from 'devlop';\nimport type { Root as HastRoot } from 'hast';\nimport type { Root as MdastRoot } from 'mdast';\nimport type { Processor } from 'unified';\nimport type { VFile } from 'vfile';\nimport { createFile, createProcessor } from './processor';\nimport type { Deprecation, PipelineOptions } from './types';\n\nconst changelog = 'https://github.com/remarkjs/react-markdown/blob/main/changelog.md';\n\n/** Mirrors the deprecation table react-markdown ships — kept verbatim so error\n * messages and changelog hashes match upstream. */\nconst deprecations: ReadonlyArray<Readonly<Deprecation>> = [\n { from: 'astPlugins', id: 'remove-buggy-html-in-markdown-parser' },\n { from: 'allowDangerousHtml', id: 'remove-buggy-html-in-markdown-parser' },\n {\n from: 'allowNode',\n id: 'replace-allownode-allowedtypes-and-disallowedtypes',\n to: 'allowElement',\n },\n {\n from: 'allowedTypes',\n id: 'replace-allownode-allowedtypes-and-disallowedtypes',\n to: 'allowedElements',\n },\n { from: 'className', id: 'remove-classname' },\n {\n from: 'disallowedTypes',\n id: 'replace-allownode-allowedtypes-and-disallowedtypes',\n to: 'disallowedElements',\n },\n { from: 'escapeHtml', id: 'remove-buggy-html-in-markdown-parser' },\n { from: 'includeElementIndex', id: '#remove-includeelementindex' },\n {\n from: 'includeNodeIndex',\n id: 'change-includenodeindex-to-includeelementindex',\n },\n { from: 'linkTarget', id: 'remove-linktarget' },\n { from: 'plugins', id: 'change-plugins-to-remarkplugins', to: 'remarkPlugins' },\n { from: 'rawSourcePos', id: '#remove-rawsourcepos' },\n { from: 'renderers', id: 'change-renderers-to-components', to: 'components' },\n { from: 'source', id: 'change-source-to-children', to: 'children' },\n { from: 'sourcePos', id: '#remove-sourcepos' },\n { from: 'transformImageUri', id: '#add-urltransform', to: 'urlTransform' },\n { from: 'transformLinkUri', id: '#add-urltransform', to: 'urlTransform' },\n];\n\n/**\n * Validate options that have nothing to do with the input markdown — kept\n * separate so the block-memo wrapper can validate once per render rather than\n * once per block-render call.\n */\nfunction validateOptions(options: Readonly<PipelineOptions>): void {\n for (const deprecation of deprecations) {\n if (Object.hasOwn(options, deprecation.from)) {\n unreachable(\n 'Unexpected `' +\n deprecation.from +\n '` prop, ' +\n (deprecation.to ? 'use `' + deprecation.to + '` instead' : 'remove it') +\n ' (see <' +\n changelog +\n '#' +\n deprecation.id +\n '> for more info)'\n );\n }\n }\n\n if (options.allowedElements && options.disallowedElements) {\n unreachable('Unexpected combined `allowedElements` and `disallowedElements`, expected one or the other');\n }\n}\n\n/** Bundled processor + parsed mdast + VFile, ready to feed `transformStage`. */\nexport interface ParsedMarkdown {\n processor: Processor<MdastRoot, MdastRoot, HastRoot, undefined, undefined>;\n file: VFile;\n mdast: MdastRoot;\n}\n\n/**\n * Stage 1: validate options, build the unified processor, parse the markdown\n * source into raw (pre-transform) mdast. The returned `mdast` is mutated in\n * place by remark plugins during {@link transformStage}, but its top-level\n * `position` offsets remain valid keys for hast→mdast lookup.\n */\nexport function parseStage(options: Readonly<PipelineOptions>): ParsedMarkdown {\n validateOptions(options);\n const processor = createProcessor(options);\n const file = createFile(options);\n const mdast = processor.parse(file);\n return { processor, file, mdast };\n}\n\n/**\n * Stage 2: run remark transformers, remark-rehype, and rehype plugins. Returns\n * the final hast Root. The mdast in {@link ParsedMarkdown} may be mutated\n * by remark transformers as a side effect of this call.\n */\nexport function transformStage(parsed: ParsedMarkdown): HastRoot {\n return parsed.processor.runSync(parsed.mdast, parsed.file);\n}\n","/**\n * Single-pass hast tree transform: rewrites raw HTML, runs `urlTransform` on\n * URL attributes, and applies `allowedElements` / `disallowedElements` /\n * `allowElement` filters. Ported 1:1 from react-markdown v10.\n *\n * @module components/markdown/transform\n */\n\nimport type { Element, Root } from 'hast';\nimport { urlAttributes } from 'html-url-attributes';\nimport type { BuildVisitor } from 'unist-util-visit';\nimport type { AllowElement, UrlTransform } from './types';\n\nexport interface TransformContext {\n allowedElements: ReadonlyArray<string> | null | undefined;\n allowElement: AllowElement | null | undefined;\n disallowedElements: ReadonlyArray<string> | null | undefined;\n skipHtml: boolean | null | undefined;\n unwrapDisallowed: boolean | null | undefined;\n urlTransform: UrlTransform;\n}\n\nexport function buildTransform(ctx: TransformContext): BuildVisitor<Root> {\n return function transform(node, index, parent) {\n if (node.type === 'raw' && parent && typeof index === 'number') {\n if (ctx.skipHtml) {\n parent.children.splice(index, 1);\n } else {\n parent.children[index] = { type: 'text', value: (node as { value: string }).value };\n }\n return index;\n }\n\n if (node.type === 'element') {\n const element = node as Element;\n let key: string;\n // hast's `Element.properties` is typed `Properties | undefined`. In the\n // current pipeline every emitter sets it to at least `{}`, but a future\n // custom handler that omits `properties` would otherwise blow up in\n // `Object.hasOwn` here — keep the fallback so the transform stays robust\n // against new handler shapes.\n const properties = element.properties ?? {};\n\n for (key in urlAttributes) {\n if (Object.hasOwn(urlAttributes, key) && Object.hasOwn(properties, key)) {\n const test = (urlAttributes as Record<string, ReadonlyArray<string> | null>)[key];\n if (test === null || test.includes(element.tagName)) {\n // Convergent application: always transform FROM the original —\n // the stash if an earlier pass archived one, else the live\n // property (untouched ⇔ nothing was archived). A shared\n // (memoized) tree that is re-entered without a re-parse — a\n // block-memo cache miss after a G3 flush, a urlTransform prop\n // swap, the aggregate footnote tree on a registry bump — then\n // yields `currentTransform(original)` instead of compounding the\n // transform onto its own previous output. This is what lets\n // `renderHastSubtree` skip the defensive clone for URL rewriting.\n //\n // The stash is written only by the first pass that actually\n // CHANGES the value: the default transform is identity for safe\n // URLs, and these elements live long in the block-memo cache and\n // the registry's footnote trees — an unconditional per-element\n // stash would be retained dead weight on every URL-bearing node.\n const stash = (element.data as { originalUrls?: Record<string, unknown> } | undefined)?.originalUrls;\n const hasStash = stash !== undefined && key in stash;\n const original = hasStash ? stash[key] : properties[key];\n const transformed = ctx.urlTransform(String(original || ''), key, element);\n if (!hasStash && transformed !== original) {\n const data = (element.data ??= {}) as { originalUrls?: Record<string, unknown> };\n (data.originalUrls ??= {})[key] = original;\n }\n properties[key] = transformed;\n }\n }\n }\n element.properties = properties;\n }\n\n if (node.type === 'element') {\n const element = node as Element;\n let remove = ctx.allowedElements\n ? !ctx.allowedElements.includes(element.tagName)\n : ctx.disallowedElements\n ? ctx.disallowedElements.includes(element.tagName)\n : false;\n\n if (!remove && ctx.allowElement && typeof index === 'number') {\n remove = !ctx.allowElement(element, index, parent);\n }\n\n if (remove && parent && typeof index === 'number') {\n if (ctx.unwrapDisallowed && element.children) {\n parent.children.splice(index, 1, ...element.children);\n } else {\n parent.children.splice(index, 1);\n }\n return index;\n }\n }\n\n return undefined;\n };\n}\n","/**\n * Default URL transform — same allowlist as react-markdown / GitHub.\n *\n * @module components/markdown/urlTransform\n */\n\nimport type { UrlTransform } from './types';\n\nconst safeProtocol = /^(https?|ircs?|mailto|xmpp)$/i;\n\n/**\n * Make a URL safe.\n *\n * Allows `http`, `https`, `irc`, `ircs`, `mailto`, and `xmpp` protocols, plus\n * URLs relative to the current protocol (e.g. `/foo`). Other protocols are\n * stripped to the empty string. Mirrors GitHub's behaviour and matches\n * `micromark-util-sanitize-uri` minus the URL-encoding pass.\n */\nexport const defaultUrlTransform: UrlTransform = (value) => {\n const colon = value.indexOf(':');\n const questionMark = value.indexOf('?');\n const numberSign = value.indexOf('#');\n const slash = value.indexOf('/');\n\n if (\n // No protocol → relative.\n colon === -1 ||\n // First colon is after `/`, `?`, or `#` → not a protocol.\n (slash !== -1 && colon > slash) ||\n (questionMark !== -1 && colon > questionMark) ||\n (numberSign !== -1 && colon > numberSign) ||\n // Allowed protocol.\n safeProtocol.test(value.slice(0, colon))\n ) {\n return value;\n }\n\n return '';\n};\n","/**\n * Freeze-boundary detector for incremental (prefix-freeze) parsing.\n *\n * Production port of the \"L4\" rule validated by the measurement study in\n * `src/experiments/prefixFreeze/` (see its README for the ablation ladder,\n * the falsification results, and the intentional two-way divergence note —\n * stricter blockers AND looser code-span masking; the corpus-scoped\n * directional pin lives in detectorConsistency.test.ts).\n *\n * The boundary is the largest source offset `b` such that, for ANY future\n * append to `text`, the markdown blocks that begin before `b` parse\n * byte-identically. Candidates are confirmed blank lines outside fenced\n * code and flow math; a candidate survives only if every blocker below\n * clears:\n *\n * 1. **Raw-HTML balance** — an unclosed container tag (or `<!--` comment)\n * before the candidate lets rehype-raw reparent later top-level siblings\n * into it (the v1.5.1 swallow bug, commit a8e89ec). Tag balance is\n * tracked outside fences; while any tag, comment, or raw block\n * (`<?…?>` / `<!DECL…>` / `<![CDATA[…]]>` — CommonMark html block types\n * 3–5) is open, candidates are blocked. Line-truncated tag starts\n * (`<div` at EOL, attributes wrapping) count as opens. Closers that\n * OVERLAP their opener (`<!-->`, `<!--->`, line-start `<?>`) close on\n * the spot — CommonMark and parse5 agree — so the markup after them is\n * scanned, not skipped as construct interior.\n * 2. **`$$` flow math** — remark-math's flow math swallows blank lines and\n * runs to EOF when unclosed (verified empirically); its closing fence\n * must sit at LINE START (a mid-line `$$` does not close it). Math\n * interiors are treated exactly like fence interiors: no candidates.\n * 3. **Continuation context** — CommonMark lists, footnote definitions, and\n * indented code blocks are NOT terminated by blank lines; later indented\n * lines can extend a block that \"ended\" before the candidate. With the\n * definition-list extension enabled, `: description` bodies behave the\n * same way.\n * 4. **Definition-list term claim** (`options.defListEnabled`) — the\n * micromark definition-list extension scans BACKWARD across exactly one\n * blank line to claim a preceding paragraph as a `<dt>`. A candidate\n * whose blank run is 1 is only safe once the next line is confirmed to\n * never match `^ {0,3}:[ \\t]`; runs of ≥ 2 blanks are immune.\n * 5. **Reference taint** — micromark decides reference-ness at parse time,\n * so a later `[label]:` definition retargets earlier literal `[text]`.\n * Every reference-style candidate before the boundary must resolve\n * against a SETTLED definition (one followed by a confirmed blank line).\n * Labels are matched with micromark's own `normalizeIdentifier`\n * (Unicode case folding — `toLowerCase` is the unsafe direction).\n * Definitions must START a block (or chain a valid definition line) —\n * a def-shaped paragraph continuation line is literal text.\n * 6. **Raw-remnant seam** — an html FLOW run can swallow non-tag lines\n * (e.g. a `$$` math fence glued under `</details>`); once tag balance\n * returns to zero, that remnant becomes FLOATING text that parse5/\n * rehype-raw attaches at the root, and its hast shape (position vs\n * seam-owned position-less, trailing-newline ownership) depends on\n * whether a sibling node FOLLOWS it. A tail block that flips between\n * def (no hast output) and paragraph therefore reshapes the frozen\n * region retroactively (2026-07-31 direction-battery counterexample,\n * reproduced on v1.8.0). Every candidate emitted while the remnant is\n * the last frozen child is rejected (they stay rejected for good); once\n * a later confirmed content line pins the seam from the frozen side,\n * the candidates AFTER that line are safe again. Dropping candidates\n * only over-blocks (safe direction). Whitespace-only remnant counts.\n * A type 2-5 block that opens AND closes on its first line owns the\n * rest of that line as raw content too (`<!-- c --> tail`) — same seam.\n * 7. **Phase poison** (`phasePoisonedAt`) — points where this line-level\n * model may have DIVERGED from micromark and provably cannot resync:\n * a fence/math open suppressed inside an html-flow run (only certainly\n * swallowed at top level — in a container it really opens and the\n * open/close phase inverts permanently), and a paragraph-inline `<!--`\n * that fails to close by end of line (literal text to micromark, but\n * the comment scan would skip real markup as comment interior), and\n * every point where CommonMark's terminator and parse5's tokenizer\n * DISAGREE about where a raw construct ends (`--!>` closes a comment\n * for parse5 only; a `<?…`/`<![CDATA[…` bogus comment ends at its\n * first `>` for parse5 but at `?>`/`]]>` for CommonMark; a paragraph-\n * inline `<?>` is open to micromark, closed to parse5) — the bytes in\n * between are raw text to one grammar and real markup to the other, and\n * the hast is parse5's. Every candidate past the first such point is\n * rejected, sticky; candidates at or before it stay valid — the\n * ambiguous region then re-parses inside the tail (pure over-block).\n *\n * ## Incremental scanning (checkpoint resume)\n *\n * The hot path calls this once per streamed frame. Appends leave every\n * previously-CONFIRMED line byte-identical, so the scan checkpoints its\n * entire per-line state after the last confirmed line (one whose\n * terminating `\\n` exists) and, given `resume`, re-lexes only from there.\n * The trailing PARTIAL line is never baked into the checkpoint: it cannot\n * emit candidates (unconfirmed lines are never blank), its tag/ref effects\n * cannot affect candidates that all precede it, and the next frame re-lexes\n * it from scratch. Resume MUTATES the checkpoint monotonically and is\n * idempotent for identical input — but a checkpoint belongs to exactly one\n * advancing state lineage (advanceIncrementalParse's), never share it.\n *\n * Continuation hazards (blocker 3) are a forward-rolling verdict updated at\n * each decisive block start — equivalent to the previous per-candidate\n * upward walk (\"nearest decisive block start above\") at O(1) per candidate.\n * Reference taint (blocker 5) maintains defs and an unresolved-ref list\n * incrementally; settling is monotone, so resolved entries only ever leave.\n *\n * ## Inline code-span masking\n *\n * `` `<div>` ``, `` `[x]` `` and `` `[^n]` `` in prose are code, not\n * markup. Before HTML/ref/footnote extraction each line is masked using\n * micromark's own pairing rule (equal-length backtick runs, leftmost\n * first) — but ONLY when the pairing is provably intra-line: if any run on\n * a line is left unpaired, or an earlier line of the same paragraph left\n * one unpaired, masking is disabled for the rest of the paragraph. A\n * cross-line span can therefore never cause an unmask mismatch: every\n * masked span is one micromark would pair identically. Skipped masking\n * only over-blocks (safe direction).\n *\n * A line only counts as blank once its terminating newline exists: the\n * trailing partial line is UNCONFIRMED (the next chunk may append content\n * to it) and treating it as blank breaks boundary monotonicity.\n *\n * Footnote refs/defs participate in blockers 3 and 5 like their link\n * counterparts (separate label namespace); the engine splices across them\n * via injection replay (v2).\n */\n\nimport { htmlBlockNames } from 'micromark-util-html-tag-name';\nimport { isMdBlank, mdTrimStart } from './mdLineText';\nimport {\n collectRefLine,\n settleRefsAndEarliestUnresolved,\n DEF_RE,\n FOOTNOTE_DEF_RE,\n type UnresolvedRef,\n} from './referenceTaint';\n\n/** CommonMark type-6 block tag names (micromark's own list), lowercase. */\nconst TYPE6_NAMES = new Set(htmlBlockNames);\n/** Table-part tag names: a stray one outside a table re-routes how parse5\n * builds every LATER GFM table (cell text foster-parented to the root —\n * v2.4.2 review P1-2; the splice bails on any such tag in the frozen\n * prefix). Poisoning candidates from the tag on at the scanner saves the\n * per-frame scan + tail parse + splice attempt that the bail would throw\n * away, and keeps the direction battery honest (soak 2026-08-19: a\n * `<td>` prefix froze a table whose shape depended on the tail). Same\n * list as spliceParse's TABLE_PART_TAG_RE. */\nconst TABLE_PART_NAMES = new Set(['td', 'th', 'tr', 'tbody', 'thead', 'tfoot', 'caption', 'col', 'colgroup']);\n/** parse5 tree-construction CONSUMES these tokens: `rehype-raw` parses in\n * FRAGMENT mode with a `<template>` context, so the run starts in \"in\n * template\" and `startTagInTemplate` routes these names onward to the modes\n * that absorb them into document structure — they emit NO node into the\n * fragment. Their bytes\n * vanish and the text nodes on either side MERGE into one — a merge whose\n * result STARTS BEFORE the construct. That is retroactive: a `<!DOCTYPE>`\n * arriving later rewrites hast the scanner already froze (2026-08-20,\n * 16800-shape sweep: `` `\\`\\`\\`\\n\\`\\`\\`\\n\\n<!DOCTYPE>\\ne` `` — the text node at\n * index 1 goes `\"\\n\"` → `\"\\n\\n\"`). Every other line-model invariant here\n * assumes a confirmed line only affects itself and what follows, so these\n * names cannot be modelled — they poison the whole document instead.\n *\n * Counter-intuitively an UNCLOSED `<body>` was already safe: it left\n * `openTotal` at 1, which blocked candidates by accident. Only the\n * BALANCED `<body>…</body>` form reaches zero and freezes across. */\nconst DOCUMENT_STRUCTURE_NAMES = new Set(['html', 'head', 'body', 'frameset']);\n\n/** The same retroactive constructs as literal openers, for the TRAILING\n * PARTIAL line. That line is never confirmed and never enters the\n * checkpoint, so `processConfirmedLine` cannot poison from it — yet the\n * full parse the frozen prefix is checked against DOES see it, and a\n * half-arrived `<!DOCTYPE html` already erases and merges (soak leg 1,\n * shards 3 and 9: a snapshot cut mid-doctype froze at a boundary the\n * arriving doctype then rewrote). */\nconst RETROACTIVE_OPENERS = [\n '<!doctype',\n '<html',\n '<head',\n '<body',\n '<frameset',\n '</html',\n '</head',\n '</body',\n '</frameset',\n];\n\n/** Does a partial line already carry one of them? Matches COMPLETE openers\n * only. A \"could still become one\" arm was tried and reverted: every `<`\n * is a prefix of every opener, so a stream cut right after a `<` dropped\n * the boundary to 0 — and since the consumer takes\n * `min(boundary, prev.stableBoundary)`, one transient dip disables\n * freezing for the whole stream permanently. Frames that cut INSIDE an\n * opener (`…<!DOCTYP`) need no suppression: the full parse they are\n * checked against does not see a doctype there either, so the frozen\n * prefix still matches. Suppresses the BOUNDARY only — nothing here may\n * reach the checkpoint, since the tail is not confirmed. */\nfunction tailCarriesRetroactive(text: string): boolean {\n const lower = text.toLowerCase();\n for (let i = lower.indexOf('<'); i !== -1; i = lower.indexOf('<', i + 1)) {\n const rest = lower.slice(i);\n for (const op of RETROACTIVE_OPENERS) if (rest.startsWith(op)) return true;\n }\n return false;\n}\n/** HTML start tags that BREAK OUT of foreign content (HTML spec \"in foreign\n * content\": the svg/math is popped and the tag is processed as HTML). */\n/** Elements whose CONTENT is parsed with HTML rules again inside svg/math. */\n// `title` belongs here too: an SVG `title` is an HTML integration point, so\n// its CONTENT is parsed with HTML rules (a `<g/>` inside it opens an element\n// rather than honouring its self-closing flag). Adding the name is safe for\n// the tokenizer question as well, because every call site asks BEFORE this\n// tag's own `applyTag` counts it: while `<title>` itself is judged the count\n// is still 0, so it does not switch to RCDATA — which is correct, a foreign\n// `title` stays in the DATA state — and once it is open its children see\n// HTML rules, which is also correct. `annotation-xml` is an HTML integration\n// point only when its `encoding` is text/html or application/xhtml+xml;\n// treating it as one unconditionally over-blocks, i.e. errs safe.\n/** parse5 ignores an end tag whose element is not \"in scope\": the search walks\n * DOWN the open-element stack and stops at a barrier. `<div><table></div>`\n * therefore leaves the div OPEN — `</div>` is discarded, `</table>` pops only\n * the table — and everything after it nests inside that div.\n *\n * A name→count bag cannot see this: it decrements `div` because it counted a\n * `div`, and reports balance. That is an UNDER-block, live since the scanner\n * was written and found 2026-08-24 (`<div><table></div></table>` freezes at\n * 41 of 66 while the full parse nests the whole tail inside the div).\n * `marquee`, `object`, `template` and `applet` are the same family.\n *\n * Per the HTML spec's \"has an element in scope\"; the MathML text integration\n * points and the SVG ones are barriers too. */\nconst SCOPE_BARRIER_NAMES = new Set([\n 'applet',\n 'caption',\n 'html',\n 'table',\n 'td',\n 'th',\n 'marquee',\n 'object',\n 'template',\n 'mi',\n 'mo',\n 'mn',\n 'ms',\n 'mtext',\n 'annotation-xml',\n 'foreignobject',\n 'desc',\n 'title',\n]);\n/** The two foreign-namespace roots markdown can reach. */\nconst FOREIGN_ROOT_NAMES = ['svg', 'math'];\n/** CommonMark type-1 block start names — start tags only. */\nconst TYPE1_NAMES = new Set(['script', 'pre', 'style', 'textarea']);\n/** parse5 elements whose CONTENT is text to the tokenizer (RAWTEXT /\n * RCDATA / script data / plaintext): every `<…>` inside is text until the\n * element's own end tag. Not the CommonMark type-1 list — `title`,\n * `iframe`, `noframes`, `xmp`, `noembed` sit in the type-6 list, so their content is a normal html\n * block to micromark yet text to parse5, and a `</div>` in there closed the\n * outer div in the balance (2026-08-19 review r2 P1-4). `plaintext` never\n * ends. */\nconst RAW_TEXT_ELEMENTS = new Set([\n 'script',\n 'style',\n 'textarea',\n 'title',\n 'xmp',\n 'iframe',\n 'noembed',\n 'noframes',\n // NOT `noscript`: hast-util-raw constructs parse5 with\n // `scriptingEnabled: false`, under which `<noscript>` content is ordinary\n // HTML — modelling it as raw text ignored a `<b>` inside and under-blocked\n // (oracle review of the r2 batch; regression caught before release).\n 'plaintext',\n]);\n/** Bytes parse5's DATA state acts on: `<` + letter / `!` / `/` / `?`.\n * Everything else (a lone `<`, `< b`) is character data. Used by the\n * `--!>` divergence-window check: a window containing none of these is\n * text to BOTH grammars and may converge. */\nconst P5_MARKUP_RE = /<[!/?A-Za-z]/;\n/** Type-6 start: `<`/`</` + name + (whitespace | `>` | `/>` | EOL). */\nconst TYPE6_START_RE = /^<\\/?([A-Za-z][A-Za-z0-9-]*)(?:[ \\t\\r]|\\/?>|$)/;\n/** Type-1 start: an OPEN tag of a raw-text name + (whitespace | `>` | EOL). */\nconst TYPE1_START_RE = /^<(script|pre|style|textarea)(?:[ \\t\\r]|>|$)/i;\n/** Type 1's end condition is a literal substring anywhere on the line —\n * no attributes, no whitespace before `>` (CommonMark 4.6). */\nconst TYPE1_CLOSE_RE = /<\\/(?:script|pre|style|textarea)>/i;\n/** Type-7 start, EXACT (§4.6 condition 7 + the §2.2 tag grammar): the whole\n * line is one complete OPEN tag or one complete CLOSING tag, followed by\n * whitespace only. Attribute values follow the spec grammar — a QUOTED\n * value may contain `>` (`<span title=\"a>b\">` alone on a line IS a type-7\n * block), an unquoted value may not (`<span title=a>b>` is a paragraph),\n * an attribute name is `[A-Za-z_:][A-Za-z0-9:._-]*`, an empty unquoted\n * value (`<a href=>`) invalidates the tag, and `/` self-closing must sit\n * directly before the `>` — every shape measured against micromark before\n * the approximate `[^>]*` test this replaces was retired (it both missed\n * the quoted-`>` class, which the retired `mayBeRawToMicromark` flag\n * existed to cover, and\n * over-accepted attribute garbage on non-type-6 names).\n *\n * Closing tags take NO attributes (`</span a=\"b\">` is a paragraph, and\n * treating it as html flow made the scanner apply a close parse5 never\n * sees: `<span>\\n\\n</span a=\"b\">\\n\\ntail` froze past a still-open span —\n * oracle re-check of the r2 batch. Type 6 is unaffected — its names are\n * recognized on `</name` + whitespace regardless of what follows.) */\nconst isSpaceTab = (c: number): boolean => c === 32 || c === 9;\nconst isAsciiAlpha = (c: number): boolean => (c >= 65 && c <= 90) || (c >= 97 && c <= 122);\nconst isAlnum = (c: number): boolean => isAsciiAlpha(c) || (c >= 48 && c <= 57);\n/** completeAttributeName continuation set: alphanumeric, `-` `.` `:` `_`. */\nconst isAttrNameRest = (c: number): boolean => isAlnum(c) || c === 45 || c === 46 || c === 58 || c === 95;\n/** completeAttributeValueUnquoted EXIT set (the value may not contain\n * these; note `=` exits into completeAttributeNameAfter, which happily\n * consumes another `=` — so `<foo a=b=c>` IS a complete tag to micromark,\n * looser than the spec's written grammar, measured and matched here). */\nconst isUnquotedExit = (c: number): boolean =>\n Number.isNaN(c) || c === 34 || c === 39 || c === 47 || c === 60 || c === 61 || c === 62 || c === 96 || isSpaceTab(c);\n\n/** The attribute area + `>` of a complete OPEN tag, transcribed state for\n * state from micromark's html-flow complete path (nameBefore / name /\n * nameAfter / valueBefore / valueQuoted(+After) / valueUnquoted / end).\n * Returns the index just past the closing `>`, or -1 where micromark\n * reaches `nok`. */\nconst completeOpenTagRest = (t: string, from: number): number => {\n let i = from;\n for (;;) {\n // completeAttributeNameBefore\n const c = t.charCodeAt(i);\n if (c === 47 /* / */) {\n i += 1;\n break; // → completeEnd\n }\n if (isSpaceTab(c)) {\n i += 1;\n continue;\n }\n if (!(c === 58 || c === 95 || isAsciiAlpha(c))) break; // → completeEnd\n i += 1; // completeAttributeName\n while (isAttrNameRest(t.charCodeAt(i))) i += 1;\n // completeAttributeNameAfter — also re-entered after an unquoted value,\n // which is what makes `=` chains legal.\n for (;;) {\n while (isSpaceTab(t.charCodeAt(i))) i += 1;\n if (t.charCodeAt(i) !== 61 /* = */) break; // → completeAttributeNameBefore\n i += 1; // completeAttributeValueBefore\n while (isSpaceTab(t.charCodeAt(i))) i += 1;\n const v = t.charCodeAt(i);\n if (Number.isNaN(v) || v === 60 || v === 61 || v === 62 || v === 96) return -1;\n if (v === 34 || v === 39) {\n // completeAttributeValueQuoted: anything but the marker or EOL.\n i += 1;\n while (t.charCodeAt(i) !== v) {\n if (i >= t.length) return -1;\n i += 1;\n }\n i += 1;\n // completeAttributeValueQuotedAfter: `/`, `>` or whitespace only.\n const a = t.charCodeAt(i);\n if (!(a === 47 || a === 62 || isSpaceTab(a))) return -1;\n break; // → completeAttributeNameBefore\n }\n // completeAttributeValueUnquoted (possibly empty: `<a b=/>` is\n // complete — the `/` exits straight through nameAfter to the end).\n while (!isUnquotedExit(t.charCodeAt(i))) i += 1;\n // → completeAttributeNameAfter(code) — loop.\n }\n }\n // completeEnd\n return t.charCodeAt(i) === 62 /* > */ ? i + 1 : -1;\n};\n\n/** Whether a line (leading indent stripped) meets §4.6 condition 7 — one\n * complete open or closing tag, whitespace only after — EXACTLY as\n * micromark decides it, including its tagName dispatch:\n * - a type-6 NAME never reaches condition 7 (`<div a=\"b>\">` is type 6,\n * `</div>` too — realT6 at the call site agrees);\n * - an OPEN raw-text name is type 1 — UNLESS the name is followed by `/`\n * (`<style/>` is a complete type-7 tag, measured);\n * - a CLOSING tag takes no attributes but its name is unrestricted:\n * `</style>` alone on a line IS type 7 (the earlier \"paragraph as end\n * tags\" note in Table A was wrong, and harmless only while\n * the retired `mayBeRawToMicromark` flag blanket-covered every\n * `<`-starting line).\n * A lone `\\r` is a LINE ENDING to micromark, not tag whitespace — the\n * classification runs on the segment before it (the rest of the physical\n * line is the block's first content either way). */\nexport const isType7Line = (line: string): boolean => {\n const cr = line.indexOf('\\r');\n const t = cr === -1 ? line : line.slice(0, cr);\n if (t.charCodeAt(0) !== 60 /* < */) return false;\n let i = 1;\n const closing = t.charCodeAt(i) === 47;\n if (closing) i += 1;\n if (!isAsciiAlpha(t.charCodeAt(i))) return false;\n const nameStart = i;\n i += 1;\n while (isAlnum(t.charCodeAt(i)) || t.charCodeAt(i) === 45) i += 1;\n const c = t.charCodeAt(i); // NaN at end of line\n // tagName exit set (EOL / `/` / `>` / whitespace); anything else is nok.\n if (!(Number.isNaN(c) || c === 47 || c === 62 || isSpaceTab(c))) return false;\n const name = t.slice(nameStart, i).toLowerCase();\n if (!closing && c !== 47 && TYPE1_NAMES.has(name)) return false; // type 1\n if (TYPE6_NAMES.has(name)) return false; // type 6 (or its basicSelfClosing)\n if (closing) {\n // completeClosingTagAfter: whitespace, then completeEnd's `>`.\n while (isSpaceTab(t.charCodeAt(i))) i += 1;\n if (t.charCodeAt(i) !== 62) return false;\n i += 1;\n } else {\n i = completeOpenTagRest(t, i);\n if (i === -1) return false;\n }\n // completeAfter: whitespace only to the end of (micromark's) line.\n while (isSpaceTab(t.charCodeAt(i))) i += 1;\n return i >= t.length;\n};\n\nexport interface FreezeBoundaryOptions {\n /** Whether remark-definition-list is in the active plugin chain (the\n * `enginePlugins` selection includes `definitionList`). Enables blockers 3b/4. */\n defListEnabled: boolean;\n /**\n * Whether `$$` flow math is in the grammar (remark-math). Default `true`\n * (the engine's own profile). The def-label scanner runs a PINNED\n * remark-parse+gfm subset where `$$` is ordinary paragraph text — under\n * that grammar the math branch is a MASKING hole: `inMath` returns early\n * without comment/fence scanning, so `$$\\n<!--\\n$$` reads as a closed\n * math block here while the subset grammar sees an OPEN type-2 HTML\n * comment running to `-->`/EOF (a candidate after it would let a\n * standalone tail parse invent ghost defs). With `false`, `$$` lines take\n * the ordinary text path and comments/fences inside are scanned.\n */\n mathFlow?: boolean;\n /**\n * Whether blocker 5 (reference taint) applies. Default `true`: the\n * engine must reject candidates past an unresolved `[label]` because a\n * later definition retargets the reference's PARSE. The def-label\n * scanner only extracts definition IDENTITIES — a pure block-level fact\n * unaffected by how inline references resolve — and under taint a\n * streaming citation footer (defs with no settling blank line yet)\n * collapses the boundary to the body's first reference, zeroing the\n * caching this profile exists for. `false` skips ref tracking entirely.\n */\n referenceTaint?: boolean;\n}\n\nexport interface FreezeScanResult {\n /** Largest freeze-safe boundary, or 0 when nothing can be frozen. */\n boundary: number;\n /** Opaque resume state — pass back on the next APPEND-ONLY call to skip\n * re-lexing the confirmed prefix. Single-consumer; see module docs. */\n checkpoint: FreezeScanCheckpoint;\n}\n\ninterface LineRec {\n start: number;\n end: number; // offset of the terminating \\n, or text.length for the last line\n text: string; // line content WITHOUT the line ending (a CRLF's `\\r` is stripped too)\n blank: boolean;\n indent: number; // leading whitespace width, tab = 4 (approximation)\n}\n\ninterface Candidate {\n /** Freeze boundary: start of the line after this blank line. */\n offset: number;\n /** Consecutive confirmed blank lines (outside fences/math) ending here. */\n blankRun: number;\n /** No unbalanced HTML container / comment / raw block before this point. */\n htmlBalanced: boolean;\n /** Rolling continuation-hazard verdict at emission (blocker 3). */\n hazard: boolean;\n /** Blocker-6: the run ending at this blank left balanced FLOATING raw\n * remnant whose hast seam is tail-dependent; reject this candidate. */\n seamRisk: boolean;\n /** Blocker-4 settle verdict, decided by the NEXT confirmed line (`null`\n * while that line hasn't confirmed — only the newest candidate can be\n * pending). Storing the verdict instead of the line lets the checkpoint\n * drop its lines array, which retained a full copy of the document\n * (round-2 review: ~2-3× doc size per mounted instance). */\n defListSettled: boolean | null;\n}\n\n/** micromark's open VERBATIM flow construct at a line boundary (two-model\n * P4a, first slice): fenced code and `$$` flow math — the members whose\n * interiors are candidate-free and whose close is a marker line. The\n * html-block types join this union in the next slice. `indent` is the\n * opener line's indent (0-3): only a column-0 opener is provably\n * top-level, so `pendingFenceCloser` suppresses the closer otherwise\n * (v2.4.0 review R1). Members are REPLACED, never mutated (see P5Tok). */\ntype MdBlock =\n | { kind: 'none' }\n | { kind: 'fence'; char: string; len: number; indent: number }\n | { kind: 'math'; len: number; indent: number }\n /** Type 1, the one html block whose four names do NOT share a parse5\n * answer: `script`/`style`/`textarea` are raw-text elements, `pre` is\n * not (it is absent from `RAW_TEXT_ELEMENTS`, and parse5 tokenizes its\n * content in the DATA state). `raw` carries that fact ON the member,\n * taken from the name at the claim site — the consumer that needs it\n * asks about PARSE5's grammar, not micromark's, and inferring it from\n * `p5Tok` there would read a field the same line sets one phase later. */\n | { kind: 'html'; type: 1; raw: boolean }\n /** The rest of the CommonMark html blocks. Types 2-5 end by their own\n * terminators; types 6/7 end at the blank. Type 7 is entered by the\n * EXACT §4.6 test (`isType7Line`) since the exact-type-7 stage — the\n * attribute-quote hole the approximate test had (and the retired\n * `mayBeRawToMicromark` flag covered) is\n * closed, which is what let the remaining run-flag consumers migrate\n * to the member. */\n | { kind: 'html'; type: 2 | 3 | 4 | 5 | 6 | 7 };\n\nconst mdHtml = (b: MdBlock, type: 1 | 2 | 3 | 4 | 5): boolean => b.kind === 'html' && b.type === type;\n/** A type-1 block whose element is RAW TEXT to parse5 too — the state in\n * which both grammars agree every byte up to the closer is content. The\n * `pre` half of type 1 is deliberately excluded (F13). */\nconst mdType1RawText = (b: MdBlock): boolean => b.kind === 'html' && b.type === 1 && b.raw;\n/** Types 2-5 open: the interiors both grammars agree are raw content. */\nconst mdHtml25 = (b: MdBlock): boolean => b.kind === 'html' && b.type >= 2 && b.type <= 5;\n\n/** parse5 tokenizer macro-state at a LINE BOUNDARY (two-model P3a, T3.1).\n * A PARTITION of {data, rawText, script, bogus} — measured before the\n * design was frozen: the within-tag attribute position co-exists with any\n * of these (`<iframe>\\n</iframe a=\"`), so it is the separate `pendingTag`\n * overlay, NOT a member. `openedInline` is captured AT OPEN (the old\n * `rawTextInline` latch — the run state is reset before the poison that\n * reads it, so a live read would lose the poison). Members are REPLACED,\n * never mutated: checkpoints are shared mutable state, and a module-level\n * token constant would alias across mounted documents. */\ntype P5Tok =\n | { kind: 'data' }\n /** RAWTEXT / RCDATA content: everything is text until `</element`. */\n | { kind: 'rawText'; element: string; openedInline: boolean }\n /** SCRIPT_DATA with the full escape ladder (P3b batch 1, the F6\n * retirement): `escaped` = a `<!--` ran without its `-->`; `double` = a\n * nested `<script` start tag arrived while escaped (implies `escaped`).\n * While `double`, a `</script>` steps back to escaped and the ELEMENT\n * STAYS OPEN (and stays counted on `openStack`); `-->` exits BOTH\n * levels (double-escaped dash-dash on `>` goes straight to\n * SCRIPT_DATA — parse5 tokenizer, verified in source). The old\n * double-entry POISON is retired: the tangle sits identically in the\n * prefix of every future parse, so candidates may release once the\n * element truly closes — the splice side refuses these prefixes\n * separately (rawTextRegionCrossesOut), because the element CROSSES\n * micromark blocks and swallows their wrap separator. */\n | { kind: 'script'; escaped: boolean; double: boolean; openedInline: boolean }\n /** COMMENT state: `<!--` seen, closes at `-->` — or at `--!>`, which\n * micromark does NOT accept; that split is why this is a separate\n * field from `mdBlock` html{2} (P4b-completion, commit 1). Until the\n * divergence actually opens, the two agree everywhere; where it opens,\n * the relation poison has already fired. */\n | { kind: 'comment' }\n /** Bogus comment: eaten to the next `>`. */\n | { kind: 'bogus' };\n\n/** \"Comment content\" for the tag walk's markup decision — the union of the\n * two grammars' comment states, so bytes are skipped as comment interior\n * if EITHER grammar is still inside one (the divergence between them is\n * poisoned at the point it opens; neither field alone may release the\n * other's block). */\nconst commentEitherOpen = (md: MdBlock, p5: P5Tok): boolean => mdHtml(md, 2) || p5.kind === 'comment';\n\n/** The raw-text MASK predicate: while it holds, `applyTag` admits only the\n * element's own end tag, so nothing reaches the balance — a raw-text state\n * the model believes in but parse5 is not in makes candidates MORE likely\n * to survive (the unsafe direction). BOTH kinds mask; every read site goes\n * through this one predicate so no rewrite can drop the script kind. */\nconst inRawTextTok = (t: P5Tok): t is Extract<P5Tok, { kind: 'rawText' | 'script' }> =>\n t.kind === 'rawText' || t.kind === 'script';\n/** The open raw-text element's name, or null when none is open. */\nconst rawTextElement = (t: P5Tok): string | null =>\n t.kind === 'rawText' ? t.element : t.kind === 'script' ? 'script' : null;\n\n/** Opaque resume token. Produced by one `computeFreezeBoundary` call and\n * passed back on the next APPEND-ONLY call; the only supported operations\n * are storing it and passing it back. The field set is an implementation\n * detail of the scanner and changes between minor versions — the brand key\n * (a structural string literal, safe across dual d.ts entries) is all that\n * ships in the public type. */\nexport interface FreezeScanCheckpoint {\n readonly '~freezeScanCheckpoint'?: never;\n}\n\n/** Mutable resume state — the real shape behind `FreezeScanCheckpoint`.\n * Intra-package only (the scanner and its tests); not reachable from the\n * public entry, so the shape stays out of `dist/index.d.ts`. All fields\n * describe the scan strictly BEFORE the first unconfirmed character\n * (`confirmedOffset`). */\nexport interface FreezeScanCheckpointInternal extends FreezeScanCheckpoint {\n defListEnabled: boolean;\n /** Grammar-profile switches baked at creation — a checkpoint is only\n * resumable under the exact profile that built it. */\n mathFlow: boolean;\n referenceTaint: boolean;\n /** Start offset of the first line NOT yet baked into this checkpoint. */\n confirmedOffset: number;\n candidates: Candidate[];\n defs: Map<string, number>; // normalized label → def line end offset\n footnoteDefs: Map<string, number>;\n unresolvedRefs: UnresolvedRef[];\n tagBalance: Map<string, number>;\n openTotal: number;\n /** parse5's tokenizer macro-state (see `P5Tok`). Bogus comment (`<!` not\n * followed by `--` / letter / `[CDATA[`, or `</` not followed by a\n * letter — eaten up to the next `>`; micromark has no such construct),\n * raw-text content, script data with its escape flag. */\n p5Tok: P5Tok;\n /** micromark's open verbatim flow construct (see `MdBlock`). */\n mdBlock: MdBlock;\n blankRun: number;\n lastBlankStart: number;\n /** Rolling blocker-3 verdict (\"nearest decisive block start so far\"). */\n hazardVerdict: boolean;\n /** Previous confirmed line was blank (block-start detection). */\n prevLineBlank: boolean;\n /** Previous confirmed line was a plain text line (def-chain detection). */\n prevLineWasText: boolean;\n /** Previous confirmed line registered a VALID definition (def chains). */\n prevLineWasValidDef: boolean;\n /** micromark's \"content construct open\" after the previous confirmed\n * line — the EXACT interrupt input for §4.6 condition 7. micromark\n * refuses type 7 while its CONTENT construct (paragraph or definition\n * chain, including container-held paragraphs) is open; `prevLineWasText`\n * (\"any non-blank line\") over-claims that, refusing after headings,\n * thematic breaks, raw-construct terminator lines and fence closes —\n * all measured as type-7-OPENING to micromark. The decision table at\n * the end of the plain path derives this per line class; the one class\n * a line model cannot settle (a pipe line: GFM table row, after which\n * type 7 OPENS, vs pipe-bearing paragraph, after which it cannot) is\n * poisoned at the refused tag line instead — see `tableMaybeOpen`. */\n prevLineOpenContent: boolean;\n /** A GFM table MAY be open: a pipe line was seen and every line since\n * has been table-continuable. A table, once its header/delimiter pair\n * formed, is continued by ANY non-blank line that is not another\n * block-level structure — `| 1 | 2 |` then `see [a] prose` is TWO\n * table rows to micromark, not a table and a paragraph (soak seed\n * 20283008: a tag line after such a pipe-less continuation row was\n * refused as \"after content\" while micromark, whose table had just\n * been broken by the html block, OPENED type 7 — the phantom closer\n * then chased a math block that never existed). Sticky across\n * content-class lines, cleared by every openContent=false class and\n * at the usual reset points. Consumed only by the type-7 residual\n * poison — over-claiming it only widens the poison (safe). */\n tableMaybeOpen: boolean;\n /** A CONTAINER may be open: a blockquote / list-item / footnote-def\n * marker line was seen and every line since has been container-\n * continuable. micromark's `tagName` carries a `!self.parser.lazy`\n * exception the content model has no input for — a type-7-shaped line\n * that LAZILY continues an open container opens a container-held html\n * block (`> quoted` then `<x-y/>`), and a container whose last line was\n * not a paragraph CLOSES instead, leaving the same line to open a\n * top-level multi-line block (`> # h` then `<x-y/>`). Both readings say\n * \"opens\" where `prevLineOpenContent` says \"refused\", and which one\n * holds depends on container state a line model does not track (16 of\n * 21 container prefixes diverged, none poisoned — 2026-08-26 review).\n * Sticky and reset exactly like `tableMaybeOpen`, and consumed by the\n * same residual poison: over-claiming it only widens the poison. */\n containerMaybeOpen: boolean;\n /** An earlier line of the current paragraph left an unpaired backtick\n * run — masking is disabled until the paragraph ends (safety gate). */\n /** A `[` left unclosed at the end of a paragraph line (code spans\n * masked). micromark lets a reference label span soft line breaks, so\n * the label may close on a LATER line where the per-line REF_RE never\n * sees a `[…]` pair (v2.4.1 review P1: `see [foo\\nbar] end` + a late\n * `[foo bar]: /u` retargeted frozen output). Cleared wherever the\n * paragraph ends. */\n openBracket: { offset: number; text: string } | null;\n paragraphHasUnpairedRun: boolean;\n /** Blocker-6 pending flag: a confirmed html-flow line left balanced\n * floating raw remnant, and no later content line has pinned the seam\n * yet. Persists across blank lines (every candidate emitted while set\n * has the remnant as its last frozen child); cleared by the next\n * non-blank line that starts OUTSIDE an html-flow run. */\n /* ^ P-seal, explicitly (two-model T3.2): of the four (P) conditions this\n * is the genuinely retroactive one — the last root-level node the\n * frozen prefix contributed can still be EXTENDED by later bytes\n * (parse5's insertText appends to an existing trailing text node). */\n p5SealPending: boolean;\n /** A definition may still be OPEN: a def-shaped line was seen and no\n * blank has ended it yet. A definition spans up to three lines (label,\n * destination, title) and its title may wrap inside its quotes, and\n * every line after the first emits NO hast node — so none of them can\n * pin the blocker-6 seam, exactly like the def line itself. The seal\n * release tested the line's own SHAPE, which caught only the first\n * (soak 20289117, seed shard 17: `[b]: /b \"t` + `w\"` released the seam\n * and the frozen remnant node went position-less to positioned under a\n * `-->` future). Cleared at the blank, where a definition provably\n * ends; read only by the seal release, where holding it over-blocks. */\n defBlockMaybeOpen: boolean;\n /** A FOOTNOTE definition may still be RESUMABLE: `[^…]:` was seen and no\n * line since has definitively interrupted the block. Unlike a link\n * definition (whose `defBlockMaybeOpen` a blank provably ends), a\n * footnote body CONTINUES ACROSS blank lines via ≥4-indent lines — the\n * list-item continuation rule — and those lines emit no top-level hast\n * node (the body renders in the footer section), so none of them may\n * release the blocker-6 seam. The seal release's old view classified a\n * post-blank indented line as indented CODE (node-emitting) and released\n * a live seam (release-gate finding A, seed 20293003 — F16, the\n * cross-blank sibling of F15). Armed by a footnote-def line; kept across\n * blanks and indented lines; cleared by a confirmed non-blank\n * BLOCK-START line at indent ≤ 3, which no footnote body can resume\n * past. Read only by the seal release, where holding it over-blocks. */\n fnDefResumable: boolean;\n /** Offset of the first fence/math OPEN suppressed inside an html-flow\n * run — the member gate since Migration B row 6 (Infinity = none). Whether the run really swallowed that line depends\n * on container context the line scan cannot see (`<embed` inside a list\n * item is a lazy paragraph line, and the glued `$$` a REAL math open —\n * seed-20260757 under-block: the tracker's fence phase INVERTS from that\n * line on, every later close reads as an open, and the corruption never\n * resyncs). Candidates past this offset are rejected outright — sticky,\n * pure over-block; candidates before it are untouched (the ambiguous\n * region then re-parses inside the tail). This field is the sticky\n * phase-corruption backstop (the old rolling hazard poison for\n * \"ambiguous tag names\" retired with exact type 7). */\n phasePoisonedAt: number;\n /** Tag names of line-truncated opens (`<div` at EOL) counted into\n * tagBalance but not yet confirmed by a later `>` — reverted at the next\n * blank line (a tag cannot span one). See TRUNCATED_TAG_RE. */\n pendingTruncatedTags: string[];\n /** Line-truncated CLOSING tags (`</div` + EOL, no `>`) inside an html-flow\n * run, waiting for a `>` on a later line of the same run. Unlike opens\n * they are NOT counted up front: a close tag cannot carry attributes, so\n * `para </style` (prose to micromark, still-open element to parse5 —\n * RAWTEXT waits for the `>`) must not zero the balance (2026-08-19\n * review P1 — the boundary crossed an open `<style>`). Confirmed and\n * applied only when a later line of the run brings the `>` (parse5\n * completes the end tag; micromark's block ends at the blank anyway);\n * dropped unapplied at the blank (element stays counted — over-block).\n * Paragraph-context truncated closes are never pended: a `>` at block\n * indent on the next line is a blockquote to micromark, and the one\n * shape that would complete the inline close (`</b\\n >`, a 4+-space\n * lazy continuation) is not modelled — the element stays counted,\n * over-block. */\n pendingTruncatedCloses: string[];\n /** An html-flow line ended inside a tag (`<div`, `</div`, `<br` — open,\n * close or void, with or without attributes): parse5's tokenizer is\n * still in that tag, so on the following lines everything up to the\n * FIRST `>` is attribute garbage — `</div>` there does NOT close\n * anything (oracle review of 2.4.4: `<div>\\n<div>\\n</div\\n</div>` froze\n * past the still-open outer div; pre-existing, 1-char slices). While\n * set: a line without `>` gets no tag scan at all; the line with the\n * `>` completes the pending close (if any), then only its text after\n * that `>` is scanned. Cleared there and at the blank line. */\n pendingTag: {\n /** parse5's position inside the tag's attribute area at the end of the\n * last scanned line (see TagAttrState). A quoted value left open\n * swallows `>` and line endings; a `>` while `outside` ends the tag. */\n attr: TagAttrState;\n /** Indent of the line that entered the tag. A following line that\n * DE-INDENTS below it may have left the container (a list item's html\n * block ends there; hast-util-raw resets the tokenizer at the li/ul\n * boundary, so a `<div>` on that line is a real start tag, not\n * garbage) — or may still be the same html block (root-level\n * ` </div\\n</div>`, still garbage). Unknowable here → poison. */\n indent: number;\n } | null;\n /** The open-element stack, in order. `tagBalance` and `openTotal` are\n * derived views kept in step with it, but the STACK is the truth: an end\n * tag's effect depends on what sits BETWEEN it and its match, which a\n * name→count bag cannot represent (see SCOPE_BARRIER_NAMES). */\n openStack: string[];\n}\n\nconst VOID_TAGS = new Set([\n 'area',\n 'base',\n 'br',\n 'col',\n 'embed',\n 'hr',\n 'img',\n 'input',\n 'link',\n 'meta',\n 'param',\n 'source',\n 'track',\n 'wbr',\n]);\n\n/** CommonMark list markers at block indent (bullet or ordered), incl. bare `-`. */\nconst LIST_MARKER_RE = /^ {0,3}(?:[-*+]|\\d{1,9}[.)])(?:[ \\t]|$)/;\n/** A line that OPENS a container holding content: a blockquote marker (a\n * bare `>` counts — the quote is open either way) or a list marker WITH\n * content on the same line. A BARE marker is excluded on purpose: an\n * empty item holds no paragraph, so the next line at block indent is\n * neither its content nor a lazy continuation, and the interrupt answer\n * there is decided (the battery measures it as OPENING). Footnote\n * definitions and def-list descriptions arm through their own regexes at\n * the call site. Arms `containerMaybeOpen`. */\nconst CONTAINER_MARKER_RE = /^ {0,3}(?:>|(?:[-*+]|\\d{1,9}[.)])[ \\t]+\\S)/;\n/** Line classes for the content-tracking decision table (the type-7\n * interrupt input). All run on the TRIMMED line (indent ≤ 3 — the ≥ 4\n * case is decided before them). Measured against micromark 2026-08-25:\n * type 7 OPENS after each class below, and after html-block lines and\n * fence/math lines; it stays REFUSED after paragraph, definition,\n * footnote-definition, list-item-with-content and blockquote lines. */\nconst ATX_HEADING_RE = /^#{1,6}(?:[ \\t]|$)/;\nconst THEMATIC_BREAK_RE = /^(?:(?:-[ \\t]*){3,}|(?:\\*[ \\t]*){3,}|(?:_[ \\t]*){3,})$/;\n/** A BARE list marker (`-` / `*` / `+` / `1.` alone): opens an EMPTY item\n * and closes any content — micromark opens type 7 on the next line. */\nconst BARE_MARKER_RE = /^(?:[-*+]|\\d{1,9}[.)])[ \\t]*$/;\n/** Setext-underline shapes not already claimed above: `=+`, and `--`\n * (a lone `-` is BARE_MARKER, three+ are THEMATIC — same false answer).\n * These CONSUME an open paragraph into a heading (content closes); with\n * no paragraph open they ARE a paragraph (content opens). */\nconst SETEXT_LEFTOVER_RE = /^(?:=+|--)[ \\t]*$/;\n/** Definition-list description marker (micromark-extension-definition-list). */\nconst DEF_LIST_DD_RE = /^ {0,3}:[ \\t]/;\n/** A whole line that is one closing tag and nothing else (`</div>`,\n * `</x-y>`, `</br>`). Such a line emits NO node through rehype-raw's\n * fragment context, so it cannot pin the blocker-6 seam. */\nconst CLOSE_TAG_ONLY_RE = /^[ \\t]*<\\/[A-Za-z][A-Za-z0-9-]*[ \\t]*>[ \\t\\r]*$/;\nconst FENCE_RE = /^ {0,3}(`{3,}|~{3,})/;\n/** Leading dollar RUN at block indent — math flow fences carry a LENGTH\n * like code fences (`$$$$` opens a fence only ≥4 dollars can close;\n * K=4 census counterexample), and the meta after the run may not contain\n * `$` (a rest with any `$` is inline math / literal text, NOT a flow\n * open). */\nconst MATH_RUN_RE = /^ {0,3}(\\$\\$+)/;\n/** Opening/closing tags (name must be followed by attr/close syntax, which\n * excludes autolinks like `<https://…>`), plus comment delimiters. */\nconst TAG_OR_COMMENT_RE = /<(\\/?)([A-Za-z][A-Za-z0-9-]*)(?=[\\s/>])([^>]*)>|<!--|-->|--!>/g;\n// Empty comments whose closer OVERLAPS the opener (`<!-->`, `<!--->`):\n// CommonMark 0.31 (html flow AND text) and parse5 all close them on the\n// spot. A `<!--` match followed by `>`/`->` must not open a comment — the\n// scan would then skip REAL markup up to the next stray `-->` (2026-08\n// project-review P1: `<!-->\\n<details>\\n-->` froze past a parse5-open\n// `<details>`, the v1.5.1 swallow class). Handled inline in the token\n// scan and in `floatingResidue`, which share the state machine.\n/** A tag START whose `>` has not arrived on this line — `<div` at EOL, or\n * `<div class=\"a\"` with attributes continuing on the next line. Counted as\n * an open (probe-confirmed hazard) and remembered as PENDING: a tag can\n * carry attributes across line endings but never across a blank line, so\n * a pending open that reaches the paragraph's blank line without a `>`\n * was prose (`if x<y then`) and its phantom open is reverted there. Any\n * later `>` before that confirms it (kept open — over-block at worst).\n * Without the revert the phantom open lived forever and the whole rest of\n * the stream lost the splice, not just that paragraph (2026-08 project\n * review, eng-parse-06). */\nconst TRUNCATED_TAG_RE = /<(\\/?)([A-Za-z][A-Za-z0-9-]*)([^>]*)$/;\n/** Anchor for the truncated-tag check: the LAST `<` that starts a tag name\n * (`<x` / `</x`). Anchoring on the last `<` of any kind missed `<div a=<`\n * (attribute bytes may hold `<`; parse5 keeps the div open) — oracle\n * re-check of r2, pre-existing. */\nconst TAG_START_LT_RE = /<\\/?[A-Za-z]/g;\n/** parse5 tokenizer position inside a tag's attribute area, tracked across\n * line endings for `pendingTag` (2026-08-19 review r2 P1-2 / P2-3):\n * `outside` = before/in an attribute name (a `\"` here starts a NAME, not a\n * value); `afterEq` = just past `=`; `unquoted` = in an unquoted value\n * (whitespace ends it); `\"` / `'` = inside a quoted value — `>` and line\n * endings are value bytes there, only the matching quote leaves it. */\ntype TagAttrState = 'outside' | 'afterEq' | 'unquoted' | '\"' | \"'\";\n/** Advance the attribute-area state over `text[from, to)`; returns the\n * index of the `>` that ENDS the tag, or -1 with the state carried in\n * `out.state`. */\nfunction scanTagAttrs(text: string, from: number, to: number, out: { state: TagAttrState }): number {\n let st = out.state;\n for (let i = from; i < to; i++) {\n const c = text[i];\n if (st === '\"' || st === \"'\") {\n if (c === st) st = 'outside';\n continue;\n }\n const ws = c === ' ' || c === '\\t' || c === '\\n' || c === '\\r' || c === '\\f';\n if (st === 'afterEq') {\n if (ws) continue;\n if (c === '\"' || c === \"'\") st = c;\n else if (c === '>') return i;\n else st = 'unquoted';\n continue;\n }\n if (st === 'unquoted') {\n if (ws) st = 'outside';\n else if (c === '>') return i;\n continue;\n }\n // outside\n if (c === '=') st = 'afterEq';\n else if (c === '>') return i;\n }\n out.state = st;\n return -1;\n}\nconst BACKTICK_RUN_RE = /`+/g;\n\nfunction computeIndent(text: string): number {\n let indent = 0;\n for (const ch of text) {\n if (ch === ' ') indent += 1;\n else if (ch === '\\t') indent += 4 - (indent % 4);\n else break;\n }\n return indent;\n}\n\n/**\n * Blocker 4: can the (possibly partial) line ever match `^ {0,3}:[ \\t]`\n * after future appends? Appends only extend the line rightward, so a line\n * is settled once its existing characters already contradict the pattern.\n */\nfunction canBecomeDdLine(text: string, confirmed: boolean): boolean {\n let i = 0;\n while (i < text.length && text[i] === ' ') i += 1;\n if (i > 3) return false; // indent too deep, regardless of future appends\n if (i === text.length) return !confirmed; // only spaces so far — a partial line may still grow a `:`\n if (text[i] !== ':') return false;\n if (i + 1 === text.length) return !confirmed; // trailing `:` — a partial line may still grow the space\n return text[i + 1] === ' ' || text[i + 1] === '\\t';\n}\n\n/**\n * Same-line code-span masking (module docs). Returns the masked text, or\n * null when masking is unsafe for this line (an unpaired run here or\n * earlier in the paragraph). Masked spans are replaced by spaces of equal\n * length so every offset stays valid.\n */\nfunction maskIntraLineCodeSpans(text: string, carryOpen: boolean): { masked: string | null; unpaired: boolean } {\n BACKTICK_RUN_RE.lastIndex = 0;\n const runs: Array<{ index: number; length: number }> = [];\n let m: RegExpExecArray | null;\n while ((m = BACKTICK_RUN_RE.exec(text)) !== null) runs.push({ index: m.index, length: m[0].length });\n if (runs.length === 0) return { masked: carryOpen ? null : text, unpaired: false };\n // Pair equal-length runs leftmost-first (micromark's rule, same line).\n const spans: Array<[number, number]> = [];\n let unpaired = false;\n for (let i = 0; i < runs.length; i++) {\n const opener = runs[i];\n let matched = -1;\n for (let j = i + 1; j < runs.length; j++) {\n if (runs[j].length === opener.length) {\n matched = j;\n break;\n }\n }\n if (matched === -1) {\n unpaired = true;\n continue;\n }\n spans.push([opener.index, runs[matched].index + runs[matched].length]);\n i = matched; // consume through the closer\n }\n if (carryOpen || unpaired) return { masked: null, unpaired };\n if (spans.length === 0) return { masked: text, unpaired: false };\n let out = '';\n let cursor = 0;\n for (const [from, to] of spans) {\n out += text.slice(cursor, from) + ' '.repeat(to - from);\n cursor = to;\n }\n out += text.slice(cursor);\n return { masked: out, unpaired: false };\n}\n\nfunction freshCheckpoint(\n defListEnabled: boolean,\n mathFlow: boolean,\n referenceTaint: boolean\n): FreezeScanCheckpointInternal {\n return {\n defListEnabled,\n mathFlow,\n referenceTaint,\n confirmedOffset: 0,\n candidates: [],\n defs: new Map(),\n footnoteDefs: new Map(),\n unresolvedRefs: [],\n tagBalance: new Map(),\n openTotal: 0,\n p5Tok: { kind: 'data' },\n openStack: [],\n mdBlock: { kind: 'none' },\n blankRun: 0,\n lastBlankStart: -1,\n hazardVerdict: false,\n prevLineBlank: true, // doc start counts as a block start\n prevLineWasText: false,\n prevLineWasValidDef: false,\n prevLineOpenContent: false,\n tableMaybeOpen: false,\n containerMaybeOpen: false,\n paragraphHasUnpairedRun: false,\n openBracket: null,\n p5SealPending: false,\n defBlockMaybeOpen: false,\n fnDefResumable: false,\n phasePoisonedAt: Infinity,\n pendingTruncatedTags: [],\n pendingTruncatedCloses: [],\n pendingTag: null,\n };\n}\n\n/** Blocker-3 classification of a block-START line (raw text; markers are\n * never inside code spans at block indent). Returns the new rolling\n * verdict, or null when the line is ambiguous (verdict unchanged). */\nfunction classifyBlockStart(text: string, indent: number, defListEnabled: boolean): boolean | null {\n if (indent >= 4) return true; // indented code / item continuation merges across blanks (A1)\n if (LIST_MARKER_RE.test(text) || FOOTNOTE_DEF_RE.test(text)) return true;\n if (defListEnabled && DEF_LIST_DD_RE.test(text)) return true;\n if (indent === 0) return false; // column-0 non-marker block terminates any list context\n return null; // indent 1–3 non-marker: ambiguous\n}\n\nexport function computeFreezeBoundary(\n text: string,\n options: FreezeBoundaryOptions,\n resume?: FreezeScanCheckpoint | null\n): FreezeScanResult {\n const mathFlow = options.mathFlow ?? true;\n const referenceTaint = options.referenceTaint ?? true;\n const prev = resume as FreezeScanCheckpointInternal | null | undefined;\n // A checkpoint encodes profile-dependent state (math phase, ref taint\n // tables) — resuming under a DIFFERENT profile would mix grammars, so\n // every switch participates in the invalidation check.\n const cp =\n prev &&\n prev.defListEnabled === options.defListEnabled &&\n prev.mathFlow === mathFlow &&\n prev.referenceTaint === referenceTaint &&\n prev.confirmedOffset <= text.length\n ? prev\n : freshCheckpoint(options.defListEnabled, mathFlow, referenceTaint);\n\n // ── advance the checkpoint over newly-CONFIRMED lines ──\n let start = cp.confirmedOffset;\n let tailLine: LineRec | null = null;\n while (start < text.length) {\n // Line endings are what micromark counts: `\\n`, `\\r\\n` and a LONE `\\r`\n // (2026-08-19 review r2 P1-5: splitting on `\\n` only hid the fence /\n // math OPENER after `a\\r` inside one scanner line, and a candidate\n // landed inside the open block). `end` is the LAST byte of the ending\n // (the `\\n` of a CRLF), so `end + 1` is the next line start as before;\n // `lineText` excludes the ending. A lone `\\r` as the very last byte is\n // NOT confirmed: the `\\n` that may follow belongs to the same ending.\n let end = text.length;\n let textEnd = text.length;\n {\n const nl = text.indexOf('\\n', start);\n const cr = text.indexOf('\\r', start);\n if (cr !== -1 && (nl === -1 || cr < nl)) {\n textEnd = cr;\n end = text.charCodeAt(cr + 1) === 10 ? cr + 1 : cr;\n } else if (nl !== -1) {\n textEnd = nl;\n end = nl;\n }\n }\n const confirmed = end < text.length && !(end === text.length - 1 && text.charCodeAt(end) === 13);\n const lineText = text.slice(start, textEnd);\n const ln: LineRec = {\n start,\n end,\n text: lineText,\n blank: confirmed && isMdBlank(lineText),\n indent: computeIndent(lineText),\n };\n if (!confirmed) {\n // The partial line is never baked into the checkpoint: it emits no\n // candidates, and its tag/ref effects cannot reach candidates that\n // all precede it.\n tailLine = ln;\n break;\n }\n\n processConfirmedLine(cp, ln, text);\n cp.confirmedOffset = end + 1;\n start = end + 1;\n }\n\n // ── settle references (blocker 5 — referenceTaint.ts) ──\n const earliestUnresolved = settleRefsAndEarliestUnresolved(cp);\n\n // ── blocker 4: defList settled check (decided by the NEXT line) ──\n const defListSettled = (c: Candidate): boolean => {\n if (!options.defListEnabled || c.blankRun >= 2) return true;\n // Confirmed next lines settle candidates eagerly in processConfirmedLine;\n // only the newest candidate can still be pending here.\n if (c.defListSettled !== null) return c.defListSettled;\n if (tailLine) return !canBecomeDdLine(tailLine.text, false);\n return false; // no next line yet — a future `: desc` could still claim the block above\n };\n\n // ── pick the last surviving candidate ──\n // A retroactive construct on the UNCONFIRMED tail line suppresses every\n // candidate for this frame (see tailCarriesRetroactive). Checked here and\n // not in the scan so nothing about the partial line is ever baked in.\n const tailRetroactive = tailLine !== null && tailCarriesRetroactive(tailLine.text);\n let boundary = 0;\n for (let i = cp.candidates.length - 1; i >= 0 && !tailRetroactive; i--) {\n const c = cp.candidates[i];\n if (!c.htmlBalanced || c.hazard || c.seamRisk) continue;\n // Fence/math phase untrusted past a suppressed open (phasePoisonedAt\n // docs) — a boundary AT the poisoned line start is still safe: the\n // whole ambiguous region lands in the tail re-parse.\n if (c.offset > cp.phasePoisonedAt) continue;\n if (c.offset > earliestUnresolved) continue;\n if (!defListSettled(c)) continue;\n boundary = c.offset;\n break;\n }\n\n return { boundary, checkpoint: cp };\n}\n\n/**\n * The closing line that would end the fence / flow-math block still open at\n * the checkpoint, or `''` when nothing provably closable is open. The whole\n * decision is scanner-domain, so it lives here rather than in the consumer:\n * a poisoned fence/math phase (blocker 7) means the \"open\" flags cannot be\n * trusted and a wrong closer would OPEN a block, and only a column-0 opener\n * is provably top-level (`openIndent` docs). `phantomSuffixCloser` prepends\n * its own newline handling; the returned text is the bare closer run.\n */\nexport function pendingFenceCloser(checkpoint: FreezeScanCheckpoint): string {\n const cp = checkpoint as FreezeScanCheckpointInternal;\n if (cp.phasePoisonedAt !== Infinity) return '';\n if (cp.mdBlock.kind === 'fence' && cp.mdBlock.indent === 0) return cp.mdBlock.char.repeat(cp.mdBlock.len);\n if (cp.mdBlock.kind === 'math' && cp.mdBlock.indent === 0) return '$'.repeat(cp.mdBlock.len);\n return '';\n}\n\n/**\n * Blocker-6 residue: the bytes of a line that are neither tags nor comment\n * tokens/content — floating raw text — computed with the SAME comment state\n * machine as the balance scan (`commentOpenAtStart` carried in from the\n * previous line; `<!-->`/`<!--->` close on the spot whether or not a comment\n * is open; `--!>` never closes for CommonMark; a stray `-->` outside a\n * comment is text). Raw-construct bytes must already be masked by the caller.\n */\nfunction floatingResidue(text: string, commentOpenAtStart: boolean): string {\n let out = '';\n let open = commentOpenAtStart;\n let last = 0; // start of the not-yet-emitted text run\n TAG_OR_COMMENT_RE.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = TAG_OR_COMMENT_RE.exec(text)) !== null) {\n if (m[0] === '<!--') {\n const next = text.slice(m.index + 4, m.index + 6);\n const overlapLen = next.startsWith('>') ? 5 : next === '->' ? 6 : 0;\n if (open) {\n if (overlapLen) {\n open = false;\n last = m.index + overlapLen;\n TAG_OR_COMMENT_RE.lastIndex = last;\n }\n continue;\n }\n out += text.slice(last, m.index);\n if (overlapLen) {\n last = m.index + overlapLen;\n TAG_OR_COMMENT_RE.lastIndex = last;\n continue;\n }\n open = true; // content until `-->` is dropped\n continue;\n }\n if (m[0] === '-->') {\n if (open) {\n open = false;\n last = m.index + 3;\n }\n continue; // stray `-->` stays in the text run\n }\n if (m[0] === '--!>') continue; // content (open) or text (closed) either way\n if (open) continue;\n out += text.slice(last, m.index); // a tag: emit the text before it, drop the tag\n last = m.index + m[0].length;\n }\n if (!open) out += text.slice(last);\n return out;\n}\n\n/** Bake one confirmed line into the checkpoint. */\nfunction processConfirmedLine(cp: FreezeScanCheckpointInternal, ln: LineRec, text: string): void {\n // Blocker-4 eager settle: this line is the \"next confirmed line\" of the\n // newest candidate. The verdict uses the RAW line exactly like the old\n // lines-array lookback did (fence/math state deliberately not consulted).\n const newest = cp.candidates[cp.candidates.length - 1];\n if (newest && newest.defListSettled === null) {\n newest.defListSettled = ln.blank ? true : !canBecomeDdLine(ln.text, true);\n }\n const isBlockStart = cp.prevLineBlank;\n // Blocker-6 seam release: a confirmed non-blank line that starts OUTSIDE\n // any html-flow run AND emits a top-level hast node at its own position is\n // real content that will sit between the remnant and whatever streams in\n // later — the seam is pinned from the frozen side. Lines that emit NOTHING\n // there must NOT release: link/footnote definition lines produce no hast\n // node (def-SHAPED but invalid lines do emit a paragraph — not releasing\n // on them only over-blocks), and comment-only lines produce at most a\n // comment node whose seam-pinning power is unverified. (Lines INSIDE the\n // run keep the flag; the run's own blank keeps it so every candidate in\n // the trailing blank run stays rejected.)\n // Migration B row 7, the CLEAR half (exact type 7): \"starts OUTSIDE any\n // html-flow run\" is the MEMBER's answer at line start — the retired\n // proxy also held the seam through `<embed x`-style paragraph lines,\n // which emit their paragraph node and pin the seam like any other\n // content line.\n if (\n cp.p5SealPending &&\n !ln.blank &&\n cp.mdBlock.kind !== 'html' &&\n !(cp.p5Tok.kind === 'comment' || cp.p5Tok.kind === 'bogus')\n ) {\n // The def clause is the LINE's own shape plus the sticky block flags: a\n // definition's destination and title lines are def CONTINUATIONS that\n // emit no node either, and a shape test cannot see them (see\n // `defBlockMaybeOpen`); a ≥4-indent line while a FOOTNOTE definition is\n // still resumable is that footnote's BODY continuation — across blank\n // lines included — not indented code, and it emits no top-level node\n // either (see `fnDefResumable`; F16, finding A of the release gate).\n const defShapedLine =\n DEF_RE.test(ln.text) ||\n FOOTNOTE_DEF_RE.test(ln.text) ||\n cp.defBlockMaybeOpen ||\n (cp.fnDefResumable && ln.indent >= 4);\n const commentOnly =\n ln.text\n .replace(/<!--[\\s\\S]*?-->/g, ' ')\n .replace(/<!--[\\s\\S]*$/, ' ')\n .replace(/[ \\t\\r]/g, '') === '';\n // A line that is ONLY a closing tag emits no node either, and the\n // predicate's other three clauses are all true of it — so `</div>`\n // released a seam it does not pin (`<!-- c --> remnant\\n</div>` froze\n // 47 of 51 bytes; 2026-08-26 review M6). Through rehype-raw's fragment\n // context a stray closer produces nothing at the root, which is the\n // design's §2.1a RETRO measurement: the trailing root text node can\n // still grow. Whole-line only — `</div> trailing` leaves a text node\n // and pins the seam like any other content.\n const closeTagOnly = CLOSE_TAG_ONLY_RE.test(ln.text);\n if (!defShapedLine && !commentOnly && !closeTagOnly) {\n cp.p5SealPending = false;\n }\n }\n /** Post-collapse (T3.4) this deliberately OVER-claims: parse5 pops the\n * foreign root on a breakout tag, and no pop is modelled any more — the\n * bag says \"foreign\" until the root's own end tag. Both consumers point\n * the over-claim the safe way (self-closing tags stay counted; raw-text\n * switches poison). */\n // T3.3 direction contract: every `tagBalance` read goes through a wrapper\n // whose NAME carries the safe direction of doubt. This one may OVER-claim\n // (saying \"foreign\" when parse5 left it keeps self-closing tags counted —\n // over-blocking); the table one below must UNDER-claim.\n const possiblyInsideForeign = (): boolean => FOREIGN_ROOT_NAMES.some((name) => (cp.tagBalance.get(name) ?? 0) > 0);\n /** A self-closing tag parse5 really closes on the spot. Post-collapse\n * (two-model T3.4): ONLY the foreign roots themselves — foreign\n * elements honour the flag in any context. Every other self-closing\n * tag is counted OPEN: being exact needed the breakout and\n * integration-point enumerations whose mis-claims were the F1/F2/F5\n * family, and counting keeps `openTotal` at or above parse5's stack\n * depth — the over-blocking side. The measured cost is that well-formed\n * self-closed children (`<svg><circle/></svg>`) stay counted past the\n * `</svg>` (its scope walk removes only the svg), which blocks freezing\n * for the rest of the document — reported with the stage's diff. */\n const honoursSelfClosing = (tag: string): boolean => tag === 'svg' || tag === 'math';\n /** T3.3b, the third wrapper direction: whether the tokenizer SWITCHES\n * for a raw-text element start tag near foreign content is unknowable\n * to a name-count bag. OVER-claiming the switch opens the raw-text mask\n * parse5 is not in — the mask suppresses the tag scan, so candidates\n * get MORE likely to survive and the boundary RISES (measured:\n * `<svg><title><div></title></svg>` is safe today only because the\n * un-switched `<div>` sits on the open stack). UNDER-claiming keeps the\n * mask shut where parse5 opens it — F2, the shipped under-block.\n * Neither direction is safe, so the honest answer is a poison. */\n const foreignRawTextSwitchUnknowable = (): boolean => possiblyInsideForeign();\n const applyTag = (tag: string, closing: boolean): void => {\n // Inside a raw-text element only its own end tag is markup.\n if (inRawTextTok(cp.p5Tok)) {\n // \"Script data double escaped\" (F6, retired poison → exact ladder):\n // inside an escaped `<script>` a nested `<script` start tag makes\n // parse5 stop honouring `</script>` — the first one only steps back\n // to escaped, and the element runs on. CommonMark ends its type-1\n // block at the first literal closer line regardless, so the two\n // grammars diverge about which BYTES are raw for the length of the\n // window — during it the element stays counted (no release), and\n // the frozen-prefix consequences are the splice guard's job.\n if (cp.p5Tok.kind === 'script' && cp.p5Tok.escaped && !closing && tag === 'script') {\n cp.p5Tok = { ...cp.p5Tok, double: true };\n }\n if (!(closing && tag === rawTextElement(cp.p5Tok))) return;\n if (cp.p5Tok.kind === 'script' && cp.p5Tok.double) {\n // `</script>` while double-escaped: back to escaped, element open,\n // stack untouched — the early return skips the pop below.\n cp.p5Tok = { ...cp.p5Tok, double: false };\n return;\n }\n cp.p5Tok = { kind: 'data' };\n } else {\n if (!closing && RAW_TEXT_ELEMENTS.has(tag) && foreignRawTextSwitchUnknowable()) {\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n } else if (!closing && RAW_TEXT_ELEMENTS.has(tag)) {\n // Migration collision rule (P3a): entering raw text while another\n // non-data state is live would silently drop that state's blocking\n // effect — poison instead, which can only lower the boundary.\n if (cp.p5Tok.kind !== 'data') cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n // openedInline: paragraph context, i.e. micromark html-TEXT rather\n // than an html block — the regime where a lifted element rewrites\n // its paragraph. Captured HERE (latched: the run state is reset\n // before the blank-line poison that reads this). Migration A row\n // 1: the member answers \"block context\" — NARROWER than the old\n // flag by the in-comment promotion artifact, and inert there: a\n // paragraph-inline 3-5 opener poisons document-wide, and tags\n // inside a comment never reach applyTag at all.\n const openedInline = cp.mdBlock.kind !== 'html';\n cp.p5Tok =\n tag === 'script'\n ? { kind: 'script', escaped: false, double: false, openedInline }\n : { kind: 'rawText', element: tag, openedInline };\n // PLAINTEXT never ends (`</plaintext>` is text too): nothing after\n // it can be modelled — poison from here on.\n if (tag === 'plaintext') cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n }\n }\n // Retroactive construct (see DOCUMENT_STRUCTURE_NAMES): parse5 erases\n // the tag and merges the text around it, changing hast BEFORE this\n // point. Poison from offset 0 — nothing in the document is freeze-safe\n // once one of these is confirmed, and the poison is monotone so it\n // stays that way. Sits past the raw-text guard on purpose: a `<body>`\n // inside `<script>` is text to parse5 too, and must not poison.\n if (DOCUMENT_STRUCTURE_NAMES.has(tag)) cp.phasePoisonedAt = 0;\n // `<template>` is the second kind of erasure. Its children go into a\n // content FRAGMENT (`hast-util-from-parse5` hangs them off `.content`,\n // not `.children`), and the sanitize pass then drops the element — so a\n // template block vanishes whole, children and all, and the text around\n // it merges. Inside a container the damage is worse: the direction\n // battery measured a list item swallowing the rest of the document\n // (`- a\\n<template>\\n<div>x</div>\\n</template>` + blank + prose — the\n // later paragraphs land INSIDE the li, and a one-character append\n // rewrites the frozen region via lazy continuation; blockquote form\n // identical; 2026-08-24, scaled soak leg 2). The top-level form measured\n // stable, but \"measured harmless\" has been refuted three times this\n // week, and erasure merges reach backward (the F9 lesson) — so the\n // poison is document-wide, same as the names above. An earlier sweep\n // recorded template as \"swept clean\"; that sweep sampled shapes with\n // blank lines around the block, which is exactly the layout where the\n // merge stays invisible.\n if (tag === 'template' && !closing) cp.phasePoisonedAt = 0;\n if (closing) {\n // Walk down for the match, stopping at a scope barrier. No match in\n // scope means parse5 DISCARDS this end tag and the element stays open —\n // so the counts must not move either.\n let idx = -1;\n for (let i = cp.openStack.length - 1; i >= 0; i--) {\n if (cp.openStack[i] === tag) {\n idx = i;\n break;\n }\n if (SCOPE_BARRIER_NAMES.has(cp.openStack[i])) break;\n }\n if (idx === -1) return;\n // Remove ONLY the matched element. What parse5 does with the elements\n // above it depends on which end tag this is: a block name generates\n // implied end tags and pops through, while a formatting name runs the\n // adoption agency, which re-parents rather than popping. Modelling the\n // first would under-count the second — measured, it re-opened four\n // fixtures as fresh under-blocks. Leaving them counted over-blocks,\n // which is the side this scanner is allowed to be wrong on.\n //\n // LOAD-BEARING beyond the counts: the formElement latent divergence\n // (design §2.1 — parse5's form pointer survives an IMPLICIT close and\n // eats a later <form>) is guarded exactly by this rule keeping the\n // implicitly-closed form on `openStack`. Modelling implied end tags\n // here needs an explicit formElement guard shipped WITH it —\n // `formElementLatent.test.ts` is the tripwire.\n cp.openStack.splice(idx, 1);\n const count = cp.tagBalance.get(tag) ?? 0;\n if (count > 0) {\n cp.tagBalance.set(tag, count - 1);\n cp.openTotal -= 1;\n }\n } else {\n cp.openStack.push(tag);\n cp.tagBalance.set(tag, (cp.tagBalance.get(tag) ?? 0) + 1);\n cp.openTotal += 1;\n }\n };\n\n /** A table part only re-routes parse5 when it appears OUTSIDE a table —\n * which is what TABLE_PART_NAMES has always meant, and what the poison\n * never checked: a well-formed `<table><tr><td>a</td></tr></table>` killed\n * freezing for the whole rest of the document (measured: boundary 0 from\n * the table onwards, against 43 for the same prose without it).\n * `tagBalance` is the open-element model the straddle bail already trusts,\n * so this adds no new assumption — and it is read only to SUPPRESS a\n * poison, so a `<table>` the scanner failed to count leaves the old,\n * over-blocking behaviour in place (2026-08-20 B1). Every call site sits\n * BEFORE this tag's own `applyTag`, so a `<table><td>` on one line has\n * the table counted by the time the part is judged. */\n // UNDER-claiming by contract: this wrapper suppresses a poison, so doubt\n // must resolve to \"not inside a table\" (poison fires). The bag can only\n // over-count opens, and an over-counted `table` here would suppress a\n // poison wrongly — which is why the read is fenced into a named wrapper.\n //\n // PENDING TRUNCATED opens are subtracted for that reason, the same\n // phantom argument the seam check makes with `effectiveOpen`: a\n // paragraph-line `compare a<table b` is prose, parse5 discards the\n // incomplete tag, and nothing is inside a table when a later `<td>` is\n // judged — yet the bag counted it and suppressed the poison\n // (`compare a<table b\\n<td>x</td>\\n</table>` froze 59 of 63 bytes;\n // 2026-08-26 review M5, the one wrapper whose implementation contradicted\n // its name). The `>` that CONFIRMS the open clears the pending list, so a\n // real table recovers the suppression on the spot.\n const definitelyInsideTable = (): boolean =>\n (cp.tagBalance.get('table') ?? 0) > cp.pendingTruncatedTags.filter((t) => t === 'table').length;\n // P-tree, explicitly (two-model T3.2): a stray table part leaves parse5's\n // template insertion-mode stack at a table mode — a Parser field a fresh\n // parser does not share, permanently. The line model cannot watch that\n // stack, so the P-tree dimension is expressed as this poison rather than\n // as a checkpoint field: sticky, document-shaping, and cheap to test.\n const strayTablePart = (tag: string): boolean => TABLE_PART_NAMES.has(tag) && !definitelyInsideTable();\n\n // A type 2-5 raw construct (comment/PI/decl/CDATA) open at the START of\n // this line makes the whole line html-block content — the construct's\n // block ends WITH the line carrying its terminator, so even that line's\n // remainder is raw text. Gates fence/math opens, masking, and def\n // registration below, alongside the html-block member.\n const commentOpenAtLineStart = commentEitherOpen(cp.mdBlock, cp.p5Tok);\n // The two halves separately, for consumers that need the INTERSECTION\n // (floatingResidue) rather than the union — captured at line start like\n // the union itself.\n const bothCommentsOpenAtLineStart = mdHtml(cp.mdBlock, 2) && cp.p5Tok.kind === 'comment';\n // P3b batches 2/3, the divergence WINDOWS: micromark still inside its\n // comment (type 2) or PI/CDATA (type 3/5) block, parse5 already out\n // (`--!>` closed the comment; the construct's first `>` closed the\n // bogus comment). Window bytes are construct interior to one grammar\n // and live input to the other — safe exactly while parse5 reads them\n // as TEXT. The first line carrying a byte parse5 would act on poisons\n // the phase (sticky, over-block).\n const inDivergenceWindow =\n (mdHtml(cp.mdBlock, 2) && cp.p5Tok.kind !== 'comment') ||\n ((mdHtml(cp.mdBlock, 3) || mdHtml(cp.mdBlock, 5)) && cp.p5Tok.kind !== 'bogus');\n if (inDivergenceWindow && P5_MARKUP_RE.test(ln.text)) {\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n }\n const rawOpenAtLineStart = mdHtml25(cp.mdBlock) || cp.p5Tok.kind === 'comment' || cp.p5Tok.kind === 'bogus';\n\n // --- fence state (interiors are candidate-free; paragraph resets) ---\n if (cp.mdBlock.kind === 'fence') {\n const close = FENCE_RE.exec(ln.text);\n if (\n close &&\n close[1][0] === cp.mdBlock.char &&\n close[1].length >= cp.mdBlock.len &&\n isMdBlank(ln.text.slice(close[0].length))\n ) {\n cp.mdBlock = { kind: 'none' };\n }\n cp.blankRun = 0;\n cp.paragraphHasUnpairedRun = false;\n cp.openBracket = null;\n cp.prevLineBlank = false;\n cp.prevLineWasText = false;\n cp.prevLineWasValidDef = false;\n cp.prevLineOpenContent = false;\n cp.tableMaybeOpen = false;\n cp.containerMaybeOpen = false;\n return;\n }\n if (cp.mdBlock.kind !== 'math' && !rawOpenAtLineStart) {\n const open = FENCE_RE.exec(ln.text);\n // A backtick fence's info string may not contain a backtick —\n // ```a``` b is a PARAGRAPH with a code span, not a fence open (A5).\n const bogusInfo =\n open !== null && open[1][0] === '`' && ln.text.slice(ln.text.indexOf(open[1]) + open[1].length).includes('`');\n if (open && !bogusInfo && cp.mdBlock.kind === 'html') {\n // Suppressed open (Migration B row 6, exact type 7): the gate is the\n // MEMBER — an html block open from previous lines owns this ``` line\n // as raw text. The retired proxy also suppressed after `<embed x`\n // paragraph openers, where the fence is REAL (fence interrupts a\n // paragraph) and suppression was the seed-20260757 phase-corruption\n // shape. The phasePoisonedAt backstop STAYS: the member itself is\n // container-blind (a run inside a list item can end at a de-indent\n // this line model cannot see), so whether the run really swallows\n // this line is still container-dependent. Poison the phase and fall\n // through so the line stays tag-scanned as raw text.\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n } else if (open && !bogusInfo) {\n // The open line is a block start for blocker 3 (a column-0 fence\n // terminates a list context; an indented one is ambiguous/hazard).\n if (isBlockStart) {\n const verdict = classifyBlockStart(ln.text, ln.indent, cp.defListEnabled);\n if (verdict !== null) cp.hazardVerdict = verdict;\n }\n cp.mdBlock = { kind: 'fence', char: open[1][0], len: open[1].length, indent: ln.indent };\n cp.blankRun = 0;\n cp.paragraphHasUnpairedRun = false;\n cp.openBracket = null;\n cp.prevLineBlank = false;\n cp.prevLineWasText = false;\n cp.prevLineWasValidDef = false;\n cp.prevLineOpenContent = false;\n cp.tableMaybeOpen = false;\n cp.containerMaybeOpen = false;\n return;\n }\n }\n\n // --- $$ flow-math state (fence-like: no candidates, close at line start;\n // the closing run must be at least as long as the opening one, with\n // nothing but whitespace after) ---\n if (cp.mdBlock.kind === 'math') {\n const close = MATH_RUN_RE.exec(ln.text);\n if (close && close[1].length >= cp.mdBlock.len && isMdBlank(ln.text.slice(close[0].length))) {\n cp.mdBlock = { kind: 'none' };\n }\n cp.blankRun = 0;\n cp.paragraphHasUnpairedRun = false;\n cp.openBracket = null;\n cp.prevLineBlank = false;\n cp.prevLineWasText = false;\n cp.prevLineWasValidDef = false;\n cp.prevLineOpenContent = false;\n cp.tableMaybeOpen = false;\n cp.containerMaybeOpen = false;\n return;\n }\n // Fence/math OPENS are gated on the html-block MEMBER (matching the\n // fence branch above): inside an html flow run a ``` or $$ line is raw text —\n // entering fence state there would skip tag extraction on lines that\n // rehype-raw parses as REAL markup (fuzz counterexample: a fence glued\n // to `</details>` hiding a quoted `<div>`). Falling through to the\n // plain-text branch keeps those lines tag-scanned (over-block safe) —\n // but the suppression itself is only certainly right at top level, so it\n // ALSO poisons the phase (see phasePoisonedAt).\n // Under the scanner profile (mathFlow=false) `$$` is ordinary paragraph\n // text — no math state, no suppressed-open poison; the line falls through\n // to the plain-text path where its content stays comment/tag-scanned.\n const mathRun = cp.mathFlow && !rawOpenAtLineStart ? MATH_RUN_RE.exec(ln.text) : null;\n if (mathRun) {\n const rest = ln.text.slice(ln.text.indexOf(mathRun[1]) + mathRun[1].length);\n // A `$` anywhere in the rest disqualifies the flow open (meta may not\n // contain `$`): `$$x$$` is inline math, `$$x$` a plain paragraph —\n // both self-contained lines, no state either way.\n if (!rest.includes('$')) {\n if (cp.mdBlock.kind === 'html') {\n // Row 6, math half — same member gate, same kept backstop.\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n } else {\n if (isBlockStart) {\n const verdict = classifyBlockStart(ln.text, ln.indent, cp.defListEnabled);\n if (verdict !== null) cp.hazardVerdict = verdict;\n }\n cp.mdBlock = { kind: 'math', len: mathRun[1].length, indent: ln.indent };\n cp.blankRun = 0;\n cp.paragraphHasUnpairedRun = false;\n cp.openBracket = null;\n cp.prevLineBlank = false;\n cp.prevLineWasText = false;\n cp.prevLineWasValidDef = false;\n cp.prevLineOpenContent = false;\n cp.tableMaybeOpen = false;\n cp.containerMaybeOpen = false;\n return;\n }\n }\n }\n\n // --- blank line: candidate emission + paragraph reset ---\n if (ln.blank) {\n // Line-truncated tag opens that never got their `>` before this blank\n // were prose: revert their phantom opens BEFORE judging balance here.\n if (cp.pendingTruncatedTags.length > 0) {\n for (const tag of cp.pendingTruncatedTags) applyTag(tag, true);\n cp.pendingTruncatedTags = [];\n }\n // Truncated closes that never got their `>` stay UNAPPLIED (see the\n // field doc): the element remains counted — over-block, never under.\n cp.pendingTruncatedCloses = [];\n // Still inside a QUOTED attribute value at the blank: micromark ends the\n // html block here, but parse5's tokenizer stays in the value — the\n // paragraph text after the blank goes in as characters (not tokenized)\n // and the NEXT raw node's bytes are eaten up to the closing quote. Which\n // grammar wins where is not modelled: poison (over-block). `outside` /\n // unquoted at the blank keep the classic behaviour (the pending close is\n // dropped, the element stays counted).\n if (cp.pendingTag !== null && (cp.pendingTag.attr === '\"' || cp.pendingTag.attr === \"'\")) {\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n }\n cp.pendingTag = null;\n // Same for a bogus comment left open WITHOUT its md construct: the\n // block ended, the tokenizer has not — poison and reset. When an md\n // type 2-5 block is still open the two grammars CROSS the blank\n // together (`<?a\\n\\n?>` is one block and one bogus comment — batch 3\n // pairs the states, so the aligned crossing must not poison).\n if (cp.p5Tok.kind === 'bogus') {\n if (mdHtml25(cp.mdBlock)) {\n // aligned — both grammars still inside; state survives the blank.\n } else {\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n cp.p5Tok = { kind: 'data' };\n }\n }\n // Types 6/7 end AT this blank — the member clears before the candidate\n // is judged, exactly when the block ends. (Type 1 survives the blank;\n // 2-5 run to their terminators.)\n if (cp.mdBlock.kind === 'html' && cp.mdBlock.type >= 6) cp.mdBlock = { kind: 'none' };\n cp.blankRun += 1;\n cp.lastBlankStart = ln.start;\n cp.candidates.push({\n offset: Math.min(ln.end + 1, text.length),\n blankRun: cp.blankRun,\n // The html member covers types 1-5 in one check: an unterminated\n // type-1 block swallows this blank and everything after it as RAW\n // content (its tags are invisible to the balance scan — the raw-text\n // mask suppresses them — which is exactly why `openTotal` reads 0\n // and the candidate looked safe), and the 2-5 interiors are the\n // same construct to both grammars.\n htmlBalanced: cp.openTotal === 0 && cp.mdBlock.kind !== 'html' && (cp.p5Tok.kind as P5Tok['kind']) !== 'bogus',\n hazard: cp.hazardVerdict,\n seamRisk: cp.p5SealPending,\n defListSettled: null,\n });\n cp.paragraphHasUnpairedRun = false;\n cp.openBracket = null;\n // A type-1 block is the one html block a BLANK LINE does not end — its\n // only end condition is the literal closer, or end of document. While\n // one is open the run must survive the blank, or the scanner reads the\n // block's raw content as markup: `<script></script >` never closes\n // (CommonMark wants the literal `</script>`; the space makes it text),\n // so the ``` lines after the blank are raw text to micromark and a real\n // FENCE to the scanner — a candidate landed inside the html block\n // (2026-08-20 soak leg 2, third shape).\n if (!mdHtml(cp.mdBlock, 1)) {\n // A RAWTEXT/RCDATA element still open ACROSS this blank has just had\n // its micromark block end under it: a type-6 run ends at the blank,\n // while parse5's raw-text state runs on to the literal end tag. From\n // here every line lives in both grammars at once — micromark opens\n // fresh blocks whose ELEMENT nodes hast-util-raw pushes straight into\n // the tree, while the same bytes are raw TEXT to parse5, so their end\n // tags never close anything. `<iframe>` + blank + `*b*\\n<div>…</div>\n // \\n</iframe>` left the div OPEN swallowing the rest of the document\n // while the scanner, suppressing every tag under the raw-text mask, called\n // it balanced (63-byte live under-block, direction battery,\n // 2026-08-24). Document-wide poison, not from-here-on: the element is\n // sanitize-stripped and its lifted children merge with neighbouring\n // text — the fuzz4 lesson, same day. Type-1 blocks are exempt because\n // a blank does NOT end them: there the two grammars agree the content\n // is raw, which is the case the guard above already keeps alive.\n // (inline-opened spans have their own poison at the opening line.)\n if (inRawTextTok(cp.p5Tok) && !cp.p5Tok.openedInline) {\n cp.phasePoisonedAt = 0;\n }\n }\n cp.prevLineBlank = true;\n cp.prevLineWasText = false;\n cp.prevLineWasValidDef = false;\n // A definition cannot span a blank line — this is where one provably\n // ends, and the next content line pins the seam again.\n cp.defBlockMaybeOpen = false;\n cp.prevLineOpenContent = false;\n cp.tableMaybeOpen = false;\n cp.containerMaybeOpen = false;\n return;\n }\n\n // --- plain text line ---\n // Blocker 3 rolling verdict (raw text; block markers sit at line start\n // where a code span cannot precede them).\n if (isBlockStart) {\n const verdict = classifyBlockStart(ln.text, ln.indent, cp.defListEnabled);\n if (verdict !== null) cp.hazardVerdict = verdict;\n } else if (\n LIST_MARKER_RE.test(ln.text) ||\n FOOTNOTE_DEF_RE.test(ln.text) ||\n (cp.defListEnabled && DEF_LIST_DD_RE.test(ln.text)) ||\n ln.indent >= 4\n ) {\n // A marker line NOT sitting after a blank still begins a block: lists\n // interrupt paragraphs, and anything starts fresh after a just-closed\n // fence/math line. Without this, the verdict stays stale and a\n // candidate right after freezes HALF a loose list (fuzz-arbiter\n // counterexamples: paragraph + glued bullet, `$$` close + glued\n // ordered item). Inside an html flow run the marker is raw text and\n // no hazard exists — turning the verdict on anyway only over-blocks.\n //\n // indent >= 4 mirrors A1 at glued positions (seed-20260841): a\n // 4-indented line directly after a fence close starts an indented CODE\n // block that merges across later blanks — a stale verdict let a\n // candidate split it. A mid-paragraph indented line is only a lazy\n // continuation, so flagging it too is pure over-block (safe).\n cp.hazardVerdict = true;\n }\n\n // Masking is only valid where micromark parses INLINE content. A line\n // starting with a TAG at block indent (approximately) opens an html FLOW\n // block of type 1/6/7 — those run until a blank line with NO inline\n // parsing: backtick runs in it (and in its continuation lines) are\n // literal text, and masking them would hide REAL tags from the balance\n // scan. Sticky until the next blank, like the unpaired-run gate. `<!`/\n // `<?` starters (types 2-5) are NOT sticky — they end at their\n // terminator's line, which rawOpenAtLineStart already tracks; making\n // them sticky suppressed a REAL `$$` open right after `-->` and let a\n // candidate split the math block (fuzz counterexample).\n //\n // Tag names OUTSIDE the type-6 list used to poison the rolling hazard\n // verdict (\"ambiguous starters\") because classifying type 7 needed\n // attribute-quote parsing. Type 7 IS exact now — the line either opens a\n // block (the member) or is a paragraph, both micromark's own answer — so\n // the blanket hazard is retired with the ambiguity (exact-type-7 stage;\n // the one undecidable interrupt class, pipe lines, has its own sticky\n // poison at the refused tag line).\n const tagStart = ln.indent <= 3 ? /^<\\/?([A-Za-z][A-Za-z0-9-]*)/.exec(mdTrimStart(ln.text)) : null;\n if (tagStart) {\n // Gate on the MEMBER, never on \"did the run start here\" — the retired\n // run flag was set by ANY `<tag` line start, an over-approximation:\n // `<embed` (not a type-6 name, not a complete\n // type-7 line) is a PARAGRAPH to micromark, yet it opened the run and\n // so hid the real type-1 block that followed it (2026-08-21 scaled\n // soak, shard 0). What matters is whether a real html block is already\n // open: type 1 may interrupt a paragraph, but a `<script>` nested\n // inside an open type-6 block does not start one. The member answers\n // MORE truly than the run flag it replaced (P4b-completion commit 6)\n // in one place — a type-1 line inside an open type 2-5 block\n // (`<?a\\n<script>`): the flag was false there and a phantom type-1\n // opened inside the construct's content; the member is html{3-5} and\n // correctly refuses. Movements measured and pinned with this commit.\n const noRealBlockOpen = cp.mdBlock.kind !== 'html';\n const t1 = noRealBlockOpen ? TYPE1_START_RE.exec(mdTrimStart(ln.text)) : null;\n // `raw` is the parse5 half of the same line: three of the four type-1\n // names are raw-text elements, `pre` is not.\n if (t1) cp.mdBlock = { kind: 'html', type: 1, raw: RAW_TEXT_ELEMENTS.has(t1[1].toLowerCase()) };\n if (cp.mdBlock.kind !== 'html') {\n const t = mdTrimStart(ln.text);\n const t6 = TYPE6_START_RE.exec(t);\n const realT6 = t6 !== null && TYPE6_NAMES.has(t6[1].toLowerCase());\n const t1Line = TYPE1_START_RE.test(t);\n // The interrupt-SENSITIVE class: a line whose only reading as an html\n // block is condition 7. Types 1 and 6 may interrupt a paragraph, so\n // their answer never depends on what came before, and neither\n // undecidable-interrupt poison below applies to them.\n const type7Shaped = !realT6 && !t1Line && isType7Line(t);\n if (\n realT6 ||\n t1Line ||\n // Type 7 cannot interrupt CONTENT (micromark's paragraph/definition\n // construct — `prevLineOpenContent`, the exact interrupt input; the\n // old `prevLineWasText` gate refused after headings, terminator\n // lines and fence closes, where micromark measurably opens). The\n // classifier itself is exact too (isType7Line) — including closing\n // raw-text names (`</style>` alone is type 7, measured) and\n // quoted-`>` attribute values.\n (!cp.prevLineOpenContent && type7Shaped)\n ) {\n // The 6/7 member (type 1 wrote html{1} above; inside this branch\n // the member is provably 'none', the guard is shape only).\n if (cp.mdBlock.kind === 'none') cp.mdBlock = { kind: 'html', type: realT6 ? 6 : 7 };\n } else if (cp.prevLineOpenContent && cp.tableMaybeOpen && type7Shaped) {\n // The one interrupt class a line model cannot settle: after a GFM\n // TABLE row type 7 opens (a table is not content), after a\n // pipe-bearing PARAGRAPH line it cannot — and table-ness was\n // decided lines ago by a header/delimiter pair this scanner does\n // not model. The marker is STICKY (`tableMaybeOpen`), because a\n // table is continued by any non-blank non-structural line — the\n // pipe-less row `see prose` after `| 1 | 2 |` is still a row\n // (soak seed 20283008). Whichever way micromark went, the two\n // readings give this line to different grammars, so the phase is\n // poisoned from here — sticky over-block, the same treatment as\n // every other undecidable divergence.\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n }\n // The SECOND undecidable interrupt class, same shape as the pipe one\n // and outside the if/else because it applies to the claim as well as\n // to the refusal. micromark's `tagName` refuses type 7 on\n // `self.interrupt && !self.parser.lazy[line]` — the lazy half is an\n // input the content model does not have. While a container may be\n // open this line is either its LAZY continuation (micromark opens a\n // container-held block) or the line after the container closed\n // (micromark opens a TOP-LEVEL multi-line block); the content model\n // reads the container line as open content and refuses. Both\n // readings give the line to a different grammar than the scanner's,\n // so poison rather than answer — sticky over-block, and the marker\n // disarms at the blank, where the container provably ended and the\n // plain verdict is right again.\n if (type7Shaped && cp.containerMaybeOpen) {\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n }\n }\n }\n // Migration B is COMPLETE: exact type 7 shipped (classifier + interrupt\n // commits), rows 4/6/7 plus the truncated-open and seam-set sites read\n // the member, and `mayBeRawToMicromark` is deleted. The nonType6QuotedGt\n // corpus family keeps standing guard over the once-was-a-hole class.\n // A type 2-5 html block (`<!--` / `<?` / `<!X` / `<![CDATA[`) STARTING on\n // this line at block indent. Not sticky (V9 — the block ends with its\n // terminator's line), and not `inRawText` unless the construct stays\n // open past EOL — but when it opens AND closes on this line, the bytes\n // after the closer are still this html block's raw content: floating\n // remnant with the blocker-6 tail-dependent seam (`<!-- c --> tail`\n // followed by a def line that a later append turns into a paragraph —\n // direction-battery counterexample surfaced by the overlapping-\n // terminator generator family, 2026-08). Feeds the blocker-6 check only.\n const rawFlowStart = ln.indent <= 3 && /^<(?:!--|\\?|![A-Za-z]|!\\[CDATA\\[)/.test(mdTrimStart(ln.text));\n // Whether this line's bytes belong to an html block / raw construct in\n // either grammar — captured HERE (after the tag-start pre-scan classified\n // the line, before the raw-construct machine may close a 2-5 member\n // mid-line) for the content-tracking table at the end of the plain path:\n // html-block lines close micromark's content construct (type 7 opens\n // after a terminator line, measured), and a mid-line INLINE opener does\n // not make the line any less a paragraph.\n const htmlOwnedLine = cp.mdBlock.kind === 'html' || rawOpenAtLineStart || rawFlowStart;\n\n // Same-line code-span masking for HTML/ref/footnote extraction. A null\n // mask means \"unsafe to mask here\" — scan the raw text (over-blocking).\n // Migration B row 4 (exact type 7): masking is valid exactly where\n // micromark parses INLINE content, and that is now the member's answer —\n // an open html block (any type, the pre-scan classified THIS line\n // already), a 2-5 construct open at line start or STARTING here\n // (`rawFlowStart` — the flag never covered those, `<?` fails its regex),\n // or parse5-side raw content. The proxy this replaces also suppressed\n // masking on every line after a `<embed x`-style PARAGRAPH opener until\n // the next blank — lines micromark measurably parses inline, where a\n // backticked tag IS a code span parse5 never sees (the boundary rises\n // there are this stage's payoff, verified by engine probe and pinned).\n const maskingSuppressed = htmlOwnedLine || inRawTextTok(cp.p5Tok);\n const { masked, unpaired } = maskingSuppressed\n ? { masked: null, unpaired: false }\n : maskIntraLineCodeSpans(ln.text, cp.paragraphHasUnpairedRun);\n if (unpaired) cp.paragraphHasUnpairedRun = true;\n const scanText = masked ?? ln.text;\n\n // Blocker 5 (reference taint) — moved to referenceTaint.ts as a pure\n // move (two-model plan P2); the module doc carries the rationale.\n // Migration B row 5 (P4b-completion): the def gate goes EXACT — \"is a\n // def-shaped line raw to micromark\" is answered by the member (an open\n // md html block) plus the parse5-side masks. The narrowing over the old\n // proxy is safe for a reason that must stay written down: the second\n // gate inside collectRefLine is `defLineStart`, and `prevLineWasText`\n // is set at the end of EVERY non-blank line — so on every narrowed\n // shape (a type-7-hole run line, a def line glued under a closed 2-5\n // block) the def is a paragraph-continuation line and stays\n // unregistered. Loosen `defLineStart` and this migration's safety\n // argument goes with it.\n // Deliberately NOT `htmlOwnedLine`: that one adds `rawFlowStart`, which\n // this gate has no use for. A line that STARTS a 2-5 construct begins\n // `<!--` / `<?` / `<!X` / `<![CDATA[` at block indent, and a def line\n // begins `[` (DEF_RE / FOOTNOTE_DEF_RE) — the two are mutually exclusive\n // at line start, so adding the term could not change a single verdict.\n // The asymmetry is intentional, not an oversight (2026-08-26 review).\n const defRawToMicromark = cp.mdBlock.kind === 'html' || rawOpenAtLineStart || inRawTextTok(cp.p5Tok);\n const { validLinkDef } = collectRefLine(cp, ln.start, ln.end, scanText, defRawToMicromark, isBlockStart);\n\n // Blocker 1: raw-block (types 3–5) state machine, then tag balance.\n // `rawSpans` records the byte ranges this line contributes to raw\n // constructs (interiors, openers, terminators) — blocker 6's remnant\n // check below must not mistake construct-consumed bytes for floating\n // text (fixture: the `?>` terminator line of a PI block).\n const rawSpans: Array<[number, number]> = [];\n let pos = 0;\n // parse5 divergence (2026-08 project-review P1): CommonMark ends a `<?`\n // block at `?>` and a `<![CDATA[` block at `]]>`, but rehype-raw's HTML\n // tokenizer sees BOTH as bogus comments that end at the FIRST `>`. Every\n // byte between that `>` and the CommonMark terminator is raw text to\n // micromark yet REAL markup to parse5 (a `<details>` there is an open\n // element that reparents later siblings). This line model cannot serve\n // two grammars at once, so the moment a construct's first `>` is not its\n // CommonMark terminator, the phase is poisoned from this line on (sticky\n // over-block — the whole divergent region re-parses inside the tail);\n // the micromark model is kept for the scan itself.\n const poisonRawDivergence = (): void => {\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n };\n /** A `<?` / `<!DECL` / `<![CDATA[` opened PARAGRAPH-INLINE on this line\n * (or at code indent). Set only when the opener is not at a position that\n * could start an html block — the block forms really do run to their\n * terminator, but the inline forms are html-TEXT attempts that any\n * block-interrupting next line retracts to literal text. */\n let inlineRawOpenerIdx = -1;\n while (pos < scanText.length) {\n if (mdHtml(cp.mdBlock, 3) || mdHtml(cp.mdBlock, 5)) {\n // P3b batch 3: micromark's type 3/5 block runs to `?>` / `]]>`;\n // parse5's BOGUS COMMENT (the p5 half of these constructs, tracked\n // on `p5Tok` since this batch) ends at the FIRST `>`. When the two\n // disagree, the window between parse5's `>` and micromark's\n // terminator is construct interior to one grammar and live input to\n // the other — poisoned ONLY if it can hold bytes parse5 acts on\n // (P5_MARKUP_RE), same rule as the `--!>` window. In window mode\n // (p5 already out) the bytes are parse5 TEXT: no rawSpans, so the\n // blocker-6 residue sees the remnant they become.\n const isPi = mdHtml(cp.mdBlock, 3);\n const term = isPi ? '?>' : ']]>';\n const c = scanText.indexOf(term, pos);\n const mdEnd = c === -1 ? scanText.length : c + term.length;\n if (cp.p5Tok.kind === 'bogus') {\n const gt = scanText.indexOf('>', pos);\n if (gt !== -1 && (c === -1 || gt !== c + term.length - 1)) {\n // parse5 closes here; the window to micromark's terminator (or\n // EOL — later window lines are checked at line start).\n cp.p5Tok = { kind: 'data' };\n rawSpans.push([pos, gt + 1]);\n if (P5_MARKUP_RE.test(scanText.slice(gt + 1, c === -1 ? scanText.length : c))) {\n poisonRawDivergence();\n }\n } else {\n rawSpans.push([pos, mdEnd]);\n if (c !== -1) cp.p5Tok = { kind: 'data' };\n }\n }\n // (p5 out already: window-mode bytes stay unmasked on purpose.)\n if (c === -1) break;\n cp.mdBlock = { kind: 'none' };\n pos = mdEnd;\n continue;\n }\n // The two first-`>` machines are de-fused (P4b-completion commit 1):\n // md type 4 is micromark's declaration block, `bogus` is parse5's\n // bogus comment. Their terminators coincide today, but they are\n // different grammars' states and each branch closes only its own.\n if (mdHtml(cp.mdBlock, 4)) {\n const c = scanText.indexOf('>', pos);\n if (c === -1) {\n rawSpans.push([pos, scanText.length]);\n break;\n }\n rawSpans.push([pos, c + 1]);\n cp.mdBlock = { kind: 'none' };\n if (cp.p5Tok.kind === 'bogus') cp.p5Tok = { kind: 'data' };\n pos = c + 1;\n continue;\n }\n if (cp.p5Tok.kind === 'bogus') {\n const c = scanText.indexOf('>', pos);\n if (c === -1) {\n rawSpans.push([pos, scanText.length]);\n break;\n }\n rawSpans.push([pos, c + 1]);\n cp.p5Tok = { kind: 'data' };\n pos = c + 1;\n continue;\n }\n // Openers below are TEXT to BOTH grammars while an outer text-consuming\n // construct is open — micromark: a comment/type-1 block owns every line\n // up to and including its end line; parse5: comment / RAW-TEXT content\n // runs to its own terminator, and where the two disagree about the\n // terminator the divergence poisons have already fired. The old code\n // let them open PHANTOM constructs inside those regions (measured:\n // `<!--\\n<?x` held commentOpen AND piOpen at once — blocking-only\n // artifacts, but artifacts a single MdBlock cannot and should not\n // represent).\n //\n // The type-1 term asks the PARSE5 half (`mdType1RawText`), not \"is a\n // type-1 block open\": `pre` is a type-1 name that parse5 tokenizes in\n // the DATA state, so `<?x` inside `<pre>` really opens a bogus comment\n // that eats the `>` of the `</pre>` line and leaves the element open\n // (F13 — 20 divergent frames on `<pre>\\n<?x\\n</pre>` + tail; before the\n // gate existed the phantom opener's own first-`>` poison covered it by\n // accident, and the gate removed both).\n if (commentOpenAtLineStart || inRawTextTok(cp.p5Tok) || mdType1RawText(cp.mdBlock)) {\n // An INLINE-opened raw-text region is the one masked context whose\n // parse5 state is unknowable from here: micromark called the opener\n // paragraph text, and parse5's tokenizer may have CLOSED the region\n // already (`</iframe a>` — attributes make it literal text to\n // micromark and a real end tag to parse5's RCDATA/RAWTEXT states).\n // The from-here-on poison at the region's opening line covers\n // forward damage, but a RETROACTIVE construct inside the masked\n // bytes (`<!DOCTYPE …>`, document-structure tags, `<template>`)\n // erases and merges BACKWARD past candidates emitted long before the\n // region opened — this scan breaking here is exactly what kept the\n // doctype's own document-wide poison from firing (release-gate\n // finding B, seed 20293004 — F17). Whether parse5 really saw the\n // construct cannot be decided; poison document-wide, the erasure\n // standard. Block-opened regions are exempt: their close is tracked\n // exactly (attribute-bearing end tags included), so the doctype\n // branch below really runs once the region ends.\n if (\n inRawTextTok(cp.p5Tok) &&\n cp.p5Tok.openedInline &&\n (tailCarriesRetroactive(ln.text) || /<template(?![a-z0-9-])/i.test(ln.text))\n ) {\n cp.phasePoisonedAt = 0;\n }\n break;\n }\n const pi = scanText.indexOf('<?', pos);\n const cd = scanText.indexOf('<![CDATA[', pos);\n // `<!` + letter = declaration; `<!--` (third char '-') and\n // `<![CDATA[` (third char '[') never match this.\n const dm = scanText.slice(pos).search(/<![A-Za-z]/);\n const decl = dm === -1 ? -1 : pos + dm;\n // parse5 bogus comment openers — only where the bytes are raw to it (a\n // real html-flow run); in a paragraph `<!` / `</` are literal text that\n // never reaches the tokenizer. `<!` + letter is the declaration above\n // (same \"until `>`\" shape); `<!--` / `<![CDATA[` are their own constructs.\n // Migration A row 2 (P4b-completion): the question is \"are these bytes\n // raw to parse5\", and the exact answer is \"an md html block is open\" —\n // provably equal to the old run-flag read HERE: types 1/2 broke out of\n // the loop above, 3-5 were consumed by their own branches, and the\n // in-comment promotion artifact cannot reach this line (the comment\n // union breaks first). Types 6/7 are the member since commit 2.\n const bm =\n cp.mdBlock.kind === 'html' ? scanText.slice(pos).search(/<!(?!--|[A-Za-z]|\\[CDATA\\[)|<\\/(?![A-Za-z])/) : -1;\n const bogus = bm === -1 ? -1 : pos + bm;\n const starts = [pi, cd, decl, bogus].filter((x) => x !== -1);\n if (starts.length === 0) break;\n const first = Math.min(...starts);\n if (first === bogus) {\n rawSpans.push([bogus, bogus + 2]);\n // Migration collision rule (P3a): a bogus opener while raw text is\n // open is TEXT to parse5 — the old model set a second flag anyway.\n // Poison instead of overwriting the raw-text state (only lowers).\n if (cp.p5Tok.kind === 'data') cp.p5Tok = { kind: 'bogus' };\n else cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n pos = bogus + 2;\n } else if (first === cd) {\n rawSpans.push([cd, cd + 9]);\n // Claim the member only OUTSIDE a 6/7 run — inside one, micromark\n // opens nothing (the run owns every byte to the blank) and the old\n // unconditional write LOST the run's identity: `</t>` opened a\n // type-7 run, `<![CDATA[…]]>` overwrote the member and closed it at\n // `]]>`, and the `$$` after was mistaken for a REAL math open — the\n // phantom closer then broke output-neutrality (soak seed 20282500,\n // fuzz shard 0; latent behind the run flag until its deletion).\n // Same rule as `<!--` since P4b commit 1: the parse5 half lives on\n // the overlay regardless (`<![CDATA[` in fragment html is a bogus\n // comment to the first `>` — rev2 #4, measured).\n if (cp.mdBlock.kind === 'none') cp.mdBlock = { kind: 'html', type: 5 };\n if (cp.p5Tok.kind === 'data') cp.p5Tok = { kind: 'bogus' };\n if (!isMdBlank(scanText.slice(0, cd)) || ln.indent > 3) inlineRawOpenerIdx = cd;\n pos = cd + 9;\n } else if (first === pi) {\n if (scanText[pi + 2] === '>') {\n // `<?>` — the opener's `?` doubles as the closer's: micromark html\n // FLOW closes it on the spot (after `<?` it is already \"at `?`,\n // searching for `>`\") and parse5 closes its bogus comment at that\n // same `>`. Both agree → a closed 3-byte span, no state. In html\n // TEXT micromark wants a real `?>` after `<?` (paragraph-inline\n // `<?>` stays open to micromark, closed to parse5) — that\n // divergence is poisoned like the others.\n rawSpans.push([pi, pi + 3]);\n pos = pi + 3;\n if (!isMdBlank(scanText.slice(0, pi)) || ln.indent > 3) poisonRawDivergence();\n continue;\n }\n rawSpans.push([pi, pi + 2]);\n // Member only outside a 6/7 run (see the CDATA branch).\n if (cp.mdBlock.kind === 'none') cp.mdBlock = { kind: 'html', type: 3 };\n if (cp.p5Tok.kind === 'data') cp.p5Tok = { kind: 'bogus' };\n if (!isMdBlank(scanText.slice(0, pi)) || ln.indent > 3) inlineRawOpenerIdx = pi;\n pos = pi + 2;\n } else {\n rawSpans.push([decl, decl + 2]);\n // `<!DOCTYPE` is the one declaration parse5 tokenizes as a real\n // DOCTYPE rather than a bogus comment, so it is consumed and erased\n // (retroactive — see DOCUMENT_STRUCTURE_NAMES). `<!ENTITY` and every\n // other `<!` + letter becomes a comment node and is position-stable.\n // Gated on block indent only, not on position within the line: an\n // INLINE `<!DOCTYPE>` in prose measured safe, but proving how far\n // parse5's insertion modes can reach back is not worth the precision,\n // so any doctype on a line that could open an html block poisons.\n // At indent >= 4 the line is indented CODE (or a lazy paragraph\n // continuation, where the doctype is html-text) — parse5 never sees\n // markup there, and poisoning cost a boundary of 62 → 0 on a plain\n // ` <!DOCTYPE html>` block. Backticked mentions are masked out\n // before this scan and never reach here at all.\n if (ln.indent <= 3 && /^doctype/i.test(scanText.slice(decl + 2))) cp.phasePoisonedAt = 0;\n // Member only outside a 6/7 run (see the CDATA branch).\n if (cp.mdBlock.kind === 'none') cp.mdBlock = { kind: 'html', type: 4 };\n // md type 4 and the p5 bogus comment share their first-`>` end, so\n // no window can open — the pairing is still tracked for honesty.\n if (cp.p5Tok.kind === 'data') cp.p5Tok = { kind: 'bogus' };\n if (!isMdBlank(scanText.slice(0, decl)) || ln.indent > 3) inlineRawOpenerIdx = decl;\n pos = decl + 2;\n }\n }\n // Blocker 7, completed for the remaining inline raw constructs — and with\n // the DOCUMENT-WIDE poison, not the from-here-on one. Two stacked failure\n // modes, both measured 2026-08-24:\n //\n // 1. micromark's BLOCK scan can interrupt the paragraph at the next line,\n // so the bytes this line model reads as construct interior are a fresh\n // html block to micromark. `x <!D y` + newline + `<!DOCTYPE>`: type 4\n // interrupts, parse5 erases the doctype — while this scanner read it as\n // declaration interior, never ran its poison, and \"closed\" the\n // declaration at the doctype's own `>` (30-byte live under-block).\n // 2. parse5 reads the whole cross-line construct as ONE bogus comment (to\n // the first `>`), i.e. a node the sanitize pass REMOVES — and removing\n // it merges the text nodes on either side. That merge reaches BACKWARD:\n // in `see … linked\\n\\n[^a]: def\\n<i>y</i> <?php …\\n\\n<!DOCTYPE html>…`\n // the merged separator text sits at index 1 of the root, INSIDE a\n // boundary at offset 24, forty bytes before the opener. A poison at the\n // opener's own offset provably does not cover it. Erasure-by-sanitize\n // is the DOCUMENT_STRUCTURE_NAMES semantics, and gets the same poison.\n //\n // (`<!--` has the same erasure shape but its own earlier machinery has kept\n // every measured variant safe — its poison is not widened here, and the\n // corpus carries the shapes that would catch it if that ever stops.)\n //\n // `type >= 3` also matches the 6/7 members, and has since the member\n // overwrite rule tightened (96901ff): a mid-line `<?…?>` or `<!X…>`\n // INSIDE an open type 6/7 run no longer takes the member, so the run's\n // own 6/7 survives to this test and the opener poisons document-wide.\n // That is KEPT deliberately, not an accident of the member surviving —\n // the run case is the same sanitize-erasure shape as the paragraph one,\n // and narrowing the predicate back to 3-5 would raise boundaries for\n // pure freeze-rate gain (2026-08-26 review min-1: measured, and declined\n // on the risk side of that trade).\n if (inlineRawOpenerIdx !== -1 && cp.mdBlock.kind === 'html' && cp.mdBlock.type >= 3) {\n cp.phasePoisonedAt = 0;\n }\n // Raw-construct bytes are data, not markup — mask them (offset-preserving)\n // and scan the REST of the line for tags. The old scan skipped the whole\n // line whenever a raw construct touched it, so a tag before a same-line\n // opener (`<details> <?php`) or after a terminator (`?><details>`) went\n // uncounted — an under-block past a parse5-open element (v2.4.0 review\n // P1/P4; the former was documented as an accepted edge, the latter not).\n let tagText = scanText;\n for (const [from, to] of rawSpans) {\n tagText = tagText.slice(0, from) + ' '.repeat(to - from) + tagText.slice(to);\n }\n // Inside a tag that started on an earlier line of this html-flow run (see\n // `pendingTag`): up to the first RAW `>` the bytes are attribute\n // garbage to parse5 — no tags, no comments, no truncation there.\n let skipTagScan = false;\n if (cp.pendingTag !== null) {\n // De-indent below the truncated line: possibly out of the container\n // (see `pendingTag.indent`) — over-block either way.\n if (ln.indent < cp.pendingTag.indent) poisonRawDivergence();\n // Walk the RAW line with parse5's attribute-area state: a `>` inside a\n // quoted value is a value byte (`<hr title=\"\\n<p></div>` — r2 P1-2: the\n // first `>` used to end the tag and `</div>` closed the outer div), and\n // a value whose quotes pair on this line is ordinary (`<div\\n\n // class=\"a\">` — r2 P2-3: any quote before the `>` used to poison the\n // whole stream, freezing 0.4% of a document instead of 96%).\n const attrs = { state: cp.pendingTag.attr };\n const gt = scanTagAttrs(ln.text, 0, ln.text.length, attrs);\n if (gt === -1) {\n // Line ending: ends an unquoted value, is a byte inside a quoted one.\n scanTagAttrs('\\n', 0, 1, attrs);\n cp.pendingTag = { attr: attrs.state, indent: cp.pendingTag.indent };\n skipTagScan = true;\n } else {\n // The `>` completes the pending truncated CLOSE (parse5 emits the end\n // tag there); a truncated OPEN was already counted at its line.\n for (const tag of cp.pendingTruncatedCloses) applyTag(tag, true);\n cp.pendingTruncatedCloses = [];\n cp.pendingTag = null;\n tagText = ' '.repeat(gt + 1) + tagText.slice(gt + 1);\n }\n }\n // Set when the tag scan itself found a tag that runs past the line end\n // (quoted attribute value left open): the anchor-on-last-`<` truncation\n // check below must not count it a second time.\n let tagHandledAsTruncated = false;\n if (!skipTagScan) {\n TAG_OR_COMMENT_RE.lastIndex = 0;\n let m: RegExpExecArray | null;\n let lastCommentOpenerIdx = -1;\n while ((m = TAG_OR_COMMENT_RE.exec(tagText)) !== null) {\n // Raw-text element content: comment tokens are text too; tags go\n // through applyTag, which admits only the element's own end tag.\n if (inRawTextTok(cp.p5Tok) && (m[0] === '<!--' || m[0] === '-->' || m[0] === '--!>')) {\n // A `<!--` inside `<script>` puts parse5 in \"script data escaped\",\n // which is where the two grammars stop agreeing — see the poison in\n // `applyTag`.\n if (cp.p5Tok.kind === 'script') {\n if (m[0] === '<!--') cp.p5Tok = { ...cp.p5Tok, escaped: true };\n // `-->` leaves the escape ladder ENTIRELY: the single- and\n // double-escaped dash-dash states both switch to \"script data\"\n // on `>` (HTML §13.2.5.24/§13.2.5.30, verified in parse5's\n // tokenizer). `--!>` stays escaped (`!` falls to anything-else\n // in the dash-dash states).\n if (m[0] === '-->') cp.p5Tok = { ...cp.p5Tok, escaped: false, double: false };\n }\n continue;\n }\n if (m[0] === '<!--') {\n const next = tagText.slice(m.index + 4, m.index + 6);\n if (commentEitherOpen(cp.mdBlock, cp.p5Tok)) {\n // Inside an OPEN comment `<!--` is content — but the regex\n // consumed its `--`, which may be the start of the closer:\n // `<!-->` / `<!--->` carry a `-->` (closes for both grammars;\n // soak seed 20260759: `<!--\\n\\n<!-->\\n<details>` left the\n // comment open and skipped the real `<details>`), `<!--!>` /\n // `<!---!>` carry a `--!>` (parse5-only closer → poison).\n if (next.startsWith('>') || next === '->') {\n // Close ONLY the comment member: with the union, an unguarded\n // clear here nukes whatever else holds the member — measured\n // regression: a stray closer while a type-1 block held html{1}\n // released every later candidate (soak leg 2, seed 20280501).\n if (mdHtml(cp.mdBlock, 2)) cp.mdBlock = { kind: 'none' };\n if (cp.p5Tok.kind === 'comment') cp.p5Tok = { kind: 'data' };\n } else if (next === '!>' || next === '-!') {\n // parse5-only closer inside the token: parse5 leaves the\n // comment, micromark does not. P3b batch 2: the divergence\n // WINDOW (from here to micromark's `-->`) is markup to parse5\n // and comment content to micromark — poison only if markup\n // bytes can appear in it on this line; later window lines are\n // checked at line start. A markup-free window is text to both\n // grammars and converges at `-->`.\n if (cp.p5Tok.kind === 'comment') cp.p5Tok = { kind: 'data' };\n if (mdHtml(cp.mdBlock, 2) && P5_MARKUP_RE.test(tagText.slice(m.index + m[0].length))) {\n poisonRawDivergence();\n }\n }\n continue;\n }\n if (next.startsWith('>') || next === '->') {\n // Empty comment with an overlapping closer (see the note above\n // TAG_OR_COMMENT_RE) — closed on the spot; the regex resumes after `<!--`,\n // where the leftover `>` / `->` matches nothing.\n continue;\n }\n // Inside an open type 6/7 block a `<!--` line is that block's\n // CONTENT — the member keeps the run's identity; parse5's comment\n // half lives on `p5Tok` (commit 1), and every comment read below\n // goes through the union.\n if (cp.mdBlock.kind === 'none') cp.mdBlock = { kind: 'html', type: 2 };\n if (cp.p5Tok.kind === 'data') cp.p5Tok = { kind: 'comment' };\n lastCommentOpenerIdx = m.index;\n continue;\n }\n if (m[0] === '-->') {\n // A STRAY `-->` (no comment open) is text to both grammars: the\n // old per-field `commentOpen = false` was a no-op there, and the\n // union must keep it one — an unguarded member clear released a\n // type-1 block's html{1} (soak leg 2, seed 20280501, `</script/>`\n // false closer upstream; regression pinned).\n if (mdHtml(cp.mdBlock, 2)) cp.mdBlock = { kind: 'none' };\n if (cp.p5Tok.kind === 'comment') cp.p5Tok = { kind: 'data' };\n continue;\n }\n if (m[0] === '--!>') {\n // parse5 accepts `--!>` as a comment closer; CommonMark does not\n // (`<!--x--!>\\n<details>\\n-->` is one html block to micromark\n // whose `<details>` is a REAL open element to parse5). P3b\n // batch 2 retires the unconditional poison: parse5's comment\n // CLOSES here, micromark's block runs on to `-->`, and the\n // window between them diverges only if it holds bytes parse5\n // would act on — `P5_MARKUP_RE` on the line remainder here, and\n // per line at the line-start check while the relation stays\n // split (md html{2} open, p5 out of comment). A markup-free\n // window is parse5 TEXT inside micromark's block: the grammars\n // converge at `-->` and the block's output is a text remnant the\n // blocker-6 seam machinery owns (floatingResidue runs on the\n // INTERSECTION of the two comment states for exactly this).\n // A p5-ONLY comment closing here (inside a type 6/7 run) never\n // diverged from micromark at all — no poison either.\n if (mdHtml(cp.mdBlock, 2) && P5_MARKUP_RE.test(tagText.slice(m.index + m[0].length))) {\n poisonRawDivergence();\n }\n if (cp.p5Tok.kind === 'comment') cp.p5Tok = { kind: 'data' };\n continue;\n }\n if (commentEitherOpen(cp.mdBlock, cp.p5Tok)) continue;\n const closing = m[1] === '/';\n const tag = m[2].toLowerCase();\n if (strayTablePart(tag)) cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start + m.index);\n let attrs = m[3] ?? '';\n // Migration A row 3: \"may this tag continue across the line ending\"\n // is a raw-stream question — an open md html block answers it. The\n // broadening over the old flag is types 3-5 interiors, and THAT is\n // safe only because a paragraph-inline 3-5 opener already poisons\n // document-wide (the F9 rule) — named dependency, do not remove one\n // without the other.\n if (cp.mdBlock.kind === 'html' && (!inRawTextTok(cp.p5Tok) || (closing && tag === rawTextElement(cp.p5Tok)))) {\n // The regex ends the tag at the first `>`, but in a real html-flow\n // run parse5 ends it at the first `>` OUTSIDE a quoted attribute\n // value (`</div a=\">` eats the rest of the line and beyond — a\n // pre-existing under-block of the r2 P1-2 family, oracle review of\n // the batch). Walk the attribute area with parse5's state machine:\n // a later `>` moves the match end; no `>` on the line means the\n // tag continues on the next line — the truncated path below takes\n // it, with the quote state carried.\n const attrStart = m.index + 1 + (closing ? 1 : 0) + m[2].length;\n const st = { state: 'outside' as TagAttrState };\n const gt = scanTagAttrs(tagText, attrStart, tagText.length, st);\n if (gt === -1) {\n if (!VOID_TAGS.has(tag)) {\n if (closing) cp.pendingTruncatedCloses.push(tag);\n else applyTag(tag, false);\n }\n scanTagAttrs('\\n', 0, 1, st);\n cp.pendingTag = { attr: st.state, indent: ln.indent };\n tagHandledAsTruncated = true;\n break;\n }\n if (gt + 1 !== m.index + m[0].length) {\n attrs = tagText.slice(attrStart, gt);\n TAG_OR_COMMENT_RE.lastIndex = gt + 1;\n }\n }\n // Paragraph context (micromark html-text / a non-real run): a CLOSING\n // tag is only `</name` + optional whitespace + `>` — `</div a=\"b\">` is\n // literal text and parse5 never sees a close (oracle review of the r2\n // batch, pre-existing: `p <div> x </div a=\"b\"> y` froze past the open\n // div). In a real html-flow run parse5 accepts end-tag attributes.\n if (closing && cp.mdBlock.kind !== 'html' && !/^\\s*$/.test(attrs)) {\n // The match ran to the first `>`, swallowing whatever sat in the\n // \"attributes\". micromark does not: it backtracks the invalid\n // closing tag to literal text and re-scans from inside it, so\n // `</t <div a=\"\">` is text `</t ` plus a REAL html-text `<div a=\"\">`\n // that parse5 opens. Skipping the whole span left that div\n // uncounted — an under-block the direction battery caught once the\n // corpus reached the shape (2026-08-20 soak leg 2, minimised to\n // `</t <div a=\"\">\\n\\r```\\n```\\n\\n`, unstable under every future).\n // Rewinding past the NAME re-scans the swallowed bytes; the\n // documented `p <div> x </div a=\"b\"> y` case is unaffected, its\n // attribute area holds no tag.\n TAG_OR_COMMENT_RE.lastIndex = m.index + 2 + m[2].length;\n continue;\n }\n const selfClosing = /\\/\\s*$/.test(attrs);\n if (VOID_TAGS.has(tag) || (selfClosing && honoursSelfClosing(tag))) continue;\n applyTag(tag, closing);\n }\n // A comment opener that is NOT the line's first token and fails to\n // close by end of line is PARAGRAPH-INLINE: micromark only recognizes\n // it as a comment if `-->` arrives before the paragraph ends, else the\n // `<!--` is literal text and everything this scan skipped as \"comment\n // interior\" until the next stray `-->` is REAL markup (seed-20260828\n // under-block: a real unclosed `<details>` went uncounted and the\n // boundary landed past it, where its raw-time element absorbs every\n // later sibling). Which way it resolves is paragraph-shape-dependent —\n // poison the candidates from the opener on (sticky, over-block), same\n // mechanism as the suppressed fence/math opens. Line-START openers are\n // html block type 2 (terminator semantics, tracked exactly) and raw/\n // flow-context openers follow parse5's comment state — neither poisons.\n // No `!inRawText` gate here, and the poison is document-wide — two\n // upgrades over the original, both bought by counterexamples:\n //\n // - `inRawText` reads `mayBeRawToMicromark`, which ANY `<letter` line\n // start sets. `<b>x</b> <!-- trailing…` is a PARAGRAPH (`b` is not a\n // type-6 name), yet the `<b` start suppressed this poison entirely\n // and the document froze at 173 of 200 (2026-08-24 scaled soak,\n // direction battery). The line-start check below is the exact\n // question the proxy was approximating.\n // - a cross-line comment is a sanitize-REMOVED node, and removing it\n // merges the text on either side — the merge reaches backward past\n // the boundary, so an opener-offset poison has the same hole F9 had\n // for `<?`/`<!`+letter. Same rule, same document-wide poison.\n if (commentEitherOpen(cp.mdBlock, cp.p5Tok) && lastCommentOpenerIdx !== -1) {\n if (!isMdBlank(tagText.slice(0, lastCommentOpenerIdx)) || ln.indent > 3) {\n cp.phasePoisonedAt = 0;\n }\n }\n // Tags whose `<` sits OUTSIDE every code-span mask but whose `>` sits\n // INSIDE one (`<div x=\"\\`\">b\\``): micromark tries html-text at the `<`\n // before the later backtick can open a span, so the tag is REAL — but\n // the masked scan above never saw its `>` and counted nothing (v2.4.0\n // review, direction battery). Re-scan the raw line for exactly those\n // matches (raw-construct spans excluded — a `<b>` inside a PI is data).\n if (masked !== null && masked !== ln.text) {\n const inRaw = (i: number) => rawSpans.some(([from, to]) => i >= from && i < to);\n TAG_OR_COMMENT_RE.lastIndex = 0;\n let mr: RegExpExecArray | null;\n while ((mr = TAG_OR_COMMENT_RE.exec(ln.text)) !== null) {\n if (mr[0] === '<!--' || mr[0] === '-->' || mr[0] === '--!>') continue;\n const startMasked = masked[mr.index] !== ln.text[mr.index];\n const wholeVisible = masked.slice(mr.index, mr.index + mr[0].length) === mr[0];\n if (startMasked || wholeVisible || inRaw(mr.index) || commentEitherOpen(cp.mdBlock, cp.p5Tok)) continue;\n const closing = mr[1] === '/';\n const tag = mr[2].toLowerCase();\n if (strayTablePart(tag)) cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start + mr.index);\n // Same html-text rule: a closing tag with attributes is text.\n if (closing && mr[3] !== undefined && !/^\\s*$/.test(mr[3])) continue;\n const selfClosing = mr[3] !== undefined && /\\/\\s*$/.test(mr[3]);\n if (VOID_TAGS.has(tag) || (selfClosing && honoursSelfClosing(tag))) continue;\n applyTag(tag, closing);\n }\n }\n // A `>` anywhere on this line confirms every pending truncated open\n // (attributes may wrap; the tag really is a tag — keep it counted).\n // Checked on the RAW line: a `>` inside a masked code span may still be\n // the tag's own closer (`<div x=\"\\`\">b\\``: micromark parses the tag\n // first, the span never forms) — v2.4.0 review R2(a).\n if (cp.pendingTruncatedTags.length > 0 && ln.text.includes('>')) {\n // A confirmed pending table-part open (`<td` + attributes wrapping)\n // is a real stray table part: poison from here (see TABLE_PART_NAMES).\n if (cp.pendingTruncatedTags.some((t) => strayTablePart(t))) {\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n }\n cp.pendingTruncatedTags = [];\n }\n // Line-truncated tag start — anchor on the LAST `<` of the line.\n if (!commentEitherOpen(cp.mdBlock, cp.p5Tok) && !tagHandledAsTruncated) {\n let lastLt = -1;\n TAG_START_LT_RE.lastIndex = 0;\n for (let ms = TAG_START_LT_RE.exec(tagText); ms !== null; ms = TAG_START_LT_RE.exec(tagText)) {\n lastLt = ms.index;\n TAG_START_LT_RE.lastIndex = ms.index + 1;\n }\n if (lastLt !== -1 && !tagText.includes('>', lastLt)) {\n const m2 = TRUNCATED_TAG_RE.exec(tagText.slice(lastLt));\n if (m2) {\n const closing = m2[1] === '/';\n const tag = m2[2].toLowerCase();\n // Table-part poison for a TRUNCATED shape only where it is markup\n // for sure (a real html-flow run); in paragraph context `compare\n // a<td b` may be prose — poison waits for the `>` that confirms the\n // pending open (r2 P3), otherwise the blank line reverts it.\n if (strayTablePart(tag) && cp.mdBlock.kind === 'html') {\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start + lastLt);\n }\n // In a REAL html-flow run parse5 stays inside this tag across the\n // line ending — open, close or void alike (`<br` + `</div>` on the\n // next line: the `</div>` is garbage). See `pendingTag`.\n if (cp.mdBlock.kind === 'html') {\n // Where parse5 stands after this line's attribute bytes + the\n // line ending (m2[3] holds them; no `>` in there by construction).\n const attrs = { state: 'outside' as TagAttrState };\n scanTagAttrs(m2[3] + '\\n', 0, m2[3].length + 1, attrs);\n cp.pendingTag = { attr: attrs.state, indent: ln.indent };\n }\n if (closing) {\n // Never counted on the spot (2026-08-19 review P1: `para </style`\n // zeroed the balance while `<style>` was still open in BOTH\n // grammars — the fuzz corpus had truncated opens only). In an\n // html-flow run the `>` may still arrive on a later line of the\n // run — pend it; in paragraph context a block-indent `>` is a\n // blockquote (the 4+-space continuation shape is not modelled:\n // over-block), so it is treated as prose: nothing.\n if (!VOID_TAGS.has(tag) && cp.mdBlock.kind === 'html') cp.pendingTruncatedCloses.push(tag);\n } else if (!VOID_TAGS.has(tag)) {\n applyTag(tag, closing);\n // Only a PARAGRAPH-line truncation can turn out to be prose. In an\n // html-flow run the bytes are raw: parse5 keeps tokenizing the\n // dangling `<div` into whatever follows the block (fuzz\n // counterexample: `</details>\\n<div\\n\\n` shortened the seam\n // separator), so there the open stays counted, unrevertable.\n // Likewise when the RAW line has a `>` after its last `<`: the\n // masked-away `>` may be the tag's real closer — keep it counted\n // rather than reverting a real tag (R2(a)).\n const rawLastLt = ln.text.lastIndexOf('<');\n const rawTruncated = rawLastLt !== -1 && !ln.text.includes('>', rawLastLt);\n // Migration B, truncated-open revertibility (exact type 7):\n // \"paragraph-line truncation\" is the member's complement. The\n // retired proxy kept `<embed x`-style PARAGRAPH truncations\n // counted forever; they are prose candidates like any other\n // paragraph truncation and revert at the blank.\n if (!closing && !(htmlOwnedLine || inRawTextTok(cp.p5Tok)) && rawTruncated) {\n cp.pendingTruncatedTags.push(tag);\n }\n }\n }\n }\n }\n }\n\n // Blocker-6 detection: this line is html-flow content, tag balance is\n // fully settled after it, and — after masking construct-consumed bytes\n // (raw spans, comment content) and stripping tag/comment tokens —\n // non-whitespace remains: balanced FLOATING remnant that parse5 will\n // attach at the root with a tail-dependent seam. `inRawText` scopes this\n // to html-flow runs; interior remnant (openTotal > 0) is contained inside\n // an element and stays position-stable, so it does not set the flag.\n // Deliberately NOT gated on raw constructs being closed at line END: a\n // settle line can carry remnant AND open a multi-line comment/PI/decl/\n // CDATA (`remnant <!-- c`), and the terminator line's scan only covers\n // its own bytes — requiring closure here would hide that remnant forever\n // (the under-block direction; review counterexample with an arbiter-level\n // hast mismatch). Unterminated construct bytes are masked (rawSpans /\n // comment-token strip); their interior text may over-flag, which is safe.\n // Pending truncated opens are PHANTOMS until confirmed: for the seam\n // question they must not count as \"an element is open\" (an open element\n // contains the remnant; a phantom does not) — otherwise a rawFlowStart\n // line ending in a truncated `<div` skips this check and, when the\n // phantom is reverted at the blank line, nobody re-runs it (v2.4.0\n // review R2(b)). Treating them as closed here only over-flags.\n const effectiveOpen = cp.openTotal - cp.pendingTruncatedTags.length;\n // Migration B row 7, the SET half (exact type 7): floating raw remnant\n // arises from RAW bytes — html-block content in either grammar\n // (`htmlOwnedLine` covers the member, line-start 2-5 state and\n // `rawFlowStart`; the p5 raw-text kinds ride along for completeness).\n // A `<embed x`-style paragraph line's text becomes a position-stable\n // paragraph node, never seam-owned remnant — the retired proxy set the\n // flag there anyway.\n if ((htmlOwnedLine || inRawTextTok(cp.p5Tok)) && effectiveOpen <= 0) {\n // Raw-construct bytes are DELETED (not blanked) here: the residue is\n // judged on `length`, not `trim()` — whitespace-only floating text\n // (`<!-- c --> </s>` leaves ` `) is seam-dependent too (v2.4.0 review\n // P2), and blanking spans would fake such whitespace.\n let masked = '';\n let cursor = 0;\n for (const [from, to] of rawSpans) {\n masked += scanText.slice(cursor, from);\n cursor = to;\n }\n masked += scanText.slice(cursor);\n // Comment content spanning lines is not covered by rawSpans (comments\n // are tracked by the token scan, not the raw state machine), so the\n // residue is taken by the SAME token walk the balance scan uses — the\n // comment-open state carried in from the line start, overlapping\n // closers (`<!-->` closing an open comment) and all. Regex masking\n // (`<!--…-->`, `<!--…$`) got the overlap case wrong: it erased the\n // `<!-->` before the \"cut at `-->`\" step could see it, hiding the real\n // remnant after it (adversarial review of 5074c4b, blocker-6 seam).\n // Comment state for the residue = the INTERSECTION of the two\n // grammars' comment states (P3b batch 2 / oracle rev2 #5): bytes are\n // construct interior only if BOTH grammars are inside a comment. In\n // the `--!>` window (md open, p5 closed) the bytes are parse5 TEXT —\n // real remnant with a tail-dependent seam; a p5-only comment inside a\n // type 6/7 run over-flags, which is the safe direction.\n if (floatingResidue(masked, bothCommentsOpenAtLineStart).length > 0) {\n cp.p5SealPending = true;\n }\n }\n\n // The span reaches past this line ending. micromark and parse5 disagree\n // about where it ENDS — `</title a>` is literal paragraph text to\n // micromark (a closing tag takes no attributes) while parse5's RCDATA\n // tokenizer accepts it and closes the element — so from here the scanner\n // cannot model the span at all: it suppressed a `<div>` the real parse\n // leaves OPEN, which then grows with every append (2026-08-21 soak leg 2,\n // boundary 144 with the div at @86 extending to @161). Poison rather than\n // reject one candidate: the divergence outlives the span.\n if (inRawTextTok(cp.p5Tok) && cp.p5Tok.openedInline) {\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n }\n\n // CommonMark type-1 end condition: the line CONTAINS the closer string,\n // and that line still belongs to the block — so this runs last, after the\n // line has been scanned as raw flow. The next line starts fresh.\n if (mdHtml(cp.mdBlock, 1) && TYPE1_CLOSE_RE.test(ln.text)) {\n cp.mdBlock = { kind: 'none' };\n // The type-1 block ends here for micromark — if parse5's raw-text\n // element SURVIVES this close (the double-escape held it open), the\n // element will swallow later md blocks and their wrap separators as\n // its own text, and sanitize stripping it then merges the survivors\n // BACKWARD past any earlier boundary (the F9/F11 erasure class — the\n // 20282605/10/11 direction-battery counterexamples: `<script>\\n\n // <!--<script>\\n</script>\\n<div>d</div>\\n</script>` froze at 56 and\n // a one-character append changed the frozen region's children).\n // Document-wide poison, the erasure standard; a tangle that resolves\n // on ONE line never reaches this branch with the element open, so\n // the single-line recovery (and the `-->` exact exit) survive.\n if (inRawTextTok(cp.p5Tok)) cp.phasePoisonedAt = 0;\n }\n\n cp.blankRun = 0;\n cp.prevLineBlank = false;\n cp.prevLineWasText = true;\n // ── content tracking: the decision table for `prevLineOpenContent` ──\n // Derives micromark's \"content construct open\" per line class, measured\n // 2026-08-25 (see the field doc). The DIRECTION stakes: claiming \"open\"\n // where micromark closed under-claims the html{7} member (the class the\n // run flag used to blanket — masking/bogus-tracking then miss real raw\n // bytes, blocked only by a DECAYING hazard verdict); claiming \"closed\"\n // where micromark kept content open over-claims the member and can\n // shadow a REAL type-1 open behind a phantom type-7 run. Neither side is\n // conservative, which is why the table is exact per class and the one\n // undecidable class (pipe lines) is poisoned at the consuming gate.\n {\n const tt = mdTrimStart(ln.text);\n let openContent: boolean;\n if (htmlOwnedLine) {\n // html-block content in either grammar — closes/never opens content.\n openContent = false;\n } else if (ln.indent >= 4) {\n // A ≥4-indent line is a LAZY CONTINUATION when content is open\n // (stays open) and INDENTED CODE when it is not (stays closed).\n openContent = cp.prevLineOpenContent;\n } else if (ATX_HEADING_RE.test(tt) || THEMATIC_BREAK_RE.test(tt)) {\n openContent = false;\n } else if (BARE_MARKER_RE.test(tt)) {\n // An EMPTY list item cannot interrupt a paragraph (CommonMark §5.2),\n // so while content is open micromark reads the marker line as a LAZY\n // CONTINUATION and content stays open — a blanket `false` here\n // OVER-claimed. It agreed for a lone `-` by accident: that is also a\n // valid setext underline, which closes content under both readings,\n // and the accident is now written down rather than relied on. At a\n // block start `prevLineOpenContent` is false anyway, which is what\n // the single-line battery rows pin.\n openContent = tt[0] === '-' ? false : cp.prevLineOpenContent;\n } else if (SETEXT_LEFTOVER_RE.test(tt)) {\n // `=+` / `--`: a setext underline when a paragraph is open (content\n // CONSUMED into a heading), a paragraph of its own when not — EXCEPT\n // inside a table, where the same bytes are just another ROW and the\n // table (with the content it holds) runs on. Flipping to false there\n // disarmed `tableMaybeOpen`, the next content line lost the marker,\n // and a later refused tag line went unpoisoned (2026-08-26 review\n // M3(a): a `<br/>` line after a `--` row froze 89 of 93 bytes while\n // micromark held a real html block inside the frozen region).\n openContent = cp.tableMaybeOpen && cp.prevLineOpenContent ? true : !cp.prevLineOpenContent;\n } else {\n // Paragraph, definition, footnote definition, list item content,\n // blockquote line — all leave content open for interrupt purposes\n // (each measured as type-7-REFUSING).\n openContent = true;\n }\n cp.prevLineOpenContent = openContent;\n // Table tracking (see the field doc): a pipe line arms it; any\n // content-class line carries it; every block-structure line (the\n // openContent=false classes) breaks the table and disarms it.\n // The arming half asks whether this line could be a table ROW at all —\n // a `|` inside an html comment or any other html-owned line is not a\n // cell separator, and arming from one poisoned documents holding no\n // table (2026-08-26 review min-2). Over-claiming the marker only\n // widens the poison, so the narrowing is the precision half: it RAISES\n // boundaries, attributed per sample in the commit that landed it.\n cp.tableMaybeOpen = (!htmlOwnedLine && ln.text.includes('|')) || (cp.tableMaybeOpen && openContent);\n // Container tracking, the same sticky shape: a container-marker line\n // arms it, any content-class line carries it (a lazy continuation and\n // an indented item line are both content), every block-structure line\n // breaks the container and disarms it. Both halves take `openContent`,\n // because the marker shapes overlap the structure ones — `- - -` is a\n // thematic break, not a list item, and the table above is what says so.\n const containerMarker =\n CONTAINER_MARKER_RE.test(ln.text) ||\n FOOTNOTE_DEF_RE.test(ln.text) ||\n (cp.defListEnabled && DEF_LIST_DD_RE.test(ln.text));\n cp.containerMaybeOpen = openContent && (containerMarker || cp.containerMaybeOpen);\n }\n // Def CHAINS (A2) are a link-definition affordance: one def line can be\n // followed directly by another. A FOOTNOTE def does NOT chain — its\n // unindented next line lazily continues the footnote BODY, so a\n // def-shaped line glued under it is literal body text and registering it\n // would be a ghost def (fuzz counterexample). Refs on that line stay\n // extracted (footnote bodies parse inline content).\n cp.prevLineWasValidDef = validLinkDef;\n // Sticky to the next blank: from a def-shaped line on, every line may be\n // that definition's destination or (wrapped) title, none of which emits a\n // node the blocker-6 seam can hang on. Carrying it across ordinary\n // paragraph lines too only delays the release to the blank — over-block.\n cp.defBlockMaybeOpen = cp.defBlockMaybeOpen || DEF_RE.test(ln.text) || FOOTNOTE_DEF_RE.test(ln.text);\n // Footnote-def resumability (F16): armed by the def line itself; a\n // non-blank BLOCK-START line at indent ≤ 3 definitively interrupts the\n // footnote block (no body line can resume past it), everything else —\n // lazy continuations (not block starts), ≥4-indent continuations, and the\n // blanks that never reach this function's non-blank tail — carries it.\n if (FOOTNOTE_DEF_RE.test(ln.text)) cp.fnDefResumable = true;\n else if (isBlockStart && ln.indent <= 3) cp.fnDefResumable = false;\n}\n","/**\n * Markdown line-text primitives shared by the freeze scanner and the\n * reference-taint module (extracted in two-model plan P2 — a pure move).\n *\n * Markdown whitespace is U+0020 / U+0009 (plus line endings) — NOT the\n * Unicode set JS `trim()` strips. A line holding only U+3000 / U+00A0 is\n * paragraph text (a lazy continuation line) for micromark, and a fence\n * closer followed by NBSP is not a closer. Using `trim()` here made the\n * scanner emit a candidate inside an unfinished paragraph (v2.4.1 review\n * P1 — CJK output does carry full-width-space-only lines).\n */\n\nexport const MD_BLANK_RE = /^[ \\t\\r]*$/;\nexport const isMdBlank = (text: string): boolean => MD_BLANK_RE.test(text);\n/** ASCII-only counterparts of `trim()` / `trimStart()` — every scanner verdict\n * must strip exactly what micromark strips (adversarial review\n * of the first fix: a def rest ending in NBSP registered a ghost def; a\n * U+3000 before a paragraph-inline `<!--` skipped the divergence poison). */\nexport const mdTrim = (text: string): string => text.replace(/^[ \\t\\r]+|[ \\t\\r]+$/g, '');\nexport const mdTrimStart = (text: string): string => text.replace(/^[ \\t\\r]+/, '');\n","/**\n * Blocker 5 — reference taint (the (R) leg of the safety condition),\n * extracted from `computeFreezeBoundary` as a PURE MOVE (two-model plan\n * P2). micromark decides reference-ness at parse time, so a later\n * `[label]:` definition retargets earlier literal `[text]`; every\n * reference-style candidate before a boundary must resolve against a\n * SETTLED definition (one followed by a confirmed blank line). This module\n * owns the definition/reference grammar and the per-line collection over\n * the checkpoint's ref sub-state; the scanner calls `collectRefLine` once\n * per confirmed line and `settleRefsAndEarliestUnresolved` once per scan.\n *\n * Nothing here may change behaviour relative to the pre-move scanner: the\n * P2 acceptance is a strict zero delta on the pinned boundary corpus plus\n * a clean four-leg soak, and a non-zero result means revert, not explain.\n */\n\nimport { normalizeIdentifier } from 'micromark-util-normalize-identifier';\n\nimport { isMdBlank, mdTrim } from './mdLineText';\n\nexport interface UnresolvedRef {\n offset: number;\n label: string;\n footnote: boolean;\n}\n\nexport const FOOTNOTE_DEF_RE = /^ {0,3}\\[\\^[^\\]]*\\]:/;\n/** Any link/footnote reference definition at block indent. */\nexport const DEF_RE = /^ {0,3}\\[((?:[^[\\]\\\\]|\\\\.)+)\\]:/;\n/** Bracketed inline candidate: link/image reference or shortcut. No nesting\n * support — plain prose brackets count as taint (conservative direction). */\nconst REF_RE = /!?\\[((?:[^[\\]\\\\]|\\\\.)*)\\]/g;\n\n/** Index of the first unescaped `ch` in `text`, or -1. */\nfunction firstUnescaped(text: string, ch: string): number {\n for (let i = 0; i < text.length; i++) {\n if (text[i] === '\\\\') i += 1;\n else if (text[i] === ch) return i;\n }\n return -1;\n}\n\n/** Index of the last unescaped `[` that has no unescaped `]` after it, or -1. */\nfunction lastUnclosedBracket(text: string): number {\n let open = -1;\n for (let i = 0; i < text.length; i++) {\n const c = text[i];\n if (c === '\\\\') i += 1;\n else if (c === '[') open = i;\n else if (c === ']') open = -1;\n }\n return open;\n}\n\nfunction normalizeLabel(label: string): string {\n const collapsed = label.replace(/[ \\t\\r\\n]+/g, ' ').replace(/^ | $/g, '');\n return collapsed ? normalizeIdentifier(collapsed) : '';\n}\n\n/**\n * Rest-of-line check for a link definition after `[label]:`: a non-empty\n * destination (angle-bracketed or a bare non-whitespace run), then nothing\n * or a title that CLOSES on this line with nothing after it. Everything\n * else — no destination, non-title garbage, garbage after a closed title\n * (`\"t\"a`), or a title left OPEN at EOL (its continuation line may append\n * garbage that invalidates the whole def: `\"t\\nt2\"a`, K=4 census) — is\n * rejected: the line is (or may become) a paragraph whose `[label]` stays\n * a live ref. Rejecting a real def only over-blocks (refs stay tainted);\n * registering a ghost under-blocks. Multi-line titles therefore never\n * register — the documented A2 conservative edge.\n */\nfunction isPlausibleLinkDefRest(rest: string): boolean {\n const t = mdTrim(rest);\n if (t === '') return false; // destination-less\n const destEnd = linkDestinationEnd(t);\n if (destEnd === -1) return false; // micromark rejects the destination → paragraph\n const after = mdTrim(t.slice(destEnd));\n if (after === '') return true;\n const opener = after[0];\n if (opener !== '\"' && opener !== \"'\" && opener !== '(') return false;\n const closer = opener === '(' ? ')' : opener;\n // Find the UNESCAPED closing delimiter; the def is valid only when it\n // exists on this line and nothing but whitespace follows it.\n for (let i = 1; i < after.length; i++) {\n if (after[i] === '\\\\') {\n i += 1;\n continue;\n }\n if (after[i] === closer) return isMdBlank(after.slice(i + 1));\n }\n return false; // title still open at EOL\n}\n\n/**\n * micromark's link-destination grammar (micromark-factory-destination),\n * applied to a trimmed def rest. Returns the index just past the\n * destination, or -1 when micromark would REJECT it — the def line is then\n * a paragraph whose `[label]` stays a live shortcut ref. Two forms:\n * - `<…>`: any characters except line endings and UNESCAPED `<` / `>`\n * (whitespace is legal); unclosed at EOL → reject. `<>` is valid.\n * - bare: a non-empty run without whitespace or ASCII control characters;\n * unescaped parentheses must balance, and a `)` at balance zero ENDS\n * the destination (whatever follows must then be a title or nothing).\n * The old check accepted any `<…>` with a `>` somewhere and any bare run —\n * `[a]: <u<v>` / `[a]: /u(x` registered GHOST defs that released reference\n * taint early (2026-08 project-review P1; ghost defs are the unsafe\n * direction — see the def-registration comment in processConfirmedLine).\n */\nfunction linkDestinationEnd(t: string): number {\n if (t.startsWith('<')) {\n for (let i = 1; i < t.length; i++) {\n const ch = t[i];\n // `enclosedEscape`: a backslash only escapes `<`, `>`, `\\`; before\n // anything else it is a literal backslash and the next character is\n // judged on its own.\n if (ch === '\\\\' && (t[i + 1] === '<' || t[i + 1] === '>' || t[i + 1] === '\\\\')) {\n i += 1;\n continue;\n }\n if (ch === '>') return i + 1;\n if (ch === '<') return -1;\n }\n return -1; // unclosed angle destination\n }\n let balance = 0;\n let i = 0;\n for (; i < t.length; i++) {\n const code = t.charCodeAt(i);\n if (code === 0x20 || code === 0x09) break; // whitespace ends the run\n if (code < 0x20 || code === 0x7f) return -1; // ASCII control\n const ch = t[i];\n // `rawEscape`: only `(`, `)`, `\\` are escapable; `\\ ` is a literal\n // backslash followed by whitespace, which ENDS the run (review probe:\n // skipping any next char swallowed the space and registered a ghost).\n if (ch === '\\\\' && (t[i + 1] === '(' || t[i + 1] === ')' || t[i + 1] === '\\\\')) {\n i += 1;\n continue;\n }\n if (ch === '(') balance += 1;\n else if (ch === ')') {\n if (balance === 0) break; // ends the destination\n balance -= 1;\n }\n }\n if (balance !== 0 || i === 0) return -1;\n return i;\n}\n\n/**\n * micromark's inline-link resource grammar (`(` destination? title? `)`)\n * on ONE line, starting at the `(` at `openIdx`. Returns the index just past\n * the closing `)`, or -1 when the resource is malformed here — the bracket\n * text before it is then a live shortcut reference.\n */\nfunction inlineResourceEnd(text: string, openIdx: number): number {\n let i = openIdx + 1;\n const skipWs = () => {\n while (i < text.length && (text[i] === ' ' || text[i] === '\\t')) i += 1;\n };\n skipWs();\n if (text[i] === ')') return i + 1; // `()` — empty resource is valid\n const destEnd = linkDestinationEnd(text.slice(i));\n if (destEnd === -1) return -1;\n i += destEnd;\n const beforeWs = i;\n skipWs();\n if (text[i] === ')') return i + 1;\n if (i === beforeWs) return -1; // title must be whitespace-separated\n const opener = text[i];\n if (opener !== '\"' && opener !== \"'\" && opener !== '(') return -1;\n const closer = opener === '(' ? ')' : opener;\n for (i += 1; i < text.length; i++) {\n if (text[i] === '\\\\') {\n i += 1;\n continue;\n }\n if (text[i] === closer) {\n i += 1;\n skipWs();\n return text[i] === ')' ? i + 1 : -1;\n }\n }\n return -1; // title still open at EOL\n}\n\n/** The checkpoint's reference sub-state, as this module sees it — the\n * fields stay flat on `FreezeScanCheckpointInternal` (a pure move does\n * not reshape state); this view is the module's contract with them. */\nexport interface RefTaintView {\n defs: Map<string, number>;\n footnoteDefs: Map<string, number>;\n unresolvedRefs: UnresolvedRef[];\n openBracket: { offset: number; text: string } | null;\n referenceTaint: boolean;\n prevLineWasText: boolean;\n prevLineWasValidDef: boolean;\n lastBlankStart: number;\n}\n\nexport interface RefLineFacts {\n /** This line registered (or chained) a definition. */\n validDef: boolean;\n /** …and it was a LINK def (`prevLineWasValidDef` tracks only those). */\n validLinkDef: boolean;\n}\n\n// Blocker 5: definitions (block-start or def-chain only — A2) and refs.\n// Inside an html flow run a def-shaped line is RAW TEXT — micromark never\n// registers it. Registering a ghost def is the UNSAFE direction twice\n// over: it releases reference taint early AND makes the footnote replay\n// inject a definition the real parse does not have (fuzz-arbiter\n// counterexample). Refs stay extracted regardless: extra candidates only\n// over-taint.\nexport function collectRefLine(\n cp: RefTaintView,\n lnStart: number,\n lnEnd: number,\n scanText: string,\n inRawText: boolean,\n isBlockStart: boolean\n): RefLineFacts {\n const defShaped = inRawText ? null : DEF_RE.exec(scanText);\n // micromark requires a NON-EMPTY destination followed by nothing but an\n // optional TITLE for a link definition. A bare `[label]:` line, or one\n // with non-title garbage after the destination (`[x]: /u[x]: /u` — K=4\n // census counterexamples), is a PARAGRAPH whose `[label]` stays a live\n // shortcut ref that a LATER real def can retarget. Rejecting a real def\n // here only over-blocks (refs stay tainted); registering a ghost\n // under-blocks. Footnote defs legitimately have empty bodies.\n const def =\n defShaped !== null &&\n (defShaped[1].startsWith('^') || isPlausibleLinkDefRest(scanText.slice(defShaped.index + defShaped[0].length)))\n ? defShaped\n : null;\n const defLineStart = isBlockStart || !cp.prevLineWasText || cp.prevLineWasValidDef;\n const validDef = def !== null && defLineStart;\n if (validDef) {\n const label = def![1];\n if (label.startsWith('^')) {\n const key = normalizeLabel(label.slice(1));\n if (key && !cp.footnoteDefs.has(key)) cp.footnoteDefs.set(key, lnEnd);\n } else {\n const key = normalizeLabel(label);\n if (key && !cp.defs.has(key)) cp.defs.set(key, lnEnd);\n }\n }\n // Blocker 5 collection is skipped entirely under referenceTaint=false\n // (the def-label scanner profile): definition IDENTITY is a block-level\n // fact independent of how inline references resolve, and taint would\n // collapse the boundary to the body's first citation while a def footer\n // streams (defs settle only after a trailing blank line).\n if (cp.referenceTaint) {\n const pushRef = (offset: number, inner: string, followAt: number): void => {\n const follow = scanText[followAt];\n // `[text](…)` is an inline link only when the resource is WELL-FORMED\n // on this line; `[foo](bad url)` fails micromark's resource grammar\n // and `[foo]` falls back to a shortcut reference a later def can\n // retarget (adversarial review). A resource that continues on the\n // next line is unverifiable here → taint (over-block).\n if (follow === '(' && inlineResourceEnd(scanText, followAt) !== -1) return;\n let label: string;\n let footnote = false;\n if (inner.startsWith('^')) {\n footnote = true;\n label = normalizeLabel(inner.slice(1));\n } else if (follow === '[') {\n const explicit = /^\\[((?:[^[\\]\\\\]|\\\\.)*)\\]/.exec(scanText.slice(followAt));\n label = normalizeLabel(explicit && explicit[1] ? explicit[1] : inner);\n } else {\n // Shortcut reference candidate. Plain prose brackets (\"[sic]\") land\n // here too — a future definition COULD retarget them, so they count.\n label = normalizeLabel(inner);\n }\n if (label) cp.unresolvedRefs.push({ offset, label, footnote });\n };\n // A bracket left open on an earlier line of this paragraph: it closes\n // here (label = the joined text — micromark's label grammar allows soft\n // line breaks, and normalizeLabel folds them), stays open when this line\n // has no bracket at all, or dies when a NEW `[` comes first (a label\n // cannot contain an unescaped `[`; that `[` may itself pend below).\n const pending = cp.openBracket;\n cp.openBracket = null;\n if (pending) {\n const close = firstUnescaped(scanText, ']');\n const open = firstUnescaped(scanText, '[');\n // A continuation line inside a blockquote carries its `>` marker in\n // the source but not in micromark's label — strip it, or the joined\n // label (`foo > bar`) could never match its def and the taint would\n // never lift (adversarial review). Wrong-way stripping only over-taints.\n const cont = (t: string): string => t.replace(/^ {0,3}>[ \\t]?/, '');\n if (close !== -1 && (open === -1 || close < open)) {\n pushRef(pending.offset, `${pending.text}\\n${cont(scanText.slice(0, close))}`, close + 1);\n } else if (close === -1 && open === -1) {\n cp.openBracket = { offset: pending.offset, text: `${pending.text}\\n${cont(scanText)}` };\n }\n }\n if (scanText.includes('[')) {\n // `[label]:` is only definition-shaped when THIS line registers it as\n // a def (the label bracket of validDef). On a paragraph CONTINUATION\n // line the same bytes are literal text where micromark still parses\n // `[label]` as a shortcut reference — skipping it there under-taints\n // and lets a later definition retarget frozen output (fuzz\n // counterexample: a def line glued under a paragraph). Extra\n // candidates only over-taint.\n const defBracket = validDef ? def!.index + def![0].indexOf('[') : -1;\n REF_RE.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = REF_RE.exec(scanText)) !== null) {\n const followAt = m.index + m[0].length;\n if (scanText[followAt] === ':' && m.index === defBracket) continue; // the def's own label\n pushRef(lnStart + m.index, m[1], followAt);\n }\n // The LAST unescaped `[` with no `]` after it stays open into the next\n // paragraph line (a def line's own label never reaches here unclosed).\n const trailingOpen = lastUnclosedBracket(scanText);\n if (trailingOpen !== -1) {\n cp.openBracket = { offset: lnStart + trailingOpen, text: scanText.slice(trailingOpen + 1) };\n }\n }\n }\n return { validDef, validLinkDef: validDef && !def![1].startsWith('^') };\n}\n\n/** Settle references (monotone: entries only ever leave — a def counts\n * once a confirmed blank line follows it), then report the earliest still\n * unresolved ref offset (`Infinity` when none). */\nexport function settleRefsAndEarliestUnresolved(cp: RefTaintView): number {\n if (cp.unresolvedRefs.length > 0) {\n const settled = (defEnd: number): boolean => cp.lastBlankStart >= defEnd;\n cp.unresolvedRefs = cp.unresolvedRefs.filter((ref) => {\n const table = ref.footnote ? cp.footnoteDefs : cp.defs;\n const defEnd = table.get(ref.label);\n return defEnd === undefined || !settled(defEnd);\n });\n }\n let earliestUnresolved = Infinity;\n for (const ref of cp.unresolvedRefs) earliestUnresolved = Math.min(earliestUnresolved, ref.offset);\n return earliestUnresolved;\n}\n","/**\n * Pure splice helpers for incremental (prefix-freeze) parsing: cut the\n * frozen prefix out of the previous frame's trees, re-base a tail-only\n * parse into document coordinates, and join the two into fresh roots.\n *\n * Invariant these helpers exist to uphold (enforced by the\n * splice-equivalence arbiter test, NOT asserted at runtime): the spliced\n * `{mdast, hast}` is deep-equal — positions included — to a full pipeline\n * run over the whole content. Defined on UNRENDERED trees; after a render,\n * `renderHastSubtree` mutates hast in place (convergent `data.originalUrls`\n * stash, raw→text rewrite — see Markdown.tsx), so no in-component\n * deep-equal check is possible or attempted.\n *\n * Prefix link/image definitions are PREPENDED to the tail source (not\n * appended: a streaming tail routinely ends inside an unclosed fence or\n * `$$` block that would swallow appended lines, and appended defs would\n * invert CommonMark first-def-wins against a same-label tail def).\n * Definitions emit zero hast (mdast-util-to-hast has no `definition`\n * handler), so their only trace is `definition` mdast nodes inside the\n * injected region, which are dropped before the join. Definition text is\n * sliced verbatim from the previous content via node positions — exact\n * source roundtrip preserves escapes and multi-line titles.\n *\n * Sanitize-STRIPPED prefix nodes (HTML comments, `<?…?>` bogus comments,\n * `<script>`) are modeled explicitly: their wrap separators survive as\n * orphans, and `alignPrefixCut` re-derives the mdast↔hast pairing from\n * separator-run lengths (B0-probe-verified: one orphan '\\n' per stripped\n * child's gap slot; separators MERGED into raw trailing literals count via\n * their trailing newlines — `literalCredit`). Layouts outside the model\n * return null → full-parse fallback for the frame.\n */\n\nimport { normalizeIdentifier } from 'micromark-util-normalize-identifier';\nimport type { Root as HastRoot, RootContent as HastContent } from 'hast';\nimport type { Root as MdastRoot, RootContent as MdastContent } from 'mdast';\nimport type { Node as UnistNode, Position } from 'unist';\n\nimport { attributeHastChildren } from './attributeHastChildren';\n\n/** One injected footnote-definition block's coordinate mapping — footer\n * `<li>` content carries positions from the DEF node, so injected-copy\n * coordinates must be rewritten back to the original's (C0 probe). */\nexport interface InjectedSegment {\n injStart: number;\n injEnd: number;\n offsetDelta: number;\n lineDelta: number;\n}\n\n/** Prefix footnote/definition events in DOCUMENT ORDER. Order is the whole\n * point: mdast-util-to-hast's footnoteOrder/footnoteCounts are built from\n * encounter order, and the replay must reproduce it exactly. */\nexport type InjectionEvent =\n /** Link/image definition — parse-time resolution only, zero hast. */\n | { kind: 'def'; source: string }\n /** Footnote definition — sliced from the PHYSICAL LINE START (column\n * invariance for the footer position rebase). */\n | { kind: 'footnoteDef'; source: string; origStart: number; origLine: number }\n /** Consecutive footnote references, verbatim source tokens. Seeds\n * footnoteOrder (first-encounter) and footnoteCounts (backref -N ids). */\n | { kind: 'refs'; tokens: string[] };\n\nexport interface PrefixInjectionPlan {\n events: InjectionEvent[];\n /** True when an event exists that CANNOT be injected reliably — the caller\n * must fall back to a full parse for this frame (safe, one-frame cost). */\n uninjectable: boolean;\n /** False when the plan must NOT be cached for resume: a position-less\n * top-level child cannot be partitioned by the resume offset, so a\n * resumed walk would re-visit it and duplicate its events (round-2\n * review). Fresh walks stay correct — they just can't be incremental. */\n cacheable?: boolean;\n}\n\n/** A plan cached in engine state: valid for any LATER boundary of the same\n * append lineage, because events derive from (content, positions) alone\n * and the boundary is monotone under appends — new frames only APPEND\n * events for children in [cached.boundary, newBoundary). */\nexport interface CachedInjectionPlan extends PrefixInjectionPlan {\n boundary: number;\n}\n\n/** Collect the prefix's injectable events (document order).\n *\n * Walks the FULL subtree, not just top-level children: definitions nested\n * inside blockquotes/lists are document-scoped in CommonMark\n * (probe-confirmed A3 — a `> [a]: /url` def must resolve a later tail\n * ref). A nested link definition's position starts at its own `[`, so a\n * single-line slice is a valid standalone def line; a MULTI-LINE nested\n * slice would drag `> ` container prefixes into the injection text, so it\n * is flagged uninjectable instead (full-parse fallback).\n *\n * Footnote definitions must be sliced from their physical line start (the\n * footer position rebase requires column invariance), so ANY nested\n * footnote def is uninjectable — the line-start slice would drag the `> `\n * container prefix in, and a node-start slice would shift columns.\n *\n * footnoteDefinition subtrees are NOT descended: refs inside a def body are\n * counted at FOOTER time (state.all over the stored def node), and the\n * injected def text replays them there; emitting them as inline events\n * would double-count.\n */\nexport function collectPrefixInjection(\n mdast: MdastRoot,\n content: string,\n boundary: number,\n resume?: CachedInjectionPlan | null\n): PrefixInjectionPlan {\n // Resume path (final-review R3): the frozen prefix is byte-identical\n // frame to frame, so a cached plan only needs the children in\n // [resume.boundary, boundary) appended — without this the deep visit\n // re-walks the ENTIRE prefix every splice frame (the collectDefLabels\n // O(stream²) shape). Boundary validity gates EVERYTHING resumed —\n // including the sticky-uninjectable short-circuit: the boundary is\n // monotone within an append lineage today, but a regressed cache must\n // degrade to a fresh walk, never to a stale verdict (round-2 review).\n const resumeValid = resume != null && resume.boundary <= boundary;\n // `uninjectable` is sticky: the offending node stays in the prefix for\n // the lineage's lifetime.\n if (resumeValid && resume!.uninjectable) return { events: resume!.events, uninjectable: true };\n const resumeAt = resumeValid ? resume!.boundary : 0;\n const events: InjectionEvent[] = resumeAt > 0 ? cloneEventsForAppend(resume!.events) : [];\n let uninjectable = false;\n let cacheable = true;\n const pushRef = (token: string): void => {\n const last = events[events.length - 1];\n if (last && last.kind === 'refs') last.tokens.push(token);\n else events.push({ kind: 'refs', tokens: [token] });\n };\n const visit = (node: UnistNode, nested: boolean): void => {\n const type = (node as { type?: string }).type;\n if (type === 'definition') {\n const start = node.position?.start?.offset;\n const end = node.position?.end?.offset;\n if (start !== undefined && end !== undefined && start < boundary) {\n const slice = content.slice(start, end);\n if (nested && slice.includes('\\n')) uninjectable = true;\n else events.push({ kind: 'def', source: slice });\n }\n return;\n }\n if (type === 'footnoteDefinition') {\n const start = node.position?.start;\n const end = node.position?.end?.offset;\n if (start?.offset === undefined || end === undefined || start.offset >= boundary) return;\n if (nested) {\n uninjectable = true;\n return;\n }\n const lineStart = start.offset - (start.column - 1);\n events.push({\n kind: 'footnoteDef',\n source: content.slice(lineStart, end),\n origStart: lineStart,\n origLine: start.line,\n });\n return; // body refs replay at footer time via the injected text\n }\n if (type === 'footnoteReference') {\n const start = node.position?.start?.offset;\n const end = node.position?.end?.offset;\n if (start === undefined || end === undefined) {\n uninjectable = true; // cannot reproduce the token verbatim\n return;\n }\n pushRef(content.slice(start, end));\n return;\n }\n const children = (node as TreeWithChildren).children;\n if (children) {\n for (const child of children) visit(child, true);\n }\n };\n // Top-level children are position-ordered with the shipped chain, and the\n // event stream assumes it. A plugin-shaped tree that reorders top-level\n // nodes must not produce a WRONG plan: an early break at the boundary\n // would silently skip a def that sits after a later-positioned sibling,\n // so the walk uses filter semantics (every child is inspected, only those\n // in [resumeAt, boundary) are visited) and flags any disorder as\n // uninjectable (full-parse fallback) — the cut layer's correct-or-bailing\n // promise for the same threat model (2026-08 project review, eng-parse-07).\n let lastStart = -1;\n for (const child of mdast.children) {\n // Nothing at or past the boundary can contribute a prefix event (E5),\n // and nothing before the resume point needs re-visiting.\n const start = child.position?.start?.offset;\n if (start !== undefined) {\n if (start < lastStart) return { events: [], uninjectable: true, cacheable: false };\n lastStart = start;\n }\n if (start === undefined) {\n // A position-less top-level child cannot be partitioned by offset: a\n // resumed walk would re-visit it and DUPLICATE its cached events.\n // Restart fresh once (correct by construction) and mark the plan\n // uncacheable. Unreachable with the shipped chain (the parser\n // positions every top-level node); defense for plugin-shaped trees.\n if (resumeAt > 0) return collectPrefixInjection(mdast, content, boundary, null);\n cacheable = false;\n visit(child, false);\n continue;\n }\n if (start >= boundary || start < resumeAt) continue;\n visit(child, false);\n }\n return { events, uninjectable, cacheable };\n}\n\n/** Cached plans are shared with the previous state — clone the array, and\n * the trailing refs event too (pushRef mutates its token list when the new\n * region opens with another reference). */\nfunction cloneEventsForAppend(events: InjectionEvent[]): InjectionEvent[] {\n const out = events.slice();\n const last = out[out.length - 1];\n if (last && last.kind === 'refs') out[out.length - 1] = { kind: 'refs', tokens: last.tokens.slice() };\n return out;\n}\n\nexport interface InjectionPrefix {\n text: string;\n segments: InjectedSegment[];\n}\n\n/** The injection TERMINATOR: a sentinel link-definition block appended after\n * the last event. The detector's blockers prove the REAL prefix is inert\n * toward the tail — but the injection text itself introduces continuation\n * context the real prefix did not have (final-review R1, probe-confirmed):\n *\n * - a trailing footnote-def event's body continues across blank lines into\n * any >=4-indented tail line, swallowing real content into a node the\n * splice then strips;\n * - with the definition-list extension, a tail-leading `: desc` separated\n * from the ORIGINAL prefix by two blank lines (claim-immune) sits only\n * ONE '\\n\\n' from the last injected block and would claim it as a <dt>.\n *\n * A column-0 link definition neutralizes both: it terminates a footnote\n * body (not >=4-indented), cannot be claimed as a <dt> (not a paragraph),\n * emits zero hast and zero wrap-separator slots, and is stripped with the\n * rest of the injected region.\n *\n * Unlike the phantom sentinel URLs (values — they can never change parse\n * SHAPE), a definition LABEL is resolvable by any `[label]` mention, so a\n * document that literally writes the sentinel label would have its tail\n * mentions resolve against the terminator (round-2 review, probe-\n * confirmed). {@link tailMentionsTerminator} closes that structurally:\n * such frames take the full path instead of splicing. */\nconst TERMINATOR_LABEL = '__aimd_injection_terminator__';\nconst INJECTION_TERMINATOR = `[${TERMINATOR_LABEL}]: __aimd_sentinel_link__`;\n\n/** True when the tail input could REFERENCE the terminator's label — the\n * one input class where the splice's synthetic definition would change how\n * the tail parses. Prefix mentions need no check: an unresolved mention is\n * reference-tainted (pinned into the tail), and a resolved one has a real\n * def that wins first-def-wins over the terminator. */\nexport function tailMentionsTerminator(tailSource: string): boolean {\n // micromark matches labels after `normalizeIdentifier` (whitespace\n // collapse + Unicode case fold), so `[__AIMD_INJECTION_TERMINATOR__]` — or\n // a dotless-ı variant — resolves against the lowercase terminator def just\n // the same. Compare in the same normal form (2026-08 project review,\n // eng-parse-04: a byte-exact `includes` let case variants through).\n // Whitespace right after `[` is trimmed by micromark's label matching\n // too (`[ __aimd_…]` resolves) — collapse it before the check (v2.4.0\n // review P5).\n return normalizeIdentifier(tailSource)\n .replace(/\\[ /g, '[')\n .includes(`[${normalizeIdentifier(TERMINATOR_LABEL)}`);\n}\n\n/** Build the injection text prepended to the tail source (with per-footnote-\n * def coordinate segments). Blocks are '\\n\\n'-joined: a def line directly\n * after a ref paragraph would be a paragraph CONTINUATION (A2, literal\n * text), and anything unindented after a footnote def line would join its\n * body. */\nexport function buildInjectionPrefix(events: InjectionEvent[]): InjectionPrefix {\n if (events.length === 0) return { text: '', segments: [] };\n let text = '';\n // Rolling line number of the text end — recounting the accumulated text\n // per event would be O(events × textLength) (final-review R3).\n let line = 1;\n const segments: InjectedSegment[] = [];\n for (const event of events) {\n if (text.length > 0) {\n text += '\\n\\n';\n line += 2;\n }\n const injStart = text.length;\n const source = event.kind === 'refs' ? event.tokens.join(' ') : event.source;\n if (event.kind === 'footnoteDef') {\n segments.push({\n injStart,\n injEnd: injStart + source.length,\n offsetDelta: event.origStart - injStart,\n lineDelta: event.origLine - line,\n });\n }\n text += source;\n line += countNewlines(source);\n }\n return { text: `${text}\\n\\n${INJECTION_TERMINATOR}\\n\\n`, segments };\n}\n\ninterface TreeWithChildren extends UnistNode {\n children?: UnistNode[];\n}\n\n/**\n * Shift every position in the subtree from tail-parse coordinates into\n * document coordinates. Tolerates position-less subtrees (KaTeX output).\n * Mutates in place — callers only pass freshly-parsed tail trees.\n */\nexport function rebaseTree(node: UnistNode, offsetDelta: number, lineDelta: number): void {\n // Exactly rebaseTreeDual with no segments (find never matches) — one\n // implementation, two names for the two call sites' semantics.\n rebaseTreeDual(node, EMPTY_SEGMENTS, offsetDelta, lineDelta);\n}\n\nconst EMPTY_SEGMENTS: InjectedSegment[] = [];\n\n/**\n * Dual-rule position rebase for the tail HAST (C0-probe-verified): the\n * footer's `<li>` content carries positions from footnoteById's DEF nodes —\n * for INJECTED defs those are injection coordinates (per-segment mapping),\n * while tail-native nodes (inline content and tail-defined footnotes) take\n * the ordinary tail shift. Dispatch is per POINT with CLOSED segment bounds:\n * END offsets are exclusive, so a node ending exactly at a segment's last\n * byte has offset === injEnd (segments are '\\n\\n'-separated — unambiguous).\n * Column is invariant under both rules (defs are sliced from line start).\n */\nexport function rebaseTreeDual(\n node: UnistNode,\n segments: InjectedSegment[],\n offsetDelta: number,\n lineDelta: number\n): void {\n // Segments live entirely inside the injection prefix; after the injected\n // region is stripped, ~every remaining point sits past them all. One\n // bound check replaces an always-failing O(segments) scan per point\n // (final-review R3).\n const maxEnd = segments.length > 0 ? segments[segments.length - 1].injEnd : -1;\n rebaseDualWalk(node, segments, maxEnd, offsetDelta, lineDelta);\n}\n\nfunction rebaseDualWalk(\n node: UnistNode,\n segments: InjectedSegment[],\n maxEnd: number,\n offsetDelta: number,\n lineDelta: number\n): void {\n const position = node.position as Position | undefined;\n if (position) {\n for (const point of [position.start, position.end]) {\n // Plugin-shaped trees (a consumer's own remark/rehype plugin emitting\n // `{ position: {} }` or a half-built point) reached this walk and threw\n // `Cannot read properties of undefined (reading 'offset')` out of the\n // render path — every other splice defence against such trees bails;\n // this one tolerates, like its \"position-less subtrees\" contract says.\n if (!point) continue;\n const seg =\n point.offset !== undefined && point.offset <= maxEnd\n ? segments.find((s) => point.offset! >= s.injStart && point.offset! <= s.injEnd)\n : undefined;\n if (seg) {\n point.offset! += seg.offsetDelta;\n if (typeof point.line === 'number') point.line += seg.lineDelta;\n } else {\n if (point.offset !== undefined) point.offset += offsetDelta;\n if (typeof point.line === 'number') point.line += lineDelta;\n }\n }\n }\n const children = (node as TreeWithChildren).children;\n if (children) {\n for (const child of children) rebaseDualWalk(child, segments, maxEnd, offsetDelta, lineDelta);\n }\n}\n\nexport interface SpliceInput {\n prevMdast: MdastRoot;\n prevHast: HastRoot;\n /** Tail trees, freshly parsed from `injectionPrefix + content.slice(boundary)`. */\n tailMdast: MdastRoot;\n tailHast: HastRoot;\n content: string;\n boundary: number;\n injectionPrefix: string;\n /** Coordinate mappings for injected footnote-def blocks (footer rebase). */\n injectedSegments: InjectedSegment[];\n}\n\n/**\n * Cut the frozen prefix from the previous trees, drop injected-def nodes\n * from the tail, re-base the tail, synthesize the root-level `'\\n'` seam\n * separator (mdast-util-to-hast's `wrap()` inserts one strictly BETWEEN\n * root children — the full parse has it at the prefix/tail junction, the\n * tail-only parse does not), and join into fresh root objects. Fresh roots\n * every frame keep blockMemo's node-identity assumptions intact while\n * never mutating the previous frame's roots.\n */\n/** Table-part START tags whose appearance outside a table re-routes parse5's\n * tree construction for the rest of the document. */\nconst TABLE_PART_TAG_RE = /<(?:td|th|tr|tbody|thead|tfoot|caption|col|colgroup)\\b/i;\n/** Same scan, but positioned: `<table>` / `</table>` and every table part in\n * one raw-HTML value, in order. */\nconst TABLE_TOKEN_RE = /<(\\/?)(table|td|th|tr|tbody|thead|tfoot|caption|col|colgroup)\\b/gi;\n\n/**\n * Does any table part in `values` sit OUTSIDE a table? Only those re-route\n * parse5; a well-formed `<table><tr><td>a</td></tr></table>` does not, and\n * bailing on it cost every later frame a full parse (2026-08-20 B1 — the\n * scanner's TABLE_PART_NAMES poison had the same gap; keep the two in step).\n *\n * Depth runs across the whole sequence because `hast-util-raw` feeds every\n * raw value to ONE parse5 instance: a `<table>` opened in one html node is\n * still open in the next. Unbalanced `</table>` clamps at zero rather than\n * going negative, so a stray close cannot mask a later stray part.\n */\nfunction hasStrayTablePart(values: Iterable<string>): boolean {\n let depth = 0;\n for (const value of values) {\n TABLE_TOKEN_RE.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = TABLE_TOKEN_RE.exec(value)) !== null) {\n const closing = m[1] === '/';\n const tag = m[2].toLowerCase();\n if (tag === 'table') {\n depth = closing ? Math.max(0, depth - 1) : depth + 1;\n continue;\n }\n if (depth === 0) return true;\n }\n }\n return false;\n}\n/** `startTagInTemplate` routes these names to \"in head\" WITHOUT first popping\n * the template insertion mode — unlike every other start tag, which pops,\n * pushes \"in body\" and REPROCESSES. So when one of them opens a raw-text\n * region, `originalInsertionMode` is captured as IN_TEMPLATE in a tail-only\n * parse and as IN_BODY in the full one. On the first stray end tag parse5\n * leaves TEXT mode and RESTORES that captured mode, and from there the two\n * parses dispatch differently: `</p>` synthesizes an empty paragraph in\n * \"in body\" and is ignored in \"in template\".\n *\n * `a\\n\\n<title>\\n\\n*b*\\n` — sixteen bytes — was a live under-block:\n * boundary 3, and the full parse has an empty `<p>` the spliced tree lacks.\n * Same for `<noframes>`, and for `<script>` when the double-escape keeps the\n * raw-text region open past its apparent closer.\n *\n * `textarea`/`iframe`/`noembed`/`xmp` take the default branch, pop first and\n * capture the CONVERGED mode — measured safe, and left alone. */\nconst HEAD_ROUTED_NAMES = new Set([\n 'base',\n 'basefont',\n 'bgsound',\n 'link',\n 'meta',\n 'noframes',\n 'script',\n 'style',\n 'template',\n 'title',\n]);\n/** The head-routed names that open a raw-text region (RCDATA / RAWTEXT /\n * script data) — the ones whose capture becomes observable. */\nconst HEAD_ROUTED_RAW_TEXT_RE = /<(script|style|title|noframes)(?=[\\s/>])/i;\nconst ANY_START_TAG_RE = /<([a-z][a-z0-9-]*)(?=[\\s/>])/gi;\n\n/** True when the tail's leading html run opens one of those regions with the\n * template mode still uncaptured, and does not honestly close it inside the\n * run. The closer must be inside the RUN, not the child: `<title>` block,\n * blank line, `</title>` block closes it and is measured safe. */\nfunction headRoutedCaptureUnclosed(values: readonly string[]): boolean {\n if (values.length === 0) return false;\n const joined = values.join('\\n');\n const opener = HEAD_ROUTED_RAW_TEXT_RE.exec(joined);\n if (opener === null) return false;\n // Any NON-head-routed start tag before the opener already popped the\n // template mode, so both parses captured the same one and this is safe.\n // Deciding that needs to know which `<…>` are markup, and a raw construct\n // makes that undecidable by regex: parse5 ends a bogus comment at the FIRST\n // `>`, so whether the `<div>` in `<![CDATA[<div>data</div>]]>` is a start\n // tag depends on where that `>` landed. Refuse to conclude convergence at\n // all when one is present — over-blocks, and the alternative was a live\n // under-block (fuzz seed 20270403, a CDATA between the comment and the\n // `<title>`).\n const before = joined.slice(0, opener.index);\n if (/<[!?]/.test(before)) return true;\n ANY_START_TAG_RE.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = ANY_START_TAG_RE.exec(before)) !== null) {\n if (!HEAD_ROUTED_NAMES.has(m[1].toLowerCase())) return false;\n }\n const name = opener[1].toLowerCase();\n const after = joined.slice(opener.index + opener[0].length);\n if (name === 'script') {\n const close = after.search(/<\\/script(?=[\\s/>])/i);\n // No closer, or a `<!--` before it: the escape states may keep the region\n // open past that tag, so the capture is still live. Over-blocks the\n // `<!-- … --> </script>` re-exit case, knowingly.\n return close === -1 || /<!--/.test(after.slice(0, close));\n }\n return !new RegExp(`</${name}(?=[\\\\s/>])`, 'i').test(after);\n}\n\n/** The two END tags HTML synthesizes (`<br>` / empty `<p>`) instead of dropping. */\nconst STRAY_SYNTHESIZED_END_TAG_RE = /<\\/(?:br|p)\\b/i;\n\n/** parse5 raw-text elements (RAWTEXT / RCDATA / script data / plaintext),\n * matching the scanner's RAW_TEXT_ELEMENTS (`noscript` excluded —\n * scriptingEnabled: false). */\nconst RAW_TEXT_OPEN_RE = /<(script|style|textarea|title|xmp|iframe|noembed|noframes|plaintext)(?=[\\s/>])/gi;\n\n/**\n * Does any frozen html block leave a parse5 raw-text REGION open at its own\n * end? Then the element crosses OUT of its micromark block — the wrap\n * separator between that block and the next becomes element text (stripped\n * with a `<script>`, swallowed into content otherwise), and the\n * separator-credit model below double-counts the gap (P3b batch 1's\n * measured counterexample: the F6 recovery granted boundary 60 on the\n * double-escape document and the spliced frame carried an extra root\n * `\"\\n\"`). The scanner deliberately RELEASES such prefixes once the\n * element truly closes (the retired poison); the splice refuses them\n * instead — the system contract is scanner boundary PLUS splice guards.\n *\n * Script regions honour the escape ladder the way the scanner does: a\n * `<!--` with no `-->` before the apparent `</script>` keeps the region\n * open past it (double-escape may be live — over-refuses the harmless\n * single-escaped case where no nested `<script` follows, knowingly).\n * Openers inside comments or quoted attribute values over-match — every\n * false positive only refuses a splice (full-parse fallback).\n */\nfunction rawTextRegionCrossesOut(values: Iterable<string>): boolean {\n for (const value of values) {\n let pos = 0;\n for (;;) {\n RAW_TEXT_OPEN_RE.lastIndex = pos;\n const open = RAW_TEXT_OPEN_RE.exec(value);\n if (open === null) break;\n const name = open[1].toLowerCase();\n const bodyStart = open.index + open[0].length;\n const closeRe = new RegExp(`</${name}(?=[\\\\s/>])`, 'ig');\n closeRe.lastIndex = bodyStart;\n let close = closeRe.exec(value);\n if (name === 'script') {\n // Skip closers still inside a live escape: `<!--` before the\n // closer with no `-->` between them.\n while (close !== null) {\n const body = value.slice(bodyStart, close.index);\n const lastOpen = body.lastIndexOf('<!--');\n if (lastOpen === -1 || body.indexOf('-->', lastOpen + 4) !== -1) break;\n close = closeRe.exec(value);\n }\n }\n if (close === null) return true;\n pos = close.index + close[0].length;\n }\n }\n return false;\n}\n\nexport function spliceTrees(input: SpliceInput): { mdast: MdastRoot; hast: HastRoot } | null {\n const { prevMdast, prevHast, tailMdast, tailHast, content, boundary, injectionPrefix, injectedSegments } = input;\n\n const injectedLen = injectionPrefix.length;\n const injectedLines = countNewlines(injectionPrefix);\n // Bounded count — slicing the prefix would allocate a copy of the whole\n // frozen document every frame just to count newlines (final-review R3).\n const prefixLines = countNewlines(content, boundary);\n const offsetDelta = boundary - injectedLen;\n const lineDelta = prefixLines - injectedLines;\n\n // --- prefix cuts (non-mutating reads of the previous frame's trees) ---\n // Filter semantics (no ordered-children early break): together with G4's\n // full straddle scan this keeps the cut correct-or-bailing even for\n // disordered trees a plugin-shaped mdast could present (round-2 review).\n const prefixMdast: MdastContent[] = [];\n for (const child of prevMdast.children) {\n const start = child.position?.start?.offset;\n if (start !== undefined && start < boundary) prefixMdast.push(child);\n }\n const attrs = attributeHastChildren(prevMdast, prevHast, boundary);\n const cutRegion: HastContent[] = [];\n for (let i = 0; i < prevHast.children.length; i++) {\n if (attrs[i] < boundary) {\n const node = prevHast.children[i];\n // HAST STRADDLE BAIL (campaign, 2026-08-03): an mdast-clean boundary\n // does not imply a hast-clean one — parse5's tree construction can\n // hoist an unclosed inline element (`<details>` open tag in a frozen\n // paragraph) to the root, where it swallows every later sibling. The\n // frozen subtree then CONTAINS tail bytes, and the tail re-parse\n // duplicates them (seed-20260751 counterexample). A positioned cut\n // child whose source extends past the boundary is exactly that shape.\n const end = node.position?.end?.offset;\n if (end !== undefined && end > boundary) return null;\n // A position-less CONTENT text is only attributable when it directly\n // follows a positioned element — its owner (parse5 merges adjacent\n // texts, so one block never emits two literal nodes). One that\n // follows another text is a stripped-construct remnant whose owner\n // may live PAST the boundary (`<?instr <b> ?>` → ` ?>`, seed-20260830:\n // attribution stalls on the last positioned child and pulled the\n // CURRENT TAIL's remnant into the cut, duplicating it). Ownership is\n // undecidable here — bail to a full parse.\n if (isTrailingLiteralText(node)) {\n const prev = i > 0 ? prevHast.children[i - 1] : undefined;\n if (!prev || prev.type !== 'element' || prev.position === undefined) return null;\n // …and it must be that element's OWN trailing literal (its html\n // block's source ends with the text). Attribution can hand a\n // following dropped-tag block's remnant (`[a]: def\\n\\n</t>\\ntext`)\n // an offset before the boundary — the def between them has no\n // output — and freezing it duplicated it (release soak).\n if (!ownsTrailingLiteral(prev as HastContent, node as HastContent & { value: string }, prefixMdast))\n return null;\n }\n cutRegion.push(node);\n continue;\n }\n // Raw trailing literal of a frozen html block (fuzz counterexample):\n // `</tag>` followed by an unblanked text line makes rehype-raw emit the\n // line as a POSITION-LESS non-whitespace text after the element. Being\n // position-less it is attributed FORWARD (to the first tail block), but\n // its bytes live before the boundary — it must freeze with its owner,\n // the preceding included node. Whitespace-only texts stay excluded:\n // those are separators/foster-hoist, owned by the model below.\n //\n // OWNERSHIP is element-adjacency (seed-20260830 regression, exposed by\n // removing the coarse tail bail): a real trailing literal always sits\n // DIRECTLY after its owner's element output — parse5 merges adjacent\n // texts, so one block never emits two literal nodes. A position-less\n // non-whitespace text after a TEXT node is the current tail's own\n // stripped-construct remnant (`<?instr <b> ?>` → ` ?>`), which the tail\n // re-parse reproduces — freezing it would duplicate it.\n const node = prevHast.children[i];\n if (\n i > 0 &&\n attrs[i - 1] < boundary &&\n prevHast.children[i - 1].type === 'element' &&\n isTrailingLiteralText(node) &&\n // …and only when that element really IS an html block's output: a\n // raw literal can only trail an `html` mdast node. A position-less\n // text after a `<p>` is the NEXT block's remnant — a stray end tag\n // (`</t>\\na`) parse5 dropped, whose text merged with the wrap\n // separator — owned by the tail, which re-parses it; freezing it\n // here duplicated it (v2.4.0 review P3). Falls through to the\n // remnant look-ahead below, which bails to a full parse. And the\n // literal must really be THAT block's trailing text: the block's raw\n // source ends with it. A dropped-tag block right after a frozen html\n // element (`</details>\\n\\n</t>\\ntext`) puts its remnant in the same\n // position, and freezing it duplicated it (release soak of the fix).\n ownsTrailingLiteral(prevHast.children[i - 1] as HastContent, node as HastContent & { value: string }, prefixMdast)\n ) {\n cutRegion.push(node);\n // NOTE: this break skips the remnant look-ahead below. Safe today\n // because a frozen stripped construct AFTER a pushed trailing\n // literal always leaves an orphan separator that alignPrefixCut's\n // block-final branch rejects via `trailingGaps > 0 || sepBuffer` —\n // a NON-LOCAL invariant: loosening that bail re-opens the swallow\n // through this path (final-review cross-reference).\n break;\n }\n // Stripped-construct remnant look-ahead (seeds 20260821/20260893): a\n // position-less NON-whitespace text in the run right past the cut\n // point is a stripped construct's remnant, and its owner carries no\n // position. If the owner is fully FROZEN, the tail re-parse cannot\n // reproduce the text and the model below would synthesize its gap\n // slot as a plain '\\n' — swallowing it (`<?instr <b> ?> after the pi`\n // froze three blocks back; sanitize stripped the bogus comment and\n // left ` ?> after the pi\\n` behind). If tail-owned, freezing it here\n // would duplicate it. Ownership is undecidable — bail to a full\n // parse. The scan stops at the first element or positioned node:\n // remnants further out belong to blocks the tail re-parses anyway.\n for (let j = i; j < prevHast.children.length; j++) {\n const look = prevHast.children[j];\n if (look.type === 'element' || look.position !== undefined) break;\n if (isTrailingLiteralText(look)) return null;\n }\n break;\n }\n\n // wrap() emits separators per mdast-child ADJACENCY, before sanitize\n // strips anything — so the seam's existence is decided by the tail's\n // post-transform MDAST (excluding wrap-invisible types, which produce no\n // to-hast output), not by whether the tail hast ends up non-empty.\n // (Learned from the arbiter: a sanitize-removed comment leaves its\n // separator behind.)\n //\n // ALL injected nodes are dropped from the tail mdast — wrap-invisible\n // defs (v1) and the replay's footnote-ref paragraphs alike; non-injected\n // children can never start before injectedLen.\n const tailMdastChildren = tailMdast.children.filter((child) => {\n const start = child.position?.start?.offset;\n return !(start !== undefined && start < injectedLen);\n });\n const tailWrapVisible = tailMdastChildren.some((child) => !isWrapInvisible(child));\n\n // parse5 tree-construction quirks that poison the WHOLE document, not one\n // seam (v2.4.2 review P1-1/P1-2 + its adversarial follow-up):\n // - a stray table-part tag (`<td>`, `<tr>`, `<col>` …) outside any table\n // changes how every LATER GFM table is built (its cell text is\n // foster-parented to the root in the full parse; a tail-only parse\n // builds a real <table>) — once such a tag sits in the frozen prefix,\n // no later splice is trustworthy;\n // - the tail-only parse opens in a mode where a stray `</br>` / `</p>` (the\n // two end tags HTML synthesizes instead of dropping) and table parts\n // are DROPPED until the first element start tag switches it to body,\n // while the full parse — already in body — synthesizes / foster-parents\n // them. Any such tag inside the tail's LEADING run of html blocks\n // (comments / PIs / declarations do not switch the mode) → bail.\n const prefixHtmlValues = prefixMdast.flatMap((c) => (c.type === 'html' ? [c.value] : []));\n if (hasStrayTablePart(prefixHtmlValues)) return null;\n if (rawTextRegionCrossesOut(prefixHtmlValues)) return null;\n const leadingHtml: string[] = [];\n for (const child of tailMdastChildren) {\n if (isWrapInvisible(child)) continue;\n if (child.type !== 'html') break;\n if (STRAY_SYNTHESIZED_END_TAG_RE.test(child.value) || TABLE_PART_TAG_RE.test(child.value)) return null;\n leadingHtml.push(child.value);\n }\n // …and the same case analysis for the head-routed raw-text names, whose\n // mode capture the comment above missed: they are precisely the start tags\n // that do NOT switch the mode to body.\n if (headRoutedCaptureUnclosed(leadingHtml)) return null;\n\n // Align the cut region against the prefix mdast (stripped-node aware) and\n // rebuild its trailing separators. Bails null on any layout the model\n // does not cover — the caller falls back to a full parse for the frame.\n const aligned = alignPrefixCut(prefixMdast, cutRegion, tailWrapVisible);\n if (aligned === null) return null;\n const hastChildren = aligned.children;\n const interiorFinalLiteral = aligned.interiorFinalLiteral;\n\n // --- tail: strip the injected region's hast, then re-base ---\n const stripResult = stripInjectedHast(tailMdast, tailHast, injectedLen, tailWrapVisible);\n if (stripResult === null) return null;\n const strippedTailHast = stripResult.rest;\n for (const child of tailMdastChildren) rebaseTree(child, offsetDelta, lineDelta);\n for (const child of strippedTailHast) rebaseTreeDual(child, injectedSegments, offsetDelta, lineDelta);\n\n // --- join ---\n //\n // Seam anatomy (all learned from the arbiter, not theory):\n // - Pre-raw, wrap() puts exactly ONE '\\n' text node between any two root\n // children — including between the last frozen block and the first\n // tail block; `alignPrefixCut` has already synthesized it (plus one per\n // trailing stripped-child gap) as plain '\\n' nodes.\n // - rehype-raw's reserialize+reparse HOISTS whitespace-only text out of\n // table internals to just BEFORE the <table> (parse5 foster-parenting),\n // then merges it with the adjacent separator into one multi-'\\n' text\n // node. That run is TAIL-derived and grows with the table — it must\n // come from the tail parse (which reproduces it as leading text), not\n // from the previous frame's tree. Joining therefore MERGES the seam\n // separator with the tail's leading text, exactly like the reparse\n // would — but ONLY when they were literally adjacent in the serialized\n // HTML. A tail whose first wrap-visible child was sanitize-STRIPPED\n // (leading comment) emits its leading text as a gap SLOT that the full\n // parse keeps as a separate node (the comment sat between them at\n // reparse time), so merging would be wrong there.\n const mdastChildren = prefixMdast.concat(tailMdastChildren);\n // Layout-driven verdict when the injection gap proved it (see\n // stripInjectedHast docs); the classification covers uninjected tails and\n // bails to a full parse when the seam is genuinely ambiguous.\n const seamMergeVerdict = stripResult.remnantMerged ?? tailLeadingTextIsHoist(tailMdastChildren, strippedTailHast);\n if (seamMergeVerdict === null) return null;\n const seamMergeAllowed = seamMergeVerdict;\n let firstTailChild = true;\n for (const child of strippedTailHast) {\n const tailEnd = hastChildren[hastChildren.length - 1];\n if (firstTailChild && child.type === 'text' && child.position !== undefined) {\n // The tail LEADS with a positioned bare text — a raw literal whose\n // preceding construct vanished at the tokenizer (stray end tag's\n // trailing spaces, deep-soak counterexample). A full parse merges it\n // into the seam separator (or keeps it apart when the vanished thing\n // was sanitize-stripped) — classifying which means modeling the\n // tokenizer. Bail to a full parse.\n return null;\n }\n if (firstTailChild && tailEnd && tailEnd.type === 'text' && child.type === 'text' && child.position === undefined) {\n // Interior-literal gate (seed-20260838, join side): when the cut\n // ends in an INTERIOR raw literal (classified by alignPrefixCut —\n // its stripped following sibling kept it un-merged at reparse\n // time), the full parse keeps it verbatim with a SEPARATE\n // separator after it, never merged. Push the tail child as its own\n // node; a hoist-merge verdict against it is out of model — bail.\n // Block-final positioned literals do NOT take this path: the full\n // parse merges them with the seam separator exactly like the\n // position-less artifacts this branch models.\n if (interiorFinalLiteral && tailEnd.value.trim() !== '') {\n if (seamMergeAllowed) return null;\n firstTailChild = false;\n hastChildren.push(child);\n continue;\n }\n // A trailing html-block literal absorbs adjacent tail text the same\n // way (footer separator of an all-invisible tail — no wrap slot sat\n // between them at reparse time), and the merge drops the source\n // position, matching hast-util-raw's merged-text output.\n const literalSeam = tailEnd.value.trim() !== '' && !tailWrapVisible;\n if (seamMergeAllowed || literalSeam) {\n // Adjacent text at the seam — the full parse would have merged\n // these during rehype-raw's reparse. Replace (don't mutate) the\n // seam node: it may be a reference into the previous frame's tree.\n hastChildren[hastChildren.length - 1] = { type: 'text', value: tailEnd.value + child.value };\n firstTailChild = false;\n continue;\n }\n }\n firstTailChild = false;\n hastChildren.push(child);\n }\n\n // No POSITIONED top-level output → bail (fuzz + exhaustive-sweep\n // finding). hast-util-raw anchors the rebuilt root's position on its\n // positioned output nodes: a sanitize-stripped comment still anchored it\n // (positioned pre-sanitize), while a defs-only doc, a tokenizer-dropped\n // `<?…` opener, or a stray `</d>` end tag (dropped, leaving only a bare\n // position-less wrap separator behind) do not — and removeComments\n // shifts the comment case across that line. Reconstructing the verdict\n // for position-less-only output means re-modeling the parse5 tokenizer\n // per child; such frames are tiny by construction, so a full parse costs\n // nothing.\n if (!hastChildren.some((child) => child.position !== undefined)) return null;\n\n // Root positions must match a full parse: start of document to end of\n // document. The re-based tail MDAST root end IS the document end. The\n // tail HAST root's position is NOT source-based after rehype-raw's\n // reparse (hast-util-raw rewrites it in serialized-HTML coordinates), so\n // it cannot be re-based — but a full parse with POSITIONED output (the\n // other case bailed above) leaves the hast root position equal to the\n // mdast root position (arbiter-verified), so reuse that.\n const docStart = { line: 1, column: 1, offset: 0 };\n const mdastRootPosition = tailMdast.position\n ? { start: docStart, end: rebasePoint(tailMdast.position.end, offsetDelta, lineDelta) }\n : prevMdast.position;\n const hastRootPosition = mdastRootPosition;\n\n const mdast: MdastRoot = { type: 'root', children: mdastChildren };\n if (mdastRootPosition) mdast.position = mdastRootPosition;\n const hast: HastRoot = { type: 'root', children: hastChildren };\n if (hastRootPosition) hast.position = hastRootPosition;\n if (prevHast.data !== undefined) hast.data = prevHast.data;\n return { mdast, hast };\n}\n\nfunction rebasePoint(point: Position['end'], offsetDelta: number, lineDelta: number): Position['end'] {\n return {\n line: point.line + lineDelta,\n column: point.column,\n offset: point.offset !== undefined ? point.offset + offsetDelta : undefined,\n };\n}\n\n/** mdast types with no to-hast output AND no wrap separator slot. Everything\n * else gets a slot at wrap() time — even nodes sanitize later strips\n * (comments, PIs, `<script>`), whose slots survive as orphan separators. */\nfunction isWrapInvisible(node: MdastContent): boolean {\n return node.type === 'definition' || node.type === 'footnoteDefinition';\n}\n\n/**\n * Stripped-node-aware prefix cut (B0-probe-verified layout model).\n *\n * The cut region of the previous hast interleaves CONTENT nodes with\n * position-less '\\n' SEPARATORS. wrap() emitted one separator per gap\n * between adjacent wrap-visible mdast children; sanitize then stripped some\n * children's output (HTML comment / PI / `<script>`), leaving their\n * separators orphaned. The walk below re-derives the pairing:\n *\n * - separator-run lengths are the gap ground truth (a run of length L\n * between two content nodes ⇒ L−1 stripped children between them; a\n * leading run of length L ⇒ L leading stripped children);\n * - positioned content cross-checks the pairing (its start offset must fall\n * inside the paired mdast child's range). Multiple positioned content\n * nodes inside ONE child's range are a raw-reparse multi-output html\n * block — legal, zero separators between them;\n * - position-less content (KaTeX span) pairs by cursor arithmetic alone.\n *\n * Internal separators are kept VERBATIM (one before a frozen <table> may\n * legitimately hold hoisted newlines — frozen with the table, stable). The\n * TRAILING run is rebuilt from scratch as plain '\\n' nodes: its last member\n * is seam-adjacent and may carry the previous frame's tail-derived hoist\n * (stale), and its length must reflect the CURRENT tail's wrap visibility,\n * not the previous frame's.\n *\n * Returns null whenever the observed layout contradicts the model — the\n * caller falls back to a full parse (safe, one-frame cost).\n */\nfunction alignPrefixCut(\n prefixMdast: MdastContent[],\n cutRegion: HastContent[],\n tailWrapVisible: boolean\n): { children: HastContent[]; interiorFinalLiteral: boolean } | null {\n const visibles = prefixMdast.filter((c) => !isWrapInvisible(c));\n\n const out: HastContent[] = [];\n let sepBuffer: HastContent[] = [];\n let pairIdx = -1; // index into `visibles` of the child paired with the last content node\n let sawContent = false;\n // Wrap separators MERGED into pushed trailing literals (every trailing\n // '\\n' on a literal is a merged separator — see the trailing-region\n // note). They count toward the NEXT gap's run length: without the\n // credit, separator runs after a literal UNDERCOUNT the stripped\n // children and the run-length rule mispairs position-less content\n // (seed-20260752: the KaTeX span paired with the stripped comment,\n // inflating the trailing gap count and duplicating the seam separator).\n let literalCredit = 0;\n\n for (const node of cutRegion) {\n if (isSeparatorText(node)) {\n sepBuffer.push(node);\n continue;\n }\n const start = node.position?.start?.offset;\n const paired = pairIdx >= 0 ? visibles[pairIdx] : undefined;\n if (\n sawContent &&\n start !== undefined &&\n paired &&\n paired.position?.start?.offset !== undefined &&\n paired.position?.end?.offset !== undefined &&\n start >= paired.position.start.offset &&\n start < paired.position.end.offset\n ) {\n // Multi-output continuation of the SAME mdast child (raw reparse of a\n // multi-element html block) — serialized adjacently, so no separator\n // may sit between the outputs.\n if (sepBuffer.length !== 0) return null;\n out.push(node);\n continue;\n }\n if (sawContent && isTrailingLiteralText(node)) {\n // Raw trailing literal of the SAME html block (position-less,\n // non-whitespace — cannot be foster-parenting hoist, which is\n // whitespace-only). Serialized adjacent to its element output, so no\n // separator may intervene; the pairing cursor stays put.\n if (sepBuffer.length !== 0) return null;\n out.push(node);\n literalCredit += countTrailingNewlines(node.value);\n continue;\n }\n // New pairing: the separator run before this node covers the gap from\n // the previous content node (1 separator) plus one per stripped child.\n //\n // LEADING-run exception (final-review R2): when the FIRST wrap-visible\n // child is a table (or any foster-parenting element), rehype-raw's\n // hoisted whitespace has no preceding wrap slot to merge into and lands\n // as a bare leading text node — one leading text with ZERO stripped\n // children. A positioned first content node therefore locates its own\n // pair by containment within [0..sepBuffer.length]; the excess leading\n // texts are hoist, kept verbatim (frozen with their table, stable —\n // interior hoist always merges into an existing slot, so only the\n // leading run needs this). Position-less first content (KaTeX — never\n // hoist-preceded) keeps the pure run-length rule.\n let nextIdx: number;\n if (!sawContent && start !== undefined) {\n nextIdx = -1;\n for (let j = 0; j <= sepBuffer.length && j < visibles.length; j++) {\n const vStart = visibles[j].position?.start?.offset;\n const vEnd = visibles[j].position?.end?.offset;\n if (vStart !== undefined && vEnd !== undefined && start >= vStart && start < vEnd) {\n nextIdx = j;\n break;\n }\n }\n if (nextIdx === -1) return null;\n // Excess leading texts beyond the stripped-child slots can only be\n // hoist, and hoist exists as a SEPARATE node only when there is no\n // slot to merge into (nextIdx === 0, probe-verified). Any excess in\n // the presence of slots is out of model → bail (round-2 review\n // tightened this from `excess > 1`).\n const excess = sepBuffer.length - nextIdx;\n if (excess > (nextIdx === 0 ? 1 : 0)) return null;\n } else {\n // Run length = observed bare separators PLUS the ones merged into\n // trailing literals since the last pairing (literalCredit) — the gap\n // ground truth the stripped-children arithmetic needs.\n const stripped = sawContent ? sepBuffer.length + literalCredit - 1 : sepBuffer.length;\n if (stripped < 0) return null;\n nextIdx = pairIdx + 1 + stripped;\n const candidate = visibles[nextIdx];\n if (!candidate) return null;\n if (start === undefined && sepBuffer.some((sep) => sep.type !== 'text' || sep.value !== '\\n')) {\n // Position-less content (KaTeX) can only be paired by run length, and\n // a merged separator (`\"\\n\\n\"` around an html block parse5 dropped\n // outright) UNDERCOUNTS the gap — the span would pair with the\n // dropped block and be frozen twice (release soak of 2.4.2). Bail.\n return null;\n }\n if (start !== undefined) {\n const cStart = candidate.position?.start?.offset;\n const cEnd = candidate.position?.end?.offset;\n if (cStart === undefined || cEnd === undefined || start < cStart || start >= cEnd) return null;\n }\n }\n out.push(...sepBuffer, node);\n sepBuffer = [];\n literalCredit = 0; // merged separators consumed by this gap\n pairIdx = nextIdx;\n sawContent = true;\n }\n\n // Trailing region: every visible child after the last paired one must be\n // stripped. The observed run came from the PREVIOUS frame (its length\n // includes that frame's seam separator when its tail was wrap-visible),\n // so it is discarded and rebuilt for the current tail.\n const trailingStripped = visibles.length - (pairIdx + 1);\n const trailingGaps = sawContent ? trailingStripped : Math.max(0, visibles.length - 1);\n const seam = visibles.length > 0 && tailWrapVisible ? 1 : 0;\n\n // Trailing-literal seam merge: when the cut ends in an html block's raw\n // trailing literal, the full parse MERGES the wrap separator into that\n // text node (adjacent text at reparse time) instead of keeping a bare\n // '\\n' — and the merge DROPS the text's source position (an unmerged\n // document-final literal keeps hast-util-raw's position; the same\n // literal followed by wrap-visible content comes out position-less,\n // fuzz-verified both ways). The literal's intrinsic value never ends\n // with '\\n' (an html node's source ends at line content), so EVERY\n // trailing '\\n' on the cut node is a previous frame's merged artifact —\n // seam separator, footer separator, or table hoist (which GROWS with the\n // streaming tail and must never be carried forward). Shed them all, then\n // re-merge (and re-drop the position) for the CURRENT tail's layout — the\n // join merges the tail's own leading text back in. Stripped children\n // after a trailing literal are out of model — bail to the full parse.\n const last = out[out.length - 1];\n // A POSITIONED whitespace-only text at the cut's end is an html block's\n // raw remnant with every tag dropped by parse5 (`</details>\\n</details>`\n // leaves only the line ending, positioned) — the trailing-literal branch\n // below models non-blank literals only, and the plain-slot rebuild would\n // push it next to a synthesized bare '\\n' where the full parse merges\n // both into one position-less `\"\\n\\n\"`. Out of model — bail (v2.4.1\n // review P2, the neighbour of the two 2.4.1 trailing-literal fixes).\n if (last !== undefined && last.type === 'text' && last.position !== undefined && last.value.trim() === '') {\n return null;\n }\n // Interior-literal gate (seed-20260838): this branch models BLOCK-FINAL\n // literals — the ones the full parse merges with the seam separator\n // (position dropped). A POSITIONED literal whose source ends BEFORE its\n // owner html node's end is an INTERIOR raw literal: a sanitize-stripped\n // sibling (`</details>` text `<embed/>`) followed it at reparse time, so\n // the full parse keeps it verbatim — positioned, un-merged, with its own\n // separator. Route those to the plain-slot rebuild (and tell the join to\n // keep its hands off — see `interiorFinalLiteral`). A positioned literal\n // whose end EQUALS the owner's end is block-final like the position-less\n // ones and stays in this branch (first freeze straight from a full-parse\n // tree — later frames see the merged, position-less artifact).\n const lastIsLiteral = last !== undefined && last.type === 'text' && last.value.trim() !== '';\n if (lastIsLiteral && pairIdx >= 0 && visibles[pairIdx].type !== 'html') {\n // Root-level literal text owned by a NON-html block: a stray `<td>`\n // earlier in the document made parse5 foster-parent the following GFM\n // table's cell text to the root and destroy the table skeleton, whose\n // internal line endings then merged into the separator AFTER it — a\n // separator the cut never sees (it lives past the boundary) and the\n // rebuild cannot reproduce (v2.4.2 review P1-2). Out of model — bail.\n return null;\n }\n const litOwnerEnd = pairIdx >= 0 ? visibles[pairIdx].position?.end?.offset : undefined;\n const litEnd = lastIsLiteral ? last.position?.end?.offset : undefined;\n if (lastIsLiteral && last.position !== undefined && (litEnd === undefined || litOwnerEnd === undefined)) {\n // Positioned literal with an unclassifiable owner — out of model.\n return null;\n }\n if (litEnd !== undefined && litOwnerEnd !== undefined && litEnd > litOwnerEnd) {\n // A positioned literal extending PAST its owner is unreachable by the\n // model (positioned ⟹ never merged ⟹ span stays inside the owner) —\n // if it ever shows up the model diverged, and folding it into the\n // block-final branch would merge bytes we cannot account for. Bail\n // explicitly: \"unreachable\" becomes \"safe when reached\" (final-review\n // MINOR, echoing the first-fix regression lesson).\n return null;\n }\n const interiorFinalLiteral =\n lastIsLiteral && litEnd !== undefined && litOwnerEnd !== undefined && litEnd < litOwnerEnd;\n if (lastIsLiteral && !interiorFinalLiteral) {\n // This bail is also the backstop for the cut loop's trailing-literal\n // break path (see the cross-reference note there): a frozen stripped\n // construct after the literal surfaces here as trailing gaps or a\n // leftover separator run. Do not loosen without restoring a remnant\n // check at the cut.\n if (trailingGaps > 0 || sepBuffer.length > 0) return null;\n const body = last.value.replace(/\\n+$/, '');\n if (last.position !== undefined && body !== last.value) {\n // A positioned block-final literal never carries trailing newlines\n // (its source ends at line content; merges drop the position) — a\n // trailing '\\n' here is out of model.\n return null;\n }\n if (seam > 0) {\n out[out.length - 1] = { type: 'text', value: `${body}\\n` };\n } else if (last.position !== undefined) {\n // Positioned block-final literal fresh from a full-parse tree: its\n // own position IS the source truth — keep the node verbatim (the\n // trailing-'\\n' guard above proved body === value).\n } else {\n // Document-final literal (nothing wrap-visible follows): hast-util-raw\n // keeps its SOURCE position — [previous element's end, owner html\n // node's end]. A literal that got merged in an earlier frame lost its\n // position, so reconstruct it from the neighbors; bail when they\n // don't carry the needed points. (If the current tail still appends a\n // footer, the join's literal-seam merge re-drops the position — the\n // same order a full parse resolves it in.)\n const prevEl = out.length >= 2 ? out[out.length - 2] : undefined;\n const owner = pairIdx >= 0 ? visibles[pairIdx] : undefined;\n const start = prevEl?.type === 'element' ? prevEl.position?.end : undefined;\n const end = owner?.position?.end;\n if (!start || !end) return null;\n out[out.length - 1] = { type: 'text', value: body, position: { start, end } };\n }\n return { children: out, interiorFinalLiteral: false };\n }\n\n // A trailing separator whose value is not a PLAIN '\\n' carries a merged\n // raw remnant (a dropped construct's whitespace, a prior merged gap) —\n // rebuilding it as bare '\\n' silently drops those bytes (deep-soak\n // counterexample: a stripped comment's preceding ' ' merged into ' \\n').\n // Out of the plain-slot model — bail to a full parse.\n if (sepBuffer.some((s) => s.type !== 'text' || s.value !== '\\n')) return null;\n // An interior literal whose merged separators were never consumed by a\n // later pairing (literal, bare separators, then nothing) — its credit\n // would have to offset the trailing-run arithmetic below, a shape the\n // trailing rebuild does not model. Bail to a full parse.\n if (literalCredit > 0) return null;\n // A frozen html child ENDING in a sanitize-stripped construct (`…-->`,\n // `…?>`, `…]]>`, declarations) leaves interior whitespace between its\n // last element and the stripped tail — whitespace the full parse MERGES\n // into the seam separator (`\"\\n\\n\"`, seed-20260850) while the plain-slot\n // rebuild below synthesizes a bare `'\\n'`. The merged node never reaches\n // the cut (attribution excludes it), so the rebuild is blind to it —\n // bail to a full parse when the last paired child has such a tail.\n const lastPaired = pairIdx >= 0 ? visibles[pairIdx] : undefined;\n if (lastPaired && lastPaired.type === 'html') {\n const v = (lastPaired as { value: string }).value;\n const lastLt = v.lastIndexOf('<');\n if (lastLt !== -1 && /^<[!?]/.test(v.slice(lastLt))) return null;\n // Same blindness, other cause: the block's OUTPUT ends before its\n // SOURCE does — parse5 dropped whatever followed the last element (a\n // stray `</details>` after the real one, v2.4.1 review P2) and the line\n // ending before it survives as a remnant the full parse merges into\n // the seam separator (`\"\\n\\n\"`), which the rebuild below cannot see.\n const lastOut = out[out.length - 1];\n const outEnd = lastOut?.type === 'element' ? lastOut.position?.end?.offset : undefined;\n const blockEnd = lastPaired.position?.end?.offset;\n if (outEnd !== undefined && blockEnd !== undefined && outEnd < blockEnd) return null;\n }\n if (sepBuffer.length !== trailingGaps && sepBuffer.length !== trailingGaps + 1) return null;\n // The rebuild below emits ONE bare '\\n' per stripped trailing child — the\n // shape a sanitize-stripped node leaves (comment/PI/CDATA/declaration:\n // rehype-raw made a node, sanitize removed it, the separators around it\n // stay separate texts). An html block that parse5 DROPPED outright (a\n // stray `</details>`, a `<!DOCTYPE>`, or an element sanitize removed as a\n // whole) leaves no node, and hast-util-raw merges the separators around\n // it into one `\"\\n\\n\"` — the two are indistinguishable from the cut hast\n // (release soak of 2.4.2, `</details>\\n<!-- c\\n\\n-->\\n</details>` —\n // pre-existing). And a child that only STARTS with a construct leaves the\n // rest as a text remnant that merges into a slot the rebuild synthesizes\n // bare (`<!-- c --> </s>` → `\" \\n\"`, release-gate finding A, seed\n // 20293003 — the old `/^\\s*<[!?]/` prefix test admitted it). Bail unless\n // every stripped trailing child is EXACTLY one sanitize-stripped\n // construct.\n for (let j = pairIdx + 1; j < visibles.length; j++) {\n const v = visibles[j];\n if (v.type === 'html' && !isExactSanitizeStrippedConstruct((v as { value: string }).value)) return null;\n }\n for (let i = 0; i < trailingGaps + seam; i++) {\n out.push({ type: 'text', value: '\\n' });\n }\n return { children: out, interiorFinalLiteral };\n}\n\n/**\n * Drop the injected region's output from a freshly-parsed tail hast.\n *\n * The injection contributes two kinds of root output: the replay's footnote\n * REF paragraphs (one `<p>` each — footnote/link defs are wrap-invisible)\n * and the wrap separators around them. Consume exactly:\n *\n * output_1 [sep output_2 … sep output_k] [gapSep]\n *\n * where k = injected wrap-visible children and gapSep (present only when\n * the REAL tail has wrap-visible children) is the injected|tail gap slot.\n * gapSep's value beyond its wrap '\\n' is text the raw reparse MERGED into\n * the slot — rehype-raw hoist ahead of a table, or the orphan separator of\n * an opener the tokenizer dropped outright (an unterminated `<?`/`<!`, fuzz\n * counterexample) — retained as a leading text node.\n *\n * `remnantMerged` carries the seam verdict that merge PROVES: the injected\n * region occupies the same serialized-adjacency position inside the tail\n * parse that the frozen prefix occupies in a full parse, so \"the tail's raw\n * pass merged the gap with what follows\" ⇔ \"a full parse merges the seam\n * separator there too\". Null when no gap was consumed (no injection): the\n * caller falls back to the hoist heuristic.\n *\n * Returns null on any layout surprise (caller falls back to a full parse).\n */\nfunction stripInjectedHast(\n tailMdast: MdastRoot,\n tailHast: HastRoot,\n injectedLen: number,\n tailWrapVisible: boolean\n): { rest: HastContent[]; remnantMerged: boolean | null } | null {\n if (injectedLen === 0) return { rest: tailHast.children.slice(), remnantMerged: null };\n const injectedVisibleCount = tailMdast.children.filter((c) => {\n const start = c.position?.start?.offset;\n return start !== undefined && start < injectedLen && !isWrapInvisible(c);\n }).length;\n if (injectedVisibleCount === 0) return { rest: tailHast.children.slice(), remnantMerged: null };\n\n const children = tailHast.children;\n let idx = 0;\n let consumed = 0;\n while (idx < children.length && consumed < injectedVisibleCount) {\n const node = children[idx];\n if (isSeparatorText(node)) {\n idx += 1;\n continue;\n }\n const start = node.position?.start?.offset;\n // Injected outputs are always positioned paragraphs; running into tail\n // content (or anything unpositioned) before finishing is a surprise.\n if (start === undefined || start >= injectedLen) return null;\n consumed += 1;\n idx += 1;\n }\n if (consumed < injectedVisibleCount) return null;\n\n let remnant = '';\n let remnantMerged: boolean | null = null;\n if (tailWrapVisible) {\n const gap = children[idx];\n if (!gap || !isSeparatorText(gap)) return null;\n remnant = (gap as { value: string }).value.slice(1);\n remnantMerged = remnant !== '';\n idx += 1;\n }\n const rest = children.slice(idx);\n if (remnant !== '') rest.unshift({ type: 'text', value: remnant });\n return { rest, remnantMerged };\n}\n\n/**\n * Decide whether the tail hast's LEADING position-less text may merge with\n * the seam separator. True only when it is rehype-raw hoist output sitting\n * directly against the seam in serialized HTML — i.e. the tail's first\n * wrap-visible mdast child SURVIVED sanitize (its output is the first tail\n * content node). If that child was stripped (leading comment), the leading\n * text is a gap SLOT the full parse keeps as a separate node.\n *\n * Three-valued (fuzz-arbiter finding — the old boolean version claimed\n * \"false is provably right wherever evidence is ambiguous\", and fuzz\n * disproved it): a tail whose first wrap-visible child VANISHES at raw time\n * (an unterminated `<?`/`<!` opener the tokenizer drops outright) leaves\n * the same post-sanitize shape as one stripped at sanitize time (a\n * complete comment), but the full parse MERGES the seam in the first case\n * and keeps it separate in the second. Positive classifications:\n * - `true` — hoist: first content is positioned inside the first visible\n * child (table foster-parenting), merge;\n * - `false` — the vanished/position-less output is positively attributable:\n * math (KaTeX emits its own output, never dropped) or a COMPLETE\n * comment/PI/decl/CDATA html child (a raw-time node existed; sanitize\n * stripped it, so the slots stay separate);\n * - `null` — cannot classify (unterminated raw constructs, mixed html\n * values): caller falls back to a full parse for the frame.\n */\nfunction tailLeadingTextIsHoist(tailMdastChildren: MdastContent[], tailHastChildren: HastContent[]): boolean | null {\n const firstText = tailHastChildren[0];\n const firstVisible = tailMdastChildren.find((c) => !isWrapInvisible(c));\n // HTML's two end-tag SYNTHESIS exceptions: a stray `</br>` becomes a\n // `<br>` and a stray `</p>` an empty `<p>` (every other unmatched end tag\n // is dropped). The full parse synthesizes them in body context; the\n // tail-only parse, which opens on the stray tag, does not — the element\n // is simply absent from the tail hast, so no join rule can put it back\n // (v2.4.2 review P1-1: `x\\n\\n</br>\\n\\ny` lost its `<br>`). Bail.\n if (firstVisible?.type === 'html' && STRAY_SYNTHESIZED_END_TAG_RE.test(firstVisible.value)) return null;\n if (!firstText) return false;\n if (!isSeparatorText(firstText)) {\n // Position-less NON-whitespace leading text: the tail starts with an\n // html block whose leading end tag the tokenizer DROPPED (`</t>\\ntext`\n // — no open element to close, so no node ever existed) and whose\n // remaining text merged with the wrap separator at reparse time. The\n // full parse therefore has ONE merged text at the seam; treat it as\n // hoist-merge (v2.4.0 review P3 join side, surfaced by the new fuzz\n // shape). Any other position-less literal keeps its own node.\n if (firstText.type === 'text' && firstText.position === undefined && firstVisible?.type === 'html') {\n if (/^\\s*<\\/[A-Za-z][A-Za-z0-9-]*\\s*>/.test(firstVisible.value)) return true;\n // A complete comment/PI/decl/CDATA existed at raw time (sanitize\n // stripped it later) — its slots stay separate: no merge. A DOCTYPE\n // is not in that class (parse5 drops it, no node) and falls to the\n // bail below.\n if (isSanitizeStrippedConstruct(firstVisible.value)) return false;\n // Anything else — an unterminated `<div` opener the tokenizer drops\n // at EOF-in-tag (release soak: `<div\\n\\n</t>\\ntext`), mixed raw\n // values — needs the tokenizer to say whether a node existed\n // between the separator and this text. Bail to a full parse.\n return null;\n }\n return false;\n }\n if (!firstVisible) return false;\n const firstContent = tailHastChildren.find((c) => !isSeparatorText(c));\n if (firstContent) {\n const start = firstContent.position?.start?.offset;\n const vStart = firstVisible.position?.start?.offset;\n const vEnd = firstVisible.position?.end?.offset;\n if (start !== undefined && vStart !== undefined && vEnd !== undefined) {\n if (start >= vStart && start < vEnd) return true; // hoist\n // First visible's output vanished; classify by the child itself below.\n }\n }\n if (firstVisible.type === 'math') return false; // KaTeX output, never dropped\n // Sanitize-stripped constructs only: a raw-time node existed, the slots\n // stay separate. A `<!DOCTYPE …>` child VANISHES at parse5 time instead\n // (no node — fragment tree construction drops the doctype token), so the\n // seam separator and the tail's leading text MERGE in a full parse\n // (release-gate finding B, seed 20293004) — it falls through to the null\n // bail, full parse for the frame.\n if (firstVisible.type === 'html' && isSanitizeStrippedConstruct(firstVisible.value)) return false;\n return null;\n}\n\n/** Single complete comment / PI / declaration / CDATA that begins with a\n * construct parse5 turns into a NODE (a comment) — raw-time node\n * guaranteed, sanitize strips it later, so its separator slots stay\n * separate. `<!DOCTYPE …>` is the one declaration this is FALSE of:\n * parse5's tokenizer recognizes it as a real doctype token, and fragment\n * tree construction then DROPS it outright — no node ever exists, so the\n * texts on either side MERGE at reparse time (release-gate finding B:\n * classifying it \"stripped ⇒ slots separate\" split a seam text the full\n * parse merges). Doctypes and anything unterminated or mixed → not\n * classifiable here. Exported for the semantics pins. */\nexport function isSanitizeStrippedConstruct(value: string): boolean {\n const v = value.trim();\n return (\n (v.startsWith('<!--') && v.endsWith('-->')) ||\n (v.startsWith('<?') && v.endsWith('?>')) ||\n (v.startsWith('<![CDATA[') && v.endsWith(']]>')) ||\n (/^<![A-Za-z]/.test(v) && !/^<!doctype/i.test(v) && v.endsWith('>'))\n );\n}\n\n/** The trailing-slot rebuild's admission test — STRICTER than the seam\n * classifier above, because the rebuild asserts the stripped child leaves\n * EXACTLY one bare '\\n' wrap slot and nothing else. The whole value must\n * be ONE construct that parse5 tokenizes into a node and sanitize strips,\n * covering the value EXACTLY: any surrounding bytes survive the strip as a\n * text remnant that merges into a neighbouring slot, which the plain-'\\n'\n * rebuild cannot represent (`<!-- c --> </s>` leaves ` ` and the full\n * parse's slot is `\" \\n\"` — release-gate finding A). The construct ends\n * are PARSE5's, not micromark's:\n * - a comment also closes at `--!>` (micromark ignores it), so the first\n * parse5 close must be the value's own terminal `-->`;\n * - `<?…` / `<!x…` / `<![CDATA[…` in HTML content are ONE bogus comment\n * running to the FIRST `>` — a `>` inside the micromark construct body\n * ends the node early and leaves a remnant;\n * - `<!doctype` never makes a node at all (see the seam classifier).\n * Exported for the semantics pins. */\nexport function isExactSanitizeStrippedConstruct(value: string): boolean {\n if (value.startsWith('<!--')) {\n if (value.length < 7 || !value.endsWith('-->')) return false;\n // First close scanned from past the opener; an overlap-close empty\n // comment (`<!--->`) is refused — conservative, full parse instead.\n const close = value.indexOf('-->', 4);\n const bangClose = value.indexOf('--!>', 4);\n if (close !== value.length - 3) return false;\n return bangClose === -1 || bangClose > close;\n }\n if (/^<!doctype/i.test(value)) return false;\n if (value.startsWith('<?') || /^<!(?:[A-Za-z]|\\[CDATA\\[)/.test(value)) {\n return value.indexOf('>') === value.length - 1;\n }\n return false;\n}\n\n/** Position-less whitespace-only root text — wrap()/rehype-raw separator runs. */\nfunction isSeparatorText(node: HastContent): boolean {\n return node.type === 'text' && node.position === undefined && node.value.trim() === '';\n}\n\n/** Whether a position-less literal is the trailing raw text of the `html`\n * mdast block that produced `el` (the element's start is that block's\n * start, and the block's source ENDS with the literal's text). Trailing raw\n * literals can only follow html-block output, and only that block's own\n * text counts — a following dropped-tag block's remnant sits in the same\n * spot but is not in this block's source. */\nfunction ownsTrailingLiteral(el: HastContent, literal: { value: string }, prefixMdast: MdastContent[]): boolean {\n const start = el.position?.start?.offset;\n if (start === undefined) return false;\n const owner = prefixMdast.find((c) => c.type === 'html' && c.position?.start?.offset === start);\n if (!owner || owner.type !== 'html') return false;\n const text = literal.value.trim();\n return text !== '' && owner.value.trimEnd().endsWith(text);\n}\n\n/** Position-less NON-whitespace text at the top level — the raw reparse's\n * literal trailing output of an html block (an unblanked text line after\n * the block's closing tag). Distinct from separators and foster-parenting\n * hoist, which are whitespace-only. */\nfunction isTrailingLiteralText(node: HastContent): node is HastContent & { type: 'text'; value: string } {\n return node.type === 'text' && node.position === undefined && node.value.trim() !== '';\n}\n\n/** Trailing '\\n' run length on a literal's value — its merged separators. */\nfunction countTrailingNewlines(value: string): number {\n let n = 0;\n for (let i = value.length - 1; i >= 0 && value[i] === '\\n'; i--) n += 1;\n return n;\n}\n\n/** Line endings in `text` before `end` (defaults to the whole string) — the\n * bound avoids allocating prefix slices on the per-frame hot path.\n * Counts what micromark counts: `\\n`, `\\r\\n` and a LONE `\\r` are one line\n * ending each (2026-08-19 review P2-1: a lone `\\r` in the frozen prefix\n * left every rebased tail `position.line` one short — offsets and shape\n * were right, only the line numbers drifted). Two indexOf sweeps keep the\n * hot path allocation-free; a `\\r` directly followed by `\\n` is the CRLF\n * pair, already counted by the `\\n` sweep. */\nfunction countNewlines(text: string, end = text.length): number {\n let count = 0;\n for (let i = text.indexOf('\\n'); i !== -1 && i < end; i = text.indexOf('\\n', i + 1)) count += 1;\n for (let i = text.indexOf('\\r'); i !== -1 && i < end; i = text.indexOf('\\r', i + 1)) {\n if (text.charCodeAt(i + 1) !== 10 /* \\n */) count += 1;\n }\n return count;\n}\n","/**\n * Shared hast predicates — engine-side home for detection helpers consumed\n * by both the incremental-parse engine (attributeHastChildren's seam\n * attribution) and core's block-memo renderer.\n *\n * Lifted verbatim from core's blockMemo.ts (boundary action ①): blockMemo\n * stays React-side while incrementalParse moves into the engine, and this\n * predicate was the one value-level edge between them.\n *\n * @module components/hastPredicates\n */\n\nimport type { Element as HastElement, ElementContent } from 'hast';\n\n/**\n * Detect mdast-util-to-hast's synthesized footnote `<section data-footnotes>`.\n * Position-based detection alone would be too broad — any future rehype plugin\n * that appends a position-less node would be misclassified. We assert by\n * `tagName === 'section'` AND presence of the `dataFootnotes` property.\n */\nexport function isFootnoteSection(node: HastElement): boolean {\n if (node.tagName !== 'section') return false;\n const props = node.properties as Record<string, unknown> | undefined;\n return props?.dataFootnotes !== undefined;\n}\n\n/**\n * Whitespace-only text node. `mdast-util-to-hast`'s `state.wrap(content,\n * true)` interleaves `\\n` text nodes between (and around) the block-level\n * children of an `<li>`, so any code reasoning about a list item's real\n * children has to look past them.\n */\nexport function isWhitespaceText(c: ElementContent): boolean {\n return c.type === 'text' && /^\\s*$/.test((c as { value: string }).value);\n}\n\n/**\n * Index of the last child that is not a whitespace-only text node, or -1 if\n * there is none.\n *\n * Both footnote-footer paths need exactly this and for the same reason.\n * Appending a backref follows mdast-util-to-hast's contract — \"if the tail of\n * the `<li>`'s content is a `<p>`, push into it, else push onto the `<li>`\" —\n * and stripping one has to find that tail again. Read the trailing\n * wrap-emitted `\\n` as the tail and the `<p>` path is bypassed in one case\n * and the wrong node stripped in the other.\n *\n * Lived in two copies until 2.5.2 (core's aggregate footer and the engine's\n * body extractor), one on each side of the 2.3.0 package split.\n */\nexport function lastMeaningfulIdx(children: ElementContent[]): number {\n for (let i = children.length - 1; i >= 0; i--) {\n if (!isWhitespaceText(children[i])) return i;\n }\n return -1;\n}\n","/**\n * Source-offset attribution for top-level hast children.\n *\n * hast positions alone cannot delimit a frozen prefix: rehype-katex\n * replaces a math block with a position-less span (and other plugins can\n * do the same), and mdast-util-to-hast's root `wrap()` interleaves\n * position-less `'\\n'` text separators. Each top-level hast child is\n * therefore attributed a source offset:\n *\n * - its own `position.start.offset` when present;\n * - otherwise the start of the first top-level MDAST child at or after the\n * running cursor (top-level mdast children always carry positions — this\n * mirrors blockMemo's source-offset lookup);\n * - the synthetic footnote section is attributed `Infinity` — it is never\n * freeze-eligible (production handles it via `FootnoteSectionEntry` /\n * `aggregateFootnotesIfLast`, not positional identity).\n *\n * The returned array is non-decreasing except for `Infinity` entries, so\n * \"children attributed before offset b\" is always a prefix of the child\n * list.\n *\n * Extracted from the prefixFreeze experiment's falsification harness\n * (which now imports this module) — the production splice and the\n * experiment must cut prefixes identically or the experiment stops being\n * evidence.\n */\n\nimport type { Root as HastRoot } from 'hast';\nimport type { Root as MdastRoot } from 'mdast';\n\nimport { isFootnoteSection } from '../hastPredicates';\n\nexport function attributeHastChildren(mdast: MdastRoot, hast: HastRoot, stopAt = Infinity): number[] {\n const mdastStarts: number[] = [];\n for (const child of mdast.children) {\n const off = child.position?.start?.offset;\n if (off !== undefined) mdastStarts.push(off);\n }\n let cursor = 0;\n let mdastIdx = 0;\n // `stopAt` truncates the walk once attribution reaches the boundary —\n // the splice consumer only reads the prefix, and top-level attribution\n // is non-decreasing (E5).\n const out: number[] = [];\n for (let i = 0; i < hast.children.length; i++) {\n const attr = attributeOne(hast.children[i], hast.children[i + 1]);\n out.push(attr);\n if (attr >= stopAt) break;\n }\n return out;\n\n function attributeOne(child: HastRoot['children'][number], next?: HastRoot['children'][number]): number {\n const start = child.position?.start?.offset;\n const end = child.position?.end?.offset;\n if (start !== undefined && start !== null) {\n cursor = Math.max(cursor, end ?? start);\n return start;\n }\n if (child.type === 'element' && isFootnoteSection(child)) return Infinity;\n // The footer's PRECEDING '\\n' is footer plumbing appended after wrap()\n // (footer.js pushes `'\\n', <section>`), not a wrap gap slot — pin it to\n // the section's Infinity so the prefix cut never absorbs it.\n if (child.type === 'text' && next?.type === 'element' && isFootnoteSection(next)) return Infinity;\n while (mdastIdx < mdastStarts.length && mdastStarts[mdastIdx] < cursor) mdastIdx += 1;\n return mdastIdx < mdastStarts.length ? mdastStarts[mdastIdx] : cursor;\n }\n}\n","/**\n * React-free state machine for incremental (prefix-freeze) parsing.\n *\n * Given the previous frame's state and the current content, either splice\n * a frozen prefix with a tail-only parse or run the full pipeline. Every\n * gate failure degrades to the full path — the caller cannot observe a\n * difference except through `usedIncremental` and the dev-only stage\n * timings. The splice output is deep-equal to a full parse (the\n * splice-equivalence arbiter test enforces this; see spliceParse.ts).\n *\n * Gate order (first failure wins):\n * - G0 depsKey identity — the parse inputs beyond `content` (plugin\n * arrays, remark-rehype options, handlers, documentId, …) must be\n * identical to the previous frame's. This intentionally covers MORE\n * than the component's G3 12-dep flush (e.g. `preserveOrphanReferences`\n * flips reach the handlers without touching any G3 field).\n * - G1 append — `content.startsWith(prev.content)`; equal content returns\n * the previous trees unchanged. Non-append rewrites (including Stage-A\n * preprocessor rewrites near the stream end) land here.\n * - G3 boundary — `b = min(computeFreezeBoundary(content), prev.stableBoundary)`\n * must be > 0. The `min` with the PREVIOUS frame's boundary is\n * load-bearing, not defensive: the freshly computed boundary proves\n * stability of the CURRENT parse's prefix, but the splice reuses the\n * PREVIOUS parse's nodes — e.g. a shortcut ref rendered literal last\n * frame must not be frozen the moment its definition arrives and the\n * fresh boundary jumps past it. `prev.stableBoundary` is exactly the\n * \"stable under all future appends\" property for prev's nodes.\n * - G4 straddle (defensive) — no prev top-level mdast child may cross the\n * boundary; the detector's blockers should already prevent this.\n *\n * (v1's G2 footnote bypass is GONE. Footnotes splice via INJECTION REPLAY:\n * the prefix's footnote event sequence — defs and refs ×count, in document\n * order, collected from prev.mdast — is prepended to the tail source, so\n * the tail run's mdast-util-to-hast state (footnoteOrder / footnoteCounts /\n * footnoteById) is seeded exactly and its footer regenerates the WHOLE\n * document's section; the injected nodes are stripped from both trees and\n * the footer's positions are rewritten by the dual rule in spliceParse.\n * Prefix inline hast is naturally stable — numbering is first-reference\n * order, which appends cannot change for the prefix. The detector's\n * reference taint (footnote namespace) keeps unresolved `[^x]` out of the\n * frozen prefix, C0-probe + arbiter verified.)\n *\n * `nextState.stableBoundary` is written on BOTH paths from the same single\n * boundary computation.\n */\n\nimport type { Root as HastRoot } from 'hast';\nimport type { Root as MdastRoot } from 'mdast';\n\nimport { parseStage, transformStage, type PipelineOptions as MarkdownOptions } from '../markdown';\nimport { computeFreezeBoundary, type FreezeScanCheckpoint } from './computeFreezeBoundary';\nimport {\n buildInjectionPrefix,\n collectPrefixInjection,\n spliceTrees,\n tailMentionsTerminator,\n type CachedInjectionPlan,\n} from './spliceParse';\n\nexport interface IncrementalParseState {\n /** The CHUNK's own text — excludes the phantom suffix. */\n content: string;\n /** The phantom suffix this state's trees were parsed with ('' standalone). */\n phantomSuffix: string;\n /** Post-transform trees (transformStage mutates mdast in place; these are\n * the settled shapes) — of `content + phantomSuffix`. */\n mdast: MdastRoot;\n hast: HastRoot;\n /** Scan boundary at the frame that produced these trees. */\n stableBoundary: number;\n /** Detector resume state: append frames re-lex only past the confirmed\n * prefix instead of the whole document (E2). Single-consumer mutable —\n * owned by this state lineage. */\n scanCheckpoint: FreezeScanCheckpoint | null;\n /** Injection-plan resume state: events derive from (content, positions)\n * alone, so within an append lineage only children past the cached\n * boundary need visiting (final-review R3 — without this the plan walk\n * re-visits the entire frozen prefix every splice frame). Null until the\n * first splice frame; carried verbatim across full-path append frames. */\n injectionPlan: CachedInjectionPlan | null;\n /** Identity tuple of every parse input beyond `content` (G0). */\n depsKey: readonly unknown[];\n}\n\nexport type IncrementalStage = 'scan' | 'parse' | 'transform';\n\nexport interface AdvanceOptions {\n remarkPlugins: MarkdownOptions['remarkPlugins'];\n rehypePlugins: MarkdownOptions['rehypePlugins'];\n /** The FULLY-MERGED remark-rehype options (handlers, clobberPrefix, …) —\n * exactly what the full path would pass to parseStage. */\n remarkRehypeOptions: MarkdownOptions['remarkRehypeOptions'];\n depsKey: readonly unknown[];\n /** Whether remark-definition-list is active (`enginePlugins` includes `definitionList`). */\n defListEnabled: boolean;\n /** Cross-chunk phantom-definition suffix (coordinated mode) — appended to\n * the parse input but NEVER frozen: the append gate, boundary scan, and\n * prefix cut all see `content` alone, and the suffix re-parses with the\n * tail every frame. It may shrink/grow/reorder between frames (registry\n * label churn) without invalidating the frozen prefix — the reference\n * taint keeps every phantom-resolved ref in the tail (a phantom's def is\n * never IN `content`, so such refs never settle). '' when standalone. */\n phantomSuffix?: string;\n /** Optional stage-timing wrapper (the component passes measureStage). */\n measure?: <T>(stage: IncrementalStage, fn: () => T) => T;\n}\n\nexport interface AdvanceResult {\n mdast: MdastRoot;\n hast: HastRoot;\n usedIncremental: boolean;\n /** The boundary the splice used (0 on the full path). */\n boundary: number;\n nextState: IncrementalParseState;\n}\n\nconst identityMeasure = <T>(_stage: IncrementalStage, fn: () => T): T => fn();\n\nfunction depsKeyEqual(a: readonly unknown[], b: readonly unknown[]): boolean {\n return a.length === b.length && a.every((value, i) => value === b[i]);\n}\n\nfunction runPipeline(source: string, options: AdvanceOptions): { mdast: MdastRoot; hast: HastRoot } {\n const measure = options.measure ?? identityMeasure;\n const parsed = measure('parse', () =>\n parseStage({\n children: source,\n remarkPlugins: options.remarkPlugins,\n rehypePlugins: options.rehypePlugins,\n remarkRehypeOptions: options.remarkRehypeOptions,\n })\n );\n const hast = measure('transform', () => transformStage(parsed));\n return { mdast: parsed.mdast, hast };\n}\n\nexport function advanceIncrementalParse(\n prev: IncrementalParseState | null,\n content: string,\n options: AdvanceOptions\n): AdvanceResult {\n const measure = options.measure ?? identityMeasure;\n const phantomSuffix = options.phantomSuffix ?? '';\n const sameDeps = prev !== null && depsKeyEqual(prev.depsKey, options.depsKey);\n\n // Zero-scan short-circuit — identical content AND suffix reuse the whole\n // previous state verbatim (registry version bumps, unrelated re-renders).\n // A suffix-only change falls through: the scan resume over unchanged\n // content is ~free, and the tail (which always contains the suffix)\n // re-parses with the new one.\n if (sameDeps && content === prev!.content && phantomSuffix === prev!.phantomSuffix) {\n return {\n mdast: prev!.mdast,\n hast: prev!.hast,\n usedIncremental: true,\n boundary: prev!.stableBoundary,\n nextState: prev!,\n };\n }\n const appendOnly = sameDeps && content.startsWith(prev!.content);\n\n // Every remaining frame scans ONCE (fence-aware). Full-path frames\n // consume the scan on the NEXT frame via `prev.stableBoundary`.\n // Append frames resume the detector from its confirmed-prefix checkpoint\n // instead of re-lexing the whole document (E2); everything else scans\n // fresh. The checkpoint is mutable and single-consumer — this state\n // lineage owns it.\n const scan = measure('scan', () =>\n computeFreezeBoundary(content, { defListEnabled: options.defListEnabled }, appendOnly ? prev!.scanCheckpoint : null)\n );\n const freshBoundary = scan.boundary;\n\n // Carried across full-path append frames; refreshed on splice frames\n // (where the plan walk actually runs). Non-append lineages start over.\n let injectionPlan: CachedInjectionPlan | null = appendOnly ? prev!.injectionPlan : null;\n\n const finish = (mdast: MdastRoot, hast: HastRoot, usedIncremental: boolean, boundary: number): AdvanceResult => ({\n mdast,\n hast,\n usedIncremental,\n boundary,\n nextState: {\n content,\n phantomSuffix,\n mdast,\n hast,\n stableBoundary: freshBoundary,\n scanCheckpoint: scan.checkpoint,\n injectionPlan,\n depsKey: options.depsKey,\n },\n });\n\n const fullPath = (): AdvanceResult => {\n const { mdast, hast } = runPipeline(content + phantomSuffix, options);\n return finish(mdast, hast, false, 0);\n };\n\n // G0 + G1 (scan already ran — its result seeds nextState either way)\n if (!appendOnly) return fullPath();\n // G3\n const boundary = Math.min(freshBoundary, prev!.stableBoundary);\n if (boundary <= 0) return fullPath();\n // G4 (defensive) — deliberately a FULL scan, no ordered-children early\n // break: this is the gate that catches ordering/straddle violations, so\n // it must not share the assumption it defends against (round-2 review).\n // O(top-level children) per frame is noise next to the tail parse.\n for (const child of prev!.mdast.children) {\n const start = child.position?.start?.offset;\n const end = child.position?.end?.offset;\n if (start !== undefined && end !== undefined && start < boundary && end > boundary) {\n return fullPath();\n }\n }\n\n // The one input class where the injection's synthetic terminator label\n // could change how the tail parses: the tail literally mentioning it.\n // Checked on the PRE-injection tail (the injection itself contains the\n // label). Pathological by construction — correctness over splice rate.\n const tailAndSuffix = content.slice(boundary) + phantomSuffix;\n if (tailMentionsTerminator(tailAndSuffix)) return fullPath();\n\n const plan = collectPrefixInjection(prev!.mdast, prev!.content, boundary, injectionPlan);\n if (plan.cacheable !== false) {\n injectionPlan = { boundary, events: plan.events, uninjectable: plan.uninjectable };\n }\n // A nested definition/footnote-def that cannot be re-injected verbatim —\n // take the full path this frame rather than splice without it (A3).\n if (plan.uninjectable) return fullPath();\n const injection = buildInjectionPrefix(plan.events);\n const tailSource = injection.text + tailAndSuffix;\n const tail = runPipeline(tailSource, options);\n const spliced = spliceTrees({\n prevMdast: prev!.mdast,\n prevHast: prev!.hast,\n tailMdast: tail.mdast,\n tailHast: tail.hast,\n content,\n boundary,\n injectionPrefix: injection.text,\n injectedSegments: injection.segments,\n });\n // null = the prefix/tail hast layout fell outside the alignment model —\n // full parse this frame (safe, one-frame cost).\n if (spliced === null) return fullPath();\n return finish(spliced.mdast, spliced.hast, true, boundary);\n}\n","/**\n * TEST/STORY helper (exported from the package barrel for the Storybook\n * streams): prefix\n * snapshots sliced at CODE-POINT granularity, so a frame boundary never\n * splits a surrogate pair. Every streaming verifier in the repo — the\n * splice-equivalence arbiter, the prefixFreeze experiment harness, and the\n * Storybook smoke/playground streams — derives its frame sequence from\n * this one implementation; a change here (e.g. moving to grapheme\n * clusters) changes them all together instead of leaving four copies to\n * drift (review finding R4).\n */\nexport function codePointSnapshots(payload: string, chunkSize: number): string[] {\n const codePoints = Array.from(payload);\n const snapshots: string[] = [];\n for (let i = chunkSize; i < codePoints.length; i += chunkSize) {\n snapshots.push(codePoints.slice(0, i).join(''));\n }\n snapshots.push(payload);\n return snapshots;\n}\n","/**\n * Lightweight def-only parse: runs a minimal unified pipeline\n * (remark-parse + remark-gfm) to extract identifiers of all\n * `footnoteDefinition` and `definition` nodes from a markdown source string.\n *\n * Used by PASS 0 of cross-chunk coordination to discover label sets without\n * triggering the full to-hast pipeline. Output is normalized via normalizeId\n * (uppercase, whitespace-collapsed) — same canonical form used everywhere in\n * the registry, phantomFootnoteLabels Set, and handler comparisons.\n *\n * @module components/collectDefLabels\n */\nimport { unified } from 'unified';\nimport remarkParse from 'remark-parse';\nimport remarkGfm from 'remark-gfm';\nimport { visit } from 'unist-util-visit';\nimport type { Root as MdastRoot } from 'mdast';\nimport { normalizeId } from './normalizeId';\nimport { computeFreezeBoundary, type FreezeScanCheckpoint } from './incrementalParse/computeFreezeBoundary';\n\n/**\n * The scanner's freeze-boundary grammar profile. `mathFlow: false` because\n * this module's PINNED pipeline (remark-parse + remark-gfm) has no\n * remark-math — `$$` is paragraph text here, and the engine's math\n * masking would hide comment/fence opens from the balance scan (ghost-def\n * counterexample, Phase B design review). `referenceTaint: false` because\n * only definition IDENTITIES matter to PASS 0 — a block-level fact\n * independent of inline reference resolution — and taint would collapse\n * the boundary to the body's first citation exactly while a def footer\n * streams. The engine's soak battery does not cover this switch\n * combination; the replay/property/fuzz suites in collectDefLabels.test.ts\n * are its safety net.\n */\nconst SCANNER_BOUNDARY_PROFILE = { defListEnabled: false, mathFlow: false, referenceTaint: false } as const;\n\nexport interface DefLabels {\n footnoteLabels: Set<string>;\n linkLabels: Set<string>;\n}\n\n// Build helper kept as its own function so the cached processor's type is\n// inferred as the FULL chained Processor (remark-parse + remark-gfm), not\n// the bare `unified()` Processor with `undefined` extension types.\n//\n// NOTE: PASS 0 deliberately pins remark-parse + remark-gfm and ignores the\n// pipeline's user remarkPlugins. The append-aware scanner below encodes\n// grammar facts about exactly this plugin set — \"definitions never cross a\n// blank line\", \"a definition's `[` sits at a line's content start\". If\n// this processor ever grows plugins whose def-like constructs violate\n// those facts (directives, MDX, multi-line containers), the scanner's\n// fast path must be revisited: its replay tests only lock today's grammar.\nfunction buildProcessor() {\n return unified().use(remarkParse).use(remarkGfm);\n}\nlet _processor: ReturnType<typeof buildProcessor> | null = null;\nfunction processor(): ReturnType<typeof buildProcessor> {\n if (!_processor) _processor = buildProcessor();\n return _processor;\n}\n\nexport function collectDefLabels(source: string): DefLabels {\n if (!source) {\n return { footnoteLabels: new Set(), linkLabels: new Set() };\n }\n const mdast = processor().parse(source) as MdastRoot;\n const footnoteLabels = new Set<string>();\n const linkLabels = new Set<string>();\n visit(mdast, (node) => {\n if (node.type === 'footnoteDefinition' && 'identifier' in node) {\n footnoteLabels.add(normalizeId(node.identifier as string));\n } else if (node.type === 'definition' && 'identifier' in node) {\n linkLabels.add(normalizeId(node.identifier as string));\n }\n });\n return { footnoteLabels, linkLabels };\n}\n\nconst setsEqual = (a: Set<string>, b: Set<string>): boolean => {\n if (a.size !== b.size) return false;\n for (const v of a) if (!b.has(v)) return false;\n return true;\n};\n\n/** Blank line (whitespace-only), the boundary no definition can span.\n * CRLF-aware on both newlines — without `\\r?` a CRLF document never\n * matches, the region silently becomes the whole source, and the fast\n * path is vacuously off for that entire input class. */\nconst BLANK_LINE_RE = /\\r?\\n[ \\t]*\\r?\\n/g;\n\n/** Index just past the LAST blank line of `source`, or 0 if none.\n * Plain non-overlapping scan: for runs of blanks (\"\\n\\n\\n\") this can land\n * a newline or two early, but the slack is whitespace-only and whitespace\n * can never satisfy DEF_LINE_START_RE, so the decision is identical.\n * @internal exported for tests only (module path — not on the package barrel) — the fast path is otherwise\n * indistinguishable from a full parse whose sets came out equal. */\nexport function lastRegionStart(source: string): number {\n BLANK_LINE_RE.lastIndex = 0;\n let start = 0;\n for (let m = BLANK_LINE_RE.exec(source); m !== null; m = BLANK_LINE_RE.exec(source)) {\n start = m.index + m[0].length;\n }\n return start;\n}\n\n/** A line that can START a definition, matched by the FULL def signature:\n * container prefixes (blockquote `>`, list bullets, ordered-list digits),\n * then `[label]` with the closing bracket IMMEDIATELY followed by `:` —\n * remark accepts a definition only with that adjacency (grammar-verified:\n * `[x]\\n: url` and `[x] : url` are paragraphs, and `[a][b]: url` is a\n * reference because the label's first unescaped `]` isn't followed by\n * `:`). The label alternation admits escape pairs (`\\]` stays inside the\n * label) and spans newlines (labels may soft-wrap; they cannot cross the\n * blank line that bounds the region). Both alternatives are disjoint, so\n * the scan is linear — no backtracking blowup on bracket-dense regions.\n *\n * Requiring the signature (not just a line-start `[`) is what keeps the\n * streaming-heavy shapes — bulleted link lists `- [t](u)`, task boxes\n * `- [x]`, reference lists `- [a][b]` — on the fast path; a bracket-only\n * probe made every append inside a blank-line-free link list pay a full\n * reparse (the measured Documents+smooth cliff). An INCOMPLETE def line\n * (`[x` with `]:` still in flight) correctly stays on the fast path too:\n * the parser sees no definition in it either, and the region re-check on\n * the completing append flips to the full parse exactly when the answer\n * can change. The `m` flag also matches at index 0, which is a true line\n * start (the region begins just past a blank line or at the document\n * start). Residual over-matching (e.g. `[x]:` inside an open code fence)\n * is safe: it costs a redundant full parse, never a wrong result.\n * @internal exported for tests only (module path — not on the package barrel). */\nexport const DEF_LINE_START_RE = /^[ \\t>*+\\d.)-]*\\[(?:[^\\]\\\\]|\\\\[\\s\\S])*\\]:/m;\n\nexport interface DefLabelScanner {\n /** Equivalent to `collectDefLabels(source)` at every call, but cheap for\n * the streaming common case. Returns a REFERENCE-STABLE result while the\n * label set is unchanged. */\n scan(source: string): DefLabels;\n}\n\n/**\n * Append-aware wrapper around {@link collectDefLabels} for the streaming\n * hot path: PASS 0 re-runs on every token, but its result — the def label\n * set — almost never changes while prose streams in.\n *\n * Fast path: when the new source merely APPENDS to the previous one, the\n * label set can only differ if the affected region contains a line-start\n * `[label]:` def signature (see DEF_LINE_START_RE — mid-line brackets,\n * bulleted links, task boxes and reference lists all lack the adjacent\n * `]:` and stay on the fast path). That region is the previous source's\n * text SINCE ITS LAST BLANK LINE plus the appended text — not just the\n * appended text, because CommonMark definitions span lines (`[x]:` with\n * the destination on the next line) and a trailing append can re-type an\n * entire paragraph (setext `===`). No construct that produces or destroys\n * a definition crosses a blank line (labels, destinations and titles all\n * forbid them), so text before that boundary is settled. When the region\n * has no def-capable line, the previous result is returned AS-IS;\n * otherwise (and for any non-append change) a full re-parse runs, and the\n * previous result object is kept whenever the recomputed sets are equal.\n *\n * Misjudging conservatively (an unnecessary `[` hit — e.g. inside an open\n * code fence) only costs a redundant full parse, never a wrong result.\n *\n * The reference stability doubles as churn control: consumers that list\n * the result in effect deps (chunk re-registration) stop firing per token.\n *\n * @param parse Full-parse fallback — injectable so tests can COUNT parses\n * and assert the fast path actually fires (from the outside, a skipped\n * parse is indistinguishable from a parse whose sets came out equal).\n * Production callers never pass it.\n */\nexport function createDefLabelScanner(parse: (source: string) => DefLabels = collectDefLabels): DefLabelScanner {\n let prevSource: string | null = null;\n let prevLabels: DefLabels | null = null;\n // Frozen-prefix cache (Phase B): labels extracted from the region before\n // `frozenEnd` are FINAL — the freeze boundary guarantees every block\n // beginning before it parses byte-identically under any future append,\n // so a def there can neither appear nor disappear. The checkpoint makes\n // the boundary scan O(new lines) per call; it belongs to this scanner's\n // single append-only lineage (non-append resets it).\n let frozenEnd = 0;\n let frozenFootnotes = new Set<string>();\n let frozenLinks = new Set<string>();\n let checkpoint: FreezeScanCheckpoint | null = null;\n\n const resetFrozen = () => {\n frozenEnd = 0;\n frozenFootnotes = new Set();\n frozenLinks = new Set();\n checkpoint = null;\n };\n\n return {\n scan(source: string): DefLabels {\n let isAppend = false;\n if (prevSource !== null && prevLabels !== null) {\n if (source === prevSource) return prevLabels;\n if (source.startsWith(prevSource)) {\n isAppend = true;\n const regionStart = lastRegionStart(prevSource);\n // Joined so a def line straddling the append boundary keeps its\n // line-start context.\n const region = prevSource.slice(regionStart) + source.slice(prevSource.length);\n if (!DEF_LINE_START_RE.test(region)) {\n prevSource = source;\n return prevLabels;\n }\n }\n }\n // Slow path — the region really may contain a definition. Advance the\n // frozen prefix as far as the boundary allows, then parse ONLY the\n // live tail instead of the whole document.\n if (!isAppend && prevSource !== null) resetFrozen();\n const scanResult = computeFreezeBoundary(source, SCANNER_BOUNDARY_PROFILE, isAppend ? checkpoint : null);\n checkpoint = scanResult.checkpoint;\n // An older freeze is permanently valid — never move backwards even if\n // a later scan reports a smaller boundary (over-blocking direction).\n const boundary = Math.max(scanResult.boundary, frozenEnd);\n if (boundary > frozenEnd) {\n const slice = source.slice(frozenEnd, boundary);\n // The slice can only add labels if it contains a def signature —\n // the same probe that gates the slow path.\n if (DEF_LINE_START_RE.test(slice)) {\n const sliceLabels = parse(slice);\n for (const label of sliceLabels.footnoteLabels) frozenFootnotes.add(label);\n for (const label of sliceLabels.linkLabels) frozenLinks.add(label);\n }\n frozenEnd = boundary;\n }\n const tailSource = source.slice(frozenEnd);\n const tail = DEF_LINE_START_RE.test(tailSource)\n ? parse(tailSource)\n : { footnoteLabels: new Set<string>(), linkLabels: new Set<string>() };\n const next: DefLabels = {\n footnoteLabels: new Set([...frozenFootnotes, ...tail.footnoteLabels]),\n linkLabels: new Set([...frozenLinks, ...tail.linkLabels]),\n };\n if (\n prevLabels !== null &&\n setsEqual(next.footnoteLabels, prevLabels.footnoteLabels) &&\n setsEqual(next.linkLabels, prevLabels.linkLabels)\n ) {\n prevSource = source;\n return prevLabels;\n }\n prevSource = source;\n prevLabels = next;\n return next;\n },\n };\n}\n","/**\n * CommonMark §4.7 label normalization. Used as the single canonical form\n * for all label-keyed structures (registry maps, phantomFootnoteLabels Set,\n * labelSet, etc.) and for handler comparisons against mdast-util-to-hast's\n * internal `state.definitionById` / `state.footnoteById` keys.\n *\n * Delegates to micromark's own `normalizeIdentifier` (collapse\n * `[\\t\\n\\r ]+` runs to one space, STRIP leading/trailing whitespace, then\n * `toLowerCase().toUpperCase()` Unicode case folding) so the result is\n * byte-identical to mdast-util-to-hast's key\n * (`String(identifier).toUpperCase()`, where `identifier` is already\n * micromark-normalized). An earlier hand-rolled version skipped the trim\n * (and used `\\s`, which also folds NBSP): a placeholder carrying the\n * ORIGINAL source label (`[ foo ]`, or `[foo\\nbar]` broken at a soft line\n * ending) looked up `' FOO '` while the def was keyed `'FOO'` — every\n * padded reference fell back to literal text in coordinated mode only\n * (2026-08 project review, eng-stream-01).\n *\n * @module components/normalizeId\n */\nimport { normalizeIdentifier } from 'micromark-util-normalize-identifier';\n\nexport function normalizeId(s: string): string {\n return normalizeIdentifier(s);\n}\n\n/**\n * The form of raw chunk SOURCE that the PASS 0.5 substring pre-check compares\n * registry labels against. It is exactly {@link normalizeId}: micromark's\n * `identifier` (what the registry keys are built from) is the label's\n * source bytes with backslashes KEPT (`[^a\\*b]` → `a\\*b`; only the `label`\n * field is unescaped), so the source must NOT be unescaped before matching\n * — an unescaping pass made every label holding an escaped punctuation\n * character miss the pre-check for good, and the cross-chunk reference\n * rendered as literal `[text][label]` (2026-08-19 review r2 P2-5; the\n * 2.4.5 narrowing to ASCII punctuation kept the wrong premise). Kept as a\n * named export for API stability.\n */\nexport function normalizeForMatch(s: string): string {\n return normalizeIdentifier(s);\n}\n","/**\n * Extract footnote-definition bodies from a chunk's POST-pipeline hast tree.\n *\n * Why not just `toHast(def.children)` in extractContributions? That call runs\n * only mdast-util-to-hast's default handlers — no rehype-katex, no rehype-raw,\n * no rehype-footer-adorn, no clobber-prefix application. Defs containing math\n * (`$x$`), inline raw HTML, or definition-list extensions would render\n * incorrectly inside the cross-chunk aggregate footer.\n *\n * Instead, we read the FINAL hast: mdast-util-to-hast's `state.footer()` has\n * already emitted `<section data-footnotes><ol><li id=\"...fn-X\">body</li>…`\n * for every def that has a real entry in `state.footnoteOrder`, the full\n * rehype chain has run on top, and the per-`<li>` body is exactly what the\n * standalone path would render. Lift those `<li>` children (minus the\n * auto-emitted backref `<a>`s, which the aggregate emits itself per\n * occurrence) and key by normalized label.\n *\n * Chunks whose only refs are phantom-injected (cross-chunk) won't have a\n * synthetic `<section>` at all — those chunks contribute no defs, and the\n * canonical-chunk handler upstream guarantees the def's body is captured\n * from the chunk that owns it.\n *\n * @module components/extractDefBodiesFromHast\n */\nimport { SKIP, visit } from 'unist-util-visit';\nimport type { Element as HastElement, Root as HastRoot, ElementContent } from 'hast';\nimport { normalizeUri } from 'micromark-util-sanitize-uri';\nimport { normalizeId } from './normalizeId';\nimport { isWhitespaceText, lastMeaningfulIdx } from './hastPredicates';\n\n// Fallback for callers that do not know the exact clobberPrefix. The main\n// renderer passes the prefix explicitly so labels containing regex metacharacters\n// or prefixes containing `user-content-fn-` are handled by string slicing.\nconst FN_LI_ID_RE = /(?:^|-)user-content-fn-(.+)$/;\n\n/**\n * The id fragment mdast-util-to-hast derives from a footnote identifier for\n * `fn-…` / `fnref-…` (`normalizeUri(identifier.toLowerCase())` — percent-\n * encodes non-ASCII, whitespace and URL-unsafe punctuation). Every place\n * that MINTS a footnote id — the standalone footer (upstream), the\n * cross-chunk marks and the aggregate footer — must use this same\n * encoding, or a mark's `href` and its `<li id>` disagree (v2.4.0 review:\n * the fallback mark wrote the raw label while the local footer was\n * encoded; `[^注]` / `[^a%b]` anchors broke).\n */\nexport function footnoteSafeId(identifier: string): string {\n return normalizeUri(identifier.toLowerCase());\n}\n\n/**\n * Extract the SOURCE identifier from a footnote `<li>` id, covering both id\n * shapes in the codebase — standalone (mdast-util-to-hast `fn-` +\n * `normalizeUri`, then the sanitize clobber + rehypeRebaseHashLinks linkage)\n * and aggregate (`${clobberPrefix}fn-${sourceIdentifier}`, raw). Exported as\n * the single source of truth for li-id parsing: the streaming cursor's\n * anchor targeting (`detectAnchor`) reuses it so a clobber-linkage change\n * can never drift the two consumers apart.\n */\nexport function sourceIdFromFootnoteLiId(idProp: string, clobberPrefix?: string): string | null {\n let raw: string | null = null;\n if (clobberPrefix !== undefined) {\n const exactPrefix = `${clobberPrefix}fn-`;\n if (idProp.startsWith(exactPrefix)) raw = idProp.slice(exactPrefix.length);\n }\n if (raw === null) {\n const m = idProp.match(FN_LI_ID_RE);\n raw = m ? m[1] : null;\n }\n if (raw === null) return null;\n // mdast-util-to-hast's footer emits `<li id=\"${prefix}fn-${normalizeUri(id)}\">`\n // which percent-encodes whitespace, non-ASCII characters (`中文` → `%E4%B8%AD…`),\n // and most URL-unsafe punctuation. The registry's def key (set by\n // extractContributions via `normalizeId(node.identifier)`) is the DECODED\n // form — uppercase + whitespace-collapsed but otherwise the source bytes.\n // Without decoding here, every label that triggers normalizeUri encoding\n // (CJK, accented Latin, spaces, `&`/`?` punctuation) would key-mismatch\n // between harvested body and registry def, leaving the aggregate footer's\n // `<li>` empty for those labels.\n try {\n return decodeURIComponent(raw);\n } catch {\n // Malformed percent-encoding (extremely rare — would require user-\n // supplied raw HTML in the def's id). Fall back to the raw form rather\n // than crashing the harvest. The raw form will key-mismatch the registry\n // def, so the aggregate footer's `<li>` renders empty for this label —\n // surface that in development instead of failing silently.\n // Bare env access on purpose — the dual dev/prod build resolves it at\n // build time, so dist never evaluates it. The previous `typeof process`\n // guard was dead in bundler browser dev (Vite substitutes only the bare\n // text, `typeof process` stays 'undefined'); do not reintroduce it.\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n `[ai-react-markdown] Malformed percent-encoding in footnote id \"${raw}\"; ` +\n 'its body may be missing from the aggregated footnote footer.'\n );\n }\n return raw;\n }\n}\n\nfunction isBackrefAnchor(c: ElementContent): boolean {\n if (c.type !== 'element') return false;\n const el = c as HastElement;\n if (el.tagName !== 'a') return false;\n return Boolean(el.properties && 'dataFootnoteBackref' in el.properties);\n}\n\n/**\n * Drop trailing auto-emitted backref anchors and any separator whitespace\n * mdast-util-to-hast emitted before them. Operates only on the tail of\n * `children` — does NOT recurse into mid-list elements — so user content\n * elsewhere in the def that happens to look like a backref anchor survives.\n *\n * The shapes we have to undo (see `mdast-util-to-hast/lib/footer.js`):\n *\n * - **trailing wrap whitespace**: `state.wrap(content, true)` inserts\n * `\\n` text nodes between/around block-level children of `<li>`. The\n * auto-emitted backref sits BEFORE the trailing `\\n`, so we have to\n * peel past whitespace before checking for the backref. Confirmed by\n * a real-pipeline trace: an empty def produces\n * `<li>` children = `[\"\\n\", <a backref>, \"\\n\"]`.\n * - **standalone separator** between consecutive backrefs (and before\n * the first one when the trailing child is NOT a text node): a `{type:\n * 'text', value: ' '}` element pushed alongside the backref anchor.\n * - **merged separator** before the first backref when the trailing\n * child IS a text node: footer.js does `tailTail.value += ' '`, so the\n * leading space is concatenated INTO the existing text node rather\n * than pushed as a separate node. After peeling the backrefs, that\n * residual trailing space sits at the end of the last text node and\n * would visibly double when the aggregate footer prepends its own\n * separator. Trim exactly one trailing space to undo it.\n */\nfunction dropTrailingBackrefs(children: ElementContent[]): ElementContent[] {\n // Step 1: identify trailing whitespace-only text nodes. Preserve them\n // verbatim in the output — they're semantically part of mdast-util-to-\n // hast's expected shape and downstream serializers may rely on them.\n let trailingWsStart = children.length;\n while (trailingWsStart > 0 && isWhitespaceText(children[trailingWsStart - 1])) {\n trailingWsStart--;\n }\n // Step 2: scan backwards from the last non-whitespace child, peeling\n // backref anchors and their inter-backref `' '` separators.\n let scan = trailingWsStart;\n let peeledAny = false;\n while (scan > 0) {\n const t = children[scan - 1];\n if (!isBackrefAnchor(t)) break;\n peeledAny = true;\n scan -= 1;\n if (scan > 0 && children[scan - 1].type === 'text' && (children[scan - 1] as { value: string }).value === ' ') {\n scan -= 1;\n }\n }\n if (!peeledAny) return children;\n const trailing = children.slice(trailingWsStart);\n // Step 3: undo the merged-separator case. Trim exactly ONE trailing\n // space from the last surviving text node (matching footer.js's\n // `+= ' '`). Multiple trailing spaces stay intact — only the one\n // footer.js appended is ours to remove. Whitespace-only text nodes\n // (e.g. `\\n`) don't qualify for trim — they aren't merged separators.\n if (scan > 0) {\n const last = children[scan - 1];\n if (last.type === 'text') {\n const v = (last as { value: string }).value;\n if (v.endsWith(' ') && !/^\\s*$/.test(v)) {\n return [...children.slice(0, scan - 1), { ...last, value: v.slice(0, -1) } as ElementContent, ...trailing];\n }\n }\n }\n return [...children.slice(0, scan), ...trailing];\n}\n\n/**\n * Strip mdast-util-to-hast's auto-emitted backref anchors from a `<li>`\n * body. The library only ever appends backrefs in one of two locations:\n * (a) directly at the end of the `<li>`'s children (after `state.wrap`\n * interleaves whitespace nodes between block-level siblings), OR\n * (b) at the end of the last `<p>` child of the `<li>`.\n * We handle both — and nothing else — to avoid stripping any\n * `data-footnote-backref`-shaped element that happens to live in user\n * content elsewhere in the def body.\n */\nfunction stripBackrefs(liChildren: ElementContent[]): ElementContent[] {\n if (liChildren.length === 0) return liChildren;\n // Look past mdast-util-to-hast's trailing `\\n` text node(s) to find the\n // meaningful tail. That tells us which of the two cases applies.\n const lastIdx = lastMeaningfulIdx(liChildren);\n if (lastIdx < 0) return liChildren;\n const last = liChildren[lastIdx];\n\n // Direct-into-li case (case A): meaningful tail IS the backref. Peel\n // from `<li>` children; dropTrailingBackrefs handles the trailing `\\n`.\n if (isBackrefAnchor(last)) {\n return dropTrailingBackrefs(liChildren);\n }\n\n // Inside-<p> case (case B): meaningful tail is `<p>` and backrefs live\n // inside its inline children. `<p>` itself has no wrap-emitted whitespace\n // (state.wrap only fires for block-level lists), so dropTrailingBackrefs\n // can scan the `<p>`'s children directly. Preserve any trailing\n // whitespace nodes that follow the `<p>` in `<li>` exactly as-is.\n if (last.type === 'element' && (last as HastElement).tagName === 'p') {\n const p = last as HastElement;\n const newPChildren = dropTrailingBackrefs(p.children as ElementContent[]);\n if (newPChildren === p.children) return liChildren;\n return liChildren.map((c, i) => (i === lastIdx ? ({ ...p, children: newPChildren } as ElementContent) : c));\n }\n\n return liChildren;\n}\n\n/**\n * Walk `hast` and return a map from normalized footnote label to the\n * cleaned-up body hast of that label's `<li>`. The body has had any\n * `<a data-footnote-backref>` anchors removed at any nesting depth so the\n * aggregate footer can emit its own per-occurrence backrefs without\n * duplicating the locally-injected one.\n */\n/**\n * Walk a body and clear `localOccurrence` props on any `<footnote-sup>`\n * placeholders we find. NESTED footnote refs inside a def body (`[^x]: see\n * [^y]`) emit placeholders whose `localOccurrence` is keyed to the parsing\n * chunk's `state.footnoteCounts`. When the aggregate footer renders the\n * harvested body under the LAST chunk's `ChunkSymbolContext.Provider`,\n * `globalOccurrenceForRef(lastChunkSym, label, localOccurrence)` resolves\n * against the wrong chunk — returning `null` and short-circuiting the\n * inline sup to render blank.\n *\n * The fix degrades gracefully: strip `localOccurrence` from harvested\n * placeholders so `FootnoteSupNumber` falls through to the\n * \"no occurrence supplied\" path — which renders a sup with the bare\n * `fnref-${label}` href (i.e. the first-occurrence anchor). Backref\n * navigation still works (any occurrence href is valid for \"jump back\");\n * the only loss is occurrence-precision for nested footnote refs in\n * aggregate-rendered bodies, which is an edge case GFM permits but rarely\n * exercised in practice. The PRIMARY render (the originating chunk's own\n * block output) is unaffected — it still has the full localOccurrence\n * resolved against the correct chunk symbol.\n */\nfunction stripLocalOccurrenceFromFootnoteSups(children: ElementContent[]): ElementContent[] {\n let changed = false;\n const out: ElementContent[] = [];\n for (const c of children) {\n if (c.type === 'element') {\n const el = c as HastElement;\n let nextEl: HastElement = el;\n if (el.tagName === 'footnote-sup' && el.properties && 'localOccurrence' in el.properties) {\n const { localOccurrence: _drop, ...rest } = el.properties;\n nextEl = { ...el, properties: rest };\n changed = true;\n }\n // Recurse into element children to catch nested placeholders.\n const newChildren = stripLocalOccurrenceFromFootnoteSups(nextEl.children as ElementContent[]);\n if (newChildren !== nextEl.children) {\n nextEl = { ...nextEl, children: newChildren };\n changed = true;\n }\n out.push(nextEl);\n } else {\n out.push(c);\n }\n }\n return changed ? out : children;\n}\n\nexport function extractDefBodiesFromHast(hast: HastRoot, clobberPrefix?: string): Map<string, ElementContent[]> {\n const out = new Map<string, ElementContent[]>();\n visit(hast, 'element', (sectionNode) => {\n const sec = sectionNode as HastElement;\n if (sec.tagName !== 'section') return;\n if (!(sec.properties && 'dataFootnotes' in sec.properties)) return;\n visit(sec, 'element', (liNode) => {\n const li = liNode as HastElement;\n if (li.tagName !== 'li') return;\n const idProp = li.properties?.id;\n if (typeof idProp !== 'string') return;\n const sourceId = sourceIdFromFootnoteLiId(idProp, clobberPrefix);\n if (sourceId === null) return;\n const normalized = normalizeId(sourceId);\n const stripped = stripBackrefs(li.children as ElementContent[]);\n // Defuse any nested `<footnote-sup>` placeholders whose local\n // occurrence indices belong to a different chunk than where the\n // body will eventually be rendered. See the function's JSDoc.\n out.set(normalized, stripLocalOccurrenceFromFootnoteSups(stripped));\n });\n // SKIP descent into this section's children so a NESTED\n // `<section data-footnotes>` (rare — produced only via user-supplied\n // raw HTML inside a def body that survives rehype-raw + sanitize)\n // isn't double-processed by both the outer visit's recursion and the\n // inner visit's enumeration of its parent. Without the SKIP, an\n // `<li>` inside the nested section is harvested twice; `out.set` is\n // last-write-wins so a nested mutation can stomp a correctly-\n // extracted outer body. SKIP scopes harvest to the outer section\n // and leaves nested footnote sections for whatever tool authored\n // them to handle.\n return SKIP;\n });\n return out;\n}\n","/**\n * Walk an mdast tree and yield ref/def records in source order. Used by\n * AIMarkdownContent's PASS 1 contribute step to populate Registry.chunkData.\n *\n * Phantom definitions (Direction B) carry sentinel content/url but the\n * sentinel parse may not produce exactly the sentinel string at the AST\n * level (e.g. `__aimd_sentinel_fn__` parses as <strong>aimd_sentinel_fn</strong>).\n * Therefore phantom detection is done both ways:\n * - linkDef: check `url === SENTINEL_LINK_URL` (raw string survives parsing).\n * - fnDef: skip if the def's normalized identifier is in the supplied\n * `phantomFootnoteLabels` set. The caller knows which labels it\n * injected (PASS 0.5 `targetPhantoms.missingFootnotes`).\n *\n * @module components/extractContributions\n */\nimport { SKIP, visit } from 'unist-util-visit';\nimport type { Root as MdastRoot } from 'mdast';\nimport { normalizeId } from './normalizeId';\nimport { SENTINEL_LINK_URL } from './remarkInjectPhantomDefs';\n\nexport type Contribution =\n | {\n kind: 'ref';\n refKind: 'footnote' | 'link' | 'image';\n label: string;\n referenceType?: 'full' | 'collapsed' | 'shortcut';\n }\n | { kind: 'fnDef'; label: string; sourceIdentifier: string; content: string }\n | { kind: 'linkDef'; label: string; url: string; title?: string };\n\nexport interface ExtractContributionsOptions {\n /** Already-normalized labels that were phantom-injected at PASS 0.5.\n * Defs matching these are skipped to avoid leaking sentinel rows into\n * registry.chunkData. */\n phantomFootnoteLabels?: Set<string>;\n // NOTE: link-definition URLs are emitted RAW. A former `urlTransform`\n // option applied the caller's transform at contribute time as a\n // \"belt-and-suspenders\" pass; it collapsed a protocol-blocked URL to ''\n // BEFORE the render-time gate could tell blocked (attribute absent) from\n // legally empty (`href=\"\"`), and a rewriting transform ran twice\n // (contribute + render) where standalone runs once. The render-time\n // `sanitizeCrossChunkUrl` gate is the single point of enforcement and\n // mirrors the standalone pipeline exactly (v2.4.2 review P1-4).\n}\n\nexport function* extractContributions(\n mdast: MdastRoot,\n options: ExtractContributionsOptions = {}\n): Generator<Contribution> {\n const phantomFn = options.phantomFootnoteLabels;\n const out: Contribution[] = [];\n visit(mdast, (n) => {\n if (n.type === 'footnoteReference') {\n out.push({\n kind: 'ref',\n refKind: 'footnote',\n label: normalizeId((n as { identifier: string }).identifier),\n });\n } else if (n.type === 'linkReference') {\n const r = n as { identifier: string; referenceType: 'full' | 'collapsed' | 'shortcut' };\n out.push({ kind: 'ref', refKind: 'link', label: normalizeId(r.identifier), referenceType: r.referenceType });\n } else if (n.type === 'imageReference') {\n const r = n as { identifier: string; referenceType: 'full' | 'collapsed' | 'shortcut' };\n out.push({ kind: 'ref', refKind: 'image', label: normalizeId(r.identifier), referenceType: r.referenceType });\n } else if (n.type === 'footnoteDefinition') {\n const d = n as { identifier: string; children: unknown[] };\n const label = normalizeId(d.identifier);\n // Skip phantom-injected (by injected-label set, since the sentinel\n // string may not survive markdown parsing intact).\n if (phantomFn?.has(label)) return SKIP;\n // Best-effort raw content snapshot: stringify the first child's\n // structure. Footnote definitions are typed `(BlockContent | DefinitionContent)[]`\n // so we serialize loosely. Used only as a coarse fingerprint string.\n const content = JSON.stringify(d.children ?? []);\n // d.identifier is mdast's already-case-folded form — the same string\n // mdast-util-to-hast uses in `<li id=\"...fn-${id}\">`. Tracked separately\n // from the uppercase-normalized `label` (used as a dictionary key) so\n // HTML ids built downstream match the inline sup's href byte-for-byte.\n //\n // bodyHast is NOT computed here — see extractDefBodiesFromHast for\n // why we source it from the post-pipeline hast instead.\n out.push({ kind: 'fnDef', label, sourceIdentifier: d.identifier, content });\n // SKIP descent into the def's children: NESTED footnoteReferences /\n // linkReferences / imageReferences inside a def body should NOT\n // count as flow refs. Without this, a def whose body contains\n // `[^x]: see [^a].` would record an extra ref to `a` in registry\n // refs — inflating `globalNumber('a')` (making `a` appear in the\n // aggregate footer even if no flow text references it), and worse,\n // inflating `getRefsForLabel('a')` so the aggregate emits a backref\n // anchor to `#fnref-a-2` that points at an id no inline `<sup>`\n // ever rendered. Trade-off: a footnoteDefinition nested INSIDE\n // another def's body (allowed by GFM but exceedingly rare) is also\n // not extracted; deferred until we see a real use case.\n return SKIP;\n } else if (n.type === 'definition') {\n const d = n as { identifier: string; url: string; title?: string };\n if (d.url === SENTINEL_LINK_URL) return;\n out.push({\n kind: 'linkDef',\n label: normalizeId(d.identifier),\n url: d.url,\n title: d.title,\n });\n }\n });\n for (const c of out) yield c;\n}\n","/**\n * Direction B: source-level phantom-definition injection helpers.\n *\n * @module components/remarkInjectPhantomDefs\n */\n\nimport { computeFreezeBoundary, pendingFenceCloser } from './incrementalParse/computeFreezeBoundary';\n\nexport const SENTINEL_LINK_URL = '__aimd_sentinel_link__';\nexport const SENTINEL_FN_CONTENT = '__aimd_sentinel_fn__';\n\nexport interface PhantomLabels {\n missingFootnotes: Set<string>;\n missingLinks: Set<string>;\n}\n\n/**\n * The phantom-definition SUFFIX for labels not locally defined ('' when\n * there are none). Kept separate from the join so the incremental engine\n * can treat it as always-tail: the suffix may shrink/grow/reorder between\n * frames (registry label churn) without breaking the append gate.\n *\n * Labels are expected to already be normalized via normalizeId (uppercase).\n */\nexport function buildPhantomSuffix(phantoms: PhantomLabels): string {\n if (phantoms.missingFootnotes.size === 0 && phantoms.missingLinks.size === 0) {\n return '';\n }\n let suffix = '\\n\\n';\n for (const label of phantoms.missingLinks) {\n suffix += `[${label}]: ${SENTINEL_LINK_URL}\\n`;\n }\n for (const label of phantoms.missingFootnotes) {\n suffix += `[^${label}]: ${SENTINEL_FN_CONTENT}\\n`;\n }\n return suffix;\n}\n\n/**\n * The bytes to put BETWEEN a chunk's content and its phantom suffix so the\n * suffix's definition lines are parsed as definitions.\n *\n * `buildPhantomSuffix` is appended (never prepended: the incremental engine\n * treats the suffix as an always-tail input, and prepending would shift\n * every source position). But an append lands INSIDE whatever block the\n * content ends in — and a fenced code block or `$$` flow-math block that is\n * still open at the end of a streaming frame swallows everything up to EOF:\n * the sentinel lines render as code/math text and, since no definition was\n * registered, every cross-chunk reference in the chunk falls back to literal\n * `[text][label]` for the whole time the block streams (2026-08 project\n * review, core-render-01). Closing the block first is output-neutral: an\n * unclosed fence/math block already renders exactly the lines it has, so\n * `content + closer` yields the same code/math node value (positions\n * extend past `content.length`, which every consumer already tolerates for\n * the suffix's own nodes).\n *\n * A closer is emitted ONLY for a block whose opener line sits at column 0:\n * that is provably a top-level fence, which only a top-level closer (same\n * char, ≥ length, ≤3 spaces indent) can end — exactly what the line scanner\n * tracks. Openers with any indent are left alone: the line model cannot\n * see container boundaries, and an indented opener may live in a list item\n * that later de-indented content already ended (micromark closed the fence\n * with the item; an emitted closer would OPEN a new fence around the\n * sentinel lines — v2.4.0 review R1) or be closed by a ≥4-space closer the\n * `^ {0,3}` scan does not recognize. Those shapes keep the plain append\n * (swallowed at worst — the pre-2.4.0 behaviour), never a wrong closer.\n *\n * Only fences and flow math are closed. Raw-HTML constructs (`<!--`, `<?`,\n * `<![CDATA[`, `<!X`, `<script>`) that stay open to EOF also swallow the\n * suffix (invisibly — sanitize strips them), but their closers are not\n * position-neutral for the paragraph-inline forms and the shapes are rare\n * in LLM output; they keep the plain-append behaviour. When the scanner's\n * fence/math phase is untrusted (`phasePoisonedAt` — a suppressed open in a\n * container, see computeFreezeBoundary blocker 7) no closer is emitted\n * either: a wrong closer would OPEN a block around the suffix.\n *\n * Returns '' when nothing needs closing. Cost: one line scan of `content`\n * (regex per line; no reference tracking) — only paid by chunks that have a\n * non-empty phantom suffix.\n */\nexport function phantomSuffixCloser(content: string): string {\n if (content === '') return '';\n const endsWithNewline = content.endsWith('\\n');\n // Confirm the trailing partial line: the suffix's own leading newline\n // will, so the state that matters is the one AFTER that line.\n const confirmed = endsWithNewline ? content : content + '\\n';\n const { checkpoint } = computeFreezeBoundary(confirmed, { defListEnabled: false, referenceTaint: false });\n // Phase trust and the column-0-only indent rule are the scanner's calls;\n // `pendingFenceCloser` owns them (the checkpoint shape is opaque here).\n const closer = pendingFenceCloser(checkpoint);\n if (closer === '') return '';\n return endsWithNewline ? closer : `\\n${closer}`;\n}\n","/**\n * Cross-chunk shared state. Holds per-chunk contributions (refs, defs,\n * linkDefs) keyed by Symbol identity allocated via useId reactId, with\n * refcount + microtask-deferred reclamation for React Strict Mode safety.\n *\n * @module components/documentRegistry\n */\n\nimport type { ElementContent as HastElementContent } from 'hast';\nimport { normalizeId } from './normalizeId';\n\nexport interface FootnoteDef {\n /** Already-normalized identifier (uppercase). Used as dictionary key for\n * case-insensitive cross-chunk lookups. */\n identifier: string;\n /** mdast's case-folded identifier — the exact string mdast-util-to-hast\n * emits in `<li id=\"${clobberPrefix}fn-${sourceIdentifier}\">` and that\n * `FootnoteSupNumber` mirrors in its anchor href. Needed so the aggregate\n * footer's `<li id>` and backref href match the inline `<sup>`'s href\n * exactly (otherwise hash navigation breaks). Optional so unit-test\n * fixtures don't need to fabricate it; production data always supplies it. */\n sourceIdentifier?: string;\n /** Content extracted from the source markdown footnote definition. */\n contentSource: string;\n /** Per-def hast body (the def's mdast children after mdast-util-to-hast\n * conversion). Drives AggregateFootnotesIfLast to render the consolidated\n * footer at the end of each document's last chunk. Optional so unit-test\n * fixtures can build minimal FootnoteDef objects without producing hast. */\n bodyHast?: HastElementContent[];\n}\n\nexport interface LinkDef {\n /** Already-normalized identifier (uppercase). */\n identifier: string;\n url: string;\n title?: string;\n}\n\nexport type RefKind = 'footnote' | 'link' | 'image';\n\nexport interface RefRecord {\n /** Already-normalized identifier (uppercase). */\n label: string;\n /** Which markdown reference space this entry belongs to. Footnote refs,\n * link refs, and image refs occupy disjoint namespaces in GFM, so they\n * must be filtered separately when computing footnote numbers / refcounts. */\n kind: RefKind;\n referenceType?: 'full' | 'collapsed' | 'shortcut';\n}\n\nexport interface ChunkData {\n refs: RefRecord[];\n defs: Map<string, FootnoteDef>;\n linkDefs: Map<string, LinkDef>;\n ownFootnoteLabels: Set<string>;\n ownLinkLabels: Set<string>;\n}\n\n/**\n * Public, read-only view of the cross-chunk registry. This is the type\n * surfaced by `useDocumentRegistry` and re-exported from the package\n * barrel. Consumers can:\n *\n * - read the registry's current state (`chunkOrder`, `chunkData`,\n * `labelSet`, `version`)\n * - observe changes (`subscribe`)\n * - run selectors (`globalNumber`, `resolveLinkDef`, …)\n *\n * Mutators — `registerChunk`, `allocateSymbol`, `releaseSymbol`,\n * `contributeLabels`, `contributeChunkData` — are intentionally off this\n * interface. Driving the registry directly is reserved for internal\n * coordinators (the package's own `MarkdownContent` renderer) and tests,\n * which import the wider `RegistryInternal` type from this module.\n * `RegistryInternal` is exported from this engine package (the core\n * renderer consumes it) but NOT from `@ai-react-markdown/core`'s public\n * barrel — keeping mutators off the consumer-facing surface prevents a\n * misbehaving consumer-component from corrupting refcounts, skipping\n * version bumps, or otherwise breaking the invariants the renderer relies\n * on.\n */\nexport interface Registry {\n /** Chunk mount-order Symbol list. **Read-only.** Direct mutation\n * (`.push`, `.splice`, index assignment) corrupts footnote numbering,\n * \"last chunk\" detection, and eviction. */\n readonly chunkOrder: readonly symbol[];\n /** Chunk Symbol → contribution payload. **Read-only.** Direct `.set` /\n * `.delete` bypasses version bumps and subscriber wake-ups. */\n readonly chunkData: ReadonlyMap<symbol, ChunkData>;\n /** Union of own-def labels across all chunks. PASS 0.5 phantom-injection\n * driver. **Read-only.** The registry derives this from per-chunk\n * contributions; direct mutation breaks the derivation. */\n readonly labelSet: {\n readonly footnoteLabels: ReadonlySet<string>;\n readonly linkLabels: ReadonlySet<string>;\n };\n /** Monotonic version counter bumped by every mutation. **Read-only** —\n * consumers should observe via `subscribe`, not by writing. */\n readonly version: number;\n\n subscribe(cb: () => void): () => void;\n\n // Selectors — pure reads over chunkOrder × chunkData, recomputed on every\n // call (NOT memoized: each is a linear walk of the registry; placeholder\n // components already gate their re-renders on `version`, so callers pay\n // one walk per registry mutation, not per render).\n canonicalFootnoteFor(label: string): symbol | null;\n canonicalLinkFor(label: string): symbol | null;\n globalNumber(label: string): number | null;\n /**\n * Resolve a cross-chunk link definition by label. The returned `url` is\n * the RAW destination from the contributing chunk's source — the registry\n * does not sanitize. The library's cross-chunk link/image placeholders run\n * the full per-attribute sanitization (`sanitizeSchema.protocols` +\n * `urlTransform`, correct key) at render time.\n *\n * Consumers reading `def.url` directly (custom backlink panels, analytics,\n * dev tooling) MUST run their own policy before rendering it as an\n * `href`/`src` — a chunk can define `[evil]: javascript:alert(1)`.\n */\n resolveLinkDef(label: string): LinkDef | null;\n getRefsForLabel(label: string): number;\n /** Map a chunk-local footnote-ref occurrence index (1-based, as emitted by\n * `customMdastHandlers`) to the corresponding document-wide occurrence\n * index across all chunks. Used by `FootnoteSupNumber` to build a unique\n * `id=\"fnref-X-N\"` for each ref instance and by `AggregateFootnotesIfLast`\n * to enumerate per-occurrence backrefs. Returns `null` if the ref isn't\n * registered yet (registry mid-flight). */\n globalOccurrenceForRef(chunkSym: symbol, label: string, localOccurrence: number): number | null;\n}\n\n/**\n * Internal registry surface — extends {@link Registry} with the mutator\n * methods and implementation-private fields (reactId-keyed refcount table,\n * subscriber set, microtask-coalesce flag, `_notify` itself).\n *\n * Exported from this module (and the engine barrel) so internal\n * coordinators (`MarkdownContent`) and tests can hold a strongly-typed\n * reference, but **not** re-exported from `@ai-react-markdown/core`'s\n * barrel — a consumer flipping `_notifyScheduled = true`\n * or pushing into `chunkOrder` directly would silently break the\n * coalesce / numbering invariants. The runtime value returned by\n * {@link createRegistry} always satisfies this wider shape; public consumers\n * just see the narrowed {@link Registry} view.\n */\nexport interface RegistryInternal extends Registry {\n /** Allocate (or reuse, for Strict Mode remount) the chunk Symbol for\n * `reactId` AND publish this chunk's own def labels (footnotes + links)\n * in one call. Canonical pair API used by `MarkdownContent`'s allocate\n * effect — combining the two reduces the pair to a single registry\n * version step, which downstream consumers see as one wake-up rather\n * than two (the second was already coalesced by microtask, but this\n * keeps the version monotonic-by-1-per-mount which makes debugging\n * easier). The granular `allocateSymbol` / `contributeLabels` methods\n * remain available for tests that need to exercise each step. */\n registerChunk(reactId: string, footnotes: Set<string>, links: Set<string>, documentIndex?: number): symbol;\n /** `documentIndex` — the chunk's position in the DOCUMENT (not its mount\n * order). Without it a chunk joins `chunkOrder` at the end, which is\n * wrong for any list that unmounts and remounts chunks: a virtualized\n * transcript scrolling back re-registers an earlier chunk after the ones\n * still mounted, and footnote numbering plus \"which chunk renders the\n * aggregate footer\" follow that order (2026-08-19 review r2 P2-10).\n * Chunks that supply an index are kept sorted by it; chunks without one\n * keep mount order after them. */\n allocateSymbol(reactId: string, documentIndex?: number): symbol;\n /** @internal Insert a chunk Symbol at its document position. */\n _placeChunk(sym: symbol, documentIndex?: number): void;\n releaseSymbol(reactId: string): void;\n contributeLabels(symbol: symbol, footnotes: Set<string>, links: Set<string>): void;\n contributeChunkData(symbol: symbol, data: ChunkData): void;\n\n _reactIdMap: Map<string, { symbol: symbol; refcount: number }>;\n /** Symbol → the `documentIndex` its chunk supplied (see allocateSymbol). */\n _chunkIndex: Map<symbol, number>;\n _subscribers: Set<() => void>;\n _notifyScheduled: boolean;\n _notify(): void;\n}\n\n/**\n * Construct a new Registry. `onEmpty`, if supplied, is invoked once each\n * time the registry transitions to \"no chunks alive\" — i.e. the last\n * tracked chunk's deferred `releaseSymbol` cleanup just removed its\n * entry, leaving `chunkOrder` and `chunkData` both empty. The container\n * uses this to evict the registry from its `documentId → Registry` map\n * so long-lived SPAs that cycle through many `documentId` values don't\n * accumulate empty shells.\n *\n * `onEmpty` fires synchronously from inside the releaseSymbol microtask,\n * so the registry's state is guaranteed quiescent during the callback —\n * no other code can interleave between the empty-state check and the\n * caller's eviction logic.\n */\nexport function createRegistry(onEmpty?: () => void): RegistryInternal {\n const reg = {\n chunkOrder: [] as symbol[],\n chunkData: new Map<symbol, ChunkData>(),\n labelSet: { footnoteLabels: new Set<string>(), linkLabels: new Set<string>() },\n version: 0,\n _reactIdMap: new Map<string, { symbol: symbol; refcount: number }>(),\n /** Symbol → its `documentIndex`, for chunks that supplied one. */\n _chunkIndex: new Map<symbol, number>(),\n _subscribers: new Set<() => void>(),\n _notifyScheduled: false,\n\n allocateSymbol(reactId: string, rawDocumentIndex?: number): symbol {\n // `NaN` compares false against everything, so it would act as a sort\n // BARRIER (no later chunk ever breaks in front of it) rather than being\n // ignored. Treat any non-finite value as \"no index\".\n const documentIndex =\n rawDocumentIndex !== undefined && Number.isFinite(rawDocumentIndex) ? rawDocumentIndex : undefined;\n if (process.env.NODE_ENV !== 'production' && rawDocumentIndex !== undefined && documentIndex === undefined) {\n console.warn(\n `[ai-react-markdown] documentIndex must be a finite number — received ${String(rawDocumentIndex)}; ignoring it for this chunk.`\n );\n }\n const existing = this._reactIdMap.get(reactId);\n if (existing) {\n existing.refcount++;\n // A LIVE chunk re-registering with a different position (the effect\n // deps include `documentIndex`, so a consumer reordering chunks\n // without remounting them lands here): move it. StrictMode's\n // double-invoke passes the same value and falls through unchanged.\n // Presence, not just value: going back to `undefined` (a consumer\n // that computes the index conditionally) must ALSO take effect —\n // otherwise `_chunkIndex` keeps a value nobody supplies and\n // `_placeChunk`'s scan steers OTHER chunks by it. Testing\n // `get(...) !== documentIndex` alone would regress the common case:\n // `get` returns undefined for un-indexed chunks too, so every\n // un-indexed chunk would jump to the tail on each re-register (which\n // happens on every `ownLabels` change while streaming).\n const moved =\n documentIndex !== undefined\n ? this._chunkIndex.get(existing.symbol) !== documentIndex\n : this._chunkIndex.has(existing.symbol);\n if (moved) {\n const at = this.chunkOrder.indexOf(existing.symbol);\n if (at !== -1) this.chunkOrder.splice(at, 1);\n this._placeChunk(existing.symbol, documentIndex);\n this._notify();\n }\n return existing.symbol;\n }\n const sym = Symbol(reactId);\n this._reactIdMap.set(reactId, { symbol: sym, refcount: 1 });\n this._placeChunk(sym, documentIndex);\n this._notify();\n return sym;\n },\n\n /** Put `sym` into `chunkOrder` at its document position. Without an index\n * it goes last (mount order — the historical behaviour); with one it\n * sorts before the first chunk that sits later, where a chunk WITHOUT an\n * index counts as \"later\" so an indexed chunk never lands behind one\n * whose position is unknown. */\n _placeChunk(sym: symbol, documentIndex?: number): void {\n if (process.env.NODE_ENV !== 'production' && this.chunkOrder.length > 0) {\n // Mixing the two modes under one documentId is the default failure of\n // a partial migration, and it FAILS LIKE THE BUG the prop exists to\n // fix: every un-indexed chunk sorts after every indexed one, so\n // numbering stops following DOM order and the aggregate footer lands\n // on the last-MOUNTED un-indexed chunk (oracle review of 2.5.0).\n const anyIndexed = documentIndex !== undefined || this.chunkOrder.some((s) => this._chunkIndex.has(s));\n const anyPlain = documentIndex === undefined || this.chunkOrder.some((s) => !this._chunkIndex.has(s));\n if (anyIndexed && anyPlain) {\n console.warn(\n '[ai-react-markdown] Some chunks of this document supply `documentIndex` and some do not. ' +\n 'Indexed chunks always sort ahead of un-indexed ones, so footnote numbering and aggregate-footer ' +\n 'placement will not follow document order. Pass `documentIndex` to every chunk, or to none.'\n );\n }\n }\n if (documentIndex === undefined) {\n this._chunkIndex.delete(sym);\n this.chunkOrder.push(sym);\n return;\n }\n this._chunkIndex.set(sym, documentIndex);\n let at = this.chunkOrder.length;\n for (let i = 0; i < this.chunkOrder.length; i++) {\n const other = this._chunkIndex.get(this.chunkOrder[i]);\n if (other === undefined || other > documentIndex) {\n at = i;\n break;\n }\n }\n this.chunkOrder.splice(at, 0, sym);\n },\n\n registerChunk(reactId: string, footnotes: Set<string>, links: Set<string>, documentIndex?: number): symbol {\n // Composition of allocateSymbol + contributeLabels. Both `_notify`\n // calls coalesce into a single microtask wake-up, so the perf\n // shape is the same as the granular pair — the API just expresses\n // the canonical \"register one chunk\" intent.\n const sym = this.allocateSymbol(reactId, documentIndex);\n this.contributeLabels(sym, footnotes, links);\n return sym;\n },\n\n releaseSymbol(reactId: string): void {\n const entry = this._reactIdMap.get(reactId);\n if (!entry) return;\n if (entry.refcount <= 0) {\n // Already fully released and awaiting the deferred cleanup (or a\n // caller released more than it allocated). Decrementing further\n // would park the refcount below zero, where the `=== 0` cleanup\n // check never fires and the chunk leaks forever with onEmpty\n // eviction disabled (2026-08 project review, eng-stream-03).\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n `[ai-react-markdown] Registry.releaseSymbol(\"${reactId}\") called with no matching allocateSymbol — ignoring (unbalanced release).`\n );\n }\n return;\n }\n entry.refcount--;\n if (entry.refcount === 0) {\n queueMicrotask(() => {\n const latest = this._reactIdMap.get(reactId);\n if (latest && latest.refcount === 0) {\n this._reactIdMap.delete(reactId);\n const idx = this.chunkOrder.indexOf(entry.symbol);\n if (idx !== -1) this.chunkOrder.splice(idx, 1);\n this._chunkIndex.delete(entry.symbol);\n this.chunkData.delete(entry.symbol);\n // Rebuild labelSet from the surviving chunks. The contribute paths\n // (`contributeLabels`, `contributeChunkData`) already rebuild this\n // union on every write, but a chunk that simply UNMOUNTS would\n // otherwise leave `labelSet` referencing labels that no live chunk\n // owns. Downstream consumers (`targetPhantoms` in\n // `MarkdownContent`) read `registry.labelSet` to gate phantom\n // injection — without this rebuild, surviving chunks would keep\n // treating refs to the released chunk's labels as phantom, while\n // `canonicalFootnoteFor` (which walks live chunkData) returns\n // null, leaving inline `<sup>` anchors pointing at `<li>` ids\n // that the aggregate footer never renders.\n const nextFn = new Set<string>();\n const nextLink = new Set<string>();\n for (const cd of this.chunkData.values()) {\n for (const l of cd.ownFootnoteLabels) nextFn.add(l);\n for (const l of cd.ownLinkLabels) nextLink.add(l);\n }\n this.labelSet.footnoteLabels = nextFn;\n this.labelSet.linkLabels = nextLink;\n this._notify();\n // Last chunk just left: notify the container so it can drop\n // this registry from its `documentId → Registry` map. The\n // identity check on the container side prevents racing a\n // freshly-allocated registry under the same documentId.\n //\n // Ordering note: `onEmpty` fires SYNCHRONOUSLY here, after\n // `_notify` has scheduled subscriber fanout (which itself\n // runs in a later microtask, see `_notifyScheduled`). So\n // the container evicts FIRST, then subscribers wake. A\n // subscriber that re-resolves via `getRegistry(documentId)`\n // during its wake-up therefore sees a freshly-allocated\n // registry — which is the right behavior, because by then\n // the consumer is genuinely starting over.\n if (this.chunkOrder.length === 0 && this.chunkData.size === 0 && onEmpty) {\n onEmpty();\n }\n }\n });\n }\n },\n\n contributeLabels(symbol: symbol, footnotes: Set<string>, links: Set<string>): void {\n // A released or never-allocated symbol must not grow chunkData: the\n // ghost entry would keep `chunkData.size === 0` from ever holding and\n // the registry would never be evicted (v2.4.1 review). Effects racing\n // an unmount can legitimately land here — ignore, do not throw.\n if (!this.chunkOrder.includes(symbol)) return;\n const data = this.chunkData.get(symbol);\n if (data) {\n data.ownFootnoteLabels = footnotes;\n data.ownLinkLabels = links;\n } else {\n this.chunkData.set(symbol, {\n refs: [],\n defs: new Map(),\n linkDefs: new Map(),\n ownFootnoteLabels: footnotes,\n ownLinkLabels: links,\n });\n }\n // Always notify. The prior `if (fnChanged || linkChanged)` optimization\n // skipped the wake-up when the UNION labelSet was unchanged — but\n // chunkData has ALWAYS mutated by the time we reach this line (we either\n // overwrote ownFootnoteLabels/ownLinkLabels on an existing entry, or we\n // just created a fresh chunkData entry above). A subscriber keyed on\n // `registry.version` would observe live chunkData changing under a\n // stable snapshot — a useSyncExternalStore tearing violation. With the\n // microtask-coalesced `_notify`, the per-call cost is the version++\n // plus a single subscriber fanout per batch, so the optimization's\n // savings are nil; correctness wins.\n const newFn = new Set<string>();\n const newLink = new Set<string>();\n for (const cd of this.chunkData.values()) {\n for (const l of cd.ownFootnoteLabels) newFn.add(l);\n for (const l of cd.ownLinkLabels) newLink.add(l);\n }\n this.labelSet.footnoteLabels = newFn;\n this.labelSet.linkLabels = newLink;\n this._notify();\n },\n\n contributeChunkData(symbol: symbol, data: ChunkData): void {\n if (!this.chunkOrder.includes(symbol)) return; // see contributeLabels\n this.chunkData.set(symbol, data);\n // Rebuild labelSet too (data may extend or shrink it)\n this.labelSet.footnoteLabels = new Set();\n this.labelSet.linkLabels = new Set();\n for (const cd of this.chunkData.values()) {\n for (const l of cd.ownFootnoteLabels) this.labelSet.footnoteLabels.add(l);\n for (const l of cd.ownLinkLabels) this.labelSet.linkLabels.add(l);\n }\n this._notify();\n },\n\n subscribe(cb: () => void): () => void {\n this._subscribers.add(cb);\n return () => {\n this._subscribers.delete(cb);\n };\n },\n\n canonicalFootnoteFor(label: string): symbol | null {\n const id = normalizeId(label);\n for (const sym of this.chunkOrder) {\n const data = this.chunkData.get(sym);\n if (data?.defs.has(id)) return sym;\n }\n return null;\n },\n\n canonicalLinkFor(label: string): symbol | null {\n const id = normalizeId(label);\n for (const sym of this.chunkOrder) {\n const data = this.chunkData.get(sym);\n if (data?.linkDefs.has(id)) return sym;\n }\n return null;\n },\n\n globalNumber(label: string): number | null {\n const id = normalizeId(label);\n let n = 0;\n const seen = new Set<string>();\n for (const sym of this.chunkOrder) {\n const data = this.chunkData.get(sym);\n if (!data) continue;\n for (const ref of data.refs) {\n // Footnote numbering is a per-space ordinal; link/image refs share\n // the `refs` array but occupy a disjoint namespace, so they must\n // NOT advance the footnote counter.\n if (ref.kind !== 'footnote') continue;\n if (!seen.has(ref.label)) {\n seen.add(ref.label);\n n++;\n if (ref.label === id) return n;\n }\n }\n }\n return null;\n },\n\n resolveLinkDef(label: string): LinkDef | null {\n const sym = this.canonicalLinkFor(label);\n if (!sym) return null;\n return this.chunkData.get(sym)?.linkDefs.get(normalizeId(label)) ?? null;\n },\n\n getRefsForLabel(label: string): number {\n const id = normalizeId(label);\n let n = 0;\n for (const sym of this.chunkOrder) {\n const data = this.chunkData.get(sym);\n if (!data) continue;\n // Only count footnote refs: the consumers (backref-strip and\n // backref-inject) decide based on whether a footnote `<li>` should\n // exist, which depends on footnote refs alone.\n for (const ref of data.refs) {\n if (ref.kind === 'footnote' && ref.label === id) n++;\n }\n }\n return n;\n },\n\n globalOccurrenceForRef(chunkSym: symbol, label: string, localOccurrence: number): number | null {\n const id = normalizeId(label);\n let global = 0;\n for (const sym of this.chunkOrder) {\n const data = this.chunkData.get(sym);\n if (!data) continue;\n let localCount = 0;\n for (const ref of data.refs) {\n if (ref.kind !== 'footnote') continue;\n if (ref.label !== id) continue;\n localCount++;\n global++;\n if (sym === chunkSym && localCount === localOccurrence) return global;\n }\n }\n return null;\n },\n\n _notify(): void {\n this.version++;\n if (this._notifyScheduled) return;\n this._notifyScheduled = true;\n queueMicrotask(() => {\n this._notifyScheduled = false;\n // Snapshot subscribers so unsubscribes during fanout don't shift the\n // iteration. New subscribers added during fanout will pick up the\n // current `version` on their next render.\n for (const cb of [...this._subscribers]) cb();\n });\n },\n };\n // Internally `reg` has both the public API and the private state.\n // The return type is {@link RegistryInternal} so internal callers\n // (`MarkdownContent`, tests) hold a strongly-typed handle to the\n // mutators and private state. Public consumers see only the narrow\n // {@link Registry} via `useDocumentRegistry`'s return type.\n return reg as unknown as RegistryInternal;\n}\n","/**\n * THE single source of the production plugin chain.\n *\n * `MarkdownContent`'s memos, the splice-equivalence arbiter's option\n * catalog (`incrementalParse/testPluginCatalog.ts`), and the prefixFreeze\n * experiment harness all build their chains HERE — plugin-order drift\n * between the renderer and its verification suites previously required\n * hand-synchronized copies, and a missed copy would silently leave the\n * arbiter testing a non-production pipeline.\n *\n * Two deliberate NON-consumers, kept as independent mirrors on purpose:\n * - `byteEquivalence.test.tsx`'s `legacyPlugins()` — it is the REFERENCE\n * implementation the new pipeline is compared against; importing this\n * module would make that comparison circular.\n * - `positionPropagation.test.ts` — it pins the position-retention\n * contract of the exact stack and must fail loudly when the stack\n * changes, not silently follow it.\n *\n * @module components/pluginChain\n */\n\nimport rehypeKatex from 'rehype-katex';\nimport rehypeRaw from '@ai-markdown/rehype-raw';\nimport rehypeUnwrapImages from 'rehype-unwrap-images';\nimport { rehypeUnwrapCrossChunkImages } from './rehypeUnwrapCrossChunkImages';\nimport rehypeSanitize from 'rehype-sanitize';\nimport remarkBreaks from 'remark-breaks';\nimport remarkCjkFriendly from 'remark-cjk-friendly';\nimport remarkCjkFriendlyGfmStrikethrough from 'remark-cjk-friendly-gfm-strikethrough';\nimport remarkEmoji from 'remark-emoji';\nimport remarkGfm from 'remark-gfm';\nimport remarkMath from 'remark-math';\nimport { remarkDefinitionList, defListHastHandlers } from 'remark-definition-list';\nimport { remarkMark as remarkMarkHighlight } from '@ai-react-markdown/remark-mark-highlight';\nimport remarkSqueezeParagraphs from 'remark-squeeze-paragraphs';\nimport remarkSmartypants from 'remark-smartypants';\nimport remarkPangu from 'remark-pangu';\nimport remarkRemoveComments from 'remark-remove-comments';\n\nimport type { PipelineOptions as MarkdownOptions } from './markdown';\nimport rehypeRebaseHashLinks from './rehypeRebaseHashLinks';\nimport rehypeFooterAdorn from './rehypeFooterAdorn';\nimport type { SanitizeSchema } from './extendSanitizeSchema';\nimport type { AIMarkdownEnginePlugin, AIMarkdownEnginePluginName } from '../plugins/defs';\n\nexport type RemarkPlugins = NonNullable<MarkdownOptions['remarkPlugins']>;\nexport type RehypePlugins = NonNullable<MarkdownOptions['rehypePlugins']>;\nexport type RemarkRehypeOptions = NonNullable<MarkdownOptions['remarkRehypeOptions']>;\n\n/**\n * Per-stage chain tables: sealed plugin name → unified plugin, in CANONICAL\n * chain order. The tables (not the caller's array order) fix each plugin's\n * splice position — required for the produced-chain byte-equivalence\n * guarantee to be checkable. The heavy unified imports stay in THIS module\n * so the `/plugins` subpath catalog remains a lightweight descriptor set.\n */\nconst EXTRA_SYNTAX_CHAIN: ReadonlyArray<readonly [AIMarkdownEnginePluginName, RemarkPlugins[number]]> = [\n ['highlight', remarkMarkHighlight as RemarkPlugins[number]],\n ['definitionList', remarkDefinitionList as RemarkPlugins[number]],\n];\nconst DISPLAY_OPTIMIZE_CHAIN: ReadonlyArray<readonly [AIMarkdownEnginePluginName, RemarkPlugins[number]]> = [\n ['removeComments', remarkRemoveComments as RemarkPlugins[number]],\n ['smartypants', remarkSmartypants as RemarkPlugins[number]],\n ['pangu', remarkPangu as RemarkPlugins[number]],\n];\n\n/** The always-on remark chain with plugin-gated extras spliced at their\n * contractual positions. ORDER IS LOAD-BEARING — see the arbiter suite. */\nexport function buildCoreRemarkPlugins(enginePlugins: readonly AIMarkdownEnginePlugin[]): RemarkPlugins {\n const selected = new Set<string>(enginePlugins.map((plugin) => plugin.name));\n return [\n // --- Core plugins (always active) ---\n remarkGfm,\n [\n remarkMath,\n {\n // Disable single-dollar inline math to avoid conflicts with currency\n // signs and other dollar usages; the preprocessor converts $...$ to $$...$$.\n singleDollarTextMath: false,\n },\n ],\n // --- Selectable extra syntax plugins (canonical table order) ---\n ...EXTRA_SYNTAX_CHAIN.filter(([name]) => selected.has(name)).map(([, plugin]) => plugin),\n // --- Formatting & normalization ---\n remarkBreaks,\n remarkEmoji,\n remarkSqueezeParagraphs,\n remarkCjkFriendly,\n remarkCjkFriendlyGfmStrikethrough,\n // --- Selectable display optimizations (canonical table order) ---\n ...DISPLAY_OPTIMIZE_CHAIN.filter(([name]) => selected.has(name)).map(([, plugin]) => plugin),\n ] as RemarkPlugins;\n}\n\n/** The rehype chain. `clobberPrefix` namespaces ids per instance; pass ''\n * for unprefixed output (test harnesses). */\nexport function buildCoreRehypePlugins(sanitizeSchema: SanitizeSchema, clobberPrefix: string): RehypePlugins {\n return [\n // Allow raw HTML through so rehype-sanitize can handle it.\n [rehypeRaw, { passThrough: [] }],\n // Sanitize HTML while allowing <mark> (highlight), KaTeX class names,\n // and any extra protocols the caller permitted via the `sanitizeSchema`\n // prop. Override `clobberPrefix` with the instance-scoped value — the\n // spread order is intentional: our prefix wins over any caller-supplied\n // prefix on the schema.\n [rehypeSanitize, { ...sanitizeSchema, clobberPrefix }],\n // Normalize the auto-generated `<section data-footnotes>`: strip the\n // sr-only `<h2>Footnotes</h2>` label and prepend `<hr>`. Keeps standalone\n // single-doc rendering visually consistent with the cross-chunk aggregate\n // footer (which builds the same shape from scratch).\n rehypeFooterAdorn,\n // Re-prefix intra-document hash hrefs so they match the ids that\n // rehype-sanitize just clobbered. Must use the SAME prefix as the schema\n // above.\n [rehypeRebaseHashLinks, { prefix: clobberPrefix }],\n rehypeKatex,\n rehypeUnwrapImages,\n // Same unwrap for `<cross-chunk-image>` placeholders (coordinated mode);\n // no-op on standalone documents.\n rehypeUnwrapCrossChunkImages,\n ] as RehypePlugins;\n}\n\n/** Base remark-rehype options (before the standalone/coordinated handler\n * merge that `MarkdownContent`'s pipeline memo layers on top). */\nexport function buildCoreRemarkRehypeOptions(enableDefinitionList: boolean): RemarkRehypeOptions {\n return {\n allowDangerousHtml: true,\n // Suppress mdast-util-to-hast's `user-content-` prefix on footnote\n // ids/hrefs; rehype-sanitize will apply the same prefix downstream\n // and `rehypeRebaseHashLinks` mirrors it onto matching hash hrefs.\n // Without this, ids would end up double-prefixed\n // (`user-content-user-content-fn-x`).\n clobberPrefix: '',\n handlers: {\n // Inject definition-list HAST handlers when the extension is active.\n ...(enableDefinitionList ? defListHastHandlers : {}),\n },\n };\n}\n","/**\n * Mirror of `rehype-unwrap-images` for the coordinated pipeline's\n * placeholders. Upstream unwraps a `<p>` whose content is only images (and\n * whitespace, or links wrapping only images) — but it only knows `<img>` /\n * `<a>`. In coordinated mode a reference-style image is a\n * `<cross-chunk-image>` placeholder (a link a `<cross-chunk-link>`), so\n * `![pic][x]` alone in a paragraph stayed wrapped: `<p><img></p>` where\n * the standalone render is a bare `<img>` (v2.4.0 review — the wrapped\n * server output diverged from standalone, and the client resolved path had\n * always differed). Runs AFTER rehype-unwrap-images with the same rule,\n * extended to the placeholder tags. Standalone documents contain no\n * placeholders, so this is a no-op there.\n *\n * @module components/rehypeUnwrapCrossChunkImages\n */\nimport type { Element, ElementContent, Root } from 'hast';\nimport { SKIP, visit } from 'unist-util-visit';\n\nconst IMAGE_TAGS = new Set(['img', 'cross-chunk-image']);\nconst LINK_TAGS = new Set(['a', 'cross-chunk-link']);\n\nconst enum Verdict {\n Unknown,\n ContainsImage,\n ContainsOther,\n}\n\n/** `seen.placeholder` flips when any placeholder tag (image OR link) took\n * part in the verdict — only such paragraphs are ours to unwrap; plain\n * `<img>`/`<a>` paragraphs were already unwrapped by rehype-unwrap-images. */\nfunction applicable(node: Element, inLink: boolean, seen: { placeholder: boolean }): Verdict {\n let image = Verdict.Unknown;\n for (const child of node.children as ElementContent[]) {\n if (child.type === 'text' && /^\\s*$/.test(child.value)) continue;\n if (child.type === 'element' && IMAGE_TAGS.has(child.tagName)) {\n if (child.tagName !== 'img') seen.placeholder = true;\n image = Verdict.ContainsImage;\n } else if (!inLink && child.type === 'element' && LINK_TAGS.has(child.tagName)) {\n if (child.tagName !== 'a') seen.placeholder = true;\n const inner = applicable(child, true, seen);\n if (inner === Verdict.ContainsOther) return Verdict.ContainsOther;\n if (inner === Verdict.ContainsImage) image = Verdict.ContainsImage;\n } else {\n return Verdict.ContainsOther;\n }\n }\n return image;\n}\n\nexport function rehypeUnwrapCrossChunkImages() {\n return function transform(tree: Root): void {\n visit(tree, 'element', (node, index, parent) => {\n if (node.tagName !== 'p' || !parent || typeof index !== 'number') return;\n // Only paragraphs where a placeholder took part — an image placeholder\n // OR a link placeholder around a plain `<img>` (`[![pic](url)][ref]`,\n // v2.4.1 review: the old guard only looked for the image tag).\n const seen = { placeholder: false };\n if (applicable(node, false, seen) === Verdict.ContainsImage && seen.placeholder) {\n parent.children.splice(index, 1, ...node.children);\n return [SKIP, index];\n }\n });\n };\n}\n","/**\n * `rehypeRebaseHashLinks` — restore intra-document hash navigation after\n * `rehype-sanitize` clobbers `id` attributes.\n *\n * ### Why this exists\n *\n * `rehype-sanitize` defends against ID-clobbering attacks (e.g. a malicious\n * `<div id=\"window\">` shadowing `window.window`) by prefixing every clobberable\n * attribute (`id`, `name`, `aria-describedby`, `aria-labelledby`) with\n * `clobberPrefix` (default `'user-content-'`). It does **not** rewrite `href`\n * values, since hashes are not themselves clobbering vectors. As a result,\n * any intra-document link — `[ref](#section)`, GFM footnote anchors, or raw\n * `<a id=\"x\"><a href=\"#x\">` pairs — points at an unprefixed hash while its\n * target id has been prefixed: navigation breaks.\n *\n * Pair this plugin with `remarkRehypeOptions: { clobberPrefix: '' }` so that\n * `mdast-util-to-hast` does not also prefix (avoiding `user-content-user-content-`\n * double prefixes), and place it **after** `rehype-sanitize` in the rehype\n * pipeline. The result mirrors GitHub's rendering: a single, consistent\n * `user-content-` prefix on every id and matching hash href.\n *\n * @module components/rehypeRebaseHashLinks\n */\n\nimport type { Root } from 'hast';\nimport type { Plugin } from 'unified';\nimport { visit } from 'unist-util-visit';\n\nconst DEFAULT_PREFIX = 'user-content-';\n\nexport interface RehypeRebaseHashLinksOptions {\n /** Prefix to apply. Must match the `clobberPrefix` used by `rehype-sanitize`. */\n prefix?: string;\n}\n\nconst rehypeRebaseHashLinks: Plugin<[RehypeRebaseHashLinksOptions?], Root> = (options) => {\n const prefix = options?.prefix ?? DEFAULT_PREFIX;\n const hashPrefix = '#' + prefix;\n return (tree) => {\n visit(tree, 'element', (node) => {\n if (node.tagName !== 'a') return;\n const href = node.properties?.href;\n if (typeof href !== 'string' || !href.startsWith('#')) return;\n if (href.startsWith(hashPrefix)) return;\n node.properties.href = hashPrefix + href.slice(1);\n });\n };\n};\n\nexport default rehypeRebaseHashLinks;\n","/**\n * Rehype plugin that normalizes the auto-generated footnote footer so its\n * shape matches the cross-chunk aggregate footer (rendered by\n * `AggregateFootnotesIfLast`).\n *\n * mdast-util-to-hast's default `state.footer()` emits:\n *\n * <section data-footnotes class=\"footnotes\">\n * <h2 id=\"...footnote-label\" class=\"sr-only\">Footnotes</h2>\n * <ol>...</ol>\n * </section>\n *\n * The aggregate footer used in coordinated mode (and which the user prefers\n * visually) emits:\n *\n * <section data-footnotes class=\"footnotes\">\n * <hr />\n * <ol>...</ol>\n * </section>\n *\n * Running this plugin on the parsed hast lets standalone single-doc\n * rendering produce the same structure as the aggregate, so a 1-chunk doc and\n * an N-chunk coordinated doc with identical content look the same.\n *\n * Operates only on `<section data-footnotes>` and is idempotent.\n *\n * @module components/rehypeFooterAdorn\n */\nimport { visit } from 'unist-util-visit';\nimport type { Element as HastElement, Root as HastRoot, ElementContent } from 'hast';\n\nconst FOOTNOTE_LABEL_ID_RE = /(?:^|-)footnote-label$/;\n\nfunction isFootnoteLabelH2(node: ElementContent): boolean {\n if (node.type !== 'element') return false;\n const el = node as HastElement;\n if (el.tagName !== 'h2') return false;\n const id = el.properties?.id;\n return typeof id === 'string' && FOOTNOTE_LABEL_ID_RE.test(id);\n}\n\nfunction isHr(node: ElementContent): boolean {\n if (node.type !== 'element') return false;\n return (node as HastElement).tagName === 'hr';\n}\n\nexport default function rehypeFooterAdorn() {\n return (tree: HastRoot) => {\n visit(tree, 'element', (n) => {\n const el = n as HastElement;\n if (el.tagName !== 'section') return;\n if (!(el.properties && 'dataFootnotes' in el.properties)) return;\n // Strip the auto-generated <h2 id=\"...footnote-label\"> — the visible\n // \"Footnotes\" header reads awkwardly, especially in streaming AI chat\n // contexts. To keep screen-reader announcement working, set\n // `aria-label=\"Footnotes\"` on the section landmark so assistive tech\n // still names the region.\n const filtered = el.children.filter((c) => !isFootnoteLabelH2(c)) as ElementContent[];\n // Prepend <hr> as the first child, unless one is already present.\n if (!filtered.some(isHr)) {\n const hr: HastElement = {\n type: 'element',\n tagName: 'hr',\n properties: {},\n children: [],\n };\n filtered.unshift(hr);\n }\n el.children = filtered;\n if (!el.properties) el.properties = {};\n if (!('ariaLabel' in el.properties)) {\n el.properties.ariaLabel = 'Footnotes';\n }\n });\n };\n}\n","/**\n * Custom mdast-util-to-hast handlers for cross-chunk label resolution.\n *\n * Direction A: `footnoteDefinitionHandler` mutates `state.footnoteOrder` (and\n * seeds `state.footnoteCounts` to 0) so `state.footer()` emits a\n * `<section data-footnotes>` even when no `footnoteReference` exists locally\n * (orphan-def protection), without the default reference handler\n * double-registering ids whose definition precedes their first reference.\n *\n * Direction B: `linkReferenceHandler` / `imageReferenceHandler` /\n * `footnoteReferenceHandler` short-circuit the default to-hast output and\n * emit custom hast tags (`cross-chunk-link` / `cross-chunk-image` /\n * `footnote-sup`) carrying `label` + `referenceType` properties. These tags\n * map to React placeholder components in Phase 11. The sentinel URL is never\n * read — the handlers only need to know that the def is resolvable\n * (i.e. present in state.definitionById).\n *\n * All identifier comparisons normalize via {@link normalizeId} to match\n * mdast-util-to-hast's internal uppercase keying convention.\n *\n * @module components/customMdastHandlers\n */\nimport type { Handlers } from 'mdast-util-to-hast';\nimport type { LinkReference, ImageReference, FootnoteReference, FootnoteDefinition } from 'mdast';\nimport type { Element as HastElement } from 'hast';\nimport { normalizeId } from './normalizeId';\nimport { SENTINEL_LINK_URL } from './remarkInjectPhantomDefs';\n\nexport interface CrossChunkHandlerOptions {\n /** Set of labels (already normalized) that this chunk phantom-injected\n * into its source for parser acceptance. Handlers use this to short-circuit\n * state writes that would otherwise leak sentinel content into the footer. */\n phantomFootnoteLabels: Set<string>;\n /** Same role for link/image defs. */\n phantomLinkLabels: Set<string>;\n /** When true, footnoteDefinitionHandler proactively registers orphan defs\n * to state.footnoteOrder (Direction A). */\n preserveOrphan: boolean;\n /** Passed through to placeholder hast properties so React components can\n * partition by document. */\n documentId: string;\n}\n\n// Type assertion helper for state shape (mdast-util-to-hast doesn't export it).\ninterface StateShape {\n options: CrossChunkHandlerOptions & Record<string, unknown>;\n footnoteOrder: string[];\n footnoteCounts: Map<string, number>;\n definitionById: Map<string, unknown>;\n all: (node: unknown) => unknown[];\n}\n\n/**\n * The chunk's OWN definition for a resolved link/image reference — carried on\n * the placeholder as `localUrl`/`localTitle` so it can render a real link\n * before the registry has anything to say (server render, the client's\n * first frame before the contribute effect): coordinated SSR otherwise\n * degraded every reference-style link to its literal `[text][label]`\n * fallback (2026-08 project review, core-render-02). Phantom (sentinel)\n * defs carry nothing — a cross-chunk def is only knowable via the registry.\n * The placeholder still runs the render-time URL gates on this value.\n */\nfunction localDefProps(s: StateShape, id: string): { localUrl?: string; localTitle?: string } {\n const def = s.definitionById.get(id) as { url?: string; title?: string | null } | undefined;\n if (!def || typeof def.url !== 'string' || def.url === SENTINEL_LINK_URL) return {};\n return def.title ? { localUrl: def.url, localTitle: def.title } : { localUrl: def.url };\n}\n\nexport function buildCrossChunkHandlers(): Handlers {\n return {\n footnoteDefinition: (state: unknown, node: FootnoteDefinition): undefined => {\n const s = state as StateShape;\n const id = normalizeId(node.identifier);\n // Phantom def → noop: do not register, do not emit. Footer will skip it\n // because footnoteOrder does not contain id (unless a real ref pushed it).\n if (s.options.phantomFootnoteLabels.has(id)) {\n return undefined;\n }\n // Direction A: orphan def protection. Register so state.footer() emits <li>.\n if (s.options.preserveOrphan && !s.footnoteOrder.includes(id)) {\n s.footnoteOrder.push(id);\n // Seed the ref-counter to 0 alongside the push. In standalone mode\n // only THIS handler is installed, so `footnoteReference` falls back to\n // mdast-util-to-hast's default — and that handler decides \"is this id\n // already registered?\" by looking at footnoteCounts, not at\n // footnoteOrder. Without the seed, a definition that appears ABOVE its\n // first reference gets pushed here and then pushed AGAIN by the\n // default handler: duplicate <li> with colliding DOM ids, and a sup\n // marker numbered by array length instead of position.\n //\n // Seed 0, not 1: at >= 1 state.footer() emits a backref pointing at a\n // fnref anchor that does not exist for a pure orphan; at 0 the\n // backref loop never runs, so pure-orphan output stays byte-identical\n // and the default handler's reuse branch produces the same numbering\n // as the ref-above-def ordering.\n if (!s.footnoteCounts.has(id)) s.footnoteCounts.set(id, 0);\n }\n return undefined; // never emit inline hast\n },\n\n linkReference: ((state: unknown, node: LinkReference): HastElement | undefined => {\n const s = state as StateShape;\n const id = normalizeId(node.identifier);\n const resolved = s.definitionById.has(id);\n if (!resolved) {\n // Unreachable in coordinated pipeline because the phantom suffix\n // guarantees a def for every referenced label that survives PASS 0.5.\n // Verified by experiment: remark-parse produces a `linkReference`\n // mdast node ONLY when a corresponding `[label]:` exists in the\n // source — without one, the brackets are emitted as plain text by\n // the parser, so neither this handler nor mdast's default ever\n // sees the reference. Defense-in-depth for an impossible state.\n return undefined;\n }\n return {\n type: 'element',\n tagName: 'cross-chunk-link',\n properties: {\n // `label` is the ORIGINAL source text (mdast's `label` field), NOT\n // the normalized `identifier`. The placeholder uses it to construct\n // hrefs that line up with mdast-util-to-hast's default `<li id>`\n // which also preserves source case. Registry lookups normalize\n // internally, so cross-chunk case-insensitive matching still works.\n label: node.label ?? node.identifier,\n referenceType: node.referenceType,\n documentId: s.options.documentId,\n ...localDefProps(s, id),\n },\n children: s.all(node) as HastElement['children'],\n };\n }) as Handlers['linkReference'],\n\n imageReference: ((state: unknown, node: ImageReference): HastElement | undefined => {\n const s = state as StateShape;\n const id = normalizeId(node.identifier);\n const resolved = s.definitionById.has(id);\n if (!resolved) return undefined;\n return {\n type: 'element',\n tagName: 'cross-chunk-image',\n properties: {\n label: node.label ?? node.identifier,\n referenceType: node.referenceType,\n alt: node.alt ?? '',\n documentId: s.options.documentId,\n ...localDefProps(s, id),\n },\n children: [],\n };\n }) as Handlers['imageReference'],\n\n footnoteReference: ((state: unknown, node: FootnoteReference): HastElement => {\n const s = state as StateShape;\n const id = normalizeId(node.identifier);\n // Bump the per-id counter for ALL refs (phantom and real). The result\n // is the chunk-local occurrence index (1, 2, 3, …) which the placeholder\n // carries so FootnoteSupNumber can disambiguate duplicate fnref-* ids\n // when the same label is referenced multiple times. For phantom refs\n // bumping is safe: state.footer() emits <li> only for ids in\n // footnoteOrder, and phantoms never get pushed there.\n const localOccurrence = (s.footnoteCounts.get(id) ?? 0) + 1;\n s.footnoteCounts.set(id, localOccurrence);\n if (s.options.phantomFootnoteLabels.has(id)) {\n return {\n type: 'element',\n tagName: 'footnote-sup',\n properties: {\n label: node.identifier,\n localOccurrence,\n documentId: s.options.documentId,\n },\n children: [],\n };\n }\n // Real local def: register in footnoteOrder so the local synthetic\n // footer can emit a <li> for it.\n if (!s.footnoteOrder.includes(id)) s.footnoteOrder.push(id);\n return {\n type: 'element',\n tagName: 'footnote-sup',\n properties: {\n label: node.identifier,\n localOccurrence,\n // The number mdast-util-to-hast would give this reference in a\n // standalone render (footnoteOrder position) — the placeholder's\n // fallback while the registry has no global number (server render /\n // first client frame), where the local synthetic footer is what\n // renders, so marks and footer agree (core-render-02).\n localNumber: s.footnoteOrder.indexOf(id) + 1,\n documentId: s.options.documentId,\n },\n children: [],\n };\n }) as Handlers['footnoteReference'],\n };\n}\n","/**\n * Two-gate URL sanitization for cross-chunk link/image placeholders.\n *\n * In the standalone path, every `<a href>` and `<img src>` element passes\n * through TWO gates before render:\n *\n * 1. `rehype-sanitize` `protocols.<attr>` allowlist — drops the attribute\n * entirely if the URL's protocol isn't permitted for that attribute.\n * Runs in the rehype plugin chain.\n * 2. `urlTransform(url, key, node)` — the caller's allowlist (default:\n * `defaultUrlTransform`, which mirrors GitHub's protocol allowlist).\n * Runs in `markdown/transform.ts` during the hast visit pass; its\n * return value IS the attribute (`''` renders `href=\"\"`).\n *\n * Cross-chunk references skip BOTH passes naturally: the placeholder hast\n * tag (`<cross-chunk-link>` / `<cross-chunk-image>`) carries only a `label`\n * attribute; the real URL is looked up from the registry at React render\n * time, AFTER both passes have run. Without an explicit re-sanitization\n * here, cross-chunk renders would observably diverge from standalone:\n *\n * - A `[evil]: javascript:…` def in chunk A used by chunk B would render\n * a live `javascript:` link, even though the same source in standalone\n * mode is stripped.\n * - A consumer who allows a custom scheme via `urlTransform` but did NOT\n * add it to `sanitizeSchema.protocols` would see standalone strip the\n * `href`, but cross-chunk render it — silently breaking the \"two gates,\n * defense in depth\" contract documented in README.\n * - A key-aware `urlTransform` (e.g. one that allows a scheme only on\n * `href` but not `src`) would behave correctly in standalone but be\n * bypassed in the cross-chunk image path if we sanitized once at\n * contribute time with a fixed key.\n *\n * This helper makes the cross-chunk path observably identical to the\n * standalone two-gate pipeline, parameterised by the correct `key` for\n * each tag (`'href'` for `<a>`, `'src'` for `<img>`).\n *\n * @module components/crossChunkUrlSanitize\n */\n\nimport { normalizeUri } from 'micromark-util-sanitize-uri';\nimport type { Element as HastElement } from 'hast';\nimport type { UrlTransform } from './markdown';\nimport type { SanitizeSchema } from './extendSanitizeSchema';\nimport { sanitizeSchema as libraryDefaultSchema } from './sanitizeSchema';\n\nexport type UrlAttrKey = 'href' | 'src';\nexport type UrlAttrTag = 'a' | 'img';\n\n/** Synthetic hast element passed as the `node` argument to `urlTransform`.\n * Mirrors the shape the in-tree pipeline would have produced. */\nfunction fakeElement(tagName: UrlAttrTag, key: UrlAttrKey, url: string): HastElement {\n return { type: 'element', tagName, properties: { [key]: url }, children: [] };\n}\n\n/** True if the URL is relative (no protocol prefix before `/`, `?`, or `#`).\n * Relative URLs are always allowed — this mirrors the convention used in\n * `defaultUrlTransform` and `hast-util-sanitize`. */\nfunction isRelative(url: string, colon: number): boolean {\n if (colon === -1) return true;\n const slash = url.indexOf('/');\n const questionMark = url.indexOf('?');\n const numberSign = url.indexOf('#');\n if (slash !== -1 && colon > slash) return true;\n if (questionMark !== -1 && colon > questionMark) return true;\n if (numberSign !== -1 && colon > numberSign) return true;\n return false;\n}\n\n/** Check the URL's protocol against an allowlist (mirrors hast-util-sanitize's\n * `Schema.protocols.<attr>` semantics). Relative URLs are always allowed.\n *\n * **Case-sensitive comparison by design** — `hast-util-sanitize` does literal\n * string equality on the protocol prefix (`url.slice(0, p.length) === p`),\n * so `HTTPS://x` against `['http','https']` is stripped. We mirror that to\n * preserve observable parity with the standalone in-tree pipeline; a more\n * permissive cross-chunk comparison would let mixed-case URLs slip through\n * here that the standalone path strips. */\nfunction isProtocolAllowed(url: string, allowed: ReadonlyArray<string>): boolean {\n const colon = url.indexOf(':');\n if (isRelative(url, colon)) return true;\n const protocol = url.slice(0, colon);\n return allowed.some((p) => p === protocol);\n}\n\n/**\n * Run a cross-chunk-resolved URL through both standalone gates, in the\n * standalone ORDER: `rehype-sanitize`'s protocol allowlist runs in the\n * plugin chain first (a blocked URL loses the attribute entirely), then\n * `urlTransform` rewrites whatever survived during the hast visit pass (its\n * return value is the attribute — `''` from `defaultUrlTransform` renders\n * `href=\"\"`, exactly like a legal empty destination `[x]: <>`).\n *\n * @returns `null` when the protocol gate strips the attribute (render it\n * ABSENT); otherwise the transformed URL string — possibly `''`, which\n * the caller must render as `href=\"\"` / `src=\"\"` to stay byte-identical\n * with standalone (v2.4.1 review: the two used to collapse into `''` and\n * the placeholder omitted the attribute for `[x]: <>` too).\n */\nexport function sanitizeCrossChunkUrl(\n rawUrl: string,\n key: UrlAttrKey,\n tagName: UrlAttrTag,\n urlTransform: UrlTransform,\n schema: SanitizeSchema\n): string | null {\n // Gate 0: the same `normalizeUri` mdast-util-to-hast applies to every\n // in-tree `href`/`src` before the gates see it (percent-encodes spaces,\n // non-ASCII, `\"`, `<` …). Without it a cross-chunk `<https://x/a b>`\n // rendered `href=\"https://x/a b\"` where standalone renders `a%20b`\n // (v2.4.0 review).\n rawUrl = normalizeUri(rawUrl);\n\n // Gate 1: rehype-sanitize protocol allowlist. Mirrors hast-util-sanitize's\n // exact merge + lookup semantics (see `lib/index.js:235` + `:672`):\n //\n // 1. Upstream merges via `{...defaultSchema, ...options}` — a SHALLOW\n // spread. If the caller schema has no `protocols` key at all, the\n // resulting state inherits `defaultSchema.protocols` entirely.\n // Mirror this by falling back to the library default's protocols\n // when the caller didn't specify any.\n // 2. If the caller DID specify `protocols`, upstream uses caller's\n // object verbatim — keys the caller didn't list become \"no\n // restriction\" (upstream's `if (!protocols || ... === 0) return true`).\n // Do NOT cherry-pick library defaults for missing keys here, or the\n // helper becomes stricter than standalone in the partial-schema\n // case (the round-2 codex finding's mirror image).\n // 3. An empty array on the caller's `protocols.<key>` means \"no\n // restriction\" per upstream (the `length === 0` branch), not \"reject\n // all\" — preserve that.\n //\n // Net effect: every shape the standalone path tolerates produces the\n // same observable result here, including a TypeScript-bypass sparse\n // schema (caller passes no `protocols` → library default protocols apply\n // for both gates).\n // `Object.hasOwn`, not `=== undefined`: upstream's shallow spread keeps an\n // EXPLICIT `protocols: undefined` (own key, undefined value) and then\n // treats it as \"no restriction\" — only an ABSENT key inherits the\n // default's protocols (v2.4.2 review P3-4).\n const allowed = Object.hasOwn(schema, 'protocols') ? schema.protocols?.[key] : libraryDefaultSchema.protocols?.[key];\n if (allowed && allowed.length > 0 && !isProtocolAllowed(rawUrl, allowed)) return null;\n\n // Gate 2: urlTransform — caller's allowlist, called with the correct key\n // and a synthetic node mirroring what the in-tree pass would have seen.\n const transformed = urlTransform(rawUrl, key, fakeElement(tagName, key, rawUrl));\n if (transformed == null) return null;\n return String(transformed);\n}\n","/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nexport default listCacheClear;\n","/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nexport default eq;\n","import eq from './eq.js';\n\n/**\n * Gets the index at which the `key` is found in `array` of key-value pairs.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} key The key to search for.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction assocIndexOf(array, key) {\n var length = array.length;\n while (length--) {\n if (eq(array[length][0], key)) {\n return length;\n }\n }\n return -1;\n}\n\nexport default assocIndexOf;\n","import assocIndexOf from './_assocIndexOf.js';\n\n/** Used for built-in method references. */\nvar arrayProto = Array.prototype;\n\n/** Built-in value references. */\nvar splice = arrayProto.splice;\n\n/**\n * Removes `key` and its value from the list cache.\n *\n * @private\n * @name delete\n * @memberOf ListCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction listCacheDelete(key) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n if (index < 0) {\n return false;\n }\n var lastIndex = data.length - 1;\n if (index == lastIndex) {\n data.pop();\n } else {\n splice.call(data, index, 1);\n }\n --this.size;\n return true;\n}\n\nexport default listCacheDelete;\n","import assocIndexOf from './_assocIndexOf.js';\n\n/**\n * Gets the list cache value for `key`.\n *\n * @private\n * @name get\n * @memberOf ListCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction listCacheGet(key) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n return index < 0 ? undefined : data[index][1];\n}\n\nexport default listCacheGet;\n","import assocIndexOf from './_assocIndexOf.js';\n\n/**\n * Checks if a list cache value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf ListCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction listCacheHas(key) {\n return assocIndexOf(this.__data__, key) > -1;\n}\n\nexport default listCacheHas;\n","import assocIndexOf from './_assocIndexOf.js';\n\n/**\n * Sets the list cache `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf ListCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the list cache instance.\n */\nfunction listCacheSet(key, value) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n if (index < 0) {\n ++this.size;\n data.push([key, value]);\n } else {\n data[index][1] = value;\n }\n return this;\n}\n\nexport default listCacheSet;\n","import listCacheClear from './_listCacheClear.js';\nimport listCacheDelete from './_listCacheDelete.js';\nimport listCacheGet from './_listCacheGet.js';\nimport listCacheHas from './_listCacheHas.js';\nimport listCacheSet from './_listCacheSet.js';\n\n/**\n * Creates an list cache object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction ListCache(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n// Add methods to `ListCache`.\nListCache.prototype.clear = listCacheClear;\nListCache.prototype['delete'] = listCacheDelete;\nListCache.prototype.get = listCacheGet;\nListCache.prototype.has = listCacheHas;\nListCache.prototype.set = listCacheSet;\n\nexport default ListCache;\n","import ListCache from './_ListCache.js';\n\n/**\n * Removes all key-value entries from the stack.\n *\n * @private\n * @name clear\n * @memberOf Stack\n */\nfunction stackClear() {\n this.__data__ = new ListCache;\n this.size = 0;\n}\n\nexport default stackClear;\n","/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\nexport default stackDelete;\n","/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\nexport default stackGet;\n","/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\nexport default stackHas;\n","/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\nexport default freeGlobal;\n","import freeGlobal from './_freeGlobal.js';\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\nexport default root;\n","import root from './_root.js';\n\n/** Built-in value references. */\nvar Symbol = root.Symbol;\n\nexport default Symbol;\n","import Symbol from './_Symbol.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the raw `toStringTag`.\n */\nfunction getRawTag(value) {\n var isOwn = hasOwnProperty.call(value, symToStringTag),\n tag = value[symToStringTag];\n\n try {\n value[symToStringTag] = undefined;\n var unmasked = true;\n } catch (e) {}\n\n var result = nativeObjectToString.call(value);\n if (unmasked) {\n if (isOwn) {\n value[symToStringTag] = tag;\n } else {\n delete value[symToStringTag];\n }\n }\n return result;\n}\n\nexport default getRawTag;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","import Symbol from './_Symbol.js';\nimport getRawTag from './_getRawTag.js';\nimport objectToString from './_objectToString.js';\n\n/** `Object#toString` result references. */\nvar nullTag = '[object Null]',\n undefinedTag = '[object Undefined]';\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * The base implementation of `getTag` without fallbacks for buggy environments.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nfunction baseGetTag(value) {\n if (value == null) {\n return value === undefined ? undefinedTag : nullTag;\n }\n return (symToStringTag && symToStringTag in Object(value))\n ? getRawTag(value)\n : objectToString(value);\n}\n\nexport default baseGetTag;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","import baseGetTag from './_baseGetTag.js';\nimport isObject from './isObject.js';\n\n/** `Object#toString` result references. */\nvar asyncTag = '[object AsyncFunction]',\n funcTag = '[object Function]',\n genTag = '[object GeneratorFunction]',\n proxyTag = '[object Proxy]';\n\n/**\n * Checks if `value` is classified as a `Function` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a function, else `false`.\n * @example\n *\n * _.isFunction(_);\n * // => true\n *\n * _.isFunction(/abc/);\n * // => false\n */\nfunction isFunction(value) {\n if (!isObject(value)) {\n return false;\n }\n // The use of `Object#toString` avoids issues with the `typeof` operator\n // in Safari 9 which returns 'object' for typed arrays and other constructors.\n var tag = baseGetTag(value);\n return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;\n}\n\nexport default isFunction;\n","import root from './_root.js';\n\n/** Used to detect overreaching core-js shims. */\nvar coreJsData = root['__core-js_shared__'];\n\nexport default coreJsData;\n","import coreJsData from './_coreJsData.js';\n\n/** Used to detect methods masquerading as native. */\nvar maskSrcKey = (function() {\n var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');\n return uid ? ('Symbol(src)_1.' + uid) : '';\n}());\n\n/**\n * Checks if `func` has its source masked.\n *\n * @private\n * @param {Function} func The function to check.\n * @returns {boolean} Returns `true` if `func` is masked, else `false`.\n */\nfunction isMasked(func) {\n return !!maskSrcKey && (maskSrcKey in func);\n}\n\nexport default isMasked;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nexport default toSource;\n","import isFunction from './isFunction.js';\nimport isMasked from './_isMasked.js';\nimport isObject from './isObject.js';\nimport toSource from './_toSource.js';\n\n/**\n * Used to match `RegExp`\n * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).\n */\nvar reRegExpChar = /[\\\\^$.*+?()[\\]{}|]/g;\n\n/** Used to detect host constructors (Safari). */\nvar reIsHostCtor = /^\\[object .+?Constructor\\]$/;\n\n/** Used for built-in method references. */\nvar funcProto = Function.prototype,\n objectProto = Object.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Used to detect if a method is native. */\nvar reIsNative = RegExp('^' +\n funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\\\$&')\n .replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g, '$1.*?') + '$'\n);\n\n/**\n * The base implementation of `_.isNative` without bad shim checks.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a native function,\n * else `false`.\n */\nfunction baseIsNative(value) {\n if (!isObject(value) || isMasked(value)) {\n return false;\n }\n var pattern = isFunction(value) ? reIsNative : reIsHostCtor;\n return pattern.test(toSource(value));\n}\n\nexport default baseIsNative;\n","/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nexport default getValue;\n","import baseIsNative from './_baseIsNative.js';\nimport getValue from './_getValue.js';\n\n/**\n * Gets the native function at `key` of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the method to get.\n * @returns {*} Returns the function if it's native, else `undefined`.\n */\nfunction getNative(object, key) {\n var value = getValue(object, key);\n return baseIsNative(value) ? value : undefined;\n}\n\nexport default getNative;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar Map = getNative(root, 'Map');\n\nexport default Map;\n","import getNative from './_getNative.js';\n\n/* Built-in method references that are verified to be native. */\nvar nativeCreate = getNative(Object, 'create');\n\nexport default nativeCreate;\n","import nativeCreate from './_nativeCreate.js';\n\n/**\n * Removes all key-value entries from the hash.\n *\n * @private\n * @name clear\n * @memberOf Hash\n */\nfunction hashClear() {\n this.__data__ = nativeCreate ? nativeCreate(null) : {};\n this.size = 0;\n}\n\nexport default hashClear;\n","/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default hashDelete;\n","import nativeCreate from './_nativeCreate.js';\n\n/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Gets the hash value for `key`.\n *\n * @private\n * @name get\n * @memberOf Hash\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction hashGet(key) {\n var data = this.__data__;\n if (nativeCreate) {\n var result = data[key];\n return result === HASH_UNDEFINED ? undefined : result;\n }\n return hasOwnProperty.call(data, key) ? data[key] : undefined;\n}\n\nexport default hashGet;\n","import nativeCreate from './_nativeCreate.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Checks if a hash value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Hash\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction hashHas(key) {\n var data = this.__data__;\n return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key);\n}\n\nexport default hashHas;\n","import nativeCreate from './_nativeCreate.js';\n\n/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/**\n * Sets the hash `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Hash\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the hash instance.\n */\nfunction hashSet(key, value) {\n var data = this.__data__;\n this.size += this.has(key) ? 0 : 1;\n data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;\n return this;\n}\n\nexport default hashSet;\n","import hashClear from './_hashClear.js';\nimport hashDelete from './_hashDelete.js';\nimport hashGet from './_hashGet.js';\nimport hashHas from './_hashHas.js';\nimport hashSet from './_hashSet.js';\n\n/**\n * Creates a hash object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Hash(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n// Add methods to `Hash`.\nHash.prototype.clear = hashClear;\nHash.prototype['delete'] = hashDelete;\nHash.prototype.get = hashGet;\nHash.prototype.has = hashHas;\nHash.prototype.set = hashSet;\n\nexport default Hash;\n","import Hash from './_Hash.js';\nimport ListCache from './_ListCache.js';\nimport Map from './_Map.js';\n\n/**\n * Removes all key-value entries from the map.\n *\n * @private\n * @name clear\n * @memberOf MapCache\n */\nfunction mapCacheClear() {\n this.size = 0;\n this.__data__ = {\n 'hash': new Hash,\n 'map': new (Map || ListCache),\n 'string': new Hash\n };\n}\n\nexport default mapCacheClear;\n","/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nexport default isKeyable;\n","import isKeyable from './_isKeyable.js';\n\n/**\n * Gets the data for `map`.\n *\n * @private\n * @param {Object} map The map to query.\n * @param {string} key The reference key.\n * @returns {*} Returns the map data.\n */\nfunction getMapData(map, key) {\n var data = map.__data__;\n return isKeyable(key)\n ? data[typeof key == 'string' ? 'string' : 'hash']\n : data.map;\n}\n\nexport default getMapData;\n","import getMapData from './_getMapData.js';\n\n/**\n * Removes `key` and its value from the map.\n *\n * @private\n * @name delete\n * @memberOf MapCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction mapCacheDelete(key) {\n var result = getMapData(this, key)['delete'](key);\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default mapCacheDelete;\n","import getMapData from './_getMapData.js';\n\n/**\n * Gets the map value for `key`.\n *\n * @private\n * @name get\n * @memberOf MapCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction mapCacheGet(key) {\n return getMapData(this, key).get(key);\n}\n\nexport default mapCacheGet;\n","import getMapData from './_getMapData.js';\n\n/**\n * Checks if a map value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf MapCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction mapCacheHas(key) {\n return getMapData(this, key).has(key);\n}\n\nexport default mapCacheHas;\n","import getMapData from './_getMapData.js';\n\n/**\n * Sets the map `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf MapCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the map cache instance.\n */\nfunction mapCacheSet(key, value) {\n var data = getMapData(this, key),\n size = data.size;\n\n data.set(key, value);\n this.size += data.size == size ? 0 : 1;\n return this;\n}\n\nexport default mapCacheSet;\n","import mapCacheClear from './_mapCacheClear.js';\nimport mapCacheDelete from './_mapCacheDelete.js';\nimport mapCacheGet from './_mapCacheGet.js';\nimport mapCacheHas from './_mapCacheHas.js';\nimport mapCacheSet from './_mapCacheSet.js';\n\n/**\n * Creates a map cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction MapCache(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n// Add methods to `MapCache`.\nMapCache.prototype.clear = mapCacheClear;\nMapCache.prototype['delete'] = mapCacheDelete;\nMapCache.prototype.get = mapCacheGet;\nMapCache.prototype.has = mapCacheHas;\nMapCache.prototype.set = mapCacheSet;\n\nexport default MapCache;\n","import ListCache from './_ListCache.js';\nimport Map from './_Map.js';\nimport MapCache from './_MapCache.js';\n\n/** Used as the size to enable large array optimizations. */\nvar LARGE_ARRAY_SIZE = 200;\n\n/**\n * Sets the stack `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Stack\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the stack cache instance.\n */\nfunction stackSet(key, value) {\n var data = this.__data__;\n if (data instanceof ListCache) {\n var pairs = data.__data__;\n if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {\n pairs.push([key, value]);\n this.size = ++data.size;\n return this;\n }\n data = this.__data__ = new MapCache(pairs);\n }\n data.set(key, value);\n this.size = data.size;\n return this;\n}\n\nexport default stackSet;\n","import ListCache from './_ListCache.js';\nimport stackClear from './_stackClear.js';\nimport stackDelete from './_stackDelete.js';\nimport stackGet from './_stackGet.js';\nimport stackHas from './_stackHas.js';\nimport stackSet from './_stackSet.js';\n\n/**\n * Creates a stack cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Stack(entries) {\n var data = this.__data__ = new ListCache(entries);\n this.size = data.size;\n}\n\n// Add methods to `Stack`.\nStack.prototype.clear = stackClear;\nStack.prototype['delete'] = stackDelete;\nStack.prototype.get = stackGet;\nStack.prototype.has = stackHas;\nStack.prototype.set = stackSet;\n\nexport default Stack;\n","/**\n * A specialized version of `_.forEach` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns `array`.\n */\nfunction arrayEach(array, iteratee) {\n var index = -1,\n length = array == null ? 0 : array.length;\n\n while (++index < length) {\n if (iteratee(array[index], index, array) === false) {\n break;\n }\n }\n return array;\n}\n\nexport default arrayEach;\n","import getNative from './_getNative.js';\n\nvar defineProperty = (function() {\n try {\n var func = getNative(Object, 'defineProperty');\n func({}, '', {});\n return func;\n } catch (e) {}\n}());\n\nexport default defineProperty;\n","import defineProperty from './_defineProperty.js';\n\n/**\n * The base implementation of `assignValue` and `assignMergeValue` without\n * value checks.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {string} key The key of the property to assign.\n * @param {*} value The value to assign.\n */\nfunction baseAssignValue(object, key, value) {\n if (key == '__proto__' && defineProperty) {\n defineProperty(object, key, {\n 'configurable': true,\n 'enumerable': true,\n 'value': value,\n 'writable': true\n });\n } else {\n object[key] = value;\n }\n}\n\nexport default baseAssignValue;\n","import baseAssignValue from './_baseAssignValue.js';\nimport eq from './eq.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Assigns `value` to `key` of `object` if the existing value is not equivalent\n * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * for equality comparisons.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {string} key The key of the property to assign.\n * @param {*} value The value to assign.\n */\nfunction assignValue(object, key, value) {\n var objValue = object[key];\n if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||\n (value === undefined && !(key in object))) {\n baseAssignValue(object, key, value);\n }\n}\n\nexport default assignValue;\n","import assignValue from './_assignValue.js';\nimport baseAssignValue from './_baseAssignValue.js';\n\n/**\n * Copies properties of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy properties from.\n * @param {Array} props The property identifiers to copy.\n * @param {Object} [object={}] The object to copy properties to.\n * @param {Function} [customizer] The function to customize copied values.\n * @returns {Object} Returns `object`.\n */\nfunction copyObject(source, props, object, customizer) {\n var isNew = !object;\n object || (object = {});\n\n var index = -1,\n length = props.length;\n\n while (++index < length) {\n var key = props[index];\n\n var newValue = customizer\n ? customizer(object[key], source[key], key, object, source)\n : undefined;\n\n if (newValue === undefined) {\n newValue = source[key];\n }\n if (isNew) {\n baseAssignValue(object, key, newValue);\n } else {\n assignValue(object, key, newValue);\n }\n }\n return object;\n}\n\nexport default copyObject;\n","/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\nexport default baseTimes;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","import baseGetTag from './_baseGetTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]';\n\n/**\n * The base implementation of `_.isArguments`.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n */\nfunction baseIsArguments(value) {\n return isObjectLike(value) && baseGetTag(value) == argsTag;\n}\n\nexport default baseIsArguments;\n","import baseIsArguments from './_baseIsArguments.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Built-in value references. */\nvar propertyIsEnumerable = objectProto.propertyIsEnumerable;\n\n/**\n * Checks if `value` is likely an `arguments` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n * else `false`.\n * @example\n *\n * _.isArguments(function() { return arguments; }());\n * // => true\n *\n * _.isArguments([1, 2, 3]);\n * // => false\n */\nvar isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {\n return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&\n !propertyIsEnumerable.call(value, 'callee');\n};\n\nexport default isArguments;\n","/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nexport default isArray;\n","/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nexport default stubFalse;\n","import root from './_root.js';\nimport stubFalse from './stubFalse.js';\n\n/** Detect free variable `exports`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Built-in value references. */\nvar Buffer = moduleExports ? root.Buffer : undefined;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined;\n\n/**\n * Checks if `value` is a buffer.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.\n * @example\n *\n * _.isBuffer(new Buffer(2));\n * // => true\n *\n * _.isBuffer(new Uint8Array(2));\n * // => false\n */\nvar isBuffer = nativeIsBuffer || stubFalse;\n\nexport default isBuffer;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nexport default isIndex;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nexport default isLength;\n","import baseGetTag from './_baseGetTag.js';\nimport isLength from './isLength.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]',\n arrayTag = '[object Array]',\n boolTag = '[object Boolean]',\n dateTag = '[object Date]',\n errorTag = '[object Error]',\n funcTag = '[object Function]',\n mapTag = '[object Map]',\n numberTag = '[object Number]',\n objectTag = '[object Object]',\n regexpTag = '[object RegExp]',\n setTag = '[object Set]',\n stringTag = '[object String]',\n weakMapTag = '[object WeakMap]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n dataViewTag = '[object DataView]',\n float32Tag = '[object Float32Array]',\n float64Tag = '[object Float64Array]',\n int8Tag = '[object Int8Array]',\n int16Tag = '[object Int16Array]',\n int32Tag = '[object Int32Array]',\n uint8Tag = '[object Uint8Array]',\n uint8ClampedTag = '[object Uint8ClampedArray]',\n uint16Tag = '[object Uint16Array]',\n uint32Tag = '[object Uint32Array]';\n\n/** Used to identify `toStringTag` values of typed arrays. */\nvar typedArrayTags = {};\ntypedArrayTags[float32Tag] = typedArrayTags[float64Tag] =\ntypedArrayTags[int8Tag] = typedArrayTags[int16Tag] =\ntypedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =\ntypedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =\ntypedArrayTags[uint32Tag] = true;\ntypedArrayTags[argsTag] = typedArrayTags[arrayTag] =\ntypedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =\ntypedArrayTags[dataViewTag] = typedArrayTags[dateTag] =\ntypedArrayTags[errorTag] = typedArrayTags[funcTag] =\ntypedArrayTags[mapTag] = typedArrayTags[numberTag] =\ntypedArrayTags[objectTag] = typedArrayTags[regexpTag] =\ntypedArrayTags[setTag] = typedArrayTags[stringTag] =\ntypedArrayTags[weakMapTag] = false;\n\n/**\n * The base implementation of `_.isTypedArray` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.\n */\nfunction baseIsTypedArray(value) {\n return isObjectLike(value) &&\n isLength(value.length) && !!typedArrayTags[baseGetTag(value)];\n}\n\nexport default baseIsTypedArray;\n","/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\nexport default baseUnary;\n","import freeGlobal from './_freeGlobal.js';\n\n/** Detect free variable `exports`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Detect free variable `process` from Node.js. */\nvar freeProcess = moduleExports && freeGlobal.process;\n\n/** Used to access faster Node.js helpers. */\nvar nodeUtil = (function() {\n try {\n // Use `util.types` for Node.js 10+.\n var types = freeModule && freeModule.require && freeModule.require('util').types;\n\n if (types) {\n return types;\n }\n\n // Legacy `process.binding('util')` for Node.js < 10.\n return freeProcess && freeProcess.binding && freeProcess.binding('util');\n } catch (e) {}\n}());\n\nexport default nodeUtil;\n","import baseIsTypedArray from './_baseIsTypedArray.js';\nimport baseUnary from './_baseUnary.js';\nimport nodeUtil from './_nodeUtil.js';\n\n/* Node.js helper references. */\nvar nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;\n\n/**\n * Checks if `value` is classified as a typed array.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.\n * @example\n *\n * _.isTypedArray(new Uint8Array);\n * // => true\n *\n * _.isTypedArray([]);\n * // => false\n */\nvar isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;\n\nexport default isTypedArray;\n","import baseTimes from './_baseTimes.js';\nimport isArguments from './isArguments.js';\nimport isArray from './isArray.js';\nimport isBuffer from './isBuffer.js';\nimport isIndex from './_isIndex.js';\nimport isTypedArray from './isTypedArray.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Creates an array of the enumerable property names of the array-like `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @param {boolean} inherited Specify returning inherited property names.\n * @returns {Array} Returns the array of property names.\n */\nfunction arrayLikeKeys(value, inherited) {\n var isArr = isArray(value),\n isArg = !isArr && isArguments(value),\n isBuff = !isArr && !isArg && isBuffer(value),\n isType = !isArr && !isArg && !isBuff && isTypedArray(value),\n skipIndexes = isArr || isArg || isBuff || isType,\n result = skipIndexes ? baseTimes(value.length, String) : [],\n length = result.length;\n\n for (var key in value) {\n if ((inherited || hasOwnProperty.call(value, key)) &&\n !(skipIndexes && (\n // Safari 9 has enumerable `arguments.length` in strict mode.\n key == 'length' ||\n // Node.js 0.10 has enumerable non-index properties on buffers.\n (isBuff && (key == 'offset' || key == 'parent')) ||\n // PhantomJS 2 has enumerable non-index properties on typed arrays.\n (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||\n // Skip index properties.\n isIndex(key, length)\n ))) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default arrayLikeKeys;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\nexport default isPrototype;\n","/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nexport default overArg;\n","import overArg from './_overArg.js';\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeKeys = overArg(Object.keys, Object);\n\nexport default nativeKeys;\n","import isPrototype from './_isPrototype.js';\nimport nativeKeys from './_nativeKeys.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction baseKeys(object) {\n if (!isPrototype(object)) {\n return nativeKeys(object);\n }\n var result = [];\n for (var key in Object(object)) {\n if (hasOwnProperty.call(object, key) && key != 'constructor') {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default baseKeys;\n","import isFunction from './isFunction.js';\nimport isLength from './isLength.js';\n\n/**\n * Checks if `value` is array-like. A value is considered array-like if it's\n * not a function and has a `value.length` that's an integer greater than or\n * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is array-like, else `false`.\n * @example\n *\n * _.isArrayLike([1, 2, 3]);\n * // => true\n *\n * _.isArrayLike(document.body.children);\n * // => true\n *\n * _.isArrayLike('abc');\n * // => true\n *\n * _.isArrayLike(_.noop);\n * // => false\n */\nfunction isArrayLike(value) {\n return value != null && isLength(value.length) && !isFunction(value);\n}\n\nexport default isArrayLike;\n","import arrayLikeKeys from './_arrayLikeKeys.js';\nimport baseKeys from './_baseKeys.js';\nimport isArrayLike from './isArrayLike.js';\n\n/**\n * Creates an array of the own enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects. See the\n * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * for more details.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keys(new Foo);\n * // => ['a', 'b'] (iteration order is not guaranteed)\n *\n * _.keys('hi');\n * // => ['0', '1']\n */\nfunction keys(object) {\n return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);\n}\n\nexport default keys;\n","import copyObject from './_copyObject.js';\nimport keys from './keys.js';\n\n/**\n * The base implementation of `_.assign` without support for multiple sources\n * or `customizer` functions.\n *\n * @private\n * @param {Object} object The destination object.\n * @param {Object} source The source object.\n * @returns {Object} Returns `object`.\n */\nfunction baseAssign(object, source) {\n return object && copyObject(source, keys(source), object);\n}\n\nexport default baseAssign;\n","/**\n * This function is like\n * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * except that it includes inherited enumerable properties.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction nativeKeysIn(object) {\n var result = [];\n if (object != null) {\n for (var key in Object(object)) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default nativeKeysIn;\n","import isObject from './isObject.js';\nimport isPrototype from './_isPrototype.js';\nimport nativeKeysIn from './_nativeKeysIn.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction baseKeysIn(object) {\n if (!isObject(object)) {\n return nativeKeysIn(object);\n }\n var isProto = isPrototype(object),\n result = [];\n\n for (var key in object) {\n if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default baseKeysIn;\n","import arrayLikeKeys from './_arrayLikeKeys.js';\nimport baseKeysIn from './_baseKeysIn.js';\nimport isArrayLike from './isArrayLike.js';\n\n/**\n * Creates an array of the own and inherited enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keysIn(new Foo);\n * // => ['a', 'b', 'c'] (iteration order is not guaranteed)\n */\nfunction keysIn(object) {\n return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);\n}\n\nexport default keysIn;\n","import copyObject from './_copyObject.js';\nimport keysIn from './keysIn.js';\n\n/**\n * The base implementation of `_.assignIn` without support for multiple sources\n * or `customizer` functions.\n *\n * @private\n * @param {Object} object The destination object.\n * @param {Object} source The source object.\n * @returns {Object} Returns `object`.\n */\nfunction baseAssignIn(object, source) {\n return object && copyObject(source, keysIn(source), object);\n}\n\nexport default baseAssignIn;\n","import root from './_root.js';\n\n/** Detect free variable `exports`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Built-in value references. */\nvar Buffer = moduleExports ? root.Buffer : undefined,\n allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined;\n\n/**\n * Creates a clone of `buffer`.\n *\n * @private\n * @param {Buffer} buffer The buffer to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Buffer} Returns the cloned buffer.\n */\nfunction cloneBuffer(buffer, isDeep) {\n if (isDeep) {\n return buffer.slice();\n }\n var length = buffer.length,\n result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length);\n\n buffer.copy(result);\n return result;\n}\n\nexport default cloneBuffer;\n","/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n var index = -1,\n length = source.length;\n\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n}\n\nexport default copyArray;\n","/**\n * A specialized version of `_.filter` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {Array} Returns the new filtered array.\n */\nfunction arrayFilter(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length,\n resIndex = 0,\n result = [];\n\n while (++index < length) {\n var value = array[index];\n if (predicate(value, index, array)) {\n result[resIndex++] = value;\n }\n }\n return result;\n}\n\nexport default arrayFilter;\n","/**\n * This method returns a new empty array.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {Array} Returns the new empty array.\n * @example\n *\n * var arrays = _.times(2, _.stubArray);\n *\n * console.log(arrays);\n * // => [[], []]\n *\n * console.log(arrays[0] === arrays[1]);\n * // => false\n */\nfunction stubArray() {\n return [];\n}\n\nexport default stubArray;\n","import arrayFilter from './_arrayFilter.js';\nimport stubArray from './stubArray.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Built-in value references. */\nvar propertyIsEnumerable = objectProto.propertyIsEnumerable;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeGetSymbols = Object.getOwnPropertySymbols;\n\n/**\n * Creates an array of the own enumerable symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of symbols.\n */\nvar getSymbols = !nativeGetSymbols ? stubArray : function(object) {\n if (object == null) {\n return [];\n }\n object = Object(object);\n return arrayFilter(nativeGetSymbols(object), function(symbol) {\n return propertyIsEnumerable.call(object, symbol);\n });\n};\n\nexport default getSymbols;\n","import copyObject from './_copyObject.js';\nimport getSymbols from './_getSymbols.js';\n\n/**\n * Copies own symbols of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy symbols from.\n * @param {Object} [object={}] The object to copy symbols to.\n * @returns {Object} Returns `object`.\n */\nfunction copySymbols(source, object) {\n return copyObject(source, getSymbols(source), object);\n}\n\nexport default copySymbols;\n","/**\n * Appends the elements of `values` to `array`.\n *\n * @private\n * @param {Array} array The array to modify.\n * @param {Array} values The values to append.\n * @returns {Array} Returns `array`.\n */\nfunction arrayPush(array, values) {\n var index = -1,\n length = values.length,\n offset = array.length;\n\n while (++index < length) {\n array[offset + index] = values[index];\n }\n return array;\n}\n\nexport default arrayPush;\n","import overArg from './_overArg.js';\n\n/** Built-in value references. */\nvar getPrototype = overArg(Object.getPrototypeOf, Object);\n\nexport default getPrototype;\n","import arrayPush from './_arrayPush.js';\nimport getPrototype from './_getPrototype.js';\nimport getSymbols from './_getSymbols.js';\nimport stubArray from './stubArray.js';\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeGetSymbols = Object.getOwnPropertySymbols;\n\n/**\n * Creates an array of the own and inherited enumerable symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of symbols.\n */\nvar getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) {\n var result = [];\n while (object) {\n arrayPush(result, getSymbols(object));\n object = getPrototype(object);\n }\n return result;\n};\n\nexport default getSymbolsIn;\n","import copyObject from './_copyObject.js';\nimport getSymbolsIn from './_getSymbolsIn.js';\n\n/**\n * Copies own and inherited symbols of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy symbols from.\n * @param {Object} [object={}] The object to copy symbols to.\n * @returns {Object} Returns `object`.\n */\nfunction copySymbolsIn(source, object) {\n return copyObject(source, getSymbolsIn(source), object);\n}\n\nexport default copySymbolsIn;\n","import arrayPush from './_arrayPush.js';\nimport isArray from './isArray.js';\n\n/**\n * The base implementation of `getAllKeys` and `getAllKeysIn` which uses\n * `keysFunc` and `symbolsFunc` to get the enumerable property names and\n * symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Function} keysFunc The function to get the keys of `object`.\n * @param {Function} symbolsFunc The function to get the symbols of `object`.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction baseGetAllKeys(object, keysFunc, symbolsFunc) {\n var result = keysFunc(object);\n return isArray(object) ? result : arrayPush(result, symbolsFunc(object));\n}\n\nexport default baseGetAllKeys;\n","import baseGetAllKeys from './_baseGetAllKeys.js';\nimport getSymbols from './_getSymbols.js';\nimport keys from './keys.js';\n\n/**\n * Creates an array of own enumerable property names and symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction getAllKeys(object) {\n return baseGetAllKeys(object, keys, getSymbols);\n}\n\nexport default getAllKeys;\n","import baseGetAllKeys from './_baseGetAllKeys.js';\nimport getSymbolsIn from './_getSymbolsIn.js';\nimport keysIn from './keysIn.js';\n\n/**\n * Creates an array of own and inherited enumerable property names and\n * symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction getAllKeysIn(object) {\n return baseGetAllKeys(object, keysIn, getSymbolsIn);\n}\n\nexport default getAllKeysIn;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar DataView = getNative(root, 'DataView');\n\nexport default DataView;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar Promise = getNative(root, 'Promise');\n\nexport default Promise;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar Set = getNative(root, 'Set');\n\nexport default Set;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar WeakMap = getNative(root, 'WeakMap');\n\nexport default WeakMap;\n","import DataView from './_DataView.js';\nimport Map from './_Map.js';\nimport Promise from './_Promise.js';\nimport Set from './_Set.js';\nimport WeakMap from './_WeakMap.js';\nimport baseGetTag from './_baseGetTag.js';\nimport toSource from './_toSource.js';\n\n/** `Object#toString` result references. */\nvar mapTag = '[object Map]',\n objectTag = '[object Object]',\n promiseTag = '[object Promise]',\n setTag = '[object Set]',\n weakMapTag = '[object WeakMap]';\n\nvar dataViewTag = '[object DataView]';\n\n/** Used to detect maps, sets, and weakmaps. */\nvar dataViewCtorString = toSource(DataView),\n mapCtorString = toSource(Map),\n promiseCtorString = toSource(Promise),\n setCtorString = toSource(Set),\n weakMapCtorString = toSource(WeakMap);\n\n/**\n * Gets the `toStringTag` of `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nvar getTag = baseGetTag;\n\n// Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.\nif ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||\n (Map && getTag(new Map) != mapTag) ||\n (Promise && getTag(Promise.resolve()) != promiseTag) ||\n (Set && getTag(new Set) != setTag) ||\n (WeakMap && getTag(new WeakMap) != weakMapTag)) {\n getTag = function(value) {\n var result = baseGetTag(value),\n Ctor = result == objectTag ? value.constructor : undefined,\n ctorString = Ctor ? toSource(Ctor) : '';\n\n if (ctorString) {\n switch (ctorString) {\n case dataViewCtorString: return dataViewTag;\n case mapCtorString: return mapTag;\n case promiseCtorString: return promiseTag;\n case setCtorString: return setTag;\n case weakMapCtorString: return weakMapTag;\n }\n }\n return result;\n };\n}\n\nexport default getTag;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Initializes an array clone.\n *\n * @private\n * @param {Array} array The array to clone.\n * @returns {Array} Returns the initialized clone.\n */\nfunction initCloneArray(array) {\n var length = array.length,\n result = new array.constructor(length);\n\n // Add properties assigned by `RegExp#exec`.\n if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {\n result.index = array.index;\n result.input = array.input;\n }\n return result;\n}\n\nexport default initCloneArray;\n","import root from './_root.js';\n\n/** Built-in value references. */\nvar Uint8Array = root.Uint8Array;\n\nexport default Uint8Array;\n","import Uint8Array from './_Uint8Array.js';\n\n/**\n * Creates a clone of `arrayBuffer`.\n *\n * @private\n * @param {ArrayBuffer} arrayBuffer The array buffer to clone.\n * @returns {ArrayBuffer} Returns the cloned array buffer.\n */\nfunction cloneArrayBuffer(arrayBuffer) {\n var result = new arrayBuffer.constructor(arrayBuffer.byteLength);\n new Uint8Array(result).set(new Uint8Array(arrayBuffer));\n return result;\n}\n\nexport default cloneArrayBuffer;\n","import cloneArrayBuffer from './_cloneArrayBuffer.js';\n\n/**\n * Creates a clone of `dataView`.\n *\n * @private\n * @param {Object} dataView The data view to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned data view.\n */\nfunction cloneDataView(dataView, isDeep) {\n var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;\n return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);\n}\n\nexport default cloneDataView;\n","/** Used to match `RegExp` flags from their coerced string values. */\nvar reFlags = /\\w*$/;\n\n/**\n * Creates a clone of `regexp`.\n *\n * @private\n * @param {Object} regexp The regexp to clone.\n * @returns {Object} Returns the cloned regexp.\n */\nfunction cloneRegExp(regexp) {\n var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));\n result.lastIndex = regexp.lastIndex;\n return result;\n}\n\nexport default cloneRegExp;\n","import Symbol from './_Symbol.js';\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined,\n symbolValueOf = symbolProto ? symbolProto.valueOf : undefined;\n\n/**\n * Creates a clone of the `symbol` object.\n *\n * @private\n * @param {Object} symbol The symbol object to clone.\n * @returns {Object} Returns the cloned symbol object.\n */\nfunction cloneSymbol(symbol) {\n return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};\n}\n\nexport default cloneSymbol;\n","import cloneArrayBuffer from './_cloneArrayBuffer.js';\n\n/**\n * Creates a clone of `typedArray`.\n *\n * @private\n * @param {Object} typedArray The typed array to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned typed array.\n */\nfunction cloneTypedArray(typedArray, isDeep) {\n var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;\n return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);\n}\n\nexport default cloneTypedArray;\n","import cloneArrayBuffer from './_cloneArrayBuffer.js';\nimport cloneDataView from './_cloneDataView.js';\nimport cloneRegExp from './_cloneRegExp.js';\nimport cloneSymbol from './_cloneSymbol.js';\nimport cloneTypedArray from './_cloneTypedArray.js';\n\n/** `Object#toString` result references. */\nvar boolTag = '[object Boolean]',\n dateTag = '[object Date]',\n mapTag = '[object Map]',\n numberTag = '[object Number]',\n regexpTag = '[object RegExp]',\n setTag = '[object Set]',\n stringTag = '[object String]',\n symbolTag = '[object Symbol]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n dataViewTag = '[object DataView]',\n float32Tag = '[object Float32Array]',\n float64Tag = '[object Float64Array]',\n int8Tag = '[object Int8Array]',\n int16Tag = '[object Int16Array]',\n int32Tag = '[object Int32Array]',\n uint8Tag = '[object Uint8Array]',\n uint8ClampedTag = '[object Uint8ClampedArray]',\n uint16Tag = '[object Uint16Array]',\n uint32Tag = '[object Uint32Array]';\n\n/**\n * Initializes an object clone based on its `toStringTag`.\n *\n * **Note:** This function only supports cloning values with tags of\n * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`.\n *\n * @private\n * @param {Object} object The object to clone.\n * @param {string} tag The `toStringTag` of the object to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the initialized clone.\n */\nfunction initCloneByTag(object, tag, isDeep) {\n var Ctor = object.constructor;\n switch (tag) {\n case arrayBufferTag:\n return cloneArrayBuffer(object);\n\n case boolTag:\n case dateTag:\n return new Ctor(+object);\n\n case dataViewTag:\n return cloneDataView(object, isDeep);\n\n case float32Tag: case float64Tag:\n case int8Tag: case int16Tag: case int32Tag:\n case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:\n return cloneTypedArray(object, isDeep);\n\n case mapTag:\n return new Ctor;\n\n case numberTag:\n case stringTag:\n return new Ctor(object);\n\n case regexpTag:\n return cloneRegExp(object);\n\n case setTag:\n return new Ctor;\n\n case symbolTag:\n return cloneSymbol(object);\n }\n}\n\nexport default initCloneByTag;\n","import isObject from './isObject.js';\n\n/** Built-in value references. */\nvar objectCreate = Object.create;\n\n/**\n * The base implementation of `_.create` without support for assigning\n * properties to the created object.\n *\n * @private\n * @param {Object} proto The object to inherit from.\n * @returns {Object} Returns the new object.\n */\nvar baseCreate = (function() {\n function object() {}\n return function(proto) {\n if (!isObject(proto)) {\n return {};\n }\n if (objectCreate) {\n return objectCreate(proto);\n }\n object.prototype = proto;\n var result = new object;\n object.prototype = undefined;\n return result;\n };\n}());\n\nexport default baseCreate;\n","import baseCreate from './_baseCreate.js';\nimport getPrototype from './_getPrototype.js';\nimport isPrototype from './_isPrototype.js';\n\n/**\n * Initializes an object clone.\n *\n * @private\n * @param {Object} object The object to clone.\n * @returns {Object} Returns the initialized clone.\n */\nfunction initCloneObject(object) {\n return (typeof object.constructor == 'function' && !isPrototype(object))\n ? baseCreate(getPrototype(object))\n : {};\n}\n\nexport default initCloneObject;\n","import getTag from './_getTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar mapTag = '[object Map]';\n\n/**\n * The base implementation of `_.isMap` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a map, else `false`.\n */\nfunction baseIsMap(value) {\n return isObjectLike(value) && getTag(value) == mapTag;\n}\n\nexport default baseIsMap;\n","import baseIsMap from './_baseIsMap.js';\nimport baseUnary from './_baseUnary.js';\nimport nodeUtil from './_nodeUtil.js';\n\n/* Node.js helper references. */\nvar nodeIsMap = nodeUtil && nodeUtil.isMap;\n\n/**\n * Checks if `value` is classified as a `Map` object.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a map, else `false`.\n * @example\n *\n * _.isMap(new Map);\n * // => true\n *\n * _.isMap(new WeakMap);\n * // => false\n */\nvar isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap;\n\nexport default isMap;\n","import getTag from './_getTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar setTag = '[object Set]';\n\n/**\n * The base implementation of `_.isSet` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a set, else `false`.\n */\nfunction baseIsSet(value) {\n return isObjectLike(value) && getTag(value) == setTag;\n}\n\nexport default baseIsSet;\n","import baseIsSet from './_baseIsSet.js';\nimport baseUnary from './_baseUnary.js';\nimport nodeUtil from './_nodeUtil.js';\n\n/* Node.js helper references. */\nvar nodeIsSet = nodeUtil && nodeUtil.isSet;\n\n/**\n * Checks if `value` is classified as a `Set` object.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a set, else `false`.\n * @example\n *\n * _.isSet(new Set);\n * // => true\n *\n * _.isSet(new WeakSet);\n * // => false\n */\nvar isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet;\n\nexport default isSet;\n","import Stack from './_Stack.js';\nimport arrayEach from './_arrayEach.js';\nimport assignValue from './_assignValue.js';\nimport baseAssign from './_baseAssign.js';\nimport baseAssignIn from './_baseAssignIn.js';\nimport cloneBuffer from './_cloneBuffer.js';\nimport copyArray from './_copyArray.js';\nimport copySymbols from './_copySymbols.js';\nimport copySymbolsIn from './_copySymbolsIn.js';\nimport getAllKeys from './_getAllKeys.js';\nimport getAllKeysIn from './_getAllKeysIn.js';\nimport getTag from './_getTag.js';\nimport initCloneArray from './_initCloneArray.js';\nimport initCloneByTag from './_initCloneByTag.js';\nimport initCloneObject from './_initCloneObject.js';\nimport isArray from './isArray.js';\nimport isBuffer from './isBuffer.js';\nimport isMap from './isMap.js';\nimport isObject from './isObject.js';\nimport isSet from './isSet.js';\nimport keys from './keys.js';\nimport keysIn from './keysIn.js';\n\n/** Used to compose bitmasks for cloning. */\nvar CLONE_DEEP_FLAG = 1,\n CLONE_FLAT_FLAG = 2,\n CLONE_SYMBOLS_FLAG = 4;\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]',\n arrayTag = '[object Array]',\n boolTag = '[object Boolean]',\n dateTag = '[object Date]',\n errorTag = '[object Error]',\n funcTag = '[object Function]',\n genTag = '[object GeneratorFunction]',\n mapTag = '[object Map]',\n numberTag = '[object Number]',\n objectTag = '[object Object]',\n regexpTag = '[object RegExp]',\n setTag = '[object Set]',\n stringTag = '[object String]',\n symbolTag = '[object Symbol]',\n weakMapTag = '[object WeakMap]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n dataViewTag = '[object DataView]',\n float32Tag = '[object Float32Array]',\n float64Tag = '[object Float64Array]',\n int8Tag = '[object Int8Array]',\n int16Tag = '[object Int16Array]',\n int32Tag = '[object Int32Array]',\n uint8Tag = '[object Uint8Array]',\n uint8ClampedTag = '[object Uint8ClampedArray]',\n uint16Tag = '[object Uint16Array]',\n uint32Tag = '[object Uint32Array]';\n\n/** Used to identify `toStringTag` values supported by `_.clone`. */\nvar cloneableTags = {};\ncloneableTags[argsTag] = cloneableTags[arrayTag] =\ncloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =\ncloneableTags[boolTag] = cloneableTags[dateTag] =\ncloneableTags[float32Tag] = cloneableTags[float64Tag] =\ncloneableTags[int8Tag] = cloneableTags[int16Tag] =\ncloneableTags[int32Tag] = cloneableTags[mapTag] =\ncloneableTags[numberTag] = cloneableTags[objectTag] =\ncloneableTags[regexpTag] = cloneableTags[setTag] =\ncloneableTags[stringTag] = cloneableTags[symbolTag] =\ncloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =\ncloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;\ncloneableTags[errorTag] = cloneableTags[funcTag] =\ncloneableTags[weakMapTag] = false;\n\n/**\n * The base implementation of `_.clone` and `_.cloneDeep` which tracks\n * traversed objects.\n *\n * @private\n * @param {*} value The value to clone.\n * @param {boolean} bitmask The bitmask flags.\n * 1 - Deep clone\n * 2 - Flatten inherited properties\n * 4 - Clone symbols\n * @param {Function} [customizer] The function to customize cloning.\n * @param {string} [key] The key of `value`.\n * @param {Object} [object] The parent object of `value`.\n * @param {Object} [stack] Tracks traversed objects and their clone counterparts.\n * @returns {*} Returns the cloned value.\n */\nfunction baseClone(value, bitmask, customizer, key, object, stack) {\n var result,\n isDeep = bitmask & CLONE_DEEP_FLAG,\n isFlat = bitmask & CLONE_FLAT_FLAG,\n isFull = bitmask & CLONE_SYMBOLS_FLAG;\n\n if (customizer) {\n result = object ? customizer(value, key, object, stack) : customizer(value);\n }\n if (result !== undefined) {\n return result;\n }\n if (!isObject(value)) {\n return value;\n }\n var isArr = isArray(value);\n if (isArr) {\n result = initCloneArray(value);\n if (!isDeep) {\n return copyArray(value, result);\n }\n } else {\n var tag = getTag(value),\n isFunc = tag == funcTag || tag == genTag;\n\n if (isBuffer(value)) {\n return cloneBuffer(value, isDeep);\n }\n if (tag == objectTag || tag == argsTag || (isFunc && !object)) {\n result = (isFlat || isFunc) ? {} : initCloneObject(value);\n if (!isDeep) {\n return isFlat\n ? copySymbolsIn(value, baseAssignIn(result, value))\n : copySymbols(value, baseAssign(result, value));\n }\n } else {\n if (!cloneableTags[tag]) {\n return object ? value : {};\n }\n result = initCloneByTag(value, tag, isDeep);\n }\n }\n // Check for circular references and return its corresponding clone.\n stack || (stack = new Stack);\n var stacked = stack.get(value);\n if (stacked) {\n return stacked;\n }\n stack.set(value, result);\n\n if (isSet(value)) {\n value.forEach(function(subValue) {\n result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack));\n });\n } else if (isMap(value)) {\n value.forEach(function(subValue, key) {\n result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack));\n });\n }\n\n var keysFunc = isFull\n ? (isFlat ? getAllKeysIn : getAllKeys)\n : (isFlat ? keysIn : keys);\n\n var props = isArr ? undefined : keysFunc(value);\n arrayEach(props || value, function(subValue, key) {\n if (props) {\n key = subValue;\n subValue = value[key];\n }\n // Recursively populate clone (susceptible to call stack limits).\n assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack));\n });\n return result;\n}\n\nexport default baseClone;\n","import baseClone from './_baseClone.js';\n\n/** Used to compose bitmasks for cloning. */\nvar CLONE_DEEP_FLAG = 1,\n CLONE_SYMBOLS_FLAG = 4;\n\n/**\n * This method is like `_.clone` except that it recursively clones `value`.\n *\n * @static\n * @memberOf _\n * @since 1.0.0\n * @category Lang\n * @param {*} value The value to recursively clone.\n * @returns {*} Returns the deep cloned value.\n * @see _.clone\n * @example\n *\n * var objects = [{ 'a': 1 }, { 'b': 2 }];\n *\n * var deep = _.cloneDeep(objects);\n * console.log(deep[0] === objects[0]);\n * // => false\n */\nfunction cloneDeep(value) {\n return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG);\n}\n\nexport default cloneDeep;\n","/**\n * Builds the `rehype-sanitize` schema used by the internal markdown renderer.\n *\n * Extracted into its own module so the merge logic can be unit-tested in\n * isolation without pulling in React or the full markdown pipeline.\n *\n * @module components/sanitizeSchema\n */\n\nimport cloneDeep from 'lodash-es/cloneDeep';\nimport { defaultSchema } from 'rehype-sanitize';\n\ntype Schema = typeof defaultSchema;\ntype AttributeEntry = NonNullable<NonNullable<Schema['attributes']>[string]>[number];\n\n/**\n * Extend the allowlist for a tag's `className` attribute with extra class\n * names while preserving all other default entries.\n *\n * `findDefinition` in hast-util-sanitize returns the *first* matching entry\n * for a given property name, so appending a second `className` entry would be\n * ignored. Instead, merge the allowed values into the existing entry.\n *\n * Edge cases:\n * - `existing` is `undefined` → returns a single new `['className', ...extra]`\n * - `existing` has no `className` entry → appends one with just the extras\n * - `existing` has a bare-string `'className'` entry (hast-util-sanitize's\n * \"allow all values\" form) → would be narrowed to an allow-list. This is a\n * semantics change, but the current `defaultSchema.attributes.code` entry\n * is always tuple-form, so this branch is defensive only.\n */\nexport function mergeClassNameAllowlist(\n existing: ReadonlyArray<AttributeEntry> | undefined,\n extraClassNames: readonly string[]\n): AttributeEntry[] {\n const entries: AttributeEntry[] = existing ? [...existing] : [];\n const idx = entries.findIndex((entry) =>\n typeof entry === 'string' ? entry === 'className' : entry[0] === 'className'\n );\n if (idx === -1) {\n return [...entries, ['className', ...extraClassNames]];\n }\n const current = entries[idx];\n const merged: AttributeEntry =\n typeof current === 'string' ? ['className', ...extraClassNames] : [...current, ...extraClassNames];\n entries[idx] = merged;\n return entries;\n}\n\nconst crossChunkTags = ['cross-chunk-link', 'cross-chunk-image', 'footnote-sup'] as const;\n\n/**\n * The full sanitize schema used by the markdown renderer: extends\n * `defaultSchema` to allow `<mark>`, the KaTeX math class names, and the\n * three custom hast tags emitted by cross-chunk coordination handlers.\n *\n * **Owns its arrays and objects.** The shallow spread of `defaultSchema`\n * alone would leave `attributes.a`, `attributes.img`, `protocols`,\n * `ancestors`, and similar nested fields aliased to `rehype-sanitize`'s\n * default singleton. A consumer who reasonably (but mistakenly) writes\n * `sanitizeSchema.protocols.href.push('myapp')` would then poison\n * `rehype-sanitize`'s `defaultSchema` for every other consumer in the\n * process — a cross-package side-effect that's near-impossible to debug.\n *\n * One `cloneDeep` at module init breaks that aliasing without measurable\n * cost (init-time only, single small object graph). The recommended\n * extension API is still {@link extendSanitizeSchema}, which clones again\n * per call; this layer just makes the exported singleton safe if someone\n * skips the helper.\n *\n * **Deep-frozen.** The engine barrel exports this object, and a mutation\n * (`sanitizeSchema.tagNames.push('script')`) would silently widen the\n * sanitizer for every renderer in the process — the README calls it a\n * read-only singleton, so it is one (2026-08-19 review r2 P3). lodash\n * `cloneDeep` of a frozen graph yields a MUTABLE copy, so\n * `extendSanitizeSchema` drafts are unaffected.\n *\n * `strip` (elements dropped WITH their content, instead of unwrapped to\n * their children) covers the raw-text elements whose content is never\n * prose: `<style>a{b:c}</style>` used to leave `a{b:c}` as body text —\n * common in LLM answers that emit a `<style>` block (r2 P3).\n */\nfunction deepFreeze<T>(value: T): T {\n if (value !== null && typeof value === 'object' && !Object.isFrozen(value)) {\n Object.freeze(value);\n for (const key of Object.keys(value as object)) deepFreeze((value as Record<string, unknown>)[key]);\n }\n return value;\n}\n\n/** Raw-text elements stripped with their content (see above). `script` is\n * rehype-sanitize's own default. */\nconst STRIPPED_TAGS = ['script', 'style', 'title', 'textarea', 'noframes', 'noembed', 'xmp', 'iframe', 'plaintext'];\n\nexport const sanitizeSchema: Schema = deepFreeze(\n cloneDeep({\n ...defaultSchema,\n tagNames: [...(defaultSchema.tagNames || []), 'mark', ...crossChunkTags],\n attributes: {\n ...defaultSchema.attributes,\n code: mergeClassNameAllowlist(defaultSchema.attributes?.code, ['math-inline', 'math-display']),\n 'cross-chunk-link': ['label', 'referenceType', 'documentId', 'localUrl', 'localTitle'],\n 'cross-chunk-image': ['label', 'referenceType', 'documentId', 'alt', 'localUrl', 'localTitle'],\n 'footnote-sup': ['label', 'localOccurrence', 'localNumber', 'documentId'],\n },\n strip: [...new Set([...(defaultSchema.strip || []), ...STRIPPED_TAGS])],\n })\n);\n","/**\n * Type definitions for the sealed engine plugin system (v2 input surface).\n *\n * An \"engine plugin\" is a first-class, core-exported description of one\n * configurable entry in the unified plugin chain. The five shipped plugins\n * replace the two v1.x enums (`AIMarkdownRenderExtraSyntax` /\n * `AIMarkdownRenderDisplayOptimizeAbility`) as the public way to select\n * optional parse-level capability.\n *\n * ## Why the set is sealed\n *\n * The incremental (prefix-freeze) parse engine's boundary scanner is\n * syntax-aware — it must know the boundary rules of every multiline\n * construct in the chain (see `computeFreezeBoundary`'s `defListEnabled`\n * option). Open plugin injection would void the engine's verification\n * record (50k-sample fuzz, direction batteries, byte equivalence), so\n * plugins are born where the certification rig lives: `packages/core`.\n * Wrappers curate (bundle default sets, filter, facade sugar); consumers\n * select. New parse-level capability lands via an upstream PR into core.\n * Third-party *content* extension stays open through `contentPreprocessors`\n * and `customComponents`.\n *\n * ## Seal mechanics\n *\n * The seal is a type-level contract and design declaration, not runtime\n * tamper-proofing — the same guarantee class as `Object.freeze`. The\n * `'~sealed'` marker key makes accidental construction a type error while\n * keeping the type structural, which is required for the type to remain\n * assignable across the package's two build entries (the root entry and\n * the `/plugins` subpath must stay mutually assignable whether or not the\n * build duplicates this declaration per entry; a `unique symbol` brand\n * would break the duplicated case. Current tsup output happens to share\n * one declaration chunk between the entries — an implementation detail\n * the seal deliberately does not lean on). A second, runtime gate\n * (`getEnginePluginInternals`, enforced in `sanitizeEnginePlugins`)\n * additionally rejects any object that lacks EITHER the marker or the\n * internal stage metadata, so a type-level forge is dropped at runtime\n * with a dev warning. Deliberately forging both keys voids the engine's\n * verification record.\n *\n * @module plugins/defs\n */\n\n/**\n * Names of the shipped engine plugins. Closed to third-party EXTENSION (see\n * module docs), but an OPEN set across 2.x versions: new plugin names may be\n * added in minor releases. Do not write exhaustive `switch` statements or\n * `Record<AIMarkdownEnginePluginName, …>` maps over this union — both break\n * on the next addition. Feature-test with `Set`/`includes` instead.\n */\nexport type AIMarkdownEnginePluginName = 'highlight' | 'definitionList' | 'smartypants' | 'pangu' | 'removeComments';\n\n/**\n * A sealed engine plugin. Values are core-exported singletons from\n * `@ai-react-markdown/core/plugins`; pass them to the `enginePlugins` prop\n * of `<AIMarkdown>`.\n *\n * - Passing an array replaces the default set wholesale (array-atomic\n * semantics); omitting the prop means `defaultEnginePlugins` (all five).\n * - The produced chain position of each plugin comes from canonical\n * per-stage tables keyed by name (`pluginChain.ts`) — the order of the\n * user-supplied array is irrelevant.\n * - Duplicate members are deduplicated with a dev warning.\n * - Serializing plugin objects is unsupported; transport\n * {@link AIMarkdownEnginePlugin.name} instead and map names back to the\n * exported singletons at the edge (remote-config scenarios).\n */\nexport interface AIMarkdownEnginePlugin {\n /** Stable identifier; the serialization escape hatch. */\n readonly name: AIMarkdownEnginePluginName;\n /**\n * @internal Type-level seal — constructible only inside core. Third-party\n * construction (including deliberately forging this marker) voids the\n * incremental engine's verification record.\n */\n readonly '~sealed': 'ai-react-markdown/engine-plugin';\n}\n\n/**\n * Chain stage a plugin belongs to. Determines the plugin's splice position\n * in the produced remark chain — user array order never does.\n * @internal\n */\nexport type EnginePluginStage = 'extraSyntax' | 'displayOptimize';\n\n/**\n * Runtime metadata carried by every sealed plugin object. Not part of the\n * public type — internal consumers read it through\n * {@link getEnginePluginInternals}.\n * @internal\n */\nexport interface EnginePluginInternals {\n readonly stage: EnginePluginStage;\n}\n\n/**\n * Read a sealed plugin's internal metadata. Returns `null` for objects that\n * do not carry it (a forged or foreign object) so callers can reject them\n * defensively instead of crashing.\n * @internal\n */\nexport function getEnginePluginInternals(plugin: AIMarkdownEnginePlugin): EnginePluginInternals | null {\n const candidate = plugin as unknown as (Partial<EnginePluginInternals> & Partial<AIMarkdownEnginePlugin>) | null;\n // Both keys are required, so the runtime gate matches the type-level seal:\n // an object carrying only the public `'~sealed'` marker (a deliberate\n // forge) or only the internal `stage` (an untyped structural mimic) is\n // rejected either way.\n return candidate != null && candidate['~sealed'] === 'ai-react-markdown/engine-plugin' && candidate.stage != null\n ? (candidate as EnginePluginInternals)\n : null;\n}\n","/**\n * The five shipped engine plugins and the default set.\n *\n * Construction happens ONLY here (principle P7: capability construction\n * follows the verification harness — the certification rig lives in this\n * package). Each object is frozen and carries internal stage metadata that\n * fixes its position in the produced chain; see `plugins/defs.ts` for the\n * seal rationale.\n *\n * @module plugins/catalog\n */\n\nimport type { AIMarkdownEnginePlugin, AIMarkdownEnginePluginName, EnginePluginInternals } from './defs';\n\nconst seal = (name: AIMarkdownEnginePluginName, stage: EnginePluginInternals['stage']): AIMarkdownEnginePlugin =>\n Object.freeze({\n name,\n '~sealed': 'ai-react-markdown/engine-plugin',\n stage,\n }) as AIMarkdownEnginePlugin;\n\n/** `==Highlight==` syntax support (v1.x: `AIMarkdownRenderExtraSyntax.HIGHLIGHT`). */\nexport const highlight = seal('highlight', 'extraSyntax');\n\n/**\n * Definition list syntax (v1.x: `AIMarkdownRenderExtraSyntax.DEFINITION_LIST`).\n * @see https://michelf.ca/projects/php-markdown/extra/#def-list\n */\nexport const definitionList = seal('definitionList', 'extraSyntax');\n\n/** Strip HTML comments from the content (v1.x: `REMOVE_COMMENTS`). */\nexport const removeComments = seal('removeComments', 'displayOptimize');\n\n/**\n * Typographic enhancements via SmartyPants — curly quotes, em-dashes, etc.\n * (v1.x: `SMARTYPANTS`). @see https://www.npmjs.com/package/smartypants\n */\nexport const smartypants = seal('smartypants', 'displayOptimize');\n\n/** Automatic spacing between CJK and half-width characters (v1.x: `PANGU`). */\nexport const pangu = seal('pangu', 'displayOptimize');\n\n/**\n * The default engine plugin set — all five, in canonical chain order.\n * Parity with the v1.x shipped defaults (`defaultAIMarkdownRenderConfig`).\n *\n * The recommended \"turn one off\" idiom:\n * ```ts\n * <AIMarkdown enginePlugins={defaultEnginePlugins.filter((p) => p !== pangu)} />\n * ```\n */\nexport const defaultEnginePlugins: readonly AIMarkdownEnginePlugin[] = Object.freeze([\n highlight,\n definitionList,\n removeComments,\n smartypants,\n pangu,\n]);\n","/**\n * Shorten long consumer-supplied `documentId` values down to a fixed-length\n * Base62 hash so they don't bloat every rendered `id=\"…\"` / `href=\"#…\"`.\n *\n * Trade-offs:\n * - Non-cryptographic hash (MurmurHash3 x86 32-bit) — pure speed, excellent\n * avalanche on the structured inputs we actually receive (UUIDs, nanoids,\n * `useId()` outputs, opaque chat-message ids). Collision domain is 2^32;\n * at ~77,000 active document ids the birthday-paradox collision rate hits\n * ~50%, which is far beyond any realistic single-page chat workload.\n * - Only kicks in past a length threshold (default 16) so short, hand-picked\n * ids stay readable and existing test fixtures (`'tst'`, `'doc-a'`, …)\n * plus `useId()`'s `'_r_0_'`-style output (≤7 chars) pass through untouched.\n * - Pure function: same input always yields the same output. Two chunks\n * sharing one logical `documentId` therefore still produce identical\n * prefixes, so cross-chunk anchor and footnote coordination is preserved.\n *\n * Why MurmurHash3 specifically (vs the simpler FNV-1a):\n * - FNV-1a does NOT pass SMHasher's avalanche test. For *structured* inputs\n * like UUIDs (fixed hyphen positions, hex-only alphabet) its lower bits\n * show measurable bias, which translates to a higher *practical* collision\n * rate than the theoretical 2^32 figure suggests.\n * - MurmurHash3's finalizer (`fmix32`) — `h ^= h>>>16; h = imul(h, M1);\n * h ^= h>>>13; h = imul(h, M2); h ^= h>>>16` — is purpose-built to\n * flatten any local pattern that survives the body, which is what gets\n * it through SMHasher. That's the entire engineering reason for the\n * ~30-line code-size delta vs FNV-1a.\n *\n * @module components/shortenDocumentId\n */\n\nconst BASE62_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n\n/** Encode a non-negative 32-bit integer as a Base62 string (no padding). */\nfunction toBase62(n: number): string {\n if (n === 0) return BASE62_ALPHABET[0];\n // Treat `n` as unsigned 32-bit so the sign bit doesn't make the loop spin.\n let v = n >>> 0;\n let out = '';\n while (v > 0) {\n out = BASE62_ALPHABET[v % 62] + out;\n v = Math.floor(v / 62);\n }\n return out;\n}\n\n/** 32-bit unsigned rotate-left, in pure JS. */\nfunction rotl32(x: number, r: number): number {\n return ((x << r) | (x >>> (32 - r))) >>> 0;\n}\n\n// MurmurHash3 x86 32-bit mixing constants — from Appleby's reference impl.\n// Naming follows the spec so the code reads against the paper verbatim.\nconst C1 = 0xcc9e2d51;\nconst C2 = 0x1b873593;\n\n// Single TextEncoder reused per process — instantiation is non-trivial and\n// the hash runs once per `<AIMarkdown>` provider commit. UTF-8 bytes (not\n// JS UTF-16 code units) are the canonical Murmur3 input so the hash stays\n// portable with reference implementations in other languages.\nconst UTF8_ENCODER = /* @__PURE__ */ new TextEncoder();\n\n/**\n * MurmurHash3 x86 32-bit. Pure function over the UTF-8 byte sequence of `s`.\n *\n * Implementation notes:\n * - `Math.imul(a, b)` performs signed 32-bit integer multiplication with\n * proper overflow truncation. Plain `a * b` would promote to IEEE-754\n * double and silently lose precision past 2^53, breaking the hash.\n * - The body processes the input in 4-byte little-endian blocks; the\n * 1–3 byte tail is folded in with the canonical Murmur3 cascade.\n * - The finalize step (the three `imul` + `xor >>> n` lines below the\n * tail) is `fmix32` — the avalanche stage that distinguishes Murmur3\n * from naive multiply-xor hashes.\n *\n * @param s - Arbitrary input string (any Unicode).\n * @param seed - Optional 32-bit seed. Defaults to `0` for deterministic\n * reproducibility across machines.\n * @returns Unsigned 32-bit integer.\n */\nfunction murmur3_32(s: string, seed: number = 0): number {\n return murmur3_32_bytes(UTF8_ENCODER.encode(s), seed);\n}\n\n/**\n * MurmurHash3 x86 32-bit over an explicit byte sequence. Split out from\n * `murmur3_32` so the ill-formed-id branch of `shortenDocumentId` can hash\n * raw UTF-16LE code units — `TextEncoder` is lossy on unpaired surrogates\n * (WHATWG USVString conversion folds every lone surrogate to U+FFFD), so\n * feeding it an ill-formed string would silently merge distinct ids.\n */\nfunction murmur3_32_bytes(bytes: Uint8Array, seed: number = 0): number {\n const len = bytes.length;\n let h1 = seed >>> 0;\n const nblocks = len >>> 2;\n\n // ── Body: 4-byte little-endian blocks ───────────────────────────────────\n for (let i = 0; i < nblocks; i++) {\n const b = i * 4;\n let k1 = bytes[b] | (bytes[b + 1] << 8) | (bytes[b + 2] << 16) | (bytes[b + 3] << 24);\n\n k1 = Math.imul(k1, C1);\n k1 = rotl32(k1, 15);\n k1 = Math.imul(k1, C2);\n\n h1 ^= k1;\n h1 = rotl32(h1, 13);\n h1 = (Math.imul(h1, 5) + 0xe6546b64) >>> 0;\n }\n\n // ── Tail: 1–3 leftover bytes, folded in with classic Murmur3 cascade ────\n // The three `if`s implement C-style switch fallthrough: rem==3 runs all\n // three statements; rem==2 runs the bottom two; rem==1 runs only the last\n // block (which is the one that also mixes into h1).\n const tail = nblocks * 4;\n const rem = len & 3;\n if (rem > 0) {\n let k1 = 0;\n if (rem === 3) k1 ^= bytes[tail + 2] << 16;\n if (rem >= 2) k1 ^= bytes[tail + 1] << 8;\n k1 ^= bytes[tail];\n k1 = Math.imul(k1, C1);\n k1 = rotl32(k1, 15);\n k1 = Math.imul(k1, C2);\n h1 ^= k1;\n }\n\n // ── Finalize (fmix32): the avalanche stage ──────────────────────────────\n h1 ^= len;\n h1 ^= h1 >>> 16;\n h1 = Math.imul(h1, 0x85ebca6b);\n h1 ^= h1 >>> 13;\n h1 = Math.imul(h1, 0xc2b2ae35);\n h1 ^= h1 >>> 16;\n\n return h1 >>> 0;\n}\n\n// With the `u` flag this character class matches ONLY unpaired surrogates:\n// a valid pair reads as one astral code point, which lies outside\n// [U+D800, U+DFFF]. Dropping the flag would make it match each HALF of a\n// valid pair and misclassify ordinary emoji ids — the flag is load-bearing.\nconst LONE_SURROGATE_RE = /[\\uD800-\\uDFFF]/u;\n\n/**\n * Whether `id` is ill-formed UTF-16 (contains at least one unpaired\n * surrogate — typically the fallout of an upstream pipeline slicing a\n * string mid-emoji). Exported as the single owner of the detection\n * semantics so consumers (e.g. core's dev-mode documentId warning) cannot\n * drift from the branch condition inside `shortenDocumentId`.\n */\nexport function hasLoneSurrogate(id: string): boolean {\n return LONE_SURROGATE_RE.test(id);\n}\n\n/**\n * Domain-separation seed for hashing ill-formed ids. Ill-formed ids hash\n * over raw UTF-16LE code-unit bytes while long well-formed ids hash over\n * UTF-8 bytes — and the two byte encodings can collide: a lone-surrogate\n * id's UTF-16LE byte sequence can equal some well-formed id's UTF-8 byte\n * sequence (e.g. utf16le(\"\\uD800\\u4E80\") === utf8(\"\\u0000\\u0600N\")\n * === [00 D8 80 4E]; both sides padded past the threshold to actually\n * reach the two hash branches). A distinct seed makes equal byte inputs\n * produce unrelated hashes, reducing cross-domain collisions to the\n * generic 2^32 class.\n */\nconst ILL_FORMED_SEED = 1;\n\n/**\n * Raw UTF-16LE code-unit bytes of `s` — total and trivially injective on\n * ALL JavaScript strings, unlike UTF-8 encoding, which is lossy on\n * ill-formed input (`TextEncoder` folds every lone surrogate to U+FFFD).\n */\nfunction utf16leBytes(s: string): Uint8Array {\n const bytes = new Uint8Array(s.length * 2);\n for (let i = 0; i < s.length; i++) {\n const c = s.charCodeAt(i);\n bytes[i * 2] = c & 0xff;\n bytes[i * 2 + 1] = c >>> 8;\n }\n return bytes;\n}\n\n/**\n * Shorten a `documentId` for use inside an HTML id prefix.\n *\n * Well-formed ids keep the original contract byte-for-byte: at or below\n * `threshold` they pass through verbatim; above it they hash via\n * MurmurHash3 over UTF-8 bytes to a 1–6 char Base62 form.\n *\n * Ill-formed UTF-16 ids (unpaired surrogates, e.g. from an upstream\n * pipeline slicing a string mid-emoji) are ALWAYS hashed, regardless of\n * length — over their raw UTF-16LE code units, seeded with\n * `ILL_FORMED_SEED`. Rationale (issue #32):\n *\n * - Returned verbatim, a lone surrogate makes the caller's\n * `encodeURIComponent` throw `URIError: URI malformed` synchronously,\n * aborting the whole render before any markdown is parsed.\n * - Hashing the WHATWG lossy projection (lone surrogates → U+FFFD, what\n * `TextEncoder`/`toWellFormed()` do) was rejected: it silently merges\n * distinct corrupted ids — and merges them with a well-formed id\n * containing a literal U+FFFD — turning the old loud error into a\n * silent cross-document anchor collision.\n * - Escaping into a well-formed string before hashing was rejected too:\n * a naive marker scheme is not injective (marker-lookalike content\n * forges it), and an escape-the-escape scheme is strictly more code\n * than hashing the raw code units, which is injective for free.\n *\n * Distinct ids therefore produce distinct prefixes up to the generic 2^32\n * birthday bound — the same guarantee long well-formed ids always had —\n * with no equivalence-class carve-out for corrupted input.\n *\n * @param id - The raw documentId (consumer-supplied or `useId()` fallback).\n * Any JavaScript string is accepted, including ill-formed UTF-16.\n * @param threshold - Only well-formed ids strictly longer than this get\n * hashed. Defaults to `16`, which leaves short hand-picked ids and\n * React's `useId()` outputs unchanged but catches UUIDs (36 chars) and\n * nanoids. Ill-formed ids ignore the threshold — they always hash.\n * @returns The original `id` (well-formed and short) or a 1–6 char Base62\n * hash (well-formed long, or ill-formed of any length).\n */\nexport function shortenDocumentId(id: string, threshold: number = 16): string {\n if (hasLoneSurrogate(id)) return toBase62(murmur3_32_bytes(utf16leBytes(id), ILL_FORMED_SEED));\n if (id.length <= threshold) return id;\n return toBase62(murmur3_32(id));\n}\n","/**\n * Dev-only pipeline stage timing.\n *\n * The block-memo render path runs four distinct stages per content change\n * (parse → transform → build → render). Which one dominates depends on the\n * workload — plugin mix, document length, math density — and every\n * optimization decision should start from that split, not from a guess.\n *\n * Two delivery channels, deliberately separate:\n *\n * - **Programmatic consumers** (the BlockMemoCompare story's profiler)\n * use {@link subscribeStageTimings} — a private, direct callback\n * channel. It must NOT go through the User Timing API: React 19 dev\n * builds emit one `performance.measure` per component render\n * (\"component tracks\"), so a page-global 'measure' observer receives a\n * flood of foreign entries it has to filter, and — measured — anything\n * that scans or clears the buffer becomes O(buffer) with MILLIONS of\n * entries in a long session.\n * - **DevTools timeline visibility**: {@link measureStage} still emits\n * one `performance.measure` per stage, named\n * `ai-markdown:stage:<stage>`. Emission is an append — cheap. It does\n * NOT clear per name afterwards: Chromium's `clearMeasures(name)` scans\n * the whole buffer, and under the React-dev flood that per-call scan\n * cost ~35% of main-thread time ON THE INSTRUMENTED SIDE ONLY —\n * inverting the very benchmark this instrumentation serves. Our own\n * growth is ~4 entries per streamed token; the benchmark harness\n * bulk-clears the buffer between runs (see useRenderProfiler.reset).\n *\n * Production builds fold {@link ENABLED} to `false`: the dual dev/prod\n * build resolves `process.env.NODE_ENV` at build time (tsup `env`), so\n * the published dist carries no env read at all; in-repo src consumers\n * (storybook, vitest) run under Vite/Node where the text is substituted\n * or `process` exists. The whole thing costs one boolean check per stage.\n *\n * @module components/devStageTimings\n */\n\n/** The stages of the block-memo render pipeline, in execution order.\n * Single source of truth: the union type, the emitted measure names, and\n * any display ordering (ProfilerPanel) all derive from this tuple.\n * `scan` is the incremental-parse boundary detector (emitted only when\n * `incrementalParse` routes through the incremental engine);\n * when incremental parsing splices, `parse`/`transform` cover the\n * TAIL-ONLY work — the honest per-frame cost, not the full-document one. */\nexport const PIPELINE_STAGES = ['scan', 'parse', 'transform', 'build', 'render'] as const;\nexport type PipelineStage = (typeof PIPELINE_STAGES)[number];\n\n/** Prefix for the emitted `performance.measure` entry names. */\nexport const STAGE_MEASURE_PREFIX = 'ai-markdown:stage:';\n\n/** Hoisted name table — measure names are shared constants, not a fresh\n * template-literal allocation per call. */\nconst STAGE_NAMES = Object.fromEntries(\n PIPELINE_STAGES.map((stage) => [stage, `${STAGE_MEASURE_PREFIX}${stage}`])\n) as Record<PipelineStage, string>;\n\n/**\n * One-time capability gate. Beyond the DEV check, probes the exact call\n * {@link measureStage} makes — the options-object `measure` overload — by\n * performing it once. Environments that expose `performance.measure` but\n * only support the legacy mark-name overloads (older jsdom, partial\n * polyfills) fail the probe and are gated off permanently, instead of\n * paying a thrown-and-swallowed exception per stage per token for the\n * whole session.\n */\nconst ENABLED: boolean =\n process.env.NODE_ENV !== 'production' &&\n (() => {\n if (typeof performance === 'undefined' || typeof performance.measure !== 'function') {\n return false;\n }\n try {\n const probe = `${STAGE_MEASURE_PREFIX}probe`;\n performance.measure(probe, { start: 0, end: 0 });\n performance.clearMeasures?.(probe);\n return true;\n } catch {\n return false;\n }\n })();\n\n/** `instanceId` is the emitting `<AIMarkdown>`'s documentId — listeners on a\n * page with several instances (e.g. an A/B comparison where BOTH sides run\n * the block-memo path) filter by it; a page-wide aggregate ignores it. */\ntype StageListener = (stage: PipelineStage, durationMs: number, instanceId?: string) => void;\nconst stageListeners = new Set<StageListener>();\n\n/**\n * Subscribe to stage timings over the private callback channel (dev-only;\n * in production builds {@link measureStage} never emits, so listeners\n * simply stay silent). Returns an unsubscribe function.\n *\n * This exists so the benchmark profiler does NOT have to observe the\n * page-global 'measure' entry type: React 19 dev floods that channel with\n * one measure per component render, which would have to be filtered per\n * batch — and the module-level listener set is still page-scoped, so the\n * one-consumer-per-page discipline from the story docs continues to apply.\n */\nexport function subscribeStageTimings(listener: StageListener): () => void {\n stageListeners.add(listener);\n return () => {\n stageListeners.delete(listener);\n };\n}\n\n/**\n * Run `fn` as the named pipeline stage. In dev: notifies\n * {@link subscribeStageTimings} listeners and emits one\n * `performance.measure` for DevTools timeline visibility. The\n * single-callable shape (instead of a start/end pair) makes the stage\n * name a typed argument and the pairing unforgettable: a call site cannot\n * mismatch or drop an end call. If `fn` throws, nothing is emitted for\n * the aborted stage.\n *\n * NOTE: emission is append-only — never clear per name from here. See the\n * module docs: `clearMeasures(name)` is O(page buffer), and React 19\n * dev's component tracks grow that buffer without bound.\n */\nexport function measureStage<T>(stage: PipelineStage, fn: () => T, instanceId?: string): T {\n if (!ENABLED) return fn();\n const start = performance.now();\n const result = fn();\n const end = performance.now();\n for (const listener of stageListeners) listener(stage, end - start, instanceId);\n // Probe-verified call — no per-call try/catch needed.\n performance.measure(STAGE_NAMES[stage], { start, end });\n return result;\n}\n","/**\n * Builds a `rehype-sanitize` schema by handing the caller a deep clone of\n * the library's internal default schema to mutate or replace.\n *\n * The mutate-and-return pattern matches the ergonomics of Next.js's\n * `webpack(config)` and Express middleware: a callback receives a draft,\n * either modifies it in place (returning nothing) or returns a fresh object\n * to replace it. The library guarantees the draft is a deep clone, so direct\n * mutation never leaks into the singleton — and the singleton itself is not\n * exported, so consumers cannot accidentally hand-roll a schema that drops\n * the library's cross-chunk tag allowlist or KaTeX className additions.\n *\n * @module components/extendSanitizeSchema\n */\n\nimport cloneDeep from 'lodash-es/cloneDeep';\nimport type { defaultSchema } from 'rehype-sanitize';\nimport { sanitizeSchema } from './sanitizeSchema';\n\n/**\n * The full `rehype-sanitize` schema type. Re-exported as the canonical\n * library-internal alias so other modules don't each redeclare\n * `typeof defaultSchema`.\n *\n * The shape is owned by `rehype-sanitize`; consumers should treat it as\n * tracking that upstream type — it may evolve across rehype-sanitize major\n * versions.\n */\nexport type SanitizeSchema = typeof defaultSchema;\n\n/**\n * Build a sanitize schema by mutating (or replacing) a deep clone of the\n * library default.\n *\n * Designed to be called ONCE at module scope so the returned object has a\n * stable identity across renders — passing it directly into\n * `<AIMarkdown sanitizeSchema={…}>` keeps the block-memo cache warm.\n *\n * @example Append a custom URL protocol via mutation:\n * ```ts\n * const SCHEMA = extendSanitizeSchema((s) => {\n * s.protocols!.href!.push('myapp');\n * s.protocols!.src!.push('myapp');\n * });\n *\n * function App() {\n * return <AIMarkdown content={…} sanitizeSchema={SCHEMA} />;\n * }\n * ```\n *\n * @example Return-style replacement for wider edits:\n * ```ts\n * const SCHEMA = extendSanitizeSchema((s) => ({\n * ...s,\n * tagNames: [...(s.tagNames ?? []), 'my-widget'],\n * }));\n * ```\n *\n * @example Inspect the library default (e.g. to learn what's already allowed):\n * ```ts\n * // The draft handed to the modifier IS the library default, deep-cloned.\n * // Logging it once at module load surfaces every default field — protocols,\n * // attributes, tagNames, etc. — without ever exposing the singleton itself.\n * extendSanitizeSchema((s) => {\n * console.log('default sanitize schema:', s);\n * });\n * ```\n *\n * @remarks Allowing a protocol on `protocols.href` lets the URL through\n * Gate 1 (the schema-level per-protocol allowlist, which runs inside the\n * rehype plugin chain). Gate 2 (`urlTransform`, the per-attribute rewriter\n * that runs later at render time in `renderHastSubtree`) must permit the\n * same protocol independently — see the `urlTransform` prop on\n * `<AIMarkdown>` and the exported {@link defaultUrlTransform} for\n * composition. Keep the two protocol lists in sync.\n *\n * ### Footguns\n *\n * - **Reassigning the local parameter** (`(s) => { s = { …new schema… }; }`)\n * does NOT replace the draft — JS only rebinds the local variable. Either\n * mutate the original draft or `return` the new object explicitly.\n * - **Returning `null`** is treated the same as returning nothing (the\n * modified draft is used). The TypeScript signature does not permit\n * `null`, but JS callers or `as`-casted code paths could silently hit\n * this. Prefer `return` with no value, or an explicit `return draft;`.\n * - **Throwing inside the modifier** propagates to the call site\n * uncaught — there is no try/catch. Callers usually invoke this once at\n * module load, where a thrown error surfaces as a startup-time crash and\n * is the correct failure mode.\n * - **Widening is total.** Adding a tag to `tagNames` admits that element\n * with ALL of its semantics — `script`, `iframe`, `style`, `object`,\n * `form`, `base` re-enter the tree verbatim, and the two-gate URL story\n * in the README / SECURITY.md no longer describes your renderer. Prefer\n * allowing an attribute or a protocol over allowing an element; treat\n * any element you add as trusted input.\n *\n * @param modifier - Receives a deep clone of the library default. Mutate it\n * freely; either return the (possibly different) result, or return\n * nothing to use the mutated draft. Returning `undefined` (and, by\n * convention, `null`) is treated the same as a mutate-only call.\n * @returns A new `Schema` object — never the library default singleton.\n */\nexport function extendSanitizeSchema(modifier: (draft: SanitizeSchema) => SanitizeSchema | void): SanitizeSchema {\n // lodash-es `cloneDeep` over the native `structuredClone` because the\n // latter is unavailable on iOS Safari < 15.4 (March 2022) and on older\n // Android WebViews that are still common on mid-tier devices. lodash-es\n // is already pulled in transitively (useStableValue + context use it),\n // so the marginal bundle cost of importing one more named export is tiny;\n // the helper is called once at module scope, so the speed difference\n // versus the native API is irrelevant. Importantly, lodash `cloneDeep`\n // preserves RegExp — a JSON-based deep clone would silently turn the\n // math/language className regexes into `{}` and corrupt sanitize\n // semantics.\n const draft = cloneDeep(sanitizeSchema);\n const result = modifier(draft);\n return result ?? draft;\n}\n","/**\n * Smooth-stream controller — framework-free typewriter pacing.\n *\n * Reveals an accumulated source string as a gradually growing prefix\n * (`getVisible()`), stepping by grapheme cluster at a rate that adapts to\n * backlog. The revealed prefix is append-only between snaps, which is\n * exactly the incremental-parse engine's fast path — the controller sits\n * upstream of the renderer and never touches the parse pipeline.\n *\n * Pacing model — an adaptive jitter buffer (audio-playout style):\n * - The controller estimates the source's arrival rate and burst interval\n * with irregular-sampling EMAs (recorded on every append), and derives a\n * target buffer B* ≈ bufferFactor × one burst's worth of text — the\n * causality floor for smoothing bursts of that period.\n * - Streaming: rate = max(floor, rateEma + (backlog − B*) / correctionTau).\n * Feedforward tracks the source speed (bounded lag at any model speed);\n * the feedback term pins the backlog near B*, dipping BELOW the source\n * rate on purpose when the buffer runs low so it can refill instead of\n * running dry between bursts. The floor is a tiny anti-freeze trickle,\n * deliberately smaller than any realistic arrival rate.\n * - Pre-stats (first burst after construction/snap): no estimate exists\n * yet, so the backlog reveals over roughly one correction window.\n * - Finished: rate = backlog / time-to-deadline, deadline stamped at\n * `finish() + drainMs` — the backlog empties BY the deadline instead of\n * decaying toward it forever.\n * - A deadline credit accumulator converts elapsed time (injectable\n * `now()`) into whole-grapheme reveals per scheduled frame — timers\n * carry no state between frames, so throttled/paused schedulers\n * self-correct on the next tick instead of drifting.\n * - The public tuning surface is three named presets ({@link SmoothStreamPacing});\n * the numeric parameters stay controller-level for advanced hosts.\n *\n * Grapheme discipline: stepping uses `Intl.Segmenter` (code-point fallback)\n * and the trailing grapheme of the source is held back until it is\n * confirmed — by more text arriving or by `finish()` — so a surrogate\n * half or a still-growing emoji ZWJ sequence is never revealed to the\n * parser mid-cluster. `snap()` (a replacement, or the very first `update`)\n * is outside this promise by design: it shows the whole replacement text\n * at once, trailing half-cluster included — a hold-back there would leave\n * a controller that never drains when nothing follows (v2.4.2 review\n * P3-1). Hosts that seed a stream mid-cluster get one frame of U+FFFD.\n *\n * @module components/smoothStream/controller\n */\n\n/**\n * The public pacing surface: three named trade-off points on the\n * latency-vs-smoothness axis (the audio-plugin buffer-preset convention —\n * perceptual parameters resist meaningful numeric tuning).\n *\n * - `'smooth'` — target ~1.7 bursts of buffer: almost never runs dry\n * between server flushes, at the cost of a little extra lag.\n * - `'balanced'` (default) — ~1 burst of buffer, the causality floor for\n * smoothing: minimal lag that can still bridge a typical gap.\n * - `'responsive'` — sub-burst buffer: lowest lag, accepts an occasional\n * visible pause between bursts.\n */\nexport type SmoothStreamPacing = 'smooth' | 'balanced' | 'responsive';\n\n/** The numeric parameter bundle a {@link SmoothStreamPacing} preset names. */\nexport interface SmoothStreamPacingParams {\n /** Target buffer as a multiple of one estimated burst's worth of text. */\n bufferFactor: number;\n /**\n * Feedback time constant (ms): how fast the backlog is steered toward\n * the target buffer. Also the pre-stats reveal window for the first\n * burst, before any arrival estimate exists.\n */\n correctionTauMs: number;\n /** Smoothing horizon (ms) for the arrival-rate / burst-interval EMAs. */\n emaTauMs: number;\n /**\n * Anti-freeze floor (grapheme clusters/s). Deliberately tiny — smaller\n * than any realistic arrival rate — so the feedback term can slow the\n * reveal below the source rate to refill the buffer, without ever\n * freezing visible progress entirely.\n */\n minCharsPerSecond: number;\n /**\n * Hard drain budget after {@link SmoothStreamController.finish}: a\n * deadline is stamped at `finish() + drainMs` and the rate scales with\n * remaining-backlog / remaining-time, so the backlog empties BY the\n * deadline (not asymptotically). Consumed when the deadline is stamped —\n * changing it affects the next drain, not one in progress.\n */\n drainMs: number;\n}\n\nexport interface SmoothStreamOptions extends Partial<SmoothStreamPacingParams> {\n /**\n * Named pacing preset, the intended tuning surface. Individual\n * {@link SmoothStreamPacingParams} fields act as advanced per-field\n * overrides on top of the chosen preset. Default `'balanced'`.\n */\n pacing?: SmoothStreamPacing;\n /**\n * Injectable clock (milliseconds, monotonic preferred). Defaults to\n * `performance.now`, falling back to `Date.now`. Tests inject a manual\n * clock — pacing must never race the wall clock.\n */\n now?: () => number;\n /**\n * Injectable frame scheduler: schedules `cb` once, ASYNCHRONOUSLY, and\n * returns a cancel function. A scheduler that invokes `cb` synchronously\n * violates the contract (the returned cancel handle would be recorded\n * after the tick already cleared it, stranding the controller). Defaults\n * to `requestAnimationFrame` with a `setTimeout` fallback so the\n * controller also runs under node.\n */\n schedule?: (cb: () => void) => () => void;\n}\n\nexport interface SmoothStreamController {\n /**\n * Sets the full accumulated source. An append-extension of the current\n * source animates; anything else — the FIRST update after construction\n * included — snaps (content replacement is not a stream). An identical\n * string is a no-op, so replayed effects (StrictMode) are safe.\n * Calling `update` after {@link finish} re-enters streaming: multi-round\n * LLM flows (stream → tool call → stream) keep one controller.\n */\n update(source: string): void;\n /**\n * Signals end of stream: confirms the held-back trailing grapheme and\n * switches the control law to the `drainMs` window. Not terminal —\n * a later {@link update} resumes animation.\n */\n finish(): void;\n /** Jumps to `source` instantly, no animation, and clears any backlog.\n * No trailing-grapheme hold-back (see the module docs). */\n snap(source: string): void;\n /**\n * Reveals everything pending right now (skip-animation affordance). Keeps\n * the grapheme discipline: while the stream is not finished, the trailing\n * grapheme of the source stays held back exactly as the animation would\n * hold it (a surrogate half or a growing ZWJ sequence must never reach\n * the parser); {@link finish} or the next {@link update} confirms it.\n */\n flush(): void;\n /** Subscribes to visible-prefix changes. Returns the unsubscribe. */\n subscribe(listener: () => void): () => void;\n /**\n * The currently revealed prefix. Reference-stable between changes —\n * safe as a `useSyncExternalStore` snapshot.\n */\n getVisible(): string;\n /** True when the visible prefix has caught up with the full source. */\n isDrained(): boolean;\n /**\n * Cancels any scheduled frame and drops all subscribers. NOT terminal:\n * any subsequent call ({@link update}, {@link subscribe}, …) revives the\n * controller. React StrictMode's dev-only effect replay (mount → cleanup\n * → re-run) disposes and then reuses the same state-held instance — a\n * permanently-latching dispose would kill the reveal in dev forever.\n * After a REAL unmount nothing calls back in, so disposal sticks.\n */\n dispose(): void;\n}\n\n/**\n * The three preset bundles. Calibrated against the burst patterns in the\n * SmoothStream stories (server-buffer-like flushes at slow and fast model\n * speeds); frozen so a shared reference can't be mutated by a consumer.\n */\nexport const SMOOTH_STREAM_PACING_PRESETS: Readonly<Record<SmoothStreamPacing, Readonly<SmoothStreamPacingParams>>> =\n Object.freeze({\n smooth: Object.freeze({\n bufferFactor: 1.7,\n correctionTauMs: 280,\n emaTauMs: 2600,\n minCharsPerSecond: 4,\n drainMs: 320,\n }),\n balanced: Object.freeze({\n bufferFactor: 1.0,\n correctionTauMs: 180,\n emaTauMs: 1800,\n minCharsPerSecond: 6,\n drainMs: 240,\n }),\n responsive: Object.freeze({\n bufferFactor: 0.45,\n correctionTauMs: 110,\n emaTauMs: 1100,\n minCharsPerSecond: 10,\n drainMs: 150,\n }),\n });\n\n/**\n * Absolute ceiling on the target buffer, expressed as milliseconds of lag\n * at the estimated rate. Guards against a skewed interval estimate (one\n * pathological gap) demanding seconds of buffered text. Internal — not a\n * preset field because no preset should ever want to move it.\n */\nconst MAX_TARGET_BUFFER_MS = 1200;\n\nconst defaultNow: () => number =\n typeof performance !== 'undefined' && typeof performance.now === 'function'\n ? () => performance.now()\n : () => Date.now();\n\nconst defaultSchedule = (cb: () => void): (() => void) => {\n if (typeof requestAnimationFrame === 'function') {\n const id = requestAnimationFrame(() => cb());\n return () => cancelAnimationFrame(id);\n }\n const id = setTimeout(cb, 16);\n return () => clearTimeout(id);\n};\n\n/**\n * Pacing knobs must be FINITE numbers. NaN is a `number` to TypeScript\n * (`{ minCharsPerSecond: parseInt(missing) }` type-checks), and `Math.max`\n * propagates NaN instead of guarding it — one poisoned knob would freeze\n * the reveal in a permanent no-op frame loop. Infinity is rejected too:\n * `Infinity × 0` on a zero-dt tick is NaN by another road.\n */\nconst finiteOr = (value: number | undefined, fallback: number): number =>\n value !== undefined && Number.isFinite(value) ? value : fallback;\n\nconst segmenter =\n typeof Intl !== 'undefined' && typeof Intl.Segmenter === 'function'\n ? new Intl.Segmenter(undefined, { granularity: 'grapheme' })\n : undefined;\n\n/**\n * Absolute end offsets (UTF-16 units) of each grapheme cluster in\n * `text`, offset by `base`. Fallback iterates code points, which still\n * never splits a surrogate pair (ZWJ sequences may step in parts).\n */\nconst graphemeEnds = (text: string, base: number): number[] => {\n const ends: number[] = [];\n if (segmenter) {\n for (const part of segmenter.segment(text)) {\n ends.push(base + part.index + part.segment.length);\n }\n } else {\n let offset = base;\n for (const cp of text) {\n offset += cp.length;\n ends.push(offset);\n }\n }\n return ends;\n};\n\n/**\n * UTF-16 units re-segmented before a resume seam. Grapheme breaking is a\n * finite-state process, so a window that starts mid-cluster re-synchronises\n * within a cluster or two and every boundary after that is right — with one\n * exception, regional indicators, handled separately below. The residual\n * risk is a single cluster longer than the window (a 30-link ZWJ chain, a\n * Zalgo pile) straddling the seam, and the cost there is one frame of odd\n * reveal granularity, never wrong text.\n */\nconst RESUME_LOOKBACK = 64;\n\nconst isMidSurrogatePair = (text: string, at: number): boolean =>\n at > 0 &&\n at < text.length &&\n (text.charCodeAt(at - 1) & 0xfc00) === 0xd800 &&\n (text.charCodeAt(at) & 0xfc00) === 0xdc00;\n\nconst RI_FIRST = 0x1f1e6;\nconst RI_LAST = 0x1f1ff;\nconst isRegionalIndicatorAt = (text: string, at: number): boolean => {\n const cp = text.codePointAt(at);\n return cp !== undefined && cp >= RI_FIRST && cp <= RI_LAST;\n};\n\nexport const createSmoothStreamController = (options: SmoothStreamOptions = {}): SmoothStreamController => {\n // Option fields are read each tick, so a caller that keeps the object\n // and replaces field values retunes pacing live (the hook relies on\n // this to reflect prop changes without controller churn).\n const now = options.now ?? defaultNow;\n const schedule = options.schedule ?? defaultSchedule;\n\n let source = '';\n /** UTF-16 offset of the revealed prefix's end. */\n let visibleEnd = 0;\n /**\n * Confirmed grapheme end offsets awaiting reveal, ascending, all in\n * `(visibleEnd, source.length]`. The trailing grapheme of the source is\n * NOT in here until confirmed (see module doc) — its end lives in\n * `tentativeEnd` and is re-derived whenever more text arrives.\n */\n let pending: number[] = [];\n let tentativeEnd = 0;\n let finished = false;\n /**\n * An offset confirmed as a source end UNCONDITIONALLY — by `finish()`, or\n * by a `snap()` that revealed everything. Correct at the time: a finished\n * stream owes the caller every byte it has. But the controller supports\n * RESUMING (a tool call or a user turn ends the round, then more text\n * arrives), and an offset that was a source end need not be a cluster\n * boundary of the longer string. `hold` protects boundaries confirmed by\n * streaming; it never saw this one. Cleared once segmentation has\n * confirmed a boundary beyond it.\n */\n let seam: number | undefined;\n /** Deadline (clock ms) by which a finished stream must be fully revealed. */\n let drainDeadlineAt: number | undefined;\n let initialized = false;\n\n let visibleCache = '';\n let credit = 0;\n let lastTickAt = 0;\n let cancelFrame: (() => void) | undefined;\n let disposed = false;\n\n // Arrival statistics for the adaptive law. Reset by snap(): a content\n // replacement is a new stream whose cadence the old estimates don't\n // describe. `undefined` = pre-stats regime (first burst).\n let rateEma: number | undefined;\n let intervalEma: number | undefined;\n let lastArrivalAt: number | undefined;\n\n const listeners = new Set<() => void>();\n\n /** Live-resolves preset + per-field overrides, sanitizing every number. */\n const resolveParams = (): SmoothStreamPacingParams => {\n const preset =\n SMOOTH_STREAM_PACING_PRESETS[options.pacing as SmoothStreamPacing] ?? SMOOTH_STREAM_PACING_PRESETS.balanced;\n return {\n bufferFactor: finiteOr(options.bufferFactor, preset.bufferFactor),\n correctionTauMs: finiteOr(options.correctionTauMs, preset.correctionTauMs),\n emaTauMs: finiteOr(options.emaTauMs, preset.emaTauMs),\n minCharsPerSecond: finiteOr(options.minCharsPerSecond, preset.minCharsPerSecond),\n drainMs: finiteOr(options.drainMs, preset.drainMs),\n };\n };\n\n /**\n * Irregular-sampling EMA update: α = 1 − e^(−gap/τ) weighs each sample\n * by the time it spans, so bursty arrival timing doesn't bias the\n * estimates the way a fixed-α EMA would. `added` is in UTF-16 units —\n * close enough to the grapheme-denominated backlog for control purposes\n * (emoji-heavy text mildly over-estimates the rate, which only pads the\n * buffer).\n */\n const recordArrival = (t: number, added: number) => {\n if (added <= 0) return;\n if (lastArrivalAt === undefined) {\n lastArrivalAt = t;\n return;\n }\n const gap = Math.max(1, t - lastArrivalAt);\n lastArrivalAt = t;\n const tau = Math.max(1, resolveParams().emaTauMs);\n // A gap longer than the smoothing horizon is a PAUSE, not cadence: at\n // that length α → 1 and this one sample would rewrite both estimates\n // (R̂ → ~0, Î → the pause), making the resume crawl at the floor while\n // B* pegs at its cap, then whoosh when Î decays. Start a new epoch\n // instead — keep the pre-pause estimates and let normal samples adapt.\n if (gap > tau) return;\n const alpha = 1 - Math.exp(-gap / tau);\n const instantRate = (added * 1000) / gap;\n // Zero-prior blend, no assignment special case: the FIRST sample also\n // enters at weight α, so a connect-flush pair ~1ms apart seeds a\n // bounded estimate instead of `added × 1000` chars/s (which would\n // track a phantom rate and disable smoothing for seconds). Early\n // under-estimation is harmless — with small R̂ the adaptive law\n // algebraically coincides with the pre-stats reveal.\n rateEma = (rateEma ?? 0) + alpha * (instantRate - (rateEma ?? 0));\n intervalEma = (intervalEma ?? 0) + alpha * (gap - (intervalEma ?? 0));\n };\n\n const notify = () => {\n visibleCache = source.slice(0, visibleEnd);\n for (const listener of [...listeners]) listener();\n };\n\n const cancelScheduled = () => {\n cancelFrame?.();\n cancelFrame = undefined;\n };\n\n const ensureScheduled = () => {\n if (disposed || cancelFrame || pending.length === 0) return;\n lastTickAt = now();\n credit = 0;\n cancelFrame = schedule(tick);\n };\n\n const tick = () => {\n cancelFrame = undefined;\n if (disposed) return;\n const t = now();\n const dt = Math.max(0, t - lastTickAt);\n lastTickAt = t;\n\n const params = resolveParams();\n let rate: number;\n if (finished && drainDeadlineAt !== undefined) {\n // Drain regime: remaining backlog over remaining time-to-deadline —\n // reaches zero BY the deadline instead of decaying asymptotically.\n rate = Math.max(params.minCharsPerSecond, (pending.length * 1000) / Math.max(1, drainDeadlineAt - t));\n } else if (rateEma !== undefined && intervalEma !== undefined) {\n // Adaptive regime: feedforward on the estimated source rate,\n // feedback steering the backlog toward the target buffer. The\n // feedback dips below the source rate on purpose when the buffer\n // runs low — that is how it refills instead of running dry.\n // Clamp order matters: the \"at least one grapheme\" floor applies\n // AFTER the lag cap, so a tiny-R̂ stream cannot end up with a\n // sub-1 target.\n const targetBuffer = Math.max(\n 1,\n Math.min(params.bufferFactor * rateEma * (intervalEma / 1000), (rateEma * MAX_TARGET_BUFFER_MS) / 1000)\n );\n rate = Math.max(\n params.minCharsPerSecond,\n rateEma + ((pending.length - targetBuffer) * 1000) / Math.max(1, params.correctionTauMs)\n );\n } else {\n // Pre-stats regime (first burst after construction/snap): no\n // arrival estimate yet — reveal over roughly one correction window.\n rate = Math.max(params.minCharsPerSecond, (pending.length * 1000) / Math.max(1, params.correctionTauMs));\n }\n credit += (rate * dt) / 1000;\n\n const reveal = Math.min(Math.floor(credit), pending.length);\n if (reveal > 0) {\n visibleEnd = pending[reveal - 1];\n pending = pending.slice(reveal);\n // Leftover credit only carries while a backlog remains; otherwise a\n // quiet spell would bank credit and dump the next chunk instantly.\n credit = pending.length > 0 ? credit - reveal : 0;\n notify();\n }\n // Re-check both guards after notify: a subscriber may have called\n // dispose() (don't schedule past it) or update() (ensureScheduled\n // already booked the next frame — booking a second would orphan its\n // cancel handle and fork the tick chain).\n if (!disposed && !cancelFrame && pending.length > 0) cancelFrame = schedule(tick);\n };\n\n /** Re-segments the unrevealed tail from the last confirmed boundary.\n *\n * Only the LAST cluster stays tentative, because appending can merge it\n * with what follows — with one exception: when the source ends inside a\n * surrogate pair, that lone high surrogate is a cluster of its own, and\n * the cluster BEFORE it would be confirmed even though the completed pair\n * merges the two (`\"👩‍👧‍👦x\"` cut at 5 revealed `\"👩‍\"` — a break inside a\n * cluster, which the module contract says never happens; 2026-08-19\n * review r2 P2-6). Two clusters stay tentative there.\n *\n * A resume needs more than that — see `seam`. The seam is dropped from\n * the schedule if it is still only scheduled, and the tail around it is\n * re-segmented with left context instead of from the seam itself\n * (2026-08-20 A2). */\n const resegmentTail = () => {\n if (seam !== undefined && seam < source.length && pending[pending.length - 1] === seam) {\n // Confirmed but not yet shown, and no longer a boundary we trust.\n // Only the last entry can be the seam: it is a source end, so nothing\n // confirmed later is smaller, and this runs before the new ends land.\n pending.pop();\n }\n const from = pending.length > 0 ? pending[pending.length - 1] : visibleEnd;\n let anchor = from;\n if (seam !== undefined && from <= seam) {\n // Text already revealed cannot be taken back — one frame showing\n // U+FFFD is the documented cost — but segmenting FROM a position\n // whose cluster break depends on what precedes it corrupts every\n // boundary after it too, and that part is avoidable. `\"👩‍👧‍👦x\"`\n // resumed at 4 segmented as [\"\\uDC67‍\", \"👦\", \"x\"] and revealed the\n // family in visibly broken pieces.\n anchor = Math.max(0, from - RESUME_LOOKBACK);\n if (isMidSurrogatePair(source, anchor)) anchor -= 1;\n // GB12/GB13 pair regional indicators off from the START of their run,\n // so parity is the one thing a bounded window cannot recover. Walk the\n // whole run instead: `\"🇺🇸🇬🇧🇫🇷\"` resumed at 2 read 🇸 and 🇬 as one flag.\n while (anchor >= 2 && isRegionalIndicatorAt(source, anchor - 2)) anchor -= 2;\n } else {\n seam = undefined;\n }\n const ends = graphemeEnds(source.slice(anchor), anchor);\n if (ends.length === 0) {\n tentativeEnd = from;\n return;\n }\n tentativeEnd = ends[ends.length - 1];\n let hold = 1;\n if (!finished && ends.length > 1) {\n const last = source.charCodeAt(source.length - 1);\n // The completed character may merge with the cluster before the lone\n // surrogate, so that cluster's end is not settled either. Screening the\n // predecessor for \"could it absorb this\" is a trap: an earlier version\n // required a non-ASCII predecessor, but GB9 lets ANY character take a\n // following Extend, and the supplementary plane is full of them —\n // `a` + U+1D165 (musical symbol) and `a` + U+E0101 (variation selector\n // supplement) both revealed a bare `a` that the next frame merged away.\n // Two clusters stay tentative whenever the source ends mid-pair; the\n // cost is one cluster of extra latency for one frame.\n if (last >= 0xd800 && last <= 0xdbff) hold = 2;\n }\n const confirmedEnds = finished ? ends : ends.slice(0, -hold);\n // A backed-up anchor re-derives boundaries at or before `from`; those\n // are settled already (revealed, or still-trusted entries in `pending`).\n for (const end of confirmedEnds) if (end > from) pending.push(end);\n };\n\n const snap = (next: string) => {\n disposed = false;\n initialized = true;\n finished = false;\n drainDeadlineAt = undefined;\n // A replacement is a new stream: the old cadence estimates are noise.\n rateEma = undefined;\n intervalEma = undefined;\n lastArrivalAt = undefined;\n source = next;\n visibleEnd = next.length;\n tentativeEnd = next.length;\n pending = [];\n seam = next.length;\n credit = 0;\n cancelScheduled();\n if (visibleCache !== next) notify();\n };\n\n /**\n * Un-latches a disposed controller AND reschedules any surviving\n * backlog. Rescheduling here is load-bearing: the StrictMode replay\n * re-runs effects with UNCHANGED props, so `update` takes its\n * identical-string early-return and `finish` its already-finished one —\n * neither would reach ensureScheduled on its own, and a mid-animation\n * backlog would freeze forever.\n */\n const revive = () => {\n if (!disposed) return;\n disposed = false;\n ensureScheduled();\n };\n\n return {\n update(next: string) {\n revive();\n if (initialized && next === source) return;\n if (!initialized || !next.startsWith(source)) {\n snap(next);\n return;\n }\n finished = false;\n drainDeadlineAt = undefined;\n const previousLength = source.length;\n source = next;\n resegmentTail();\n recordArrival(now(), next.length - previousLength);\n ensureScheduled();\n },\n finish() {\n revive();\n if (finished) return;\n finished = true;\n // The pause between rounds (tool call, user turn) must never become\n // a gap sample: drop the arrival clock so the resume's first update\n // re-seeds it. The EMAs persist — same stream, likely same cadence.\n lastArrivalAt = undefined;\n drainDeadlineAt = now() + resolveParams().drainMs;\n if (tentativeEnd > (pending.length > 0 ? pending[pending.length - 1] : visibleEnd)) {\n pending.push(tentativeEnd);\n }\n seam = source.length;\n ensureScheduled();\n },\n snap,\n flush() {\n disposed = false;\n // Unfinished stream: the unconfirmed trailing grapheme (`tentativeEnd`,\n // never in `pending`) stays held — revealing it here would expose a\n // possibly-broken cluster to the parser, the one thing the module's\n // grapheme discipline promises never happens (2026-08 project review,\n // eng-stream-04). Finished streams have confirmed it into `pending`.\n const target = finished ? source.length : pending.length > 0 ? pending[pending.length - 1] : visibleEnd;\n if (target <= visibleEnd) return;\n visibleEnd = target;\n pending = [];\n credit = 0;\n cancelScheduled();\n notify();\n },\n subscribe(listener: () => void) {\n revive();\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n getVisible: () => visibleCache,\n isDrained: () => visibleEnd === source.length,\n dispose() {\n disposed = true;\n cancelScheduled();\n listeners.clear();\n },\n };\n};\n","/**\n * LaTeX preprocessing pipeline.\n *\n * Normalizes raw markdown so that LaTeX expressions survive the remark/rehype\n * rendering pipeline intact. The main entry point is {@link preprocessLaTeX},\n * which splits content into protected regions (code blocks, inline code, HTML\n * tags) and applies a sequence of transformations to the unprotected text:\n *\n * 1. Escape mhchem commands (`\\ce`, `\\pu`)\n * 2. Escape currency dollar signs (e.g. `$100`, `$1,000.50`)\n * 3. Convert bracket delimiters (`\\[...\\]`, `\\(...\\)`) to dollar delimiters\n * 4. Escape pipes inside closed LaTeX blocks to prevent GFM table interference\n * 5. Escape pipes inside unclosed LaTeX blocks (streaming partial content)\n * 6. Escape underscores inside `\\text{...}` commands\n * 7. Convert single-dollar delimiters to double-dollar delimiters\n * 8. Truncate trailing unclosed LaTeX blocks (streaming protection)\n *\n * Thanks to the implementations from the following repositories:\n * - https://github.com/lobehub/lobe-ui/blob/master/src/hooks/useMarkdown/latex.ts\n * - https://github.com/danny-avila/LibreChat/blob/main/client/src/utils/latex.ts\n *\n * @module preprocessors/latex\n */\n\ninterface Segment {\n text: string;\n isCode: boolean;\n}\n\ntype FenceMarker = '`' | '~';\n\nfunction getRepeatedMarkerLength(content: string, start: number, marker: FenceMarker): number {\n let end = start;\n while (end < content.length && content[end] === marker) {\n end += 1;\n }\n return end - start;\n}\n\n/**\n * Sticky regex for matching known HTML tags at a specific position.\n * The `y` (sticky) flag anchors the match at `lastIndex`, avoiding the need\n * to create a substring for each `<` character encountered during scanning.\n */\nconst HTML_TAG_REGEX =\n /<\\/?(span|div|p|br|hr|img|a|em|strong|b|i|u|s|sub|sup|code|pre|table|tr|td|th|thead|tbody|tfoot|ul|ol|li|dl|dt|dd|h[1-6]|blockquote|details|summary|figure|figcaption|section|article|aside|nav|header|footer|main|mark|del|ins|small|abbr|cite|dfn|kbd|samp|var|ruby|rt|rp|bdo|wbr|input|button|select|textarea|label|fieldset|legend|output|iframe|video|audio|source|canvas|svg|math|time)(?:\\s[^>]*)?\\/?>/iy;\n\n/**\n * Tags whose inner text must be treated as literal (never processed as LaTeX).\n * For these, an opening tag triggers protection of the entire paired region\n * `<tag>...</tag>` rather than just the tag itself, so dollar signs and other\n * LaTeX-looking characters inside (e.g. `<code>$x^2$</code>`) survive untouched.\n */\nconst LITERAL_CONTENT_TAGS = new Set(['code', 'pre', 'kbd', 'samp', 'math', 'svg']);\nconst LITERAL_CONTENT_CLOSE_REGEX: Record<string, RegExp> = {\n code: /<\\/code\\s*>/gi,\n pre: /<\\/pre\\s*>/gi,\n kbd: /<\\/kbd\\s*>/gi,\n samp: /<\\/samp\\s*>/gi,\n math: /<\\/math\\s*>/gi,\n svg: /<\\/svg\\s*>/gi,\n};\n\n/** True when only spaces/tabs (and an optional `\\r`) follow `pos` up to the\n * next `\\n` or EOF — CommonMark's closing-fence rule. Without it\n * ` ``` not-a-closer ` closed the fence and inverted the open/close phase\n * for the rest of the document (v2.4.1 review P2). */\nfunction restOfLineIsBlank(content: string, pos: number): boolean {\n for (let i = pos; i < content.length; i++) {\n const c = content[i];\n if (c === '\\n') return true;\n if (c !== ' ' && c !== '\\t' && c !== '\\r') return false;\n }\n return true;\n}\n\n/** A backtick fence's info string may not contain a backtick — such a line\n * is a paragraph (possibly holding code spans), not an opener. */\nfunction lineHasBacktick(content: string, pos: number): boolean {\n for (let i = pos; i < content.length && content[i] !== '\\n'; i++) {\n if (content[i] === '`') return true;\n }\n return false;\n}\n\n/**\n * The run at `pos` is the first non-blank thing on its line. Any amount of\n * leading indentation is accepted: CommonMark's 0–3 space limit is measured\n * RELATIVE to the enclosing container, and this text-level pass has no\n * container model — a fence nested two list levels deep sits at column 4+\n * (v2.4.2 review P1-3: `- a\\n - b\\n ~~~\\n price = $100\\n ~~~`\n * had its `$` rewritten). Accepting a deeper-indented fence can only\n * OVER-protect (an indented code block that happens to hold a fence line\n * is treated as one), which is the safe direction for a preprocessor.\n */\nfunction lineIndentBefore(content: string, pos: number): number {\n let i = pos - 1;\n let indent = 0;\n while (i >= 0 && (content[i] === ' ' || content[i] === '\\t')) {\n indent += content[i] === '\\t' ? 4 : 1;\n i--;\n }\n return i < 0 || content[i] === '\\n' || content[i] === '\\r' ? indent : -1;\n}\n\n/**\n * Find the next run of *exactly* `n` consecutive backticks at or after\n * `start`. Runs of any other length are skipped over. Returns the start\n * index of the matching run, or `-1` if no such run exists.\n *\n * Used to locate the closing delimiter of a CommonMark inline code span:\n * the closer must be a backtick run of the *same* length as the opener.\n */\nfunction findClosingBacktickRun(content: string, start: number, n: number): number {\n let i = start;\n while (i < content.length) {\n const ch = content[i];\n if (ch === '`') {\n const runLen = getRepeatedMarkerLength(content, i, '`');\n if (runLen === n) return i;\n i += runLen;\n } else if (ch === '\\n' || ch === '\\r') {\n // A code span cannot cross a blank line (it ends the paragraph): two\n // lone backticks in different paragraphs are literal, and pairing\n // them would shield every `$…$` in between from conversion\n // (2026-08-19 review P2-2 — inline sibling of the v2.4.1 fence fix).\n // Line endings are `\\n`, `\\r\\n` and a lone `\\r` (r2 P3): a blank line\n // is an ending, optional spaces/tabs, then another ending (or EOF).\n let j = i + 1;\n if (ch === '\\r' && content[j] === '\\n') j += 1;\n while (j < content.length && (content[j] === ' ' || content[j] === '\\t')) j += 1;\n if (j >= content.length || content[j] === '\\n' || content[j] === '\\r') return -1;\n i += 1;\n } else {\n i += 1;\n }\n }\n return -1;\n}\n\n/**\n * Split content into alternating text and protected segments.\n * Protected segments (isCode: true) are excluded from LaTeX processing:\n * - fenced multiline code blocks: 3+ backticks or tildes at the *start of a\n * line* (any indentation — container-relative limits are not modelled).\n * Mid-line runs are never fence openers. INDENTED code blocks (4+ spaces\n * after a blank line, outside any container) are NOT modelled: without a\n * container model they cannot be told from a list item's continuation\n * paragraph, and protecting them would silence math in nested lists.\n * Known limitation — `$` inside an indented code block may be rewritten.\n * - inline code spans: a run of N backticks closed by another run of exactly\n * N backticks. May span newlines. Multi-backtick forms (e.g. `` `` `x` ``)\n * are supported so literal backtick characters can appear inside.\n * - HTML tags (e.g. `<span>$</span>` where `$` should not be treated as LaTeX).\n */\nexport function splitByProtectedRegions(content: string): Segment[] {\n const segments: Segment[] = [];\n let lastIndex = 0;\n let multilineStart = -1;\n let multilineFenceMarker: FenceMarker | null = null;\n let multilineFenceLength = 0;\n let multilineFenceIndent = 0;\n\n function pushProtected(start: number, end: number) {\n if (start > lastIndex) {\n segments.push({ text: content.substring(lastIndex, start), isCode: false });\n }\n segments.push({ text: content.substring(start, end), isCode: true });\n lastIndex = end;\n }\n\n let i = 0;\n while (i < content.length) {\n const char = content[i];\n\n // Inside a fenced code block: only look for a closing fence line.\n if (multilineStart !== -1) {\n if (char === multilineFenceMarker) {\n const runLen = getRepeatedMarkerLength(content, i, multilineFenceMarker);\n // A closer may be indented at most 3 columns MORE than its opener\n // (CommonMark, container-relative): a ` ```` line inside a\n // column-0 fence is content, not a closer — accepting it closed the\n // block early and exposed its body (adversarial review of the\n // any-indent opener change).\n const closerIndent = lineIndentBefore(content, i);\n if (\n runLen >= multilineFenceLength &&\n closerIndent !== -1 &&\n closerIndent <= multilineFenceIndent + 3 &&\n restOfLineIsBlank(content, i + runLen)\n ) {\n pushProtected(multilineStart, i + runLen);\n multilineStart = -1;\n multilineFenceMarker = null;\n multilineFenceLength = 0;\n i += runLen;\n continue;\n }\n i += runLen;\n continue;\n }\n i += 1;\n continue;\n }\n\n // Outside code: check fence opener, inline code span, then HTML tag.\n if (char === '`' || char === '~') {\n const runLen = getRepeatedMarkerLength(content, i, char);\n\n // Fenced code block opener: ≥3 markers and at a valid line start.\n const openerIndent = lineIndentBefore(content, i);\n if (runLen >= 3 && openerIndent !== -1 && !(char === '`' && lineHasBacktick(content, i + runLen))) {\n multilineStart = i;\n multilineFenceMarker = char;\n multilineFenceLength = runLen;\n multilineFenceIndent = openerIndent;\n i += runLen;\n continue;\n }\n\n // Inline code span: only backticks (tildes are never inline delimiters).\n if (char === '`') {\n const closeIdx = findClosingBacktickRun(content, i + runLen, runLen);\n if (closeIdx !== -1) {\n pushProtected(i, closeIdx + runLen);\n i = closeIdx + runLen;\n continue;\n }\n }\n\n // Unmatched run — skip the whole run so we don't re-interpret its\n // individual backticks on subsequent iterations.\n i += runLen;\n continue;\n }\n\n if (char === '<') {\n // Only match known HTML tags to avoid false positives with angle brackets\n // in markdown links (<Slides Demo>), math comparisons ($a < b$), etc.\n // Use sticky regex to match at position i without creating a substring.\n HTML_TAG_REGEX.lastIndex = i;\n const tagMatch = HTML_TAG_REGEX.exec(content);\n if (tagMatch) {\n let endIndex = i + tagMatch[0].length;\n // For literal-content tags (code/pre/math/...), protect the paired\n // <tag>...</tag> region so inner `$` never enters LaTeX processing.\n const tagName = tagMatch[1].toLowerCase();\n const isOpeningPairedTag =\n content[i + 1] !== '/' && !tagMatch[0].endsWith('/>') && LITERAL_CONTENT_TAGS.has(tagName);\n if (isOpeningPairedTag) {\n const closeRegex = LITERAL_CONTENT_CLOSE_REGEX[tagName];\n closeRegex.lastIndex = endIndex;\n const closeMatch = closeRegex.exec(content);\n if (closeMatch) {\n endIndex = closeMatch.index + closeMatch[0].length;\n } else {\n // Streaming: closing tag hasn't arrived yet. Protect everything\n // to the end of input so inner `$` etc. aren't mutated before\n // the closer shows up in a later chunk.\n endIndex = content.length;\n }\n }\n pushProtected(i, endIndex);\n i = endIndex;\n continue;\n }\n }\n\n i += 1;\n }\n\n if (multilineStart !== -1) {\n pushProtected(multilineStart, content.length);\n }\n\n // Push remaining text\n if (lastIndex < content.length) {\n segments.push({ text: content.substring(lastIndex), isCode: false });\n }\n\n return segments;\n}\n\n/**\n * Escape mhchem commands in LaTeX expressions to ensure proper rendering.\n *\n * @param text Input string containing LaTeX expressions with mhchem commands\n * @returns String with escaped mhchem commands\n * @from https://github.com/lobehub/lobe-ui/blob/master/src/hooks/useMarkdown/latex.ts\n */\nfunction escapeMhchemCommands(text: string) {\n return text.replaceAll('$\\\\ce{', '$\\\\\\\\ce{').replaceAll('$\\\\pu{', '$\\\\\\\\pu{');\n}\n\nconst CURRENCY_REGEX = /(?<![\\\\$])\\$(?!\\$)(?=\\d+(?:,\\d{3})*(?:\\.\\d+)?(?:[KMBkmb])?(?:\\s|$|[^a-zA-Z\\d]))/g;\n// Match \\[...\\] and \\(...\\) as LaTeX delimiters, but exclude:\n// - !\\[...\\] (markdown image)\n// - \\[...\\]( (markdown link)\nconst DELIMITERS_REGEX = /(?<!!)\\\\\\[([\\S\\s]*?[^\\\\])\\\\](?!\\()|\\\\\\((.*?)\\\\\\)/g;\nconst ARRAY_COL_SPEC_OR_PIPE_REGEX = /(\\\\begin\\{(?:array|tabular[x*]?)\\}\\{[^}]*\\})|(?<!\\\\)\\|/g;\n// Display $$ allows multiline; inline $ forbids newlines (consistent with SINGLE_DOLLAR_REGEX).\n// Both display delimiters use EXACTLY the delimiter lexicon of\n// findUnclosedDelimiterStart / isEscapedByBackslashRun: a `$$` preceded by\n// an EVEN run of backslashes (zero included) is a delimiter, an odd run\n// escapes it — nothing else matters, in particular not a preceding `$`\n// (`$$$$` is an empty display, `\\$$$x$$` opens at the second `$`). The\n// incremental wrapper freezes on that lexicon's verdict, so any other rule\n// here diverges from it: the old escape-blind opener let `Cost \\$$x$ … |\n// table |` pair with a `$$` far below and rewrite the table's pipes\n// (2026-08-19 review r2 P1-1), and a `(?<![\\\\$])` guard disagreed on `$$$$`\n// / `\\$$$` (oracle re-check). Inline stays as it was (line-local; the cut is\n// a line start, so it cannot pair across a freeze).\nconst EVEN_BACKSLASHES = String.raw`(?<=(?:^|[^\\\\])(?:\\\\\\\\)*)`;\nconst LATEX_BLOCK_REGEX = new RegExp(\n String.raw`${EVEN_BACKSLASHES}\\$\\$([\\S\\s]*?)${EVEN_BACKSLASHES}\\$\\$|(?<![\\\\$])\\$(?!\\$)((?:[^$\\n]|\\\\\\$)*?)(?<![\\\\` +\n '`' +\n String.raw`])\\$(?!\\$)`,\n 'g'\n);\nconst TEXT_COMMAND = '\\\\text{';\nconst SINGLE_DOLLAR_REGEX = /(?<![\\\\$])\\$(?!\\$)((?:[^$\\n]|\\\\[$])+?)(?<!\\\\)(?<!`)\\$(?!\\$)/g;\n\n/** Bare `$` count in `str[from, to)`: a `$` not preceded by `\\\\` or `$` and\n * not followed by `$` (the old NO_ESCAPED_DOLLAR_REGEX rule), with the\n * characters just outside the range supplied so a range can be counted in\n * isolation and summed with its neighbours: `prev` stands in for\n * `str[from - 1]`, `next` for `str[to]`. */\nfunction countBareDollars(str: string, from: number, to: number, prev: string, next: string): number {\n let n = 0;\n for (let j = from; j < to; j++) {\n if (str.charCodeAt(j) !== 36 /* $ */) continue;\n const before = j > from ? str[j - 1] : prev;\n const after = j + 1 < to ? str[j + 1] : next;\n if (before !== '\\\\' && before !== '$' && after !== '$') n += 1;\n }\n return n;\n}\n\n/**\n * Escape currency dollar signs (e.g. $100, $1,000.50) so they are not\n * misinterpreted as LaTeX delimiters.\n *\n * The tricky part: a `$` followed by digits might still be inside a LaTeX\n * expression (e.g. `$8.29 \\text{ B} \\times 4$`). We detect this by checking\n * whether there is an odd number of unescaped `$` on the same line after the\n * current match — if so, the current `$` is a LaTeX opener, not currency.\n */\nfunction escapeCurrencyDollarSigns(text: string): string {\n const parts: string[] = [];\n let lastIndex = 0;\n const currencyMatches = Array.from(text.matchAll(CURRENCY_REGEX));\n\n // Track the processed content of the current line incrementally, together\n // with its bare-`$` COUNT: the parity check below used to re-scan the whole\n // processed line on every match, O(line²) for a line with many currency\n // hits (12 KB table row: 59 ms per frame; 8 KB: 243 ms — 2026-08-19\n // review r2 P2-1). Appending a piece adds its own count plus a seam\n // correction (the previous last `$` loses its \"not followed by `$`\" when\n // the piece starts with `$`).\n let currentLineProcessed = '';\n let currentLineDollars = 0;\n const appendToLine = (piece: string): void => {\n if (piece.length === 0) return;\n const prevLast = currentLineProcessed.length > 0 ? currentLineProcessed[currentLineProcessed.length - 1] : '';\n const prevBeforeLast = currentLineProcessed.length > 1 ? currentLineProcessed[currentLineProcessed.length - 2] : '';\n const prevLastCounted = prevLast === '$' && prevBeforeLast !== '\\\\' && prevBeforeLast !== '$';\n if (prevLastCounted && piece[0] === '$') currentLineDollars -= 1;\n currentLineDollars += countBareDollars(piece, 0, piece.length, prevLast, '');\n currentLineProcessed += piece;\n };\n const resetLine = (rest: string): void => {\n currentLineProcessed = '';\n currentLineDollars = 0;\n appendToLine(rest);\n };\n\n for (let i = 0; i < currencyMatches.length; i++) {\n const match = currencyMatches[i];\n const segment = text.substring(lastIndex, match.index);\n parts.push(segment);\n\n // Update currentLineProcessed: keep only content after the last newline.\n const newlineIdx = Math.max(segment.lastIndexOf('\\n'), segment.lastIndexOf('\\r'));\n if (newlineIdx !== -1) {\n resetLine(segment.substring(newlineIdx + 1));\n } else {\n appendToLine(segment);\n }\n\n let needEscape = true;\n // Only the FIRST line after this match matters below; bound the slice\n // by the next line ending instead of splitting the whole remainder into\n // a line array on every match — O(remainder) per frame on the hot path\n // for the last match (2026-08-19 review).\n const restStart = match.index + 1;\n const restEnd = i < currencyMatches.length - 1 ? currencyMatches[i + 1].index : text.length;\n let firstLineBeforeNextMatch = '';\n if (restEnd - restStart > 0) {\n let eol = restEnd;\n for (let k = restStart; k < restEnd; k++) {\n const c = text.charCodeAt(k);\n if (c === 10 /* \\n */ || c === 13 /* \\r */) {\n eol = k;\n break;\n }\n }\n firstLineBeforeNextMatch = text.substring(restStart, eol);\n }\n const restDollars = countBareDollars(firstLineBeforeNextMatch, 0, firstLineBeforeNextMatch.length, '', '');\n if (restDollars % 2 !== 0) {\n // Parity of `currentLineProcessed + firstLineBeforeNextMatch` (the\n // current `$` itself excluded), summed from the two counts with the\n // seam corrected both ways.\n const L = currentLineProcessed;\n const lLast = L.length > 0 ? L[L.length - 1] : '';\n const lBeforeLast = L.length > 1 ? L[L.length - 2] : '';\n const lLastCounted = lLast === '$' && lBeforeLast !== '\\\\' && lBeforeLast !== '$';\n const f0 = firstLineBeforeNextMatch[0];\n let whole = currentLineDollars + restDollars;\n // L's last `$` is now followed by F's first char.\n if (lLastCounted && f0 === '$') whole -= 1;\n // F's first `$` was counted with an empty predecessor; L supplies one.\n if (f0 === '$' && (lLast === '\\\\' || lLast === '$') && firstLineBeforeNextMatch[1] !== '$') whole -= 1;\n if (whole % 2 !== 0) needEscape = false;\n }\n\n const replacement = needEscape ? '\\\\$' : '$';\n parts.push(replacement);\n // Append to currentLineProcessed so subsequent parity checks on the same\n // line see the correct count of unescaped `$` (e.g. a left-as-`$` opener\n // that the next match's check must count).\n appendToLine(replacement);\n lastIndex = match.index + 1;\n }\n parts.push(text.substring(lastIndex));\n return parts.join('');\n}\n\n/**\n * Convert LaTeX bracket delimiters to dollar sign delimiters.\n * Converts \\[...\\] to $$...$$ and \\(...\\) to $...$\n *\n * @param text Input string containing LaTeX expressions\n * @returns String with LaTeX bracket delimiters converted to dollar sign delimiters\n * @modified from https://github.com/lobehub/lobe-ui/blob/master/src/hooks/useMarkdown/latex.ts\n */\nfunction convertLatexDelimiters(text: string): string {\n return text.replaceAll(\n DELIMITERS_REGEX,\n (match: string, squareBracket: string | undefined, roundBracket: string | undefined): string => {\n if (squareBracket !== undefined) {\n return `$$${squareBracket}$$`;\n } else if (roundBracket !== undefined) {\n return `$${roundBracket}$`;\n }\n return match;\n }\n );\n}\n\n/**\n * Helper function: replace unescaped pipes with \\vert in LaTeX math fragments\n * @from https://github.com/lobehub/lobe-ui/blob/master/src/hooks/useMarkdown/latex.ts\n */\nconst replaceUnescapedPipes = (formula: string): string =>\n // Use \\vert{} so the control sequence terminates before the next token.\n // Preserve `|` inside \\begin{array}{...} / \\begin{tabular}{...} column specifiers.\n formula.replaceAll(ARRAY_COL_SPEC_OR_PIPE_REGEX, (match, colSpec: string | undefined) =>\n colSpec !== undefined ? match : '\\\\vert{}'\n );\n/**\n * Escape pipes in LaTeX expressions to prevent them from being interpreted as\n * column separators in markdown tables.\n *\n * @param text Input string containing LaTeX expressions\n * @returns String with pipes escaped in LaTeX expressions\n * @modified from https://github.com/lobehub/lobe-ui/blob/master/src/hooks/useMarkdown/latex.ts\n */\nfunction escapeLatexPipes(text: string): string {\n return text.replaceAll(LATEX_BLOCK_REGEX, (match, display, inline) => {\n if (display !== undefined) return `$$${replaceUnescapedPipes(display)}$$`;\n if (inline !== undefined) return `$${replaceUnescapedPipes(inline)}$`;\n return match;\n });\n}\n\n/**\n * Whether the character at position `pos` is escaped by the immediately\n * preceding backslash run. An even-count run (including zero) means the\n * `$` is unescaped; an odd count means it is escaped. Example: `\\\\$` has\n * two preceding backslashes — the `\\` escapes the `\\`, leaving `$` real.\n */\nfunction isEscapedByBackslashRun(text: string, pos: number): boolean {\n let count = 0;\n let j = pos - 1;\n while (j >= 0 && text[j] === '\\\\') {\n count++;\n j--;\n }\n return count % 2 === 1;\n}\n\n/**\n * Find the start index of the trailing unclosed `$$` or `$` delimiter.\n *\n * Scans through all dollar-sign tokens tracking open/close state.\n * Returns the index of the last *opening* delimiter that was never closed,\n * or `-1` if every delimiter is paired.\n *\n * @param text Input string to scan.\n * @param mode `'both'` tracks `$$` and `$`; `'double-only'` tracks only `$$`.\n */\nfunction findUnclosedDelimiterStart(text: string, mode: 'both' | 'double-only'): number {\n let unclosedStart = -1;\n let i = 0;\n while (i < text.length) {\n if (text[i] === '$' && i + 1 < text.length && text[i + 1] === '$' && !isEscapedByBackslashRun(text, i)) {\n unclosedStart = unclosedStart === -1 ? i : -1;\n i += 2;\n } else if (\n mode === 'both' &&\n text[i] === '$' &&\n !isEscapedByBackslashRun(text, i) &&\n (i + 1 >= text.length || text[i + 1] !== '$')\n ) {\n unclosedStart = unclosedStart === -1 ? i : -1;\n i += 1;\n } else {\n i += 1;\n }\n }\n return unclosedStart;\n}\n\nfunction escapeLatexPipesInUnclosed(text: string): string {\n const unclosedStart = findUnclosedDelimiterStart(text, 'both');\n if (unclosedStart === -1) return text;\n\n // Escape pipes only in the unclosed tail\n const before = text.substring(0, unclosedStart);\n const delimLen = text[unclosedStart + 1] === '$' ? 2 : 1;\n const delim = text.substring(unclosedStart, unclosedStart + delimLen);\n const tail = text.substring(unclosedStart + delimLen);\n return before + delim + replaceUnescapedPipes(tail);\n}\n\n/**\n * Truncate trailing unclosed `$$` blocks (streaming protection).\n *\n * During streaming, an unclosed `$$` at the start of a line triggers\n * remarkMath's `mathFlow` tokenizer, which treats all subsequent content\n * as part of a display math block until a closing `$$` fence is found.\n * Since the closing fence hasn't arrived yet, the entire remainder of the\n * document is swallowed into one giant math node — producing a wall of\n * red KaTeX error text.\n *\n * This function detects the trailing unclosed `$$` and removes it\n * (including any preceding whitespace/newlines) so that remarkMath never\n * sees the incomplete delimiter. Once the closing delimiter arrives in\n * a later streaming chunk, the complete block will render normally.\n *\n * Only tracks `$$` — single `$` does not trigger mathFlow and is harmless\n * when `singleDollarTextMath` is `false`.\n */\nfunction truncateUnclosedLatexBlock(\n text: string,\n unclosedStart = findUnclosedDelimiterStart(text, 'double-only')\n): string {\n if (unclosedStart === -1) return text;\n\n // Strip the unclosed $$ block and any trailing whitespace before it.\n return text.substring(0, unclosedStart).trimEnd();\n}\n\n/**\n * Escape unescaped underscores within `\\text{...}` commands in LaTeX expressions.\n * For example, `\\text{node_domain}` becomes `\\text{node\\_domain}`, but\n * `\\text{node\\_domain}` stays unchanged.\n *\n * The body scan is brace-aware: nested groups `\\text{outer {inner}_x}`\n * are matched via a depth counter that respects `\\{` / `\\}` escapes and\n * the escape for `\\\\` itself, so the entire body (depth ≥ 0) is scanned\n * before we escape its underscores. An unclosed `\\text{` body (missing\n * closing brace, e.g. during streaming) is left untouched.\n *\n * @param text Input string that may contain LaTeX expressions\n * @returns String with unescaped underscores escaped within `\\text{...}` commands\n */\nfunction escapeTextUnderscores(text: string): string {\n let out = '';\n let i = 0;\n while (i < text.length) {\n const start = text.indexOf(TEXT_COMMAND, i);\n if (start === -1) {\n out += text.substring(i);\n return out;\n }\n\n out += text.substring(i, start);\n const bodyStart = start + TEXT_COMMAND.length;\n let depth = 1;\n let j = bodyStart;\n while (j < text.length && depth > 0) {\n const c = text[j];\n if (c === '\\\\' && j + 1 < text.length) {\n // Skip the escaped character so `\\{`, `\\}`, `\\\\` don't affect depth.\n j += 2;\n continue;\n }\n if (c === '{') depth++;\n else if (c === '}') {\n depth--;\n if (depth === 0) break;\n }\n j++;\n }\n\n if (depth !== 0) {\n // Unclosed \\text{ — leave the remainder as-is so a later streaming\n // chunk can complete it.\n out += text.substring(start);\n return out;\n }\n\n const body = text.substring(bodyStart, j);\n const escapedBody = body.replaceAll(/(?<!\\\\)_/g, '\\\\_');\n out += `\\\\text{${escapedBody}}`;\n i = j + 1; // past closing `}`\n }\n return out;\n}\n\n/**\n * Convert single dollar delimiters to double dollar delimiters.\n * e.g. $x^2$ → $$x^2$$\n */\nfunction convertSingleToDoubleDollar(text: string): string {\n return text.replaceAll(SINGLE_DOLLAR_REGEX, (_match, content: string) => `$$${content}$$`);\n}\n\n/**\n * Main LaTeX preprocessor entry point.\n *\n * Splits the input into protected regions (code blocks, inline code, HTML tags)\n * and applies the full normalization pipeline to unprotected text segments.\n * Returns the input unchanged when no LaTeX-related characters (`$`, `\\[`, `\\(`)\n * are detected.\n *\n * @param str - Raw markdown string.\n * @returns The preprocessed string with normalized LaTeX delimiters.\n */\nexport function preprocessLaTeX(str: string): string {\n // Return early if no LaTeX patterns are found.\n if (!hasLatexTrigger(str)) return str;\n // The transform chain itself lives in `processSlice` — the incremental\n // preprocessor needs the same chain with quiescence probes, and until\n // 2.5.2 the two were written out separately and kept byte-equal BY HAND.\n // Byte-equality is a hard contract (the incremental wrapper freezes a\n // prefix of this function's output), so a chain that can drift is a defect\n // waiting to happen rather than a duplication to tolerate. The only thing\n // that was ever genuinely different is the whole-string early-exit above,\n // which a slice must not re-decide — see `processSlice`.\n return processSlice(str, false).out;\n}\n\n// ─── Incremental (append-aware) wrapper ─────────────────────────────────────\n//\n// `preprocessLaTeX` is O(n) per call and runs on every revealed frame during\n// smooth streaming. The wrapper below freezes the transformed output of the\n// settled prefix and re-processes only the active tail, byte-identical to\n// `preprocessLaTeX(full)` at every step — INCLUDING the whole-string\n// early-exit's quirks (that equivalence, not idealized semantics, is the\n// contract; pinned by the replay/property suites in latex.incremental.test.ts).\n//\n// Safe-cut rules (oracle-amended design, 2026-08-05 review):\n// - a cut sits at a LINE START (preceding char strictly `\\n`; lone-`\\r`\n// documents never cut and gracefully degrade to full reprocessing),\n// - inside a TEXT segment of the active region's own split (never inside a\n// fence / inline span / protected tag region),\n// - with no dangling backtick run between the last blank line and it (an\n// unmatched run can pair with a run arriving later and re-segment the\n// past — but a code span cannot cross a blank line, so a blank settles\n// every run before it),\n// - with no LATENT html tag before it — a viable `<`+letter start whose `>`\n// has not arrived: HTML_TAG_REGEX admits newlines in attributes, so the\n// match window spans lines and only a `>` anywhere after the `<` settles\n// it permanently (B1 counterexample),\n// - and, decided on the TRANSFORMED slice (raw-text checks are unsound both\n// ways because currency escaping rewrites the `$` token stream — B5):\n// quiescence — no tail-sensitive transform engaged at slice end.\n\n/** The original whole-string early-exit predicate (shared verbatim). */\nfunction hasLatexTrigger(str: string): boolean {\n return str.includes('$') || str.includes('\\\\[') || str.includes('\\\\(');\n}\n\n/** Does `text` contain an unclosed `\\text{` body? Mirrors the escape-aware\n * brace walk of `escapeTextUnderscores`'s unclosed branch. */\nfunction hasUnclosedTextCommand(text: string): boolean {\n let i = 0;\n while (i < text.length) {\n const start = text.indexOf(TEXT_COMMAND, i);\n if (start === -1) return false;\n let depth = 1;\n let j = start + TEXT_COMMAND.length;\n while (j < text.length && depth > 0) {\n const c = text[j];\n if (c === '\\\\' && j + 1 < text.length) {\n j += 2;\n continue;\n }\n if (c === '{') depth++;\n else if (c === '}') depth--;\n j++;\n }\n if (depth !== 0) return true;\n i = j;\n }\n return false;\n}\n\n/** A convertible (non-image) `\\[` still present after delimiter conversion —\n * its `\\]` has not arrived, so a later append changes this segment. */\nconst RESIDUAL_OPEN_BRACKET_RE = /(?<!!)\\\\\\[/;\n\n/** Segment whose first non-whitespace bytes are a `$$` — the only shape\n * whose B3 seam flag can be set (see processSlice). */\nconst LEADING_DOUBLE_DOLLAR_RE = /^\\s*\\$\\$/;\n\ninterface SliceResult {\n out: string;\n /** No tail-sensitive transform engaged: safe to freeze this output. */\n quiescent: boolean;\n /** `truncateUnclosedLatexBlock` fired in the slice's FIRST segment with\n * only whitespace before the `$$` opener — the original's `trimEnd`\n * would cross the seam into the frozen output (B3). */\n truncatedAtSeamStart: boolean;\n}\n\n/** THE LaTeX transform chain — the single definition of it. Both entry\n * points come through here: {@link preprocessLaTeX} with `probe: false`\n * (output only), the incremental preprocessor with probes on.\n *\n * `probe` adds the quiescence flags and never touches `out`, so the two\n * callers cannot diverge on output. The whole-string early-exit stays OUT\n * of here on purpose: a slice must not re-decide it, because `\\text{a_b}`\n * in a trigger-free slice still transforms when the FULL string carries a\n * `$` elsewhere. */\nfunction processSlice(slice: string, probe = true): SliceResult {\n const segments = splitByProtectedRegions(slice);\n const parts: string[] = [];\n let quiescent = true;\n let truncatedAtSeamStart = false;\n for (let index = 0; index < segments.length; index++) {\n const segment = segments[index];\n if (segment.isCode) {\n parts.push(segment.text);\n continue;\n }\n let text = segment.text;\n text = escapeMhchemCommands(text);\n text = escapeCurrencyDollarSigns(text);\n text = convertLatexDelimiters(text);\n if (probe && RESIDUAL_OPEN_BRACKET_RE.test(text)) quiescent = false;\n text = escapeLatexPipes(text);\n if (probe && findUnclosedDelimiterStart(text, 'both') !== -1) quiescent = false;\n text = escapeLatexPipesInUnclosed(text);\n if (probe && hasUnclosedTextCommand(text)) quiescent = false;\n text = escapeTextUnderscores(text);\n text = convertSingleToDoubleDollar(text);\n // The tail pass (`probe: false`) only needs the FIRST segment's flag,\n // and that flag needs the segment's first non-blank bytes to be a `$$`\n // opener — cheap to rule out before the O(segment) unclosed scan (plain\n // prose is one segment; this scan was the last ~20% over stateless).\n // The scan result feeds truncateUnclosedLatexBlock too — one O(segment)\n // pass, not two (r2 P2-2: a tail starting with `$$`, the streaming\n // display block's steady state, scanned twice per frame).\n let unclosedDouble: number | undefined;\n if (probe || (index === 0 && LEADING_DOUBLE_DOLLAR_RE.test(text))) {\n unclosedDouble = findUnclosedDelimiterStart(text, 'double-only');\n if (unclosedDouble !== -1) {\n quiescent = false;\n if (index === 0 && text.slice(0, unclosedDouble).trim() === '') {\n truncatedAtSeamStart = true;\n }\n }\n }\n text = truncateUnclosedLatexBlock(text, unclosedDouble);\n parts.push(text);\n }\n return { out: parts.join(''), quiescent, truncatedAtSeamStart };\n}\n\n/** A raw line holding only spaces / tabs / CR — a CommonMark blank line. */\nfunction isBlankRawLine(text: string, from: number, to: number): boolean {\n for (let i = from; i < to; i++) {\n const c = text.charCodeAt(i);\n if (c !== 32 && c !== 9 && c !== 13) return false;\n }\n return true;\n}\n\n/**\n * Last raw-safe cut in `active`, or -1. Raw conditions only (line start\n * inside a text segment, no dangling backtick run before the last blank\n * line, no latent `<`); the transformed-output quiescence check happens on\n * the candidate slice afterwards.\n */\nfunction findRawSafeCut(active: string): number {\n const segments = splitByProtectedRegions(active);\n let offset = 0;\n let lastCut = -1;\n let backtickHazard = false;\n let latentLt = false;\n for (const segment of segments) {\n if (segment.isCode) {\n // Protected regions contain no cuts; a matched tag/span/fence carries\n // no cross-append state. `>` inside one still discharges a latent `<`\n // (HTML_TAG_REGEX scans raw text, blind to our segmentation).\n if (segment.text.includes('>')) latentLt = false;\n offset += segment.text.length;\n continue;\n }\n const text = segment.text;\n // Whether the segment's first (possibly partial) line starts at a real\n // line start — only then may it count as a blank line below.\n let atLineStart = offset === 0 || active.charCodeAt(offset - 1) === 10;\n let lineStart = 0;\n while (lineStart <= text.length) {\n const nl = text.indexOf('\\n', lineStart);\n const lineEnd = nl === -1 ? text.length : nl;\n // A dangling backtick run can only be re-segmented by a run arriving\n // later that PAIRS with it, and a code span cannot cross a blank line\n // (findClosingBacktickRun stops there; a mid-line run cannot become a\n // fence, which needs a line-start run of 3+). So a blank line settles\n // every backtick before it: the hazard latch releases and lines\n // after the blank are candidates again — instead of a lone backtick\n // freezing nothing for the rest of the stream (2026-08-19 review\n // P2-3; oracle-checked: the span search is the only segmentation\n // decision that looks past a finished line). The blank must be a\n // WHOLE raw line, exactly what findClosingBacktickRun stops at:\n // terminated by `\\n` inside this segment, only spaces/tabs/CR, and\n // starting at a real line start — a segment's first partial line sits\n // after a protected span on the same line, and the remainder after\n // its last `\\n` is the START of a line that continues in the next\n // segment (property-suite counterexample: an empty remainder released\n // the latch and a cut landed past a still-unpaired backtick).\n if (atLineStart && nl !== -1 && isBlankRawLine(text, lineStart, lineEnd)) backtickHazard = false;\n for (let i = lineStart; i < lineEnd; i++) {\n const ch = text[i];\n if (ch === '`') backtickHazard = true;\n else if (ch === '>') latentLt = false;\n else if (ch === '<') {\n const next = text[i + 1];\n if (next !== undefined && (next === '/' || /[A-Za-z]/.test(next))) latentLt = true;\n }\n }\n if (nl === -1) break;\n if (!backtickHazard && !latentLt) lastCut = offset + nl + 1;\n lineStart = nl + 1;\n atLineStart = true;\n }\n offset += text.length;\n }\n return lastCut;\n}\n\n/** Only attempt a freeze once the unfrozen region exceeds this many chars —\n * below it the extra pipeline pass costs more than it saves. */\nconst DEFAULT_FREEZE_ATTEMPT_THRESHOLD = 512;\n\n/**\n * Append-aware `preprocessLaTeX`: one instance per streaming lineage (the\n * component holds it like the smooth-stream controller). Byte-identical to\n * `preprocessLaTeX(full)` on every call; non-append input resets all state;\n * identical input replays the cached output (StrictMode/idempotence).\n *\n * @param options.freezeThreshold Active-region size below which no freeze\n * is attempted. Tests pass `0` so SHORT pinned counterexamples actually\n * exercise the freeze path instead of passing vacuously through the\n * full-reprocess fallback.\n * @internal Wired by the renderer; not part of the public API.\n */\nexport function createIncrementalLatexPreprocessor(options?: {\n freezeThreshold?: number;\n /** Failure backoff (default on). Tests that rely on `freezeThreshold: 0`\n * to attempt a freeze on EVERY call turn it off, so 1-char chunkings keep\n * exercising the cut rules instead of skipping most attempts; backoff\n * can only freeze LESS, so passing without it implies passing with it.\n * @internal */\n backoff?: boolean;\n /** Test hook: called once per freeze ATTEMPT (a scan of the active\n * region) with the region's length and how many source bytes the\n * attempt froze (0 = failed), so the backoff bound and freeze progress\n * can be pinned. @internal */\n onAttempt?: (info: { activeLength: number; frozenBytes: number }) => void;\n}): (content: string) => string {\n const freezeThreshold = options?.freezeThreshold ?? DEFAULT_FREEZE_ATTEMPT_THRESHOLD;\n const onAttempt = options?.onAttempt;\n const backoff = options?.backoff ?? true;\n let prevSource = '';\n let prevOutput = '';\n let frozenSrcEnd = 0;\n let frozenOut = '';\n let triggered = false;\n // Failure backoff (2026-08-19 review P2-3): a candidate that is not\n // quiescent stays that way for as long as it is the candidate (its bytes\n // never change under append — an early stray `$` keeps parity odd for\n // every later slice), yet each frame paid a full active-region scan plus\n // a wasted candidate pass on top of the unavoidable tail pass (3× the\n // stateless cost on such documents). After a failed attempt the next one\n // waits until the active region has doubled; failed-attempt cost is then\n // a geometric series (≤ 4·O(n) over the whole stream). Freezing later\n // never changes output — every frame equals `preprocessLaTeX(full)`.\n let nextAttemptLen = 0;\n\n return function incrementalPreprocessLaTeX(source: string): string {\n if (source === prevSource) return prevOutput;\n const isAppend = source.length > prevSource.length && source.startsWith(prevSource);\n if (!isAppend) {\n frozenSrcEnd = 0;\n frozenOut = '';\n triggered = false;\n nextAttemptLen = 0;\n }\n if (!triggered) {\n // Monotone gate (B4): while the ACCUMULATED string has no trigger, the\n // original early-exits with the identity — freezing transformed output\n // in that regime would diverge the moment a later `$` arrives and the\n // full run starts transforming the prefix (`\\text{a_b}` quirk). Only\n // the appended chunk plus one char of overlap needs checking (`\\[` /\n // `\\(` can straddle the seam).\n const checkFrom = isAppend ? Math.max(0, prevSource.length - 1) : 0;\n if (!hasLatexTrigger(source.slice(checkFrom))) {\n prevSource = source;\n prevOutput = source;\n return source;\n }\n triggered = true;\n }\n let active = source.slice(frozenSrcEnd);\n if (active.length > freezeThreshold && active.length >= nextAttemptLen) {\n const activeLength = active.length;\n let advanced = false;\n let frozenBytes = 0;\n const freeze = (cut: number, slice: SliceResult) => {\n frozenOut += slice.out;\n frozenSrcEnd += cut;\n active = source.slice(frozenSrcEnd);\n advanced = true;\n frozenBytes = cut;\n };\n const cut = findRawSafeCut(active);\n if (cut > 0) {\n const candidate = processSlice(active.slice(0, cut));\n if (candidate.quiescent) freeze(cut, candidate);\n }\n // A shorter fallback cut (largest cut before the first non-quiescent\n // segment) was designed and rejected: quiescence is segment-granular\n // (plain prose is ONE segment) and, with the threshold, the unfrozen\n // prefix before trouble is < threshold bytes anyway — the backoff\n // alone brings a permanently-failing document to ≈ the stateless\n // cost (oracle review, 2026-08-19).\n nextAttemptLen = advanced || !backoff ? 0 : active.length * 2;\n onAttempt?.({ activeLength, frozenBytes });\n }\n // Tail pass: transforms only — its `quiescent` is never read, only the\n // first segment's B3 flag, so the per-segment probes are skipped (they\n // were ~40% on top of the stateless cost for a document whose freeze\n // never succeeds; the backoff had already removed the other 2×).\n const tail = processSlice(active, false);\n // B3 seam correction: the original's segment-level `trimEnd` reaches\n // back across our cut when the truncated `$$` block's segment starts\n // with nothing but whitespace. Applied at COMPOSE time only — the\n // frozen output itself stays untrimmed, because the block will close\n // in a later append and the untrimmed bytes become correct again.\n const head = tail.truncatedAtSeamStart ? frozenOut.replace(/\\s+$/, '') : frozenOut;\n const out = head + tail.out;\n prevSource = source;\n prevOutput = out;\n return out;\n };\n}\n","/**\n * Content preprocessing pipeline.\n *\n * Runs all preprocessors (built-in + user-supplied) in sequence before\n * the markdown string is handed to react-markdown. The built-in LaTeX\n * preprocessor always runs first, followed by any extra preprocessors\n * provided by the consumer.\n *\n * @module preprocessors\n */\n\nimport { AIMDContentPreprocessor } from './defs';\nimport { preprocessLaTeX } from './latex';\n\n/** Sequentially apply an array of preprocessor functions via left-fold. */\nfunction applyPreprocessors(value: string, ...fns: Array<AIMDContentPreprocessor>): string {\n return fns.reduce((result, fn) => fn(result), value);\n}\n\n/** Stable empty array to avoid re-renders when no extra preprocessors are given. */\nconst defaultExtraPreprocessors: AIMDContentPreprocessor[] = [];\n\n/**\n * Run the full preprocessing pipeline on raw markdown content.\n *\n * @param content - Raw markdown string.\n * @param extraPreprocessors - Optional user-supplied preprocessors appended after the built-in ones.\n * @param latexPreprocessor - The LaTeX stage. Defaults to the stateless\n * {@link preprocessLaTeX}; the renderer passes a per-instance\n * append-aware wrapper (byte-identical output, O(active tail) on\n * streaming appends) so per-frame reveals stop paying O(document).\n * @returns The preprocessed markdown string ready for rendering.\n */\nexport default function preprocessAIMDContent(\n content: string,\n extraPreprocessors: AIMDContentPreprocessor[] = defaultExtraPreprocessors,\n latexPreprocessor: AIMDContentPreprocessor = preprocessLaTeX\n) {\n return applyPreprocessors(content, latexPreprocessor, ...extraPreprocessors);\n}\n","/**\n * Optional streaming tail-repair preprocessor built on `remend` (the\n * markdown-termination engine extracted from Vercel's Streamdown).\n *\n * While a response streams, the tail of the markdown source is frequently\n * mid-construct — `**bold` without its closer, an unterminated `` `code ``\n * span, a half-typed `[link](url`. The stock pipeline renders those frames\n * literally (asterisks and all) until the closing bytes arrive. Wrapping the\n * content with this preprocessor completes the unterminated syntax so every\n * frame renders styled.\n *\n * NOT enabled by default — opt in per instance:\n *\n * ```tsx\n * const remend = createRemendPreprocessor();\n * <AIMarkdown content={content} contentPreprocessors={[remend]} />\n * ```\n *\n * Create the preprocessor ONCE (module scope or `useMemo`) — a fresh function\n * identity per render would defeat `contentPreprocessors`' stable-value\n * memoization and re-run the whole pipeline every frame.\n *\n * Interactions (see docs/content-preprocessors.md for the full discussion):\n *\n * - **block-memo**: zero conflict. Repairs only append/adjust the tail;\n * earlier blocks' bytes are untouched, so their hast digests still hit.\n * - **incremental parse** (`incrementalParse`): frames whose tail was\n * repaired are not byte-appends of the previous frame, so the engine's\n * append gate falls back to a full parse for exactly those frames (not\n * sticky — splicing resumes once the construct closes in the real bytes).\n * - **`preprocessLaTeX`**: user preprocessors run AFTER the built-in LaTeX\n * pass. Math repair is therefore disabled here (`katex`/`inlineKatex`\n * forced off) — the LaTeX preprocessor already owns `$` handling,\n * including truncating unclosed `$$` tails.\n * - **complete documents**: on well-formed text remend is a no-op, so the\n * final frame renders identically with or without it. A document that\n * legitimately ends inside an unterminated marker (a trailing lone `*`)\n * will get it closed — acceptable for streaming UIs, but don't apply this\n * preprocessor to static content.\n *\n * @module preprocessors/remend\n */\n\nimport remend, { type RemendOptions } from 'remend';\nimport type { AIMDContentPreprocessor } from './defs';\n\n/** Options accepted by {@link createRemendPreprocessor} — everything remend\n * supports except the math toggles, which this pipeline reserves for the\n * built-in LaTeX preprocessor. */\nexport type RemendPreprocessorOptions = Omit<RemendOptions, 'katex' | 'inlineKatex'>;\n\n/**\n * Build an {@link AIMDContentPreprocessor} that completes unterminated\n * markdown syntax at the streaming tail.\n *\n * Deviations from remend's own defaults:\n *\n * - `linkMode: 'text-only'` (overridable) — remend's default (`'protocol'`)\n * substitutes a `streamdown:incomplete-link` placeholder URL, but this\n * pipeline's URL sanitizer strips unknown protocols, which would leave a\n * dead `<a>` for the duration of the stream. Rendering the link text\n * plainly until the real URL arrives looks better under our sanitize\n * defaults.\n * - `katex`/`inlineKatex` forced off (NOT overridable — removed from the\n * option type) — the built-in LaTeX preprocessor (which runs first)\n * already rewrites and truncates `$`/`$$` constructs; two writers on the\n * same delimiters would fight.\n */\nexport function createRemendPreprocessor(options?: RemendPreprocessorOptions): AIMDContentPreprocessor {\n return (content) =>\n remend(content, {\n linkMode: 'text-only',\n ...options,\n katex: false,\n inlineKatex: false,\n });\n}\n"],"mappings":"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","names":["unreachable","unreachable","processor","i","masked","normalizeIdentifier","visit","normalizeIdentifier","node","boundary","unified","remarkParse","normalizeIdentifier","unified","remarkParse","visit","visit","SKIP","visit","visit","SKIP","global","SKIP","visit","visit","SKIP","remarkGfm","visit","visit","remarkGfm","sanitizeSchema","normalizeUri","Symbol","objectProto","nativeObjectToString","symToStringTag","funcProto","objectProto","funcToString","hasOwnProperty","Map","objectProto","hasOwnProperty","objectProto","hasOwnProperty","HASH_UNDEFINED","objectProto","hasOwnProperty","objectProto","hasOwnProperty","MAX_SAFE_INTEGER","argsTag","funcTag","freeExports","freeModule","moduleExports","objectProto","hasOwnProperty","objectProto","objectProto","hasOwnProperty","objectProto","hasOwnProperty","freeExports","freeModule","moduleExports","Buffer","objectProto","propertyIsEnumerable","nativeGetSymbols","Promise","Set","mapTag","objectTag","setTag","weakMapTag","dataViewTag","objectProto","hasOwnProperty","Uint8Array","boolTag","dateTag","mapTag","numberTag","regexpTag","setTag","stringTag","arrayBufferTag","dataViewTag","float32Tag","float64Tag","int8Tag","int16Tag","int32Tag","uint8Tag","uint8ClampedTag","uint16Tag","uint32Tag","mapTag","setTag","argsTag","arrayTag","boolTag","dateTag","errorTag","funcTag","genTag","mapTag","numberTag","objectTag","regexpTag","setTag","stringTag","symbolTag","weakMapTag","arrayBufferTag","dataViewTag","float32Tag","float64Tag","int8Tag","int16Tag","int32Tag","uint8Tag","uint8ClampedTag","uint16Tag","uint32Tag","key","CLONE_DEEP_FLAG","CLONE_SYMBOLS_FLAG","normalizeUri","id","cut"]}
1
+ {"version":3,"sources":["../src/fixtures/scenarios.ts","../src/components/markdown/processor.ts","../src/components/markdown/stages.ts","../src/components/markdown/transform.ts","../src/components/markdown/urlTransform.ts","../src/components/incrementalParse/computeFreezeBoundary.ts","../src/components/incrementalParse/mdLineText.ts","../src/components/incrementalParse/referenceTaint.ts","../src/components/incrementalParse/spliceParse.ts","../src/components/hastPredicates.ts","../src/components/incrementalParse/attributeHastChildren.ts","../src/components/incrementalParse/advanceIncrementalParse.ts","../src/components/incrementalParse/codePointSnapshots.ts","../src/components/collectDefLabels.ts","../src/components/normalizeId.ts","../src/components/extractDefBodiesFromHast.ts","../src/components/extractContributions.ts","../src/components/remarkInjectPhantomDefs.ts","../src/components/documentRegistry.ts","../src/components/pluginChain.ts","../src/components/rehypeUnwrapCrossChunkImages.ts","../src/components/rehypeRebaseHashLinks.ts","../src/components/rehypeFooterAdorn.ts","../src/components/customMdastHandlers.ts","../src/components/crossChunkUrlSanitize.ts","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_listCacheClear.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/eq.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_assocIndexOf.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_listCacheDelete.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_listCacheGet.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_listCacheHas.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_listCacheSet.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_ListCache.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_stackClear.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_stackDelete.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_stackGet.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_stackHas.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_freeGlobal.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_root.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_Symbol.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_getRawTag.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_objectToString.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseGetTag.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isObject.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isFunction.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_coreJsData.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_isMasked.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_toSource.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseIsNative.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_getValue.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_getNative.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_Map.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_nativeCreate.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_hashClear.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_hashDelete.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_hashGet.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_hashHas.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_hashSet.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_Hash.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_mapCacheClear.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_isKeyable.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_getMapData.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_mapCacheDelete.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_mapCacheGet.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_mapCacheHas.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_mapCacheSet.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_MapCache.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_stackSet.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_Stack.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_arrayEach.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_defineProperty.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseAssignValue.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_assignValue.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_copyObject.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseTimes.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isObjectLike.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseIsArguments.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isArguments.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isArray.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/stubFalse.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isBuffer.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_isIndex.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isLength.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseIsTypedArray.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseUnary.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_nodeUtil.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isTypedArray.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_arrayLikeKeys.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_isPrototype.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_overArg.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_nativeKeys.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseKeys.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isArrayLike.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/keys.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseAssign.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_nativeKeysIn.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseKeysIn.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/keysIn.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseAssignIn.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_cloneBuffer.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_copyArray.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_arrayFilter.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/stubArray.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_getSymbols.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_copySymbols.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_arrayPush.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_getPrototype.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_getSymbolsIn.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_copySymbolsIn.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseGetAllKeys.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_getAllKeys.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_getAllKeysIn.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_DataView.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_Promise.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_Set.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_WeakMap.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_getTag.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_initCloneArray.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_Uint8Array.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_cloneArrayBuffer.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_cloneDataView.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_cloneRegExp.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_cloneSymbol.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_cloneTypedArray.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_initCloneByTag.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseCreate.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_initCloneObject.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseIsMap.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isMap.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseIsSet.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/isSet.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/_baseClone.js","../../../node_modules/.pnpm/lodash-es@4.18.1/node_modules/lodash-es/cloneDeep.js","../src/components/sanitizeSchema.ts","../src/plugins/defs.ts","../src/plugins/catalog.ts","../src/components/shortenDocumentId.ts","../src/components/devStageTimings.ts","../src/components/extendSanitizeSchema.ts","../src/components/smoothStream/controller.ts","../src/preprocessors/latex.ts","../src/preprocessors/index.ts","../src/preprocessors/remend.ts"],"sourcesContent":["/**\n * Streaming stress-payload fixtures, extracted verbatim from core's\n * stories/streaming/scenarios.ts (boundary action ⑦): the engine's\n * equivalence/sensitivity test batteries consume DEFAULT_PAYLOAD/withDefs,\n * and stories keep using them through the engine entry — one source, no\n * drifting copies.\n *\n * @module fixtures/scenarios\n */\n\nconst DEFAULT_BLOCKS = [\n '# Stress payload\\n\\n',\n 'Streaming markdown with mixed token boundaries — code, math, tables, admonitions — all incomplete during transit.\\n\\n',\n '```ts\\nconst fib = (n: number): number => (n < 2 ? n : fib(n - 1) + fib(n - 2));\\nconst result = Array.from({ length: 12 }, (_, i) => fib(i));\\n```\\n\\n',\n '$$\\n\\\\int_0^\\\\infty e^{-x^2}\\\\,dx = \\\\frac{\\\\sqrt{\\\\pi}}{2}\\n$$\\n\\n',\n 'Inline math like $E = mc^2$ and $\\\\frac{a}{b}$ keeps appearing.\\n\\n',\n '| Lang | Year | Stable |\\n| --- | --- | --- |\\n| JavaScript | 1995 | yes |\\n| TypeScript | 2012 | yes |\\n| Rust | 2010 | yes |\\n\\n',\n '> The hard part is **incomplete tokens** — code fences, LaTeX delimiters, table rows mid-emission.\\n\\n',\n '- bullet one with `inline code`\\n- bullet two with [link](https://example.com)\\n- bullet three closes the test payload.\\n',\n];\n\nexport const DEFAULT_PAYLOAD = DEFAULT_BLOCKS.join('');\n\n/** Definition-bearing tail appended by {@link withDefs}: footnote and\n * link-reference defs WITH in-text references. */\nconst DEFS_TAIL =\n 'References[^n1] appear mid-prose[^n2], along with [reference links][spec] and [another one][gfm].\\n\\n' +\n '[^n1]: First footnote body with `code` and a [link](https://example.com/fn).\\n' +\n '[^n2]: Second footnote body, plain text.\\n\\n' +\n '[spec]: https://spec.commonmark.org\\n' +\n '[gfm]: https://github.github.com/gfm/ \"GFM spec\"\\n';\n\n/**\n * Append the definitions tail to a payload (any payload — including the\n * ALREADY-SCALED one; apply after `.repeat()` so one tail serves the whole\n * document and no repeat seam glues a def line onto the next repetition).\n *\n * What this exercises — and what it does NOT: the default payload contains\n * zero definitions, so without this tail the def-label scanner runs on a\n * best-case input and the aggregate footnote footer never renders. With\n * it, def lines stream through the scanner's active region (its full-parse\n * slow path) and the footer assembles. It does NOT exercise the\n * cross-chunk PHANTOM path: each benchmark side is a single chunk, so no\n * label is ever defined \"elsewhere\" and the phantom candidate set stays\n * empty — measuring that needs a second chunk contributing definitions\n * the first one references.\n */\nexport function withDefs(payload: string): string {\n const sep = payload.endsWith('\\n\\n') ? '' : payload.endsWith('\\n') ? '\\n' : '\\n\\n';\n return payload + sep + DEFS_TAIL;\n}\n","/**\n * Unified processor and VFile setup. Ported 1:1 from react-markdown\n * v10 `createProcessor` and `createFile`.\n *\n * @module components/markdown/processor\n */\n\nimport { unreachable } from 'devlop';\nimport type { Root as HastRoot } from 'hast';\nimport type { Root as MdastRoot } from 'mdast';\nimport remarkParse from 'remark-parse';\nimport remarkRehype, { type Options as RemarkRehypeOptions } from 'remark-rehype';\nimport { type PluggableList, type Processor, unified } from 'unified';\nimport { VFile } from 'vfile';\nimport type { PipelineOptions } from './types';\n\nconst emptyPlugins: PluggableList = [];\nconst emptyRemarkRehypeOptions: Readonly<RemarkRehypeOptions> = { allowDangerousHtml: true };\n\n/**\n * Build the unified processor: remark-parse → remarkPlugins → remark-rehype →\n * rehypePlugins. Returns an unfrozen processor — caller is expected to call\n * `.parse()` and `.runSync()` (or `.run()`) on it.\n */\nexport function createProcessor(\n options: Readonly<PipelineOptions>\n): Processor<MdastRoot, MdastRoot, HastRoot, undefined, undefined> {\n const rehypePlugins = options.rehypePlugins || emptyPlugins;\n const remarkPlugins = options.remarkPlugins || emptyPlugins;\n const remarkRehypeOptions = options.remarkRehypeOptions\n ? { ...options.remarkRehypeOptions, ...emptyRemarkRehypeOptions }\n : emptyRemarkRehypeOptions;\n\n return unified().use(remarkParse).use(remarkPlugins).use(remarkRehype, remarkRehypeOptions).use(rehypePlugins);\n}\n\n/**\n * Wrap the markdown string in a VFile so plugins that consume `file.value`\n * work. Mirrors react-markdown: in dev `unreachable` throws an AssertionError\n * for non-string `children`; in prod it silently no-ops, leaving `file.value`\n * undefined and unified treating the input as empty.\n */\nexport function createFile(options: Readonly<PipelineOptions>): VFile {\n const children = options.children || '';\n const file = new VFile();\n\n if (typeof children === 'string') {\n file.value = children;\n } else {\n unreachable('Unexpected value `' + String(children) + '` for `children` prop, expected `string`');\n }\n\n return file;\n}\n","/**\n * The pure pipeline stages, lifted verbatim from core's Markdown.tsx\n * (boundary action ②): parseStage / transformStage are framework-agnostic\n * (mdast/hast in, hast out) and are consumed by the incremental-parse\n * engine, so they live engine-side; renderHastSubtree and the `<Markdown>`\n * component stay in core.\n *\n * The deprecation table and validation travel with parseStage — every\n * caller (React or not) must get identical validation semantics.\n *\n * @module components/markdown/stages\n */\n\nimport { unreachable } from 'devlop';\nimport type { Root as HastRoot } from 'hast';\nimport type { Root as MdastRoot } from 'mdast';\nimport type { Processor } from 'unified';\nimport type { VFile } from 'vfile';\nimport { createFile, createProcessor } from './processor';\nimport type { Deprecation, PipelineOptions } from './types';\n\nconst changelog = 'https://github.com/remarkjs/react-markdown/blob/main/changelog.md';\n\n/** Mirrors the deprecation table react-markdown ships — kept verbatim so error\n * messages and changelog hashes match upstream. */\nconst deprecations: ReadonlyArray<Readonly<Deprecation>> = [\n { from: 'astPlugins', id: 'remove-buggy-html-in-markdown-parser' },\n { from: 'allowDangerousHtml', id: 'remove-buggy-html-in-markdown-parser' },\n {\n from: 'allowNode',\n id: 'replace-allownode-allowedtypes-and-disallowedtypes',\n to: 'allowElement',\n },\n {\n from: 'allowedTypes',\n id: 'replace-allownode-allowedtypes-and-disallowedtypes',\n to: 'allowedElements',\n },\n { from: 'className', id: 'remove-classname' },\n {\n from: 'disallowedTypes',\n id: 'replace-allownode-allowedtypes-and-disallowedtypes',\n to: 'disallowedElements',\n },\n { from: 'escapeHtml', id: 'remove-buggy-html-in-markdown-parser' },\n { from: 'includeElementIndex', id: '#remove-includeelementindex' },\n {\n from: 'includeNodeIndex',\n id: 'change-includenodeindex-to-includeelementindex',\n },\n { from: 'linkTarget', id: 'remove-linktarget' },\n { from: 'plugins', id: 'change-plugins-to-remarkplugins', to: 'remarkPlugins' },\n { from: 'rawSourcePos', id: '#remove-rawsourcepos' },\n { from: 'renderers', id: 'change-renderers-to-components', to: 'components' },\n { from: 'source', id: 'change-source-to-children', to: 'children' },\n { from: 'sourcePos', id: '#remove-sourcepos' },\n { from: 'transformImageUri', id: '#add-urltransform', to: 'urlTransform' },\n { from: 'transformLinkUri', id: '#add-urltransform', to: 'urlTransform' },\n];\n\n/**\n * Validate options that have nothing to do with the input markdown — kept\n * separate so the block-memo wrapper can validate once per render rather than\n * once per block-render call.\n */\nfunction validateOptions(options: Readonly<PipelineOptions>): void {\n for (const deprecation of deprecations) {\n if (Object.hasOwn(options, deprecation.from)) {\n unreachable(\n 'Unexpected `' +\n deprecation.from +\n '` prop, ' +\n (deprecation.to ? 'use `' + deprecation.to + '` instead' : 'remove it') +\n ' (see <' +\n changelog +\n '#' +\n deprecation.id +\n '> for more info)'\n );\n }\n }\n\n if (options.allowedElements && options.disallowedElements) {\n unreachable('Unexpected combined `allowedElements` and `disallowedElements`, expected one or the other');\n }\n}\n\n/** Bundled processor + parsed mdast + VFile, ready to feed `transformStage`. */\nexport interface ParsedMarkdown {\n processor: Processor<MdastRoot, MdastRoot, HastRoot, undefined, undefined>;\n file: VFile;\n mdast: MdastRoot;\n}\n\n/**\n * Stage 1: validate options, build the unified processor, parse the markdown\n * source into raw (pre-transform) mdast. The returned `mdast` is mutated in\n * place by remark plugins during {@link transformStage}, but its top-level\n * `position` offsets remain valid keys for hast→mdast lookup.\n */\nexport function parseStage(options: Readonly<PipelineOptions>): ParsedMarkdown {\n validateOptions(options);\n const processor = createProcessor(options);\n const file = createFile(options);\n const mdast = processor.parse(file);\n return { processor, file, mdast };\n}\n\n/**\n * Stage 2: run remark transformers, remark-rehype, and rehype plugins. Returns\n * the final hast Root. The mdast in {@link ParsedMarkdown} may be mutated\n * by remark transformers as a side effect of this call.\n */\nexport function transformStage(parsed: ParsedMarkdown): HastRoot {\n return parsed.processor.runSync(parsed.mdast, parsed.file);\n}\n","/**\n * Single-pass hast tree transform: rewrites raw HTML, runs `urlTransform` on\n * URL attributes, and applies `allowedElements` / `disallowedElements` /\n * `allowElement` filters. Ported 1:1 from react-markdown v10.\n *\n * @module components/markdown/transform\n */\n\nimport type { Element, Root } from 'hast';\nimport { urlAttributes } from 'html-url-attributes';\nimport type { BuildVisitor } from 'unist-util-visit';\nimport type { AllowElement, UrlTransform } from './types';\n\nexport interface TransformContext {\n allowedElements: ReadonlyArray<string> | null | undefined;\n allowElement: AllowElement | null | undefined;\n disallowedElements: ReadonlyArray<string> | null | undefined;\n skipHtml: boolean | null | undefined;\n unwrapDisallowed: boolean | null | undefined;\n urlTransform: UrlTransform;\n}\n\nexport function buildTransform(ctx: TransformContext): BuildVisitor<Root> {\n return function transform(node, index, parent) {\n if (node.type === 'raw' && parent && typeof index === 'number') {\n if (ctx.skipHtml) {\n parent.children.splice(index, 1);\n } else {\n parent.children[index] = { type: 'text', value: (node as { value: string }).value };\n }\n return index;\n }\n\n if (node.type === 'element') {\n const element = node as Element;\n let key: string;\n // hast's `Element.properties` is typed `Properties | undefined`. In the\n // current pipeline every emitter sets it to at least `{}`, but a future\n // custom handler that omits `properties` would otherwise blow up in\n // `Object.hasOwn` here — keep the fallback so the transform stays robust\n // against new handler shapes.\n const properties = element.properties ?? {};\n\n for (key in urlAttributes) {\n if (Object.hasOwn(urlAttributes, key) && Object.hasOwn(properties, key)) {\n const test = (urlAttributes as Record<string, ReadonlyArray<string> | null>)[key];\n if (test === null || test.includes(element.tagName)) {\n // Convergent application: always transform FROM the original —\n // the stash if an earlier pass archived one, else the live\n // property (untouched ⇔ nothing was archived). A shared\n // (memoized) tree that is re-entered without a re-parse — a\n // block-memo cache miss after a G3 flush, a urlTransform prop\n // swap, the aggregate footnote tree on a registry bump — then\n // yields `currentTransform(original)` instead of compounding the\n // transform onto its own previous output. This is what lets\n // `renderHastSubtree` skip the defensive clone for URL rewriting.\n //\n // The stash is written only by the first pass that actually\n // CHANGES the value: the default transform is identity for safe\n // URLs, and these elements live long in the block-memo cache and\n // the registry's footnote trees — an unconditional per-element\n // stash would be retained dead weight on every URL-bearing node.\n const stash = (element.data as { originalUrls?: Record<string, unknown> } | undefined)?.originalUrls;\n const hasStash = stash !== undefined && key in stash;\n const original = hasStash ? stash[key] : properties[key];\n const transformed = ctx.urlTransform(String(original || ''), key, element);\n if (!hasStash && transformed !== original) {\n const data = (element.data ??= {}) as { originalUrls?: Record<string, unknown> };\n (data.originalUrls ??= {})[key] = original;\n }\n properties[key] = transformed;\n }\n }\n }\n element.properties = properties;\n }\n\n if (node.type === 'element') {\n const element = node as Element;\n let remove = ctx.allowedElements\n ? !ctx.allowedElements.includes(element.tagName)\n : ctx.disallowedElements\n ? ctx.disallowedElements.includes(element.tagName)\n : false;\n\n if (!remove && ctx.allowElement && typeof index === 'number') {\n remove = !ctx.allowElement(element, index, parent);\n }\n\n if (remove && parent && typeof index === 'number') {\n if (ctx.unwrapDisallowed && element.children) {\n parent.children.splice(index, 1, ...element.children);\n } else {\n parent.children.splice(index, 1);\n }\n return index;\n }\n }\n\n return undefined;\n };\n}\n","/**\n * Default URL transform — same allowlist as react-markdown / GitHub.\n *\n * @module components/markdown/urlTransform\n */\n\nimport type { UrlTransform } from './types';\n\nconst safeProtocol = /^(https?|ircs?|mailto|xmpp)$/i;\n\n/**\n * Make a URL safe.\n *\n * Allows `http`, `https`, `irc`, `ircs`, `mailto`, and `xmpp` protocols, plus\n * URLs relative to the current protocol (e.g. `/foo`). Other protocols are\n * stripped to the empty string. Mirrors GitHub's behaviour and matches\n * `micromark-util-sanitize-uri` minus the URL-encoding pass.\n */\nexport const defaultUrlTransform: UrlTransform = (value) => {\n const colon = value.indexOf(':');\n const questionMark = value.indexOf('?');\n const numberSign = value.indexOf('#');\n const slash = value.indexOf('/');\n\n if (\n // No protocol → relative.\n colon === -1 ||\n // First colon is after `/`, `?`, or `#` → not a protocol.\n (slash !== -1 && colon > slash) ||\n (questionMark !== -1 && colon > questionMark) ||\n (numberSign !== -1 && colon > numberSign) ||\n // Allowed protocol.\n safeProtocol.test(value.slice(0, colon))\n ) {\n return value;\n }\n\n return '';\n};\n","/**\n * Freeze-boundary detector for incremental (prefix-freeze) parsing.\n *\n * Production port of the \"L4\" rule validated by the measurement study in\n * `src/experiments/prefixFreeze/` (see its README for the ablation ladder,\n * the falsification results, and the intentional two-way divergence note —\n * stricter blockers AND looser code-span masking; the corpus-scoped\n * directional pin lives in detectorConsistency.test.ts).\n *\n * The boundary is the largest source offset `b` such that, for ANY future\n * append to `text`, the markdown blocks that begin before `b` parse\n * byte-identically. Candidates are confirmed blank lines outside fenced\n * code and flow math; a candidate survives only if every blocker below\n * clears:\n *\n * 1. **Raw-HTML balance** — an unclosed container tag (or `<!--` comment)\n * before the candidate lets rehype-raw reparent later top-level siblings\n * into it (the v1.5.1 swallow bug, commit a8e89ec). Tag balance is\n * tracked outside fences; while any tag, comment, or raw block\n * (`<?…?>` / `<!DECL…>` / `<![CDATA[…]]>` — CommonMark html block types\n * 3–5) is open, candidates are blocked. Line-truncated tag starts\n * (`<div` at EOL, attributes wrapping) count as opens. Closers that\n * OVERLAP their opener (`<!-->`, `<!--->`, line-start `<?>`) close on\n * the spot — CommonMark and parse5 agree — so the markup after them is\n * scanned, not skipped as construct interior.\n * 2. **`$$` flow math** — remark-math's flow math swallows blank lines and\n * runs to EOF when unclosed (verified empirically); its closing fence\n * must sit at LINE START (a mid-line `$$` does not close it). Math\n * interiors are treated exactly like fence interiors: no candidates.\n * 3. **Continuation context** — CommonMark lists, footnote definitions, and\n * indented code blocks are NOT terminated by blank lines; later indented\n * lines can extend a block that \"ended\" before the candidate. With the\n * definition-list extension enabled, `: description` bodies behave the\n * same way.\n * 4. **Definition-list term claim** (`options.defListEnabled`) — the\n * micromark definition-list extension scans BACKWARD across exactly one\n * blank line to claim a preceding paragraph as a `<dt>`. A candidate\n * whose blank run is 1 is only safe once the next line is confirmed to\n * never match `^ {0,3}:[ \\t]`; runs of ≥ 2 blanks are immune.\n * 5. **Reference taint** — micromark decides reference-ness at parse time,\n * so a later `[label]:` definition retargets earlier literal `[text]`.\n * Every reference-style candidate before the boundary must resolve\n * against a SETTLED definition (one followed by a confirmed blank line).\n * Labels are matched with micromark's own `normalizeIdentifier`\n * (Unicode case folding — `toLowerCase` is the unsafe direction).\n * Definitions must START a block (or chain a valid definition line) —\n * a def-shaped paragraph continuation line is literal text.\n * 6. **Raw-remnant seam** — an html FLOW run can swallow non-tag lines\n * (e.g. a `$$` math fence glued under `</details>`); once tag balance\n * returns to zero, that remnant becomes FLOATING text that parse5/\n * rehype-raw attaches at the root, and its hast shape (position vs\n * seam-owned position-less, trailing-newline ownership) depends on\n * whether a sibling node FOLLOWS it. A tail block that flips between\n * def (no hast output) and paragraph therefore reshapes the frozen\n * region retroactively (2026-07-31 direction-battery counterexample,\n * reproduced on v1.8.0). Every candidate emitted while the remnant is\n * the last frozen child is rejected (they stay rejected for good); once\n * a later confirmed content line pins the seam from the frozen side,\n * the candidates AFTER that line are safe again. Dropping candidates\n * only over-blocks (safe direction). Whitespace-only remnant counts.\n * A type 2-5 block that opens AND closes on its first line owns the\n * rest of that line as raw content too (`<!-- c --> tail`) — same seam.\n * 7. **Phase poison** (`phasePoisonedAt`) — points where this line-level\n * model may have DIVERGED from micromark and provably cannot resync:\n * a fence/math open suppressed inside an html-flow run (only certainly\n * swallowed at top level — in a container it really opens and the\n * open/close phase inverts permanently), and a paragraph-inline `<!--`\n * that fails to close by end of line (literal text to micromark, but\n * the comment scan would skip real markup as comment interior), and\n * every point where CommonMark's terminator and parse5's tokenizer\n * DISAGREE about where a raw construct ends (`--!>` closes a comment\n * for parse5 only; a `<?…`/`<![CDATA[…` bogus comment ends at its\n * first `>` for parse5 but at `?>`/`]]>` for CommonMark; a paragraph-\n * inline `<?>` is open to micromark, closed to parse5) — the bytes in\n * between are raw text to one grammar and real markup to the other, and\n * the hast is parse5's. Every candidate past the first such point is\n * rejected, sticky; candidates at or before it stay valid — the\n * ambiguous region then re-parses inside the tail (pure over-block).\n *\n * ## Incremental scanning (checkpoint resume)\n *\n * The hot path calls this once per streamed frame. Appends leave every\n * previously-CONFIRMED line byte-identical, so the scan checkpoints its\n * entire per-line state after the last confirmed line (one whose\n * terminating `\\n` exists) and, given `resume`, re-lexes only from there.\n * The trailing PARTIAL line is never baked into the checkpoint: it cannot\n * emit candidates (unconfirmed lines are never blank), its tag/ref effects\n * cannot affect candidates that all precede it, and the next frame re-lexes\n * it from scratch. Resume MUTATES the checkpoint monotonically and is\n * idempotent for identical input — but a checkpoint belongs to exactly one\n * advancing state lineage (advanceIncrementalParse's), never share it.\n *\n * Continuation hazards (blocker 3) are a forward-rolling verdict updated at\n * each decisive block start — equivalent to the previous per-candidate\n * upward walk (\"nearest decisive block start above\") at O(1) per candidate.\n * Reference taint (blocker 5) maintains defs and an unresolved-ref list\n * incrementally; settling is monotone, so resolved entries only ever leave.\n *\n * ## Inline code-span masking\n *\n * `` `<div>` ``, `` `[x]` `` and `` `[^n]` `` in prose are code, not\n * markup. Before HTML/ref/footnote extraction each line is masked using\n * micromark's own pairing rule (equal-length backtick runs, leftmost\n * first) — but ONLY when the pairing is provably intra-line: if any run on\n * a line is left unpaired, or an earlier line of the same paragraph left\n * one unpaired, masking is disabled for the rest of the paragraph. A\n * cross-line span can therefore never cause an unmask mismatch: every\n * masked span is one micromark would pair identically. Skipped masking\n * only over-blocks (safe direction).\n *\n * A line only counts as blank once its terminating newline exists: the\n * trailing partial line is UNCONFIRMED (the next chunk may append content\n * to it) and treating it as blank breaks boundary monotonicity.\n *\n * Footnote refs/defs participate in blockers 3 and 5 like their link\n * counterparts (separate label namespace); the engine splices across them\n * via injection replay (v2).\n */\n\nimport { htmlBlockNames } from 'micromark-util-html-tag-name';\nimport { isMdBlank, mdTrimStart } from './mdLineText';\nimport {\n collectRefLine,\n settleRefsAndEarliestUnresolved,\n DEF_RE,\n FOOTNOTE_DEF_RE,\n type UnresolvedRef,\n} from './referenceTaint';\n\n/** CommonMark type-6 block tag names (micromark's own list), lowercase. */\nconst TYPE6_NAMES = new Set(htmlBlockNames);\n/** Table-part tag names: a stray one outside a table re-routes how parse5\n * builds every LATER GFM table (cell text foster-parented to the root —\n * v2.4.2 review P1-2; the splice bails on any such tag in the frozen\n * prefix). Poisoning candidates from the tag on at the scanner saves the\n * per-frame scan + tail parse + splice attempt that the bail would throw\n * away, and keeps the direction battery honest (soak 2026-08-19: a\n * `<td>` prefix froze a table whose shape depended on the tail). Same\n * list as spliceParse's TABLE_PART_TAG_RE. */\nconst TABLE_PART_NAMES = new Set(['td', 'th', 'tr', 'tbody', 'thead', 'tfoot', 'caption', 'col', 'colgroup']);\n/** parse5 tree-construction CONSUMES these tokens: `rehype-raw` parses in\n * FRAGMENT mode with a `<template>` context, so the run starts in \"in\n * template\" and `startTagInTemplate` routes these names onward to the modes\n * that absorb them into document structure — they emit NO node into the\n * fragment. Their bytes\n * vanish and the text nodes on either side MERGE into one — a merge whose\n * result STARTS BEFORE the construct. That is retroactive: a `<!DOCTYPE>`\n * arriving later rewrites hast the scanner already froze (2026-08-20,\n * 16800-shape sweep: `` `\\`\\`\\`\\n\\`\\`\\`\\n\\n<!DOCTYPE>\\ne` `` — the text node at\n * index 1 goes `\"\\n\"` → `\"\\n\\n\"`). Every other line-model invariant here\n * assumes a confirmed line only affects itself and what follows, so these\n * names cannot be modelled — they poison the whole document instead.\n *\n * Counter-intuitively an UNCLOSED `<body>` was already safe: it left\n * `openTotal` at 1, which blocked candidates by accident. Only the\n * BALANCED `<body>…</body>` form reaches zero and freezes across. */\nconst DOCUMENT_STRUCTURE_NAMES = new Set(['html', 'head', 'body', 'frameset']);\n\n/** The same retroactive constructs as literal openers, for the TRAILING\n * PARTIAL line. That line is never confirmed and never enters the\n * checkpoint, so `processConfirmedLine` cannot poison from it — yet the\n * full parse the frozen prefix is checked against DOES see it, and a\n * half-arrived `<!DOCTYPE html` already erases and merges (soak leg 1,\n * shards 3 and 9: a snapshot cut mid-doctype froze at a boundary the\n * arriving doctype then rewrote). */\nconst RETROACTIVE_OPENERS = [\n '<!doctype',\n '<html',\n '<head',\n '<body',\n '<frameset',\n '</html',\n '</head',\n '</body',\n '</frameset',\n];\n\n/** Does a partial line already carry one of them? Matches COMPLETE openers\n * only. A \"could still become one\" arm was tried and reverted: every `<`\n * is a prefix of every opener, so a stream cut right after a `<` dropped\n * the boundary to 0 — and since the consumer takes\n * `min(boundary, prev.stableBoundary)`, one transient dip disables\n * freezing for the whole stream permanently. Frames that cut INSIDE an\n * opener (`…<!DOCTYP`) need no suppression: the full parse they are\n * checked against does not see a doctype there either, so the frozen\n * prefix still matches. Suppresses the BOUNDARY only — nothing here may\n * reach the checkpoint, since the tail is not confirmed. */\nfunction tailCarriesRetroactive(text: string): boolean {\n const lower = text.toLowerCase();\n for (let i = lower.indexOf('<'); i !== -1; i = lower.indexOf('<', i + 1)) {\n const rest = lower.slice(i);\n for (const op of RETROACTIVE_OPENERS) if (rest.startsWith(op)) return true;\n }\n return false;\n}\n/** HTML start tags that BREAK OUT of foreign content (HTML spec \"in foreign\n * content\": the svg/math is popped and the tag is processed as HTML). */\n/** Elements whose CONTENT is parsed with HTML rules again inside svg/math. */\n// `title` belongs here too: an SVG `title` is an HTML integration point, so\n// its CONTENT is parsed with HTML rules (a `<g/>` inside it opens an element\n// rather than honouring its self-closing flag). Adding the name is safe for\n// the tokenizer question as well, because every call site asks BEFORE this\n// tag's own `applyTag` counts it: while `<title>` itself is judged the count\n// is still 0, so it does not switch to RCDATA — which is correct, a foreign\n// `title` stays in the DATA state — and once it is open its children see\n// HTML rules, which is also correct. `annotation-xml` is an HTML integration\n// point only when its `encoding` is text/html or application/xhtml+xml;\n// treating it as one unconditionally over-blocks, i.e. errs safe.\n/** parse5 ignores an end tag whose element is not \"in scope\": the search walks\n * DOWN the open-element stack and stops at a barrier. `<div><table></div>`\n * therefore leaves the div OPEN — `</div>` is discarded, `</table>` pops only\n * the table — and everything after it nests inside that div.\n *\n * A name→count bag cannot see this: it decrements `div` because it counted a\n * `div`, and reports balance. That is an UNDER-block, live since the scanner\n * was written and found 2026-08-24 (`<div><table></div></table>` freezes at\n * 41 of 66 while the full parse nests the whole tail inside the div).\n * `marquee`, `object`, `template` and `applet` are the same family.\n *\n * That discard has a SECOND consequence, on end tags that are never in the\n * source at all (F19, 2026-08-27). `hast-util-raw` serialises the whole mdast\n * before re-parsing, so every markdown construct contributes a real tag pair\n * to parse5's input: `>` becomes `<blockquote>…</blockquote>`, `#` becomes\n * `<h1>…</h1>`, `*a*` becomes `<em>…</em>`. A barrier still OPEN when one of\n * those GENERATED end tags fires discards it by the same scope walk — and the\n * host then leaks, re-nesting everything after it (`><table>\\n</table>` +\n * blank + prose puts the tail paragraph INSIDE the blockquote; `# h <table>`\n * inside the h1). For a formatting name the leak is worse: the element stays\n * in the active-formatting-elements list and is RECONSTRUCTED around all\n * following content, which is a live shipped divergence — `*<object>*\\n\n * </object>` + blank + prose wraps the tail in a top-level `<em>` that the\n * incremental path never produces (23 bytes, every incremental frame).\n * The closing walk below cannot see this: the barrier's own raw tags are\n * BALANCED, and the tag that gets discarded was never scanned. So the second\n * consequence needs its own guard — `scopeBarrierStraddlesHost`.\n *\n * Per the HTML spec's \"has an element in scope\"; the MathML text integration\n * points and the SVG ones are barriers too. */\nconst SCOPE_BARRIER_NAMES = new Set([\n 'applet',\n 'caption',\n 'html',\n 'table',\n 'td',\n 'th',\n 'marquee',\n 'object',\n 'template',\n 'mi',\n 'mo',\n 'mn',\n 'ms',\n 'mtext',\n 'annotation-xml',\n 'foreignobject',\n 'desc',\n 'title',\n]);\n/** The two foreign-namespace roots markdown can reach. */\nconst FOREIGN_ROOT_NAMES = ['svg', 'math'];\n/** CommonMark type-1 block start names — start tags only. */\nconst TYPE1_NAMES = new Set(['script', 'pre', 'style', 'textarea']);\n/** parse5 elements whose CONTENT is text to the tokenizer (RAWTEXT /\n * RCDATA / script data / plaintext): every `<…>` inside is text until the\n * element's own end tag. Not the CommonMark type-1 list — `title`,\n * `iframe`, `noframes`, `xmp`, `noembed` sit in the type-6 list, so their content is a normal html\n * block to micromark yet text to parse5, and a `</div>` in there closed the\n * outer div in the balance (2026-08-19 review r2 P1-4). `plaintext` never\n * ends. */\nconst RAW_TEXT_ELEMENTS = new Set([\n 'script',\n 'style',\n 'textarea',\n 'title',\n 'xmp',\n 'iframe',\n 'noembed',\n 'noframes',\n // NOT `noscript`: hast-util-raw constructs parse5 with\n // `scriptingEnabled: false`, under which `<noscript>` content is ordinary\n // HTML — modelling it as raw text ignored a `<b>` inside and under-blocked\n // (oracle review of the r2 batch; regression caught before release).\n 'plaintext',\n]);\n/** Bytes parse5's DATA state acts on: `<` + letter / `!` / `/` / `?`.\n * Everything else (a lone `<`, `< b`) is character data. Used by the\n * `--!>` divergence-window check: a window containing none of these is\n * text to BOTH grammars and may converge. */\nconst P5_MARKUP_RE = /<[!/?A-Za-z]/;\n/** Type-6 start: `<`/`</` + name + (whitespace | `>` | `/>` | EOL). */\nconst TYPE6_START_RE = /^<\\/?([A-Za-z][A-Za-z0-9-]*)(?:[ \\t\\r]|\\/?>|$)/;\n/** Type-1 start: an OPEN tag of a raw-text name + (whitespace | `>` | EOL). */\nconst TYPE1_START_RE = /^<(script|pre|style|textarea)(?:[ \\t\\r]|>|$)/i;\n/** Type 1's end condition is a literal substring anywhere on the line —\n * no attributes, no whitespace before `>` (CommonMark 4.6). */\nconst TYPE1_CLOSE_RE = /<\\/(?:script|pre|style|textarea)>/i;\n/** Type-7 start, EXACT (§4.6 condition 7 + the §2.2 tag grammar): the whole\n * line is one complete OPEN tag or one complete CLOSING tag, followed by\n * whitespace only. Attribute values follow the spec grammar — a QUOTED\n * value may contain `>` (`<span title=\"a>b\">` alone on a line IS a type-7\n * block), an unquoted value may not (`<span title=a>b>` is a paragraph),\n * an attribute name is `[A-Za-z_:][A-Za-z0-9:._-]*`, an empty unquoted\n * value (`<a href=>`) invalidates the tag, and `/` self-closing must sit\n * directly before the `>` — every shape measured against micromark before\n * the approximate `[^>]*` test this replaces was retired (it both missed\n * the quoted-`>` class, which the retired `mayBeRawToMicromark` flag\n * existed to cover, and\n * over-accepted attribute garbage on non-type-6 names).\n *\n * Closing tags take NO attributes (`</span a=\"b\">` is a paragraph, and\n * treating it as html flow made the scanner apply a close parse5 never\n * sees: `<span>\\n\\n</span a=\"b\">\\n\\ntail` froze past a still-open span —\n * oracle re-check of the r2 batch. Type 6 is unaffected — its names are\n * recognized on `</name` + whitespace regardless of what follows.) */\nconst isSpaceTab = (c: number): boolean => c === 32 || c === 9;\nconst isAsciiAlpha = (c: number): boolean => (c >= 65 && c <= 90) || (c >= 97 && c <= 122);\nconst isAlnum = (c: number): boolean => isAsciiAlpha(c) || (c >= 48 && c <= 57);\n/** completeAttributeName continuation set: alphanumeric, `-` `.` `:` `_`. */\nconst isAttrNameRest = (c: number): boolean => isAlnum(c) || c === 45 || c === 46 || c === 58 || c === 95;\n/** completeAttributeValueUnquoted EXIT set (the value may not contain\n * these; note `=` exits into completeAttributeNameAfter, which happily\n * consumes another `=` — so `<foo a=b=c>` IS a complete tag to micromark,\n * looser than the spec's written grammar, measured and matched here). */\nconst isUnquotedExit = (c: number): boolean =>\n Number.isNaN(c) || c === 34 || c === 39 || c === 47 || c === 60 || c === 61 || c === 62 || c === 96 || isSpaceTab(c);\n\n/** The attribute area + `>` of a complete OPEN tag, transcribed state for\n * state from micromark's html-flow complete path (nameBefore / name /\n * nameAfter / valueBefore / valueQuoted(+After) / valueUnquoted / end).\n * Returns the index just past the closing `>`, or -1 where micromark\n * reaches `nok`. */\nconst completeOpenTagRest = (t: string, from: number): number => {\n let i = from;\n for (;;) {\n // completeAttributeNameBefore\n const c = t.charCodeAt(i);\n if (c === 47 /* / */) {\n i += 1;\n break; // → completeEnd\n }\n if (isSpaceTab(c)) {\n i += 1;\n continue;\n }\n if (!(c === 58 || c === 95 || isAsciiAlpha(c))) break; // → completeEnd\n i += 1; // completeAttributeName\n while (isAttrNameRest(t.charCodeAt(i))) i += 1;\n // completeAttributeNameAfter — also re-entered after an unquoted value,\n // which is what makes `=` chains legal.\n for (;;) {\n while (isSpaceTab(t.charCodeAt(i))) i += 1;\n if (t.charCodeAt(i) !== 61 /* = */) break; // → completeAttributeNameBefore\n i += 1; // completeAttributeValueBefore\n while (isSpaceTab(t.charCodeAt(i))) i += 1;\n const v = t.charCodeAt(i);\n if (Number.isNaN(v) || v === 60 || v === 61 || v === 62 || v === 96) return -1;\n if (v === 34 || v === 39) {\n // completeAttributeValueQuoted: anything but the marker or EOL.\n i += 1;\n while (t.charCodeAt(i) !== v) {\n if (i >= t.length) return -1;\n i += 1;\n }\n i += 1;\n // completeAttributeValueQuotedAfter: `/`, `>` or whitespace only.\n const a = t.charCodeAt(i);\n if (!(a === 47 || a === 62 || isSpaceTab(a))) return -1;\n break; // → completeAttributeNameBefore\n }\n // completeAttributeValueUnquoted (possibly empty: `<a b=/>` is\n // complete — the `/` exits straight through nameAfter to the end).\n while (!isUnquotedExit(t.charCodeAt(i))) i += 1;\n // → completeAttributeNameAfter(code) — loop.\n }\n }\n // completeEnd\n return t.charCodeAt(i) === 62 /* > */ ? i + 1 : -1;\n};\n\n/** Whether a line (leading indent stripped) meets §4.6 condition 7 — one\n * complete open or closing tag, whitespace only after — EXACTLY as\n * micromark decides it, including its tagName dispatch:\n * - a type-6 NAME never reaches condition 7 (`<div a=\"b>\">` is type 6,\n * `</div>` too — realT6 at the call site agrees);\n * - an OPEN raw-text name is type 1 — UNLESS the name is followed by `/`\n * (`<style/>` is a complete type-7 tag, measured);\n * - a CLOSING tag takes no attributes but its name is unrestricted:\n * `</style>` alone on a line IS type 7 (the earlier \"paragraph as end\n * tags\" note in Table A was wrong, and harmless only while\n * the retired `mayBeRawToMicromark` flag blanket-covered every\n * `<`-starting line).\n * A lone `\\r` is a LINE ENDING to micromark, not tag whitespace — the\n * classification runs on the segment before it (the rest of the physical\n * line is the block's first content either way). */\nexport const isType7Line = (line: string): boolean => {\n const cr = line.indexOf('\\r');\n const t = cr === -1 ? line : line.slice(0, cr);\n if (t.charCodeAt(0) !== 60 /* < */) return false;\n let i = 1;\n const closing = t.charCodeAt(i) === 47;\n if (closing) i += 1;\n if (!isAsciiAlpha(t.charCodeAt(i))) return false;\n const nameStart = i;\n i += 1;\n while (isAlnum(t.charCodeAt(i)) || t.charCodeAt(i) === 45) i += 1;\n const c = t.charCodeAt(i); // NaN at end of line\n // tagName exit set (EOL / `/` / `>` / whitespace); anything else is nok.\n if (!(Number.isNaN(c) || c === 47 || c === 62 || isSpaceTab(c))) return false;\n const name = t.slice(nameStart, i).toLowerCase();\n if (!closing && c !== 47 && TYPE1_NAMES.has(name)) return false; // type 1\n if (TYPE6_NAMES.has(name)) return false; // type 6 (or its basicSelfClosing)\n if (closing) {\n // completeClosingTagAfter: whitespace, then completeEnd's `>`.\n while (isSpaceTab(t.charCodeAt(i))) i += 1;\n if (t.charCodeAt(i) !== 62) return false;\n i += 1;\n } else {\n i = completeOpenTagRest(t, i);\n if (i === -1) return false;\n }\n // completeAfter: whitespace only to the end of (micromark's) line.\n while (isSpaceTab(t.charCodeAt(i))) i += 1;\n return i >= t.length;\n};\n\nexport interface FreezeBoundaryOptions {\n /** Whether remark-definition-list is in the active plugin chain (the\n * `enginePlugins` selection includes `definitionList`). Enables blockers 3b/4. */\n defListEnabled: boolean;\n /**\n * Whether `$$` flow math is in the grammar (remark-math). Default `true`\n * (the engine's own profile). The def-label scanner runs a PINNED\n * remark-parse+gfm subset where `$$` is ordinary paragraph text — under\n * that grammar the math branch is a MASKING hole: `inMath` returns early\n * without comment/fence scanning, so `$$\\n<!--\\n$$` reads as a closed\n * math block here while the subset grammar sees an OPEN type-2 HTML\n * comment running to `-->`/EOF (a candidate after it would let a\n * standalone tail parse invent ghost defs). With `false`, `$$` lines take\n * the ordinary text path and comments/fences inside are scanned.\n */\n mathFlow?: boolean;\n /**\n * Whether blocker 5 (reference taint) applies. Default `true`: the\n * engine must reject candidates past an unresolved `[label]` because a\n * later definition retargets the reference's PARSE. The def-label\n * scanner only extracts definition IDENTITIES — a pure block-level fact\n * unaffected by how inline references resolve — and under taint a\n * streaming citation footer (defs with no settling blank line yet)\n * collapses the boundary to the body's first reference, zeroing the\n * caching this profile exists for. `false` skips ref tracking entirely.\n */\n referenceTaint?: boolean;\n}\n\nexport interface FreezeScanResult {\n /** Largest freeze-safe boundary, or 0 when nothing can be frozen. */\n boundary: number;\n /** Opaque resume state — pass back on the next APPEND-ONLY call to skip\n * re-lexing the confirmed prefix. Single-consumer; see module docs. */\n checkpoint: FreezeScanCheckpoint;\n}\n\ninterface LineRec {\n start: number;\n end: number; // offset of the terminating \\n, or text.length for the last line\n text: string; // line content WITHOUT the line ending (a CRLF's `\\r` is stripped too)\n blank: boolean;\n indent: number; // leading whitespace width, tab = 4 (approximation)\n}\n\ninterface Candidate {\n /** Freeze boundary: start of the line after this blank line. */\n offset: number;\n /** Consecutive confirmed blank lines (outside fences/math) ending here. */\n blankRun: number;\n /** No unbalanced HTML container / comment / raw block before this point. */\n htmlBalanced: boolean;\n /** Rolling continuation-hazard verdict at emission (blocker 3). */\n hazard: boolean;\n /** Blocker-6: the run ending at this blank left balanced FLOATING raw\n * remnant whose hast seam is tail-dependent; reject this candidate. */\n seamRisk: boolean;\n /** Blocker-4 settle verdict, decided by the NEXT confirmed line (`null`\n * while that line hasn't confirmed — only the newest candidate can be\n * pending). Storing the verdict instead of the line lets the checkpoint\n * drop its lines array, which retained a full copy of the document\n * (round-2 review: ~2-3× doc size per mounted instance). */\n defListSettled: boolean | null;\n}\n\n/** micromark's open VERBATIM flow construct at a line boundary (two-model\n * P4a, first slice): fenced code and `$$` flow math — the members whose\n * interiors are candidate-free and whose close is a marker line. The\n * html-block types join this union in the next slice. `indent` is the\n * opener line's indent (0-3): only a column-0 opener is provably\n * top-level, so `pendingFenceCloser` suppresses the closer otherwise\n * (v2.4.0 review R1). Members are REPLACED, never mutated (see P5Tok). */\ntype MdBlock =\n | { kind: 'none' }\n | { kind: 'fence'; char: string; len: number; indent: number }\n | { kind: 'math'; len: number; indent: number }\n /** Type 1, the one html block whose four names do NOT share a parse5\n * answer: `script`/`style`/`textarea` are raw-text elements, `pre` is\n * not (it is absent from `RAW_TEXT_ELEMENTS`, and parse5 tokenizes its\n * content in the DATA state). `raw` carries that fact ON the member,\n * taken from the name at the claim site — the consumer that needs it\n * asks about PARSE5's grammar, not micromark's, and inferring it from\n * `p5Tok` there would read a field the same line sets one phase later.\n *\n * `indent` is the opener line's indent, and carries the same meaning it\n * does on `fence`/`math` above: only a column-0 opener is provably\n * top-level. An html block opened at indent 1-3 may be a list item's\n * content (`- a` then ` <table>`), and the F19 guard reads it for\n * exactly that — a barrier inside a container-HELD html block still\n * straddles the item's generated end tag. */\n | { kind: 'html'; type: 1; raw: boolean; indent: number }\n /** The rest of the CommonMark html blocks. Types 2-5 end by their own\n * terminators; types 6/7 end at the blank. Type 7 is entered by the\n * EXACT §4.6 test (`isType7Line`) since the exact-type-7 stage — the\n * attribute-quote hole the approximate test had (and the retired\n * `mayBeRawToMicromark` flag covered) is\n * closed, which is what let the remaining run-flag consumers migrate\n * to the member. */\n | { kind: 'html'; type: 2 | 3 | 4 | 5 | 6 | 7; indent: number };\n\nconst mdHtml = (b: MdBlock, type: 1 | 2 | 3 | 4 | 5): boolean => b.kind === 'html' && b.type === type;\n/** A type-1 block whose element is RAW TEXT to parse5 too — the state in\n * which both grammars agree every byte up to the closer is content. The\n * `pre` half of type 1 is deliberately excluded (F13). */\nconst mdType1RawText = (b: MdBlock): boolean => b.kind === 'html' && b.type === 1 && b.raw;\n/** Types 2-5 open: the interiors both grammars agree are raw content. */\nconst mdHtml25 = (b: MdBlock): boolean => b.kind === 'html' && b.type >= 2 && b.type <= 5;\n\n/** parse5 tokenizer macro-state at a LINE BOUNDARY (two-model P3a, T3.1).\n * A PARTITION of {data, rawText, script, bogus} — measured before the\n * design was frozen: the within-tag attribute position co-exists with any\n * of these (`<iframe>\\n</iframe a=\"`), so it is the separate `pendingTag`\n * overlay, NOT a member. `openedInline` is captured AT OPEN (the old\n * `rawTextInline` latch — the run state is reset before the poison that\n * reads it, so a live read would lose the poison). Members are REPLACED,\n * never mutated: checkpoints are shared mutable state, and a module-level\n * token constant would alias across mounted documents. */\ntype P5Tok =\n | { kind: 'data' }\n /** RAWTEXT / RCDATA content: everything is text until `</element`. */\n | { kind: 'rawText'; element: string; openedInline: boolean }\n /** SCRIPT_DATA with the full escape ladder (P3b batch 1, the F6\n * retirement): `escaped` = a `<!--` ran without its `-->`; `double` = a\n * nested `<script` start tag arrived while escaped (implies `escaped`).\n * While `double`, a `</script>` steps back to escaped and the ELEMENT\n * STAYS OPEN (and stays counted on `openStack`); `-->` exits BOTH\n * levels (double-escaped dash-dash on `>` goes straight to\n * SCRIPT_DATA — parse5 tokenizer, verified in source). The old\n * double-entry POISON is retired: the tangle sits identically in the\n * prefix of every future parse, so candidates may release once the\n * element truly closes — the splice side refuses these prefixes\n * separately (rawTextRegionCrossesOut), because the element CROSSES\n * micromark blocks and swallows their wrap separator. */\n | { kind: 'script'; escaped: boolean; double: boolean; openedInline: boolean }\n /** COMMENT state: `<!--` seen, closes at `-->` — or at `--!>`, which\n * micromark does NOT accept; that split is why this is a separate\n * field from `mdBlock` html{2} (P4b-completion, commit 1). Until the\n * divergence actually opens, the two agree everywhere; where it opens,\n * the relation poison has already fired. */\n | { kind: 'comment' }\n /** Bogus comment: eaten to the next `>`. */\n | { kind: 'bogus' };\n\n/** \"Comment content\" for the tag walk's markup decision — the union of the\n * two grammars' comment states, so bytes are skipped as comment interior\n * if EITHER grammar is still inside one (the divergence between them is\n * poisoned at the point it opens; neither field alone may release the\n * other's block). */\nconst commentEitherOpen = (md: MdBlock, p5: P5Tok): boolean => mdHtml(md, 2) || p5.kind === 'comment';\n\n/** The raw-text MASK predicate: while it holds, `applyTag` admits only the\n * element's own end tag, so nothing reaches the balance — a raw-text state\n * the model believes in but parse5 is not in makes candidates MORE likely\n * to survive (the unsafe direction). BOTH kinds mask; every read site goes\n * through this one predicate so no rewrite can drop the script kind. */\nconst inRawTextTok = (t: P5Tok): t is Extract<P5Tok, { kind: 'rawText' | 'script' }> =>\n t.kind === 'rawText' || t.kind === 'script';\n/** The open raw-text element's name, or null when none is open. */\nconst rawTextElement = (t: P5Tok): string | null =>\n t.kind === 'rawText' ? t.element : t.kind === 'script' ? 'script' : null;\n\n/** Opaque resume token. Produced by one `computeFreezeBoundary` call and\n * passed back on the next APPEND-ONLY call; the only supported operations\n * are storing it and passing it back. The field set is an implementation\n * detail of the scanner and changes between minor versions — the brand key\n * (a structural string literal, safe across dual d.ts entries) is all that\n * ships in the public type. */\nexport interface FreezeScanCheckpoint {\n readonly '~freezeScanCheckpoint'?: never;\n}\n\n/** Mutable resume state — the real shape behind `FreezeScanCheckpoint`.\n * Intra-package only (the scanner and its tests); not reachable from the\n * public entry, so the shape stays out of `dist/index.d.ts`. All fields\n * describe the scan strictly BEFORE the first unconfirmed character\n * (`confirmedOffset`). */\nexport interface FreezeScanCheckpointInternal extends FreezeScanCheckpoint {\n defListEnabled: boolean;\n /** Grammar-profile switches baked at creation — a checkpoint is only\n * resumable under the exact profile that built it. */\n mathFlow: boolean;\n referenceTaint: boolean;\n /** Start offset of the first line NOT yet baked into this checkpoint. */\n confirmedOffset: number;\n candidates: Candidate[];\n defs: Map<string, number>; // normalized label → def line end offset\n footnoteDefs: Map<string, number>;\n unresolvedRefs: UnresolvedRef[];\n tagBalance: Map<string, number>;\n openTotal: number;\n /** parse5's tokenizer macro-state (see `P5Tok`). Bogus comment (`<!` not\n * followed by `--` / letter / `[CDATA[`, or `</` not followed by a\n * letter — eaten up to the next `>`; micromark has no such construct),\n * raw-text content, script data with its escape flag. */\n p5Tok: P5Tok;\n /** micromark's open verbatim flow construct (see `MdBlock`). */\n mdBlock: MdBlock;\n blankRun: number;\n lastBlankStart: number;\n /** Rolling blocker-3 verdict (\"nearest decisive block start so far\"). */\n hazardVerdict: boolean;\n /** Previous confirmed line was blank (block-start detection). */\n prevLineBlank: boolean;\n /** Previous confirmed line was a plain text line (def-chain detection). */\n prevLineWasText: boolean;\n /** Previous confirmed line registered a VALID definition (def chains). */\n prevLineWasValidDef: boolean;\n /** micromark's \"content construct open\" after the previous confirmed\n * line — the EXACT interrupt input for §4.6 condition 7. micromark\n * refuses type 7 while its CONTENT construct (paragraph or definition\n * chain, including container-held paragraphs) is open; `prevLineWasText`\n * (\"any non-blank line\") over-claims that, refusing after headings,\n * thematic breaks, raw-construct terminator lines and fence closes —\n * all measured as type-7-OPENING to micromark. The decision table at\n * the end of the plain path derives this per line class; the one class\n * a line model cannot settle (a pipe line: GFM table row, after which\n * type 7 OPENS, vs pipe-bearing paragraph, after which it cannot) is\n * poisoned at the refused tag line instead — see `tableMaybeOpen`. */\n prevLineOpenContent: boolean;\n /** A GFM table MAY be open: a pipe line was seen and every line since\n * has been table-continuable. A table, once its header/delimiter pair\n * formed, is continued by ANY non-blank line that is not another\n * block-level structure — `| 1 | 2 |` then `see [a] prose` is TWO\n * table rows to micromark, not a table and a paragraph (soak seed\n * 20283008: a tag line after such a pipe-less continuation row was\n * refused as \"after content\" while micromark, whose table had just\n * been broken by the html block, OPENED type 7 — the phantom closer\n * then chased a math block that never existed). Sticky across\n * content-class lines, cleared by every openContent=false class and\n * at the usual reset points. Consumed only by the type-7 residual\n * poison — over-claiming it only widens the poison (safe). */\n tableMaybeOpen: boolean;\n /** A CONTAINER may be open: a blockquote / list-item / footnote-def\n * marker line was seen and every line since has been container-\n * continuable. micromark's `tagName` carries a `!self.parser.lazy`\n * exception the content model has no input for — a type-7-shaped line\n * that LAZILY continues an open container opens a container-held html\n * block (`> quoted` then `<x-y/>`), and a container whose last line was\n * not a paragraph CLOSES instead, leaving the same line to open a\n * top-level multi-line block (`> # h` then `<x-y/>`). Both readings say\n * \"opens\" where `prevLineOpenContent` says \"refused\", and which one\n * holds depends on container state a line model does not track (16 of\n * 21 container prefixes diverged, none poisoned — 2026-08-26 review).\n * Sticky and reset exactly like `tableMaybeOpen`, and consumed by the\n * same residual poison: over-claiming it only widens the poison. */\n containerMaybeOpen: boolean;\n /** An earlier line of the current paragraph left an unpaired backtick\n * run — masking is disabled until the paragraph ends (safety gate). */\n /** A `[` left unclosed at the end of a paragraph line (code spans\n * masked). micromark lets a reference label span soft line breaks, so\n * the label may close on a LATER line where the per-line REF_RE never\n * sees a `[…]` pair (v2.4.1 review P1: `see [foo\\nbar] end` + a late\n * `[foo bar]: /u` retargeted frozen output). Cleared wherever the\n * paragraph ends. */\n openBracket: { offset: number; text: string } | null;\n paragraphHasUnpairedRun: boolean;\n /** Blocker-6 pending flag: a confirmed html-flow line left balanced\n * floating raw remnant, and no later content line has pinned the seam\n * yet. Persists across blank lines (every candidate emitted while set\n * has the remnant as its last frozen child); cleared by the next\n * non-blank line that starts OUTSIDE an html-flow run. */\n /* ^ P-seal, explicitly (two-model T3.2): of the four (P) conditions this\n * is the genuinely retroactive one — the last root-level node the\n * frozen prefix contributed can still be EXTENDED by later bytes\n * (parse5's insertText appends to an existing trailing text node). */\n p5SealPending: boolean;\n /** A definition may still be OPEN: a def-shaped line was seen and no\n * blank has ended it yet. A definition spans up to three lines (label,\n * destination, title) and its title may wrap inside its quotes, and\n * every line after the first emits NO hast node — so none of them can\n * pin the blocker-6 seam, exactly like the def line itself. The seal\n * release tested the line's own SHAPE, which caught only the first\n * (soak 20289117, seed shard 17: `[b]: /b \"t` + `w\"` released the seam\n * and the frozen remnant node went position-less to positioned under a\n * `-->` future). Cleared at the blank, where a definition provably\n * ends; read only by the seal release, where holding it over-blocks. */\n defBlockMaybeOpen: boolean;\n /** A FOOTNOTE definition may still be RESUMABLE: `[^…]:` was seen and no\n * line since has definitively interrupted the block. Unlike a link\n * definition (whose `defBlockMaybeOpen` a blank provably ends), a\n * footnote body CONTINUES ACROSS blank lines via ≥4-indent lines — the\n * list-item continuation rule — and a resumed body paragraph then takes\n * LAZY continuation lines at ANY indent. None of those lines emits a\n * top-level hast node (the body renders in the footer section), so none\n * of them may release the blocker-6 seam. The seal release's first view\n * classified a post-blank indented line as indented CODE and released a\n * live seam (release-gate finding A, seed 20293003 — F16, the\n * cross-blank sibling of F15); its second view kept an `indent >= 4`\n * conjunct, which the lazy continuation refuted at indent 0 (F18, the\n * adversarial review of the derived-release design). Armed by a\n * footnote-def line; kept across blanks and every non-interrupting line;\n * cleared by a confirmed non-blank BLOCK-START line at indent ≤ 3, the\n * one shape no footnote body can resume past (blank above ⟹ not lazy).\n * Read only by the seal release, where holding it over-blocks. */\n fnDefResumable: boolean;\n /** Offset of the first fence/math OPEN suppressed inside an html-flow\n * run — the member gate since Migration B row 6 (Infinity = none). Whether the run really swallowed that line depends\n * on container context the line scan cannot see (`<embed` inside a list\n * item is a lazy paragraph line, and the glued `$$` a REAL math open —\n * seed-20260757 under-block: the tracker's fence phase INVERTS from that\n * line on, every later close reads as an open, and the corruption never\n * resyncs). Candidates past this offset are rejected outright — sticky,\n * pure over-block; candidates before it are untouched (the ambiguous\n * region then re-parses inside the tail). This field is the sticky\n * phase-corruption backstop (the old rolling hazard poison for\n * \"ambiguous tag names\" retired with exact type 7). */\n phasePoisonedAt: number;\n /** Tag names of line-truncated opens (`<div` at EOL) counted into\n * tagBalance but not yet confirmed by a later `>` — reverted at the next\n * blank line (a tag cannot span one). See TRUNCATED_TAG_RE. */\n pendingTruncatedTags: string[];\n /** Line-truncated CLOSING tags (`</div` + EOL, no `>`) inside an html-flow\n * run, waiting for a `>` on a later line of the same run. Unlike opens\n * they are NOT counted up front: a close tag cannot carry attributes, so\n * `para </style` (prose to micromark, still-open element to parse5 —\n * RAWTEXT waits for the `>`) must not zero the balance (2026-08-19\n * review P1 — the boundary crossed an open `<style>`). Confirmed and\n * applied only when a later line of the run brings the `>` (parse5\n * completes the end tag; micromark's block ends at the blank anyway);\n * dropped unapplied at the blank (element stays counted — over-block).\n * Paragraph-context truncated closes are never pended: a `>` at block\n * indent on the next line is a blockquote to micromark, and the one\n * shape that would complete the inline close (`</b\\n >`, a 4+-space\n * lazy continuation) is not modelled — the element stays counted,\n * over-block. */\n pendingTruncatedCloses: string[];\n /** An html-flow line ended inside a tag (`<div`, `</div`, `<br` — open,\n * close or void, with or without attributes): parse5's tokenizer is\n * still in that tag, so on the following lines everything up to the\n * FIRST `>` is attribute garbage — `</div>` there does NOT close\n * anything (oracle review of 2.4.4: `<div>\\n<div>\\n</div\\n</div>` froze\n * past the still-open outer div; pre-existing, 1-char slices). While\n * set: a line without `>` gets no tag scan at all; the line with the\n * `>` completes the pending close (if any), then only its text after\n * that `>` is scanned. Cleared there and at the blank line. */\n pendingTag: {\n /** parse5's position inside the tag's attribute area at the end of the\n * last scanned line (see TagAttrState). A quoted value left open\n * swallows `>` and line endings; a `>` while `outside` ends the tag. */\n attr: TagAttrState;\n /** Indent of the line that entered the tag. A following line that\n * DE-INDENTS below it may have left the container (a list item's html\n * block ends there; hast-util-raw resets the tokenizer at the li/ul\n * boundary, so a `<div>` on that line is a real start tag, not\n * garbage) — or may still be the same html block (root-level\n * ` </div\\n</div>`, still garbage). Unknowable here → poison. */\n indent: number;\n } | null;\n /** The open-element stack, in order. `tagBalance` and `openTotal` are\n * derived views kept in step with it, but the STACK is the truth: an end\n * tag's effect depends on what sits BETWEEN it and its match, which a\n * name→count bag cannot represent (see SCOPE_BARRIER_NAMES). */\n openStack: string[];\n}\n\n/** Elements parse5 inserts WITHOUT pushing them on the open-element stack.\n * This is parse5's list, not the HTML spec's void-element list: the spec\n * names fourteen, and parse5 additionally inserts `basefont`, `bgsound`\n * and `keygen` as void (the first two through \"in head\", `keygen` through\n * \"in body\"). Omitting the three counted them OPEN forever, which\n * over-blocks — the safe direction, and why it survived; the dangerous\n * direction (a name here that parse5 really keeps open) was measured\n * empty. `frame` is deliberately NOT here: outside a frameset parse5\n * IGNORES it — no element at all — which is the discarded-token class the\n * `frameset` document-structure poison already covers. */\nconst VOID_TAGS = new Set([\n 'area',\n 'base',\n 'basefont',\n 'bgsound',\n 'br',\n 'col',\n 'embed',\n 'hr',\n 'img',\n 'input',\n 'keygen',\n 'link',\n 'meta',\n 'param',\n 'source',\n 'track',\n 'wbr',\n]);\n\n/** CommonMark list markers at block indent (bullet or ordered), incl. bare `-`. */\nconst LIST_MARKER_RE = /^ {0,3}(?:[-*+]|\\d{1,9}[.)])(?:[ \\t]|$)/;\n/** A line that OPENS a container holding content: a blockquote marker (a\n * bare `>` counts — the quote is open either way) or a list marker WITH\n * content on the same line. A BARE marker is excluded on purpose: an\n * empty item holds no paragraph, so the next line at block indent is\n * neither its content nor a lazy continuation, and the interrupt answer\n * there is decided (the battery measures it as OPENING). Footnote\n * definitions and def-list descriptions arm through their own regexes at\n * the call site. Arms `containerMaybeOpen`. */\nconst CONTAINER_MARKER_RE = /^ {0,3}(?:>|(?:[-*+]|\\d{1,9}[.)])[ \\t]+\\S)/;\n/** Line classes for the content-tracking decision table (the type-7\n * interrupt input). All run on the TRIMMED line (indent ≤ 3 — the ≥ 4\n * case is decided before them). Measured against micromark 2026-08-25:\n * type 7 OPENS after each class below, and after html-block lines and\n * fence/math lines; it stays REFUSED after paragraph, definition,\n * footnote-definition, list-item-with-content and blockquote lines. */\nconst ATX_HEADING_RE = /^#{1,6}(?:[ \\t]|$)/;\nconst THEMATIC_BREAK_RE = /^(?:(?:-[ \\t]*){3,}|(?:\\*[ \\t]*){3,}|(?:_[ \\t]*){3,})$/;\n/** A BARE list marker (`-` / `*` / `+` / `1.` alone): opens an EMPTY item\n * and closes any content — micromark opens type 7 on the next line. */\nconst BARE_MARKER_RE = /^(?:[-*+]|\\d{1,9}[.)])[ \\t]*$/;\n/** Setext-underline shapes not already claimed above: `=+`, and `--`\n * (a lone `-` is BARE_MARKER, three+ are THEMATIC — same false answer).\n * These CONSUME an open paragraph into a heading (content closes); with\n * no paragraph open they ARE a paragraph (content opens). */\nconst SETEXT_LEFTOVER_RE = /^(?:=+|--)[ \\t]*$/;\n/** Definition-list description marker (micromark-extension-definition-list). */\nconst DEF_LIST_DD_RE = /^ {0,3}:[ \\t]/;\n/** A whole line that is one closing tag and nothing else (`</div>`,\n * `</x-y>`, `</br>`). Such a line emits NO node through rehype-raw's\n * fragment context, so it cannot pin the blocker-6 seam. */\nconst CLOSE_TAG_ONLY_RE = /^[ \\t]*<\\/[A-Za-z][A-Za-z0-9-]*[ \\t]*>[ \\t\\r]*$/;\nconst FENCE_RE = /^ {0,3}(`{3,}|~{3,})/;\n/** Leading dollar RUN at block indent — math flow fences carry a LENGTH\n * like code fences (`$$$$` opens a fence only ≥4 dollars can close;\n * K=4 census counterexample), and the meta after the run may not contain\n * `$` (a rest with any `$` is inline math / literal text, NOT a flow\n * open). */\nconst MATH_RUN_RE = /^ {0,3}(\\$\\$+)/;\n/** Opening/closing tags (name must be followed by attr/close syntax, which\n * excludes autolinks like `<https://…>`), plus comment delimiters. */\nconst TAG_OR_COMMENT_RE = /<(\\/?)([A-Za-z][A-Za-z0-9-]*)(?=[\\s/>])([^>]*)>|<!--|-->|--!>/g;\n// Empty comments whose closer OVERLAPS the opener (`<!-->`, `<!--->`):\n// CommonMark 0.31 (html flow AND text) and parse5 all close them on the\n// spot. A `<!--` match followed by `>`/`->` must not open a comment — the\n// scan would then skip REAL markup up to the next stray `-->` (2026-08\n// project-review P1: `<!-->\\n<details>\\n-->` froze past a parse5-open\n// `<details>`, the v1.5.1 swallow class). Handled inline in the token\n// scan and in `floatingResidue`, which share the state machine.\n/** A tag START whose `>` has not arrived on this line — `<div` at EOL, or\n * `<div class=\"a\"` with attributes continuing on the next line. Counted as\n * an open (probe-confirmed hazard) and remembered as PENDING: a tag can\n * carry attributes across line endings but never across a blank line, so\n * a pending open that reaches the paragraph's blank line without a `>`\n * was prose (`if x<y then`) and its phantom open is reverted there. Any\n * later `>` before that confirms it (kept open — over-block at worst).\n * Without the revert the phantom open lived forever and the whole rest of\n * the stream lost the splice, not just that paragraph (2026-08 project\n * review, eng-parse-06). */\nconst TRUNCATED_TAG_RE = /<(\\/?)([A-Za-z][A-Za-z0-9-]*)([^>]*)$/;\n/** Anchor for the truncated-tag check: the LAST `<` that starts a tag name\n * (`<x` / `</x`). Anchoring on the last `<` of any kind missed `<div a=<`\n * (attribute bytes may hold `<`; parse5 keeps the div open) — oracle\n * re-check of r2, pre-existing. */\nconst TAG_START_LT_RE = /<\\/?[A-Za-z]/g;\n/** parse5 tokenizer position inside a tag's attribute area, tracked across\n * line endings for `pendingTag` (2026-08-19 review r2 P1-2 / P2-3):\n * `outside` = before/in an attribute name (a `\"` here starts a NAME, not a\n * value); `afterEq` = just past `=`; `unquoted` = in an unquoted value\n * (whitespace ends it); `\"` / `'` = inside a quoted value — `>` and line\n * endings are value bytes there, only the matching quote leaves it. */\ntype TagAttrState = 'outside' | 'afterEq' | 'unquoted' | '\"' | \"'\";\n/** Advance the attribute-area state over `text[from, to)`; returns the\n * index of the `>` that ENDS the tag, or -1 with the state carried in\n * `out.state`. */\nfunction scanTagAttrs(text: string, from: number, to: number, out: { state: TagAttrState }): number {\n let st = out.state;\n for (let i = from; i < to; i++) {\n const c = text[i];\n if (st === '\"' || st === \"'\") {\n if (c === st) st = 'outside';\n continue;\n }\n const ws = c === ' ' || c === '\\t' || c === '\\n' || c === '\\r' || c === '\\f';\n if (st === 'afterEq') {\n if (ws) continue;\n if (c === '\"' || c === \"'\") st = c;\n else if (c === '>') return i;\n else st = 'unquoted';\n continue;\n }\n if (st === 'unquoted') {\n if (ws) st = 'outside';\n else if (c === '>') return i;\n continue;\n }\n // outside\n if (c === '=') st = 'afterEq';\n else if (c === '>') return i;\n }\n out.state = st;\n return -1;\n}\nconst BACKTICK_RUN_RE = /`+/g;\n\nfunction computeIndent(text: string): number {\n let indent = 0;\n for (const ch of text) {\n if (ch === ' ') indent += 1;\n else if (ch === '\\t') indent += 4 - (indent % 4);\n else break;\n }\n return indent;\n}\n\n/**\n * Blocker 4: can the (possibly partial) line ever match `^ {0,3}:[ \\t]`\n * after future appends? Appends only extend the line rightward, so a line\n * is settled once its existing characters already contradict the pattern.\n */\nfunction canBecomeDdLine(text: string, confirmed: boolean): boolean {\n let i = 0;\n while (i < text.length && text[i] === ' ') i += 1;\n if (i > 3) return false; // indent too deep, regardless of future appends\n if (i === text.length) return !confirmed; // only spaces so far — a partial line may still grow a `:`\n if (text[i] !== ':') return false;\n if (i + 1 === text.length) return !confirmed; // trailing `:` — a partial line may still grow the space\n return text[i + 1] === ' ' || text[i + 1] === '\\t';\n}\n\n/**\n * Same-line code-span masking (module docs). Returns the masked text, or\n * null when masking is unsafe for this line (an unpaired run here or\n * earlier in the paragraph). Masked spans are replaced by spaces of equal\n * length so every offset stays valid.\n */\nfunction maskIntraLineCodeSpans(text: string, carryOpen: boolean): { masked: string | null; unpaired: boolean } {\n BACKTICK_RUN_RE.lastIndex = 0;\n const runs: Array<{ index: number; length: number }> = [];\n let m: RegExpExecArray | null;\n while ((m = BACKTICK_RUN_RE.exec(text)) !== null) runs.push({ index: m.index, length: m[0].length });\n if (runs.length === 0) return { masked: carryOpen ? null : text, unpaired: false };\n // Pair equal-length runs leftmost-first (micromark's rule, same line).\n const spans: Array<[number, number]> = [];\n let unpaired = false;\n for (let i = 0; i < runs.length; i++) {\n const opener = runs[i];\n let matched = -1;\n for (let j = i + 1; j < runs.length; j++) {\n if (runs[j].length === opener.length) {\n matched = j;\n break;\n }\n }\n if (matched === -1) {\n unpaired = true;\n continue;\n }\n spans.push([opener.index, runs[matched].index + runs[matched].length]);\n i = matched; // consume through the closer\n }\n if (carryOpen || unpaired) return { masked: null, unpaired };\n if (spans.length === 0) return { masked: text, unpaired: false };\n let out = '';\n let cursor = 0;\n for (const [from, to] of spans) {\n out += text.slice(cursor, from) + ' '.repeat(to - from);\n cursor = to;\n }\n out += text.slice(cursor);\n return { masked: out, unpaired: false };\n}\n\nfunction freshCheckpoint(\n defListEnabled: boolean,\n mathFlow: boolean,\n referenceTaint: boolean\n): FreezeScanCheckpointInternal {\n return {\n defListEnabled,\n mathFlow,\n referenceTaint,\n confirmedOffset: 0,\n candidates: [],\n defs: new Map(),\n footnoteDefs: new Map(),\n unresolvedRefs: [],\n tagBalance: new Map(),\n openTotal: 0,\n p5Tok: { kind: 'data' },\n openStack: [],\n mdBlock: { kind: 'none' },\n blankRun: 0,\n lastBlankStart: -1,\n hazardVerdict: false,\n prevLineBlank: true, // doc start counts as a block start\n prevLineWasText: false,\n prevLineWasValidDef: false,\n prevLineOpenContent: false,\n tableMaybeOpen: false,\n containerMaybeOpen: false,\n paragraphHasUnpairedRun: false,\n openBracket: null,\n p5SealPending: false,\n defBlockMaybeOpen: false,\n fnDefResumable: false,\n phasePoisonedAt: Infinity,\n pendingTruncatedTags: [],\n pendingTruncatedCloses: [],\n pendingTag: null,\n };\n}\n\n/** Blocker-3 classification of a block-START line (raw text; markers are\n * never inside code spans at block indent). Returns the new rolling\n * verdict, or null when the line is ambiguous (verdict unchanged). */\nfunction classifyBlockStart(text: string, indent: number, defListEnabled: boolean): boolean | null {\n if (indent >= 4) return true; // indented code / item continuation merges across blanks (A1)\n if (LIST_MARKER_RE.test(text) || FOOTNOTE_DEF_RE.test(text)) return true;\n if (defListEnabled && DEF_LIST_DD_RE.test(text)) return true;\n if (indent === 0) return false; // column-0 non-marker block terminates any list context\n return null; // indent 1–3 non-marker: ambiguous\n}\n\nexport function computeFreezeBoundary(\n text: string,\n options: FreezeBoundaryOptions,\n resume?: FreezeScanCheckpoint | null\n): FreezeScanResult {\n const mathFlow = options.mathFlow ?? true;\n const referenceTaint = options.referenceTaint ?? true;\n const prev = resume as FreezeScanCheckpointInternal | null | undefined;\n // A checkpoint encodes profile-dependent state (math phase, ref taint\n // tables) — resuming under a DIFFERENT profile would mix grammars, so\n // every switch participates in the invalidation check.\n const cp =\n prev &&\n prev.defListEnabled === options.defListEnabled &&\n prev.mathFlow === mathFlow &&\n prev.referenceTaint === referenceTaint &&\n prev.confirmedOffset <= text.length\n ? prev\n : freshCheckpoint(options.defListEnabled, mathFlow, referenceTaint);\n\n // ── advance the checkpoint over newly-CONFIRMED lines ──\n let start = cp.confirmedOffset;\n let tailLine: LineRec | null = null;\n while (start < text.length) {\n // Line endings are what micromark counts: `\\n`, `\\r\\n` and a LONE `\\r`\n // (2026-08-19 review r2 P1-5: splitting on `\\n` only hid the fence /\n // math OPENER after `a\\r` inside one scanner line, and a candidate\n // landed inside the open block). `end` is the LAST byte of the ending\n // (the `\\n` of a CRLF), so `end + 1` is the next line start as before;\n // `lineText` excludes the ending. A lone `\\r` as the very last byte is\n // NOT confirmed: the `\\n` that may follow belongs to the same ending.\n let end = text.length;\n let textEnd = text.length;\n {\n const nl = text.indexOf('\\n', start);\n const cr = text.indexOf('\\r', start);\n if (cr !== -1 && (nl === -1 || cr < nl)) {\n textEnd = cr;\n end = text.charCodeAt(cr + 1) === 10 ? cr + 1 : cr;\n } else if (nl !== -1) {\n textEnd = nl;\n end = nl;\n }\n }\n const confirmed = end < text.length && !(end === text.length - 1 && text.charCodeAt(end) === 13);\n const lineText = text.slice(start, textEnd);\n const ln: LineRec = {\n start,\n end,\n text: lineText,\n blank: confirmed && isMdBlank(lineText),\n indent: computeIndent(lineText),\n };\n if (!confirmed) {\n // The partial line is never baked into the checkpoint: it emits no\n // candidates, and its tag/ref effects cannot reach candidates that\n // all precede it.\n tailLine = ln;\n break;\n }\n\n processConfirmedLine(cp, ln, text);\n cp.confirmedOffset = end + 1;\n start = end + 1;\n }\n\n // ── settle references (blocker 5 — referenceTaint.ts) ──\n const earliestUnresolved = settleRefsAndEarliestUnresolved(cp);\n\n // ── blocker 4: defList settled check (decided by the NEXT line) ──\n const defListSettled = (c: Candidate): boolean => {\n if (!options.defListEnabled || c.blankRun >= 2) return true;\n // Confirmed next lines settle candidates eagerly in processConfirmedLine;\n // only the newest candidate can still be pending here.\n if (c.defListSettled !== null) return c.defListSettled;\n if (tailLine) return !canBecomeDdLine(tailLine.text, false);\n return false; // no next line yet — a future `: desc` could still claim the block above\n };\n\n // ── pick the last surviving candidate ──\n // A retroactive construct on the UNCONFIRMED tail line suppresses every\n // candidate for this frame (see tailCarriesRetroactive). Checked here and\n // not in the scan so nothing about the partial line is ever baked in.\n const tailRetroactive = tailLine !== null && tailCarriesRetroactive(tailLine.text);\n let boundary = 0;\n for (let i = cp.candidates.length - 1; i >= 0 && !tailRetroactive; i--) {\n const c = cp.candidates[i];\n if (!c.htmlBalanced || c.hazard || c.seamRisk) continue;\n // Fence/math phase untrusted past a suppressed open (phasePoisonedAt\n // docs) — a boundary AT the poisoned line start is still safe: the\n // whole ambiguous region lands in the tail re-parse.\n if (c.offset > cp.phasePoisonedAt) continue;\n if (c.offset > earliestUnresolved) continue;\n if (!defListSettled(c)) continue;\n boundary = c.offset;\n break;\n }\n\n return { boundary, checkpoint: cp };\n}\n\n/**\n * The closing line that would end the fence / flow-math block still open at\n * the checkpoint, or `''` when nothing provably closable is open. The whole\n * decision is scanner-domain, so it lives here rather than in the consumer:\n * a poisoned fence/math phase (blocker 7) means the \"open\" flags cannot be\n * trusted and a wrong closer would OPEN a block, and only a column-0 opener\n * is provably top-level (`openIndent` docs). `phantomSuffixCloser` prepends\n * its own newline handling; the returned text is the bare closer run.\n */\nexport function pendingFenceCloser(checkpoint: FreezeScanCheckpoint): string {\n const cp = checkpoint as FreezeScanCheckpointInternal;\n if (cp.phasePoisonedAt !== Infinity) return '';\n if (cp.mdBlock.kind === 'fence' && cp.mdBlock.indent === 0) return cp.mdBlock.char.repeat(cp.mdBlock.len);\n if (cp.mdBlock.kind === 'math' && cp.mdBlock.indent === 0) return '$'.repeat(cp.mdBlock.len);\n return '';\n}\n\n/**\n * Blocker-6 residue: the bytes of a line that are neither tags nor comment\n * tokens/content — floating raw text — computed with the SAME comment state\n * machine as the balance scan (`commentOpenAtStart` carried in from the\n * previous line; `<!-->`/`<!--->` close on the spot whether or not a comment\n * is open; `--!>` never closes for CommonMark; a stray `-->` outside a\n * comment is text). Raw-construct bytes must already be masked by the caller.\n */\nfunction floatingResidue(text: string, commentOpenAtStart: boolean): string {\n let out = '';\n let open = commentOpenAtStart;\n let last = 0; // start of the not-yet-emitted text run\n TAG_OR_COMMENT_RE.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = TAG_OR_COMMENT_RE.exec(text)) !== null) {\n if (m[0] === '<!--') {\n const next = text.slice(m.index + 4, m.index + 6);\n const overlapLen = next.startsWith('>') ? 5 : next === '->' ? 6 : 0;\n if (open) {\n if (overlapLen) {\n open = false;\n last = m.index + overlapLen;\n TAG_OR_COMMENT_RE.lastIndex = last;\n }\n continue;\n }\n out += text.slice(last, m.index);\n if (overlapLen) {\n last = m.index + overlapLen;\n TAG_OR_COMMENT_RE.lastIndex = last;\n continue;\n }\n open = true; // content until `-->` is dropped\n continue;\n }\n if (m[0] === '-->') {\n if (open) {\n open = false;\n last = m.index + 3;\n }\n continue; // stray `-->` stays in the text run\n }\n if (m[0] === '--!>') continue; // content (open) or text (closed) either way\n if (open) continue;\n out += text.slice(last, m.index); // a tag: emit the text before it, drop the tag\n last = m.index + m[0].length;\n }\n if (!open) out += text.slice(last);\n return out;\n}\n\n/** A raw construct (html block types 2-5) STARTING at the head of a line:\n * comment, processing instruction, declaration, CDATA. Shared by the\n * line's own `rawFlowStart` and by the seal release's L3. */\nconst RAW_CONSTRUCT_START_RE = /^<(?:!--|\\?|![A-Za-z]|!\\[CDATA\\[)/;\n\n/** Blocks a LATER line can continue without emitting a node of its own —\n * the seal release's L1a input. A link definition takes destination and\n * title lines; a footnote definition's body resumes across blank lines and\n * the resumed paragraph then takes lazy continuations at any indent; a\n * container (list item, blockquote, def-list description) holds content\n * lines the same way. Membership is per BLOCK, never per line shape: the\n * gate runs before the line is classified at all, because a line below a\n * resumable block has no independent block identity to classify. */\nconst sealResumableAbove = (cp: FreezeScanCheckpointInternal): boolean =>\n cp.defBlockMaybeOpen || cp.fnDefResumable || cp.containerMaybeOpen;\n\n/**\n * Blocker-6 seam release, DERIVED from parse5's own rule instead of\n * enumerated (design rev3 §2/§6).\n *\n * The rule at the token layer: a trailing text node is sealed by a NODE\n * being appended after it, at whatever insertion point is current —\n * `defaultTreeAdapter.insertText` extends the last child only while that\n * child is still a text node, and a root-level append is merely the most\n * common way to stop it. Lifted to lines:\n *\n * > Release at the first confirmed line whose bytes cause at least one\n * > node to be appended, at whatever insertion point is current, after\n * > the remnant.\n *\n * A line does that iff all three of\n *\n * L1 it STARTS a block (micromark) — not a blank, not the interior of an\n * open leaf block, not a continuation of a resumable block above;\n * L2 that block's type has to-hast output — `isWrapInvisible`\n * (spliceParse) is the exact complement: `definition` and\n * `footnoteDefinition` are the only invisible types;\n * L3 that block's serialized output survives parse5 as ≥ 1 node.\n *\n * Every layer is positively decided and an unclassified line WITHHOLDS.\n * That default is the whole point. The enumeration this replaces listed the\n * node-less line classes and released everything it had not listed, so its\n * failure mode was an under-block, and it took one on four separate\n * occasions — def continuations (F15), whole-line stray closers (review\n * M6), cross-blank body continuations (F16), lazy continuations of a\n * resumed body (F18) — each fixed by adding one member to a list whose\n * complement has no enumeration.\n */\nfunction sealReleaseDerived(cp: FreezeScanCheckpointInternal, ln: LineRec, isBlockStart: boolean): boolean {\n // L1a — the resumable-context gate, ahead of every classification. The\n // only line that provably interrupts a resumable block is a BLOCK-START\n // line at ≤ 3 indent: blank above means it cannot be a lazy continuation,\n // ≤ 3 indent means no 4-indent-gated body can resume through it. Below\n // that interruption the rule is indent-INDEPENDENT, and every\n // indent-conditioned reading of it has been refuted (F16's `indent >= 4`\n // conjunct fell to a lazy continuation at indent 0 within hours of\n // landing). The escape stays sound for CONTAINERS by the general seal\n // rule above: a ≤3-indent line below an open list item either continues\n // the item — appending its paragraph INSIDE the item, after the remnant —\n // or closes the container, appending at the root after the whole list.\n if (sealResumableAbove(cp) && !(isBlockStart && ln.indent <= 3)) return false;\n // L1b — the line must START a block. `prevLineOpenContent` is micromark's\n // own \"content construct open\" answer, derived per line class by the\n // decision table at the end of this function; while it holds, this line\n // belongs to the block above and appends nothing of its own.\n if (cp.prevLineOpenContent) return false;\n // The one class the line model cannot settle stays UNKNOWN, and UNKNOWN\n // withholds: after a pipe line, whether a GFM table is open decides\n // whether this line is another ROW (no node of its own) or a fresh block.\n if (cp.tableMaybeOpen) return false;\n // Both conjuncts above are the model speaking, not a measured guard, and\n // the difference is worth writing down: over the pinned corpus neither\n // decided a single verdict the enumeration would have decided otherwise\n // (every divergence was L3). They are unreachable through TODAY's arm site\n // — a line that arms the seam is html-owned, which closes content and\n // disarms both markers — so they cost nothing and hold the moment the arm\n // widens. Delete them only together with that argument.\n const head = mdTrimStart(ln.text);\n // L3 — parse5 survival, uniform across the whole html-flow class. The\n // class holds both node-emitting members (`<div>` opens an element) and\n // the parse5-DROPPED ones (a stray end tag, a doctype, a\n // document-structure name — no node, the remnant stays last), and the\n // enumeration leaked on that split twice: M6 for whole-line closers, and\n // again on doctype and `<html>`/`<head>` lines, which it released while\n // parse5 leaves no node for any of them (found by this migration's own\n // tripwire, inert only because the document-structure poison happened to\n // cover them). It also released a whole-line `<?instr ?>` while withholding\n // a whole-line `<!-- note -->` — same class, neither answer earned, and\n // that release is revoked here. Releasing the emitting half of the class is\n // a precision change with its own attribution, not part of this landing. The test runs at ANY indent: a\n // ≥4-indent html-shaped line is indented CODE and does emit, so\n // withholding it over-blocks rather than claims — and it keeps this\n // predicate at or inside the enumeration's releases, which the migration\n // asserts.\n if (RAW_CONSTRUCT_START_RE.test(head) || TYPE1_START_RE.test(head) || isType7Line(head)) return false;\n const t6 = TYPE6_START_RE.exec(head);\n if (t6 !== null && TYPE6_NAMES.has(t6[1].toLowerCase())) return false;\n // L2 — wrap visibility. A def-SHAPED but INVALID line does emit its\n // paragraph; withholding on the shape only over-blocks, and the shape is\n // all a line model has.\n if (DEF_RE.test(ln.text) || FOOTNOTE_DEF_RE.test(ln.text)) return false;\n // What is left starts a block whose to-hast output is an element —\n // paragraph, heading, thematic break, fence, flow math, list, blockquote,\n // table, indented code — and every one of them appends a node after the\n // remnant.\n return true;\n}\n\n/**\n * The RETIRED enumeration of node-less line classes, kept for one release\n * as the migration's containment assertion (design §8.4): the derived\n * predicate must release only where this one did. Deleted with its F-rows\n * at the next version.\n */\nfunction sealReleaseEnumerated(cp: FreezeScanCheckpointInternal, ln: LineRec, isBlockStart: boolean): boolean {\n const defShapedLine =\n DEF_RE.test(ln.text) ||\n FOOTNOTE_DEF_RE.test(ln.text) ||\n cp.defBlockMaybeOpen ||\n (cp.fnDefResumable && !(isBlockStart && ln.indent <= 3));\n const commentOnly =\n ln.text\n .replace(/<!--[\\s\\S]*?-->/g, ' ')\n .replace(/<!--[\\s\\S]*$/, ' ')\n .replace(/[ \\t\\r]/g, '') === '';\n return !defShapedLine && !commentOnly && !CLOSE_TAG_ONLY_RE.test(ln.text);\n}\n\n/** Bake one confirmed line into the checkpoint. */\nfunction processConfirmedLine(cp: FreezeScanCheckpointInternal, ln: LineRec, text: string): void {\n // Blocker-4 eager settle: this line is the \"next confirmed line\" of the\n // newest candidate. The verdict uses the RAW line exactly like the old\n // lines-array lookback did (fence/math state deliberately not consulted).\n const newest = cp.candidates[cp.candidates.length - 1];\n if (newest && newest.defListSettled === null) {\n newest.defListSettled = ln.blank ? true : !canBecomeDdLine(ln.text, true);\n }\n const isBlockStart = cp.prevLineBlank;\n // Blocker-6 seam release (see `sealReleaseDerived` for the rule and its\n // three layers). The three conditions here are L1's leaf-block half,\n // answered from state rather than from the line: a blank line starts no\n // block, a line INSIDE an html-flow run or inside a still-open\n // comment/bogus-comment token is that construct's interior, and the run's\n // own blank keeps the flag so every candidate in the trailing blank run\n // stays rejected.\n //\n // Evaluation order is load-bearing: this runs BEFORE the line's own\n // construct effects (the raw-construct scan and the tag scan sit further\n // down), so the predicate answers from the previous line's state plus\n // this line's raw text.\n if (\n cp.p5SealPending &&\n !ln.blank &&\n cp.mdBlock.kind !== 'html' &&\n !(cp.p5Tok.kind === 'comment' || cp.p5Tok.kind === 'bogus')\n ) {\n if (sealReleaseDerived(cp, ln, isBlockStart)) {\n cp.p5SealPending = false;\n // The migration's containment assertion, live for one release: the\n // derived predicate must release only where the enumeration it\n // replaces did. The other quadrant (the enumeration releasing where\n // the derived one holds) is this change's whole point and is silent;\n // THIS direction would be the derived side going UP, which is the\n // defect direction, so it is reported rather than tolerated. Not a\n // hot path — the check runs on a non-blank line only while a seam is\n // actually pending.\n if (process.env.NODE_ENV !== 'production' && !sealReleaseEnumerated(cp, ln, isBlockStart)) {\n console.error(\n `[ai-react-markdown] seal-release containment broken at offset ${ln.start}: the derived predicate ` +\n `released a line the retired enumeration withheld (${JSON.stringify(ln.text.slice(0, 80))}).`\n );\n }\n }\n }\n /** Post-collapse (T3.4) this deliberately OVER-claims: parse5 pops the\n * foreign root on a breakout tag, and no pop is modelled any more — the\n * bag says \"foreign\" until the root's own end tag. Both consumers point\n * the over-claim the safe way (self-closing tags stay counted; raw-text\n * switches poison). */\n // T3.3 direction contract: every `tagBalance` read goes through a wrapper\n // whose NAME carries the safe direction of doubt. This one may OVER-claim\n // (saying \"foreign\" when parse5 left it keeps self-closing tags counted —\n // over-blocking); the table one below must UNDER-claim.\n const possiblyInsideForeign = (): boolean => FOREIGN_ROOT_NAMES.some((name) => (cp.tagBalance.get(name) ?? 0) > 0);\n /** A self-closing tag parse5 really closes on the spot. Post-collapse\n * (two-model T3.4): ONLY the foreign roots themselves — foreign\n * elements honour the flag in any context. Every other self-closing\n * tag is counted OPEN: being exact needed the breakout and\n * integration-point enumerations whose mis-claims were the F1/F2/F5\n * family, and counting keeps `openTotal` at or above parse5's stack\n * depth — the over-blocking side. The measured cost is that well-formed\n * self-closed children (`<svg><circle/></svg>`) stay counted past the\n * `</svg>` (its scope walk removes only the svg), which blocks freezing\n * for the rest of the document — reported with the stage's diff. */\n const honoursSelfClosing = (tag: string): boolean => tag === 'svg' || tag === 'math';\n /** T3.3b, the third wrapper direction: whether the tokenizer SWITCHES\n * for a raw-text element start tag near foreign content is unknowable\n * to a name-count bag. OVER-claiming the switch opens the raw-text mask\n * parse5 is not in — the mask suppresses the tag scan, so candidates\n * get MORE likely to survive and the boundary RISES (measured:\n * `<svg><title><div></title></svg>` is safe today only because the\n * un-switched `<div>` sits on the open stack). UNDER-claiming keeps the\n * mask shut where parse5 opens it — F2, the shipped under-block.\n * Neither direction is safe, so the honest answer is a poison. */\n const foreignRawTextSwitchUnknowable = (): boolean => possiblyInsideForeign();\n /** This line carried an end tag parse5 DISCARDS (F24). Consumed by the\n * blocker-6 arm below — see the `idx === -1` branch for the rule. */\n let discardedEndTag = false;\n const applyTag = (tag: string, closing: boolean): void => {\n // Inside a raw-text element only its own end tag is markup.\n if (inRawTextTok(cp.p5Tok)) {\n // \"Script data double escaped\" (F6, retired poison → exact ladder):\n // inside an escaped `<script>` a nested `<script` start tag makes\n // parse5 stop honouring `</script>` — the first one only steps back\n // to escaped, and the element runs on. CommonMark ends its type-1\n // block at the first literal closer line regardless, so the two\n // grammars diverge about which BYTES are raw for the length of the\n // window — during it the element stays counted (no release), and\n // the frozen-prefix consequences are the splice guard's job.\n if (cp.p5Tok.kind === 'script' && cp.p5Tok.escaped && !closing && tag === 'script') {\n cp.p5Tok = { ...cp.p5Tok, double: true };\n }\n if (!(closing && tag === rawTextElement(cp.p5Tok))) return;\n if (cp.p5Tok.kind === 'script' && cp.p5Tok.double) {\n // `</script>` while double-escaped: back to escaped, element open,\n // stack untouched — the early return skips the pop below.\n cp.p5Tok = { ...cp.p5Tok, double: false };\n return;\n }\n cp.p5Tok = { kind: 'data' };\n } else {\n if (!closing && RAW_TEXT_ELEMENTS.has(tag) && foreignRawTextSwitchUnknowable()) {\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n } else if (!closing && RAW_TEXT_ELEMENTS.has(tag)) {\n // Migration collision rule (P3a): entering raw text while another\n // non-data state is live would silently drop that state's blocking\n // effect — poison instead, which can only lower the boundary.\n if (cp.p5Tok.kind !== 'data') cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n // openedInline: paragraph context, i.e. micromark html-TEXT rather\n // than an html block — the regime where a lifted element rewrites\n // its paragraph. Captured HERE (latched: the run state is reset\n // before the blank-line poison that reads this). Migration A row\n // 1: the member answers \"block context\" — NARROWER than the old\n // flag by the in-comment promotion artifact, and inert there: a\n // paragraph-inline 3-5 opener poisons document-wide, and tags\n // inside a comment never reach applyTag at all.\n const openedInline = cp.mdBlock.kind !== 'html';\n cp.p5Tok =\n tag === 'script'\n ? { kind: 'script', escaped: false, double: false, openedInline }\n : { kind: 'rawText', element: tag, openedInline };\n // PLAINTEXT never ends (`</plaintext>` is text too): nothing after\n // it can be modelled — poison from here on.\n if (tag === 'plaintext') cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n }\n }\n // Retroactive construct (see DOCUMENT_STRUCTURE_NAMES): parse5 erases\n // the tag and merges the text around it, changing hast BEFORE this\n // point. Poison from offset 0 — nothing in the document is freeze-safe\n // once one of these is confirmed, and the poison is monotone so it\n // stays that way. Sits past the raw-text guard on purpose: a `<body>`\n // inside `<script>` is text to parse5 too, and must not poison.\n if (DOCUMENT_STRUCTURE_NAMES.has(tag)) cp.phasePoisonedAt = 0;\n // `<template>` is the second kind of erasure. Its children go into a\n // content FRAGMENT (`hast-util-from-parse5` hangs them off `.content`,\n // not `.children`), and the sanitize pass then drops the element — so a\n // template block vanishes whole, children and all, and the text around\n // it merges. Inside a container the damage is worse: the direction\n // battery measured a list item swallowing the rest of the document\n // (`- a\\n<template>\\n<div>x</div>\\n</template>` + blank + prose — the\n // later paragraphs land INSIDE the li, and a one-character append\n // rewrites the frozen region via lazy continuation; blockquote form\n // identical; 2026-08-24, scaled soak leg 2). The top-level form measured\n // stable, but \"measured harmless\" has been refuted three times this\n // week, and erasure merges reach backward (the F9 lesson) — so the\n // poison is document-wide, same as the names above. An earlier sweep\n // recorded template as \"swept clean\"; that sweep sampled shapes with\n // blank lines around the block, which is exactly the layout where the\n // merge stays invisible.\n if (tag === 'template' && !closing) cp.phasePoisonedAt = 0;\n if (closing) {\n // Walk down for the match, stopping at a scope barrier. No match in\n // scope means parse5 DISCARDS this end tag and the element stays open —\n // so the counts must not move either.\n let idx = -1;\n for (let i = cp.openStack.length - 1; i >= 0; i--) {\n if (cp.openStack[i] === tag) {\n idx = i;\n break;\n }\n if (SCOPE_BARRIER_NAMES.has(cp.openStack[i])) break;\n }\n if (idx === -1) {\n // parse5's \"any other end tag\" rule reached its end: no element to\n // pop, so the token is DROPPED and the character data on either side\n // of it lands at one insertion point — one text node where the raw\n // bytes show two runs. That merge is RETROACTIVE, and the trailing\n // half of it can still grow when later bytes arrive, which is\n // blocker 6's own hazard: arm the seam and let the release predicate\n // decide when a node finally sits after it.\n //\n // F24, and the reason this is keyed on the RULE: the hazard used to\n // be covered by `DOCUMENT_STRUCTURE_NAMES` — four names, poisoning\n // the whole document — while parse5 discards end tags by the\n // thousand-name-wide rule above. `</address>\\n</address>\\n\\n` is 23\n // bytes that froze all 23 while the `\\n` between the two discarded\n // tags was a live trailing text node; `<area>\\n</script >\\n\\n` is the\n // same shape whose FIRST construct is a void START tag, which is why\n // no reading of it as \"stray end tags\" closes the class. The four\n // names keep their document-wide poison: they also merge ATTRIBUTES\n // onto elements that already exist, which is an erasure this seam\n // does not model.\n discardedEndTag = true;\n return;\n }\n // Remove ONLY the matched element. What parse5 does with the elements\n // above it depends on which end tag this is: a block name generates\n // implied end tags and pops through, while a formatting name runs the\n // adoption agency, which re-parents rather than popping. Modelling the\n // first would under-count the second — measured, it re-opened four\n // fixtures as fresh under-blocks. Leaving them counted over-blocks,\n // which is the side this scanner is allowed to be wrong on.\n //\n // LOAD-BEARING beyond the counts: the formElement latent divergence\n // (design §2.1 — parse5's form pointer survives an IMPLICIT close and\n // eats a later <form>) is guarded exactly by this rule keeping the\n // implicitly-closed form on `openStack`. Modelling implied end tags\n // here needs an explicit formElement guard shipped WITH it —\n // `formElementLatent.test.ts` is the tripwire.\n cp.openStack.splice(idx, 1);\n const count = cp.tagBalance.get(tag) ?? 0;\n if (count > 0) {\n cp.tagBalance.set(tag, count - 1);\n cp.openTotal -= 1;\n }\n } else {\n cp.openStack.push(tag);\n cp.tagBalance.set(tag, (cp.tagBalance.get(tag) ?? 0) + 1);\n cp.openTotal += 1;\n }\n };\n\n /** A table part only re-routes parse5 when it appears OUTSIDE a table —\n * which is what TABLE_PART_NAMES has always meant, and what the poison\n * never checked: a well-formed `<table><tr><td>a</td></tr></table>` killed\n * freezing for the whole rest of the document (measured: boundary 0 from\n * the table onwards, against 43 for the same prose without it).\n * `tagBalance` is the open-element model the straddle bail already trusts,\n * so this adds no new assumption — and it is read only to SUPPRESS a\n * poison, so a `<table>` the scanner failed to count leaves the old,\n * over-blocking behaviour in place (2026-08-20 B1). Every call site sits\n * BEFORE this tag's own `applyTag`, so a `<table><td>` on one line has\n * the table counted by the time the part is judged. */\n // UNDER-claiming by contract: this wrapper suppresses a poison, so doubt\n // must resolve to \"not inside a table\" (poison fires). The bag can only\n // over-count opens, and an over-counted `table` here would suppress a\n // poison wrongly — which is why the read is fenced into a named wrapper.\n //\n // PENDING TRUNCATED opens are subtracted for that reason, the same\n // phantom argument the seam check makes with `effectiveOpen`: a\n // paragraph-line `compare a<table b` is prose, parse5 discards the\n // incomplete tag, and nothing is inside a table when a later `<td>` is\n // judged — yet the bag counted it and suppressed the poison\n // (`compare a<table b\\n<td>x</td>\\n</table>` froze 59 of 63 bytes;\n // 2026-08-26 review M5, the one wrapper whose implementation contradicted\n // its name). The `>` that CONFIRMS the open clears the pending list, so a\n // real table recovers the suppression on the spot.\n const definitelyInsideTable = (): boolean =>\n (cp.tagBalance.get('table') ?? 0) > cp.pendingTruncatedTags.filter((t) => t === 'table').length;\n // P-tree, explicitly (two-model T3.2): a stray table part leaves parse5's\n // template insertion-mode stack at a table mode — a Parser field a fresh\n // parser does not share, permanently. The line model cannot watch that\n // stack, so the P-tree dimension is expressed as this poison rather than\n // as a checkpoint field: sticky, document-shaping, and cheap to test.\n const strayTablePart = (tag: string): boolean => TABLE_PART_NAMES.has(tag) && !definitelyInsideTable();\n\n // A type 2-5 raw construct (comment/PI/decl/CDATA) open at the START of\n // this line makes the whole line html-block content — the construct's\n // block ends WITH the line carrying its terminator, so even that line's\n // remainder is raw text. Gates fence/math opens, masking, and def\n // registration below, alongside the html-block member.\n const commentOpenAtLineStart = commentEitherOpen(cp.mdBlock, cp.p5Tok);\n // The two halves separately, for consumers that need the INTERSECTION\n // (floatingResidue) rather than the union — captured at line start like\n // the union itself.\n const bothCommentsOpenAtLineStart = mdHtml(cp.mdBlock, 2) && cp.p5Tok.kind === 'comment';\n // P3b batches 2/3, the divergence WINDOWS: micromark still inside its\n // comment (type 2) or PI/CDATA (type 3/5) block, parse5 already out\n // (`--!>` closed the comment; the construct's first `>` closed the\n // bogus comment). Window bytes are construct interior to one grammar\n // and live input to the other — safe exactly while parse5 reads them\n // as TEXT. The first line carrying a byte parse5 would act on poisons\n // the phase (sticky, over-block).\n const inDivergenceWindow =\n (mdHtml(cp.mdBlock, 2) && cp.p5Tok.kind !== 'comment') ||\n ((mdHtml(cp.mdBlock, 3) || mdHtml(cp.mdBlock, 5)) && cp.p5Tok.kind !== 'bogus');\n if (inDivergenceWindow && P5_MARKUP_RE.test(ln.text)) {\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n }\n const rawOpenAtLineStart = mdHtml25(cp.mdBlock) || cp.p5Tok.kind === 'comment' || cp.p5Tok.kind === 'bogus';\n\n // --- fence state (interiors are candidate-free; paragraph resets) ---\n if (cp.mdBlock.kind === 'fence') {\n const close = FENCE_RE.exec(ln.text);\n if (\n close &&\n close[1][0] === cp.mdBlock.char &&\n close[1].length >= cp.mdBlock.len &&\n isMdBlank(ln.text.slice(close[0].length))\n ) {\n cp.mdBlock = { kind: 'none' };\n }\n cp.blankRun = 0;\n cp.paragraphHasUnpairedRun = false;\n cp.openBracket = null;\n cp.prevLineBlank = false;\n cp.prevLineWasText = false;\n cp.prevLineWasValidDef = false;\n cp.prevLineOpenContent = false;\n cp.tableMaybeOpen = false;\n cp.containerMaybeOpen = false;\n return;\n }\n if (cp.mdBlock.kind !== 'math' && !rawOpenAtLineStart) {\n const open = FENCE_RE.exec(ln.text);\n // A backtick fence's info string may not contain a backtick —\n // ```a``` b is a PARAGRAPH with a code span, not a fence open (A5).\n const bogusInfo =\n open !== null && open[1][0] === '`' && ln.text.slice(ln.text.indexOf(open[1]) + open[1].length).includes('`');\n if (open && !bogusInfo && cp.mdBlock.kind === 'html') {\n // Suppressed open (Migration B row 6, exact type 7): the gate is the\n // MEMBER — an html block open from previous lines owns this ``` line\n // as raw text. The retired proxy also suppressed after `<embed x`\n // paragraph openers, where the fence is REAL (fence interrupts a\n // paragraph) and suppression was the seed-20260757 phase-corruption\n // shape. The phasePoisonedAt backstop STAYS: the member itself is\n // container-blind (a run inside a list item can end at a de-indent\n // this line model cannot see), so whether the run really swallows\n // this line is still container-dependent. Poison the phase and fall\n // through so the line stays tag-scanned as raw text.\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n } else if (open && !bogusInfo) {\n // The open line is a block start for blocker 3 (a column-0 fence\n // terminates a list context; an indented one is ambiguous/hazard).\n if (isBlockStart) {\n const verdict = classifyBlockStart(ln.text, ln.indent, cp.defListEnabled);\n if (verdict !== null) cp.hazardVerdict = verdict;\n }\n cp.mdBlock = { kind: 'fence', char: open[1][0], len: open[1].length, indent: ln.indent };\n cp.blankRun = 0;\n cp.paragraphHasUnpairedRun = false;\n cp.openBracket = null;\n cp.prevLineBlank = false;\n cp.prevLineWasText = false;\n cp.prevLineWasValidDef = false;\n cp.prevLineOpenContent = false;\n cp.tableMaybeOpen = false;\n cp.containerMaybeOpen = false;\n return;\n }\n }\n\n // --- $$ flow-math state (fence-like: no candidates, close at line start;\n // the closing run must be at least as long as the opening one, with\n // nothing but whitespace after) ---\n if (cp.mdBlock.kind === 'math') {\n const close = MATH_RUN_RE.exec(ln.text);\n if (close && close[1].length >= cp.mdBlock.len && isMdBlank(ln.text.slice(close[0].length))) {\n cp.mdBlock = { kind: 'none' };\n }\n cp.blankRun = 0;\n cp.paragraphHasUnpairedRun = false;\n cp.openBracket = null;\n cp.prevLineBlank = false;\n cp.prevLineWasText = false;\n cp.prevLineWasValidDef = false;\n cp.prevLineOpenContent = false;\n cp.tableMaybeOpen = false;\n cp.containerMaybeOpen = false;\n return;\n }\n // Fence/math OPENS are gated on the html-block MEMBER (matching the\n // fence branch above): inside an html flow run a ``` or $$ line is raw text —\n // entering fence state there would skip tag extraction on lines that\n // rehype-raw parses as REAL markup (fuzz counterexample: a fence glued\n // to `</details>` hiding a quoted `<div>`). Falling through to the\n // plain-text branch keeps those lines tag-scanned (over-block safe) —\n // but the suppression itself is only certainly right at top level, so it\n // ALSO poisons the phase (see phasePoisonedAt).\n // Under the scanner profile (mathFlow=false) `$$` is ordinary paragraph\n // text — no math state, no suppressed-open poison; the line falls through\n // to the plain-text path where its content stays comment/tag-scanned.\n const mathRun = cp.mathFlow && !rawOpenAtLineStart ? MATH_RUN_RE.exec(ln.text) : null;\n if (mathRun) {\n const rest = ln.text.slice(ln.text.indexOf(mathRun[1]) + mathRun[1].length);\n // A `$` anywhere in the rest disqualifies the flow open (meta may not\n // contain `$`): `$$x$$` is inline math, `$$x$` a plain paragraph —\n // both self-contained lines, no state either way.\n if (!rest.includes('$')) {\n if (cp.mdBlock.kind === 'html') {\n // Row 6, math half — same member gate, same kept backstop.\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n } else {\n if (isBlockStart) {\n const verdict = classifyBlockStart(ln.text, ln.indent, cp.defListEnabled);\n if (verdict !== null) cp.hazardVerdict = verdict;\n }\n cp.mdBlock = { kind: 'math', len: mathRun[1].length, indent: ln.indent };\n cp.blankRun = 0;\n cp.paragraphHasUnpairedRun = false;\n cp.openBracket = null;\n cp.prevLineBlank = false;\n cp.prevLineWasText = false;\n cp.prevLineWasValidDef = false;\n cp.prevLineOpenContent = false;\n cp.tableMaybeOpen = false;\n cp.containerMaybeOpen = false;\n return;\n }\n }\n }\n\n // --- blank line: candidate emission + paragraph reset ---\n if (ln.blank) {\n // Line-truncated tag opens that never got their `>` before this blank\n // were prose: revert their phantom opens BEFORE judging balance here.\n if (cp.pendingTruncatedTags.length > 0) {\n for (const tag of cp.pendingTruncatedTags) applyTag(tag, true);\n cp.pendingTruncatedTags = [];\n }\n // Truncated closes that never got their `>` stay UNAPPLIED (see the\n // field doc): the element remains counted — over-block, never under.\n cp.pendingTruncatedCloses = [];\n // Still inside a QUOTED attribute value at the blank: micromark ends the\n // html block here, but parse5's tokenizer stays in the value — the\n // paragraph text after the blank goes in as characters (not tokenized)\n // and the NEXT raw node's bytes are eaten up to the closing quote. Which\n // grammar wins where is not modelled: poison (over-block). `outside` /\n // unquoted at the blank keep the classic behaviour (the pending close is\n // dropped, the element stays counted).\n if (cp.pendingTag !== null && (cp.pendingTag.attr === '\"' || cp.pendingTag.attr === \"'\")) {\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n }\n cp.pendingTag = null;\n // Same for a bogus comment left open WITHOUT its md construct: the\n // block ended, the tokenizer has not — poison and reset. When an md\n // type 2-5 block is still open the two grammars CROSS the blank\n // together (`<?a\\n\\n?>` is one block and one bogus comment — batch 3\n // pairs the states, so the aligned crossing must not poison).\n if (cp.p5Tok.kind === 'bogus') {\n if (mdHtml25(cp.mdBlock)) {\n // aligned — both grammars still inside; state survives the blank.\n } else {\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n cp.p5Tok = { kind: 'data' };\n }\n }\n // The THIRD state, and the one this branch did not have (F27). parse5\n // has exactly three non-data token states that can outlive micromark's\n // block across a blank: a raw-text element (poisoned below), a bogus\n // comment (right above), and a COMMENT — which had no alignment check\n // at all. A `<!--` inside an ALREADY-OPEN type-6 block is that block's\n // raw CONTENT to micromark, so no type-2 block ever opens for it; the\n // type-6 block then ends at this blank while parse5's comment runs to\n // end of document, and the candidate sailed through `htmlBalanced`\n // because that check excludes only `bogus`.\n // `<div><p></div></p>` + `<!--` + blank froze 25 of 36 bytes with the\n // whole rest of the document sitting inside a comment nothing closes.\n // The balanced tag pair on the first line is load-bearing in the\n // counterexample: `<div>` alone leaves the bag open and the candidate\n // dies of that instead, which is how the shape hides from minimisation.\n //\n // Poison ONLY — deliberately no `p5Tok` reset, unlike the bogus sibling\n // above. A bogus comment ends at the next `>`, so its state is\n // unrecoverable and resetting is the honest answer there; a real comment\n // runs to `-->`, and resetting would read later comment CONTENT as live\n // markup, which is the under-block direction. Do not tidy the asymmetry.\n if (cp.p5Tok.kind === 'comment' && !mdHtml(cp.mdBlock, 2)) {\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n }\n // Types 6/7 end AT this blank — the member clears before the candidate\n // is judged, exactly when the block ends. (Type 1 survives the blank;\n // 2-5 run to their terminators.)\n if (cp.mdBlock.kind === 'html' && cp.mdBlock.type >= 6) cp.mdBlock = { kind: 'none' };\n cp.blankRun += 1;\n cp.lastBlankStart = ln.start;\n cp.candidates.push({\n offset: Math.min(ln.end + 1, text.length),\n blankRun: cp.blankRun,\n // The html member covers types 1-5 in one check: an unterminated\n // type-1 block swallows this blank and everything after it as RAW\n // content (its tags are invisible to the balance scan — the raw-text\n // mask suppresses them — which is exactly why `openTotal` reads 0\n // and the candidate looked safe), and the 2-5 interiors are the\n // same construct to both grammars.\n htmlBalanced: cp.openTotal === 0 && cp.mdBlock.kind !== 'html' && (cp.p5Tok.kind as P5Tok['kind']) !== 'bogus',\n hazard: cp.hazardVerdict,\n seamRisk: cp.p5SealPending,\n defListSettled: null,\n });\n cp.paragraphHasUnpairedRun = false;\n cp.openBracket = null;\n // A type-1 block is the one html block a BLANK LINE does not end — its\n // only end condition is the literal closer, or end of document. While\n // one is open the run must survive the blank, or the scanner reads the\n // block's raw content as markup: `<script></script >` never closes\n // (CommonMark wants the literal `</script>`; the space makes it text),\n // so the ``` lines after the blank are raw text to micromark and a real\n // FENCE to the scanner — a candidate landed inside the html block\n // (2026-08-20 soak leg 2, third shape).\n if (!mdHtml(cp.mdBlock, 1)) {\n // A RAWTEXT/RCDATA element still open ACROSS this blank has just had\n // its micromark block end under it: a type-6 run ends at the blank,\n // while parse5's raw-text state runs on to the literal end tag. From\n // here every line lives in both grammars at once — micromark opens\n // fresh blocks whose ELEMENT nodes hast-util-raw pushes straight into\n // the tree, while the same bytes are raw TEXT to parse5, so their end\n // tags never close anything. `<iframe>` + blank + `*b*\\n<div>…</div>\n // \\n</iframe>` left the div OPEN swallowing the rest of the document\n // while the scanner, suppressing every tag under the raw-text mask, called\n // it balanced (63-byte live under-block, direction battery,\n // 2026-08-24). Document-wide poison, not from-here-on: the element is\n // sanitize-stripped and its lifted children merge with neighbouring\n // text — the fuzz4 lesson, same day. Type-1 blocks are exempt because\n // a blank does NOT end them: there the two grammars agree the content\n // is raw, which is the case the guard above already keeps alive.\n // (inline-opened spans have their own poison at the opening line.)\n if (inRawTextTok(cp.p5Tok) && !cp.p5Tok.openedInline) {\n cp.phasePoisonedAt = 0;\n }\n }\n cp.prevLineBlank = true;\n cp.prevLineWasText = false;\n cp.prevLineWasValidDef = false;\n // A definition cannot span a blank line — this is where one provably\n // ends, and the next content line pins the seam again.\n cp.defBlockMaybeOpen = false;\n cp.prevLineOpenContent = false;\n cp.tableMaybeOpen = false;\n cp.containerMaybeOpen = false;\n return;\n }\n\n // --- plain text line ---\n // Blocker 3 rolling verdict (raw text; block markers sit at line start\n // where a code span cannot precede them).\n if (isBlockStart) {\n const verdict = classifyBlockStart(ln.text, ln.indent, cp.defListEnabled);\n if (verdict !== null) cp.hazardVerdict = verdict;\n } else if (\n LIST_MARKER_RE.test(ln.text) ||\n FOOTNOTE_DEF_RE.test(ln.text) ||\n (cp.defListEnabled && DEF_LIST_DD_RE.test(ln.text)) ||\n ln.indent >= 4\n ) {\n // A marker line NOT sitting after a blank still begins a block: lists\n // interrupt paragraphs, and anything starts fresh after a just-closed\n // fence/math line. Without this, the verdict stays stale and a\n // candidate right after freezes HALF a loose list (fuzz-arbiter\n // counterexamples: paragraph + glued bullet, `$$` close + glued\n // ordered item). Inside an html flow run the marker is raw text and\n // no hazard exists — turning the verdict on anyway only over-blocks.\n //\n // indent >= 4 mirrors A1 at glued positions (seed-20260841): a\n // 4-indented line directly after a fence close starts an indented CODE\n // block that merges across later blanks — a stale verdict let a\n // candidate split it. A mid-paragraph indented line is only a lazy\n // continuation, so flagging it too is pure over-block (safe).\n cp.hazardVerdict = true;\n }\n\n // Masking is only valid where micromark parses INLINE content. A line\n // starting with a TAG at block indent (approximately) opens an html FLOW\n // block of type 1/6/7 — those run until a blank line with NO inline\n // parsing: backtick runs in it (and in its continuation lines) are\n // literal text, and masking them would hide REAL tags from the balance\n // scan. Sticky until the next blank, like the unpaired-run gate. `<!`/\n // `<?` starters (types 2-5) are NOT sticky — they end at their\n // terminator's line, which rawOpenAtLineStart already tracks; making\n // them sticky suppressed a REAL `$$` open right after `-->` and let a\n // candidate split the math block (fuzz counterexample).\n //\n // Tag names OUTSIDE the type-6 list used to poison the rolling hazard\n // verdict (\"ambiguous starters\") because classifying type 7 needed\n // attribute-quote parsing. Type 7 IS exact now — the line either opens a\n // block (the member) or is a paragraph, both micromark's own answer — so\n // the blanket hazard is retired with the ambiguity (exact-type-7 stage;\n // the one undecidable interrupt class, pipe lines, has its own sticky\n // poison at the refused tag line).\n const tagStart = ln.indent <= 3 ? /^<\\/?([A-Za-z][A-Za-z0-9-]*)/.exec(mdTrimStart(ln.text)) : null;\n if (tagStart) {\n // Gate on the MEMBER, never on \"did the run start here\" — the retired\n // run flag was set by ANY `<tag` line start, an over-approximation:\n // `<embed` (not a type-6 name, not a complete\n // type-7 line) is a PARAGRAPH to micromark, yet it opened the run and\n // so hid the real type-1 block that followed it (2026-08-21 scaled\n // soak, shard 0). What matters is whether a real html block is already\n // open: type 1 may interrupt a paragraph, but a `<script>` nested\n // inside an open type-6 block does not start one. The member answers\n // MORE truly than the run flag it replaced (P4b-completion commit 6)\n // in one place — a type-1 line inside an open type 2-5 block\n // (`<?a\\n<script>`): the flag was false there and a phantom type-1\n // opened inside the construct's content; the member is html{3-5} and\n // correctly refuses. Movements measured and pinned with this commit.\n const noRealBlockOpen = cp.mdBlock.kind !== 'html';\n const t1 = noRealBlockOpen ? TYPE1_START_RE.exec(mdTrimStart(ln.text)) : null;\n // `raw` is the parse5 half of the same line: three of the four type-1\n // names are raw-text elements, `pre` is not.\n if (t1) cp.mdBlock = { kind: 'html', type: 1, raw: RAW_TEXT_ELEMENTS.has(t1[1].toLowerCase()), indent: ln.indent };\n if (cp.mdBlock.kind !== 'html') {\n const t = mdTrimStart(ln.text);\n const t6 = TYPE6_START_RE.exec(t);\n const realT6 = t6 !== null && TYPE6_NAMES.has(t6[1].toLowerCase());\n const t1Line = TYPE1_START_RE.test(t);\n // The interrupt-SENSITIVE class: a line whose only reading as an html\n // block is condition 7. Types 1 and 6 may interrupt a paragraph, so\n // their answer never depends on what came before, and neither\n // undecidable-interrupt poison below applies to them.\n const type7Shaped = !realT6 && !t1Line && isType7Line(t);\n if (\n realT6 ||\n t1Line ||\n // Type 7 cannot interrupt CONTENT (micromark's paragraph/definition\n // construct — `prevLineOpenContent`, the exact interrupt input; the\n // old `prevLineWasText` gate refused after headings, terminator\n // lines and fence closes, where micromark measurably opens). The\n // classifier itself is exact too (isType7Line) — including closing\n // raw-text names (`</style>` alone is type 7, measured) and\n // quoted-`>` attribute values.\n (!cp.prevLineOpenContent && type7Shaped)\n ) {\n // The 6/7 member (type 1 wrote html{1} above; inside this branch\n // the member is provably 'none', the guard is shape only).\n if (cp.mdBlock.kind === 'none') cp.mdBlock = { kind: 'html', type: realT6 ? 6 : 7, indent: ln.indent };\n } else if (cp.prevLineOpenContent && cp.tableMaybeOpen && type7Shaped) {\n // The one interrupt class a line model cannot settle: after a GFM\n // TABLE row type 7 opens (a table is not content), after a\n // pipe-bearing PARAGRAPH line it cannot — and table-ness was\n // decided lines ago by a header/delimiter pair this scanner does\n // not model. The marker is STICKY (`tableMaybeOpen`), because a\n // table is continued by any non-blank non-structural line — the\n // pipe-less row `see prose` after `| 1 | 2 |` is still a row\n // (soak seed 20283008). Whichever way micromark went, the two\n // readings give this line to different grammars, so the phase is\n // poisoned from here — sticky over-block, the same treatment as\n // every other undecidable divergence.\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n }\n // The SECOND undecidable interrupt class, same shape as the pipe one\n // and outside the if/else because it applies to the claim as well as\n // to the refusal. micromark's `tagName` refuses type 7 on\n // `self.interrupt && !self.parser.lazy[line]` — the lazy half is an\n // input the content model does not have. While a container may be\n // open this line is either its LAZY continuation (micromark opens a\n // container-held block) or the line after the container closed\n // (micromark opens a TOP-LEVEL multi-line block); the content model\n // reads the container line as open content and refuses. Both\n // readings give the line to a different grammar than the scanner's,\n // so poison rather than answer — sticky over-block, and the marker\n // disarms at the blank, where the container provably ended and the\n // plain verdict is right again.\n if (type7Shaped && cp.containerMaybeOpen) {\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n }\n }\n }\n // Migration B is COMPLETE: exact type 7 shipped (classifier + interrupt\n // commits), rows 4/6/7 plus the truncated-open and seam-set sites read\n // the member, and `mayBeRawToMicromark` is deleted. The nonType6QuotedGt\n // corpus family keeps standing guard over the once-was-a-hole class.\n // A type 2-5 html block (`<!--` / `<?` / `<!X` / `<![CDATA[`) STARTING on\n // this line at block indent. Not sticky (V9 — the block ends with its\n // terminator's line), and not `inRawText` unless the construct stays\n // open past EOL — but when it opens AND closes on this line, the bytes\n // after the closer are still this html block's raw content: floating\n // remnant with the blocker-6 tail-dependent seam (`<!-- c --> tail`\n // followed by a def line that a later append turns into a paragraph —\n // direction-battery counterexample surfaced by the overlapping-\n // terminator generator family, 2026-08). Feeds the blocker-6 check only.\n const rawFlowStart = ln.indent <= 3 && RAW_CONSTRUCT_START_RE.test(mdTrimStart(ln.text));\n // Whether this line's bytes belong to an html block / raw construct in\n // either grammar — captured HERE (after the tag-start pre-scan classified\n // the line, before the raw-construct machine may close a 2-5 member\n // mid-line) for the content-tracking table at the end of the plain path:\n // html-block lines close micromark's content construct (type 7 opens\n // after a terminator line, measured), and a mid-line INLINE opener does\n // not make the line any less a paragraph.\n const htmlOwnedLine = cp.mdBlock.kind === 'html' || rawOpenAtLineStart || rawFlowStart;\n\n // Same-line code-span masking for HTML/ref/footnote extraction. A null\n // mask means \"unsafe to mask here\" — scan the raw text (over-blocking).\n // Migration B row 4 (exact type 7): masking is valid exactly where\n // micromark parses INLINE content, and that is now the member's answer —\n // an open html block (any type, the pre-scan classified THIS line\n // already), a 2-5 construct open at line start or STARTING here\n // (`rawFlowStart` — the flag never covered those, `<?` fails its regex),\n // or parse5-side raw content. The proxy this replaces also suppressed\n // masking on every line after a `<embed x`-style PARAGRAPH opener until\n // the next blank — lines micromark measurably parses inline, where a\n // backticked tag IS a code span parse5 never sees (the boundary rises\n // there are this stage's payoff, verified by engine probe and pinned).\n const maskingSuppressed = htmlOwnedLine || inRawTextTok(cp.p5Tok);\n const { masked, unpaired } = maskingSuppressed\n ? { masked: null, unpaired: false }\n : maskIntraLineCodeSpans(ln.text, cp.paragraphHasUnpairedRun);\n if (unpaired) cp.paragraphHasUnpairedRun = true;\n const scanText = masked ?? ln.text;\n\n // Blocker 5 (reference taint) — moved to referenceTaint.ts as a pure\n // move (two-model plan P2); the module doc carries the rationale.\n // Migration B row 5 (P4b-completion): the def gate goes EXACT — \"is a\n // def-shaped line raw to micromark\" is answered by the member (an open\n // md html block) plus the parse5-side masks. The narrowing over the old\n // proxy is safe for a reason that must stay written down: the second\n // gate inside collectRefLine is `defLineStart`, and `prevLineWasText`\n // is set at the end of EVERY non-blank line — so on every narrowed\n // shape (a type-7-hole run line, a def line glued under a closed 2-5\n // block) the def is a paragraph-continuation line and stays\n // unregistered. Loosen `defLineStart` and this migration's safety\n // argument goes with it.\n // Deliberately NOT `htmlOwnedLine`: that one adds `rawFlowStart`, which\n // this gate has no use for. A line that STARTS a 2-5 construct begins\n // `<!--` / `<?` / `<!X` / `<![CDATA[` at block indent, and a def line\n // begins `[` (DEF_RE / FOOTNOTE_DEF_RE) — the two are mutually exclusive\n // at line start, so adding the term could not change a single verdict.\n // The asymmetry is intentional, not an oversight (2026-08-26 review).\n const defRawToMicromark = cp.mdBlock.kind === 'html' || rawOpenAtLineStart || inRawTextTok(cp.p5Tok);\n const { validLinkDef } = collectRefLine(cp, ln.start, ln.end, scanText, ln.text, defRawToMicromark, isBlockStart);\n\n // Blocker 1: raw-block (types 3–5) state machine, then tag balance.\n // `rawSpans` records the byte ranges this line contributes to raw\n // constructs (interiors, openers, terminators) — blocker 6's remnant\n // check below must not mistake construct-consumed bytes for floating\n // text (fixture: the `?>` terminator line of a PI block).\n const rawSpans: Array<[number, number]> = [];\n let pos = 0;\n // parse5 divergence (2026-08 project-review P1): CommonMark ends a `<?`\n // block at `?>` and a `<![CDATA[` block at `]]>`, but rehype-raw's HTML\n // tokenizer sees BOTH as bogus comments that end at the FIRST `>`. Every\n // byte between that `>` and the CommonMark terminator is raw text to\n // micromark yet REAL markup to parse5 (a `<details>` there is an open\n // element that reparents later siblings). This line model cannot serve\n // two grammars at once, so the moment a construct's first `>` is not its\n // CommonMark terminator, the phase is poisoned from this line on (sticky\n // over-block — the whole divergent region re-parses inside the tail);\n // the micromark model is kept for the scan itself.\n const poisonRawDivergence = (): void => {\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n };\n /** A `<?` / `<!DECL` / `<![CDATA[` opened PARAGRAPH-INLINE on this line\n * (or at code indent). Set only when the opener is not at a position that\n * could start an html block — the block forms really do run to their\n * terminator, but the inline forms are html-TEXT attempts that any\n * block-interrupting next line retracts to literal text. */\n let inlineRawOpenerIdx = -1;\n while (pos < scanText.length) {\n if (mdHtml(cp.mdBlock, 3) || mdHtml(cp.mdBlock, 5)) {\n // P3b batch 3: micromark's type 3/5 block runs to `?>` / `]]>`;\n // parse5's BOGUS COMMENT (the p5 half of these constructs, tracked\n // on `p5Tok` since this batch) ends at the FIRST `>`. When the two\n // disagree, the window between parse5's `>` and micromark's\n // terminator is construct interior to one grammar and live input to\n // the other — poisoned ONLY if it can hold bytes parse5 acts on\n // (P5_MARKUP_RE), same rule as the `--!>` window. In window mode\n // (p5 already out) the bytes are parse5 TEXT: no rawSpans, so the\n // blocker-6 residue sees the remnant they become.\n const isPi = mdHtml(cp.mdBlock, 3);\n const term = isPi ? '?>' : ']]>';\n const c = scanText.indexOf(term, pos);\n const mdEnd = c === -1 ? scanText.length : c + term.length;\n if (cp.p5Tok.kind === 'bogus') {\n const gt = scanText.indexOf('>', pos);\n if (gt !== -1 && (c === -1 || gt !== c + term.length - 1)) {\n // parse5 closes here; the window to micromark's terminator (or\n // EOL — later window lines are checked at line start).\n cp.p5Tok = { kind: 'data' };\n rawSpans.push([pos, gt + 1]);\n if (P5_MARKUP_RE.test(scanText.slice(gt + 1, c === -1 ? scanText.length : c))) {\n poisonRawDivergence();\n }\n } else {\n rawSpans.push([pos, mdEnd]);\n if (c !== -1) cp.p5Tok = { kind: 'data' };\n }\n }\n // (p5 out already: window-mode bytes stay unmasked on purpose.)\n if (c === -1) break;\n cp.mdBlock = { kind: 'none' };\n pos = mdEnd;\n continue;\n }\n // The two first-`>` machines are de-fused (P4b-completion commit 1):\n // md type 4 is micromark's declaration block, `bogus` is parse5's\n // bogus comment. Their terminators coincide today, but they are\n // different grammars' states and each branch closes only its own.\n if (mdHtml(cp.mdBlock, 4)) {\n const c = scanText.indexOf('>', pos);\n if (c === -1) {\n rawSpans.push([pos, scanText.length]);\n break;\n }\n rawSpans.push([pos, c + 1]);\n cp.mdBlock = { kind: 'none' };\n if (cp.p5Tok.kind === 'bogus') cp.p5Tok = { kind: 'data' };\n pos = c + 1;\n continue;\n }\n if (cp.p5Tok.kind === 'bogus') {\n const c = scanText.indexOf('>', pos);\n if (c === -1) {\n rawSpans.push([pos, scanText.length]);\n break;\n }\n rawSpans.push([pos, c + 1]);\n cp.p5Tok = { kind: 'data' };\n pos = c + 1;\n continue;\n }\n // Openers below are TEXT to BOTH grammars while an outer text-consuming\n // construct is open — micromark: a comment/type-1 block owns every line\n // up to and including its end line; parse5: comment / RAW-TEXT content\n // runs to its own terminator, and where the two disagree about the\n // terminator the divergence poisons have already fired. The old code\n // let them open PHANTOM constructs inside those regions (measured:\n // `<!--\\n<?x` held commentOpen AND piOpen at once — blocking-only\n // artifacts, but artifacts a single MdBlock cannot and should not\n // represent).\n //\n // The type-1 term asks the PARSE5 half (`mdType1RawText`), not \"is a\n // type-1 block open\": `pre` is a type-1 name that parse5 tokenizes in\n // the DATA state, so `<?x` inside `<pre>` really opens a bogus comment\n // that eats the `>` of the `</pre>` line and leaves the element open\n // (F13 — 20 divergent frames on `<pre>\\n<?x\\n</pre>` + tail; before the\n // gate existed the phantom opener's own first-`>` poison covered it by\n // accident, and the gate removed both).\n if (commentOpenAtLineStart || inRawTextTok(cp.p5Tok) || mdType1RawText(cp.mdBlock)) {\n // An INLINE-opened raw-text region is the one masked context whose\n // parse5 state is unknowable from here: micromark called the opener\n // paragraph text, and parse5's tokenizer may have CLOSED the region\n // already (`</iframe a>` — attributes make it literal text to\n // micromark and a real end tag to parse5's RCDATA/RAWTEXT states).\n // The from-here-on poison at the region's opening line covers\n // forward damage, but a RETROACTIVE construct inside the masked\n // bytes (`<!DOCTYPE …>`, document-structure tags, `<template>`)\n // erases and merges BACKWARD past candidates emitted long before the\n // region opened — this scan breaking here is exactly what kept the\n // doctype's own document-wide poison from firing (release-gate\n // finding B, seed 20293004 — F17). Whether parse5 really saw the\n // construct cannot be decided; poison document-wide, the erasure\n // standard.\n //\n // Block-opened regions were exempt here until F20 (2026-08-27), on the\n // stated ground that \"their close is tracked exactly, attribute-bearing\n // end tags included\". That is true of PARSE5's close and false of\n // micromark's, and the mask's third term asks micromark. `</script/>`\n // is a valid end tag to parse5 — the `/` is a bogus self-closing flag —\n // while CommonMark's type-1 end condition wants the LITERAL `</script>`,\n // so the block runs on and `mdType1RawText` keeps masking a region\n // parse5 has already left. `maskUnbacked` below is that desync.\n if (\n inRawTextTok(cp.p5Tok) &&\n cp.p5Tok.openedInline &&\n (tailCarriesRetroactive(ln.text) || /<template(?![a-z0-9-])/i.test(ln.text))\n ) {\n cp.phasePoisonedAt = 0;\n }\n // The block-opened half is F20, guarded at the END of the line instead\n // (`maskUnbacked`): the desync it tests is a property of the line's\n // SETTLED state, and `mdBlock` is not settled here — a legitimate\n // `</script>` line still reads as type-1 open at this point in the scan.\n break;\n }\n const pi = scanText.indexOf('<?', pos);\n const cd = scanText.indexOf('<![CDATA[', pos);\n // `<!` + letter = declaration; `<!--` (third char '-') and\n // `<![CDATA[` (third char '[') never match this.\n const dm = scanText.slice(pos).search(/<![A-Za-z]/);\n const decl = dm === -1 ? -1 : pos + dm;\n // parse5 bogus comment openers — only where the bytes are raw to it (a\n // real html-flow run); in a paragraph `<!` / `</` are literal text that\n // never reaches the tokenizer. `<!` + letter is the declaration above\n // (same \"until `>`\" shape); `<!--` / `<![CDATA[` are their own constructs.\n // Migration A row 2 (P4b-completion): the question is \"are these bytes\n // raw to parse5\", and the exact answer is \"an md html block is open\" —\n // provably equal to the old run-flag read HERE: types 1/2 broke out of\n // the loop above, 3-5 were consumed by their own branches, and the\n // in-comment promotion artifact cannot reach this line (the comment\n // union breaks first). Types 6/7 are the member since commit 2.\n const bm =\n cp.mdBlock.kind === 'html' ? scanText.slice(pos).search(/<!(?!--|[A-Za-z]|\\[CDATA\\[)|<\\/(?![A-Za-z])/) : -1;\n const bogus = bm === -1 ? -1 : pos + bm;\n const starts = [pi, cd, decl, bogus].filter((x) => x !== -1);\n if (starts.length === 0) break;\n const first = Math.min(...starts);\n if (first === bogus) {\n rawSpans.push([bogus, bogus + 2]);\n // Migration collision rule (P3a): a bogus opener while raw text is\n // open is TEXT to parse5 — the old model set a second flag anyway.\n // Poison instead of overwriting the raw-text state (only lowers).\n if (cp.p5Tok.kind === 'data') cp.p5Tok = { kind: 'bogus' };\n else cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n pos = bogus + 2;\n } else if (first === cd) {\n rawSpans.push([cd, cd + 9]);\n // Claim the member only OUTSIDE a 6/7 run — inside one, micromark\n // opens nothing (the run owns every byte to the blank) and the old\n // unconditional write LOST the run's identity: `</t>` opened a\n // type-7 run, `<![CDATA[…]]>` overwrote the member and closed it at\n // `]]>`, and the `$$` after was mistaken for a REAL math open — the\n // phantom closer then broke output-neutrality (soak seed 20282500,\n // fuzz shard 0; latent behind the run flag until its deletion).\n // Same rule as `<!--` since P4b commit 1: the parse5 half lives on\n // the overlay regardless (`<![CDATA[` in fragment html is a bogus\n // comment to the first `>` — rev2 #4, measured).\n if (cp.mdBlock.kind === 'none') cp.mdBlock = { kind: 'html', type: 5, indent: ln.indent };\n if (cp.p5Tok.kind === 'data') cp.p5Tok = { kind: 'bogus' };\n if (!isMdBlank(scanText.slice(0, cd)) || ln.indent > 3) inlineRawOpenerIdx = cd;\n pos = cd + 9;\n } else if (first === pi) {\n if (scanText[pi + 2] === '>') {\n // `<?>` — the opener's `?` doubles as the closer's: micromark html\n // FLOW closes it on the spot (after `<?` it is already \"at `?`,\n // searching for `>`\") and parse5 closes its bogus comment at that\n // same `>`. Both agree → a closed 3-byte span, no state. In html\n // TEXT micromark wants a real `?>` after `<?` (paragraph-inline\n // `<?>` stays open to micromark, closed to parse5) — that\n // divergence is poisoned like the others.\n rawSpans.push([pi, pi + 3]);\n pos = pi + 3;\n if (!isMdBlank(scanText.slice(0, pi)) || ln.indent > 3) poisonRawDivergence();\n continue;\n }\n rawSpans.push([pi, pi + 2]);\n // Member only outside a 6/7 run (see the CDATA branch).\n if (cp.mdBlock.kind === 'none') cp.mdBlock = { kind: 'html', type: 3, indent: ln.indent };\n if (cp.p5Tok.kind === 'data') cp.p5Tok = { kind: 'bogus' };\n if (!isMdBlank(scanText.slice(0, pi)) || ln.indent > 3) inlineRawOpenerIdx = pi;\n pos = pi + 2;\n } else {\n rawSpans.push([decl, decl + 2]);\n // `<!DOCTYPE` is the one declaration parse5 tokenizes as a real\n // DOCTYPE rather than a bogus comment, so it is consumed and erased\n // (retroactive — see DOCUMENT_STRUCTURE_NAMES). `<!ENTITY` and every\n // other `<!` + letter becomes a comment node and is position-stable.\n // Gated on block indent only, not on position within the line: an\n // INLINE `<!DOCTYPE>` in prose measured safe, but proving how far\n // parse5's insertion modes can reach back is not worth the precision,\n // so any doctype on a line that could open an html block poisons.\n // At indent >= 4 the line is indented CODE (or a lazy paragraph\n // continuation, where the doctype is html-text) — parse5 never sees\n // markup there, and poisoning cost a boundary of 62 → 0 on a plain\n // ` <!DOCTYPE html>` block. Backticked mentions are masked out\n // before this scan and never reach here at all.\n if (ln.indent <= 3 && /^doctype/i.test(scanText.slice(decl + 2))) cp.phasePoisonedAt = 0;\n // Member only outside a 6/7 run (see the CDATA branch).\n if (cp.mdBlock.kind === 'none') cp.mdBlock = { kind: 'html', type: 4, indent: ln.indent };\n // md type 4 and the p5 bogus comment share their first-`>` end, so\n // no window can open — the pairing is still tracked for honesty.\n if (cp.p5Tok.kind === 'data') cp.p5Tok = { kind: 'bogus' };\n if (!isMdBlank(scanText.slice(0, decl)) || ln.indent > 3) inlineRawOpenerIdx = decl;\n pos = decl + 2;\n }\n }\n // Blocker 7, completed for the remaining inline raw constructs — and with\n // the DOCUMENT-WIDE poison, not the from-here-on one. Two stacked failure\n // modes, both measured 2026-08-24:\n //\n // 1. micromark's BLOCK scan can interrupt the paragraph at the next line,\n // so the bytes this line model reads as construct interior are a fresh\n // html block to micromark. `x <!D y` + newline + `<!DOCTYPE>`: type 4\n // interrupts, parse5 erases the doctype — while this scanner read it as\n // declaration interior, never ran its poison, and \"closed\" the\n // declaration at the doctype's own `>` (30-byte live under-block).\n // 2. parse5 reads the whole cross-line construct as ONE bogus comment (to\n // the first `>`), i.e. a node the sanitize pass REMOVES — and removing\n // it merges the text nodes on either side. That merge reaches BACKWARD:\n // in `see … linked\\n\\n[^a]: def\\n<i>y</i> <?php …\\n\\n<!DOCTYPE html>…`\n // the merged separator text sits at index 1 of the root, INSIDE a\n // boundary at offset 24, forty bytes before the opener. A poison at the\n // opener's own offset provably does not cover it. Erasure-by-sanitize\n // is the DOCUMENT_STRUCTURE_NAMES semantics, and gets the same poison.\n //\n // (`<!--` has the same erasure shape but its own earlier machinery has kept\n // every measured variant safe — its poison is not widened here, and the\n // corpus carries the shapes that would catch it if that ever stops.)\n //\n // `type >= 3` also matches the 6/7 members, and has since the member\n // overwrite rule tightened (the two-soak-holes fix): a mid-line `<?…?>` or `<!X…>`\n // INSIDE an open type 6/7 run no longer takes the member, so the run's\n // own 6/7 survives to this test and the opener poisons document-wide.\n // That is KEPT deliberately, not an accident of the member surviving —\n // the run case is the same sanitize-erasure shape as the paragraph one,\n // and narrowing the predicate back to 3-5 would raise boundaries for\n // pure freeze-rate gain (2026-08-26 review min-1: measured, and declined\n // on the risk side of that trade).\n if (inlineRawOpenerIdx !== -1 && cp.mdBlock.kind === 'html' && cp.mdBlock.type >= 3) {\n cp.phasePoisonedAt = 0;\n }\n // Raw-construct bytes are data, not markup — mask them (offset-preserving)\n // and scan the REST of the line for tags. The old scan skipped the whole\n // line whenever a raw construct touched it, so a tag before a same-line\n // opener (`<details> <?php`) or after a terminator (`?><details>`) went\n // uncounted — an under-block past a parse5-open element (v2.4.0 review\n // P1/P4; the former was documented as an accepted edge, the latter not).\n let tagText = scanText;\n for (const [from, to] of rawSpans) {\n tagText = tagText.slice(0, from) + ' '.repeat(to - from) + tagText.slice(to);\n }\n // Inside a tag that started on an earlier line of this html-flow run (see\n // `pendingTag`): up to the first RAW `>` the bytes are attribute\n // garbage to parse5 — no tags, no comments, no truncation there.\n let skipTagScan = false;\n if (cp.pendingTag !== null) {\n // De-indent below the truncated line: possibly out of the container\n // (see `pendingTag.indent`) — over-block either way.\n if (ln.indent < cp.pendingTag.indent) poisonRawDivergence();\n // Walk the RAW line with parse5's attribute-area state: a `>` inside a\n // quoted value is a value byte (`<hr title=\"\\n<p></div>` — r2 P1-2: the\n // first `>` used to end the tag and `</div>` closed the outer div), and\n // a value whose quotes pair on this line is ordinary (`<div\\n\n // class=\"a\">` — r2 P2-3: any quote before the `>` used to poison the\n // whole stream, freezing 0.4% of a document instead of 96%).\n const attrs = { state: cp.pendingTag.attr };\n const gt = scanTagAttrs(ln.text, 0, ln.text.length, attrs);\n if (gt === -1) {\n // Line ending: ends an unquoted value, is a byte inside a quoted one.\n scanTagAttrs('\\n', 0, 1, attrs);\n cp.pendingTag = { attr: attrs.state, indent: cp.pendingTag.indent };\n skipTagScan = true;\n } else {\n // The `>` completes the pending truncated CLOSE (parse5 emits the end\n // tag there); a truncated OPEN was already counted at its line.\n for (const tag of cp.pendingTruncatedCloses) applyTag(tag, true);\n cp.pendingTruncatedCloses = [];\n cp.pendingTag = null;\n tagText = ' '.repeat(gt + 1) + tagText.slice(gt + 1);\n }\n }\n // Set when the tag scan itself found a tag that runs past the line end\n // (quoted attribute value left open): the anchor-on-last-`<` truncation\n // check below must not count it a second time.\n let tagHandledAsTruncated = false;\n if (!skipTagScan) {\n TAG_OR_COMMENT_RE.lastIndex = 0;\n let m: RegExpExecArray | null;\n let lastCommentOpenerIdx = -1;\n while ((m = TAG_OR_COMMENT_RE.exec(tagText)) !== null) {\n // Raw-text element content: comment tokens are text too; tags go\n // through applyTag, which admits only the element's own end tag.\n if (inRawTextTok(cp.p5Tok) && (m[0] === '<!--' || m[0] === '-->' || m[0] === '--!>')) {\n // A `<!--` inside `<script>` puts parse5 in \"script data escaped\",\n // which is where the two grammars stop agreeing — see the poison in\n // `applyTag`.\n if (cp.p5Tok.kind === 'script') {\n if (m[0] === '<!--') cp.p5Tok = { ...cp.p5Tok, escaped: true };\n // `-->` leaves the escape ladder ENTIRELY: the single- and\n // double-escaped dash-dash states both switch to \"script data\"\n // on `>` (HTML §13.2.5.24/§13.2.5.30, verified in parse5's\n // tokenizer). `--!>` stays escaped (`!` falls to anything-else\n // in the dash-dash states).\n if (m[0] === '-->') cp.p5Tok = { ...cp.p5Tok, escaped: false, double: false };\n }\n continue;\n }\n if (m[0] === '<!--') {\n const next = tagText.slice(m.index + 4, m.index + 6);\n if (commentEitherOpen(cp.mdBlock, cp.p5Tok)) {\n // Inside an OPEN comment `<!--` is content — but the regex\n // consumed its `--`, which may be the start of the closer:\n // `<!-->` / `<!--->` carry a `-->` (closes for both grammars;\n // soak seed 20260759: `<!--\\n\\n<!-->\\n<details>` left the\n // comment open and skipped the real `<details>`), `<!--!>` /\n // `<!---!>` carry a `--!>` (parse5-only closer → poison).\n if (next.startsWith('>') || next === '->') {\n // Close ONLY the comment member: with the union, an unguarded\n // clear here nukes whatever else holds the member — measured\n // regression: a stray closer while a type-1 block held html{1}\n // released every later candidate (soak leg 2, seed 20280501).\n if (mdHtml(cp.mdBlock, 2)) cp.mdBlock = { kind: 'none' };\n if (cp.p5Tok.kind === 'comment') cp.p5Tok = { kind: 'data' };\n } else if (next === '!>' || next === '-!') {\n // parse5-only closer inside the token: parse5 leaves the\n // comment, micromark does not. P3b batch 2: the divergence\n // WINDOW (from here to micromark's `-->`) is markup to parse5\n // and comment content to micromark — poison only if markup\n // bytes can appear in it on this line; later window lines are\n // checked at line start. A markup-free window is text to both\n // grammars and converges at `-->`.\n if (cp.p5Tok.kind === 'comment') cp.p5Tok = { kind: 'data' };\n if (mdHtml(cp.mdBlock, 2) && P5_MARKUP_RE.test(tagText.slice(m.index + m[0].length))) {\n poisonRawDivergence();\n }\n }\n continue;\n }\n if (next.startsWith('>') || next === '->') {\n // Empty comment with an overlapping closer (see the note above\n // TAG_OR_COMMENT_RE) — closed on the spot; the regex resumes after `<!--`,\n // where the leftover `>` / `->` matches nothing.\n continue;\n }\n // Inside an open type 6/7 block a `<!--` line is that block's\n // CONTENT — the member keeps the run's identity; parse5's comment\n // half lives on `p5Tok` (commit 1), and every comment read below\n // goes through the union.\n if (cp.mdBlock.kind === 'none') cp.mdBlock = { kind: 'html', type: 2, indent: ln.indent };\n if (cp.p5Tok.kind === 'data') cp.p5Tok = { kind: 'comment' };\n lastCommentOpenerIdx = m.index;\n continue;\n }\n if (m[0] === '-->') {\n // A STRAY `-->` (no comment open) is text to both grammars: the\n // old per-field `commentOpen = false` was a no-op there, and the\n // union must keep it one — an unguarded member clear released a\n // type-1 block's html{1} (soak leg 2, seed 20280501, `</script/>`\n // false closer upstream; regression pinned).\n if (mdHtml(cp.mdBlock, 2)) cp.mdBlock = { kind: 'none' };\n if (cp.p5Tok.kind === 'comment') cp.p5Tok = { kind: 'data' };\n continue;\n }\n if (m[0] === '--!>') {\n // parse5 accepts `--!>` as a comment closer; CommonMark does not\n // (`<!--x--!>\\n<details>\\n-->` is one html block to micromark\n // whose `<details>` is a REAL open element to parse5). P3b\n // batch 2 retires the unconditional poison: parse5's comment\n // CLOSES here, micromark's block runs on to `-->`, and the\n // window between them diverges only if it holds bytes parse5\n // would act on — `P5_MARKUP_RE` on the line remainder here, and\n // per line at the line-start check while the relation stays\n // split (md html{2} open, p5 out of comment). A markup-free\n // window is parse5 TEXT inside micromark's block: the grammars\n // converge at `-->` and the block's output is a text remnant the\n // blocker-6 seam machinery owns (floatingResidue runs on the\n // INTERSECTION of the two comment states for exactly this).\n // A p5-ONLY comment closing here (inside a type 6/7 run) never\n // diverged from micromark at all — no poison either.\n if (mdHtml(cp.mdBlock, 2) && P5_MARKUP_RE.test(tagText.slice(m.index + m[0].length))) {\n poisonRawDivergence();\n }\n if (cp.p5Tok.kind === 'comment') cp.p5Tok = { kind: 'data' };\n continue;\n }\n if (commentEitherOpen(cp.mdBlock, cp.p5Tok)) continue;\n const closing = m[1] === '/';\n const tag = m[2].toLowerCase();\n if (strayTablePart(tag)) cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start + m.index);\n let attrs = m[3] ?? '';\n // Migration A row 3: \"may this tag continue across the line ending\"\n // is a raw-stream question — an open md html block answers it. The\n // broadening over the old flag is types 3-5 interiors, and THAT is\n // safe only because a paragraph-inline 3-5 opener already poisons\n // document-wide (the F9 rule) — named dependency, do not remove one\n // without the other.\n if (cp.mdBlock.kind === 'html' && (!inRawTextTok(cp.p5Tok) || (closing && tag === rawTextElement(cp.p5Tok)))) {\n // The regex ends the tag at the first `>`, but in a real html-flow\n // run parse5 ends it at the first `>` OUTSIDE a quoted attribute\n // value (`</div a=\">` eats the rest of the line and beyond — a\n // pre-existing under-block of the r2 P1-2 family, oracle review of\n // the batch). Walk the attribute area with parse5's state machine:\n // a later `>` moves the match end; no `>` on the line means the\n // tag continues on the next line — the truncated path below takes\n // it, with the quote state carried.\n const attrStart = m.index + 1 + (closing ? 1 : 0) + m[2].length;\n const st = { state: 'outside' as TagAttrState };\n const gt = scanTagAttrs(tagText, attrStart, tagText.length, st);\n if (gt === -1) {\n if (!VOID_TAGS.has(tag)) {\n if (closing) cp.pendingTruncatedCloses.push(tag);\n else applyTag(tag, false);\n }\n scanTagAttrs('\\n', 0, 1, st);\n cp.pendingTag = { attr: st.state, indent: ln.indent };\n tagHandledAsTruncated = true;\n break;\n }\n if (gt + 1 !== m.index + m[0].length) {\n attrs = tagText.slice(attrStart, gt);\n TAG_OR_COMMENT_RE.lastIndex = gt + 1;\n }\n }\n // Paragraph context (micromark html-text / a non-real run): a CLOSING\n // tag is only `</name` + optional whitespace + `>` — `</div a=\"b\">` is\n // literal text and parse5 never sees a close (oracle review of the r2\n // batch, pre-existing: `p <div> x </div a=\"b\"> y` froze past the open\n // div). In a real html-flow run parse5 accepts end-tag attributes.\n if (closing && cp.mdBlock.kind !== 'html' && !/^\\s*$/.test(attrs)) {\n // The match ran to the first `>`, swallowing whatever sat in the\n // \"attributes\". micromark does not: it backtracks the invalid\n // closing tag to literal text and re-scans from inside it, so\n // `</t <div a=\"\">` is text `</t ` plus a REAL html-text `<div a=\"\">`\n // that parse5 opens. Skipping the whole span left that div\n // uncounted — an under-block the direction battery caught once the\n // corpus reached the shape (2026-08-20 soak leg 2, minimised to\n // `</t <div a=\"\">\\n\\r```\\n```\\n\\n`, unstable under every future).\n // Rewinding past the NAME re-scans the swallowed bytes; the\n // documented `p <div> x </div a=\"b\"> y` case is unaffected, its\n // attribute area holds no tag.\n TAG_OR_COMMENT_RE.lastIndex = m.index + 2 + m[2].length;\n continue;\n }\n const selfClosing = /\\/\\s*$/.test(attrs);\n if (VOID_TAGS.has(tag) || (selfClosing && honoursSelfClosing(tag))) continue;\n applyTag(tag, closing);\n }\n // A comment opener that is NOT the line's first token and fails to\n // close by end of line is PARAGRAPH-INLINE: micromark only recognizes\n // it as a comment if `-->` arrives before the paragraph ends, else the\n // `<!--` is literal text and everything this scan skipped as \"comment\n // interior\" until the next stray `-->` is REAL markup (seed-20260828\n // under-block: a real unclosed `<details>` went uncounted and the\n // boundary landed past it, where its raw-time element absorbs every\n // later sibling). Which way it resolves is paragraph-shape-dependent —\n // poison the candidates from the opener on (sticky, over-block), same\n // mechanism as the suppressed fence/math opens. Line-START openers are\n // html block type 2 (terminator semantics, tracked exactly) and raw/\n // flow-context openers follow parse5's comment state — neither poisons.\n // No `!inRawText` gate here, and the poison is document-wide — two\n // upgrades over the original, both bought by counterexamples:\n //\n // - `inRawText` reads `mayBeRawToMicromark`, which ANY `<letter` line\n // start sets. `<b>x</b> <!-- trailing…` is a PARAGRAPH (`b` is not a\n // type-6 name), yet the `<b` start suppressed this poison entirely\n // and the document froze at 173 of 200 (2026-08-24 scaled soak,\n // direction battery). The line-start check below is the exact\n // question the proxy was approximating.\n // - a cross-line comment is a sanitize-REMOVED node, and removing it\n // merges the text on either side — the merge reaches backward past\n // the boundary, so an opener-offset poison has the same hole F9 had\n // for `<?`/`<!`+letter. Same rule, same document-wide poison.\n if (commentEitherOpen(cp.mdBlock, cp.p5Tok) && lastCommentOpenerIdx !== -1) {\n if (!isMdBlank(tagText.slice(0, lastCommentOpenerIdx)) || ln.indent > 3) {\n cp.phasePoisonedAt = 0;\n }\n }\n // Tags whose `<` sits OUTSIDE every code-span mask but whose `>` sits\n // INSIDE one (`<div x=\"\\`\">b\\``): micromark tries html-text at the `<`\n // before the later backtick can open a span, so the tag is REAL — but\n // the masked scan above never saw its `>` and counted nothing (v2.4.0\n // review, direction battery). Re-scan the raw line for exactly those\n // matches (raw-construct spans excluded — a `<b>` inside a PI is data).\n if (masked !== null && masked !== ln.text) {\n const inRaw = (i: number) => rawSpans.some(([from, to]) => i >= from && i < to);\n TAG_OR_COMMENT_RE.lastIndex = 0;\n let mr: RegExpExecArray | null;\n while ((mr = TAG_OR_COMMENT_RE.exec(ln.text)) !== null) {\n if (mr[0] === '<!--' || mr[0] === '-->' || mr[0] === '--!>') continue;\n const startMasked = masked[mr.index] !== ln.text[mr.index];\n const wholeVisible = masked.slice(mr.index, mr.index + mr[0].length) === mr[0];\n if (startMasked || wholeVisible || inRaw(mr.index) || commentEitherOpen(cp.mdBlock, cp.p5Tok)) continue;\n const closing = mr[1] === '/';\n const tag = mr[2].toLowerCase();\n if (strayTablePart(tag)) cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start + mr.index);\n // Same html-text rule: a closing tag with attributes is text.\n if (closing && mr[3] !== undefined && !/^\\s*$/.test(mr[3])) continue;\n const selfClosing = mr[3] !== undefined && /\\/\\s*$/.test(mr[3]);\n if (VOID_TAGS.has(tag) || (selfClosing && honoursSelfClosing(tag))) continue;\n applyTag(tag, closing);\n }\n }\n // A `>` anywhere on this line confirms every pending truncated open\n // (attributes may wrap; the tag really is a tag — keep it counted).\n // Checked on the RAW line: a `>` inside a masked code span may still be\n // the tag's own closer (`<div x=\"\\`\">b\\``: micromark parses the tag\n // first, the span never forms) — v2.4.0 review R2(a).\n if (cp.pendingTruncatedTags.length > 0 && ln.text.includes('>')) {\n // A confirmed pending table-part open (`<td` + attributes wrapping)\n // is a real stray table part: poison from here (see TABLE_PART_NAMES).\n if (cp.pendingTruncatedTags.some((t) => strayTablePart(t))) {\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n }\n cp.pendingTruncatedTags = [];\n }\n // Line-truncated tag start — anchor on the LAST `<` of the line.\n if (!commentEitherOpen(cp.mdBlock, cp.p5Tok) && !tagHandledAsTruncated) {\n let lastLt = -1;\n TAG_START_LT_RE.lastIndex = 0;\n for (let ms = TAG_START_LT_RE.exec(tagText); ms !== null; ms = TAG_START_LT_RE.exec(tagText)) {\n lastLt = ms.index;\n TAG_START_LT_RE.lastIndex = ms.index + 1;\n }\n if (lastLt !== -1 && !tagText.includes('>', lastLt)) {\n const m2 = TRUNCATED_TAG_RE.exec(tagText.slice(lastLt));\n if (m2) {\n const closing = m2[1] === '/';\n const tag = m2[2].toLowerCase();\n // Table-part poison for a TRUNCATED shape only where it is markup\n // for sure (a real html-flow run); in paragraph context `compare\n // a<td b` may be prose — poison waits for the `>` that confirms the\n // pending open (r2 P3), otherwise the blank line reverts it.\n if (strayTablePart(tag) && cp.mdBlock.kind === 'html') {\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start + lastLt);\n }\n // In a REAL html-flow run parse5 stays inside this tag across the\n // line ending — open, close or void alike (`<br` + `</div>` on the\n // next line: the `</div>` is garbage). See `pendingTag`.\n if (cp.mdBlock.kind === 'html') {\n // Where parse5 stands after this line's attribute bytes + the\n // line ending (m2[3] holds them; no `>` in there by construction).\n const attrs = { state: 'outside' as TagAttrState };\n scanTagAttrs(m2[3] + '\\n', 0, m2[3].length + 1, attrs);\n cp.pendingTag = { attr: attrs.state, indent: ln.indent };\n }\n if (closing) {\n // Never counted on the spot (2026-08-19 review P1: `para </style`\n // zeroed the balance while `<style>` was still open in BOTH\n // grammars — the fuzz corpus had truncated opens only). In an\n // html-flow run the `>` may still arrive on a later line of the\n // run — pend it; in paragraph context a block-indent `>` is a\n // blockquote (the 4+-space continuation shape is not modelled:\n // over-block), so it is treated as prose: nothing.\n if (!VOID_TAGS.has(tag) && cp.mdBlock.kind === 'html') cp.pendingTruncatedCloses.push(tag);\n } else if (!VOID_TAGS.has(tag)) {\n applyTag(tag, closing);\n // Only a PARAGRAPH-line truncation can turn out to be prose. In an\n // html-flow run the bytes are raw: parse5 keeps tokenizing the\n // dangling `<div` into whatever follows the block (fuzz\n // counterexample: `</details>\\n<div\\n\\n` shortened the seam\n // separator), so there the open stays counted, unrevertable.\n // Likewise when the RAW line has a `>` after its last `<`: the\n // masked-away `>` may be the tag's real closer — keep it counted\n // rather than reverting a real tag (R2(a)).\n const rawLastLt = ln.text.lastIndexOf('<');\n const rawTruncated = rawLastLt !== -1 && !ln.text.includes('>', rawLastLt);\n // Migration B, truncated-open revertibility (exact type 7):\n // \"paragraph-line truncation\" is the member's complement. The\n // retired proxy kept `<embed x`-style PARAGRAPH truncations\n // counted forever; they are prose candidates like any other\n // paragraph truncation and revert at the blank.\n if (!closing && !(htmlOwnedLine || inRawTextTok(cp.p5Tok)) && rawTruncated) {\n cp.pendingTruncatedTags.push(tag);\n }\n }\n }\n }\n }\n }\n\n // Blocker-6 detection: this line is html-flow content, tag balance is\n // fully settled after it, and — after masking construct-consumed bytes\n // (raw spans, comment content) and stripping tag/comment tokens —\n // non-whitespace remains: balanced FLOATING remnant that parse5 will\n // attach at the root with a tail-dependent seam. `inRawText` scopes this\n // to html-flow runs; interior remnant (openTotal > 0) is contained inside\n // an element and stays position-stable, so it does not set the flag.\n // Deliberately NOT gated on raw constructs being closed at line END: a\n // settle line can carry remnant AND open a multi-line comment/PI/decl/\n // CDATA (`remnant <!-- c`), and the terminator line's scan only covers\n // its own bytes — requiring closure here would hide that remnant forever\n // (the under-block direction; review counterexample with an arbiter-level\n // hast mismatch). Unterminated construct bytes are masked (rawSpans /\n // comment-token strip); their interior text may over-flag, which is safe.\n // Pending truncated opens are PHANTOMS until confirmed: for the seam\n // question they must not count as \"an element is open\" (an open element\n // contains the remnant; a phantom does not) — otherwise a rawFlowStart\n // line ending in a truncated `<div` skips this check and, when the\n // phantom is reverted at the blank line, nobody re-runs it (v2.4.0\n // review R2(b)). Treating them as closed here only over-flags.\n const effectiveOpen = cp.openTotal - cp.pendingTruncatedTags.length;\n // Migration B row 7, the SET half (exact type 7): floating raw remnant\n // arises from RAW bytes — html-block content in either grammar\n // (`htmlOwnedLine` covers the member, line-start 2-5 state and\n // `rawFlowStart`; the p5 raw-text kinds ride along for completeness).\n // A `<embed x`-style paragraph line's text becomes a position-stable\n // paragraph node, never seam-owned remnant — the retired proxy set the\n // flag there anyway.\n if ((htmlOwnedLine || inRawTextTok(cp.p5Tok)) && effectiveOpen <= 0) {\n // Raw-construct bytes are DELETED (not blanked) here: the residue is\n // judged on `length`, not `trim()` — whitespace-only floating text\n // (`<!-- c --> </s>` leaves ` `) is seam-dependent too (v2.4.0 review\n // P2), and blanking spans would fake such whitespace.\n let masked = '';\n let cursor = 0;\n for (const [from, to] of rawSpans) {\n masked += scanText.slice(cursor, from);\n cursor = to;\n }\n masked += scanText.slice(cursor);\n // Comment content spanning lines is not covered by rawSpans (comments\n // are tracked by the token scan, not the raw state machine), so the\n // residue is taken by the SAME token walk the balance scan uses — the\n // comment-open state carried in from the line start, overlapping\n // closers (`<!-->` closing an open comment) and all. Regex masking\n // (`<!--…-->`, `<!--…$`) got the overlap case wrong: it erased the\n // `<!-->` before the \"cut at `-->`\" step could see it, hiding the real\n // remnant after it (adversarial review of 5074c4b, blocker-6 seam).\n // Comment state for the residue = the INTERSECTION of the two\n // grammars' comment states (P3b batch 2 / oracle rev2 #5): bytes are\n // construct interior only if BOTH grammars are inside a comment. In\n // the `--!>` window (md open, p5 closed) the bytes are parse5 TEXT —\n // real remnant with a tail-dependent seam; a p5-only comment inside a\n // type 6/7 run over-flags, which is the safe direction.\n if (floatingResidue(masked, bothCommentsOpenAtLineStart).length > 0 || discardedEndTag) {\n cp.p5SealPending = true;\n }\n }\n\n // The span reaches past this line ending. micromark and parse5 disagree\n // about where it ENDS — `</title a>` is literal paragraph text to\n // micromark (a closing tag takes no attributes) while parse5's RCDATA\n // tokenizer accepts it and closes the element — so from here the scanner\n // cannot model the span at all: it suppressed a `<div>` the real parse\n // leaves OPEN, which then grows with every append (2026-08-21 soak leg 2,\n // boundary 144 with the div at @86 extending to @161). Poison rather than\n // reject one candidate: the divergence outlives the span.\n if (inRawTextTok(cp.p5Tok) && cp.p5Tok.openedInline) {\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n }\n\n // CommonMark type-1 end condition: the line CONTAINS the closer string,\n // and that line still belongs to the block — so this runs last, after the\n // line has been scanned as raw flow. The next line starts fresh.\n if (mdHtml(cp.mdBlock, 1) && TYPE1_CLOSE_RE.test(ln.text)) {\n cp.mdBlock = { kind: 'none' };\n // The type-1 block ends here for micromark — if parse5's raw-text\n // element SURVIVES this close (the double-escape held it open), the\n // element will swallow later md blocks and their wrap separators as\n // its own text, and sanitize stripping it then merges the survivors\n // BACKWARD past any earlier boundary (the F9/F11 erasure class — the\n // 20282605/10/11 direction-battery counterexamples: `<script>\\n\n // <!--<script>\\n</script>\\n<div>d</div>\\n</script>` froze at 56 and\n // a one-character append changed the frozen region's children).\n // Document-wide poison, the erasure standard; a tangle that resolves\n // on ONE line never reaches this branch with the element open, so\n // the single-line recovery (and the `-->` exact exit) survive.\n if (inRawTextTok(cp.p5Tok)) cp.phasePoisonedAt = 0;\n }\n\n cp.blankRun = 0;\n cp.prevLineBlank = false;\n cp.prevLineWasText = true;\n // ── content tracking: the decision table for `prevLineOpenContent` ──\n // Derives micromark's \"content construct open\" per line class, measured\n // 2026-08-25 (see the field doc). The DIRECTION stakes: claiming \"open\"\n // where micromark closed under-claims the html{7} member (the class the\n // run flag used to blanket — masking/bogus-tracking then miss real raw\n // bytes, blocked only by a DECAYING hazard verdict); claiming \"closed\"\n // where micromark kept content open over-claims the member and can\n // shadow a REAL type-1 open behind a phantom type-7 run. Neither side is\n // conservative, which is why the table is exact per class and the one\n // undecidable class (pipe lines) is poisoned at the consuming gate.\n {\n const tt = mdTrimStart(ln.text);\n let openContent: boolean;\n if (htmlOwnedLine) {\n // html-block content in either grammar — closes/never opens content.\n openContent = false;\n } else if (ln.indent >= 4) {\n // A ≥4-indent line is a LAZY CONTINUATION when content is open\n // (stays open) and INDENTED CODE when it is not (stays closed).\n openContent = cp.prevLineOpenContent;\n } else if (ATX_HEADING_RE.test(tt) || THEMATIC_BREAK_RE.test(tt)) {\n openContent = false;\n } else if (BARE_MARKER_RE.test(tt)) {\n // An EMPTY list item cannot interrupt a paragraph (CommonMark §5.2),\n // so while content is open micromark reads the marker line as a LAZY\n // CONTINUATION and content stays open — a blanket `false` here\n // OVER-claimed. It agreed for a lone `-` by accident: that is also a\n // valid setext underline, which closes content under both readings,\n // and the accident is now written down rather than relied on. At a\n // block start `prevLineOpenContent` is false anyway, which is what\n // the single-line battery rows pin.\n openContent = tt[0] === '-' ? false : cp.prevLineOpenContent;\n } else if (SETEXT_LEFTOVER_RE.test(tt)) {\n // `=+` / `--`: a setext underline when a paragraph is open (content\n // CONSUMED into a heading), a paragraph of its own when not — EXCEPT\n // inside a table, where the same bytes are just another ROW and the\n // table (with the content it holds) runs on. Flipping to false there\n // disarmed `tableMaybeOpen`, the next content line lost the marker,\n // and a later refused tag line went unpoisoned (2026-08-26 review\n // M3(a): a `<br/>` line after a `--` row froze 89 of 93 bytes while\n // micromark held a real html block inside the frozen region).\n openContent = cp.tableMaybeOpen && cp.prevLineOpenContent ? true : !cp.prevLineOpenContent;\n } else {\n // Paragraph, definition, footnote definition, list item content,\n // blockquote line — all leave content open for interrupt purposes\n // (each measured as type-7-REFUSING).\n openContent = true;\n }\n cp.prevLineOpenContent = openContent;\n // Table tracking (see the field doc): a pipe line arms it; any\n // content-class line carries it; every block-structure line (the\n // openContent=false classes) breaks the table and disarms it.\n // The arming half asks whether this line could be a table ROW at all —\n // a `|` inside an html comment or any other html-owned line is not a\n // cell separator, and arming from one poisoned documents holding no\n // table (2026-08-26 review min-2). Over-claiming the marker only\n // widens the poison, so the narrowing is the precision half: it RAISES\n // boundaries, attributed per sample in the commit that landed it.\n cp.tableMaybeOpen = (!htmlOwnedLine && ln.text.includes('|')) || (cp.tableMaybeOpen && openContent);\n // Container tracking, the same sticky shape: a container-marker line\n // arms it, any content-class line carries it (a lazy continuation and\n // an indented item line are both content), every block-structure line\n // breaks the container and disarms it. Both halves take `openContent`,\n // because the marker shapes overlap the structure ones — `- - -` is a\n // thematic break, not a list item, and the table above is what says so.\n const containerMarker =\n CONTAINER_MARKER_RE.test(ln.text) ||\n FOOTNOTE_DEF_RE.test(ln.text) ||\n (cp.defListEnabled && DEF_LIST_DD_RE.test(ln.text));\n cp.containerMaybeOpen = openContent && (containerMarker || cp.containerMaybeOpen);\n }\n // Def CHAINS (A2) are a link-definition affordance: one def line can be\n // followed directly by another. A FOOTNOTE def does NOT chain — its\n // unindented next line lazily continues the footnote BODY, so a\n // def-shaped line glued under it is literal body text and registering it\n // would be a ghost def (fuzz counterexample). Refs on that line stay\n // extracted (footnote bodies parse inline content).\n cp.prevLineWasValidDef = validLinkDef;\n // Sticky to the next blank: from a def-shaped line on, every line may be\n // that definition's destination or (wrapped) title, none of which emits a\n // node the blocker-6 seam can hang on. Carrying it across ordinary\n // paragraph lines too only delays the release to the blank — over-block.\n cp.defBlockMaybeOpen = cp.defBlockMaybeOpen || DEF_RE.test(ln.text) || FOOTNOTE_DEF_RE.test(ln.text);\n // Footnote-def resumability (F16): armed by the def line itself; a\n // non-blank BLOCK-START line at indent ≤ 3 definitively interrupts the\n // footnote block (no body line can resume past it), everything else —\n // lazy continuations (not block starts), ≥4-indent continuations, and the\n // blanks that never reach this function's non-blank tail — carries it.\n if (FOOTNOTE_DEF_RE.test(ln.text)) cp.fnDefResumable = true;\n else if (isBlockStart && ln.indent <= 3) cp.fnDefResumable = false;\n // F19, the barrier's second consequence (see SCOPE_BARRIER_NAMES): a barrier\n // left open at the end of a line whose content is HELD by a markdown\n // construct will swallow that construct's generated end tag. The scanner\n // cannot enumerate generated elements — it never sees them — so it answers\n // the only question that decides the case: is anything generated open around\n // this barrier? No, in exactly one position: an html BLOCK, whose raw text\n // becomes a root-level node with no wrapper. Every other position (a\n // container marker line, a heading line, a paragraph's inline html) has at\n // least one generated element around it, and which one is unknowable here.\n // \"Top-level\" takes the reading `pendingFenceCloser` already gives it: only\n // a column-0 opener is provably top-level, since an html block opened at\n // indent 1-3 may be a list item's own content (`- a` then ` <table>`, the\n // one family cell the block-vs-inline test alone left UNDER).\n //\n // Direction: writes the poison only, so both ways of being wrong LOWER the\n // boundary — an over-claimed barrier on the bag widens it, and so does\n // calling a top-level host non-top-level. `ln.start`, not 0: the re-nesting\n // reaches forward only (measured — every node before the host is unchanged).\n //\n // The accepted cost is the shapes where the barrier closes on a LATER line\n // inside the same host and never straddles anything (`> <table>\\n> </table>`,\n // and the paragraph-inline `<table>` that parse5 foster-parents out of its\n // own way). Sparing those needs a per-host \"did this construct end here\"\n // model — a second grammar, for the shapes this one is already blind to.\n //\n // PENDING TRUNCATED opens are subtracted, the `effectiveOpen` argument: a\n // line-truncated `compare a<td b` leaves parse5's tokenizer INSIDE the tag,\n // so no element is open yet and no generated end tag can be discarded. This\n // is the one reading here that fires the poison LESS, and it is sound\n // because it only DEFERS: if a later line brings the `>`, the pending list\n // is cleared with the name still on `openStack`, and the check fires on that\n // line — still ahead of the blank where the paragraph's `</p>` is emitted.\n const isBarrier = (name: string): boolean => SCOPE_BARRIER_NAMES.has(name);\n const topLevelHtmlBlock = cp.mdBlock.kind === 'html' && cp.mdBlock.indent === 0;\n const confirmedBarriers = cp.openStack.filter(isBarrier).length - cp.pendingTruncatedTags.filter(isBarrier).length;\n if (!topLevelHtmlBlock && confirmedBarriers > 0) {\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n }\n // F20 — the raw-text mask outliving the grammar that justifies it.\n //\n // The tag scan is suppressed while `mdType1RawText(cp.mdBlock)` holds, and\n // that member's contract is \"the state in which BOTH grammars agree every\n // byte up to the closer is content\". `</script/>` breaks the agreement: the\n // `/` is a bogus self-closing flag parse5 ignores, so the element closes for\n // parse5, while CommonMark's type-1 end condition wants the LITERAL\n // `</script>` and the block runs on. From there the mask hides tags parse5\n // really acts on — `<script>` + `</script/>` + `<pre>` + `</3` + `</pre>`\n // froze 39 of 41 bytes while the bogus comment ate the `>` of the `</pre>`\n // line and left the `pre` open swallowing the tail (100% of engaged frames\n // diverged on three of six configs; pre-existing through the 22.23.2 corpus regen). F17 fixed\n // the inline-opened case and exempted this one because \"their close is\n // tracked exactly\" — true of parse5's close, false of micromark's.\n //\n // Settled state only, which is why this sits at the end of the line and not\n // in the scan loop: mid-scan a legitimate `</script>` line still reads as\n // type-1 open, and testing there poisoned F13's own fixture.\n //\n // Forward damage (the tags the scan is not counting) takes the from-here\n // poison; backward damage takes the document-wide one on the same erasure\n // standard as the inline branch — a doctype inside the masked bytes merges\n // text across candidates emitted long before the region opened.\n const maskUnbacked = mdType1RawText(cp.mdBlock) && !inRawTextTok(cp.p5Tok);\n if (maskUnbacked) {\n cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);\n if (tailCarriesRetroactive(ln.text) || /<template(?![a-z0-9-])/i.test(ln.text)) {\n cp.phasePoisonedAt = 0;\n }\n }\n}\n\n/**\n * TEST-ONLY view of the name lists this scanner classifies tags by.\n *\n * Not part of the module's behaviour and not re-exported by any barrel; it\n * exists so a test can DERIVE its corpus from the scanner's own taxonomy\n * instead of transcribing it. The census alphabet was hand-written for two\n * years, and F13 is exactly one cell of the table below — `pre`, the single\n * member of `TYPE1_NAMES \\ RAW_TEXT_ELEMENTS`. A transcribed list cannot\n * grow that cell back when an upstream `htmlBlockNames` bump moves a name;\n * a derived one does, on the next test run.\n *\n * Adding a list here widens every derived corpus automatically, which is\n * the point — so add one whenever the scanner starts keying a decision on a\n * new set of names.\n */\nexport const SCANNER_NAME_LISTS: ReadonlyArray<readonly [string, ReadonlySet<string>]> = [\n ['type1', TYPE1_NAMES],\n ['rawText', RAW_TEXT_ELEMENTS],\n ['type6', TYPE6_NAMES],\n ['void', VOID_TAGS],\n ['documentStructure', DOCUMENT_STRUCTURE_NAMES],\n ['tablePart', TABLE_PART_NAMES],\n ['scopeBarrier', SCOPE_BARRIER_NAMES],\n ['foreignRoot', new Set(FOREIGN_ROOT_NAMES)],\n];\n","/**\n * Markdown line-text primitives shared by the freeze scanner and the\n * reference-taint module (extracted in two-model plan P2 — a pure move).\n *\n * Markdown whitespace is U+0020 / U+0009 (plus line endings) — NOT the\n * Unicode set JS `trim()` strips. A line holding only U+3000 / U+00A0 is\n * paragraph text (a lazy continuation line) for micromark, and a fence\n * closer followed by NBSP is not a closer. Using `trim()` here made the\n * scanner emit a candidate inside an unfinished paragraph (v2.4.1 review\n * P1 — CJK output does carry full-width-space-only lines).\n */\n\nexport const MD_BLANK_RE = /^[ \\t\\r]*$/;\nexport const isMdBlank = (text: string): boolean => MD_BLANK_RE.test(text);\n/** ASCII-only counterparts of `trim()` / `trimStart()` — every scanner verdict\n * must strip exactly what micromark strips (adversarial review\n * of the first fix: a def rest ending in NBSP registered a ghost def; a\n * U+3000 before a paragraph-inline `<!--` skipped the divergence poison). */\nexport const mdTrim = (text: string): string => text.replace(/^[ \\t\\r]+|[ \\t\\r]+$/g, '');\nexport const mdTrimStart = (text: string): string => text.replace(/^[ \\t\\r]+/, '');\n","/**\n * Blocker 5 — reference taint (the (R) leg of the safety condition),\n * extracted from `computeFreezeBoundary` as a PURE MOVE (two-model plan\n * P2). micromark decides reference-ness at parse time, so a later\n * `[label]:` definition retargets earlier literal `[text]`; every\n * reference-style candidate before a boundary must resolve against a\n * SETTLED definition (one followed by a confirmed blank line). This module\n * owns the definition/reference grammar and the per-line collection over\n * the checkpoint's ref sub-state; the scanner calls `collectRefLine` once\n * per confirmed line and `settleRefsAndEarliestUnresolved` once per scan.\n *\n * Nothing here may change behaviour relative to the pre-move scanner: the\n * P2 acceptance is a strict zero delta on the pinned boundary corpus plus\n * a clean four-leg soak, and a non-zero result means revert, not explain.\n */\n\nimport { normalizeIdentifier } from 'micromark-util-normalize-identifier';\n\nimport { isMdBlank, mdTrim } from './mdLineText';\n\nexport interface UnresolvedRef {\n offset: number;\n label: string;\n footnote: boolean;\n}\n\nexport const FOOTNOTE_DEF_RE = /^ {0,3}\\[\\^[^\\]]*\\]:/;\n/** Any link/footnote reference definition at block indent. */\nexport const DEF_RE = /^ {0,3}\\[((?:[^[\\]\\\\]|\\\\.)+)\\]:/;\n/** Bracketed inline candidate: link/image reference or shortcut. No nesting\n * support — plain prose brackets count as taint (conservative direction). */\nconst REF_RE = /!?\\[((?:[^[\\]\\\\]|\\\\.)*)\\]/g;\n\n/** Index of the first unescaped `ch` in `text`, or -1. */\nfunction firstUnescaped(text: string, ch: string): number {\n for (let i = 0; i < text.length; i++) {\n if (text[i] === '\\\\') i += 1;\n else if (text[i] === ch) return i;\n }\n return -1;\n}\n\n/** Index of the last unescaped `[` that has no unescaped `]` after it, or -1. */\nfunction lastUnclosedBracket(text: string): number {\n let open = -1;\n for (let i = 0; i < text.length; i++) {\n const c = text[i];\n if (c === '\\\\') i += 1;\n else if (c === '[') open = i;\n else if (c === ']') open = -1;\n }\n return open;\n}\n\nfunction normalizeLabel(label: string): string {\n const collapsed = label.replace(/[ \\t\\r\\n]+/g, ' ').replace(/^ | $/g, '');\n return collapsed ? normalizeIdentifier(collapsed) : '';\n}\n\n/**\n * Rest-of-line check for a link definition after `[label]:`: a non-empty\n * destination (angle-bracketed or a bare non-whitespace run), then nothing\n * or a title that CLOSES on this line with nothing after it. Everything\n * else — no destination, non-title garbage, garbage after a closed title\n * (`\"t\"a`), or a title left OPEN at EOL (its continuation line may append\n * garbage that invalidates the whole def: `\"t\\nt2\"a`, K=4 census) — is\n * rejected: the line is (or may become) a paragraph whose `[label]` stays\n * a live ref. Rejecting a real def only over-blocks (refs stay tainted);\n * registering a ghost under-blocks. Multi-line titles therefore never\n * register — the documented A2 conservative edge.\n */\nfunction isPlausibleLinkDefRest(rest: string): boolean {\n const t = mdTrim(rest);\n if (t === '') return false; // destination-less\n const destEnd = linkDestinationEnd(t);\n if (destEnd === -1) return false; // micromark rejects the destination → paragraph\n const after = mdTrim(t.slice(destEnd));\n if (after === '') return true;\n const opener = after[0];\n if (opener !== '\"' && opener !== \"'\" && opener !== '(') return false;\n const closer = opener === '(' ? ')' : opener;\n // Find the UNESCAPED closing delimiter; the def is valid only when it\n // exists on this line and nothing but whitespace follows it.\n for (let i = 1; i < after.length; i++) {\n if (after[i] === '\\\\') {\n i += 1;\n continue;\n }\n if (after[i] === closer) return isMdBlank(after.slice(i + 1));\n }\n return false; // title still open at EOL\n}\n\n/**\n * micromark's link-destination grammar (micromark-factory-destination),\n * applied to a trimmed def rest. Returns the index just past the\n * destination, or -1 when micromark would REJECT it — the def line is then\n * a paragraph whose `[label]` stays a live shortcut ref. Two forms:\n * - `<…>`: any characters except line endings and UNESCAPED `<` / `>`\n * (whitespace is legal); unclosed at EOL → reject. `<>` is valid.\n * - bare: a non-empty run without whitespace or ASCII control characters;\n * unescaped parentheses must balance, and a `)` at balance zero ENDS\n * the destination (whatever follows must then be a title or nothing).\n * The old check accepted any `<…>` with a `>` somewhere and any bare run —\n * `[a]: <u<v>` / `[a]: /u(x` registered GHOST defs that released reference\n * taint early (2026-08 project-review P1; ghost defs are the unsafe\n * direction — see the def-registration comment in processConfirmedLine).\n */\nfunction linkDestinationEnd(t: string): number {\n if (t.startsWith('<')) {\n for (let i = 1; i < t.length; i++) {\n const ch = t[i];\n // `enclosedEscape`: a backslash only escapes `<`, `>`, `\\`; before\n // anything else it is a literal backslash and the next character is\n // judged on its own.\n if (ch === '\\\\' && (t[i + 1] === '<' || t[i + 1] === '>' || t[i + 1] === '\\\\')) {\n i += 1;\n continue;\n }\n if (ch === '>') return i + 1;\n if (ch === '<') return -1;\n }\n return -1; // unclosed angle destination\n }\n let balance = 0;\n let i = 0;\n for (; i < t.length; i++) {\n const code = t.charCodeAt(i);\n if (code === 0x20 || code === 0x09) break; // whitespace ends the run\n if (code < 0x20 || code === 0x7f) return -1; // ASCII control\n const ch = t[i];\n // `rawEscape`: only `(`, `)`, `\\` are escapable; `\\ ` is a literal\n // backslash followed by whitespace, which ENDS the run (review probe:\n // skipping any next char swallowed the space and registered a ghost).\n if (ch === '\\\\' && (t[i + 1] === '(' || t[i + 1] === ')' || t[i + 1] === '\\\\')) {\n i += 1;\n continue;\n }\n if (ch === '(') balance += 1;\n else if (ch === ')') {\n if (balance === 0) break; // ends the destination\n balance -= 1;\n }\n }\n if (balance !== 0 || i === 0) return -1;\n return i;\n}\n\n/**\n * micromark's inline-link resource grammar (`(` destination? title? `)`)\n * on ONE line, starting at the `(` at `openIdx`. Returns the index just past\n * the closing `)`, or -1 when the resource is malformed here — the bracket\n * text before it is then a live shortcut reference.\n */\nfunction inlineResourceEnd(text: string, openIdx: number): number {\n let i = openIdx + 1;\n const skipWs = () => {\n while (i < text.length && (text[i] === ' ' || text[i] === '\\t')) i += 1;\n };\n skipWs();\n if (text[i] === ')') return i + 1; // `()` — empty resource is valid\n const destEnd = linkDestinationEnd(text.slice(i));\n if (destEnd === -1) return -1;\n i += destEnd;\n const beforeWs = i;\n skipWs();\n if (text[i] === ')') return i + 1;\n if (i === beforeWs) return -1; // title must be whitespace-separated\n const opener = text[i];\n if (opener !== '\"' && opener !== \"'\" && opener !== '(') return -1;\n const closer = opener === '(' ? ')' : opener;\n for (i += 1; i < text.length; i++) {\n if (text[i] === '\\\\') {\n i += 1;\n continue;\n }\n if (text[i] === closer) {\n i += 1;\n skipWs();\n return text[i] === ')' ? i + 1 : -1;\n }\n }\n return -1; // title still open at EOL\n}\n\n/** The checkpoint's reference sub-state, as this module sees it — the\n * fields stay flat on `FreezeScanCheckpointInternal` (a pure move does\n * not reshape state); this view is the module's contract with them. */\nexport interface RefTaintView {\n defs: Map<string, number>;\n footnoteDefs: Map<string, number>;\n unresolvedRefs: UnresolvedRef[];\n openBracket: { offset: number; text: string } | null;\n referenceTaint: boolean;\n prevLineWasText: boolean;\n prevLineWasValidDef: boolean;\n lastBlankStart: number;\n}\n\nexport interface RefLineFacts {\n /** This line registered (or chained) a definition. */\n validDef: boolean;\n /** …and it was a LINK def (`prevLineWasValidDef` tracks only those). */\n validLinkDef: boolean;\n}\n\n// Blocker 5: definitions (block-start or def-chain only — A2) and refs.\n// Inside an html flow run a def-shaped line is RAW TEXT — micromark never\n// registers it. Registering a ghost def is the UNSAFE direction twice\n// over: it releases reference taint early AND makes the footnote replay\n// inject a definition the real parse does not have (fuzz-arbiter\n// counterexample). Refs stay extracted regardless: extra candidates only\n// over-taint.\nexport function collectRefLine(\n cp: RefTaintView,\n lnStart: number,\n lnEnd: number,\n scanText: string,\n rawText: string,\n inRawText: boolean,\n isBlockStart: boolean\n): RefLineFacts {\n // The definition decision reads the RAW line, never `scanText`. A link\n // reference definition is a BLOCK construct: micromark decides it before\n // any inline parsing, so a code span does not exist yet and its backticks\n // are ordinary characters. `scanText` has intra-line code spans blanked\n // out — correct for the inline extractions below, and an input error\n // here, because blanking DELETES the very content that invalidates a\n // definition. `[x]: /u ` + a code span is a PARAGRAPH whose `[x]` is a\n // live shortcut reference; masked, it read as a valid definition, so the\n // scanner registered a ghost def, never tainted the reference, and froze\n // a paragraph that a later `[x]: …` retargets into a linkReference —\n // 18 of 18 bytes, shipped-output divergence on three configs (gate290\n // census leg, fragment band K=4, probe collideDef:x).\n //\n // Index arithmetic stays sound across the two strings because masking is\n // LENGTH-PRESERVING (spans become runs of spaces), so `defBracket` below\n // is a valid offset into `scanText` even though `def` was matched here.\n // Keep that property if you touch `maskIntraLineCodeSpans`.\n const defShaped = inRawText ? null : DEF_RE.exec(rawText);\n // micromark requires a NON-EMPTY destination followed by nothing but an\n // optional TITLE for a link definition. A bare `[label]:` line, or one\n // with non-title garbage after the destination (`[x]: /u[x]: /u` — K=4\n // census counterexamples), is a PARAGRAPH whose `[label]` stays a live\n // shortcut ref that a LATER real def can retarget. Rejecting a real def\n // here only over-blocks (refs stay tainted); registering a ghost\n // under-blocks. Footnote defs legitimately have empty bodies.\n const def =\n defShaped !== null &&\n (defShaped[1].startsWith('^') || isPlausibleLinkDefRest(rawText.slice(defShaped.index + defShaped[0].length)))\n ? defShaped\n : null;\n const defLineStart = isBlockStart || !cp.prevLineWasText || cp.prevLineWasValidDef;\n const validDef = def !== null && defLineStart;\n if (validDef) {\n const label = def![1];\n if (label.startsWith('^')) {\n const key = normalizeLabel(label.slice(1));\n if (key && !cp.footnoteDefs.has(key)) cp.footnoteDefs.set(key, lnEnd);\n } else {\n const key = normalizeLabel(label);\n if (key && !cp.defs.has(key)) cp.defs.set(key, lnEnd);\n }\n }\n // Blocker 5 collection is skipped entirely under referenceTaint=false\n // (the def-label scanner profile): definition IDENTITY is a block-level\n // fact independent of how inline references resolve, and taint would\n // collapse the boundary to the body's first citation while a def footer\n // streams (defs settle only after a trailing blank line).\n if (cp.referenceTaint) {\n const pushRef = (offset: number, inner: string, followAt: number): void => {\n const follow = scanText[followAt];\n // `[text](…)` is an inline link only when the resource is WELL-FORMED\n // on this line; `[foo](bad url)` fails micromark's resource grammar\n // and `[foo]` falls back to a shortcut reference a later def can\n // retarget (adversarial review). A resource that continues on the\n // next line is unverifiable here → taint (over-block).\n if (follow === '(' && inlineResourceEnd(scanText, followAt) !== -1) return;\n let label: string;\n let footnote = false;\n if (inner.startsWith('^')) {\n footnote = true;\n label = normalizeLabel(inner.slice(1));\n } else if (follow === '[') {\n const explicit = /^\\[((?:[^[\\]\\\\]|\\\\.)*)\\]/.exec(scanText.slice(followAt));\n label = normalizeLabel(explicit && explicit[1] ? explicit[1] : inner);\n } else {\n // Shortcut reference candidate. Plain prose brackets (\"[sic]\") land\n // here too — a future definition COULD retarget them, so they count.\n label = normalizeLabel(inner);\n }\n if (label) cp.unresolvedRefs.push({ offset, label, footnote });\n };\n // A bracket left open on an earlier line of this paragraph: it closes\n // here (label = the joined text — micromark's label grammar allows soft\n // line breaks, and normalizeLabel folds them), stays open when this line\n // has no bracket at all, or dies when a NEW `[` comes first (a label\n // cannot contain an unescaped `[`; that `[` may itself pend below).\n const pending = cp.openBracket;\n cp.openBracket = null;\n if (pending) {\n const close = firstUnescaped(scanText, ']');\n const open = firstUnescaped(scanText, '[');\n // A continuation line inside a blockquote carries its `>` marker in\n // the source but not in micromark's label — strip it, or the joined\n // label (`foo > bar`) could never match its def and the taint would\n // never lift (adversarial review). Wrong-way stripping only over-taints.\n const cont = (t: string): string => t.replace(/^ {0,3}>[ \\t]?/, '');\n if (close !== -1 && (open === -1 || close < open)) {\n pushRef(pending.offset, `${pending.text}\\n${cont(scanText.slice(0, close))}`, close + 1);\n } else if (close === -1 && open === -1) {\n cp.openBracket = { offset: pending.offset, text: `${pending.text}\\n${cont(scanText)}` };\n }\n }\n if (scanText.includes('[')) {\n // `[label]:` is only definition-shaped when THIS line registers it as\n // a def (the label bracket of validDef). On a paragraph CONTINUATION\n // line the same bytes are literal text where micromark still parses\n // `[label]` as a shortcut reference — skipping it there under-taints\n // and lets a later definition retarget frozen output (fuzz\n // counterexample: a def line glued under a paragraph). Extra\n // candidates only over-taint.\n const defBracket = validDef ? def!.index + def![0].indexOf('[') : -1;\n REF_RE.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = REF_RE.exec(scanText)) !== null) {\n const followAt = m.index + m[0].length;\n if (scanText[followAt] === ':' && m.index === defBracket) continue; // the def's own label\n pushRef(lnStart + m.index, m[1], followAt);\n }\n // The LAST unescaped `[` with no `]` after it stays open into the next\n // paragraph line (a def line's own label never reaches here unclosed).\n const trailingOpen = lastUnclosedBracket(scanText);\n if (trailingOpen !== -1) {\n cp.openBracket = { offset: lnStart + trailingOpen, text: scanText.slice(trailingOpen + 1) };\n }\n }\n }\n return { validDef, validLinkDef: validDef && !def![1].startsWith('^') };\n}\n\n/** Settle references (monotone: entries only ever leave — a def counts\n * once a confirmed blank line follows it), then report the earliest still\n * unresolved ref offset (`Infinity` when none). */\nexport function settleRefsAndEarliestUnresolved(cp: RefTaintView): number {\n if (cp.unresolvedRefs.length > 0) {\n const settled = (defEnd: number): boolean => cp.lastBlankStart >= defEnd;\n cp.unresolvedRefs = cp.unresolvedRefs.filter((ref) => {\n const table = ref.footnote ? cp.footnoteDefs : cp.defs;\n const defEnd = table.get(ref.label);\n return defEnd === undefined || !settled(defEnd);\n });\n }\n let earliestUnresolved = Infinity;\n for (const ref of cp.unresolvedRefs) earliestUnresolved = Math.min(earliestUnresolved, ref.offset);\n return earliestUnresolved;\n}\n","/**\n * Pure splice helpers for incremental (prefix-freeze) parsing: cut the\n * frozen prefix out of the previous frame's trees, re-base a tail-only\n * parse into document coordinates, and join the two into fresh roots.\n *\n * Invariant these helpers exist to uphold (enforced by the\n * splice-equivalence arbiter test, NOT asserted at runtime): the spliced\n * `{mdast, hast}` is deep-equal — positions included — to a full pipeline\n * run over the whole content. Defined on UNRENDERED trees; after a render,\n * `renderHastSubtree` mutates hast in place (convergent `data.originalUrls`\n * stash, raw→text rewrite — see Markdown.tsx), so no in-component\n * deep-equal check is possible or attempted.\n *\n * Prefix link/image definitions are PREPENDED to the tail source (not\n * appended: a streaming tail routinely ends inside an unclosed fence or\n * `$$` block that would swallow appended lines, and appended defs would\n * invert CommonMark first-def-wins against a same-label tail def).\n * Definitions emit zero hast (mdast-util-to-hast has no `definition`\n * handler), so their only trace is `definition` mdast nodes inside the\n * injected region, which are dropped before the join. Definition text is\n * sliced verbatim from the previous content via node positions — exact\n * source roundtrip preserves escapes and multi-line titles.\n *\n * Sanitize-STRIPPED prefix nodes (HTML comments, `<?…?>` bogus comments,\n * `<script>`) are modeled explicitly: their wrap separators survive as\n * orphans, and `alignPrefixCut` re-derives the mdast↔hast pairing from\n * separator-run lengths (B0-probe-verified: one orphan '\\n' per stripped\n * child's gap slot; separators MERGED into raw trailing literals count via\n * their trailing newlines — `literalCredit`). Layouts outside the model\n * return null → full-parse fallback for the frame.\n */\n\nimport { normalizeIdentifier } from 'micromark-util-normalize-identifier';\nimport type { Root as HastRoot, RootContent as HastContent } from 'hast';\nimport type { Root as MdastRoot, RootContent as MdastContent } from 'mdast';\nimport type { Node as UnistNode, Position } from 'unist';\n\nimport { attributeHastChildren } from './attributeHastChildren';\n\n/** One injected footnote-definition block's coordinate mapping — footer\n * `<li>` content carries positions from the DEF node, so injected-copy\n * coordinates must be rewritten back to the original's (C0 probe). */\nexport interface InjectedSegment {\n injStart: number;\n injEnd: number;\n offsetDelta: number;\n lineDelta: number;\n}\n\n/** Prefix footnote/definition events in DOCUMENT ORDER. Order is the whole\n * point: mdast-util-to-hast's footnoteOrder/footnoteCounts are built from\n * encounter order, and the replay must reproduce it exactly. */\nexport type InjectionEvent =\n /** Link/image definition — parse-time resolution only, zero hast. */\n | { kind: 'def'; source: string }\n /** Footnote definition — sliced from the PHYSICAL LINE START (column\n * invariance for the footer position rebase). */\n | { kind: 'footnoteDef'; source: string; origStart: number; origLine: number }\n /** Consecutive footnote references, verbatim source tokens. Seeds\n * footnoteOrder (first-encounter) and footnoteCounts (backref -N ids). */\n | { kind: 'refs'; tokens: string[] };\n\nexport interface PrefixInjectionPlan {\n events: InjectionEvent[];\n /** True when an event exists that CANNOT be injected reliably — the caller\n * must fall back to a full parse for this frame (safe, one-frame cost). */\n uninjectable: boolean;\n /** False when the plan must NOT be cached for resume: a position-less\n * top-level child cannot be partitioned by the resume offset, so a\n * resumed walk would re-visit it and duplicate its events (round-2\n * review). Fresh walks stay correct — they just can't be incremental. */\n cacheable?: boolean;\n}\n\n/** A plan cached in engine state: valid for any LATER boundary of the same\n * append lineage, because events derive from (content, positions) alone\n * and the boundary is monotone under appends — new frames only APPEND\n * events for children in [cached.boundary, newBoundary). */\nexport interface CachedInjectionPlan extends PrefixInjectionPlan {\n boundary: number;\n}\n\n/** Collect the prefix's injectable events (document order).\n *\n * Walks the FULL subtree, not just top-level children: definitions nested\n * inside blockquotes/lists are document-scoped in CommonMark\n * (probe-confirmed A3 — a `> [a]: /url` def must resolve a later tail\n * ref). A nested link definition's position starts at its own `[`, so a\n * single-line slice is a valid standalone def line; a MULTI-LINE nested\n * slice would drag `> ` container prefixes into the injection text, so it\n * is flagged uninjectable instead (full-parse fallback).\n *\n * Footnote definitions must be sliced from their physical line start (the\n * footer position rebase requires column invariance), so ANY nested\n * footnote def is uninjectable — the line-start slice would drag the `> `\n * container prefix in, and a node-start slice would shift columns.\n *\n * footnoteDefinition subtrees are NOT descended: refs inside a def body are\n * counted at FOOTER time (state.all over the stored def node), and the\n * injected def text replays them there; emitting them as inline events\n * would double-count.\n */\nexport function collectPrefixInjection(\n mdast: MdastRoot,\n content: string,\n boundary: number,\n resume?: CachedInjectionPlan | null\n): PrefixInjectionPlan {\n // Resume path (final-review R3): the frozen prefix is byte-identical\n // frame to frame, so a cached plan only needs the children in\n // [resume.boundary, boundary) appended — without this the deep visit\n // re-walks the ENTIRE prefix every splice frame (the collectDefLabels\n // O(stream²) shape). Boundary validity gates EVERYTHING resumed —\n // including the sticky-uninjectable short-circuit: the boundary is\n // monotone within an append lineage today, but a regressed cache must\n // degrade to a fresh walk, never to a stale verdict (round-2 review).\n const resumeValid = resume != null && resume.boundary <= boundary;\n // `uninjectable` is sticky: the offending node stays in the prefix for\n // the lineage's lifetime.\n if (resumeValid && resume!.uninjectable) return { events: resume!.events, uninjectable: true };\n const resumeAt = resumeValid ? resume!.boundary : 0;\n const events: InjectionEvent[] = resumeAt > 0 ? cloneEventsForAppend(resume!.events) : [];\n let uninjectable = false;\n let cacheable = true;\n const pushRef = (token: string): void => {\n const last = events[events.length - 1];\n if (last && last.kind === 'refs') last.tokens.push(token);\n else events.push({ kind: 'refs', tokens: [token] });\n };\n const visit = (node: UnistNode, nested: boolean): void => {\n const type = (node as { type?: string }).type;\n if (type === 'definition') {\n const start = node.position?.start?.offset;\n const end = node.position?.end?.offset;\n if (start !== undefined && end !== undefined && start < boundary) {\n const slice = content.slice(start, end);\n if (nested && slice.includes('\\n')) uninjectable = true;\n else events.push({ kind: 'def', source: slice });\n }\n return;\n }\n if (type === 'footnoteDefinition') {\n const start = node.position?.start;\n const end = node.position?.end?.offset;\n if (start?.offset === undefined || end === undefined || start.offset >= boundary) return;\n if (nested) {\n uninjectable = true;\n return;\n }\n const lineStart = start.offset - (start.column - 1);\n events.push({\n kind: 'footnoteDef',\n source: content.slice(lineStart, end),\n origStart: lineStart,\n origLine: start.line,\n });\n return; // body refs replay at footer time via the injected text\n }\n if (type === 'footnoteReference') {\n const start = node.position?.start?.offset;\n const end = node.position?.end?.offset;\n if (start === undefined || end === undefined) {\n uninjectable = true; // cannot reproduce the token verbatim\n return;\n }\n pushRef(content.slice(start, end));\n return;\n }\n const children = (node as TreeWithChildren).children;\n if (children) {\n for (const child of children) visit(child, true);\n }\n };\n // Top-level children are position-ordered with the shipped chain, and the\n // event stream assumes it. A plugin-shaped tree that reorders top-level\n // nodes must not produce a WRONG plan: an early break at the boundary\n // would silently skip a def that sits after a later-positioned sibling,\n // so the walk uses filter semantics (every child is inspected, only those\n // in [resumeAt, boundary) are visited) and flags any disorder as\n // uninjectable (full-parse fallback) — the cut layer's correct-or-bailing\n // promise for the same threat model (2026-08 project review, eng-parse-07).\n let lastStart = -1;\n for (const child of mdast.children) {\n // Nothing at or past the boundary can contribute a prefix event (E5),\n // and nothing before the resume point needs re-visiting.\n const start = child.position?.start?.offset;\n if (start !== undefined) {\n if (start < lastStart) return { events: [], uninjectable: true, cacheable: false };\n lastStart = start;\n }\n if (start === undefined) {\n // A position-less top-level child cannot be partitioned by offset: a\n // resumed walk would re-visit it and DUPLICATE its cached events.\n // Restart fresh once (correct by construction) and mark the plan\n // uncacheable. Unreachable with the shipped chain (the parser\n // positions every top-level node); defense for plugin-shaped trees.\n if (resumeAt > 0) return collectPrefixInjection(mdast, content, boundary, null);\n cacheable = false;\n visit(child, false);\n continue;\n }\n if (start >= boundary || start < resumeAt) continue;\n visit(child, false);\n }\n return { events, uninjectable, cacheable };\n}\n\n/** Cached plans are shared with the previous state — clone the array, and\n * the trailing refs event too (pushRef mutates its token list when the new\n * region opens with another reference). */\nfunction cloneEventsForAppend(events: InjectionEvent[]): InjectionEvent[] {\n const out = events.slice();\n const last = out[out.length - 1];\n if (last && last.kind === 'refs') out[out.length - 1] = { kind: 'refs', tokens: last.tokens.slice() };\n return out;\n}\n\nexport interface InjectionPrefix {\n text: string;\n segments: InjectedSegment[];\n}\n\n/** The injection TERMINATOR: a sentinel link-definition block appended after\n * the last event. The detector's blockers prove the REAL prefix is inert\n * toward the tail — but the injection text itself introduces continuation\n * context the real prefix did not have (final-review R1, probe-confirmed):\n *\n * - a trailing footnote-def event's body continues across blank lines into\n * any >=4-indented tail line, swallowing real content into a node the\n * splice then strips;\n * - with the definition-list extension, a tail-leading `: desc` separated\n * from the ORIGINAL prefix by two blank lines (claim-immune) sits only\n * ONE '\\n\\n' from the last injected block and would claim it as a <dt>.\n *\n * A column-0 link definition neutralizes both: it terminates a footnote\n * body (not >=4-indented), cannot be claimed as a <dt> (not a paragraph),\n * emits zero hast and zero wrap-separator slots, and is stripped with the\n * rest of the injected region.\n *\n * Unlike the phantom sentinel URLs (values — they can never change parse\n * SHAPE), a definition LABEL is resolvable by any `[label]` mention, so a\n * document that literally writes the sentinel label would have its tail\n * mentions resolve against the terminator (round-2 review, probe-\n * confirmed). {@link tailMentionsTerminator} closes that structurally:\n * such frames take the full path instead of splicing. */\nconst TERMINATOR_LABEL = '__aimd_injection_terminator__';\nconst INJECTION_TERMINATOR = `[${TERMINATOR_LABEL}]: __aimd_sentinel_link__`;\n\n/** True when the tail input could REFERENCE the terminator's label — the\n * one input class where the splice's synthetic definition would change how\n * the tail parses. Prefix mentions need no check: an unresolved mention is\n * reference-tainted (pinned into the tail), and a resolved one has a real\n * def that wins first-def-wins over the terminator. */\nexport function tailMentionsTerminator(tailSource: string): boolean {\n // micromark matches labels after `normalizeIdentifier` (whitespace\n // collapse + Unicode case fold), so `[__AIMD_INJECTION_TERMINATOR__]` — or\n // a dotless-ı variant — resolves against the lowercase terminator def just\n // the same. Compare in the same normal form (2026-08 project review,\n // eng-parse-04: a byte-exact `includes` let case variants through).\n // Whitespace right after `[` is trimmed by micromark's label matching\n // too (`[ __aimd_…]` resolves) — collapse it before the check (v2.4.0\n // review P5).\n return normalizeIdentifier(tailSource)\n .replace(/\\[ /g, '[')\n .includes(`[${normalizeIdentifier(TERMINATOR_LABEL)}`);\n}\n\n/** Build the injection text prepended to the tail source (with per-footnote-\n * def coordinate segments). Blocks are '\\n\\n'-joined: a def line directly\n * after a ref paragraph would be a paragraph CONTINUATION (A2, literal\n * text), and anything unindented after a footnote def line would join its\n * body. */\nexport function buildInjectionPrefix(events: InjectionEvent[]): InjectionPrefix {\n if (events.length === 0) return { text: '', segments: [] };\n let text = '';\n // Rolling line number of the text end — recounting the accumulated text\n // per event would be O(events × textLength) (final-review R3).\n let line = 1;\n const segments: InjectedSegment[] = [];\n for (const event of events) {\n if (text.length > 0) {\n text += '\\n\\n';\n line += 2;\n }\n const injStart = text.length;\n const source = event.kind === 'refs' ? event.tokens.join(' ') : event.source;\n if (event.kind === 'footnoteDef') {\n segments.push({\n injStart,\n injEnd: injStart + source.length,\n offsetDelta: event.origStart - injStart,\n lineDelta: event.origLine - line,\n });\n }\n text += source;\n line += countNewlines(source);\n }\n return { text: `${text}\\n\\n${INJECTION_TERMINATOR}\\n\\n`, segments };\n}\n\ninterface TreeWithChildren extends UnistNode {\n children?: UnistNode[];\n}\n\n/**\n * Shift every position in the subtree from tail-parse coordinates into\n * document coordinates. Tolerates position-less subtrees (KaTeX output).\n * Mutates in place — callers only pass freshly-parsed tail trees.\n */\nexport function rebaseTree(node: UnistNode, offsetDelta: number, lineDelta: number): void {\n // Exactly rebaseTreeDual with no segments (find never matches) — one\n // implementation, two names for the two call sites' semantics.\n rebaseTreeDual(node, EMPTY_SEGMENTS, offsetDelta, lineDelta);\n}\n\nconst EMPTY_SEGMENTS: InjectedSegment[] = [];\n\n/**\n * Dual-rule position rebase for the tail HAST (C0-probe-verified): the\n * footer's `<li>` content carries positions from footnoteById's DEF nodes —\n * for INJECTED defs those are injection coordinates (per-segment mapping),\n * while tail-native nodes (inline content and tail-defined footnotes) take\n * the ordinary tail shift. Dispatch is per POINT with CLOSED segment bounds:\n * END offsets are exclusive, so a node ending exactly at a segment's last\n * byte has offset === injEnd (segments are '\\n\\n'-separated — unambiguous).\n * Column is invariant under both rules (defs are sliced from line start).\n */\nexport function rebaseTreeDual(\n node: UnistNode,\n segments: InjectedSegment[],\n offsetDelta: number,\n lineDelta: number\n): void {\n // Segments live entirely inside the injection prefix; after the injected\n // region is stripped, ~every remaining point sits past them all. One\n // bound check replaces an always-failing O(segments) scan per point\n // (final-review R3).\n const maxEnd = segments.length > 0 ? segments[segments.length - 1].injEnd : -1;\n rebaseDualWalk(node, segments, maxEnd, offsetDelta, lineDelta);\n}\n\nfunction rebaseDualWalk(\n node: UnistNode,\n segments: InjectedSegment[],\n maxEnd: number,\n offsetDelta: number,\n lineDelta: number\n): void {\n const position = node.position as Position | undefined;\n if (position) {\n for (const point of [position.start, position.end]) {\n // Plugin-shaped trees (a consumer's own remark/rehype plugin emitting\n // `{ position: {} }` or a half-built point) reached this walk and threw\n // `Cannot read properties of undefined (reading 'offset')` out of the\n // render path — every other splice defence against such trees bails;\n // this one tolerates, like its \"position-less subtrees\" contract says.\n if (!point) continue;\n const seg =\n point.offset !== undefined && point.offset <= maxEnd\n ? segments.find((s) => point.offset! >= s.injStart && point.offset! <= s.injEnd)\n : undefined;\n if (seg) {\n point.offset! += seg.offsetDelta;\n if (typeof point.line === 'number') point.line += seg.lineDelta;\n } else {\n if (point.offset !== undefined) point.offset += offsetDelta;\n if (typeof point.line === 'number') point.line += lineDelta;\n }\n }\n }\n const children = (node as TreeWithChildren).children;\n if (children) {\n for (const child of children) rebaseDualWalk(child, segments, maxEnd, offsetDelta, lineDelta);\n }\n}\n\nexport interface SpliceInput {\n prevMdast: MdastRoot;\n prevHast: HastRoot;\n /** Tail trees, freshly parsed from `injectionPrefix + content.slice(boundary)`. */\n tailMdast: MdastRoot;\n tailHast: HastRoot;\n content: string;\n boundary: number;\n injectionPrefix: string;\n /** Coordinate mappings for injected footnote-def blocks (footer rebase). */\n injectedSegments: InjectedSegment[];\n}\n\n/**\n * Cut the frozen prefix from the previous trees, drop injected-def nodes\n * from the tail, re-base the tail, synthesize the root-level `'\\n'` seam\n * separator (mdast-util-to-hast's `wrap()` inserts one strictly BETWEEN\n * root children — the full parse has it at the prefix/tail junction, the\n * tail-only parse does not), and join into fresh root objects. Fresh roots\n * every frame keep blockMemo's node-identity assumptions intact while\n * never mutating the previous frame's roots.\n */\n/** Table-part START tags whose appearance outside a table re-routes parse5's\n * tree construction for the rest of the document. */\nconst TABLE_PART_TAG_RE = /<(?:td|th|tr|tbody|thead|tfoot|caption|col|colgroup)\\b/i;\n/** Same scan, but positioned: `<table>` / `</table>` and every table part in\n * one raw-HTML value, in order. */\nconst TABLE_TOKEN_RE = /<(\\/?)(table|td|th|tr|tbody|thead|tfoot|caption|col|colgroup)\\b/gi;\n\n/**\n * Does any table part in `values` sit OUTSIDE a table? Only those re-route\n * parse5; a well-formed `<table><tr><td>a</td></tr></table>` does not, and\n * bailing on it cost every later frame a full parse (2026-08-20 B1 — the\n * scanner's TABLE_PART_NAMES poison had the same gap; keep the two in step).\n *\n * Depth runs across the whole sequence because `hast-util-raw` feeds every\n * raw value to ONE parse5 instance: a `<table>` opened in one html node is\n * still open in the next. Unbalanced `</table>` clamps at zero rather than\n * going negative, so a stray close cannot mask a later stray part.\n */\nfunction hasStrayTablePart(values: Iterable<string>): boolean {\n let depth = 0;\n for (const value of values) {\n TABLE_TOKEN_RE.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = TABLE_TOKEN_RE.exec(value)) !== null) {\n const closing = m[1] === '/';\n const tag = m[2].toLowerCase();\n if (tag === 'table') {\n depth = closing ? Math.max(0, depth - 1) : depth + 1;\n continue;\n }\n if (depth === 0) return true;\n }\n }\n return false;\n}\n/** `startTagInTemplate` routes these names to \"in head\" WITHOUT first popping\n * the template insertion mode — unlike every other start tag, which pops,\n * pushes \"in body\" and REPROCESSES. So when one of them opens a raw-text\n * region, `originalInsertionMode` is captured as IN_TEMPLATE in a tail-only\n * parse and as IN_BODY in the full one. On the first stray end tag parse5\n * leaves TEXT mode and RESTORES that captured mode, and from there the two\n * parses dispatch differently: `</p>` synthesizes an empty paragraph in\n * \"in body\" and is ignored in \"in template\".\n *\n * `a\\n\\n<title>\\n\\n*b*\\n` — sixteen bytes — was a live under-block:\n * boundary 3, and the full parse has an empty `<p>` the spliced tree lacks.\n * Same for `<noframes>`, and for `<script>` when the double-escape keeps the\n * raw-text region open past its apparent closer.\n *\n * `textarea`/`iframe`/`noembed`/`xmp` take the default branch, pop first and\n * capture the CONVERGED mode — measured safe, and left alone. */\nconst HEAD_ROUTED_NAMES = new Set([\n 'base',\n 'basefont',\n 'bgsound',\n 'link',\n 'meta',\n 'noframes',\n 'script',\n 'style',\n 'template',\n 'title',\n]);\n/** The head-routed names that open a raw-text region (RCDATA / RAWTEXT /\n * script data) — the ones whose capture becomes observable. */\nconst HEAD_ROUTED_RAW_TEXT_RE = /<(script|style|title|noframes)(?=[\\s/>])/i;\nconst ANY_START_TAG_RE = /<([a-z][a-z0-9-]*)(?=[\\s/>])/gi;\n\n/** True when the tail's leading html run opens one of those regions with the\n * template mode still uncaptured, and does not honestly close it inside the\n * run. The closer must be inside the RUN, not the child: `<title>` block,\n * blank line, `</title>` block closes it and is measured safe. */\nfunction headRoutedCaptureUnclosed(values: readonly string[]): boolean {\n if (values.length === 0) return false;\n const joined = values.join('\\n');\n const opener = HEAD_ROUTED_RAW_TEXT_RE.exec(joined);\n if (opener === null) return false;\n // Any NON-head-routed start tag before the opener already popped the\n // template mode, so both parses captured the same one and this is safe.\n // Deciding that needs to know which `<…>` are markup, and a raw construct\n // makes that undecidable by regex: parse5 ends a bogus comment at the FIRST\n // `>`, so whether the `<div>` in `<![CDATA[<div>data</div>]]>` is a start\n // tag depends on where that `>` landed. Refuse to conclude convergence at\n // all when one is present — over-blocks, and the alternative was a live\n // under-block (fuzz seed 20270403, a CDATA between the comment and the\n // `<title>`).\n const before = joined.slice(0, opener.index);\n if (/<[!?]/.test(before)) return true;\n ANY_START_TAG_RE.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = ANY_START_TAG_RE.exec(before)) !== null) {\n if (!HEAD_ROUTED_NAMES.has(m[1].toLowerCase())) return false;\n }\n const name = opener[1].toLowerCase();\n const after = joined.slice(opener.index + opener[0].length);\n if (name === 'script') {\n const close = after.search(/<\\/script(?=[\\s/>])/i);\n // No closer, or a `<!--` before it: the escape states may keep the region\n // open past that tag, so the capture is still live. Over-blocks the\n // `<!-- … --> </script>` re-exit case, knowingly.\n return close === -1 || /<!--/.test(after.slice(0, close));\n }\n return !new RegExp(`</${name}(?=[\\\\s/>])`, 'i').test(after);\n}\n\n/** The two END tags HTML synthesizes (`<br>` / empty `<p>`) instead of dropping. */\nconst STRAY_SYNTHESIZED_END_TAG_RE = /<\\/(?:br|p)\\b/i;\n\n/** parse5 raw-text elements (RAWTEXT / RCDATA / script data / plaintext),\n * matching the scanner's RAW_TEXT_ELEMENTS (`noscript` excluded —\n * scriptingEnabled: false). */\nconst RAW_TEXT_OPEN_RE = /<(script|style|textarea|title|xmp|iframe|noembed|noframes|plaintext)(?=[\\s/>])/gi;\n\n/**\n * Does any frozen html block leave a parse5 raw-text REGION open at its own\n * end? Then the element crosses OUT of its micromark block — the wrap\n * separator between that block and the next becomes element text (stripped\n * with a `<script>`, swallowed into content otherwise), and the\n * separator-credit model below double-counts the gap (P3b batch 1's\n * measured counterexample: the F6 recovery granted boundary 60 on the\n * double-escape document and the spliced frame carried an extra root\n * `\"\\n\"`). The scanner deliberately RELEASES such prefixes once the\n * element truly closes (the retired poison); the splice refuses them\n * instead — the system contract is scanner boundary PLUS splice guards.\n *\n * Script regions honour the escape ladder the way the scanner does: a\n * `<!--` with no `-->` before the apparent `</script>` keeps the region\n * open past it (double-escape may be live — over-refuses the harmless\n * single-escaped case where no nested `<script` follows, knowingly).\n * Openers inside comments or quoted attribute values over-match — every\n * false positive only refuses a splice (full-parse fallback).\n */\nfunction rawTextRegionCrossesOut(values: Iterable<string>): boolean {\n for (const value of values) {\n let pos = 0;\n for (;;) {\n RAW_TEXT_OPEN_RE.lastIndex = pos;\n const open = RAW_TEXT_OPEN_RE.exec(value);\n if (open === null) break;\n const name = open[1].toLowerCase();\n const bodyStart = open.index + open[0].length;\n const closeRe = new RegExp(`</${name}(?=[\\\\s/>])`, 'ig');\n closeRe.lastIndex = bodyStart;\n let close = closeRe.exec(value);\n if (name === 'script') {\n // Skip closers still inside a live escape: `<!--` before the\n // closer with no `-->` between them.\n while (close !== null) {\n const body = value.slice(bodyStart, close.index);\n const lastOpen = body.lastIndexOf('<!--');\n if (lastOpen === -1 || body.indexOf('-->', lastOpen + 4) !== -1) break;\n close = closeRe.exec(value);\n }\n }\n if (close === null) return true;\n pos = close.index + close[0].length;\n }\n }\n return false;\n}\n\nexport function spliceTrees(input: SpliceInput): { mdast: MdastRoot; hast: HastRoot } | null {\n const { prevMdast, prevHast, tailMdast, tailHast, content, boundary, injectionPrefix, injectedSegments } = input;\n\n const injectedLen = injectionPrefix.length;\n const injectedLines = countNewlines(injectionPrefix);\n // Bounded count — slicing the prefix would allocate a copy of the whole\n // frozen document every frame just to count newlines (final-review R3).\n const prefixLines = countNewlines(content, boundary);\n const offsetDelta = boundary - injectedLen;\n const lineDelta = prefixLines - injectedLines;\n\n // --- prefix cuts (non-mutating reads of the previous frame's trees) ---\n // Filter semantics (no ordered-children early break): together with G4's\n // full straddle scan this keeps the cut correct-or-bailing even for\n // disordered trees a plugin-shaped mdast could present (round-2 review).\n const prefixMdast: MdastContent[] = [];\n for (const child of prevMdast.children) {\n const start = child.position?.start?.offset;\n if (start !== undefined && start < boundary) prefixMdast.push(child);\n }\n const attrs = attributeHastChildren(prevMdast, prevHast, boundary);\n const cutRegion: HastContent[] = [];\n for (let i = 0; i < prevHast.children.length; i++) {\n if (attrs[i] < boundary) {\n const node = prevHast.children[i];\n // HAST STRADDLE BAIL (campaign, 2026-08-03): an mdast-clean boundary\n // does not imply a hast-clean one — parse5's tree construction can\n // hoist an unclosed inline element (`<details>` open tag in a frozen\n // paragraph) to the root, where it swallows every later sibling. The\n // frozen subtree then CONTAINS tail bytes, and the tail re-parse\n // duplicates them (seed-20260751 counterexample). A positioned cut\n // child whose source extends past the boundary is exactly that shape.\n const end = node.position?.end?.offset;\n if (end !== undefined && end > boundary) return null;\n // A position-less CONTENT text is only attributable when it directly\n // follows a positioned element — its owner (parse5 merges adjacent\n // texts, so one block never emits two literal nodes). One that\n // follows another text is a stripped-construct remnant whose owner\n // may live PAST the boundary (`<?instr <b> ?>` → ` ?>`, seed-20260830:\n // attribution stalls on the last positioned child and pulled the\n // CURRENT TAIL's remnant into the cut, duplicating it). Ownership is\n // undecidable here — bail to a full parse.\n if (isTrailingLiteralText(node)) {\n const prev = i > 0 ? prevHast.children[i - 1] : undefined;\n if (!prev || prev.type !== 'element' || prev.position === undefined) return null;\n // …and it must be that element's OWN trailing literal (its html\n // block's source ends with the text). Attribution can hand a\n // following dropped-tag block's remnant (`[a]: def\\n\\n</t>\\ntext`)\n // an offset before the boundary — the def between them has no\n // output — and freezing it duplicated it (release soak).\n if (!ownsTrailingLiteral(prev as HastContent, node as HastContent & { value: string }, prefixMdast))\n return null;\n }\n cutRegion.push(node);\n continue;\n }\n // Raw trailing literal of a frozen html block (fuzz counterexample):\n // `</tag>` followed by an unblanked text line makes rehype-raw emit the\n // line as a POSITION-LESS non-whitespace text after the element. Being\n // position-less it is attributed FORWARD (to the first tail block), but\n // its bytes live before the boundary — it must freeze with its owner,\n // the preceding included node. Whitespace-only texts stay excluded:\n // those are separators/foster-hoist, owned by the model below.\n //\n // OWNERSHIP is element-adjacency (seed-20260830 regression, exposed by\n // removing the coarse tail bail): a real trailing literal always sits\n // DIRECTLY after its owner's element output — parse5 merges adjacent\n // texts, so one block never emits two literal nodes. A position-less\n // non-whitespace text after a TEXT node is the current tail's own\n // stripped-construct remnant (`<?instr <b> ?>` → ` ?>`), which the tail\n // re-parse reproduces — freezing it would duplicate it.\n const node = prevHast.children[i];\n if (\n i > 0 &&\n attrs[i - 1] < boundary &&\n prevHast.children[i - 1].type === 'element' &&\n isTrailingLiteralText(node) &&\n // …and only when that element really IS an html block's output: a\n // raw literal can only trail an `html` mdast node. A position-less\n // text after a `<p>` is the NEXT block's remnant — a stray end tag\n // (`</t>\\na`) parse5 dropped, whose text merged with the wrap\n // separator — owned by the tail, which re-parses it; freezing it\n // here duplicated it (v2.4.0 review P3). Falls through to the\n // remnant look-ahead below, which bails to a full parse. And the\n // literal must really be THAT block's trailing text: the block's raw\n // source ends with it. A dropped-tag block right after a frozen html\n // element (`</details>\\n\\n</t>\\ntext`) puts its remnant in the same\n // position, and freezing it duplicated it (release soak of the fix).\n ownsTrailingLiteral(prevHast.children[i - 1] as HastContent, node as HastContent & { value: string }, prefixMdast)\n ) {\n cutRegion.push(node);\n // NOTE: this break skips the remnant look-ahead below. Safe today\n // because a frozen stripped construct AFTER a pushed trailing\n // literal always leaves an orphan separator that alignPrefixCut's\n // block-final branch rejects via `trailingGaps > 0 || sepBuffer` —\n // a NON-LOCAL invariant: loosening that bail re-opens the swallow\n // through this path (final-review cross-reference).\n break;\n }\n // Stripped-construct remnant look-ahead (seeds 20260821/20260893): a\n // position-less NON-whitespace text in the run right past the cut\n // point is a stripped construct's remnant, and its owner carries no\n // position. If the owner is fully FROZEN, the tail re-parse cannot\n // reproduce the text and the model below would synthesize its gap\n // slot as a plain '\\n' — swallowing it (`<?instr <b> ?> after the pi`\n // froze three blocks back; sanitize stripped the bogus comment and\n // left ` ?> after the pi\\n` behind). If tail-owned, freezing it here\n // would duplicate it. Ownership is undecidable — bail to a full\n // parse. The scan stops at the first element or positioned node:\n // remnants further out belong to blocks the tail re-parses anyway.\n for (let j = i; j < prevHast.children.length; j++) {\n const look = prevHast.children[j];\n if (look.type === 'element' || look.position !== undefined) break;\n if (isTrailingLiteralText(look)) return null;\n }\n break;\n }\n\n // wrap() emits separators per mdast-child ADJACENCY, before sanitize\n // strips anything — so the seam's existence is decided by the tail's\n // post-transform MDAST (excluding wrap-invisible types, which produce no\n // to-hast output), not by whether the tail hast ends up non-empty.\n // (Learned from the arbiter: a sanitize-removed comment leaves its\n // separator behind.)\n //\n // ALL injected nodes are dropped from the tail mdast — wrap-invisible\n // defs (v1) and the replay's footnote-ref paragraphs alike; non-injected\n // children can never start before injectedLen.\n const tailMdastChildren = tailMdast.children.filter((child) => {\n const start = child.position?.start?.offset;\n return !(start !== undefined && start < injectedLen);\n });\n const tailWrapVisible = tailMdastChildren.some((child) => !isWrapInvisible(child));\n\n // parse5 tree-construction quirks that poison the WHOLE document, not one\n // seam (v2.4.2 review P1-1/P1-2 + its adversarial follow-up):\n // - a stray table-part tag (`<td>`, `<tr>`, `<col>` …) outside any table\n // changes how every LATER GFM table is built (its cell text is\n // foster-parented to the root in the full parse; a tail-only parse\n // builds a real <table>) — once such a tag sits in the frozen prefix,\n // no later splice is trustworthy;\n // - the tail-only parse opens in a mode where a stray `</br>` / `</p>` (the\n // two end tags HTML synthesizes instead of dropping) and table parts\n // are DROPPED until the first element start tag switches it to body,\n // while the full parse — already in body — synthesizes / foster-parents\n // them. Any such tag inside the tail's LEADING run of html blocks\n // (comments / PIs / declarations do not switch the mode) → bail.\n const prefixHtmlValues = prefixMdast.flatMap((c) => (c.type === 'html' ? [c.value] : []));\n if (hasStrayTablePart(prefixHtmlValues)) return null;\n if (rawTextRegionCrossesOut(prefixHtmlValues)) return null;\n const leadingHtml: string[] = [];\n for (const child of tailMdastChildren) {\n if (isWrapInvisible(child)) continue;\n if (child.type !== 'html') break;\n if (STRAY_SYNTHESIZED_END_TAG_RE.test(child.value) || TABLE_PART_TAG_RE.test(child.value)) return null;\n leadingHtml.push(child.value);\n }\n // …and the same case analysis for the head-routed raw-text names, whose\n // mode capture the comment above missed: they are precisely the start tags\n // that do NOT switch the mode to body.\n if (headRoutedCaptureUnclosed(leadingHtml)) return null;\n\n // Align the cut region against the prefix mdast (stripped-node aware) and\n // rebuild its trailing separators. Bails null on any layout the model\n // does not cover — the caller falls back to a full parse for the frame.\n const aligned = alignPrefixCut(prefixMdast, cutRegion, tailWrapVisible);\n if (aligned === null) return null;\n const hastChildren = aligned.children;\n const interiorFinalLiteral = aligned.interiorFinalLiteral;\n\n // --- tail: strip the injected region's hast, then re-base ---\n const stripResult = stripInjectedHast(tailMdast, tailHast, injectedLen, tailWrapVisible);\n if (stripResult === null) return null;\n const strippedTailHast = stripResult.rest;\n for (const child of tailMdastChildren) rebaseTree(child, offsetDelta, lineDelta);\n for (const child of strippedTailHast) rebaseTreeDual(child, injectedSegments, offsetDelta, lineDelta);\n\n // --- join ---\n //\n // Seam anatomy (all learned from the arbiter, not theory):\n // - Pre-raw, wrap() puts exactly ONE '\\n' text node between any two root\n // children — including between the last frozen block and the first\n // tail block; `alignPrefixCut` has already synthesized it (plus one per\n // trailing stripped-child gap) as plain '\\n' nodes.\n // - rehype-raw's reserialize+reparse HOISTS whitespace-only text out of\n // table internals to just BEFORE the <table> (parse5 foster-parenting),\n // then merges it with the adjacent separator into one multi-'\\n' text\n // node. That run is TAIL-derived and grows with the table — it must\n // come from the tail parse (which reproduces it as leading text), not\n // from the previous frame's tree. Joining therefore MERGES the seam\n // separator with the tail's leading text, exactly like the reparse\n // would — but ONLY when they were literally adjacent in the serialized\n // HTML. A tail whose first wrap-visible child was sanitize-STRIPPED\n // (leading comment) emits its leading text as a gap SLOT that the full\n // parse keeps as a separate node (the comment sat between them at\n // reparse time), so merging would be wrong there.\n const mdastChildren = prefixMdast.concat(tailMdastChildren);\n // Layout-driven verdict when the injection gap proved it (see\n // stripInjectedHast docs); the classification covers uninjected tails and\n // bails to a full parse when the seam is genuinely ambiguous.\n const seamMergeVerdict = stripResult.remnantMerged ?? tailLeadingTextIsHoist(tailMdastChildren, strippedTailHast);\n if (seamMergeVerdict === null) return null;\n const seamMergeAllowed = seamMergeVerdict;\n let firstTailChild = true;\n for (const child of strippedTailHast) {\n const tailEnd = hastChildren[hastChildren.length - 1];\n if (firstTailChild && child.type === 'text' && child.position !== undefined) {\n // The tail LEADS with a positioned bare text — a raw literal whose\n // preceding construct vanished at the tokenizer (stray end tag's\n // trailing spaces, deep-soak counterexample). A full parse merges it\n // into the seam separator (or keeps it apart when the vanished thing\n // was sanitize-stripped) — classifying which means modeling the\n // tokenizer. Bail to a full parse.\n return null;\n }\n if (firstTailChild && tailEnd && tailEnd.type === 'text' && child.type === 'text' && child.position === undefined) {\n // Interior-literal gate (seed-20260838, join side): when the cut\n // ends in an INTERIOR raw literal (classified by alignPrefixCut —\n // its stripped following sibling kept it un-merged at reparse\n // time), the full parse keeps it verbatim with a SEPARATE\n // separator after it, never merged. Push the tail child as its own\n // node; a hoist-merge verdict against it is out of model — bail.\n // Block-final positioned literals do NOT take this path: the full\n // parse merges them with the seam separator exactly like the\n // position-less artifacts this branch models.\n if (interiorFinalLiteral && tailEnd.value.trim() !== '') {\n if (seamMergeAllowed) return null;\n firstTailChild = false;\n hastChildren.push(child);\n continue;\n }\n // A trailing html-block literal absorbs adjacent tail text the same\n // way (footer separator of an all-invisible tail — no wrap slot sat\n // between them at reparse time), and the merge drops the source\n // position, matching hast-util-raw's merged-text output.\n const literalSeam = tailEnd.value.trim() !== '' && !tailWrapVisible;\n if (seamMergeAllowed || literalSeam) {\n // Adjacent text at the seam — the full parse would have merged\n // these during rehype-raw's reparse. Replace (don't mutate) the\n // seam node: it may be a reference into the previous frame's tree.\n hastChildren[hastChildren.length - 1] = { type: 'text', value: tailEnd.value + child.value };\n firstTailChild = false;\n continue;\n }\n }\n firstTailChild = false;\n hastChildren.push(child);\n }\n\n // No POSITIONED top-level output → bail (fuzz + exhaustive-sweep\n // finding). hast-util-raw anchors the rebuilt root's position on its\n // positioned output nodes: a sanitize-stripped comment still anchored it\n // (positioned pre-sanitize), while a defs-only doc, a tokenizer-dropped\n // `<?…` opener, or a stray `</d>` end tag (dropped, leaving only a bare\n // position-less wrap separator behind) do not — and removeComments\n // shifts the comment case across that line. Reconstructing the verdict\n // for position-less-only output means re-modeling the parse5 tokenizer\n // per child; such frames are tiny by construction, so a full parse costs\n // nothing.\n if (!hastChildren.some((child) => child.position !== undefined)) return null;\n\n // Root positions must match a full parse: start of document to end of\n // document. The re-based tail MDAST root end IS the document end. The\n // tail HAST root's position is NOT source-based after rehype-raw's\n // reparse (hast-util-raw rewrites it in serialized-HTML coordinates), so\n // it cannot be re-based — but a full parse with POSITIONED output (the\n // other case bailed above) leaves the hast root position equal to the\n // mdast root position (arbiter-verified), so reuse that.\n const docStart = { line: 1, column: 1, offset: 0 };\n const mdastRootPosition = tailMdast.position\n ? { start: docStart, end: rebasePoint(tailMdast.position.end, offsetDelta, lineDelta) }\n : prevMdast.position;\n const hastRootPosition = mdastRootPosition;\n\n const mdast: MdastRoot = { type: 'root', children: mdastChildren };\n if (mdastRootPosition) mdast.position = mdastRootPosition;\n const hast: HastRoot = { type: 'root', children: hastChildren };\n if (hastRootPosition) hast.position = hastRootPosition;\n if (prevHast.data !== undefined) hast.data = prevHast.data;\n return { mdast, hast };\n}\n\nfunction rebasePoint(point: Position['end'], offsetDelta: number, lineDelta: number): Position['end'] {\n return {\n line: point.line + lineDelta,\n column: point.column,\n offset: point.offset !== undefined ? point.offset + offsetDelta : undefined,\n };\n}\n\n/** mdast types with no to-hast output AND no wrap separator slot. Everything\n * else gets a slot at wrap() time — even nodes sanitize later strips\n * (comments, PIs, `<script>`), whose slots survive as orphan separators. */\nfunction isWrapInvisible(node: MdastContent): boolean {\n return node.type === 'definition' || node.type === 'footnoteDefinition';\n}\n\n/**\n * Stripped-node-aware prefix cut (B0-probe-verified layout model).\n *\n * The cut region of the previous hast interleaves CONTENT nodes with\n * position-less '\\n' SEPARATORS. wrap() emitted one separator per gap\n * between adjacent wrap-visible mdast children; sanitize then stripped some\n * children's output (HTML comment / PI / `<script>`), leaving their\n * separators orphaned. The walk below re-derives the pairing:\n *\n * - separator-run lengths are the gap ground truth (a run of length L\n * between two content nodes ⇒ L−1 stripped children between them; a\n * leading run of length L ⇒ L leading stripped children);\n * - positioned content cross-checks the pairing (its start offset must fall\n * inside the paired mdast child's range). Multiple positioned content\n * nodes inside ONE child's range are a raw-reparse multi-output html\n * block — legal, zero separators between them;\n * - position-less content (KaTeX span) pairs by cursor arithmetic alone.\n *\n * Internal separators are kept VERBATIM (one before a frozen <table> may\n * legitimately hold hoisted newlines — frozen with the table, stable). The\n * TRAILING run is rebuilt from scratch as plain '\\n' nodes: its last member\n * is seam-adjacent and may carry the previous frame's tail-derived hoist\n * (stale), and its length must reflect the CURRENT tail's wrap visibility,\n * not the previous frame's.\n *\n * Returns null whenever the observed layout contradicts the model — the\n * caller falls back to a full parse (safe, one-frame cost).\n */\nfunction alignPrefixCut(\n prefixMdast: MdastContent[],\n cutRegion: HastContent[],\n tailWrapVisible: boolean\n): { children: HastContent[]; interiorFinalLiteral: boolean } | null {\n const visibles = prefixMdast.filter((c) => !isWrapInvisible(c));\n\n const out: HastContent[] = [];\n let sepBuffer: HastContent[] = [];\n let pairIdx = -1; // index into `visibles` of the child paired with the last content node\n let sawContent = false;\n // Wrap separators MERGED into pushed trailing literals (every trailing\n // '\\n' on a literal is a merged separator — see the trailing-region\n // note). They count toward the NEXT gap's run length: without the\n // credit, separator runs after a literal UNDERCOUNT the stripped\n // children and the run-length rule mispairs position-less content\n // (seed-20260752: the KaTeX span paired with the stripped comment,\n // inflating the trailing gap count and duplicating the seam separator).\n let literalCredit = 0;\n\n for (const node of cutRegion) {\n if (isSeparatorText(node)) {\n sepBuffer.push(node);\n continue;\n }\n const start = node.position?.start?.offset;\n const paired = pairIdx >= 0 ? visibles[pairIdx] : undefined;\n if (\n sawContent &&\n start !== undefined &&\n paired &&\n paired.position?.start?.offset !== undefined &&\n paired.position?.end?.offset !== undefined &&\n start >= paired.position.start.offset &&\n start < paired.position.end.offset\n ) {\n // Multi-output continuation of the SAME mdast child (raw reparse of a\n // multi-element html block) — serialized adjacently, so no separator\n // may sit between the outputs.\n if (sepBuffer.length !== 0) return null;\n out.push(node);\n continue;\n }\n if (sawContent && isTrailingLiteralText(node)) {\n // Raw trailing literal of the SAME html block (position-less,\n // non-whitespace — cannot be foster-parenting hoist, which is\n // whitespace-only). Serialized adjacent to its element output, so no\n // separator may intervene; the pairing cursor stays put.\n if (sepBuffer.length !== 0) return null;\n out.push(node);\n literalCredit += countTrailingNewlines(node.value);\n continue;\n }\n // New pairing: the separator run before this node covers the gap from\n // the previous content node (1 separator) plus one per stripped child.\n //\n // LEADING-run exception (final-review R2): when the FIRST wrap-visible\n // child is a table (or any foster-parenting element), rehype-raw's\n // hoisted whitespace has no preceding wrap slot to merge into and lands\n // as a bare leading text node — one leading text with ZERO stripped\n // children. A positioned first content node therefore locates its own\n // pair by containment within [0..sepBuffer.length]; the excess leading\n // texts are hoist, kept verbatim (frozen with their table, stable —\n // interior hoist always merges into an existing slot, so only the\n // leading run needs this). Position-less first content (KaTeX — never\n // hoist-preceded) keeps the pure run-length rule.\n let nextIdx: number;\n if (!sawContent && start !== undefined) {\n nextIdx = -1;\n for (let j = 0; j <= sepBuffer.length && j < visibles.length; j++) {\n const vStart = visibles[j].position?.start?.offset;\n const vEnd = visibles[j].position?.end?.offset;\n if (vStart !== undefined && vEnd !== undefined && start >= vStart && start < vEnd) {\n nextIdx = j;\n break;\n }\n }\n if (nextIdx === -1) return null;\n // Excess leading texts beyond the stripped-child slots can only be\n // hoist, and hoist exists as a SEPARATE node only when there is no\n // slot to merge into (nextIdx === 0, probe-verified). Any excess in\n // the presence of slots is out of model → bail (round-2 review\n // tightened this from `excess > 1`).\n const excess = sepBuffer.length - nextIdx;\n if (excess > (nextIdx === 0 ? 1 : 0)) return null;\n } else {\n // Run length = observed bare separators PLUS the ones merged into\n // trailing literals since the last pairing (literalCredit) — the gap\n // ground truth the stripped-children arithmetic needs.\n const stripped = sawContent ? sepBuffer.length + literalCredit - 1 : sepBuffer.length;\n if (stripped < 0) return null;\n nextIdx = pairIdx + 1 + stripped;\n const candidate = visibles[nextIdx];\n if (!candidate) return null;\n if (start === undefined && sepBuffer.some((sep) => sep.type !== 'text' || sep.value !== '\\n')) {\n // Position-less content (KaTeX) can only be paired by run length, and\n // a merged separator (`\"\\n\\n\"` around an html block parse5 dropped\n // outright) UNDERCOUNTS the gap — the span would pair with the\n // dropped block and be frozen twice (release soak of 2.4.2). Bail.\n return null;\n }\n if (start !== undefined) {\n const cStart = candidate.position?.start?.offset;\n const cEnd = candidate.position?.end?.offset;\n if (cStart === undefined || cEnd === undefined || start < cStart || start >= cEnd) return null;\n }\n }\n out.push(...sepBuffer, node);\n sepBuffer = [];\n literalCredit = 0; // merged separators consumed by this gap\n pairIdx = nextIdx;\n sawContent = true;\n }\n\n // Trailing region: every visible child after the last paired one must be\n // stripped. The observed run came from the PREVIOUS frame (its length\n // includes that frame's seam separator when its tail was wrap-visible),\n // so it is discarded and rebuilt for the current tail.\n const trailingStripped = visibles.length - (pairIdx + 1);\n const trailingGaps = sawContent ? trailingStripped : Math.max(0, visibles.length - 1);\n const seam = visibles.length > 0 && tailWrapVisible ? 1 : 0;\n\n // Trailing-literal seam merge: when the cut ends in an html block's raw\n // trailing literal, the full parse MERGES the wrap separator into that\n // text node (adjacent text at reparse time) instead of keeping a bare\n // '\\n' — and the merge DROPS the text's source position (an unmerged\n // document-final literal keeps hast-util-raw's position; the same\n // literal followed by wrap-visible content comes out position-less,\n // fuzz-verified both ways). The literal's intrinsic value never ends\n // with '\\n' (an html node's source ends at line content), so EVERY\n // trailing '\\n' on the cut node is a previous frame's merged artifact —\n // seam separator, footer separator, or table hoist (which GROWS with the\n // streaming tail and must never be carried forward). Shed them all, then\n // re-merge (and re-drop the position) for the CURRENT tail's layout — the\n // join merges the tail's own leading text back in. Stripped children\n // after a trailing literal are out of model — bail to the full parse.\n const last = out[out.length - 1];\n // A POSITIONED whitespace-only text at the cut's end is an html block's\n // raw remnant with every tag dropped by parse5 (`</details>\\n</details>`\n // leaves only the line ending, positioned) — the trailing-literal branch\n // below models non-blank literals only, and the plain-slot rebuild would\n // push it next to a synthesized bare '\\n' where the full parse merges\n // both into one position-less `\"\\n\\n\"`. Out of model — bail (v2.4.1\n // review P2, the neighbour of the two 2.4.1 trailing-literal fixes).\n if (last !== undefined && last.type === 'text' && last.position !== undefined && last.value.trim() === '') {\n return null;\n }\n // Interior-literal gate (seed-20260838): this branch models BLOCK-FINAL\n // literals — the ones the full parse merges with the seam separator\n // (position dropped). A POSITIONED literal whose source ends BEFORE its\n // owner html node's end is an INTERIOR raw literal: a sanitize-stripped\n // sibling (`</details>` text `<embed/>`) followed it at reparse time, so\n // the full parse keeps it verbatim — positioned, un-merged, with its own\n // separator. Route those to the plain-slot rebuild (and tell the join to\n // keep its hands off — see `interiorFinalLiteral`). A positioned literal\n // whose end EQUALS the owner's end is block-final like the position-less\n // ones and stays in this branch (first freeze straight from a full-parse\n // tree — later frames see the merged, position-less artifact).\n const lastIsLiteral = last !== undefined && last.type === 'text' && last.value.trim() !== '';\n if (lastIsLiteral && pairIdx >= 0 && visibles[pairIdx].type !== 'html') {\n // Root-level literal text owned by a NON-html block: a stray `<td>`\n // earlier in the document made parse5 foster-parent the following GFM\n // table's cell text to the root and destroy the table skeleton, whose\n // internal line endings then merged into the separator AFTER it — a\n // separator the cut never sees (it lives past the boundary) and the\n // rebuild cannot reproduce (v2.4.2 review P1-2). Out of model — bail.\n return null;\n }\n const litOwnerEnd = pairIdx >= 0 ? visibles[pairIdx].position?.end?.offset : undefined;\n const litEnd = lastIsLiteral ? last.position?.end?.offset : undefined;\n if (lastIsLiteral && last.position !== undefined && (litEnd === undefined || litOwnerEnd === undefined)) {\n // Positioned literal with an unclassifiable owner — out of model.\n return null;\n }\n if (litEnd !== undefined && litOwnerEnd !== undefined && litEnd > litOwnerEnd) {\n // A positioned literal extending PAST its owner is unreachable by the\n // model (positioned ⟹ never merged ⟹ span stays inside the owner) —\n // if it ever shows up the model diverged, and folding it into the\n // block-final branch would merge bytes we cannot account for. Bail\n // explicitly: \"unreachable\" becomes \"safe when reached\" (final-review\n // MINOR, echoing the first-fix regression lesson).\n return null;\n }\n const interiorFinalLiteral =\n lastIsLiteral && litEnd !== undefined && litOwnerEnd !== undefined && litEnd < litOwnerEnd;\n if (lastIsLiteral && !interiorFinalLiteral) {\n // This bail is also the backstop for the cut loop's trailing-literal\n // break path (see the cross-reference note there): a frozen stripped\n // construct after the literal surfaces here as trailing gaps or a\n // leftover separator run. Do not loosen without restoring a remnant\n // check at the cut.\n if (trailingGaps > 0 || sepBuffer.length > 0) return null;\n const body = last.value.replace(/\\n+$/, '');\n if (last.position !== undefined && body !== last.value) {\n // A positioned block-final literal never carries trailing newlines\n // (its source ends at line content; merges drop the position) — a\n // trailing '\\n' here is out of model.\n return null;\n }\n if (seam > 0) {\n out[out.length - 1] = { type: 'text', value: `${body}\\n` };\n } else if (last.position !== undefined) {\n // Positioned block-final literal fresh from a full-parse tree: its\n // own position IS the source truth — keep the node verbatim (the\n // trailing-'\\n' guard above proved body === value).\n } else {\n // Document-final literal (nothing wrap-visible follows): hast-util-raw\n // keeps its SOURCE position — [previous element's end, owner html\n // node's end]. A literal that got merged in an earlier frame lost its\n // position, so reconstruct it from the neighbors; bail when they\n // don't carry the needed points. (If the current tail still appends a\n // footer, the join's literal-seam merge re-drops the position — the\n // same order a full parse resolves it in.)\n const prevEl = out.length >= 2 ? out[out.length - 2] : undefined;\n const owner = pairIdx >= 0 ? visibles[pairIdx] : undefined;\n const start = prevEl?.type === 'element' ? prevEl.position?.end : undefined;\n const end = owner?.position?.end;\n if (!start || !end) return null;\n out[out.length - 1] = { type: 'text', value: body, position: { start, end } };\n }\n return { children: out, interiorFinalLiteral: false };\n }\n\n // A trailing separator whose value is not a PLAIN '\\n' carries a merged\n // raw remnant (a dropped construct's whitespace, a prior merged gap) —\n // rebuilding it as bare '\\n' silently drops those bytes (deep-soak\n // counterexample: a stripped comment's preceding ' ' merged into ' \\n').\n // Out of the plain-slot model — bail to a full parse.\n if (sepBuffer.some((s) => s.type !== 'text' || s.value !== '\\n')) return null;\n // An interior literal whose merged separators were never consumed by a\n // later pairing (literal, bare separators, then nothing) — its credit\n // would have to offset the trailing-run arithmetic below, a shape the\n // trailing rebuild does not model. Bail to a full parse.\n if (literalCredit > 0) return null;\n // A frozen html child ENDING in a sanitize-stripped construct (`…-->`,\n // `…?>`, `…]]>`, declarations) leaves interior whitespace between its\n // last element and the stripped tail — whitespace the full parse MERGES\n // into the seam separator (`\"\\n\\n\"`, seed-20260850) while the plain-slot\n // rebuild below synthesizes a bare `'\\n'`. The merged node never reaches\n // the cut (attribution excludes it), so the rebuild is blind to it —\n // bail to a full parse when the last paired child has such a tail.\n const lastPaired = pairIdx >= 0 ? visibles[pairIdx] : undefined;\n if (lastPaired && lastPaired.type === 'html') {\n const v = (lastPaired as { value: string }).value;\n const lastLt = v.lastIndexOf('<');\n if (lastLt !== -1 && /^<[!?]/.test(v.slice(lastLt))) return null;\n // Same blindness, other cause: the block's OUTPUT ends before its\n // SOURCE does — parse5 dropped whatever followed the last element (a\n // stray `</details>` after the real one, v2.4.1 review P2) and the line\n // ending before it survives as a remnant the full parse merges into\n // the seam separator (`\"\\n\\n\"`), which the rebuild below cannot see.\n const lastOut = out[out.length - 1];\n const outEnd = lastOut?.type === 'element' ? lastOut.position?.end?.offset : undefined;\n const blockEnd = lastPaired.position?.end?.offset;\n if (outEnd !== undefined && blockEnd !== undefined && outEnd < blockEnd) return null;\n }\n if (sepBuffer.length !== trailingGaps && sepBuffer.length !== trailingGaps + 1) return null;\n // The rebuild below emits ONE bare '\\n' per stripped trailing child — the\n // shape a sanitize-stripped node leaves (comment/PI/CDATA/declaration:\n // rehype-raw made a node, sanitize removed it, the separators around it\n // stay separate texts). An html block that parse5 DROPPED outright (a\n // stray `</details>`, a `<!DOCTYPE>`, or an element sanitize removed as a\n // whole) leaves no node, and hast-util-raw merges the separators around\n // it into one `\"\\n\\n\"` — the two are indistinguishable from the cut hast\n // (release soak of 2.4.2, `</details>\\n<!-- c\\n\\n-->\\n</details>` —\n // pre-existing). And a child that only STARTS with a construct leaves the\n // rest as a text remnant that merges into a slot the rebuild synthesizes\n // bare (`<!-- c --> </s>` → `\" \\n\"`, release-gate finding A, seed\n // 20293003 — the old `/^\\s*<[!?]/` prefix test admitted it). Bail unless\n // every stripped trailing child is EXACTLY one sanitize-stripped\n // construct.\n for (let j = pairIdx + 1; j < visibles.length; j++) {\n const v = visibles[j];\n if (v.type === 'html' && !isExactSanitizeStrippedConstruct((v as { value: string }).value)) return null;\n }\n for (let i = 0; i < trailingGaps + seam; i++) {\n out.push({ type: 'text', value: '\\n' });\n }\n return { children: out, interiorFinalLiteral };\n}\n\n/**\n * Drop the injected region's output from a freshly-parsed tail hast.\n *\n * The injection contributes two kinds of root output: the replay's footnote\n * REF paragraphs (one `<p>` each — footnote/link defs are wrap-invisible)\n * and the wrap separators around them. Consume exactly:\n *\n * output_1 [sep output_2 … sep output_k] [gapSep]\n *\n * where k = injected wrap-visible children and gapSep (present only when\n * the REAL tail has wrap-visible children) is the injected|tail gap slot.\n * gapSep's value beyond its wrap '\\n' is text the raw reparse MERGED into\n * the slot — rehype-raw hoist ahead of a table, or the orphan separator of\n * an opener the tokenizer dropped outright (an unterminated `<?`/`<!`, fuzz\n * counterexample) — retained as a leading text node.\n *\n * `remnantMerged` carries the seam verdict that merge PROVES: the injected\n * region occupies the same serialized-adjacency position inside the tail\n * parse that the frozen prefix occupies in a full parse, so \"the tail's raw\n * pass merged the gap with what follows\" ⇔ \"a full parse merges the seam\n * separator there too\". Null when no gap was consumed (no injection): the\n * caller falls back to the hoist heuristic.\n *\n * Returns null on any layout surprise (caller falls back to a full parse).\n */\nfunction stripInjectedHast(\n tailMdast: MdastRoot,\n tailHast: HastRoot,\n injectedLen: number,\n tailWrapVisible: boolean\n): { rest: HastContent[]; remnantMerged: boolean | null } | null {\n if (injectedLen === 0) return { rest: tailHast.children.slice(), remnantMerged: null };\n const injectedVisibleCount = tailMdast.children.filter((c) => {\n const start = c.position?.start?.offset;\n return start !== undefined && start < injectedLen && !isWrapInvisible(c);\n }).length;\n if (injectedVisibleCount === 0) return { rest: tailHast.children.slice(), remnantMerged: null };\n\n const children = tailHast.children;\n let idx = 0;\n let consumed = 0;\n while (idx < children.length && consumed < injectedVisibleCount) {\n const node = children[idx];\n if (isSeparatorText(node)) {\n idx += 1;\n continue;\n }\n const start = node.position?.start?.offset;\n // Injected outputs are always positioned paragraphs; running into tail\n // content (or anything unpositioned) before finishing is a surprise.\n if (start === undefined || start >= injectedLen) return null;\n consumed += 1;\n idx += 1;\n }\n if (consumed < injectedVisibleCount) return null;\n\n let remnant = '';\n let remnantMerged: boolean | null = null;\n if (tailWrapVisible) {\n const gap = children[idx];\n if (!gap || !isSeparatorText(gap)) return null;\n remnant = (gap as { value: string }).value.slice(1);\n remnantMerged = remnant !== '';\n idx += 1;\n }\n const rest = children.slice(idx);\n if (remnant !== '') rest.unshift({ type: 'text', value: remnant });\n return { rest, remnantMerged };\n}\n\n/**\n * Decide whether the tail hast's LEADING position-less text may merge with\n * the seam separator. True only when it is rehype-raw hoist output sitting\n * directly against the seam in serialized HTML — i.e. the tail's first\n * wrap-visible mdast child SURVIVED sanitize (its output is the first tail\n * content node). If that child was stripped (leading comment), the leading\n * text is a gap SLOT the full parse keeps as a separate node.\n *\n * Three-valued (fuzz-arbiter finding — the old boolean version claimed\n * \"false is provably right wherever evidence is ambiguous\", and fuzz\n * disproved it): a tail whose first wrap-visible child VANISHES at raw time\n * (an unterminated `<?`/`<!` opener the tokenizer drops outright) leaves\n * the same post-sanitize shape as one stripped at sanitize time (a\n * complete comment), but the full parse MERGES the seam in the first case\n * and keeps it separate in the second. Positive classifications:\n * - `true` — hoist: first content is positioned inside the first visible\n * child (table foster-parenting), merge;\n * - `false` — the vanished/position-less output is positively attributable:\n * math (KaTeX emits its own output, never dropped) or a COMPLETE\n * comment/PI/decl/CDATA html child (a raw-time node existed; sanitize\n * stripped it, so the slots stay separate);\n * - `null` — cannot classify (unterminated raw constructs, mixed html\n * values): caller falls back to a full parse for the frame.\n */\nfunction tailLeadingTextIsHoist(tailMdastChildren: MdastContent[], tailHastChildren: HastContent[]): boolean | null {\n const firstText = tailHastChildren[0];\n const firstVisible = tailMdastChildren.find((c) => !isWrapInvisible(c));\n // HTML's two end-tag SYNTHESIS exceptions: a stray `</br>` becomes a\n // `<br>` and a stray `</p>` an empty `<p>` (every other unmatched end tag\n // is dropped). The full parse synthesizes them in body context; the\n // tail-only parse, which opens on the stray tag, does not — the element\n // is simply absent from the tail hast, so no join rule can put it back\n // (v2.4.2 review P1-1: `x\\n\\n</br>\\n\\ny` lost its `<br>`). Bail.\n if (firstVisible?.type === 'html' && STRAY_SYNTHESIZED_END_TAG_RE.test(firstVisible.value)) return null;\n if (!firstText) return false;\n if (!isSeparatorText(firstText)) {\n // Position-less NON-whitespace leading text: the tail starts with an\n // html block whose leading end tag the tokenizer DROPPED (`</t>\\ntext`\n // — no open element to close, so no node ever existed) and whose\n // remaining text merged with the wrap separator at reparse time. The\n // full parse therefore has ONE merged text at the seam; treat it as\n // hoist-merge (v2.4.0 review P3 join side, surfaced by the new fuzz\n // shape). Any other position-less literal keeps its own node.\n if (firstText.type === 'text' && firstText.position === undefined && firstVisible?.type === 'html') {\n if (/^\\s*<\\/[A-Za-z][A-Za-z0-9-]*\\s*>/.test(firstVisible.value)) return true;\n // A complete comment/PI/decl/CDATA existed at raw time (sanitize\n // stripped it later) — its slots stay separate: no merge. A DOCTYPE\n // is not in that class (parse5 drops it, no node) and falls to the\n // bail below.\n if (isSanitizeStrippedConstruct(firstVisible.value)) return false;\n // Anything else — an unterminated `<div` opener the tokenizer drops\n // at EOF-in-tag (release soak: `<div\\n\\n</t>\\ntext`), mixed raw\n // values — needs the tokenizer to say whether a node existed\n // between the separator and this text. Bail to a full parse.\n return null;\n }\n return false;\n }\n if (!firstVisible) return false;\n const firstContent = tailHastChildren.find((c) => !isSeparatorText(c));\n if (firstContent) {\n const start = firstContent.position?.start?.offset;\n const vStart = firstVisible.position?.start?.offset;\n const vEnd = firstVisible.position?.end?.offset;\n if (start !== undefined && vStart !== undefined && vEnd !== undefined) {\n if (start >= vStart && start < vEnd) return true; // hoist\n // First visible's output vanished; classify by the child itself below.\n }\n }\n if (firstVisible.type === 'math') return false; // KaTeX output, never dropped\n // Sanitize-stripped constructs only: a raw-time node existed, the slots\n // stay separate. A `<!DOCTYPE …>` child VANISHES at parse5 time instead\n // (no node — fragment tree construction drops the doctype token), so the\n // seam separator and the tail's leading text MERGE in a full parse\n // (release-gate finding B, seed 20293004) — it falls through to the null\n // bail, full parse for the frame.\n if (firstVisible.type === 'html' && isSanitizeStrippedConstruct(firstVisible.value)) return false;\n return null;\n}\n\n/** Single complete comment / PI / declaration / CDATA that begins with a\n * construct parse5 turns into a NODE (a comment) — raw-time node\n * guaranteed, sanitize strips it later, so its separator slots stay\n * separate. `<!DOCTYPE …>` is the one declaration this is FALSE of:\n * parse5's tokenizer recognizes it as a real doctype token, and fragment\n * tree construction then DROPS it outright — no node ever exists, so the\n * texts on either side MERGE at reparse time (release-gate finding B:\n * classifying it \"stripped ⇒ slots separate\" split a seam text the full\n * parse merges). Doctypes and anything unterminated or mixed → not\n * classifiable here. Exported for the semantics pins. */\nexport function isSanitizeStrippedConstruct(value: string): boolean {\n const v = value.trim();\n return (\n (v.startsWith('<!--') && v.endsWith('-->')) ||\n (v.startsWith('<?') && v.endsWith('?>')) ||\n (v.startsWith('<![CDATA[') && v.endsWith(']]>')) ||\n (/^<![A-Za-z]/.test(v) && !/^<!doctype/i.test(v) && v.endsWith('>'))\n );\n}\n\n/** The trailing-slot rebuild's admission test — STRICTER than the seam\n * classifier above, because the rebuild asserts the stripped child leaves\n * EXACTLY one bare '\\n' wrap slot and nothing else. The whole value must\n * be ONE construct that parse5 tokenizes into a node and sanitize strips,\n * covering the value EXACTLY: any surrounding bytes survive the strip as a\n * text remnant that merges into a neighbouring slot, which the plain-'\\n'\n * rebuild cannot represent (`<!-- c --> </s>` leaves ` ` and the full\n * parse's slot is `\" \\n\"` — release-gate finding A). The construct ends\n * are PARSE5's, not micromark's:\n * - a comment also closes at `--!>` (micromark ignores it), so the first\n * parse5 close must be the value's own terminal `-->`;\n * - `<?…` / `<!x…` / `<![CDATA[…` in HTML content are ONE bogus comment\n * running to the FIRST `>` — a `>` inside the micromark construct body\n * ends the node early and leaves a remnant;\n * - `<!doctype` never makes a node at all (see the seam classifier).\n * Exported for the semantics pins. */\nexport function isExactSanitizeStrippedConstruct(value: string): boolean {\n if (value.startsWith('<!--')) {\n if (value.length < 7 || !value.endsWith('-->')) return false;\n // First close scanned from past the opener; an overlap-close empty\n // comment (`<!--->`) is refused — conservative, full parse instead.\n const close = value.indexOf('-->', 4);\n const bangClose = value.indexOf('--!>', 4);\n if (close !== value.length - 3) return false;\n return bangClose === -1 || bangClose > close;\n }\n if (/^<!doctype/i.test(value)) return false;\n if (value.startsWith('<?') || /^<!(?:[A-Za-z]|\\[CDATA\\[)/.test(value)) {\n return value.indexOf('>') === value.length - 1;\n }\n return false;\n}\n\n/** Position-less whitespace-only root text — wrap()/rehype-raw separator runs. */\nfunction isSeparatorText(node: HastContent): boolean {\n return node.type === 'text' && node.position === undefined && node.value.trim() === '';\n}\n\n/** Whether a position-less literal is the trailing raw text of the `html`\n * mdast block that produced `el` (the element's start is that block's\n * start, and the block's source ENDS with the literal's text). Trailing raw\n * literals can only follow html-block output, and only that block's own\n * text counts — a following dropped-tag block's remnant sits in the same\n * spot but is not in this block's source. */\nfunction ownsTrailingLiteral(el: HastContent, literal: { value: string }, prefixMdast: MdastContent[]): boolean {\n const start = el.position?.start?.offset;\n if (start === undefined) return false;\n const owner = prefixMdast.find((c) => c.type === 'html' && c.position?.start?.offset === start);\n if (!owner || owner.type !== 'html') return false;\n const text = literal.value.trim();\n return text !== '' && owner.value.trimEnd().endsWith(text);\n}\n\n/** Position-less NON-whitespace text at the top level — the raw reparse's\n * literal trailing output of an html block (an unblanked text line after\n * the block's closing tag). Distinct from separators and foster-parenting\n * hoist, which are whitespace-only. */\nfunction isTrailingLiteralText(node: HastContent): node is HastContent & { type: 'text'; value: string } {\n return node.type === 'text' && node.position === undefined && node.value.trim() !== '';\n}\n\n/** Trailing '\\n' run length on a literal's value — its merged separators. */\nfunction countTrailingNewlines(value: string): number {\n let n = 0;\n for (let i = value.length - 1; i >= 0 && value[i] === '\\n'; i--) n += 1;\n return n;\n}\n\n/** Line endings in `text` before `end` (defaults to the whole string) — the\n * bound avoids allocating prefix slices on the per-frame hot path.\n * Counts what micromark counts: `\\n`, `\\r\\n` and a LONE `\\r` are one line\n * ending each (2026-08-19 review P2-1: a lone `\\r` in the frozen prefix\n * left every rebased tail `position.line` one short — offsets and shape\n * were right, only the line numbers drifted). Two indexOf sweeps keep the\n * hot path allocation-free; a `\\r` directly followed by `\\n` is the CRLF\n * pair, already counted by the `\\n` sweep. */\nfunction countNewlines(text: string, end = text.length): number {\n let count = 0;\n for (let i = text.indexOf('\\n'); i !== -1 && i < end; i = text.indexOf('\\n', i + 1)) count += 1;\n for (let i = text.indexOf('\\r'); i !== -1 && i < end; i = text.indexOf('\\r', i + 1)) {\n if (text.charCodeAt(i + 1) !== 10 /* \\n */) count += 1;\n }\n return count;\n}\n","/**\n * Shared hast predicates — engine-side home for detection helpers consumed\n * by both the incremental-parse engine (attributeHastChildren's seam\n * attribution) and core's block-memo renderer.\n *\n * Lifted verbatim from core's blockMemo.ts (boundary action ①): blockMemo\n * stays React-side while incrementalParse moves into the engine, and this\n * predicate was the one value-level edge between them.\n *\n * @module components/hastPredicates\n */\n\nimport type { Element as HastElement, ElementContent } from 'hast';\n\n/**\n * Detect mdast-util-to-hast's synthesized footnote `<section data-footnotes>`.\n * Position-based detection alone would be too broad — any future rehype plugin\n * that appends a position-less node would be misclassified. We assert by\n * `tagName === 'section'` AND presence of the `dataFootnotes` property.\n */\nexport function isFootnoteSection(node: HastElement): boolean {\n if (node.tagName !== 'section') return false;\n const props = node.properties as Record<string, unknown> | undefined;\n return props?.dataFootnotes !== undefined;\n}\n\n/**\n * Whitespace-only text node. `mdast-util-to-hast`'s `state.wrap(content,\n * true)` interleaves `\\n` text nodes between (and around) the block-level\n * children of an `<li>`, so any code reasoning about a list item's real\n * children has to look past them.\n */\nexport function isWhitespaceText(c: ElementContent): boolean {\n return c.type === 'text' && /^\\s*$/.test((c as { value: string }).value);\n}\n\n/**\n * Index of the last child that is not a whitespace-only text node, or -1 if\n * there is none.\n *\n * Both footnote-footer paths need exactly this and for the same reason.\n * Appending a backref follows mdast-util-to-hast's contract — \"if the tail of\n * the `<li>`'s content is a `<p>`, push into it, else push onto the `<li>`\" —\n * and stripping one has to find that tail again. Read the trailing\n * wrap-emitted `\\n` as the tail and the `<p>` path is bypassed in one case\n * and the wrong node stripped in the other.\n *\n * Lived in two copies until 2.5.2 (core's aggregate footer and the engine's\n * body extractor), one on each side of the 2.3.0 package split.\n */\nexport function lastMeaningfulIdx(children: ElementContent[]): number {\n for (let i = children.length - 1; i >= 0; i--) {\n if (!isWhitespaceText(children[i])) return i;\n }\n return -1;\n}\n","/**\n * Source-offset attribution for top-level hast children.\n *\n * hast positions alone cannot delimit a frozen prefix: rehype-katex\n * replaces a math block with a position-less span (and other plugins can\n * do the same), and mdast-util-to-hast's root `wrap()` interleaves\n * position-less `'\\n'` text separators. Each top-level hast child is\n * therefore attributed a source offset:\n *\n * - its own `position.start.offset` when present;\n * - otherwise the start of the first top-level MDAST child at or after the\n * running cursor (top-level mdast children always carry positions — this\n * mirrors blockMemo's source-offset lookup);\n * - the synthetic footnote section is attributed `Infinity` — it is never\n * freeze-eligible (production handles it via `FootnoteSectionEntry` /\n * `aggregateFootnotesIfLast`, not positional identity).\n *\n * The returned array is non-decreasing except for `Infinity` entries, so\n * \"children attributed before offset b\" is always a prefix of the child\n * list.\n *\n * Extracted from the prefixFreeze experiment's falsification harness\n * (which now imports this module) — the production splice and the\n * experiment must cut prefixes identically or the experiment stops being\n * evidence.\n */\n\nimport type { Root as HastRoot } from 'hast';\nimport type { Root as MdastRoot } from 'mdast';\n\nimport { isFootnoteSection } from '../hastPredicates';\n\nexport function attributeHastChildren(mdast: MdastRoot, hast: HastRoot, stopAt = Infinity): number[] {\n const mdastStarts: number[] = [];\n for (const child of mdast.children) {\n const off = child.position?.start?.offset;\n if (off !== undefined) mdastStarts.push(off);\n }\n let cursor = 0;\n let mdastIdx = 0;\n // `stopAt` truncates the walk once attribution reaches the boundary —\n // the splice consumer only reads the prefix, and top-level attribution\n // is non-decreasing (E5).\n const out: number[] = [];\n for (let i = 0; i < hast.children.length; i++) {\n const attr = attributeOne(hast.children[i], hast.children[i + 1]);\n out.push(attr);\n if (attr >= stopAt) break;\n }\n return out;\n\n function attributeOne(child: HastRoot['children'][number], next?: HastRoot['children'][number]): number {\n const start = child.position?.start?.offset;\n const end = child.position?.end?.offset;\n if (start !== undefined && start !== null) {\n cursor = Math.max(cursor, end ?? start);\n return start;\n }\n if (child.type === 'element' && isFootnoteSection(child)) return Infinity;\n // The footer's PRECEDING '\\n' is footer plumbing appended after wrap()\n // (footer.js pushes `'\\n', <section>`), not a wrap gap slot — pin it to\n // the section's Infinity so the prefix cut never absorbs it.\n if (child.type === 'text' && next?.type === 'element' && isFootnoteSection(next)) return Infinity;\n while (mdastIdx < mdastStarts.length && mdastStarts[mdastIdx] < cursor) mdastIdx += 1;\n return mdastIdx < mdastStarts.length ? mdastStarts[mdastIdx] : cursor;\n }\n}\n","/**\n * React-free state machine for incremental (prefix-freeze) parsing.\n *\n * Given the previous frame's state and the current content, either splice\n * a frozen prefix with a tail-only parse or run the full pipeline. Every\n * gate failure degrades to the full path — the caller cannot observe a\n * difference except through `usedIncremental` and the dev-only stage\n * timings. The splice output is deep-equal to a full parse (the\n * splice-equivalence arbiter test enforces this; see spliceParse.ts).\n *\n * Gate order (first failure wins):\n * - G0 depsKey identity — the parse inputs beyond `content` (plugin\n * arrays, remark-rehype options, handlers, documentId, …) must be\n * identical to the previous frame's. This intentionally covers MORE\n * than the component's G3 12-dep flush (e.g. `preserveOrphanReferences`\n * flips reach the handlers without touching any G3 field).\n * - G1 append — `content.startsWith(prev.content)`; equal content returns\n * the previous trees unchanged. Non-append rewrites (including Stage-A\n * preprocessor rewrites near the stream end) land here.\n * - G3 boundary — `b = min(computeFreezeBoundary(content), prev.stableBoundary)`\n * must be > 0. The `min` with the PREVIOUS frame's boundary is\n * load-bearing, not defensive: the freshly computed boundary proves\n * stability of the CURRENT parse's prefix, but the splice reuses the\n * PREVIOUS parse's nodes — e.g. a shortcut ref rendered literal last\n * frame must not be frozen the moment its definition arrives and the\n * fresh boundary jumps past it. `prev.stableBoundary` is exactly the\n * \"stable under all future appends\" property for prev's nodes.\n * - G4 straddle (defensive) — no prev top-level mdast child may cross the\n * boundary; the detector's blockers should already prevent this.\n *\n * (v1's G2 footnote bypass is GONE. Footnotes splice via INJECTION REPLAY:\n * the prefix's footnote event sequence — defs and refs ×count, in document\n * order, collected from prev.mdast — is prepended to the tail source, so\n * the tail run's mdast-util-to-hast state (footnoteOrder / footnoteCounts /\n * footnoteById) is seeded exactly and its footer regenerates the WHOLE\n * document's section; the injected nodes are stripped from both trees and\n * the footer's positions are rewritten by the dual rule in spliceParse.\n * Prefix inline hast is naturally stable — numbering is first-reference\n * order, which appends cannot change for the prefix. The detector's\n * reference taint (footnote namespace) keeps unresolved `[^x]` out of the\n * frozen prefix, C0-probe + arbiter verified.)\n *\n * `nextState.stableBoundary` is written on BOTH paths from the same single\n * boundary computation.\n */\n\nimport type { Root as HastRoot } from 'hast';\nimport type { Root as MdastRoot } from 'mdast';\n\nimport { parseStage, transformStage, type PipelineOptions as MarkdownOptions } from '../markdown';\nimport { computeFreezeBoundary, type FreezeScanCheckpoint } from './computeFreezeBoundary';\nimport {\n buildInjectionPrefix,\n collectPrefixInjection,\n spliceTrees,\n tailMentionsTerminator,\n type CachedInjectionPlan,\n} from './spliceParse';\n\nexport interface IncrementalParseState {\n /** The CHUNK's own text — excludes the phantom suffix. */\n content: string;\n /** The phantom suffix this state's trees were parsed with ('' standalone). */\n phantomSuffix: string;\n /** Post-transform trees (transformStage mutates mdast in place; these are\n * the settled shapes) — of `content + phantomSuffix`. */\n mdast: MdastRoot;\n hast: HastRoot;\n /** Scan boundary at the frame that produced these trees. */\n stableBoundary: number;\n /** Detector resume state: append frames re-lex only past the confirmed\n * prefix instead of the whole document (E2). Single-consumer mutable —\n * owned by this state lineage. */\n scanCheckpoint: FreezeScanCheckpoint | null;\n /** Injection-plan resume state: events derive from (content, positions)\n * alone, so within an append lineage only children past the cached\n * boundary need visiting (final-review R3 — without this the plan walk\n * re-visits the entire frozen prefix every splice frame). Null until the\n * first splice frame; carried verbatim across full-path append frames. */\n injectionPlan: CachedInjectionPlan | null;\n /** Identity tuple of every parse input beyond `content` (G0). */\n depsKey: readonly unknown[];\n}\n\nexport type IncrementalStage = 'scan' | 'parse' | 'transform';\n\nexport interface AdvanceOptions {\n remarkPlugins: MarkdownOptions['remarkPlugins'];\n rehypePlugins: MarkdownOptions['rehypePlugins'];\n /** The FULLY-MERGED remark-rehype options (handlers, clobberPrefix, …) —\n * exactly what the full path would pass to parseStage. */\n remarkRehypeOptions: MarkdownOptions['remarkRehypeOptions'];\n depsKey: readonly unknown[];\n /** Whether remark-definition-list is active (`enginePlugins` includes `definitionList`). */\n defListEnabled: boolean;\n /** Cross-chunk phantom-definition suffix (coordinated mode) — appended to\n * the parse input but NEVER frozen: the append gate, boundary scan, and\n * prefix cut all see `content` alone, and the suffix re-parses with the\n * tail every frame. It may shrink/grow/reorder between frames (registry\n * label churn) without invalidating the frozen prefix — the reference\n * taint keeps every phantom-resolved ref in the tail (a phantom's def is\n * never IN `content`, so such refs never settle). '' when standalone. */\n phantomSuffix?: string;\n /** Optional stage-timing wrapper (the component passes measureStage). */\n measure?: <T>(stage: IncrementalStage, fn: () => T) => T;\n}\n\nexport interface AdvanceResult {\n mdast: MdastRoot;\n hast: HastRoot;\n usedIncremental: boolean;\n /** The boundary the splice used (0 on the full path). */\n boundary: number;\n nextState: IncrementalParseState;\n}\n\nconst identityMeasure = <T>(_stage: IncrementalStage, fn: () => T): T => fn();\n\nfunction depsKeyEqual(a: readonly unknown[], b: readonly unknown[]): boolean {\n return a.length === b.length && a.every((value, i) => value === b[i]);\n}\n\nfunction runPipeline(source: string, options: AdvanceOptions): { mdast: MdastRoot; hast: HastRoot } {\n const measure = options.measure ?? identityMeasure;\n const parsed = measure('parse', () =>\n parseStage({\n children: source,\n remarkPlugins: options.remarkPlugins,\n rehypePlugins: options.rehypePlugins,\n remarkRehypeOptions: options.remarkRehypeOptions,\n })\n );\n const hast = measure('transform', () => transformStage(parsed));\n return { mdast: parsed.mdast, hast };\n}\n\nexport function advanceIncrementalParse(\n prev: IncrementalParseState | null,\n content: string,\n options: AdvanceOptions\n): AdvanceResult {\n const measure = options.measure ?? identityMeasure;\n const phantomSuffix = options.phantomSuffix ?? '';\n const sameDeps = prev !== null && depsKeyEqual(prev.depsKey, options.depsKey);\n\n // Zero-scan short-circuit — identical content AND suffix reuse the whole\n // previous state verbatim (registry version bumps, unrelated re-renders).\n // A suffix-only change falls through: the scan resume over unchanged\n // content is ~free, and the tail (which always contains the suffix)\n // re-parses with the new one.\n if (sameDeps && content === prev!.content && phantomSuffix === prev!.phantomSuffix) {\n return {\n mdast: prev!.mdast,\n hast: prev!.hast,\n usedIncremental: true,\n boundary: prev!.stableBoundary,\n nextState: prev!,\n };\n }\n const appendOnly = sameDeps && content.startsWith(prev!.content);\n\n // Every remaining frame scans ONCE (fence-aware). Full-path frames\n // consume the scan on the NEXT frame via `prev.stableBoundary`.\n // Append frames resume the detector from its confirmed-prefix checkpoint\n // instead of re-lexing the whole document (E2); everything else scans\n // fresh. The checkpoint is mutable and single-consumer — this state\n // lineage owns it.\n const scan = measure('scan', () =>\n computeFreezeBoundary(content, { defListEnabled: options.defListEnabled }, appendOnly ? prev!.scanCheckpoint : null)\n );\n const freshBoundary = scan.boundary;\n\n // Carried across full-path append frames; refreshed on splice frames\n // (where the plan walk actually runs). Non-append lineages start over.\n let injectionPlan: CachedInjectionPlan | null = appendOnly ? prev!.injectionPlan : null;\n\n const finish = (mdast: MdastRoot, hast: HastRoot, usedIncremental: boolean, boundary: number): AdvanceResult => ({\n mdast,\n hast,\n usedIncremental,\n boundary,\n nextState: {\n content,\n phantomSuffix,\n mdast,\n hast,\n stableBoundary: freshBoundary,\n scanCheckpoint: scan.checkpoint,\n injectionPlan,\n depsKey: options.depsKey,\n },\n });\n\n const fullPath = (): AdvanceResult => {\n const { mdast, hast } = runPipeline(content + phantomSuffix, options);\n return finish(mdast, hast, false, 0);\n };\n\n // G0 + G1 (scan already ran — its result seeds nextState either way)\n if (!appendOnly) return fullPath();\n // G3\n const boundary = Math.min(freshBoundary, prev!.stableBoundary);\n if (boundary <= 0) return fullPath();\n // G4 (defensive) — deliberately a FULL scan, no ordered-children early\n // break: this is the gate that catches ordering/straddle violations, so\n // it must not share the assumption it defends against (round-2 review).\n // O(top-level children) per frame is noise next to the tail parse.\n for (const child of prev!.mdast.children) {\n const start = child.position?.start?.offset;\n const end = child.position?.end?.offset;\n if (start !== undefined && end !== undefined && start < boundary && end > boundary) {\n return fullPath();\n }\n }\n\n // The one input class where the injection's synthetic terminator label\n // could change how the tail parses: the tail literally mentioning it.\n // Checked on the PRE-injection tail (the injection itself contains the\n // label). Pathological by construction — correctness over splice rate.\n const tailAndSuffix = content.slice(boundary) + phantomSuffix;\n if (tailMentionsTerminator(tailAndSuffix)) return fullPath();\n\n const plan = collectPrefixInjection(prev!.mdast, prev!.content, boundary, injectionPlan);\n if (plan.cacheable !== false) {\n injectionPlan = { boundary, events: plan.events, uninjectable: plan.uninjectable };\n }\n // A nested definition/footnote-def that cannot be re-injected verbatim —\n // take the full path this frame rather than splice without it (A3).\n if (plan.uninjectable) return fullPath();\n const injection = buildInjectionPrefix(plan.events);\n const tailSource = injection.text + tailAndSuffix;\n const tail = runPipeline(tailSource, options);\n const spliced = spliceTrees({\n prevMdast: prev!.mdast,\n prevHast: prev!.hast,\n tailMdast: tail.mdast,\n tailHast: tail.hast,\n content,\n boundary,\n injectionPrefix: injection.text,\n injectedSegments: injection.segments,\n });\n // null = the prefix/tail hast layout fell outside the alignment model —\n // full parse this frame (safe, one-frame cost).\n if (spliced === null) return fullPath();\n return finish(spliced.mdast, spliced.hast, true, boundary);\n}\n","/**\n * TEST/STORY helper (exported from the package barrel for the Storybook\n * streams): prefix\n * snapshots sliced at CODE-POINT granularity, so a frame boundary never\n * splits a surrogate pair. Every streaming verifier in the repo — the\n * splice-equivalence arbiter, the prefixFreeze experiment harness, and the\n * Storybook smoke/playground streams — derives its frame sequence from\n * this one implementation; a change here (e.g. moving to grapheme\n * clusters) changes them all together instead of leaving four copies to\n * drift (review finding R4).\n */\nexport function codePointSnapshots(payload: string, chunkSize: number): string[] {\n const codePoints = Array.from(payload);\n const snapshots: string[] = [];\n for (let i = chunkSize; i < codePoints.length; i += chunkSize) {\n snapshots.push(codePoints.slice(0, i).join(''));\n }\n snapshots.push(payload);\n return snapshots;\n}\n","/**\n * Lightweight def-only parse: runs a minimal unified pipeline\n * (remark-parse + remark-gfm) to extract identifiers of all\n * `footnoteDefinition` and `definition` nodes from a markdown source string.\n *\n * Used by PASS 0 of cross-chunk coordination to discover label sets without\n * triggering the full to-hast pipeline. Output is normalized via normalizeId\n * (uppercase, whitespace-collapsed) — same canonical form used everywhere in\n * the registry, phantomFootnoteLabels Set, and handler comparisons.\n *\n * @module components/collectDefLabels\n */\nimport { unified } from 'unified';\nimport remarkParse from 'remark-parse';\nimport remarkGfm from 'remark-gfm';\nimport { visit } from 'unist-util-visit';\nimport type { Root as MdastRoot } from 'mdast';\nimport { normalizeId } from './normalizeId';\nimport { computeFreezeBoundary, type FreezeScanCheckpoint } from './incrementalParse/computeFreezeBoundary';\n\n/**\n * The scanner's freeze-boundary grammar profile. `mathFlow: false` because\n * this module's PINNED pipeline (remark-parse + remark-gfm) has no\n * remark-math — `$$` is paragraph text here, and the engine's math\n * masking would hide comment/fence opens from the balance scan (ghost-def\n * counterexample, Phase B design review). `referenceTaint: false` because\n * only definition IDENTITIES matter to PASS 0 — a block-level fact\n * independent of inline reference resolution — and taint would collapse\n * the boundary to the body's first citation exactly while a def footer\n * streams. The engine's soak battery does not cover this switch\n * combination; the replay/property/fuzz suites in collectDefLabels.test.ts\n * are its safety net.\n */\nconst SCANNER_BOUNDARY_PROFILE = { defListEnabled: false, mathFlow: false, referenceTaint: false } as const;\n\nexport interface DefLabels {\n footnoteLabels: Set<string>;\n linkLabels: Set<string>;\n}\n\n// Build helper kept as its own function so the cached processor's type is\n// inferred as the FULL chained Processor (remark-parse + remark-gfm), not\n// the bare `unified()` Processor with `undefined` extension types.\n//\n// NOTE: PASS 0 deliberately pins remark-parse + remark-gfm and ignores the\n// pipeline's user remarkPlugins. The append-aware scanner below encodes\n// grammar facts about exactly this plugin set — \"definitions never cross a\n// blank line\", \"a definition's `[` sits at a line's content start\". If\n// this processor ever grows plugins whose def-like constructs violate\n// those facts (directives, MDX, multi-line containers), the scanner's\n// fast path must be revisited: its replay tests only lock today's grammar.\nfunction buildProcessor() {\n return unified().use(remarkParse).use(remarkGfm);\n}\nlet _processor: ReturnType<typeof buildProcessor> | null = null;\nfunction processor(): ReturnType<typeof buildProcessor> {\n if (!_processor) _processor = buildProcessor();\n return _processor;\n}\n\nexport function collectDefLabels(source: string): DefLabels {\n if (!source) {\n return { footnoteLabels: new Set(), linkLabels: new Set() };\n }\n const mdast = processor().parse(source) as MdastRoot;\n const footnoteLabels = new Set<string>();\n const linkLabels = new Set<string>();\n visit(mdast, (node) => {\n if (node.type === 'footnoteDefinition' && 'identifier' in node) {\n footnoteLabels.add(normalizeId(node.identifier as string));\n } else if (node.type === 'definition' && 'identifier' in node) {\n linkLabels.add(normalizeId(node.identifier as string));\n }\n });\n return { footnoteLabels, linkLabels };\n}\n\nconst setsEqual = (a: Set<string>, b: Set<string>): boolean => {\n if (a.size !== b.size) return false;\n for (const v of a) if (!b.has(v)) return false;\n return true;\n};\n\n/** Blank line (whitespace-only), the boundary no definition can span.\n * CRLF-aware on both newlines — without `\\r?` a CRLF document never\n * matches, the region silently becomes the whole source, and the fast\n * path is vacuously off for that entire input class. */\nconst BLANK_LINE_RE = /\\r?\\n[ \\t]*\\r?\\n/g;\n\n/** Index just past the LAST blank line of `source`, or 0 if none.\n * Plain non-overlapping scan: for runs of blanks (\"\\n\\n\\n\") this can land\n * a newline or two early, but the slack is whitespace-only and whitespace\n * can never satisfy DEF_LINE_START_RE, so the decision is identical.\n * @internal exported for tests only (module path — not on the package barrel) — the fast path is otherwise\n * indistinguishable from a full parse whose sets came out equal. */\nexport function lastRegionStart(source: string): number {\n BLANK_LINE_RE.lastIndex = 0;\n let start = 0;\n for (let m = BLANK_LINE_RE.exec(source); m !== null; m = BLANK_LINE_RE.exec(source)) {\n start = m.index + m[0].length;\n }\n return start;\n}\n\n/** A line that can START a definition, matched by the FULL def signature:\n * container prefixes (blockquote `>`, list bullets, ordered-list digits),\n * then `[label]` with the closing bracket IMMEDIATELY followed by `:` —\n * remark accepts a definition only with that adjacency (grammar-verified:\n * `[x]\\n: url` and `[x] : url` are paragraphs, and `[a][b]: url` is a\n * reference because the label's first unescaped `]` isn't followed by\n * `:`). The label alternation admits escape pairs (`\\]` stays inside the\n * label) and spans newlines (labels may soft-wrap; they cannot cross the\n * blank line that bounds the region). Both alternatives are disjoint, so\n * the scan is linear — no backtracking blowup on bracket-dense regions.\n *\n * Requiring the signature (not just a line-start `[`) is what keeps the\n * streaming-heavy shapes — bulleted link lists `- [t](u)`, task boxes\n * `- [x]`, reference lists `- [a][b]` — on the fast path; a bracket-only\n * probe made every append inside a blank-line-free link list pay a full\n * reparse (the measured Documents+smooth cliff). An INCOMPLETE def line\n * (`[x` with `]:` still in flight) correctly stays on the fast path too:\n * the parser sees no definition in it either, and the region re-check on\n * the completing append flips to the full parse exactly when the answer\n * can change. The `m` flag also matches at index 0, which is a true line\n * start (the region begins just past a blank line or at the document\n * start). Residual over-matching (e.g. `[x]:` inside an open code fence)\n * is safe: it costs a redundant full parse, never a wrong result.\n * @internal exported for tests only (module path — not on the package barrel). */\nexport const DEF_LINE_START_RE = /^[ \\t>*+\\d.)-]*\\[(?:[^\\]\\\\]|\\\\[\\s\\S])*\\]:/m;\n\nexport interface DefLabelScanner {\n /** Equivalent to `collectDefLabels(source)` at every call, but cheap for\n * the streaming common case. Returns a REFERENCE-STABLE result while the\n * label set is unchanged. */\n scan(source: string): DefLabels;\n}\n\n/**\n * Append-aware wrapper around {@link collectDefLabels} for the streaming\n * hot path: PASS 0 re-runs on every token, but its result — the def label\n * set — almost never changes while prose streams in.\n *\n * Fast path: when the new source merely APPENDS to the previous one, the\n * label set can only differ if the affected region contains a line-start\n * `[label]:` def signature (see DEF_LINE_START_RE — mid-line brackets,\n * bulleted links, task boxes and reference lists all lack the adjacent\n * `]:` and stay on the fast path). That region is the previous source's\n * text SINCE ITS LAST BLANK LINE plus the appended text — not just the\n * appended text, because CommonMark definitions span lines (`[x]:` with\n * the destination on the next line) and a trailing append can re-type an\n * entire paragraph (setext `===`). No construct that produces or destroys\n * a definition crosses a blank line (labels, destinations and titles all\n * forbid them), so text before that boundary is settled. When the region\n * has no def-capable line, the previous result is returned AS-IS;\n * otherwise (and for any non-append change) a full re-parse runs, and the\n * previous result object is kept whenever the recomputed sets are equal.\n *\n * Misjudging conservatively (an unnecessary `[` hit — e.g. inside an open\n * code fence) only costs a redundant full parse, never a wrong result.\n *\n * The reference stability doubles as churn control: consumers that list\n * the result in effect deps (chunk re-registration) stop firing per token.\n *\n * @param parse Full-parse fallback — injectable so tests can COUNT parses\n * and assert the fast path actually fires (from the outside, a skipped\n * parse is indistinguishable from a parse whose sets came out equal).\n * Production callers never pass it.\n */\nexport function createDefLabelScanner(parse: (source: string) => DefLabels = collectDefLabels): DefLabelScanner {\n let prevSource: string | null = null;\n let prevLabels: DefLabels | null = null;\n // Frozen-prefix cache (Phase B): labels extracted from the region before\n // `frozenEnd` are FINAL — the freeze boundary guarantees every block\n // beginning before it parses byte-identically under any future append,\n // so a def there can neither appear nor disappear. The checkpoint makes\n // the boundary scan O(new lines) per call; it belongs to this scanner's\n // single append-only lineage (non-append resets it).\n let frozenEnd = 0;\n let frozenFootnotes = new Set<string>();\n let frozenLinks = new Set<string>();\n let checkpoint: FreezeScanCheckpoint | null = null;\n\n const resetFrozen = () => {\n frozenEnd = 0;\n frozenFootnotes = new Set();\n frozenLinks = new Set();\n checkpoint = null;\n };\n\n return {\n scan(source: string): DefLabels {\n let isAppend = false;\n if (prevSource !== null && prevLabels !== null) {\n if (source === prevSource) return prevLabels;\n if (source.startsWith(prevSource)) {\n isAppend = true;\n const regionStart = lastRegionStart(prevSource);\n // Joined so a def line straddling the append boundary keeps its\n // line-start context.\n const region = prevSource.slice(regionStart) + source.slice(prevSource.length);\n if (!DEF_LINE_START_RE.test(region)) {\n prevSource = source;\n return prevLabels;\n }\n }\n }\n // Slow path — the region really may contain a definition. Advance the\n // frozen prefix as far as the boundary allows, then parse ONLY the\n // live tail instead of the whole document.\n if (!isAppend && prevSource !== null) resetFrozen();\n const scanResult = computeFreezeBoundary(source, SCANNER_BOUNDARY_PROFILE, isAppend ? checkpoint : null);\n checkpoint = scanResult.checkpoint;\n // An older freeze is permanently valid — never move backwards even if\n // a later scan reports a smaller boundary (over-blocking direction).\n const boundary = Math.max(scanResult.boundary, frozenEnd);\n if (boundary > frozenEnd) {\n const slice = source.slice(frozenEnd, boundary);\n // The slice can only add labels if it contains a def signature —\n // the same probe that gates the slow path.\n if (DEF_LINE_START_RE.test(slice)) {\n const sliceLabels = parse(slice);\n for (const label of sliceLabels.footnoteLabels) frozenFootnotes.add(label);\n for (const label of sliceLabels.linkLabels) frozenLinks.add(label);\n }\n frozenEnd = boundary;\n }\n const tailSource = source.slice(frozenEnd);\n const tail = DEF_LINE_START_RE.test(tailSource)\n ? parse(tailSource)\n : { footnoteLabels: new Set<string>(), linkLabels: new Set<string>() };\n const next: DefLabels = {\n footnoteLabels: new Set([...frozenFootnotes, ...tail.footnoteLabels]),\n linkLabels: new Set([...frozenLinks, ...tail.linkLabels]),\n };\n if (\n prevLabels !== null &&\n setsEqual(next.footnoteLabels, prevLabels.footnoteLabels) &&\n setsEqual(next.linkLabels, prevLabels.linkLabels)\n ) {\n prevSource = source;\n return prevLabels;\n }\n prevSource = source;\n prevLabels = next;\n return next;\n },\n };\n}\n","/**\n * CommonMark §4.7 label normalization. Used as the single canonical form\n * for all label-keyed structures (registry maps, phantomFootnoteLabels Set,\n * labelSet, etc.) and for handler comparisons against mdast-util-to-hast's\n * internal `state.definitionById` / `state.footnoteById` keys.\n *\n * Delegates to micromark's own `normalizeIdentifier` (collapse\n * `[\\t\\n\\r ]+` runs to one space, STRIP leading/trailing whitespace, then\n * `toLowerCase().toUpperCase()` Unicode case folding) so the result is\n * byte-identical to mdast-util-to-hast's key\n * (`String(identifier).toUpperCase()`, where `identifier` is already\n * micromark-normalized). An earlier hand-rolled version skipped the trim\n * (and used `\\s`, which also folds NBSP): a placeholder carrying the\n * ORIGINAL source label (`[ foo ]`, or `[foo\\nbar]` broken at a soft line\n * ending) looked up `' FOO '` while the def was keyed `'FOO'` — every\n * padded reference fell back to literal text in coordinated mode only\n * (2026-08 project review, eng-stream-01).\n *\n * @module components/normalizeId\n */\nimport { normalizeIdentifier } from 'micromark-util-normalize-identifier';\n\nexport function normalizeId(s: string): string {\n return normalizeIdentifier(s);\n}\n\n/**\n * The form of raw chunk SOURCE that the PASS 0.5 substring pre-check compares\n * registry labels against. It is exactly {@link normalizeId}: micromark's\n * `identifier` (what the registry keys are built from) is the label's\n * source bytes with backslashes KEPT (`[^a\\*b]` → `a\\*b`; only the `label`\n * field is unescaped), so the source must NOT be unescaped before matching\n * — an unescaping pass made every label holding an escaped punctuation\n * character miss the pre-check for good, and the cross-chunk reference\n * rendered as literal `[text][label]` (2026-08-19 review r2 P2-5; the\n * 2.4.5 narrowing to ASCII punctuation kept the wrong premise). Kept as a\n * named export for API stability.\n */\nexport function normalizeForMatch(s: string): string {\n return normalizeIdentifier(s);\n}\n","/**\n * Extract footnote-definition bodies from a chunk's POST-pipeline hast tree.\n *\n * Why not just `toHast(def.children)` in extractContributions? That call runs\n * only mdast-util-to-hast's default handlers — no rehype-katex, no rehype-raw,\n * no rehype-footer-adorn, no clobber-prefix application. Defs containing math\n * (`$x$`), inline raw HTML, or definition-list extensions would render\n * incorrectly inside the cross-chunk aggregate footer.\n *\n * Instead, we read the FINAL hast: mdast-util-to-hast's `state.footer()` has\n * already emitted `<section data-footnotes><ol><li id=\"...fn-X\">body</li>…`\n * for every def that has a real entry in `state.footnoteOrder`, the full\n * rehype chain has run on top, and the per-`<li>` body is exactly what the\n * standalone path would render. Lift those `<li>` children (minus the\n * auto-emitted backref `<a>`s, which the aggregate emits itself per\n * occurrence) and key by normalized label.\n *\n * Chunks whose only refs are phantom-injected (cross-chunk) won't have a\n * synthetic `<section>` at all — those chunks contribute no defs, and the\n * canonical-chunk handler upstream guarantees the def's body is captured\n * from the chunk that owns it.\n *\n * @module components/extractDefBodiesFromHast\n */\nimport { SKIP, visit } from 'unist-util-visit';\nimport type { Element as HastElement, Root as HastRoot, ElementContent } from 'hast';\nimport { normalizeUri } from 'micromark-util-sanitize-uri';\nimport { normalizeId } from './normalizeId';\nimport { isWhitespaceText, lastMeaningfulIdx } from './hastPredicates';\n\n// Fallback for callers that do not know the exact clobberPrefix. The main\n// renderer passes the prefix explicitly so labels containing regex metacharacters\n// or prefixes containing `user-content-fn-` are handled by string slicing.\nconst FN_LI_ID_RE = /(?:^|-)user-content-fn-(.+)$/;\n\n/**\n * The id fragment mdast-util-to-hast derives from a footnote identifier for\n * `fn-…` / `fnref-…` (`normalizeUri(identifier.toLowerCase())` — percent-\n * encodes non-ASCII, whitespace and URL-unsafe punctuation). Every place\n * that MINTS a footnote id — the standalone footer (upstream), the\n * cross-chunk marks and the aggregate footer — must use this same\n * encoding, or a mark's `href` and its `<li id>` disagree (v2.4.0 review:\n * the fallback mark wrote the raw label while the local footer was\n * encoded; `[^注]` / `[^a%b]` anchors broke).\n */\nexport function footnoteSafeId(identifier: string): string {\n return normalizeUri(identifier.toLowerCase());\n}\n\n/**\n * Extract the SOURCE identifier from a footnote `<li>` id, covering both id\n * shapes in the codebase — standalone (mdast-util-to-hast `fn-` +\n * `normalizeUri`, then the sanitize clobber + rehypeRebaseHashLinks linkage)\n * and aggregate (`${clobberPrefix}fn-${sourceIdentifier}`, raw). Exported as\n * the single source of truth for li-id parsing: the streaming cursor's\n * anchor targeting (`detectAnchor`) reuses it so a clobber-linkage change\n * can never drift the two consumers apart.\n */\nexport function sourceIdFromFootnoteLiId(idProp: string, clobberPrefix?: string): string | null {\n let raw: string | null = null;\n if (clobberPrefix !== undefined) {\n const exactPrefix = `${clobberPrefix}fn-`;\n if (idProp.startsWith(exactPrefix)) raw = idProp.slice(exactPrefix.length);\n }\n if (raw === null) {\n const m = idProp.match(FN_LI_ID_RE);\n raw = m ? m[1] : null;\n }\n if (raw === null) return null;\n // mdast-util-to-hast's footer emits `<li id=\"${prefix}fn-${normalizeUri(id)}\">`\n // which percent-encodes whitespace, non-ASCII characters (`中文` → `%E4%B8%AD…`),\n // and most URL-unsafe punctuation. The registry's def key (set by\n // extractContributions via `normalizeId(node.identifier)`) is the DECODED\n // form — uppercase + whitespace-collapsed but otherwise the source bytes.\n // Without decoding here, every label that triggers normalizeUri encoding\n // (CJK, accented Latin, spaces, `&`/`?` punctuation) would key-mismatch\n // between harvested body and registry def, leaving the aggregate footer's\n // `<li>` empty for those labels.\n try {\n return decodeURIComponent(raw);\n } catch {\n // Malformed percent-encoding (extremely rare — would require user-\n // supplied raw HTML in the def's id). Fall back to the raw form rather\n // than crashing the harvest. The raw form will key-mismatch the registry\n // def, so the aggregate footer's `<li>` renders empty for this label —\n // surface that in development instead of failing silently.\n // Bare env access on purpose — the dual dev/prod build resolves it at\n // build time, so dist never evaluates it. The previous `typeof process`\n // guard was dead in bundler browser dev (Vite substitutes only the bare\n // text, `typeof process` stays 'undefined'); do not reintroduce it.\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n `[ai-react-markdown] Malformed percent-encoding in footnote id \"${raw}\"; ` +\n 'its body may be missing from the aggregated footnote footer.'\n );\n }\n return raw;\n }\n}\n\nfunction isBackrefAnchor(c: ElementContent): boolean {\n if (c.type !== 'element') return false;\n const el = c as HastElement;\n if (el.tagName !== 'a') return false;\n return Boolean(el.properties && 'dataFootnoteBackref' in el.properties);\n}\n\n/**\n * Drop trailing auto-emitted backref anchors and any separator whitespace\n * mdast-util-to-hast emitted before them. Operates only on the tail of\n * `children` — does NOT recurse into mid-list elements — so user content\n * elsewhere in the def that happens to look like a backref anchor survives.\n *\n * The shapes we have to undo (see `mdast-util-to-hast/lib/footer.js`):\n *\n * - **trailing wrap whitespace**: `state.wrap(content, true)` inserts\n * `\\n` text nodes between/around block-level children of `<li>`. The\n * auto-emitted backref sits BEFORE the trailing `\\n`, so we have to\n * peel past whitespace before checking for the backref. Confirmed by\n * a real-pipeline trace: an empty def produces\n * `<li>` children = `[\"\\n\", <a backref>, \"\\n\"]`.\n * - **standalone separator** between consecutive backrefs (and before\n * the first one when the trailing child is NOT a text node): a `{type:\n * 'text', value: ' '}` element pushed alongside the backref anchor.\n * - **merged separator** before the first backref when the trailing\n * child IS a text node: footer.js does `tailTail.value += ' '`, so the\n * leading space is concatenated INTO the existing text node rather\n * than pushed as a separate node. After peeling the backrefs, that\n * residual trailing space sits at the end of the last text node and\n * would visibly double when the aggregate footer prepends its own\n * separator. Trim exactly one trailing space to undo it.\n */\nfunction dropTrailingBackrefs(children: ElementContent[]): ElementContent[] {\n // Step 1: identify trailing whitespace-only text nodes. Preserve them\n // verbatim in the output — they're semantically part of mdast-util-to-\n // hast's expected shape and downstream serializers may rely on them.\n let trailingWsStart = children.length;\n while (trailingWsStart > 0 && isWhitespaceText(children[trailingWsStart - 1])) {\n trailingWsStart--;\n }\n // Step 2: scan backwards from the last non-whitespace child, peeling\n // backref anchors and their inter-backref `' '` separators.\n let scan = trailingWsStart;\n let peeledAny = false;\n while (scan > 0) {\n const t = children[scan - 1];\n if (!isBackrefAnchor(t)) break;\n peeledAny = true;\n scan -= 1;\n if (scan > 0 && children[scan - 1].type === 'text' && (children[scan - 1] as { value: string }).value === ' ') {\n scan -= 1;\n }\n }\n if (!peeledAny) return children;\n const trailing = children.slice(trailingWsStart);\n // Step 3: undo the merged-separator case. Trim exactly ONE trailing\n // space from the last surviving text node (matching footer.js's\n // `+= ' '`). Multiple trailing spaces stay intact — only the one\n // footer.js appended is ours to remove. Whitespace-only text nodes\n // (e.g. `\\n`) don't qualify for trim — they aren't merged separators.\n if (scan > 0) {\n const last = children[scan - 1];\n if (last.type === 'text') {\n const v = (last as { value: string }).value;\n if (v.endsWith(' ') && !/^\\s*$/.test(v)) {\n return [...children.slice(0, scan - 1), { ...last, value: v.slice(0, -1) } as ElementContent, ...trailing];\n }\n }\n }\n return [...children.slice(0, scan), ...trailing];\n}\n\n/**\n * Strip mdast-util-to-hast's auto-emitted backref anchors from a `<li>`\n * body. The library only ever appends backrefs in one of two locations:\n * (a) directly at the end of the `<li>`'s children (after `state.wrap`\n * interleaves whitespace nodes between block-level siblings), OR\n * (b) at the end of the last `<p>` child of the `<li>`.\n * We handle both — and nothing else — to avoid stripping any\n * `data-footnote-backref`-shaped element that happens to live in user\n * content elsewhere in the def body.\n */\nfunction stripBackrefs(liChildren: ElementContent[]): ElementContent[] {\n if (liChildren.length === 0) return liChildren;\n // Look past mdast-util-to-hast's trailing `\\n` text node(s) to find the\n // meaningful tail. That tells us which of the two cases applies.\n const lastIdx = lastMeaningfulIdx(liChildren);\n if (lastIdx < 0) return liChildren;\n const last = liChildren[lastIdx];\n\n // Direct-into-li case (case A): meaningful tail IS the backref. Peel\n // from `<li>` children; dropTrailingBackrefs handles the trailing `\\n`.\n if (isBackrefAnchor(last)) {\n return dropTrailingBackrefs(liChildren);\n }\n\n // Inside-<p> case (case B): meaningful tail is `<p>` and backrefs live\n // inside its inline children. `<p>` itself has no wrap-emitted whitespace\n // (state.wrap only fires for block-level lists), so dropTrailingBackrefs\n // can scan the `<p>`'s children directly. Preserve any trailing\n // whitespace nodes that follow the `<p>` in `<li>` exactly as-is.\n if (last.type === 'element' && (last as HastElement).tagName === 'p') {\n const p = last as HastElement;\n const newPChildren = dropTrailingBackrefs(p.children as ElementContent[]);\n if (newPChildren === p.children) return liChildren;\n return liChildren.map((c, i) => (i === lastIdx ? ({ ...p, children: newPChildren } as ElementContent) : c));\n }\n\n return liChildren;\n}\n\n/**\n * Walk `hast` and return a map from normalized footnote label to the\n * cleaned-up body hast of that label's `<li>`. The body has had any\n * `<a data-footnote-backref>` anchors removed at any nesting depth so the\n * aggregate footer can emit its own per-occurrence backrefs without\n * duplicating the locally-injected one.\n */\n/**\n * Walk a body and clear `localOccurrence` props on any `<footnote-sup>`\n * placeholders we find. NESTED footnote refs inside a def body (`[^x]: see\n * [^y]`) emit placeholders whose `localOccurrence` is keyed to the parsing\n * chunk's `state.footnoteCounts`. When the aggregate footer renders the\n * harvested body under the LAST chunk's `ChunkSymbolContext.Provider`,\n * `globalOccurrenceForRef(lastChunkSym, label, localOccurrence)` resolves\n * against the wrong chunk — returning `null` and short-circuiting the\n * inline sup to render blank.\n *\n * The fix degrades gracefully: strip `localOccurrence` from harvested\n * placeholders so `FootnoteSupNumber` falls through to the\n * \"no occurrence supplied\" path — which renders a sup with the bare\n * `fnref-${label}` href (i.e. the first-occurrence anchor). Backref\n * navigation still works (any occurrence href is valid for \"jump back\");\n * the only loss is occurrence-precision for nested footnote refs in\n * aggregate-rendered bodies, which is an edge case GFM permits but rarely\n * exercised in practice. The PRIMARY render (the originating chunk's own\n * block output) is unaffected — it still has the full localOccurrence\n * resolved against the correct chunk symbol.\n */\nfunction stripLocalOccurrenceFromFootnoteSups(children: ElementContent[]): ElementContent[] {\n let changed = false;\n const out: ElementContent[] = [];\n for (const c of children) {\n if (c.type === 'element') {\n const el = c as HastElement;\n let nextEl: HastElement = el;\n if (el.tagName === 'footnote-sup' && el.properties && 'localOccurrence' in el.properties) {\n const { localOccurrence: _drop, ...rest } = el.properties;\n nextEl = { ...el, properties: rest };\n changed = true;\n }\n // Recurse into element children to catch nested placeholders.\n const newChildren = stripLocalOccurrenceFromFootnoteSups(nextEl.children as ElementContent[]);\n if (newChildren !== nextEl.children) {\n nextEl = { ...nextEl, children: newChildren };\n changed = true;\n }\n out.push(nextEl);\n } else {\n out.push(c);\n }\n }\n return changed ? out : children;\n}\n\nexport function extractDefBodiesFromHast(hast: HastRoot, clobberPrefix?: string): Map<string, ElementContent[]> {\n const out = new Map<string, ElementContent[]>();\n visit(hast, 'element', (sectionNode) => {\n const sec = sectionNode as HastElement;\n if (sec.tagName !== 'section') return;\n if (!(sec.properties && 'dataFootnotes' in sec.properties)) return;\n visit(sec, 'element', (liNode) => {\n const li = liNode as HastElement;\n if (li.tagName !== 'li') return;\n const idProp = li.properties?.id;\n if (typeof idProp !== 'string') return;\n const sourceId = sourceIdFromFootnoteLiId(idProp, clobberPrefix);\n if (sourceId === null) return;\n const normalized = normalizeId(sourceId);\n const stripped = stripBackrefs(li.children as ElementContent[]);\n // Defuse any nested `<footnote-sup>` placeholders whose local\n // occurrence indices belong to a different chunk than where the\n // body will eventually be rendered. See the function's JSDoc.\n out.set(normalized, stripLocalOccurrenceFromFootnoteSups(stripped));\n });\n // SKIP descent into this section's children so a NESTED\n // `<section data-footnotes>` (rare — produced only via user-supplied\n // raw HTML inside a def body that survives rehype-raw + sanitize)\n // isn't double-processed by both the outer visit's recursion and the\n // inner visit's enumeration of its parent. Without the SKIP, an\n // `<li>` inside the nested section is harvested twice; `out.set` is\n // last-write-wins so a nested mutation can stomp a correctly-\n // extracted outer body. SKIP scopes harvest to the outer section\n // and leaves nested footnote sections for whatever tool authored\n // them to handle.\n return SKIP;\n });\n return out;\n}\n","/**\n * Walk an mdast tree and yield ref/def records in source order. Used by\n * AIMarkdownContent's PASS 1 contribute step to populate Registry.chunkData.\n *\n * Phantom definitions (Direction B) carry sentinel content/url but the\n * sentinel parse may not produce exactly the sentinel string at the AST\n * level (e.g. `__aimd_sentinel_fn__` parses as <strong>aimd_sentinel_fn</strong>).\n * Therefore phantom detection is done both ways:\n * - linkDef: check `url === SENTINEL_LINK_URL` (raw string survives parsing).\n * - fnDef: skip if the def's normalized identifier is in the supplied\n * `phantomFootnoteLabels` set. The caller knows which labels it\n * injected (PASS 0.5 `targetPhantoms.missingFootnotes`).\n *\n * @module components/extractContributions\n */\nimport { SKIP, visit } from 'unist-util-visit';\nimport type { Root as MdastRoot } from 'mdast';\nimport { normalizeId } from './normalizeId';\nimport { SENTINEL_LINK_URL } from './remarkInjectPhantomDefs';\n\nexport type Contribution =\n | {\n kind: 'ref';\n refKind: 'footnote' | 'link' | 'image';\n label: string;\n referenceType?: 'full' | 'collapsed' | 'shortcut';\n }\n | { kind: 'fnDef'; label: string; sourceIdentifier: string; content: string }\n | { kind: 'linkDef'; label: string; url: string; title?: string };\n\nexport interface ExtractContributionsOptions {\n /** Already-normalized labels that were phantom-injected at PASS 0.5.\n * Defs matching these are skipped to avoid leaking sentinel rows into\n * registry.chunkData. */\n phantomFootnoteLabels?: Set<string>;\n // NOTE: link-definition URLs are emitted RAW. A former `urlTransform`\n // option applied the caller's transform at contribute time as a\n // \"belt-and-suspenders\" pass; it collapsed a protocol-blocked URL to ''\n // BEFORE the render-time gate could tell blocked (attribute absent) from\n // legally empty (`href=\"\"`), and a rewriting transform ran twice\n // (contribute + render) where standalone runs once. The render-time\n // `sanitizeCrossChunkUrl` gate is the single point of enforcement and\n // mirrors the standalone pipeline exactly (v2.4.2 review P1-4).\n}\n\nexport function* extractContributions(\n mdast: MdastRoot,\n options: ExtractContributionsOptions = {}\n): Generator<Contribution> {\n const phantomFn = options.phantomFootnoteLabels;\n const out: Contribution[] = [];\n visit(mdast, (n) => {\n if (n.type === 'footnoteReference') {\n out.push({\n kind: 'ref',\n refKind: 'footnote',\n label: normalizeId((n as { identifier: string }).identifier),\n });\n } else if (n.type === 'linkReference') {\n const r = n as { identifier: string; referenceType: 'full' | 'collapsed' | 'shortcut' };\n out.push({ kind: 'ref', refKind: 'link', label: normalizeId(r.identifier), referenceType: r.referenceType });\n } else if (n.type === 'imageReference') {\n const r = n as { identifier: string; referenceType: 'full' | 'collapsed' | 'shortcut' };\n out.push({ kind: 'ref', refKind: 'image', label: normalizeId(r.identifier), referenceType: r.referenceType });\n } else if (n.type === 'footnoteDefinition') {\n const d = n as { identifier: string; children: unknown[] };\n const label = normalizeId(d.identifier);\n // Skip phantom-injected (by injected-label set, since the sentinel\n // string may not survive markdown parsing intact).\n if (phantomFn?.has(label)) return SKIP;\n // Best-effort raw content snapshot: stringify the first child's\n // structure. Footnote definitions are typed `(BlockContent | DefinitionContent)[]`\n // so we serialize loosely. Used only as a coarse fingerprint string.\n const content = JSON.stringify(d.children ?? []);\n // d.identifier is mdast's already-case-folded form — the same string\n // mdast-util-to-hast uses in `<li id=\"...fn-${id}\">`. Tracked separately\n // from the uppercase-normalized `label` (used as a dictionary key) so\n // HTML ids built downstream match the inline sup's href byte-for-byte.\n //\n // bodyHast is NOT computed here — see extractDefBodiesFromHast for\n // why we source it from the post-pipeline hast instead.\n out.push({ kind: 'fnDef', label, sourceIdentifier: d.identifier, content });\n // SKIP descent into the def's children: NESTED footnoteReferences /\n // linkReferences / imageReferences inside a def body should NOT\n // count as flow refs. Without this, a def whose body contains\n // `[^x]: see [^a].` would record an extra ref to `a` in registry\n // refs — inflating `globalNumber('a')` (making `a` appear in the\n // aggregate footer even if no flow text references it), and worse,\n // inflating `getRefsForLabel('a')` so the aggregate emits a backref\n // anchor to `#fnref-a-2` that points at an id no inline `<sup>`\n // ever rendered. Trade-off: a footnoteDefinition nested INSIDE\n // another def's body (allowed by GFM but exceedingly rare) is also\n // not extracted; deferred until we see a real use case.\n return SKIP;\n } else if (n.type === 'definition') {\n const d = n as { identifier: string; url: string; title?: string };\n if (d.url === SENTINEL_LINK_URL) return;\n out.push({\n kind: 'linkDef',\n label: normalizeId(d.identifier),\n url: d.url,\n title: d.title,\n });\n }\n });\n for (const c of out) yield c;\n}\n","/**\n * Direction B: source-level phantom-definition injection helpers.\n *\n * @module components/remarkInjectPhantomDefs\n */\n\nimport { computeFreezeBoundary, pendingFenceCloser } from './incrementalParse/computeFreezeBoundary';\n\nexport const SENTINEL_LINK_URL = '__aimd_sentinel_link__';\nexport const SENTINEL_FN_CONTENT = '__aimd_sentinel_fn__';\n\nexport interface PhantomLabels {\n missingFootnotes: Set<string>;\n missingLinks: Set<string>;\n}\n\n/**\n * The phantom-definition SUFFIX for labels not locally defined ('' when\n * there are none). Kept separate from the join so the incremental engine\n * can treat it as always-tail: the suffix may shrink/grow/reorder between\n * frames (registry label churn) without breaking the append gate.\n *\n * Labels are expected to already be normalized via normalizeId (uppercase).\n */\nexport function buildPhantomSuffix(phantoms: PhantomLabels): string {\n if (phantoms.missingFootnotes.size === 0 && phantoms.missingLinks.size === 0) {\n return '';\n }\n let suffix = '\\n\\n';\n for (const label of phantoms.missingLinks) {\n suffix += `[${label}]: ${SENTINEL_LINK_URL}\\n`;\n }\n for (const label of phantoms.missingFootnotes) {\n suffix += `[^${label}]: ${SENTINEL_FN_CONTENT}\\n`;\n }\n return suffix;\n}\n\n/**\n * The bytes to put BETWEEN a chunk's content and its phantom suffix so the\n * suffix's definition lines are parsed as definitions.\n *\n * `buildPhantomSuffix` is appended (never prepended: the incremental engine\n * treats the suffix as an always-tail input, and prepending would shift\n * every source position). But an append lands INSIDE whatever block the\n * content ends in — and a fenced code block or `$$` flow-math block that is\n * still open at the end of a streaming frame swallows everything up to EOF:\n * the sentinel lines render as code/math text and, since no definition was\n * registered, every cross-chunk reference in the chunk falls back to literal\n * `[text][label]` for the whole time the block streams (2026-08 project\n * review, core-render-01). Closing the block first is output-neutral: an\n * unclosed fence/math block already renders exactly the lines it has, so\n * `content + closer` yields the same code/math node value (positions\n * extend past `content.length`, which every consumer already tolerates for\n * the suffix's own nodes).\n *\n * A closer is emitted ONLY for a block whose opener line sits at column 0:\n * that is provably a top-level fence, which only a top-level closer (same\n * char, ≥ length, ≤3 spaces indent) can end — exactly what the line scanner\n * tracks. Openers with any indent are left alone: the line model cannot\n * see container boundaries, and an indented opener may live in a list item\n * that later de-indented content already ended (micromark closed the fence\n * with the item; an emitted closer would OPEN a new fence around the\n * sentinel lines — v2.4.0 review R1) or be closed by a ≥4-space closer the\n * `^ {0,3}` scan does not recognize. Those shapes keep the plain append\n * (swallowed at worst — the pre-2.4.0 behaviour), never a wrong closer.\n *\n * Only fences and flow math are closed. Raw-HTML constructs (`<!--`, `<?`,\n * `<![CDATA[`, `<!X`, `<script>`) that stay open to EOF also swallow the\n * suffix (invisibly — sanitize strips them), but their closers are not\n * position-neutral for the paragraph-inline forms and the shapes are rare\n * in LLM output; they keep the plain-append behaviour. When the scanner's\n * fence/math phase is untrusted (`phasePoisonedAt` — a suppressed open in a\n * container, see computeFreezeBoundary blocker 7) no closer is emitted\n * either: a wrong closer would OPEN a block around the suffix.\n *\n * Returns '' when nothing needs closing. Cost: one line scan of `content`\n * (regex per line; no reference tracking) — only paid by chunks that have a\n * non-empty phantom suffix.\n */\nexport function phantomSuffixCloser(content: string): string {\n if (content === '') return '';\n const endsWithNewline = content.endsWith('\\n');\n // Confirm the trailing partial line: the suffix's own leading newline\n // will, so the state that matters is the one AFTER that line.\n const confirmed = endsWithNewline ? content : content + '\\n';\n const { checkpoint } = computeFreezeBoundary(confirmed, { defListEnabled: false, referenceTaint: false });\n // Phase trust and the column-0-only indent rule are the scanner's calls;\n // `pendingFenceCloser` owns them (the checkpoint shape is opaque here).\n const closer = pendingFenceCloser(checkpoint);\n if (closer === '') return '';\n return endsWithNewline ? closer : `\\n${closer}`;\n}\n","/**\n * Cross-chunk shared state. Holds per-chunk contributions (refs, defs,\n * linkDefs) keyed by Symbol identity allocated via useId reactId, with\n * refcount + microtask-deferred reclamation for React Strict Mode safety.\n *\n * @module components/documentRegistry\n */\n\nimport type { ElementContent as HastElementContent } from 'hast';\nimport { normalizeId } from './normalizeId';\n\nexport interface FootnoteDef {\n /** Already-normalized identifier (uppercase). Used as dictionary key for\n * case-insensitive cross-chunk lookups. */\n identifier: string;\n /** mdast's case-folded identifier — the exact string mdast-util-to-hast\n * emits in `<li id=\"${clobberPrefix}fn-${sourceIdentifier}\">` and that\n * `FootnoteSupNumber` mirrors in its anchor href. Needed so the aggregate\n * footer's `<li id>` and backref href match the inline `<sup>`'s href\n * exactly (otherwise hash navigation breaks). Optional so unit-test\n * fixtures don't need to fabricate it; production data always supplies it. */\n sourceIdentifier?: string;\n /** Content extracted from the source markdown footnote definition. */\n contentSource: string;\n /** Per-def hast body (the def's mdast children after mdast-util-to-hast\n * conversion). Drives AggregateFootnotesIfLast to render the consolidated\n * footer at the end of each document's last chunk. Optional so unit-test\n * fixtures can build minimal FootnoteDef objects without producing hast. */\n bodyHast?: HastElementContent[];\n}\n\nexport interface LinkDef {\n /** Already-normalized identifier (uppercase). */\n identifier: string;\n url: string;\n title?: string;\n}\n\nexport type RefKind = 'footnote' | 'link' | 'image';\n\nexport interface RefRecord {\n /** Already-normalized identifier (uppercase). */\n label: string;\n /** Which markdown reference space this entry belongs to. Footnote refs,\n * link refs, and image refs occupy disjoint namespaces in GFM, so they\n * must be filtered separately when computing footnote numbers / refcounts. */\n kind: RefKind;\n referenceType?: 'full' | 'collapsed' | 'shortcut';\n}\n\nexport interface ChunkData {\n refs: RefRecord[];\n defs: Map<string, FootnoteDef>;\n linkDefs: Map<string, LinkDef>;\n ownFootnoteLabels: Set<string>;\n ownLinkLabels: Set<string>;\n}\n\n/**\n * Public, read-only view of the cross-chunk registry. This is the type\n * surfaced by `useDocumentRegistry` and re-exported from the package\n * barrel. Consumers can:\n *\n * - read the registry's current state (`chunkOrder`, `chunkData`,\n * `labelSet`, `version`)\n * - observe changes (`subscribe`)\n * - run selectors (`globalNumber`, `resolveLinkDef`, …)\n *\n * Mutators — `registerChunk`, `allocateSymbol`, `releaseSymbol`,\n * `contributeLabels`, `contributeChunkData` — are intentionally off this\n * interface. Driving the registry directly is reserved for internal\n * coordinators (the package's own `MarkdownContent` renderer) and tests,\n * which import the wider `RegistryInternal` type from this module.\n * `RegistryInternal` is exported from this engine package (the core\n * renderer consumes it) but NOT from `@ai-react-markdown/core`'s public\n * barrel — keeping mutators off the consumer-facing surface prevents a\n * misbehaving consumer-component from corrupting refcounts, skipping\n * version bumps, or otherwise breaking the invariants the renderer relies\n * on.\n */\nexport interface Registry {\n /** Chunk mount-order Symbol list. **Read-only.** Direct mutation\n * (`.push`, `.splice`, index assignment) corrupts footnote numbering,\n * \"last chunk\" detection, and eviction. */\n readonly chunkOrder: readonly symbol[];\n /** Chunk Symbol → contribution payload. **Read-only.** Direct `.set` /\n * `.delete` bypasses version bumps and subscriber wake-ups. */\n readonly chunkData: ReadonlyMap<symbol, ChunkData>;\n /** Union of own-def labels across all chunks. PASS 0.5 phantom-injection\n * driver. **Read-only.** The registry derives this from per-chunk\n * contributions; direct mutation breaks the derivation. */\n readonly labelSet: {\n readonly footnoteLabels: ReadonlySet<string>;\n readonly linkLabels: ReadonlySet<string>;\n };\n /** Monotonic version counter bumped by every mutation. **Read-only** —\n * consumers should observe via `subscribe`, not by writing. */\n readonly version: number;\n\n subscribe(cb: () => void): () => void;\n\n // Selectors — pure reads over chunkOrder × chunkData, recomputed on every\n // call (NOT memoized: each is a linear walk of the registry; placeholder\n // components already gate their re-renders on `version`, so callers pay\n // one walk per registry mutation, not per render).\n canonicalFootnoteFor(label: string): symbol | null;\n canonicalLinkFor(label: string): symbol | null;\n globalNumber(label: string): number | null;\n /**\n * Resolve a cross-chunk link definition by label. The returned `url` is\n * the RAW destination from the contributing chunk's source — the registry\n * does not sanitize. The library's cross-chunk link/image placeholders run\n * the full per-attribute sanitization (`sanitizeSchema.protocols` +\n * `urlTransform`, correct key) at render time.\n *\n * Consumers reading `def.url` directly (custom backlink panels, analytics,\n * dev tooling) MUST run their own policy before rendering it as an\n * `href`/`src` — a chunk can define `[evil]: javascript:alert(1)`.\n */\n resolveLinkDef(label: string): LinkDef | null;\n getRefsForLabel(label: string): number;\n /** Map a chunk-local footnote-ref occurrence index (1-based, as emitted by\n * `customMdastHandlers`) to the corresponding document-wide occurrence\n * index across all chunks. Used by `FootnoteSupNumber` to build a unique\n * `id=\"fnref-X-N\"` for each ref instance and by `AggregateFootnotesIfLast`\n * to enumerate per-occurrence backrefs. Returns `null` if the ref isn't\n * registered yet (registry mid-flight). */\n globalOccurrenceForRef(chunkSym: symbol, label: string, localOccurrence: number): number | null;\n}\n\n/**\n * Internal registry surface — extends {@link Registry} with the mutator\n * methods and implementation-private fields (reactId-keyed refcount table,\n * subscriber set, microtask-coalesce flag, `_notify` itself).\n *\n * Exported from this module (and the engine barrel) so internal\n * coordinators (`MarkdownContent`) and tests can hold a strongly-typed\n * reference, but **not** re-exported from `@ai-react-markdown/core`'s\n * barrel — a consumer flipping `_notifyScheduled = true`\n * or pushing into `chunkOrder` directly would silently break the\n * coalesce / numbering invariants. The runtime value returned by\n * {@link createRegistry} always satisfies this wider shape; public consumers\n * just see the narrowed {@link Registry} view.\n */\nexport interface RegistryInternal extends Registry {\n /** Allocate (or reuse, for Strict Mode remount) the chunk Symbol for\n * `reactId` AND publish this chunk's own def labels (footnotes + links)\n * in one call. Canonical pair API used by `MarkdownContent`'s allocate\n * effect — combining the two reduces the pair to a single registry\n * version step, which downstream consumers see as one wake-up rather\n * than two (the second was already coalesced by microtask, but this\n * keeps the version monotonic-by-1-per-mount which makes debugging\n * easier). The granular `allocateSymbol` / `contributeLabels` methods\n * remain available for tests that need to exercise each step. */\n registerChunk(reactId: string, footnotes: Set<string>, links: Set<string>, documentIndex?: number): symbol;\n /** `documentIndex` — the chunk's position in the DOCUMENT (not its mount\n * order). Without it a chunk joins `chunkOrder` at the end, which is\n * wrong for any list that unmounts and remounts chunks: a virtualized\n * transcript scrolling back re-registers an earlier chunk after the ones\n * still mounted, and footnote numbering plus \"which chunk renders the\n * aggregate footer\" follow that order (2026-08-19 review r2 P2-10).\n * Chunks that supply an index are kept sorted by it; chunks without one\n * keep mount order after them. */\n allocateSymbol(reactId: string, documentIndex?: number): symbol;\n /** @internal Insert a chunk Symbol at its document position. */\n _placeChunk(sym: symbol, documentIndex?: number): void;\n releaseSymbol(reactId: string): void;\n contributeLabels(symbol: symbol, footnotes: Set<string>, links: Set<string>): void;\n contributeChunkData(symbol: symbol, data: ChunkData): void;\n\n _reactIdMap: Map<string, { symbol: symbol; refcount: number }>;\n /** Symbol → the `documentIndex` its chunk supplied (see allocateSymbol). */\n _chunkIndex: Map<symbol, number>;\n _subscribers: Set<() => void>;\n _notifyScheduled: boolean;\n _notify(): void;\n}\n\n/**\n * Construct a new Registry. `onEmpty`, if supplied, is invoked once each\n * time the registry transitions to \"no chunks alive\" — i.e. the last\n * tracked chunk's deferred `releaseSymbol` cleanup just removed its\n * entry, leaving `chunkOrder` and `chunkData` both empty. The container\n * uses this to evict the registry from its `documentId → Registry` map\n * so long-lived SPAs that cycle through many `documentId` values don't\n * accumulate empty shells.\n *\n * `onEmpty` fires synchronously from inside the releaseSymbol microtask,\n * so the registry's state is guaranteed quiescent during the callback —\n * no other code can interleave between the empty-state check and the\n * caller's eviction logic.\n */\nexport function createRegistry(onEmpty?: () => void): RegistryInternal {\n const reg = {\n chunkOrder: [] as symbol[],\n chunkData: new Map<symbol, ChunkData>(),\n labelSet: { footnoteLabels: new Set<string>(), linkLabels: new Set<string>() },\n version: 0,\n _reactIdMap: new Map<string, { symbol: symbol; refcount: number }>(),\n /** Symbol → its `documentIndex`, for chunks that supplied one. */\n _chunkIndex: new Map<symbol, number>(),\n _subscribers: new Set<() => void>(),\n _notifyScheduled: false,\n\n allocateSymbol(reactId: string, rawDocumentIndex?: number): symbol {\n // `NaN` compares false against everything, so it would act as a sort\n // BARRIER (no later chunk ever breaks in front of it) rather than being\n // ignored. Treat any non-finite value as \"no index\".\n const documentIndex =\n rawDocumentIndex !== undefined && Number.isFinite(rawDocumentIndex) ? rawDocumentIndex : undefined;\n if (process.env.NODE_ENV !== 'production' && rawDocumentIndex !== undefined && documentIndex === undefined) {\n console.warn(\n `[ai-react-markdown] documentIndex must be a finite number — received ${String(rawDocumentIndex)}; ignoring it for this chunk.`\n );\n }\n const existing = this._reactIdMap.get(reactId);\n if (existing) {\n existing.refcount++;\n // A LIVE chunk re-registering with a different position (the effect\n // deps include `documentIndex`, so a consumer reordering chunks\n // without remounting them lands here): move it. StrictMode's\n // double-invoke passes the same value and falls through unchanged.\n // Presence, not just value: going back to `undefined` (a consumer\n // that computes the index conditionally) must ALSO take effect —\n // otherwise `_chunkIndex` keeps a value nobody supplies and\n // `_placeChunk`'s scan steers OTHER chunks by it. Testing\n // `get(...) !== documentIndex` alone would regress the common case:\n // `get` returns undefined for un-indexed chunks too, so every\n // un-indexed chunk would jump to the tail on each re-register (which\n // happens on every `ownLabels` change while streaming).\n const moved =\n documentIndex !== undefined\n ? this._chunkIndex.get(existing.symbol) !== documentIndex\n : this._chunkIndex.has(existing.symbol);\n if (moved) {\n const at = this.chunkOrder.indexOf(existing.symbol);\n if (at !== -1) this.chunkOrder.splice(at, 1);\n this._placeChunk(existing.symbol, documentIndex);\n this._notify();\n }\n return existing.symbol;\n }\n const sym = Symbol(reactId);\n this._reactIdMap.set(reactId, { symbol: sym, refcount: 1 });\n this._placeChunk(sym, documentIndex);\n this._notify();\n return sym;\n },\n\n /** Put `sym` into `chunkOrder` at its document position. Without an index\n * it goes last (mount order — the historical behaviour); with one it\n * sorts before the first chunk that sits later, where a chunk WITHOUT an\n * index counts as \"later\" so an indexed chunk never lands behind one\n * whose position is unknown. */\n _placeChunk(sym: symbol, documentIndex?: number): void {\n if (process.env.NODE_ENV !== 'production' && this.chunkOrder.length > 0) {\n // Mixing the two modes under one documentId is the default failure of\n // a partial migration, and it FAILS LIKE THE BUG the prop exists to\n // fix: every un-indexed chunk sorts after every indexed one, so\n // numbering stops following DOM order and the aggregate footer lands\n // on the last-MOUNTED un-indexed chunk (oracle review of 2.5.0).\n const anyIndexed = documentIndex !== undefined || this.chunkOrder.some((s) => this._chunkIndex.has(s));\n const anyPlain = documentIndex === undefined || this.chunkOrder.some((s) => !this._chunkIndex.has(s));\n if (anyIndexed && anyPlain) {\n console.warn(\n '[ai-react-markdown] Some chunks of this document supply `documentIndex` and some do not. ' +\n 'Indexed chunks always sort ahead of un-indexed ones, so footnote numbering and aggregate-footer ' +\n 'placement will not follow document order. Pass `documentIndex` to every chunk, or to none.'\n );\n }\n }\n if (documentIndex === undefined) {\n this._chunkIndex.delete(sym);\n this.chunkOrder.push(sym);\n return;\n }\n this._chunkIndex.set(sym, documentIndex);\n let at = this.chunkOrder.length;\n for (let i = 0; i < this.chunkOrder.length; i++) {\n const other = this._chunkIndex.get(this.chunkOrder[i]);\n if (other === undefined || other > documentIndex) {\n at = i;\n break;\n }\n }\n this.chunkOrder.splice(at, 0, sym);\n },\n\n registerChunk(reactId: string, footnotes: Set<string>, links: Set<string>, documentIndex?: number): symbol {\n // Composition of allocateSymbol + contributeLabels. Both `_notify`\n // calls coalesce into a single microtask wake-up, so the perf\n // shape is the same as the granular pair — the API just expresses\n // the canonical \"register one chunk\" intent.\n const sym = this.allocateSymbol(reactId, documentIndex);\n this.contributeLabels(sym, footnotes, links);\n return sym;\n },\n\n releaseSymbol(reactId: string): void {\n const entry = this._reactIdMap.get(reactId);\n if (!entry) return;\n if (entry.refcount <= 0) {\n // Already fully released and awaiting the deferred cleanup (or a\n // caller released more than it allocated). Decrementing further\n // would park the refcount below zero, where the `=== 0` cleanup\n // check never fires and the chunk leaks forever with onEmpty\n // eviction disabled (2026-08 project review, eng-stream-03).\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n `[ai-react-markdown] Registry.releaseSymbol(\"${reactId}\") called with no matching allocateSymbol — ignoring (unbalanced release).`\n );\n }\n return;\n }\n entry.refcount--;\n if (entry.refcount === 0) {\n queueMicrotask(() => {\n const latest = this._reactIdMap.get(reactId);\n if (latest && latest.refcount === 0) {\n this._reactIdMap.delete(reactId);\n const idx = this.chunkOrder.indexOf(entry.symbol);\n if (idx !== -1) this.chunkOrder.splice(idx, 1);\n this._chunkIndex.delete(entry.symbol);\n this.chunkData.delete(entry.symbol);\n // Rebuild labelSet from the surviving chunks. The contribute paths\n // (`contributeLabels`, `contributeChunkData`) already rebuild this\n // union on every write, but a chunk that simply UNMOUNTS would\n // otherwise leave `labelSet` referencing labels that no live chunk\n // owns. Downstream consumers (`targetPhantoms` in\n // `MarkdownContent`) read `registry.labelSet` to gate phantom\n // injection — without this rebuild, surviving chunks would keep\n // treating refs to the released chunk's labels as phantom, while\n // `canonicalFootnoteFor` (which walks live chunkData) returns\n // null, leaving inline `<sup>` anchors pointing at `<li>` ids\n // that the aggregate footer never renders.\n const nextFn = new Set<string>();\n const nextLink = new Set<string>();\n for (const cd of this.chunkData.values()) {\n for (const l of cd.ownFootnoteLabels) nextFn.add(l);\n for (const l of cd.ownLinkLabels) nextLink.add(l);\n }\n this.labelSet.footnoteLabels = nextFn;\n this.labelSet.linkLabels = nextLink;\n this._notify();\n // Last chunk just left: notify the container so it can drop\n // this registry from its `documentId → Registry` map. The\n // identity check on the container side prevents racing a\n // freshly-allocated registry under the same documentId.\n //\n // Ordering note: `onEmpty` fires SYNCHRONOUSLY here, after\n // `_notify` has scheduled subscriber fanout (which itself\n // runs in a later microtask, see `_notifyScheduled`). So\n // the container evicts FIRST, then subscribers wake. A\n // subscriber that re-resolves via `getRegistry(documentId)`\n // during its wake-up therefore sees a freshly-allocated\n // registry — which is the right behavior, because by then\n // the consumer is genuinely starting over.\n if (this.chunkOrder.length === 0 && this.chunkData.size === 0 && onEmpty) {\n onEmpty();\n }\n }\n });\n }\n },\n\n contributeLabels(symbol: symbol, footnotes: Set<string>, links: Set<string>): void {\n // A released or never-allocated symbol must not grow chunkData: the\n // ghost entry would keep `chunkData.size === 0` from ever holding and\n // the registry would never be evicted (v2.4.1 review). Effects racing\n // an unmount can legitimately land here — ignore, do not throw.\n if (!this.chunkOrder.includes(symbol)) return;\n const data = this.chunkData.get(symbol);\n if (data) {\n data.ownFootnoteLabels = footnotes;\n data.ownLinkLabels = links;\n } else {\n this.chunkData.set(symbol, {\n refs: [],\n defs: new Map(),\n linkDefs: new Map(),\n ownFootnoteLabels: footnotes,\n ownLinkLabels: links,\n });\n }\n // Always notify. The prior `if (fnChanged || linkChanged)` optimization\n // skipped the wake-up when the UNION labelSet was unchanged — but\n // chunkData has ALWAYS mutated by the time we reach this line (we either\n // overwrote ownFootnoteLabels/ownLinkLabels on an existing entry, or we\n // just created a fresh chunkData entry above). A subscriber keyed on\n // `registry.version` would observe live chunkData changing under a\n // stable snapshot — a useSyncExternalStore tearing violation. With the\n // microtask-coalesced `_notify`, the per-call cost is the version++\n // plus a single subscriber fanout per batch, so the optimization's\n // savings are nil; correctness wins.\n const newFn = new Set<string>();\n const newLink = new Set<string>();\n for (const cd of this.chunkData.values()) {\n for (const l of cd.ownFootnoteLabels) newFn.add(l);\n for (const l of cd.ownLinkLabels) newLink.add(l);\n }\n this.labelSet.footnoteLabels = newFn;\n this.labelSet.linkLabels = newLink;\n this._notify();\n },\n\n contributeChunkData(symbol: symbol, data: ChunkData): void {\n if (!this.chunkOrder.includes(symbol)) return; // see contributeLabels\n this.chunkData.set(symbol, data);\n // Rebuild labelSet too (data may extend or shrink it)\n this.labelSet.footnoteLabels = new Set();\n this.labelSet.linkLabels = new Set();\n for (const cd of this.chunkData.values()) {\n for (const l of cd.ownFootnoteLabels) this.labelSet.footnoteLabels.add(l);\n for (const l of cd.ownLinkLabels) this.labelSet.linkLabels.add(l);\n }\n this._notify();\n },\n\n subscribe(cb: () => void): () => void {\n this._subscribers.add(cb);\n return () => {\n this._subscribers.delete(cb);\n };\n },\n\n canonicalFootnoteFor(label: string): symbol | null {\n const id = normalizeId(label);\n for (const sym of this.chunkOrder) {\n const data = this.chunkData.get(sym);\n if (data?.defs.has(id)) return sym;\n }\n return null;\n },\n\n canonicalLinkFor(label: string): symbol | null {\n const id = normalizeId(label);\n for (const sym of this.chunkOrder) {\n const data = this.chunkData.get(sym);\n if (data?.linkDefs.has(id)) return sym;\n }\n return null;\n },\n\n globalNumber(label: string): number | null {\n const id = normalizeId(label);\n let n = 0;\n const seen = new Set<string>();\n for (const sym of this.chunkOrder) {\n const data = this.chunkData.get(sym);\n if (!data) continue;\n for (const ref of data.refs) {\n // Footnote numbering is a per-space ordinal; link/image refs share\n // the `refs` array but occupy a disjoint namespace, so they must\n // NOT advance the footnote counter.\n if (ref.kind !== 'footnote') continue;\n if (!seen.has(ref.label)) {\n seen.add(ref.label);\n n++;\n if (ref.label === id) return n;\n }\n }\n }\n return null;\n },\n\n resolveLinkDef(label: string): LinkDef | null {\n const sym = this.canonicalLinkFor(label);\n if (!sym) return null;\n return this.chunkData.get(sym)?.linkDefs.get(normalizeId(label)) ?? null;\n },\n\n getRefsForLabel(label: string): number {\n const id = normalizeId(label);\n let n = 0;\n for (const sym of this.chunkOrder) {\n const data = this.chunkData.get(sym);\n if (!data) continue;\n // Only count footnote refs: the consumers (backref-strip and\n // backref-inject) decide based on whether a footnote `<li>` should\n // exist, which depends on footnote refs alone.\n for (const ref of data.refs) {\n if (ref.kind === 'footnote' && ref.label === id) n++;\n }\n }\n return n;\n },\n\n globalOccurrenceForRef(chunkSym: symbol, label: string, localOccurrence: number): number | null {\n const id = normalizeId(label);\n let global = 0;\n for (const sym of this.chunkOrder) {\n const data = this.chunkData.get(sym);\n if (!data) continue;\n let localCount = 0;\n for (const ref of data.refs) {\n if (ref.kind !== 'footnote') continue;\n if (ref.label !== id) continue;\n localCount++;\n global++;\n if (sym === chunkSym && localCount === localOccurrence) return global;\n }\n }\n return null;\n },\n\n _notify(): void {\n this.version++;\n if (this._notifyScheduled) return;\n this._notifyScheduled = true;\n queueMicrotask(() => {\n this._notifyScheduled = false;\n // Snapshot subscribers so unsubscribes during fanout don't shift the\n // iteration. New subscribers added during fanout will pick up the\n // current `version` on their next render.\n for (const cb of [...this._subscribers]) cb();\n });\n },\n };\n // Internally `reg` has both the public API and the private state.\n // The return type is {@link RegistryInternal} so internal callers\n // (`MarkdownContent`, tests) hold a strongly-typed handle to the\n // mutators and private state. Public consumers see only the narrow\n // {@link Registry} via `useDocumentRegistry`'s return type.\n return reg as unknown as RegistryInternal;\n}\n","/**\n * THE single source of the production plugin chain.\n *\n * `MarkdownContent`'s memos, the splice-equivalence arbiter's option\n * catalog (`incrementalParse/testPluginCatalog.ts`), and the prefixFreeze\n * experiment harness all build their chains HERE — plugin-order drift\n * between the renderer and its verification suites previously required\n * hand-synchronized copies, and a missed copy would silently leave the\n * arbiter testing a non-production pipeline.\n *\n * Two deliberate NON-consumers, kept as independent mirrors on purpose:\n * - `byteEquivalence.test.tsx`'s `legacyPlugins()` — it is the REFERENCE\n * implementation the new pipeline is compared against; importing this\n * module would make that comparison circular.\n * - `positionPropagation.test.ts` — it pins the position-retention\n * contract of the exact stack and must fail loudly when the stack\n * changes, not silently follow it.\n *\n * @module components/pluginChain\n */\n\nimport rehypeKatex from 'rehype-katex';\nimport rehypeRaw from '@ai-markdown/rehype-raw';\nimport rehypeUnwrapImages from 'rehype-unwrap-images';\nimport { rehypeUnwrapCrossChunkImages } from './rehypeUnwrapCrossChunkImages';\nimport rehypeSanitize from 'rehype-sanitize';\nimport remarkBreaks from 'remark-breaks';\nimport remarkCjkFriendly from 'remark-cjk-friendly';\nimport remarkCjkFriendlyGfmStrikethrough from 'remark-cjk-friendly-gfm-strikethrough';\nimport remarkEmoji from 'remark-emoji';\nimport remarkGfm from 'remark-gfm';\nimport remarkMath from 'remark-math';\nimport { remarkDefinitionList, defListHastHandlers } from 'remark-definition-list';\nimport { remarkMark as remarkMarkHighlight } from '@ai-react-markdown/remark-mark-highlight';\nimport remarkSqueezeParagraphs from 'remark-squeeze-paragraphs';\nimport remarkSmartypants from 'remark-smartypants';\nimport remarkPangu from 'remark-pangu';\nimport remarkRemoveComments from 'remark-remove-comments';\n\nimport type { PipelineOptions as MarkdownOptions } from './markdown';\nimport rehypeRebaseHashLinks from './rehypeRebaseHashLinks';\nimport rehypeFooterAdorn from './rehypeFooterAdorn';\nimport type { SanitizeSchema } from './extendSanitizeSchema';\nimport type { AIMarkdownEnginePlugin, AIMarkdownEnginePluginName } from '../plugins/defs';\n\nexport type RemarkPlugins = NonNullable<MarkdownOptions['remarkPlugins']>;\nexport type RehypePlugins = NonNullable<MarkdownOptions['rehypePlugins']>;\nexport type RemarkRehypeOptions = NonNullable<MarkdownOptions['remarkRehypeOptions']>;\n\n/**\n * Per-stage chain tables: sealed plugin name → unified plugin, in CANONICAL\n * chain order. The tables (not the caller's array order) fix each plugin's\n * splice position — required for the produced-chain byte-equivalence\n * guarantee to be checkable. The heavy unified imports stay in THIS module\n * so the `/plugins` subpath catalog remains a lightweight descriptor set.\n */\nconst EXTRA_SYNTAX_CHAIN: ReadonlyArray<readonly [AIMarkdownEnginePluginName, RemarkPlugins[number]]> = [\n ['highlight', remarkMarkHighlight as RemarkPlugins[number]],\n ['definitionList', remarkDefinitionList as RemarkPlugins[number]],\n];\nconst DISPLAY_OPTIMIZE_CHAIN: ReadonlyArray<readonly [AIMarkdownEnginePluginName, RemarkPlugins[number]]> = [\n ['removeComments', remarkRemoveComments as RemarkPlugins[number]],\n ['smartypants', remarkSmartypants as RemarkPlugins[number]],\n ['pangu', remarkPangu as RemarkPlugins[number]],\n];\n\n/** The always-on remark chain with plugin-gated extras spliced at their\n * contractual positions. ORDER IS LOAD-BEARING — see the arbiter suite. */\nexport function buildCoreRemarkPlugins(enginePlugins: readonly AIMarkdownEnginePlugin[]): RemarkPlugins {\n const selected = new Set<string>(enginePlugins.map((plugin) => plugin.name));\n return [\n // --- Core plugins (always active) ---\n remarkGfm,\n [\n remarkMath,\n {\n // Disable single-dollar inline math to avoid conflicts with currency\n // signs and other dollar usages; the preprocessor converts $...$ to $$...$$.\n singleDollarTextMath: false,\n },\n ],\n // --- Selectable extra syntax plugins (canonical table order) ---\n ...EXTRA_SYNTAX_CHAIN.filter(([name]) => selected.has(name)).map(([, plugin]) => plugin),\n // --- Formatting & normalization ---\n remarkBreaks,\n remarkEmoji,\n remarkSqueezeParagraphs,\n remarkCjkFriendly,\n remarkCjkFriendlyGfmStrikethrough,\n // --- Selectable display optimizations (canonical table order) ---\n ...DISPLAY_OPTIMIZE_CHAIN.filter(([name]) => selected.has(name)).map(([, plugin]) => plugin),\n ] as RemarkPlugins;\n}\n\n/** The rehype chain. `clobberPrefix` namespaces ids per instance; pass ''\n * for unprefixed output (test harnesses). */\nexport function buildCoreRehypePlugins(sanitizeSchema: SanitizeSchema, clobberPrefix: string): RehypePlugins {\n return [\n // Allow raw HTML through so rehype-sanitize can handle it.\n [rehypeRaw, { passThrough: [] }],\n // Sanitize HTML while allowing <mark> (highlight), KaTeX class names,\n // and any extra protocols the caller permitted via the `sanitizeSchema`\n // prop. Override `clobberPrefix` with the instance-scoped value — the\n // spread order is intentional: our prefix wins over any caller-supplied\n // prefix on the schema.\n [rehypeSanitize, { ...sanitizeSchema, clobberPrefix }],\n // Normalize the auto-generated `<section data-footnotes>`: strip the\n // sr-only `<h2>Footnotes</h2>` label and prepend `<hr>`. Keeps standalone\n // single-doc rendering visually consistent with the cross-chunk aggregate\n // footer (which builds the same shape from scratch).\n rehypeFooterAdorn,\n // Re-prefix intra-document hash hrefs so they match the ids that\n // rehype-sanitize just clobbered. Must use the SAME prefix as the schema\n // above.\n [rehypeRebaseHashLinks, { prefix: clobberPrefix }],\n rehypeKatex,\n rehypeUnwrapImages,\n // Same unwrap for `<cross-chunk-image>` placeholders (coordinated mode);\n // no-op on standalone documents.\n rehypeUnwrapCrossChunkImages,\n ] as RehypePlugins;\n}\n\n/** Base remark-rehype options (before the standalone/coordinated handler\n * merge that `MarkdownContent`'s pipeline memo layers on top). */\nexport function buildCoreRemarkRehypeOptions(enableDefinitionList: boolean): RemarkRehypeOptions {\n return {\n allowDangerousHtml: true,\n // Suppress mdast-util-to-hast's `user-content-` prefix on footnote\n // ids/hrefs; rehype-sanitize will apply the same prefix downstream\n // and `rehypeRebaseHashLinks` mirrors it onto matching hash hrefs.\n // Without this, ids would end up double-prefixed\n // (`user-content-user-content-fn-x`).\n clobberPrefix: '',\n handlers: {\n // Inject definition-list HAST handlers when the extension is active.\n ...(enableDefinitionList ? defListHastHandlers : {}),\n },\n };\n}\n","/**\n * Mirror of `rehype-unwrap-images` for the coordinated pipeline's\n * placeholders. Upstream unwraps a `<p>` whose content is only images (and\n * whitespace, or links wrapping only images) — but it only knows `<img>` /\n * `<a>`. In coordinated mode a reference-style image is a\n * `<cross-chunk-image>` placeholder (a link a `<cross-chunk-link>`), so\n * `![pic][x]` alone in a paragraph stayed wrapped: `<p><img></p>` where\n * the standalone render is a bare `<img>` (v2.4.0 review — the wrapped\n * server output diverged from standalone, and the client resolved path had\n * always differed). Runs AFTER rehype-unwrap-images with the same rule,\n * extended to the placeholder tags. Standalone documents contain no\n * placeholders, so this is a no-op there.\n *\n * @module components/rehypeUnwrapCrossChunkImages\n */\nimport type { Element, ElementContent, Root } from 'hast';\nimport { SKIP, visit } from 'unist-util-visit';\n\nconst IMAGE_TAGS = new Set(['img', 'cross-chunk-image']);\nconst LINK_TAGS = new Set(['a', 'cross-chunk-link']);\n\nconst enum Verdict {\n Unknown,\n ContainsImage,\n ContainsOther,\n}\n\n/** `seen.placeholder` flips when any placeholder tag (image OR link) took\n * part in the verdict — only such paragraphs are ours to unwrap; plain\n * `<img>`/`<a>` paragraphs were already unwrapped by rehype-unwrap-images. */\nfunction applicable(node: Element, inLink: boolean, seen: { placeholder: boolean }): Verdict {\n let image = Verdict.Unknown;\n for (const child of node.children as ElementContent[]) {\n if (child.type === 'text' && /^\\s*$/.test(child.value)) continue;\n if (child.type === 'element' && IMAGE_TAGS.has(child.tagName)) {\n if (child.tagName !== 'img') seen.placeholder = true;\n image = Verdict.ContainsImage;\n } else if (!inLink && child.type === 'element' && LINK_TAGS.has(child.tagName)) {\n if (child.tagName !== 'a') seen.placeholder = true;\n const inner = applicable(child, true, seen);\n if (inner === Verdict.ContainsOther) return Verdict.ContainsOther;\n if (inner === Verdict.ContainsImage) image = Verdict.ContainsImage;\n } else {\n return Verdict.ContainsOther;\n }\n }\n return image;\n}\n\nexport function rehypeUnwrapCrossChunkImages() {\n return function transform(tree: Root): void {\n visit(tree, 'element', (node, index, parent) => {\n if (node.tagName !== 'p' || !parent || typeof index !== 'number') return;\n // Only paragraphs where a placeholder took part — an image placeholder\n // OR a link placeholder around a plain `<img>` (`[![pic](url)][ref]`,\n // v2.4.1 review: the old guard only looked for the image tag).\n const seen = { placeholder: false };\n if (applicable(node, false, seen) === Verdict.ContainsImage && seen.placeholder) {\n parent.children.splice(index, 1, ...node.children);\n return [SKIP, index];\n }\n });\n };\n}\n","/**\n * `rehypeRebaseHashLinks` — restore intra-document hash navigation after\n * `rehype-sanitize` clobbers `id` attributes.\n *\n * ### Why this exists\n *\n * `rehype-sanitize` defends against ID-clobbering attacks (e.g. a malicious\n * `<div id=\"window\">` shadowing `window.window`) by prefixing every clobberable\n * attribute (`id`, `name`, `aria-describedby`, `aria-labelledby`) with\n * `clobberPrefix` (default `'user-content-'`). It does **not** rewrite `href`\n * values, since hashes are not themselves clobbering vectors. As a result,\n * any intra-document link — `[ref](#section)`, GFM footnote anchors, or raw\n * `<a id=\"x\"><a href=\"#x\">` pairs — points at an unprefixed hash while its\n * target id has been prefixed: navigation breaks.\n *\n * Pair this plugin with `remarkRehypeOptions: { clobberPrefix: '' }` so that\n * `mdast-util-to-hast` does not also prefix (avoiding `user-content-user-content-`\n * double prefixes), and place it **after** `rehype-sanitize` in the rehype\n * pipeline. The result mirrors GitHub's rendering: a single, consistent\n * `user-content-` prefix on every id and matching hash href.\n *\n * @module components/rehypeRebaseHashLinks\n */\n\nimport type { Root } from 'hast';\nimport type { Plugin } from 'unified';\nimport { visit } from 'unist-util-visit';\n\nconst DEFAULT_PREFIX = 'user-content-';\n\nexport interface RehypeRebaseHashLinksOptions {\n /** Prefix to apply. Must match the `clobberPrefix` used by `rehype-sanitize`. */\n prefix?: string;\n}\n\nconst rehypeRebaseHashLinks: Plugin<[RehypeRebaseHashLinksOptions?], Root> = (options) => {\n const prefix = options?.prefix ?? DEFAULT_PREFIX;\n const hashPrefix = '#' + prefix;\n return (tree) => {\n visit(tree, 'element', (node) => {\n if (node.tagName !== 'a') return;\n const href = node.properties?.href;\n if (typeof href !== 'string' || !href.startsWith('#')) return;\n if (href.startsWith(hashPrefix)) return;\n node.properties.href = hashPrefix + href.slice(1);\n });\n };\n};\n\nexport default rehypeRebaseHashLinks;\n","/**\n * Rehype plugin that normalizes the auto-generated footnote footer so its\n * shape matches the cross-chunk aggregate footer (rendered by\n * `AggregateFootnotesIfLast`).\n *\n * mdast-util-to-hast's default `state.footer()` emits:\n *\n * <section data-footnotes class=\"footnotes\">\n * <h2 id=\"...footnote-label\" class=\"sr-only\">Footnotes</h2>\n * <ol>...</ol>\n * </section>\n *\n * The aggregate footer used in coordinated mode (and which the user prefers\n * visually) emits:\n *\n * <section data-footnotes class=\"footnotes\">\n * <hr />\n * <ol>...</ol>\n * </section>\n *\n * Running this plugin on the parsed hast lets standalone single-doc\n * rendering produce the same structure as the aggregate, so a 1-chunk doc and\n * an N-chunk coordinated doc with identical content look the same.\n *\n * Operates only on `<section data-footnotes>` and is idempotent.\n *\n * @module components/rehypeFooterAdorn\n */\nimport { visit } from 'unist-util-visit';\nimport type { Element as HastElement, Root as HastRoot, ElementContent } from 'hast';\n\nconst FOOTNOTE_LABEL_ID_RE = /(?:^|-)footnote-label$/;\n\nfunction isFootnoteLabelH2(node: ElementContent): boolean {\n if (node.type !== 'element') return false;\n const el = node as HastElement;\n if (el.tagName !== 'h2') return false;\n const id = el.properties?.id;\n return typeof id === 'string' && FOOTNOTE_LABEL_ID_RE.test(id);\n}\n\nfunction isHr(node: ElementContent): boolean {\n if (node.type !== 'element') return false;\n return (node as HastElement).tagName === 'hr';\n}\n\nexport default function rehypeFooterAdorn() {\n return (tree: HastRoot) => {\n visit(tree, 'element', (n) => {\n const el = n as HastElement;\n if (el.tagName !== 'section') return;\n if (!(el.properties && 'dataFootnotes' in el.properties)) return;\n // Strip the auto-generated <h2 id=\"...footnote-label\"> — the visible\n // \"Footnotes\" header reads awkwardly, especially in streaming AI chat\n // contexts. To keep screen-reader announcement working, set\n // `aria-label=\"Footnotes\"` on the section landmark so assistive tech\n // still names the region.\n const filtered = el.children.filter((c) => !isFootnoteLabelH2(c)) as ElementContent[];\n // Prepend <hr> as the first child, unless one is already present.\n if (!filtered.some(isHr)) {\n const hr: HastElement = {\n type: 'element',\n tagName: 'hr',\n properties: {},\n children: [],\n };\n filtered.unshift(hr);\n }\n el.children = filtered;\n if (!el.properties) el.properties = {};\n if (!('ariaLabel' in el.properties)) {\n el.properties.ariaLabel = 'Footnotes';\n }\n });\n };\n}\n","/**\n * Custom mdast-util-to-hast handlers for cross-chunk label resolution.\n *\n * Direction A: `footnoteDefinitionHandler` mutates `state.footnoteOrder` (and\n * seeds `state.footnoteCounts` to 0) so `state.footer()` emits a\n * `<section data-footnotes>` even when no `footnoteReference` exists locally\n * (orphan-def protection), without the default reference handler\n * double-registering ids whose definition precedes their first reference.\n *\n * Direction B: `linkReferenceHandler` / `imageReferenceHandler` /\n * `footnoteReferenceHandler` short-circuit the default to-hast output and\n * emit custom hast tags (`cross-chunk-link` / `cross-chunk-image` /\n * `footnote-sup`) carrying `label` + `referenceType` properties. These tags\n * map to React placeholder components in Phase 11. The sentinel URL is never\n * read — the handlers only need to know that the def is resolvable\n * (i.e. present in state.definitionById).\n *\n * All identifier comparisons normalize via {@link normalizeId} to match\n * mdast-util-to-hast's internal uppercase keying convention.\n *\n * @module components/customMdastHandlers\n */\nimport type { Handlers } from 'mdast-util-to-hast';\nimport type { LinkReference, ImageReference, FootnoteReference, FootnoteDefinition } from 'mdast';\nimport type { Element as HastElement } from 'hast';\nimport { normalizeId } from './normalizeId';\nimport { SENTINEL_LINK_URL } from './remarkInjectPhantomDefs';\n\nexport interface CrossChunkHandlerOptions {\n /** Set of labels (already normalized) that this chunk phantom-injected\n * into its source for parser acceptance. Handlers use this to short-circuit\n * state writes that would otherwise leak sentinel content into the footer. */\n phantomFootnoteLabels: Set<string>;\n /** Same role for link/image defs. */\n phantomLinkLabels: Set<string>;\n /** When true, footnoteDefinitionHandler proactively registers orphan defs\n * to state.footnoteOrder (Direction A). */\n preserveOrphan: boolean;\n /** Passed through to placeholder hast properties so React components can\n * partition by document. */\n documentId: string;\n}\n\n// Type assertion helper for state shape (mdast-util-to-hast doesn't export it).\ninterface StateShape {\n options: CrossChunkHandlerOptions & Record<string, unknown>;\n footnoteOrder: string[];\n footnoteCounts: Map<string, number>;\n definitionById: Map<string, unknown>;\n all: (node: unknown) => unknown[];\n}\n\n/**\n * The chunk's OWN definition for a resolved link/image reference — carried on\n * the placeholder as `localUrl`/`localTitle` so it can render a real link\n * before the registry has anything to say (server render, the client's\n * first frame before the contribute effect): coordinated SSR otherwise\n * degraded every reference-style link to its literal `[text][label]`\n * fallback (2026-08 project review, core-render-02). Phantom (sentinel)\n * defs carry nothing — a cross-chunk def is only knowable via the registry.\n * The placeholder still runs the render-time URL gates on this value.\n */\nfunction localDefProps(s: StateShape, id: string): { localUrl?: string; localTitle?: string } {\n const def = s.definitionById.get(id) as { url?: string; title?: string | null } | undefined;\n if (!def || typeof def.url !== 'string' || def.url === SENTINEL_LINK_URL) return {};\n return def.title ? { localUrl: def.url, localTitle: def.title } : { localUrl: def.url };\n}\n\nexport function buildCrossChunkHandlers(): Handlers {\n return {\n footnoteDefinition: (state: unknown, node: FootnoteDefinition): undefined => {\n const s = state as StateShape;\n const id = normalizeId(node.identifier);\n // Phantom def → noop: do not register, do not emit. Footer will skip it\n // because footnoteOrder does not contain id (unless a real ref pushed it).\n if (s.options.phantomFootnoteLabels.has(id)) {\n return undefined;\n }\n // Direction A: orphan def protection. Register so state.footer() emits <li>.\n if (s.options.preserveOrphan && !s.footnoteOrder.includes(id)) {\n s.footnoteOrder.push(id);\n // Seed the ref-counter to 0 alongside the push. In standalone mode\n // only THIS handler is installed, so `footnoteReference` falls back to\n // mdast-util-to-hast's default — and that handler decides \"is this id\n // already registered?\" by looking at footnoteCounts, not at\n // footnoteOrder. Without the seed, a definition that appears ABOVE its\n // first reference gets pushed here and then pushed AGAIN by the\n // default handler: duplicate <li> with colliding DOM ids, and a sup\n // marker numbered by array length instead of position.\n //\n // Seed 0, not 1: at >= 1 state.footer() emits a backref pointing at a\n // fnref anchor that does not exist for a pure orphan; at 0 the\n // backref loop never runs, so pure-orphan output stays byte-identical\n // and the default handler's reuse branch produces the same numbering\n // as the ref-above-def ordering.\n if (!s.footnoteCounts.has(id)) s.footnoteCounts.set(id, 0);\n }\n return undefined; // never emit inline hast\n },\n\n linkReference: ((state: unknown, node: LinkReference): HastElement | undefined => {\n const s = state as StateShape;\n const id = normalizeId(node.identifier);\n const resolved = s.definitionById.has(id);\n if (!resolved) {\n // Unreachable in coordinated pipeline because the phantom suffix\n // guarantees a def for every referenced label that survives PASS 0.5.\n // Verified by experiment: remark-parse produces a `linkReference`\n // mdast node ONLY when a corresponding `[label]:` exists in the\n // source — without one, the brackets are emitted as plain text by\n // the parser, so neither this handler nor mdast's default ever\n // sees the reference. Defense-in-depth for an impossible state.\n return undefined;\n }\n return {\n type: 'element',\n tagName: 'cross-chunk-link',\n properties: {\n // `label` is the ORIGINAL source text (mdast's `label` field), NOT\n // the normalized `identifier`. The placeholder uses it to construct\n // hrefs that line up with mdast-util-to-hast's default `<li id>`\n // which also preserves source case. Registry lookups normalize\n // internally, so cross-chunk case-insensitive matching still works.\n label: node.label ?? node.identifier,\n referenceType: node.referenceType,\n documentId: s.options.documentId,\n ...localDefProps(s, id),\n },\n children: s.all(node) as HastElement['children'],\n };\n }) as Handlers['linkReference'],\n\n imageReference: ((state: unknown, node: ImageReference): HastElement | undefined => {\n const s = state as StateShape;\n const id = normalizeId(node.identifier);\n const resolved = s.definitionById.has(id);\n if (!resolved) return undefined;\n return {\n type: 'element',\n tagName: 'cross-chunk-image',\n properties: {\n label: node.label ?? node.identifier,\n referenceType: node.referenceType,\n alt: node.alt ?? '',\n documentId: s.options.documentId,\n ...localDefProps(s, id),\n },\n children: [],\n };\n }) as Handlers['imageReference'],\n\n footnoteReference: ((state: unknown, node: FootnoteReference): HastElement => {\n const s = state as StateShape;\n const id = normalizeId(node.identifier);\n // Bump the per-id counter for ALL refs (phantom and real). The result\n // is the chunk-local occurrence index (1, 2, 3, …) which the placeholder\n // carries so FootnoteSupNumber can disambiguate duplicate fnref-* ids\n // when the same label is referenced multiple times. For phantom refs\n // bumping is safe: state.footer() emits <li> only for ids in\n // footnoteOrder, and phantoms never get pushed there.\n const localOccurrence = (s.footnoteCounts.get(id) ?? 0) + 1;\n s.footnoteCounts.set(id, localOccurrence);\n if (s.options.phantomFootnoteLabels.has(id)) {\n return {\n type: 'element',\n tagName: 'footnote-sup',\n properties: {\n label: node.identifier,\n localOccurrence,\n documentId: s.options.documentId,\n },\n children: [],\n };\n }\n // Real local def: register in footnoteOrder so the local synthetic\n // footer can emit a <li> for it.\n if (!s.footnoteOrder.includes(id)) s.footnoteOrder.push(id);\n return {\n type: 'element',\n tagName: 'footnote-sup',\n properties: {\n label: node.identifier,\n localOccurrence,\n // The number mdast-util-to-hast would give this reference in a\n // standalone render (footnoteOrder position) — the placeholder's\n // fallback while the registry has no global number (server render /\n // first client frame), where the local synthetic footer is what\n // renders, so marks and footer agree (core-render-02).\n localNumber: s.footnoteOrder.indexOf(id) + 1,\n documentId: s.options.documentId,\n },\n children: [],\n };\n }) as Handlers['footnoteReference'],\n };\n}\n","/**\n * Two-gate URL sanitization for cross-chunk link/image placeholders.\n *\n * In the standalone path, every `<a href>` and `<img src>` element passes\n * through TWO gates before render:\n *\n * 1. `rehype-sanitize` `protocols.<attr>` allowlist — drops the attribute\n * entirely if the URL's protocol isn't permitted for that attribute.\n * Runs in the rehype plugin chain.\n * 2. `urlTransform(url, key, node)` — the caller's allowlist (default:\n * `defaultUrlTransform`, which mirrors GitHub's protocol allowlist).\n * Runs in `markdown/transform.ts` during the hast visit pass; its\n * return value IS the attribute (`''` renders `href=\"\"`).\n *\n * Cross-chunk references skip BOTH passes naturally: the placeholder hast\n * tag (`<cross-chunk-link>` / `<cross-chunk-image>`) carries only a `label`\n * attribute; the real URL is looked up from the registry at React render\n * time, AFTER both passes have run. Without an explicit re-sanitization\n * here, cross-chunk renders would observably diverge from standalone:\n *\n * - A `[evil]: javascript:…` def in chunk A used by chunk B would render\n * a live `javascript:` link, even though the same source in standalone\n * mode is stripped.\n * - A consumer who allows a custom scheme via `urlTransform` but did NOT\n * add it to `sanitizeSchema.protocols` would see standalone strip the\n * `href`, but cross-chunk render it — silently breaking the \"two gates,\n * defense in depth\" contract documented in README.\n * - A key-aware `urlTransform` (e.g. one that allows a scheme only on\n * `href` but not `src`) would behave correctly in standalone but be\n * bypassed in the cross-chunk image path if we sanitized once at\n * contribute time with a fixed key.\n *\n * This helper makes the cross-chunk path observably identical to the\n * standalone two-gate pipeline, parameterised by the correct `key` for\n * each tag (`'href'` for `<a>`, `'src'` for `<img>`).\n *\n * @module components/crossChunkUrlSanitize\n */\n\nimport { normalizeUri } from 'micromark-util-sanitize-uri';\nimport type { Element as HastElement } from 'hast';\nimport type { UrlTransform } from './markdown';\nimport type { SanitizeSchema } from './extendSanitizeSchema';\nimport { sanitizeSchema as libraryDefaultSchema } from './sanitizeSchema';\n\nexport type UrlAttrKey = 'href' | 'src';\nexport type UrlAttrTag = 'a' | 'img';\n\n/** Synthetic hast element passed as the `node` argument to `urlTransform`.\n * Mirrors the shape the in-tree pipeline would have produced. */\nfunction fakeElement(tagName: UrlAttrTag, key: UrlAttrKey, url: string): HastElement {\n return { type: 'element', tagName, properties: { [key]: url }, children: [] };\n}\n\n/** True if the URL is relative (no protocol prefix before `/`, `?`, or `#`).\n * Relative URLs are always allowed — this mirrors the convention used in\n * `defaultUrlTransform` and `hast-util-sanitize`. */\nfunction isRelative(url: string, colon: number): boolean {\n if (colon === -1) return true;\n const slash = url.indexOf('/');\n const questionMark = url.indexOf('?');\n const numberSign = url.indexOf('#');\n if (slash !== -1 && colon > slash) return true;\n if (questionMark !== -1 && colon > questionMark) return true;\n if (numberSign !== -1 && colon > numberSign) return true;\n return false;\n}\n\n/** Check the URL's protocol against an allowlist (mirrors hast-util-sanitize's\n * `Schema.protocols.<attr>` semantics). Relative URLs are always allowed.\n *\n * **Case-sensitive comparison by design** — `hast-util-sanitize` does literal\n * string equality on the protocol prefix (`url.slice(0, p.length) === p`),\n * so `HTTPS://x` against `['http','https']` is stripped. We mirror that to\n * preserve observable parity with the standalone in-tree pipeline; a more\n * permissive cross-chunk comparison would let mixed-case URLs slip through\n * here that the standalone path strips. */\nfunction isProtocolAllowed(url: string, allowed: ReadonlyArray<string>): boolean {\n const colon = url.indexOf(':');\n if (isRelative(url, colon)) return true;\n const protocol = url.slice(0, colon);\n return allowed.some((p) => p === protocol);\n}\n\n/**\n * Run a cross-chunk-resolved URL through both standalone gates, in the\n * standalone ORDER: `rehype-sanitize`'s protocol allowlist runs in the\n * plugin chain first (a blocked URL loses the attribute entirely), then\n * `urlTransform` rewrites whatever survived during the hast visit pass (its\n * return value is the attribute — `''` from `defaultUrlTransform` renders\n * `href=\"\"`, exactly like a legal empty destination `[x]: <>`).\n *\n * @returns `null` when the protocol gate strips the attribute (render it\n * ABSENT); otherwise the transformed URL string — possibly `''`, which\n * the caller must render as `href=\"\"` / `src=\"\"` to stay byte-identical\n * with standalone (v2.4.1 review: the two used to collapse into `''` and\n * the placeholder omitted the attribute for `[x]: <>` too).\n */\nexport function sanitizeCrossChunkUrl(\n rawUrl: string,\n key: UrlAttrKey,\n tagName: UrlAttrTag,\n urlTransform: UrlTransform,\n schema: SanitizeSchema\n): string | null {\n // Gate 0: the same `normalizeUri` mdast-util-to-hast applies to every\n // in-tree `href`/`src` before the gates see it (percent-encodes spaces,\n // non-ASCII, `\"`, `<` …). Without it a cross-chunk `<https://x/a b>`\n // rendered `href=\"https://x/a b\"` where standalone renders `a%20b`\n // (v2.4.0 review).\n rawUrl = normalizeUri(rawUrl);\n\n // Gate 1: rehype-sanitize protocol allowlist. Mirrors hast-util-sanitize's\n // exact merge + lookup semantics (see `lib/index.js:235` + `:672`):\n //\n // 1. Upstream merges via `{...defaultSchema, ...options}` — a SHALLOW\n // spread. If the caller schema has no `protocols` key at all, the\n // resulting state inherits `defaultSchema.protocols` entirely.\n // Mirror this by falling back to the library default's protocols\n // when the caller didn't specify any.\n // 2. If the caller DID specify `protocols`, upstream uses caller's\n // object verbatim — keys the caller didn't list become \"no\n // restriction\" (upstream's `if (!protocols || ... === 0) return true`).\n // Do NOT cherry-pick library defaults for missing keys here, or the\n // helper becomes stricter than standalone in the partial-schema\n // case (the round-2 codex finding's mirror image).\n // 3. An empty array on the caller's `protocols.<key>` means \"no\n // restriction\" per upstream (the `length === 0` branch), not \"reject\n // all\" — preserve that.\n //\n // Net effect: every shape the standalone path tolerates produces the\n // same observable result here, including a TypeScript-bypass sparse\n // schema (caller passes no `protocols` → library default protocols apply\n // for both gates).\n // `Object.hasOwn`, not `=== undefined`: upstream's shallow spread keeps an\n // EXPLICIT `protocols: undefined` (own key, undefined value) and then\n // treats it as \"no restriction\" — only an ABSENT key inherits the\n // default's protocols (v2.4.2 review P3-4).\n const allowed = Object.hasOwn(schema, 'protocols') ? schema.protocols?.[key] : libraryDefaultSchema.protocols?.[key];\n if (allowed && allowed.length > 0 && !isProtocolAllowed(rawUrl, allowed)) return null;\n\n // Gate 2: urlTransform — caller's allowlist, called with the correct key\n // and a synthetic node mirroring what the in-tree pass would have seen.\n const transformed = urlTransform(rawUrl, key, fakeElement(tagName, key, rawUrl));\n if (transformed == null) return null;\n return String(transformed);\n}\n","/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nexport default listCacheClear;\n","/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nexport default eq;\n","import eq from './eq.js';\n\n/**\n * Gets the index at which the `key` is found in `array` of key-value pairs.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} key The key to search for.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction assocIndexOf(array, key) {\n var length = array.length;\n while (length--) {\n if (eq(array[length][0], key)) {\n return length;\n }\n }\n return -1;\n}\n\nexport default assocIndexOf;\n","import assocIndexOf from './_assocIndexOf.js';\n\n/** Used for built-in method references. */\nvar arrayProto = Array.prototype;\n\n/** Built-in value references. */\nvar splice = arrayProto.splice;\n\n/**\n * Removes `key` and its value from the list cache.\n *\n * @private\n * @name delete\n * @memberOf ListCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction listCacheDelete(key) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n if (index < 0) {\n return false;\n }\n var lastIndex = data.length - 1;\n if (index == lastIndex) {\n data.pop();\n } else {\n splice.call(data, index, 1);\n }\n --this.size;\n return true;\n}\n\nexport default listCacheDelete;\n","import assocIndexOf from './_assocIndexOf.js';\n\n/**\n * Gets the list cache value for `key`.\n *\n * @private\n * @name get\n * @memberOf ListCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction listCacheGet(key) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n return index < 0 ? undefined : data[index][1];\n}\n\nexport default listCacheGet;\n","import assocIndexOf from './_assocIndexOf.js';\n\n/**\n * Checks if a list cache value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf ListCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction listCacheHas(key) {\n return assocIndexOf(this.__data__, key) > -1;\n}\n\nexport default listCacheHas;\n","import assocIndexOf from './_assocIndexOf.js';\n\n/**\n * Sets the list cache `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf ListCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the list cache instance.\n */\nfunction listCacheSet(key, value) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n if (index < 0) {\n ++this.size;\n data.push([key, value]);\n } else {\n data[index][1] = value;\n }\n return this;\n}\n\nexport default listCacheSet;\n","import listCacheClear from './_listCacheClear.js';\nimport listCacheDelete from './_listCacheDelete.js';\nimport listCacheGet from './_listCacheGet.js';\nimport listCacheHas from './_listCacheHas.js';\nimport listCacheSet from './_listCacheSet.js';\n\n/**\n * Creates an list cache object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction ListCache(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n// Add methods to `ListCache`.\nListCache.prototype.clear = listCacheClear;\nListCache.prototype['delete'] = listCacheDelete;\nListCache.prototype.get = listCacheGet;\nListCache.prototype.has = listCacheHas;\nListCache.prototype.set = listCacheSet;\n\nexport default ListCache;\n","import ListCache from './_ListCache.js';\n\n/**\n * Removes all key-value entries from the stack.\n *\n * @private\n * @name clear\n * @memberOf Stack\n */\nfunction stackClear() {\n this.__data__ = new ListCache;\n this.size = 0;\n}\n\nexport default stackClear;\n","/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\nexport default stackDelete;\n","/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\nexport default stackGet;\n","/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\nexport default stackHas;\n","/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\nexport default freeGlobal;\n","import freeGlobal from './_freeGlobal.js';\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\nexport default root;\n","import root from './_root.js';\n\n/** Built-in value references. */\nvar Symbol = root.Symbol;\n\nexport default Symbol;\n","import Symbol from './_Symbol.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the raw `toStringTag`.\n */\nfunction getRawTag(value) {\n var isOwn = hasOwnProperty.call(value, symToStringTag),\n tag = value[symToStringTag];\n\n try {\n value[symToStringTag] = undefined;\n var unmasked = true;\n } catch (e) {}\n\n var result = nativeObjectToString.call(value);\n if (unmasked) {\n if (isOwn) {\n value[symToStringTag] = tag;\n } else {\n delete value[symToStringTag];\n }\n }\n return result;\n}\n\nexport default getRawTag;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","import Symbol from './_Symbol.js';\nimport getRawTag from './_getRawTag.js';\nimport objectToString from './_objectToString.js';\n\n/** `Object#toString` result references. */\nvar nullTag = '[object Null]',\n undefinedTag = '[object Undefined]';\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * The base implementation of `getTag` without fallbacks for buggy environments.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nfunction baseGetTag(value) {\n if (value == null) {\n return value === undefined ? undefinedTag : nullTag;\n }\n return (symToStringTag && symToStringTag in Object(value))\n ? getRawTag(value)\n : objectToString(value);\n}\n\nexport default baseGetTag;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","import baseGetTag from './_baseGetTag.js';\nimport isObject from './isObject.js';\n\n/** `Object#toString` result references. */\nvar asyncTag = '[object AsyncFunction]',\n funcTag = '[object Function]',\n genTag = '[object GeneratorFunction]',\n proxyTag = '[object Proxy]';\n\n/**\n * Checks if `value` is classified as a `Function` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a function, else `false`.\n * @example\n *\n * _.isFunction(_);\n * // => true\n *\n * _.isFunction(/abc/);\n * // => false\n */\nfunction isFunction(value) {\n if (!isObject(value)) {\n return false;\n }\n // The use of `Object#toString` avoids issues with the `typeof` operator\n // in Safari 9 which returns 'object' for typed arrays and other constructors.\n var tag = baseGetTag(value);\n return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;\n}\n\nexport default isFunction;\n","import root from './_root.js';\n\n/** Used to detect overreaching core-js shims. */\nvar coreJsData = root['__core-js_shared__'];\n\nexport default coreJsData;\n","import coreJsData from './_coreJsData.js';\n\n/** Used to detect methods masquerading as native. */\nvar maskSrcKey = (function() {\n var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');\n return uid ? ('Symbol(src)_1.' + uid) : '';\n}());\n\n/**\n * Checks if `func` has its source masked.\n *\n * @private\n * @param {Function} func The function to check.\n * @returns {boolean} Returns `true` if `func` is masked, else `false`.\n */\nfunction isMasked(func) {\n return !!maskSrcKey && (maskSrcKey in func);\n}\n\nexport default isMasked;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nexport default toSource;\n","import isFunction from './isFunction.js';\nimport isMasked from './_isMasked.js';\nimport isObject from './isObject.js';\nimport toSource from './_toSource.js';\n\n/**\n * Used to match `RegExp`\n * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).\n */\nvar reRegExpChar = /[\\\\^$.*+?()[\\]{}|]/g;\n\n/** Used to detect host constructors (Safari). */\nvar reIsHostCtor = /^\\[object .+?Constructor\\]$/;\n\n/** Used for built-in method references. */\nvar funcProto = Function.prototype,\n objectProto = Object.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Used to detect if a method is native. */\nvar reIsNative = RegExp('^' +\n funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\\\$&')\n .replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g, '$1.*?') + '$'\n);\n\n/**\n * The base implementation of `_.isNative` without bad shim checks.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a native function,\n * else `false`.\n */\nfunction baseIsNative(value) {\n if (!isObject(value) || isMasked(value)) {\n return false;\n }\n var pattern = isFunction(value) ? reIsNative : reIsHostCtor;\n return pattern.test(toSource(value));\n}\n\nexport default baseIsNative;\n","/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nexport default getValue;\n","import baseIsNative from './_baseIsNative.js';\nimport getValue from './_getValue.js';\n\n/**\n * Gets the native function at `key` of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the method to get.\n * @returns {*} Returns the function if it's native, else `undefined`.\n */\nfunction getNative(object, key) {\n var value = getValue(object, key);\n return baseIsNative(value) ? value : undefined;\n}\n\nexport default getNative;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar Map = getNative(root, 'Map');\n\nexport default Map;\n","import getNative from './_getNative.js';\n\n/* Built-in method references that are verified to be native. */\nvar nativeCreate = getNative(Object, 'create');\n\nexport default nativeCreate;\n","import nativeCreate from './_nativeCreate.js';\n\n/**\n * Removes all key-value entries from the hash.\n *\n * @private\n * @name clear\n * @memberOf Hash\n */\nfunction hashClear() {\n this.__data__ = nativeCreate ? nativeCreate(null) : {};\n this.size = 0;\n}\n\nexport default hashClear;\n","/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default hashDelete;\n","import nativeCreate from './_nativeCreate.js';\n\n/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Gets the hash value for `key`.\n *\n * @private\n * @name get\n * @memberOf Hash\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction hashGet(key) {\n var data = this.__data__;\n if (nativeCreate) {\n var result = data[key];\n return result === HASH_UNDEFINED ? undefined : result;\n }\n return hasOwnProperty.call(data, key) ? data[key] : undefined;\n}\n\nexport default hashGet;\n","import nativeCreate from './_nativeCreate.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Checks if a hash value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Hash\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction hashHas(key) {\n var data = this.__data__;\n return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key);\n}\n\nexport default hashHas;\n","import nativeCreate from './_nativeCreate.js';\n\n/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/**\n * Sets the hash `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Hash\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the hash instance.\n */\nfunction hashSet(key, value) {\n var data = this.__data__;\n this.size += this.has(key) ? 0 : 1;\n data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;\n return this;\n}\n\nexport default hashSet;\n","import hashClear from './_hashClear.js';\nimport hashDelete from './_hashDelete.js';\nimport hashGet from './_hashGet.js';\nimport hashHas from './_hashHas.js';\nimport hashSet from './_hashSet.js';\n\n/**\n * Creates a hash object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Hash(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n// Add methods to `Hash`.\nHash.prototype.clear = hashClear;\nHash.prototype['delete'] = hashDelete;\nHash.prototype.get = hashGet;\nHash.prototype.has = hashHas;\nHash.prototype.set = hashSet;\n\nexport default Hash;\n","import Hash from './_Hash.js';\nimport ListCache from './_ListCache.js';\nimport Map from './_Map.js';\n\n/**\n * Removes all key-value entries from the map.\n *\n * @private\n * @name clear\n * @memberOf MapCache\n */\nfunction mapCacheClear() {\n this.size = 0;\n this.__data__ = {\n 'hash': new Hash,\n 'map': new (Map || ListCache),\n 'string': new Hash\n };\n}\n\nexport default mapCacheClear;\n","/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nexport default isKeyable;\n","import isKeyable from './_isKeyable.js';\n\n/**\n * Gets the data for `map`.\n *\n * @private\n * @param {Object} map The map to query.\n * @param {string} key The reference key.\n * @returns {*} Returns the map data.\n */\nfunction getMapData(map, key) {\n var data = map.__data__;\n return isKeyable(key)\n ? data[typeof key == 'string' ? 'string' : 'hash']\n : data.map;\n}\n\nexport default getMapData;\n","import getMapData from './_getMapData.js';\n\n/**\n * Removes `key` and its value from the map.\n *\n * @private\n * @name delete\n * @memberOf MapCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction mapCacheDelete(key) {\n var result = getMapData(this, key)['delete'](key);\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default mapCacheDelete;\n","import getMapData from './_getMapData.js';\n\n/**\n * Gets the map value for `key`.\n *\n * @private\n * @name get\n * @memberOf MapCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction mapCacheGet(key) {\n return getMapData(this, key).get(key);\n}\n\nexport default mapCacheGet;\n","import getMapData from './_getMapData.js';\n\n/**\n * Checks if a map value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf MapCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction mapCacheHas(key) {\n return getMapData(this, key).has(key);\n}\n\nexport default mapCacheHas;\n","import getMapData from './_getMapData.js';\n\n/**\n * Sets the map `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf MapCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the map cache instance.\n */\nfunction mapCacheSet(key, value) {\n var data = getMapData(this, key),\n size = data.size;\n\n data.set(key, value);\n this.size += data.size == size ? 0 : 1;\n return this;\n}\n\nexport default mapCacheSet;\n","import mapCacheClear from './_mapCacheClear.js';\nimport mapCacheDelete from './_mapCacheDelete.js';\nimport mapCacheGet from './_mapCacheGet.js';\nimport mapCacheHas from './_mapCacheHas.js';\nimport mapCacheSet from './_mapCacheSet.js';\n\n/**\n * Creates a map cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction MapCache(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n// Add methods to `MapCache`.\nMapCache.prototype.clear = mapCacheClear;\nMapCache.prototype['delete'] = mapCacheDelete;\nMapCache.prototype.get = mapCacheGet;\nMapCache.prototype.has = mapCacheHas;\nMapCache.prototype.set = mapCacheSet;\n\nexport default MapCache;\n","import ListCache from './_ListCache.js';\nimport Map from './_Map.js';\nimport MapCache from './_MapCache.js';\n\n/** Used as the size to enable large array optimizations. */\nvar LARGE_ARRAY_SIZE = 200;\n\n/**\n * Sets the stack `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Stack\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the stack cache instance.\n */\nfunction stackSet(key, value) {\n var data = this.__data__;\n if (data instanceof ListCache) {\n var pairs = data.__data__;\n if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {\n pairs.push([key, value]);\n this.size = ++data.size;\n return this;\n }\n data = this.__data__ = new MapCache(pairs);\n }\n data.set(key, value);\n this.size = data.size;\n return this;\n}\n\nexport default stackSet;\n","import ListCache from './_ListCache.js';\nimport stackClear from './_stackClear.js';\nimport stackDelete from './_stackDelete.js';\nimport stackGet from './_stackGet.js';\nimport stackHas from './_stackHas.js';\nimport stackSet from './_stackSet.js';\n\n/**\n * Creates a stack cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Stack(entries) {\n var data = this.__data__ = new ListCache(entries);\n this.size = data.size;\n}\n\n// Add methods to `Stack`.\nStack.prototype.clear = stackClear;\nStack.prototype['delete'] = stackDelete;\nStack.prototype.get = stackGet;\nStack.prototype.has = stackHas;\nStack.prototype.set = stackSet;\n\nexport default Stack;\n","/**\n * A specialized version of `_.forEach` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns `array`.\n */\nfunction arrayEach(array, iteratee) {\n var index = -1,\n length = array == null ? 0 : array.length;\n\n while (++index < length) {\n if (iteratee(array[index], index, array) === false) {\n break;\n }\n }\n return array;\n}\n\nexport default arrayEach;\n","import getNative from './_getNative.js';\n\nvar defineProperty = (function() {\n try {\n var func = getNative(Object, 'defineProperty');\n func({}, '', {});\n return func;\n } catch (e) {}\n}());\n\nexport default defineProperty;\n","import defineProperty from './_defineProperty.js';\n\n/**\n * The base implementation of `assignValue` and `assignMergeValue` without\n * value checks.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {string} key The key of the property to assign.\n * @param {*} value The value to assign.\n */\nfunction baseAssignValue(object, key, value) {\n if (key == '__proto__' && defineProperty) {\n defineProperty(object, key, {\n 'configurable': true,\n 'enumerable': true,\n 'value': value,\n 'writable': true\n });\n } else {\n object[key] = value;\n }\n}\n\nexport default baseAssignValue;\n","import baseAssignValue from './_baseAssignValue.js';\nimport eq from './eq.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Assigns `value` to `key` of `object` if the existing value is not equivalent\n * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * for equality comparisons.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {string} key The key of the property to assign.\n * @param {*} value The value to assign.\n */\nfunction assignValue(object, key, value) {\n var objValue = object[key];\n if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||\n (value === undefined && !(key in object))) {\n baseAssignValue(object, key, value);\n }\n}\n\nexport default assignValue;\n","import assignValue from './_assignValue.js';\nimport baseAssignValue from './_baseAssignValue.js';\n\n/**\n * Copies properties of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy properties from.\n * @param {Array} props The property identifiers to copy.\n * @param {Object} [object={}] The object to copy properties to.\n * @param {Function} [customizer] The function to customize copied values.\n * @returns {Object} Returns `object`.\n */\nfunction copyObject(source, props, object, customizer) {\n var isNew = !object;\n object || (object = {});\n\n var index = -1,\n length = props.length;\n\n while (++index < length) {\n var key = props[index];\n\n var newValue = customizer\n ? customizer(object[key], source[key], key, object, source)\n : undefined;\n\n if (newValue === undefined) {\n newValue = source[key];\n }\n if (isNew) {\n baseAssignValue(object, key, newValue);\n } else {\n assignValue(object, key, newValue);\n }\n }\n return object;\n}\n\nexport default copyObject;\n","/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\nexport default baseTimes;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","import baseGetTag from './_baseGetTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]';\n\n/**\n * The base implementation of `_.isArguments`.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n */\nfunction baseIsArguments(value) {\n return isObjectLike(value) && baseGetTag(value) == argsTag;\n}\n\nexport default baseIsArguments;\n","import baseIsArguments from './_baseIsArguments.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Built-in value references. */\nvar propertyIsEnumerable = objectProto.propertyIsEnumerable;\n\n/**\n * Checks if `value` is likely an `arguments` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n * else `false`.\n * @example\n *\n * _.isArguments(function() { return arguments; }());\n * // => true\n *\n * _.isArguments([1, 2, 3]);\n * // => false\n */\nvar isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {\n return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&\n !propertyIsEnumerable.call(value, 'callee');\n};\n\nexport default isArguments;\n","/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nexport default isArray;\n","/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nexport default stubFalse;\n","import root from './_root.js';\nimport stubFalse from './stubFalse.js';\n\n/** Detect free variable `exports`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Built-in value references. */\nvar Buffer = moduleExports ? root.Buffer : undefined;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined;\n\n/**\n * Checks if `value` is a buffer.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.\n * @example\n *\n * _.isBuffer(new Buffer(2));\n * // => true\n *\n * _.isBuffer(new Uint8Array(2));\n * // => false\n */\nvar isBuffer = nativeIsBuffer || stubFalse;\n\nexport default isBuffer;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nexport default isIndex;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nexport default isLength;\n","import baseGetTag from './_baseGetTag.js';\nimport isLength from './isLength.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]',\n arrayTag = '[object Array]',\n boolTag = '[object Boolean]',\n dateTag = '[object Date]',\n errorTag = '[object Error]',\n funcTag = '[object Function]',\n mapTag = '[object Map]',\n numberTag = '[object Number]',\n objectTag = '[object Object]',\n regexpTag = '[object RegExp]',\n setTag = '[object Set]',\n stringTag = '[object String]',\n weakMapTag = '[object WeakMap]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n dataViewTag = '[object DataView]',\n float32Tag = '[object Float32Array]',\n float64Tag = '[object Float64Array]',\n int8Tag = '[object Int8Array]',\n int16Tag = '[object Int16Array]',\n int32Tag = '[object Int32Array]',\n uint8Tag = '[object Uint8Array]',\n uint8ClampedTag = '[object Uint8ClampedArray]',\n uint16Tag = '[object Uint16Array]',\n uint32Tag = '[object Uint32Array]';\n\n/** Used to identify `toStringTag` values of typed arrays. */\nvar typedArrayTags = {};\ntypedArrayTags[float32Tag] = typedArrayTags[float64Tag] =\ntypedArrayTags[int8Tag] = typedArrayTags[int16Tag] =\ntypedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =\ntypedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =\ntypedArrayTags[uint32Tag] = true;\ntypedArrayTags[argsTag] = typedArrayTags[arrayTag] =\ntypedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =\ntypedArrayTags[dataViewTag] = typedArrayTags[dateTag] =\ntypedArrayTags[errorTag] = typedArrayTags[funcTag] =\ntypedArrayTags[mapTag] = typedArrayTags[numberTag] =\ntypedArrayTags[objectTag] = typedArrayTags[regexpTag] =\ntypedArrayTags[setTag] = typedArrayTags[stringTag] =\ntypedArrayTags[weakMapTag] = false;\n\n/**\n * The base implementation of `_.isTypedArray` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.\n */\nfunction baseIsTypedArray(value) {\n return isObjectLike(value) &&\n isLength(value.length) && !!typedArrayTags[baseGetTag(value)];\n}\n\nexport default baseIsTypedArray;\n","/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\nexport default baseUnary;\n","import freeGlobal from './_freeGlobal.js';\n\n/** Detect free variable `exports`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Detect free variable `process` from Node.js. */\nvar freeProcess = moduleExports && freeGlobal.process;\n\n/** Used to access faster Node.js helpers. */\nvar nodeUtil = (function() {\n try {\n // Use `util.types` for Node.js 10+.\n var types = freeModule && freeModule.require && freeModule.require('util').types;\n\n if (types) {\n return types;\n }\n\n // Legacy `process.binding('util')` for Node.js < 10.\n return freeProcess && freeProcess.binding && freeProcess.binding('util');\n } catch (e) {}\n}());\n\nexport default nodeUtil;\n","import baseIsTypedArray from './_baseIsTypedArray.js';\nimport baseUnary from './_baseUnary.js';\nimport nodeUtil from './_nodeUtil.js';\n\n/* Node.js helper references. */\nvar nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;\n\n/**\n * Checks if `value` is classified as a typed array.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.\n * @example\n *\n * _.isTypedArray(new Uint8Array);\n * // => true\n *\n * _.isTypedArray([]);\n * // => false\n */\nvar isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;\n\nexport default isTypedArray;\n","import baseTimes from './_baseTimes.js';\nimport isArguments from './isArguments.js';\nimport isArray from './isArray.js';\nimport isBuffer from './isBuffer.js';\nimport isIndex from './_isIndex.js';\nimport isTypedArray from './isTypedArray.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Creates an array of the enumerable property names of the array-like `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @param {boolean} inherited Specify returning inherited property names.\n * @returns {Array} Returns the array of property names.\n */\nfunction arrayLikeKeys(value, inherited) {\n var isArr = isArray(value),\n isArg = !isArr && isArguments(value),\n isBuff = !isArr && !isArg && isBuffer(value),\n isType = !isArr && !isArg && !isBuff && isTypedArray(value),\n skipIndexes = isArr || isArg || isBuff || isType,\n result = skipIndexes ? baseTimes(value.length, String) : [],\n length = result.length;\n\n for (var key in value) {\n if ((inherited || hasOwnProperty.call(value, key)) &&\n !(skipIndexes && (\n // Safari 9 has enumerable `arguments.length` in strict mode.\n key == 'length' ||\n // Node.js 0.10 has enumerable non-index properties on buffers.\n (isBuff && (key == 'offset' || key == 'parent')) ||\n // PhantomJS 2 has enumerable non-index properties on typed arrays.\n (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||\n // Skip index properties.\n isIndex(key, length)\n ))) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default arrayLikeKeys;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\nexport default isPrototype;\n","/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nexport default overArg;\n","import overArg from './_overArg.js';\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeKeys = overArg(Object.keys, Object);\n\nexport default nativeKeys;\n","import isPrototype from './_isPrototype.js';\nimport nativeKeys from './_nativeKeys.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction baseKeys(object) {\n if (!isPrototype(object)) {\n return nativeKeys(object);\n }\n var result = [];\n for (var key in Object(object)) {\n if (hasOwnProperty.call(object, key) && key != 'constructor') {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default baseKeys;\n","import isFunction from './isFunction.js';\nimport isLength from './isLength.js';\n\n/**\n * Checks if `value` is array-like. A value is considered array-like if it's\n * not a function and has a `value.length` that's an integer greater than or\n * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is array-like, else `false`.\n * @example\n *\n * _.isArrayLike([1, 2, 3]);\n * // => true\n *\n * _.isArrayLike(document.body.children);\n * // => true\n *\n * _.isArrayLike('abc');\n * // => true\n *\n * _.isArrayLike(_.noop);\n * // => false\n */\nfunction isArrayLike(value) {\n return value != null && isLength(value.length) && !isFunction(value);\n}\n\nexport default isArrayLike;\n","import arrayLikeKeys from './_arrayLikeKeys.js';\nimport baseKeys from './_baseKeys.js';\nimport isArrayLike from './isArrayLike.js';\n\n/**\n * Creates an array of the own enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects. See the\n * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * for more details.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keys(new Foo);\n * // => ['a', 'b'] (iteration order is not guaranteed)\n *\n * _.keys('hi');\n * // => ['0', '1']\n */\nfunction keys(object) {\n return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);\n}\n\nexport default keys;\n","import copyObject from './_copyObject.js';\nimport keys from './keys.js';\n\n/**\n * The base implementation of `_.assign` without support for multiple sources\n * or `customizer` functions.\n *\n * @private\n * @param {Object} object The destination object.\n * @param {Object} source The source object.\n * @returns {Object} Returns `object`.\n */\nfunction baseAssign(object, source) {\n return object && copyObject(source, keys(source), object);\n}\n\nexport default baseAssign;\n","/**\n * This function is like\n * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * except that it includes inherited enumerable properties.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction nativeKeysIn(object) {\n var result = [];\n if (object != null) {\n for (var key in Object(object)) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default nativeKeysIn;\n","import isObject from './isObject.js';\nimport isPrototype from './_isPrototype.js';\nimport nativeKeysIn from './_nativeKeysIn.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction baseKeysIn(object) {\n if (!isObject(object)) {\n return nativeKeysIn(object);\n }\n var isProto = isPrototype(object),\n result = [];\n\n for (var key in object) {\n if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default baseKeysIn;\n","import arrayLikeKeys from './_arrayLikeKeys.js';\nimport baseKeysIn from './_baseKeysIn.js';\nimport isArrayLike from './isArrayLike.js';\n\n/**\n * Creates an array of the own and inherited enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keysIn(new Foo);\n * // => ['a', 'b', 'c'] (iteration order is not guaranteed)\n */\nfunction keysIn(object) {\n return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);\n}\n\nexport default keysIn;\n","import copyObject from './_copyObject.js';\nimport keysIn from './keysIn.js';\n\n/**\n * The base implementation of `_.assignIn` without support for multiple sources\n * or `customizer` functions.\n *\n * @private\n * @param {Object} object The destination object.\n * @param {Object} source The source object.\n * @returns {Object} Returns `object`.\n */\nfunction baseAssignIn(object, source) {\n return object && copyObject(source, keysIn(source), object);\n}\n\nexport default baseAssignIn;\n","import root from './_root.js';\n\n/** Detect free variable `exports`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Built-in value references. */\nvar Buffer = moduleExports ? root.Buffer : undefined,\n allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined;\n\n/**\n * Creates a clone of `buffer`.\n *\n * @private\n * @param {Buffer} buffer The buffer to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Buffer} Returns the cloned buffer.\n */\nfunction cloneBuffer(buffer, isDeep) {\n if (isDeep) {\n return buffer.slice();\n }\n var length = buffer.length,\n result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length);\n\n buffer.copy(result);\n return result;\n}\n\nexport default cloneBuffer;\n","/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n var index = -1,\n length = source.length;\n\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n}\n\nexport default copyArray;\n","/**\n * A specialized version of `_.filter` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {Array} Returns the new filtered array.\n */\nfunction arrayFilter(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length,\n resIndex = 0,\n result = [];\n\n while (++index < length) {\n var value = array[index];\n if (predicate(value, index, array)) {\n result[resIndex++] = value;\n }\n }\n return result;\n}\n\nexport default arrayFilter;\n","/**\n * This method returns a new empty array.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {Array} Returns the new empty array.\n * @example\n *\n * var arrays = _.times(2, _.stubArray);\n *\n * console.log(arrays);\n * // => [[], []]\n *\n * console.log(arrays[0] === arrays[1]);\n * // => false\n */\nfunction stubArray() {\n return [];\n}\n\nexport default stubArray;\n","import arrayFilter from './_arrayFilter.js';\nimport stubArray from './stubArray.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Built-in value references. */\nvar propertyIsEnumerable = objectProto.propertyIsEnumerable;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeGetSymbols = Object.getOwnPropertySymbols;\n\n/**\n * Creates an array of the own enumerable symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of symbols.\n */\nvar getSymbols = !nativeGetSymbols ? stubArray : function(object) {\n if (object == null) {\n return [];\n }\n object = Object(object);\n return arrayFilter(nativeGetSymbols(object), function(symbol) {\n return propertyIsEnumerable.call(object, symbol);\n });\n};\n\nexport default getSymbols;\n","import copyObject from './_copyObject.js';\nimport getSymbols from './_getSymbols.js';\n\n/**\n * Copies own symbols of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy symbols from.\n * @param {Object} [object={}] The object to copy symbols to.\n * @returns {Object} Returns `object`.\n */\nfunction copySymbols(source, object) {\n return copyObject(source, getSymbols(source), object);\n}\n\nexport default copySymbols;\n","/**\n * Appends the elements of `values` to `array`.\n *\n * @private\n * @param {Array} array The array to modify.\n * @param {Array} values The values to append.\n * @returns {Array} Returns `array`.\n */\nfunction arrayPush(array, values) {\n var index = -1,\n length = values.length,\n offset = array.length;\n\n while (++index < length) {\n array[offset + index] = values[index];\n }\n return array;\n}\n\nexport default arrayPush;\n","import overArg from './_overArg.js';\n\n/** Built-in value references. */\nvar getPrototype = overArg(Object.getPrototypeOf, Object);\n\nexport default getPrototype;\n","import arrayPush from './_arrayPush.js';\nimport getPrototype from './_getPrototype.js';\nimport getSymbols from './_getSymbols.js';\nimport stubArray from './stubArray.js';\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeGetSymbols = Object.getOwnPropertySymbols;\n\n/**\n * Creates an array of the own and inherited enumerable symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of symbols.\n */\nvar getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) {\n var result = [];\n while (object) {\n arrayPush(result, getSymbols(object));\n object = getPrototype(object);\n }\n return result;\n};\n\nexport default getSymbolsIn;\n","import copyObject from './_copyObject.js';\nimport getSymbolsIn from './_getSymbolsIn.js';\n\n/**\n * Copies own and inherited symbols of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy symbols from.\n * @param {Object} [object={}] The object to copy symbols to.\n * @returns {Object} Returns `object`.\n */\nfunction copySymbolsIn(source, object) {\n return copyObject(source, getSymbolsIn(source), object);\n}\n\nexport default copySymbolsIn;\n","import arrayPush from './_arrayPush.js';\nimport isArray from './isArray.js';\n\n/**\n * The base implementation of `getAllKeys` and `getAllKeysIn` which uses\n * `keysFunc` and `symbolsFunc` to get the enumerable property names and\n * symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Function} keysFunc The function to get the keys of `object`.\n * @param {Function} symbolsFunc The function to get the symbols of `object`.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction baseGetAllKeys(object, keysFunc, symbolsFunc) {\n var result = keysFunc(object);\n return isArray(object) ? result : arrayPush(result, symbolsFunc(object));\n}\n\nexport default baseGetAllKeys;\n","import baseGetAllKeys from './_baseGetAllKeys.js';\nimport getSymbols from './_getSymbols.js';\nimport keys from './keys.js';\n\n/**\n * Creates an array of own enumerable property names and symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction getAllKeys(object) {\n return baseGetAllKeys(object, keys, getSymbols);\n}\n\nexport default getAllKeys;\n","import baseGetAllKeys from './_baseGetAllKeys.js';\nimport getSymbolsIn from './_getSymbolsIn.js';\nimport keysIn from './keysIn.js';\n\n/**\n * Creates an array of own and inherited enumerable property names and\n * symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction getAllKeysIn(object) {\n return baseGetAllKeys(object, keysIn, getSymbolsIn);\n}\n\nexport default getAllKeysIn;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar DataView = getNative(root, 'DataView');\n\nexport default DataView;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar Promise = getNative(root, 'Promise');\n\nexport default Promise;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar Set = getNative(root, 'Set');\n\nexport default Set;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar WeakMap = getNative(root, 'WeakMap');\n\nexport default WeakMap;\n","import DataView from './_DataView.js';\nimport Map from './_Map.js';\nimport Promise from './_Promise.js';\nimport Set from './_Set.js';\nimport WeakMap from './_WeakMap.js';\nimport baseGetTag from './_baseGetTag.js';\nimport toSource from './_toSource.js';\n\n/** `Object#toString` result references. */\nvar mapTag = '[object Map]',\n objectTag = '[object Object]',\n promiseTag = '[object Promise]',\n setTag = '[object Set]',\n weakMapTag = '[object WeakMap]';\n\nvar dataViewTag = '[object DataView]';\n\n/** Used to detect maps, sets, and weakmaps. */\nvar dataViewCtorString = toSource(DataView),\n mapCtorString = toSource(Map),\n promiseCtorString = toSource(Promise),\n setCtorString = toSource(Set),\n weakMapCtorString = toSource(WeakMap);\n\n/**\n * Gets the `toStringTag` of `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nvar getTag = baseGetTag;\n\n// Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.\nif ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||\n (Map && getTag(new Map) != mapTag) ||\n (Promise && getTag(Promise.resolve()) != promiseTag) ||\n (Set && getTag(new Set) != setTag) ||\n (WeakMap && getTag(new WeakMap) != weakMapTag)) {\n getTag = function(value) {\n var result = baseGetTag(value),\n Ctor = result == objectTag ? value.constructor : undefined,\n ctorString = Ctor ? toSource(Ctor) : '';\n\n if (ctorString) {\n switch (ctorString) {\n case dataViewCtorString: return dataViewTag;\n case mapCtorString: return mapTag;\n case promiseCtorString: return promiseTag;\n case setCtorString: return setTag;\n case weakMapCtorString: return weakMapTag;\n }\n }\n return result;\n };\n}\n\nexport default getTag;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Initializes an array clone.\n *\n * @private\n * @param {Array} array The array to clone.\n * @returns {Array} Returns the initialized clone.\n */\nfunction initCloneArray(array) {\n var length = array.length,\n result = new array.constructor(length);\n\n // Add properties assigned by `RegExp#exec`.\n if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {\n result.index = array.index;\n result.input = array.input;\n }\n return result;\n}\n\nexport default initCloneArray;\n","import root from './_root.js';\n\n/** Built-in value references. */\nvar Uint8Array = root.Uint8Array;\n\nexport default Uint8Array;\n","import Uint8Array from './_Uint8Array.js';\n\n/**\n * Creates a clone of `arrayBuffer`.\n *\n * @private\n * @param {ArrayBuffer} arrayBuffer The array buffer to clone.\n * @returns {ArrayBuffer} Returns the cloned array buffer.\n */\nfunction cloneArrayBuffer(arrayBuffer) {\n var result = new arrayBuffer.constructor(arrayBuffer.byteLength);\n new Uint8Array(result).set(new Uint8Array(arrayBuffer));\n return result;\n}\n\nexport default cloneArrayBuffer;\n","import cloneArrayBuffer from './_cloneArrayBuffer.js';\n\n/**\n * Creates a clone of `dataView`.\n *\n * @private\n * @param {Object} dataView The data view to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned data view.\n */\nfunction cloneDataView(dataView, isDeep) {\n var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;\n return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);\n}\n\nexport default cloneDataView;\n","/** Used to match `RegExp` flags from their coerced string values. */\nvar reFlags = /\\w*$/;\n\n/**\n * Creates a clone of `regexp`.\n *\n * @private\n * @param {Object} regexp The regexp to clone.\n * @returns {Object} Returns the cloned regexp.\n */\nfunction cloneRegExp(regexp) {\n var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));\n result.lastIndex = regexp.lastIndex;\n return result;\n}\n\nexport default cloneRegExp;\n","import Symbol from './_Symbol.js';\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined,\n symbolValueOf = symbolProto ? symbolProto.valueOf : undefined;\n\n/**\n * Creates a clone of the `symbol` object.\n *\n * @private\n * @param {Object} symbol The symbol object to clone.\n * @returns {Object} Returns the cloned symbol object.\n */\nfunction cloneSymbol(symbol) {\n return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};\n}\n\nexport default cloneSymbol;\n","import cloneArrayBuffer from './_cloneArrayBuffer.js';\n\n/**\n * Creates a clone of `typedArray`.\n *\n * @private\n * @param {Object} typedArray The typed array to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned typed array.\n */\nfunction cloneTypedArray(typedArray, isDeep) {\n var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;\n return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);\n}\n\nexport default cloneTypedArray;\n","import cloneArrayBuffer from './_cloneArrayBuffer.js';\nimport cloneDataView from './_cloneDataView.js';\nimport cloneRegExp from './_cloneRegExp.js';\nimport cloneSymbol from './_cloneSymbol.js';\nimport cloneTypedArray from './_cloneTypedArray.js';\n\n/** `Object#toString` result references. */\nvar boolTag = '[object Boolean]',\n dateTag = '[object Date]',\n mapTag = '[object Map]',\n numberTag = '[object Number]',\n regexpTag = '[object RegExp]',\n setTag = '[object Set]',\n stringTag = '[object String]',\n symbolTag = '[object Symbol]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n dataViewTag = '[object DataView]',\n float32Tag = '[object Float32Array]',\n float64Tag = '[object Float64Array]',\n int8Tag = '[object Int8Array]',\n int16Tag = '[object Int16Array]',\n int32Tag = '[object Int32Array]',\n uint8Tag = '[object Uint8Array]',\n uint8ClampedTag = '[object Uint8ClampedArray]',\n uint16Tag = '[object Uint16Array]',\n uint32Tag = '[object Uint32Array]';\n\n/**\n * Initializes an object clone based on its `toStringTag`.\n *\n * **Note:** This function only supports cloning values with tags of\n * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`.\n *\n * @private\n * @param {Object} object The object to clone.\n * @param {string} tag The `toStringTag` of the object to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the initialized clone.\n */\nfunction initCloneByTag(object, tag, isDeep) {\n var Ctor = object.constructor;\n switch (tag) {\n case arrayBufferTag:\n return cloneArrayBuffer(object);\n\n case boolTag:\n case dateTag:\n return new Ctor(+object);\n\n case dataViewTag:\n return cloneDataView(object, isDeep);\n\n case float32Tag: case float64Tag:\n case int8Tag: case int16Tag: case int32Tag:\n case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:\n return cloneTypedArray(object, isDeep);\n\n case mapTag:\n return new Ctor;\n\n case numberTag:\n case stringTag:\n return new Ctor(object);\n\n case regexpTag:\n return cloneRegExp(object);\n\n case setTag:\n return new Ctor;\n\n case symbolTag:\n return cloneSymbol(object);\n }\n}\n\nexport default initCloneByTag;\n","import isObject from './isObject.js';\n\n/** Built-in value references. */\nvar objectCreate = Object.create;\n\n/**\n * The base implementation of `_.create` without support for assigning\n * properties to the created object.\n *\n * @private\n * @param {Object} proto The object to inherit from.\n * @returns {Object} Returns the new object.\n */\nvar baseCreate = (function() {\n function object() {}\n return function(proto) {\n if (!isObject(proto)) {\n return {};\n }\n if (objectCreate) {\n return objectCreate(proto);\n }\n object.prototype = proto;\n var result = new object;\n object.prototype = undefined;\n return result;\n };\n}());\n\nexport default baseCreate;\n","import baseCreate from './_baseCreate.js';\nimport getPrototype from './_getPrototype.js';\nimport isPrototype from './_isPrototype.js';\n\n/**\n * Initializes an object clone.\n *\n * @private\n * @param {Object} object The object to clone.\n * @returns {Object} Returns the initialized clone.\n */\nfunction initCloneObject(object) {\n return (typeof object.constructor == 'function' && !isPrototype(object))\n ? baseCreate(getPrototype(object))\n : {};\n}\n\nexport default initCloneObject;\n","import getTag from './_getTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar mapTag = '[object Map]';\n\n/**\n * The base implementation of `_.isMap` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a map, else `false`.\n */\nfunction baseIsMap(value) {\n return isObjectLike(value) && getTag(value) == mapTag;\n}\n\nexport default baseIsMap;\n","import baseIsMap from './_baseIsMap.js';\nimport baseUnary from './_baseUnary.js';\nimport nodeUtil from './_nodeUtil.js';\n\n/* Node.js helper references. */\nvar nodeIsMap = nodeUtil && nodeUtil.isMap;\n\n/**\n * Checks if `value` is classified as a `Map` object.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a map, else `false`.\n * @example\n *\n * _.isMap(new Map);\n * // => true\n *\n * _.isMap(new WeakMap);\n * // => false\n */\nvar isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap;\n\nexport default isMap;\n","import getTag from './_getTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar setTag = '[object Set]';\n\n/**\n * The base implementation of `_.isSet` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a set, else `false`.\n */\nfunction baseIsSet(value) {\n return isObjectLike(value) && getTag(value) == setTag;\n}\n\nexport default baseIsSet;\n","import baseIsSet from './_baseIsSet.js';\nimport baseUnary from './_baseUnary.js';\nimport nodeUtil from './_nodeUtil.js';\n\n/* Node.js helper references. */\nvar nodeIsSet = nodeUtil && nodeUtil.isSet;\n\n/**\n * Checks if `value` is classified as a `Set` object.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a set, else `false`.\n * @example\n *\n * _.isSet(new Set);\n * // => true\n *\n * _.isSet(new WeakSet);\n * // => false\n */\nvar isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet;\n\nexport default isSet;\n","import Stack from './_Stack.js';\nimport arrayEach from './_arrayEach.js';\nimport assignValue from './_assignValue.js';\nimport baseAssign from './_baseAssign.js';\nimport baseAssignIn from './_baseAssignIn.js';\nimport cloneBuffer from './_cloneBuffer.js';\nimport copyArray from './_copyArray.js';\nimport copySymbols from './_copySymbols.js';\nimport copySymbolsIn from './_copySymbolsIn.js';\nimport getAllKeys from './_getAllKeys.js';\nimport getAllKeysIn from './_getAllKeysIn.js';\nimport getTag from './_getTag.js';\nimport initCloneArray from './_initCloneArray.js';\nimport initCloneByTag from './_initCloneByTag.js';\nimport initCloneObject from './_initCloneObject.js';\nimport isArray from './isArray.js';\nimport isBuffer from './isBuffer.js';\nimport isMap from './isMap.js';\nimport isObject from './isObject.js';\nimport isSet from './isSet.js';\nimport keys from './keys.js';\nimport keysIn from './keysIn.js';\n\n/** Used to compose bitmasks for cloning. */\nvar CLONE_DEEP_FLAG = 1,\n CLONE_FLAT_FLAG = 2,\n CLONE_SYMBOLS_FLAG = 4;\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]',\n arrayTag = '[object Array]',\n boolTag = '[object Boolean]',\n dateTag = '[object Date]',\n errorTag = '[object Error]',\n funcTag = '[object Function]',\n genTag = '[object GeneratorFunction]',\n mapTag = '[object Map]',\n numberTag = '[object Number]',\n objectTag = '[object Object]',\n regexpTag = '[object RegExp]',\n setTag = '[object Set]',\n stringTag = '[object String]',\n symbolTag = '[object Symbol]',\n weakMapTag = '[object WeakMap]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n dataViewTag = '[object DataView]',\n float32Tag = '[object Float32Array]',\n float64Tag = '[object Float64Array]',\n int8Tag = '[object Int8Array]',\n int16Tag = '[object Int16Array]',\n int32Tag = '[object Int32Array]',\n uint8Tag = '[object Uint8Array]',\n uint8ClampedTag = '[object Uint8ClampedArray]',\n uint16Tag = '[object Uint16Array]',\n uint32Tag = '[object Uint32Array]';\n\n/** Used to identify `toStringTag` values supported by `_.clone`. */\nvar cloneableTags = {};\ncloneableTags[argsTag] = cloneableTags[arrayTag] =\ncloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =\ncloneableTags[boolTag] = cloneableTags[dateTag] =\ncloneableTags[float32Tag] = cloneableTags[float64Tag] =\ncloneableTags[int8Tag] = cloneableTags[int16Tag] =\ncloneableTags[int32Tag] = cloneableTags[mapTag] =\ncloneableTags[numberTag] = cloneableTags[objectTag] =\ncloneableTags[regexpTag] = cloneableTags[setTag] =\ncloneableTags[stringTag] = cloneableTags[symbolTag] =\ncloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =\ncloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;\ncloneableTags[errorTag] = cloneableTags[funcTag] =\ncloneableTags[weakMapTag] = false;\n\n/**\n * The base implementation of `_.clone` and `_.cloneDeep` which tracks\n * traversed objects.\n *\n * @private\n * @param {*} value The value to clone.\n * @param {boolean} bitmask The bitmask flags.\n * 1 - Deep clone\n * 2 - Flatten inherited properties\n * 4 - Clone symbols\n * @param {Function} [customizer] The function to customize cloning.\n * @param {string} [key] The key of `value`.\n * @param {Object} [object] The parent object of `value`.\n * @param {Object} [stack] Tracks traversed objects and their clone counterparts.\n * @returns {*} Returns the cloned value.\n */\nfunction baseClone(value, bitmask, customizer, key, object, stack) {\n var result,\n isDeep = bitmask & CLONE_DEEP_FLAG,\n isFlat = bitmask & CLONE_FLAT_FLAG,\n isFull = bitmask & CLONE_SYMBOLS_FLAG;\n\n if (customizer) {\n result = object ? customizer(value, key, object, stack) : customizer(value);\n }\n if (result !== undefined) {\n return result;\n }\n if (!isObject(value)) {\n return value;\n }\n var isArr = isArray(value);\n if (isArr) {\n result = initCloneArray(value);\n if (!isDeep) {\n return copyArray(value, result);\n }\n } else {\n var tag = getTag(value),\n isFunc = tag == funcTag || tag == genTag;\n\n if (isBuffer(value)) {\n return cloneBuffer(value, isDeep);\n }\n if (tag == objectTag || tag == argsTag || (isFunc && !object)) {\n result = (isFlat || isFunc) ? {} : initCloneObject(value);\n if (!isDeep) {\n return isFlat\n ? copySymbolsIn(value, baseAssignIn(result, value))\n : copySymbols(value, baseAssign(result, value));\n }\n } else {\n if (!cloneableTags[tag]) {\n return object ? value : {};\n }\n result = initCloneByTag(value, tag, isDeep);\n }\n }\n // Check for circular references and return its corresponding clone.\n stack || (stack = new Stack);\n var stacked = stack.get(value);\n if (stacked) {\n return stacked;\n }\n stack.set(value, result);\n\n if (isSet(value)) {\n value.forEach(function(subValue) {\n result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack));\n });\n } else if (isMap(value)) {\n value.forEach(function(subValue, key) {\n result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack));\n });\n }\n\n var keysFunc = isFull\n ? (isFlat ? getAllKeysIn : getAllKeys)\n : (isFlat ? keysIn : keys);\n\n var props = isArr ? undefined : keysFunc(value);\n arrayEach(props || value, function(subValue, key) {\n if (props) {\n key = subValue;\n subValue = value[key];\n }\n // Recursively populate clone (susceptible to call stack limits).\n assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack));\n });\n return result;\n}\n\nexport default baseClone;\n","import baseClone from './_baseClone.js';\n\n/** Used to compose bitmasks for cloning. */\nvar CLONE_DEEP_FLAG = 1,\n CLONE_SYMBOLS_FLAG = 4;\n\n/**\n * This method is like `_.clone` except that it recursively clones `value`.\n *\n * @static\n * @memberOf _\n * @since 1.0.0\n * @category Lang\n * @param {*} value The value to recursively clone.\n * @returns {*} Returns the deep cloned value.\n * @see _.clone\n * @example\n *\n * var objects = [{ 'a': 1 }, { 'b': 2 }];\n *\n * var deep = _.cloneDeep(objects);\n * console.log(deep[0] === objects[0]);\n * // => false\n */\nfunction cloneDeep(value) {\n return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG);\n}\n\nexport default cloneDeep;\n","/**\n * Builds the `rehype-sanitize` schema used by the internal markdown renderer.\n *\n * Extracted into its own module so the merge logic can be unit-tested in\n * isolation without pulling in React or the full markdown pipeline.\n *\n * @module components/sanitizeSchema\n */\n\nimport cloneDeep from 'lodash-es/cloneDeep';\nimport { defaultSchema } from 'rehype-sanitize';\n\ntype Schema = typeof defaultSchema;\ntype AttributeEntry = NonNullable<NonNullable<Schema['attributes']>[string]>[number];\n\n/**\n * Extend the allowlist for a tag's `className` attribute with extra class\n * names while preserving all other default entries.\n *\n * `findDefinition` in hast-util-sanitize returns the *first* matching entry\n * for a given property name, so appending a second `className` entry would be\n * ignored. Instead, merge the allowed values into the existing entry.\n *\n * Edge cases:\n * - `existing` is `undefined` → returns a single new `['className', ...extra]`\n * - `existing` has no `className` entry → appends one with just the extras\n * - `existing` has a bare-string `'className'` entry (hast-util-sanitize's\n * \"allow all values\" form) → would be narrowed to an allow-list. This is a\n * semantics change, but the current `defaultSchema.attributes.code` entry\n * is always tuple-form, so this branch is defensive only.\n */\nexport function mergeClassNameAllowlist(\n existing: ReadonlyArray<AttributeEntry> | undefined,\n extraClassNames: readonly string[]\n): AttributeEntry[] {\n const entries: AttributeEntry[] = existing ? [...existing] : [];\n const idx = entries.findIndex((entry) =>\n typeof entry === 'string' ? entry === 'className' : entry[0] === 'className'\n );\n if (idx === -1) {\n return [...entries, ['className', ...extraClassNames]];\n }\n const current = entries[idx];\n const merged: AttributeEntry =\n typeof current === 'string' ? ['className', ...extraClassNames] : [...current, ...extraClassNames];\n entries[idx] = merged;\n return entries;\n}\n\nconst crossChunkTags = ['cross-chunk-link', 'cross-chunk-image', 'footnote-sup'] as const;\n\n/**\n * The full sanitize schema used by the markdown renderer: extends\n * `defaultSchema` to allow `<mark>`, the KaTeX math class names, and the\n * three custom hast tags emitted by cross-chunk coordination handlers.\n *\n * **Owns its arrays and objects.** The shallow spread of `defaultSchema`\n * alone would leave `attributes.a`, `attributes.img`, `protocols`,\n * `ancestors`, and similar nested fields aliased to `rehype-sanitize`'s\n * default singleton. A consumer who reasonably (but mistakenly) writes\n * `sanitizeSchema.protocols.href.push('myapp')` would then poison\n * `rehype-sanitize`'s `defaultSchema` for every other consumer in the\n * process — a cross-package side-effect that's near-impossible to debug.\n *\n * One `cloneDeep` at module init breaks that aliasing without measurable\n * cost (init-time only, single small object graph). The recommended\n * extension API is still {@link extendSanitizeSchema}, which clones again\n * per call; this layer just makes the exported singleton safe if someone\n * skips the helper.\n *\n * **Deep-frozen.** The engine barrel exports this object, and a mutation\n * (`sanitizeSchema.tagNames.push('script')`) would silently widen the\n * sanitizer for every renderer in the process — the README calls it a\n * read-only singleton, so it is one (2026-08-19 review r2 P3). lodash\n * `cloneDeep` of a frozen graph yields a MUTABLE copy, so\n * `extendSanitizeSchema` drafts are unaffected.\n *\n * `strip` (elements dropped WITH their content, instead of unwrapped to\n * their children) covers the raw-text elements whose content is never\n * prose: `<style>a{b:c}</style>` used to leave `a{b:c}` as body text —\n * common in LLM answers that emit a `<style>` block (r2 P3).\n */\nfunction deepFreeze<T>(value: T): T {\n if (value !== null && typeof value === 'object' && !Object.isFrozen(value)) {\n Object.freeze(value);\n for (const key of Object.keys(value as object)) deepFreeze((value as Record<string, unknown>)[key]);\n }\n return value;\n}\n\n/** Raw-text elements stripped with their content (see above). `script` is\n * rehype-sanitize's own default. */\nconst STRIPPED_TAGS = ['script', 'style', 'title', 'textarea', 'noframes', 'noembed', 'xmp', 'iframe', 'plaintext'];\n\nexport const sanitizeSchema: Schema = deepFreeze(\n cloneDeep({\n ...defaultSchema,\n tagNames: [...(defaultSchema.tagNames || []), 'mark', ...crossChunkTags],\n attributes: {\n ...defaultSchema.attributes,\n code: mergeClassNameAllowlist(defaultSchema.attributes?.code, ['math-inline', 'math-display']),\n 'cross-chunk-link': ['label', 'referenceType', 'documentId', 'localUrl', 'localTitle'],\n 'cross-chunk-image': ['label', 'referenceType', 'documentId', 'alt', 'localUrl', 'localTitle'],\n 'footnote-sup': ['label', 'localOccurrence', 'localNumber', 'documentId'],\n },\n strip: [...new Set([...(defaultSchema.strip || []), ...STRIPPED_TAGS])],\n })\n);\n","/**\n * Type definitions for the sealed engine plugin system (v2 input surface).\n *\n * An \"engine plugin\" is a first-class, core-exported description of one\n * configurable entry in the unified plugin chain. The five shipped plugins\n * replace the two v1.x enums (`AIMarkdownRenderExtraSyntax` /\n * `AIMarkdownRenderDisplayOptimizeAbility`) as the public way to select\n * optional parse-level capability.\n *\n * ## Why the set is sealed\n *\n * The incremental (prefix-freeze) parse engine's boundary scanner is\n * syntax-aware — it must know the boundary rules of every multiline\n * construct in the chain (see `computeFreezeBoundary`'s `defListEnabled`\n * option). Open plugin injection would void the engine's verification\n * record (50k-sample fuzz, direction batteries, byte equivalence), so\n * plugins are born where the certification rig lives: `packages/core`.\n * Wrappers curate (bundle default sets, filter, facade sugar); consumers\n * select. New parse-level capability lands via an upstream PR into core.\n * Third-party *content* extension stays open through `contentPreprocessors`\n * and `customComponents`.\n *\n * ## Seal mechanics\n *\n * The seal is a type-level contract and design declaration, not runtime\n * tamper-proofing — the same guarantee class as `Object.freeze`. The\n * `'~sealed'` marker key makes accidental construction a type error while\n * keeping the type structural, which is required for the type to remain\n * assignable across the package's two build entries (the root entry and\n * the `/plugins` subpath must stay mutually assignable whether or not the\n * build duplicates this declaration per entry; a `unique symbol` brand\n * would break the duplicated case. Current tsup output happens to share\n * one declaration chunk between the entries — an implementation detail\n * the seal deliberately does not lean on). A second, runtime gate\n * (`getEnginePluginInternals`, enforced in `sanitizeEnginePlugins`)\n * additionally rejects any object that lacks EITHER the marker or the\n * internal stage metadata, so a type-level forge is dropped at runtime\n * with a dev warning. Deliberately forging both keys voids the engine's\n * verification record.\n *\n * @module plugins/defs\n */\n\n/**\n * Names of the shipped engine plugins. Closed to third-party EXTENSION (see\n * module docs), but an OPEN set across 2.x versions: new plugin names may be\n * added in minor releases. Do not write exhaustive `switch` statements or\n * `Record<AIMarkdownEnginePluginName, …>` maps over this union — both break\n * on the next addition. Feature-test with `Set`/`includes` instead.\n */\nexport type AIMarkdownEnginePluginName = 'highlight' | 'definitionList' | 'smartypants' | 'pangu' | 'removeComments';\n\n/**\n * A sealed engine plugin. Values are core-exported singletons from\n * `@ai-react-markdown/core/plugins`; pass them to the `enginePlugins` prop\n * of `<AIMarkdown>`.\n *\n * - Passing an array replaces the default set wholesale (array-atomic\n * semantics); omitting the prop means `defaultEnginePlugins` (all five).\n * - The produced chain position of each plugin comes from canonical\n * per-stage tables keyed by name (`pluginChain.ts`) — the order of the\n * user-supplied array is irrelevant.\n * - Duplicate members are deduplicated with a dev warning.\n * - Serializing plugin objects is unsupported; transport\n * {@link AIMarkdownEnginePlugin.name} instead and map names back to the\n * exported singletons at the edge (remote-config scenarios).\n */\nexport interface AIMarkdownEnginePlugin {\n /** Stable identifier; the serialization escape hatch. */\n readonly name: AIMarkdownEnginePluginName;\n /**\n * @internal Type-level seal — constructible only inside core. Third-party\n * construction (including deliberately forging this marker) voids the\n * incremental engine's verification record.\n */\n readonly '~sealed': 'ai-react-markdown/engine-plugin';\n}\n\n/**\n * Chain stage a plugin belongs to. Determines the plugin's splice position\n * in the produced remark chain — user array order never does.\n * @internal\n */\nexport type EnginePluginStage = 'extraSyntax' | 'displayOptimize';\n\n/**\n * Runtime metadata carried by every sealed plugin object. Not part of the\n * public type — internal consumers read it through\n * {@link getEnginePluginInternals}.\n * @internal\n */\nexport interface EnginePluginInternals {\n readonly stage: EnginePluginStage;\n}\n\n/**\n * Read a sealed plugin's internal metadata. Returns `null` for objects that\n * do not carry it (a forged or foreign object) so callers can reject them\n * defensively instead of crashing.\n * @internal\n */\nexport function getEnginePluginInternals(plugin: AIMarkdownEnginePlugin): EnginePluginInternals | null {\n const candidate = plugin as unknown as (Partial<EnginePluginInternals> & Partial<AIMarkdownEnginePlugin>) | null;\n // Both keys are required, so the runtime gate matches the type-level seal:\n // an object carrying only the public `'~sealed'` marker (a deliberate\n // forge) or only the internal `stage` (an untyped structural mimic) is\n // rejected either way.\n return candidate != null && candidate['~sealed'] === 'ai-react-markdown/engine-plugin' && candidate.stage != null\n ? (candidate as EnginePluginInternals)\n : null;\n}\n","/**\n * The five shipped engine plugins and the default set.\n *\n * Construction happens ONLY here (principle P7: capability construction\n * follows the verification harness — the certification rig lives in this\n * package). Each object is frozen and carries internal stage metadata that\n * fixes its position in the produced chain; see `plugins/defs.ts` for the\n * seal rationale.\n *\n * @module plugins/catalog\n */\n\nimport type { AIMarkdownEnginePlugin, AIMarkdownEnginePluginName, EnginePluginInternals } from './defs';\n\nconst seal = (name: AIMarkdownEnginePluginName, stage: EnginePluginInternals['stage']): AIMarkdownEnginePlugin =>\n Object.freeze({\n name,\n '~sealed': 'ai-react-markdown/engine-plugin',\n stage,\n }) as AIMarkdownEnginePlugin;\n\n/** `==Highlight==` syntax support (v1.x: `AIMarkdownRenderExtraSyntax.HIGHLIGHT`). */\nexport const highlight = seal('highlight', 'extraSyntax');\n\n/**\n * Definition list syntax (v1.x: `AIMarkdownRenderExtraSyntax.DEFINITION_LIST`).\n * @see https://michelf.ca/projects/php-markdown/extra/#def-list\n */\nexport const definitionList = seal('definitionList', 'extraSyntax');\n\n/** Strip HTML comments from the content (v1.x: `REMOVE_COMMENTS`). */\nexport const removeComments = seal('removeComments', 'displayOptimize');\n\n/**\n * Typographic enhancements via SmartyPants — curly quotes, em-dashes, etc.\n * (v1.x: `SMARTYPANTS`). @see https://www.npmjs.com/package/smartypants\n */\nexport const smartypants = seal('smartypants', 'displayOptimize');\n\n/** Automatic spacing between CJK and half-width characters (v1.x: `PANGU`). */\nexport const pangu = seal('pangu', 'displayOptimize');\n\n/**\n * The default engine plugin set — all five, in canonical chain order.\n * Parity with the v1.x shipped defaults (`defaultAIMarkdownRenderConfig`).\n *\n * The recommended \"turn one off\" idiom:\n * ```ts\n * <AIMarkdown enginePlugins={defaultEnginePlugins.filter((p) => p !== pangu)} />\n * ```\n */\nexport const defaultEnginePlugins: readonly AIMarkdownEnginePlugin[] = Object.freeze([\n highlight,\n definitionList,\n removeComments,\n smartypants,\n pangu,\n]);\n","/**\n * Shorten long consumer-supplied `documentId` values down to a fixed-length\n * Base62 hash so they don't bloat every rendered `id=\"…\"` / `href=\"#…\"`.\n *\n * Trade-offs:\n * - Non-cryptographic hash (MurmurHash3 x86 32-bit) — pure speed, excellent\n * avalanche on the structured inputs we actually receive (UUIDs, nanoids,\n * `useId()` outputs, opaque chat-message ids). Collision domain is 2^32;\n * at ~77,000 active document ids the birthday-paradox collision rate hits\n * ~50%, which is far beyond any realistic single-page chat workload.\n * - Only kicks in past a length threshold (default 16) so short, hand-picked\n * ids stay readable and existing test fixtures (`'tst'`, `'doc-a'`, …)\n * plus `useId()`'s `'_r_0_'`-style output (≤7 chars) pass through untouched.\n * - Pure function: same input always yields the same output. Two chunks\n * sharing one logical `documentId` therefore still produce identical\n * prefixes, so cross-chunk anchor and footnote coordination is preserved.\n *\n * Why MurmurHash3 specifically (vs the simpler FNV-1a):\n * - FNV-1a does NOT pass SMHasher's avalanche test. For *structured* inputs\n * like UUIDs (fixed hyphen positions, hex-only alphabet) its lower bits\n * show measurable bias, which translates to a higher *practical* collision\n * rate than the theoretical 2^32 figure suggests.\n * - MurmurHash3's finalizer (`fmix32`) — `h ^= h>>>16; h = imul(h, M1);\n * h ^= h>>>13; h = imul(h, M2); h ^= h>>>16` — is purpose-built to\n * flatten any local pattern that survives the body, which is what gets\n * it through SMHasher. That's the entire engineering reason for the\n * ~30-line code-size delta vs FNV-1a.\n *\n * @module components/shortenDocumentId\n */\n\nconst BASE62_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n\n/** Encode a non-negative 32-bit integer as a Base62 string (no padding). */\nfunction toBase62(n: number): string {\n if (n === 0) return BASE62_ALPHABET[0];\n // Treat `n` as unsigned 32-bit so the sign bit doesn't make the loop spin.\n let v = n >>> 0;\n let out = '';\n while (v > 0) {\n out = BASE62_ALPHABET[v % 62] + out;\n v = Math.floor(v / 62);\n }\n return out;\n}\n\n/** 32-bit unsigned rotate-left, in pure JS. */\nfunction rotl32(x: number, r: number): number {\n return ((x << r) | (x >>> (32 - r))) >>> 0;\n}\n\n// MurmurHash3 x86 32-bit mixing constants — from Appleby's reference impl.\n// Naming follows the spec so the code reads against the paper verbatim.\nconst C1 = 0xcc9e2d51;\nconst C2 = 0x1b873593;\n\n// Single TextEncoder reused per process — instantiation is non-trivial and\n// the hash runs once per `<AIMarkdown>` provider commit. UTF-8 bytes (not\n// JS UTF-16 code units) are the canonical Murmur3 input so the hash stays\n// portable with reference implementations in other languages.\nconst UTF8_ENCODER = /* @__PURE__ */ new TextEncoder();\n\n/**\n * MurmurHash3 x86 32-bit. Pure function over the UTF-8 byte sequence of `s`.\n *\n * Implementation notes:\n * - `Math.imul(a, b)` performs signed 32-bit integer multiplication with\n * proper overflow truncation. Plain `a * b` would promote to IEEE-754\n * double and silently lose precision past 2^53, breaking the hash.\n * - The body processes the input in 4-byte little-endian blocks; the\n * 1–3 byte tail is folded in with the canonical Murmur3 cascade.\n * - The finalize step (the three `imul` + `xor >>> n` lines below the\n * tail) is `fmix32` — the avalanche stage that distinguishes Murmur3\n * from naive multiply-xor hashes.\n *\n * @param s - Arbitrary input string (any Unicode).\n * @param seed - Optional 32-bit seed. Defaults to `0` for deterministic\n * reproducibility across machines.\n * @returns Unsigned 32-bit integer.\n */\nfunction murmur3_32(s: string, seed: number = 0): number {\n return murmur3_32_bytes(UTF8_ENCODER.encode(s), seed);\n}\n\n/**\n * MurmurHash3 x86 32-bit over an explicit byte sequence. Split out from\n * `murmur3_32` so the ill-formed-id branch of `shortenDocumentId` can hash\n * raw UTF-16LE code units — `TextEncoder` is lossy on unpaired surrogates\n * (WHATWG USVString conversion folds every lone surrogate to U+FFFD), so\n * feeding it an ill-formed string would silently merge distinct ids.\n */\nfunction murmur3_32_bytes(bytes: Uint8Array, seed: number = 0): number {\n const len = bytes.length;\n let h1 = seed >>> 0;\n const nblocks = len >>> 2;\n\n // ── Body: 4-byte little-endian blocks ───────────────────────────────────\n for (let i = 0; i < nblocks; i++) {\n const b = i * 4;\n let k1 = bytes[b] | (bytes[b + 1] << 8) | (bytes[b + 2] << 16) | (bytes[b + 3] << 24);\n\n k1 = Math.imul(k1, C1);\n k1 = rotl32(k1, 15);\n k1 = Math.imul(k1, C2);\n\n h1 ^= k1;\n h1 = rotl32(h1, 13);\n h1 = (Math.imul(h1, 5) + 0xe6546b64) >>> 0;\n }\n\n // ── Tail: 1–3 leftover bytes, folded in with classic Murmur3 cascade ────\n // The three `if`s implement C-style switch fallthrough: rem==3 runs all\n // three statements; rem==2 runs the bottom two; rem==1 runs only the last\n // block (which is the one that also mixes into h1).\n const tail = nblocks * 4;\n const rem = len & 3;\n if (rem > 0) {\n let k1 = 0;\n if (rem === 3) k1 ^= bytes[tail + 2] << 16;\n if (rem >= 2) k1 ^= bytes[tail + 1] << 8;\n k1 ^= bytes[tail];\n k1 = Math.imul(k1, C1);\n k1 = rotl32(k1, 15);\n k1 = Math.imul(k1, C2);\n h1 ^= k1;\n }\n\n // ── Finalize (fmix32): the avalanche stage ──────────────────────────────\n h1 ^= len;\n h1 ^= h1 >>> 16;\n h1 = Math.imul(h1, 0x85ebca6b);\n h1 ^= h1 >>> 13;\n h1 = Math.imul(h1, 0xc2b2ae35);\n h1 ^= h1 >>> 16;\n\n return h1 >>> 0;\n}\n\n// With the `u` flag this character class matches ONLY unpaired surrogates:\n// a valid pair reads as one astral code point, which lies outside\n// [U+D800, U+DFFF]. Dropping the flag would make it match each HALF of a\n// valid pair and misclassify ordinary emoji ids — the flag is load-bearing.\nconst LONE_SURROGATE_RE = /[\\uD800-\\uDFFF]/u;\n\n/**\n * Whether `id` is ill-formed UTF-16 (contains at least one unpaired\n * surrogate — typically the fallout of an upstream pipeline slicing a\n * string mid-emoji). Exported as the single owner of the detection\n * semantics so consumers (e.g. core's dev-mode documentId warning) cannot\n * drift from the branch condition inside `shortenDocumentId`.\n */\nexport function hasLoneSurrogate(id: string): boolean {\n return LONE_SURROGATE_RE.test(id);\n}\n\n/**\n * Domain-separation seed for hashing ill-formed ids. Ill-formed ids hash\n * over raw UTF-16LE code-unit bytes while long well-formed ids hash over\n * UTF-8 bytes — and the two byte encodings can collide: a lone-surrogate\n * id's UTF-16LE byte sequence can equal some well-formed id's UTF-8 byte\n * sequence (e.g. utf16le(\"\\uD800\\u4E80\") === utf8(\"\\u0000\\u0600N\")\n * === [00 D8 80 4E]; both sides padded past the threshold to actually\n * reach the two hash branches). A distinct seed makes equal byte inputs\n * produce unrelated hashes, reducing cross-domain collisions to the\n * generic 2^32 class.\n */\nconst ILL_FORMED_SEED = 1;\n\n/**\n * Raw UTF-16LE code-unit bytes of `s` — total and trivially injective on\n * ALL JavaScript strings, unlike UTF-8 encoding, which is lossy on\n * ill-formed input (`TextEncoder` folds every lone surrogate to U+FFFD).\n */\nfunction utf16leBytes(s: string): Uint8Array {\n const bytes = new Uint8Array(s.length * 2);\n for (let i = 0; i < s.length; i++) {\n const c = s.charCodeAt(i);\n bytes[i * 2] = c & 0xff;\n bytes[i * 2 + 1] = c >>> 8;\n }\n return bytes;\n}\n\n/**\n * Shorten a `documentId` for use inside an HTML id prefix.\n *\n * Well-formed ids keep the original contract byte-for-byte: at or below\n * `threshold` they pass through verbatim; above it they hash via\n * MurmurHash3 over UTF-8 bytes to a 1–6 char Base62 form.\n *\n * Ill-formed UTF-16 ids (unpaired surrogates, e.g. from an upstream\n * pipeline slicing a string mid-emoji) are ALWAYS hashed, regardless of\n * length — over their raw UTF-16LE code units, seeded with\n * `ILL_FORMED_SEED`. Rationale (issue #32):\n *\n * - Returned verbatim, a lone surrogate makes the caller's\n * `encodeURIComponent` throw `URIError: URI malformed` synchronously,\n * aborting the whole render before any markdown is parsed.\n * - Hashing the WHATWG lossy projection (lone surrogates → U+FFFD, what\n * `TextEncoder`/`toWellFormed()` do) was rejected: it silently merges\n * distinct corrupted ids — and merges them with a well-formed id\n * containing a literal U+FFFD — turning the old loud error into a\n * silent cross-document anchor collision.\n * - Escaping into a well-formed string before hashing was rejected too:\n * a naive marker scheme is not injective (marker-lookalike content\n * forges it), and an escape-the-escape scheme is strictly more code\n * than hashing the raw code units, which is injective for free.\n *\n * Distinct ids therefore produce distinct prefixes up to the generic 2^32\n * birthday bound — the same guarantee long well-formed ids always had —\n * with no equivalence-class carve-out for corrupted input.\n *\n * @param id - The raw documentId (consumer-supplied or `useId()` fallback).\n * Any JavaScript string is accepted, including ill-formed UTF-16.\n * @param threshold - Only well-formed ids strictly longer than this get\n * hashed. Defaults to `16`, which leaves short hand-picked ids and\n * React's `useId()` outputs unchanged but catches UUIDs (36 chars) and\n * nanoids. Ill-formed ids ignore the threshold — they always hash.\n * @returns The original `id` (well-formed and short) or a 1–6 char Base62\n * hash (well-formed long, or ill-formed of any length).\n */\nexport function shortenDocumentId(id: string, threshold: number = 16): string {\n if (hasLoneSurrogate(id)) return toBase62(murmur3_32_bytes(utf16leBytes(id), ILL_FORMED_SEED));\n if (id.length <= threshold) return id;\n return toBase62(murmur3_32(id));\n}\n","/**\n * Dev-only pipeline stage timing.\n *\n * The block-memo render path runs four distinct stages per content change\n * (parse → transform → build → render). Which one dominates depends on the\n * workload — plugin mix, document length, math density — and every\n * optimization decision should start from that split, not from a guess.\n *\n * Two delivery channels, deliberately separate:\n *\n * - **Programmatic consumers** (the BlockMemoCompare story's profiler)\n * use {@link subscribeStageTimings} — a private, direct callback\n * channel. It must NOT go through the User Timing API: React 19 dev\n * builds emit one `performance.measure` per component render\n * (\"component tracks\"), so a page-global 'measure' observer receives a\n * flood of foreign entries it has to filter, and — measured — anything\n * that scans or clears the buffer becomes O(buffer) with MILLIONS of\n * entries in a long session.\n * - **DevTools timeline visibility**: {@link measureStage} still emits\n * one `performance.measure` per stage, named\n * `ai-markdown:stage:<stage>`. Emission is an append — cheap. It does\n * NOT clear per name afterwards: Chromium's `clearMeasures(name)` scans\n * the whole buffer, and under the React-dev flood that per-call scan\n * cost ~35% of main-thread time ON THE INSTRUMENTED SIDE ONLY —\n * inverting the very benchmark this instrumentation serves. Our own\n * growth is ~4 entries per streamed token; the benchmark harness\n * bulk-clears the buffer between runs (see useRenderProfiler.reset).\n *\n * Production builds fold {@link ENABLED} to `false`: the dual dev/prod\n * build resolves `process.env.NODE_ENV` at build time (tsup `env`), so\n * the published dist carries no env read at all; in-repo src consumers\n * (storybook, vitest) run under Vite/Node where the text is substituted\n * or `process` exists. The whole thing costs one boolean check per stage.\n *\n * @module components/devStageTimings\n */\n\n/** The stages of the block-memo render pipeline, in execution order.\n * Single source of truth: the union type, the emitted measure names, and\n * any display ordering (ProfilerPanel) all derive from this tuple.\n * `scan` is the incremental-parse boundary detector (emitted only when\n * `incrementalParse` routes through the incremental engine);\n * when incremental parsing splices, `parse`/`transform` cover the\n * TAIL-ONLY work — the honest per-frame cost, not the full-document one. */\nexport const PIPELINE_STAGES = ['scan', 'parse', 'transform', 'build', 'render'] as const;\nexport type PipelineStage = (typeof PIPELINE_STAGES)[number];\n\n/** Prefix for the emitted `performance.measure` entry names. */\nexport const STAGE_MEASURE_PREFIX = 'ai-markdown:stage:';\n\n/** Hoisted name table — measure names are shared constants, not a fresh\n * template-literal allocation per call. */\nconst STAGE_NAMES = Object.fromEntries(\n PIPELINE_STAGES.map((stage) => [stage, `${STAGE_MEASURE_PREFIX}${stage}`])\n) as Record<PipelineStage, string>;\n\n/**\n * One-time capability gate. Beyond the DEV check, probes the exact call\n * {@link measureStage} makes — the options-object `measure` overload — by\n * performing it once. Environments that expose `performance.measure` but\n * only support the legacy mark-name overloads (older jsdom, partial\n * polyfills) fail the probe and are gated off permanently, instead of\n * paying a thrown-and-swallowed exception per stage per token for the\n * whole session.\n */\nconst ENABLED: boolean =\n process.env.NODE_ENV !== 'production' &&\n (() => {\n if (typeof performance === 'undefined' || typeof performance.measure !== 'function') {\n return false;\n }\n try {\n const probe = `${STAGE_MEASURE_PREFIX}probe`;\n performance.measure(probe, { start: 0, end: 0 });\n performance.clearMeasures?.(probe);\n return true;\n } catch {\n return false;\n }\n })();\n\n/** `instanceId` is the emitting `<AIMarkdown>`'s documentId — listeners on a\n * page with several instances (e.g. an A/B comparison where BOTH sides run\n * the block-memo path) filter by it; a page-wide aggregate ignores it. */\ntype StageListener = (stage: PipelineStage, durationMs: number, instanceId?: string) => void;\nconst stageListeners = new Set<StageListener>();\n\n/**\n * Subscribe to stage timings over the private callback channel (dev-only;\n * in production builds {@link measureStage} never emits, so listeners\n * simply stay silent). Returns an unsubscribe function.\n *\n * This exists so the benchmark profiler does NOT have to observe the\n * page-global 'measure' entry type: React 19 dev floods that channel with\n * one measure per component render, which would have to be filtered per\n * batch — and the module-level listener set is still page-scoped, so the\n * one-consumer-per-page discipline from the story docs continues to apply.\n */\nexport function subscribeStageTimings(listener: StageListener): () => void {\n stageListeners.add(listener);\n return () => {\n stageListeners.delete(listener);\n };\n}\n\n/**\n * Run `fn` as the named pipeline stage. In dev: notifies\n * {@link subscribeStageTimings} listeners and emits one\n * `performance.measure` for DevTools timeline visibility. The\n * single-callable shape (instead of a start/end pair) makes the stage\n * name a typed argument and the pairing unforgettable: a call site cannot\n * mismatch or drop an end call. If `fn` throws, nothing is emitted for\n * the aborted stage.\n *\n * NOTE: emission is append-only — never clear per name from here. See the\n * module docs: `clearMeasures(name)` is O(page buffer), and React 19\n * dev's component tracks grow that buffer without bound.\n */\nexport function measureStage<T>(stage: PipelineStage, fn: () => T, instanceId?: string): T {\n if (!ENABLED) return fn();\n const start = performance.now();\n const result = fn();\n const end = performance.now();\n for (const listener of stageListeners) listener(stage, end - start, instanceId);\n // Probe-verified call — no per-call try/catch needed.\n performance.measure(STAGE_NAMES[stage], { start, end });\n return result;\n}\n","/**\n * Builds a `rehype-sanitize` schema by handing the caller a deep clone of\n * the library's internal default schema to mutate or replace.\n *\n * The mutate-and-return pattern matches the ergonomics of Next.js's\n * `webpack(config)` and Express middleware: a callback receives a draft,\n * either modifies it in place (returning nothing) or returns a fresh object\n * to replace it. The library guarantees the draft is a deep clone, so direct\n * mutation never leaks into the singleton — and the singleton itself is not\n * exported, so consumers cannot accidentally hand-roll a schema that drops\n * the library's cross-chunk tag allowlist or KaTeX className additions.\n *\n * @module components/extendSanitizeSchema\n */\n\nimport cloneDeep from 'lodash-es/cloneDeep';\nimport type { defaultSchema } from 'rehype-sanitize';\nimport { sanitizeSchema } from './sanitizeSchema';\n\n/**\n * The full `rehype-sanitize` schema type. Re-exported as the canonical\n * library-internal alias so other modules don't each redeclare\n * `typeof defaultSchema`.\n *\n * The shape is owned by `rehype-sanitize`; consumers should treat it as\n * tracking that upstream type — it may evolve across rehype-sanitize major\n * versions.\n */\nexport type SanitizeSchema = typeof defaultSchema;\n\n/**\n * Build a sanitize schema by mutating (or replacing) a deep clone of the\n * library default.\n *\n * Designed to be called ONCE at module scope so the returned object has a\n * stable identity across renders — passing it directly into\n * `<AIMarkdown sanitizeSchema={…}>` keeps the block-memo cache warm.\n *\n * @example Append a custom URL protocol via mutation:\n * ```ts\n * const SCHEMA = extendSanitizeSchema((s) => {\n * s.protocols!.href!.push('myapp');\n * s.protocols!.src!.push('myapp');\n * });\n *\n * function App() {\n * return <AIMarkdown content={…} sanitizeSchema={SCHEMA} />;\n * }\n * ```\n *\n * @example Return-style replacement for wider edits:\n * ```ts\n * const SCHEMA = extendSanitizeSchema((s) => ({\n * ...s,\n * tagNames: [...(s.tagNames ?? []), 'my-widget'],\n * }));\n * ```\n *\n * @example Inspect the library default (e.g. to learn what's already allowed):\n * ```ts\n * // The draft handed to the modifier IS the library default, deep-cloned.\n * // Logging it once at module load surfaces every default field — protocols,\n * // attributes, tagNames, etc. — without ever exposing the singleton itself.\n * extendSanitizeSchema((s) => {\n * console.log('default sanitize schema:', s);\n * });\n * ```\n *\n * @remarks Allowing a protocol on `protocols.href` lets the URL through\n * Gate 1 (the schema-level per-protocol allowlist, which runs inside the\n * rehype plugin chain). Gate 2 (`urlTransform`, the per-attribute rewriter\n * that runs later at render time in `renderHastSubtree`) must permit the\n * same protocol independently — see the `urlTransform` prop on\n * `<AIMarkdown>` and the exported {@link defaultUrlTransform} for\n * composition. Keep the two protocol lists in sync.\n *\n * ### Footguns\n *\n * - **Reassigning the local parameter** (`(s) => { s = { …new schema… }; }`)\n * does NOT replace the draft — JS only rebinds the local variable. Either\n * mutate the original draft or `return` the new object explicitly.\n * - **Returning `null`** is treated the same as returning nothing (the\n * modified draft is used). The TypeScript signature does not permit\n * `null`, but JS callers or `as`-casted code paths could silently hit\n * this. Prefer `return` with no value, or an explicit `return draft;`.\n * - **Throwing inside the modifier** propagates to the call site\n * uncaught — there is no try/catch. Callers usually invoke this once at\n * module load, where a thrown error surfaces as a startup-time crash and\n * is the correct failure mode.\n * - **Widening is total.** Adding a tag to `tagNames` admits that element\n * with ALL of its semantics — `script`, `iframe`, `style`, `object`,\n * `form`, `base` re-enter the tree verbatim, and the two-gate URL story\n * in the README / SECURITY.md no longer describes your renderer. Prefer\n * allowing an attribute or a protocol over allowing an element; treat\n * any element you add as trusted input.\n *\n * @param modifier - Receives a deep clone of the library default. Mutate it\n * freely; either return the (possibly different) result, or return\n * nothing to use the mutated draft. Returning `undefined` (and, by\n * convention, `null`) is treated the same as a mutate-only call.\n * @returns A new `Schema` object — never the library default singleton.\n */\nexport function extendSanitizeSchema(modifier: (draft: SanitizeSchema) => SanitizeSchema | void): SanitizeSchema {\n // lodash-es `cloneDeep` over the native `structuredClone` because the\n // latter is unavailable on iOS Safari < 15.4 (March 2022) and on older\n // Android WebViews that are still common on mid-tier devices. lodash-es\n // is already pulled in transitively (useStableValue + context use it),\n // so the marginal bundle cost of importing one more named export is tiny;\n // the helper is called once at module scope, so the speed difference\n // versus the native API is irrelevant. Importantly, lodash `cloneDeep`\n // preserves RegExp — a JSON-based deep clone would silently turn the\n // math/language className regexes into `{}` and corrupt sanitize\n // semantics.\n const draft = cloneDeep(sanitizeSchema);\n const result = modifier(draft);\n return result ?? draft;\n}\n","/**\n * Smooth-stream controller — framework-free typewriter pacing.\n *\n * Reveals an accumulated source string as a gradually growing prefix\n * (`getVisible()`), stepping by grapheme cluster at a rate that adapts to\n * backlog. The revealed prefix is append-only between snaps, which is\n * exactly the incremental-parse engine's fast path — the controller sits\n * upstream of the renderer and never touches the parse pipeline.\n *\n * Pacing model — an adaptive jitter buffer (audio-playout style):\n * - The controller estimates the source's arrival rate and burst interval\n * with irregular-sampling EMAs (recorded on every append), and derives a\n * target buffer B* ≈ bufferFactor × one burst's worth of text — the\n * causality floor for smoothing bursts of that period.\n * - Streaming: rate = max(floor, rateEma + (backlog − B*) / correctionTau).\n * Feedforward tracks the source speed (bounded lag at any model speed);\n * the feedback term pins the backlog near B*, dipping BELOW the source\n * rate on purpose when the buffer runs low so it can refill instead of\n * running dry between bursts. The floor is a tiny anti-freeze trickle,\n * deliberately smaller than any realistic arrival rate.\n * - Pre-stats (first burst after construction/snap): no estimate exists\n * yet, so the backlog reveals over roughly one correction window.\n * - Finished: rate = backlog / time-to-deadline, deadline stamped at\n * `finish() + drainMs` — the backlog empties BY the deadline instead of\n * decaying toward it forever.\n * - A deadline credit accumulator converts elapsed time (injectable\n * `now()`) into whole-grapheme reveals per scheduled frame — timers\n * carry no state between frames, so throttled/paused schedulers\n * self-correct on the next tick instead of drifting.\n * - The public tuning surface is three named presets ({@link SmoothStreamPacing});\n * the numeric parameters stay controller-level for advanced hosts.\n *\n * Grapheme discipline: stepping uses `Intl.Segmenter` (code-point fallback)\n * and the trailing grapheme of the source is held back until it is\n * confirmed — by more text arriving or by `finish()` — so a surrogate\n * half or a still-growing emoji ZWJ sequence is never revealed to the\n * parser mid-cluster. `snap()` (a replacement, or the very first `update`)\n * is outside this promise by design: it shows the whole replacement text\n * at once, trailing half-cluster included — a hold-back there would leave\n * a controller that never drains when nothing follows (v2.4.2 review\n * P3-1). Hosts that seed a stream mid-cluster get one frame of U+FFFD.\n *\n * @module components/smoothStream/controller\n */\n\n/**\n * The public pacing surface: three named trade-off points on the\n * latency-vs-smoothness axis (the audio-plugin buffer-preset convention —\n * perceptual parameters resist meaningful numeric tuning).\n *\n * - `'smooth'` — target ~1.7 bursts of buffer: almost never runs dry\n * between server flushes, at the cost of a little extra lag.\n * - `'balanced'` (default) — ~1 burst of buffer, the causality floor for\n * smoothing: minimal lag that can still bridge a typical gap.\n * - `'responsive'` — sub-burst buffer: lowest lag, accepts an occasional\n * visible pause between bursts.\n */\nexport type SmoothStreamPacing = 'smooth' | 'balanced' | 'responsive';\n\n/** The numeric parameter bundle a {@link SmoothStreamPacing} preset names. */\nexport interface SmoothStreamPacingParams {\n /** Target buffer as a multiple of one estimated burst's worth of text. */\n bufferFactor: number;\n /**\n * Feedback time constant (ms): how fast the backlog is steered toward\n * the target buffer. Also the pre-stats reveal window for the first\n * burst, before any arrival estimate exists.\n */\n correctionTauMs: number;\n /** Smoothing horizon (ms) for the arrival-rate / burst-interval EMAs. */\n emaTauMs: number;\n /**\n * Anti-freeze floor (grapheme clusters/s). Deliberately tiny — smaller\n * than any realistic arrival rate — so the feedback term can slow the\n * reveal below the source rate to refill the buffer, without ever\n * freezing visible progress entirely.\n */\n minCharsPerSecond: number;\n /**\n * Hard drain budget after {@link SmoothStreamController.finish}: a\n * deadline is stamped at `finish() + drainMs` and the rate scales with\n * remaining-backlog / remaining-time, so the backlog empties BY the\n * deadline (not asymptotically). Consumed when the deadline is stamped —\n * changing it affects the next drain, not one in progress.\n */\n drainMs: number;\n}\n\nexport interface SmoothStreamOptions extends Partial<SmoothStreamPacingParams> {\n /**\n * Named pacing preset, the intended tuning surface. Individual\n * {@link SmoothStreamPacingParams} fields act as advanced per-field\n * overrides on top of the chosen preset. Default `'balanced'`.\n */\n pacing?: SmoothStreamPacing;\n /**\n * Injectable clock (milliseconds, monotonic preferred). Defaults to\n * `performance.now`, falling back to `Date.now`. Tests inject a manual\n * clock — pacing must never race the wall clock.\n */\n now?: () => number;\n /**\n * Injectable frame scheduler: schedules `cb` once, ASYNCHRONOUSLY, and\n * returns a cancel function. A scheduler that invokes `cb` synchronously\n * violates the contract (the returned cancel handle would be recorded\n * after the tick already cleared it, stranding the controller). Defaults\n * to `requestAnimationFrame` with a `setTimeout` fallback so the\n * controller also runs under node.\n */\n schedule?: (cb: () => void) => () => void;\n}\n\nexport interface SmoothStreamController {\n /**\n * Sets the full accumulated source. An append-extension of the current\n * source animates; anything else — the FIRST update after construction\n * included — snaps (content replacement is not a stream). An identical\n * string is a no-op, so replayed effects (StrictMode) are safe.\n * Calling `update` after {@link finish} re-enters streaming: multi-round\n * LLM flows (stream → tool call → stream) keep one controller.\n */\n update(source: string): void;\n /**\n * Signals end of stream: confirms the held-back trailing grapheme and\n * switches the control law to the `drainMs` window. Not terminal —\n * a later {@link update} resumes animation.\n */\n finish(): void;\n /** Jumps to `source` instantly, no animation, and clears any backlog.\n * No trailing-grapheme hold-back (see the module docs). */\n snap(source: string): void;\n /**\n * Reveals everything pending right now (skip-animation affordance). Keeps\n * the grapheme discipline: while the stream is not finished, the trailing\n * grapheme of the source stays held back exactly as the animation would\n * hold it (a surrogate half or a growing ZWJ sequence must never reach\n * the parser); {@link finish} or the next {@link update} confirms it.\n */\n flush(): void;\n /** Subscribes to visible-prefix changes. Returns the unsubscribe. */\n subscribe(listener: () => void): () => void;\n /**\n * The currently revealed prefix. Reference-stable between changes —\n * safe as a `useSyncExternalStore` snapshot.\n */\n getVisible(): string;\n /** True when the visible prefix has caught up with the full source. */\n isDrained(): boolean;\n /**\n * Cancels any scheduled frame and drops all subscribers. NOT terminal:\n * any subsequent call ({@link update}, {@link subscribe}, …) revives the\n * controller. React StrictMode's dev-only effect replay (mount → cleanup\n * → re-run) disposes and then reuses the same state-held instance — a\n * permanently-latching dispose would kill the reveal in dev forever.\n * After a REAL unmount nothing calls back in, so disposal sticks.\n */\n dispose(): void;\n}\n\n/**\n * The three preset bundles. Calibrated against the burst patterns in the\n * SmoothStream stories (server-buffer-like flushes at slow and fast model\n * speeds); frozen so a shared reference can't be mutated by a consumer.\n */\nexport const SMOOTH_STREAM_PACING_PRESETS: Readonly<Record<SmoothStreamPacing, Readonly<SmoothStreamPacingParams>>> =\n Object.freeze({\n smooth: Object.freeze({\n bufferFactor: 1.7,\n correctionTauMs: 280,\n emaTauMs: 2600,\n minCharsPerSecond: 4,\n drainMs: 320,\n }),\n balanced: Object.freeze({\n bufferFactor: 1.0,\n correctionTauMs: 180,\n emaTauMs: 1800,\n minCharsPerSecond: 6,\n drainMs: 240,\n }),\n responsive: Object.freeze({\n bufferFactor: 0.45,\n correctionTauMs: 110,\n emaTauMs: 1100,\n minCharsPerSecond: 10,\n drainMs: 150,\n }),\n });\n\n/**\n * Absolute ceiling on the target buffer, expressed as milliseconds of lag\n * at the estimated rate. Guards against a skewed interval estimate (one\n * pathological gap) demanding seconds of buffered text. Internal — not a\n * preset field because no preset should ever want to move it.\n */\nconst MAX_TARGET_BUFFER_MS = 1200;\n\nconst defaultNow: () => number =\n typeof performance !== 'undefined' && typeof performance.now === 'function'\n ? () => performance.now()\n : () => Date.now();\n\nconst defaultSchedule = (cb: () => void): (() => void) => {\n if (typeof requestAnimationFrame === 'function') {\n const id = requestAnimationFrame(() => cb());\n return () => cancelAnimationFrame(id);\n }\n const id = setTimeout(cb, 16);\n return () => clearTimeout(id);\n};\n\n/**\n * Pacing knobs must be FINITE numbers. NaN is a `number` to TypeScript\n * (`{ minCharsPerSecond: parseInt(missing) }` type-checks), and `Math.max`\n * propagates NaN instead of guarding it — one poisoned knob would freeze\n * the reveal in a permanent no-op frame loop. Infinity is rejected too:\n * `Infinity × 0` on a zero-dt tick is NaN by another road.\n */\nconst finiteOr = (value: number | undefined, fallback: number): number =>\n value !== undefined && Number.isFinite(value) ? value : fallback;\n\nconst segmenter =\n typeof Intl !== 'undefined' && typeof Intl.Segmenter === 'function'\n ? new Intl.Segmenter(undefined, { granularity: 'grapheme' })\n : undefined;\n\n/**\n * Absolute end offsets (UTF-16 units) of each grapheme cluster in\n * `text`, offset by `base`. Fallback iterates code points, which still\n * never splits a surrogate pair (ZWJ sequences may step in parts).\n */\nconst graphemeEnds = (text: string, base: number): number[] => {\n const ends: number[] = [];\n if (segmenter) {\n for (const part of segmenter.segment(text)) {\n ends.push(base + part.index + part.segment.length);\n }\n } else {\n let offset = base;\n for (const cp of text) {\n offset += cp.length;\n ends.push(offset);\n }\n }\n return ends;\n};\n\n/**\n * UTF-16 units re-segmented before a resume seam. Grapheme breaking is a\n * finite-state process, so a window that starts mid-cluster re-synchronises\n * within a cluster or two and every boundary after that is right — with one\n * exception, regional indicators, handled separately below. The residual\n * risk is a single cluster longer than the window (a 30-link ZWJ chain, a\n * Zalgo pile) straddling the seam, and the cost there is one frame of odd\n * reveal granularity, never wrong text.\n */\nconst RESUME_LOOKBACK = 64;\n\nconst isMidSurrogatePair = (text: string, at: number): boolean =>\n at > 0 &&\n at < text.length &&\n (text.charCodeAt(at - 1) & 0xfc00) === 0xd800 &&\n (text.charCodeAt(at) & 0xfc00) === 0xdc00;\n\nconst RI_FIRST = 0x1f1e6;\nconst RI_LAST = 0x1f1ff;\nconst isRegionalIndicatorAt = (text: string, at: number): boolean => {\n const cp = text.codePointAt(at);\n return cp !== undefined && cp >= RI_FIRST && cp <= RI_LAST;\n};\n\nexport const createSmoothStreamController = (options: SmoothStreamOptions = {}): SmoothStreamController => {\n // Option fields are read each tick, so a caller that keeps the object\n // and replaces field values retunes pacing live (the hook relies on\n // this to reflect prop changes without controller churn).\n const now = options.now ?? defaultNow;\n const schedule = options.schedule ?? defaultSchedule;\n\n let source = '';\n /** UTF-16 offset of the revealed prefix's end. */\n let visibleEnd = 0;\n /**\n * Confirmed grapheme end offsets awaiting reveal, ascending, all in\n * `(visibleEnd, source.length]`. The trailing grapheme of the source is\n * NOT in here until confirmed (see module doc) — its end lives in\n * `tentativeEnd` and is re-derived whenever more text arrives.\n */\n let pending: number[] = [];\n let tentativeEnd = 0;\n let finished = false;\n /**\n * An offset confirmed as a source end UNCONDITIONALLY — by `finish()`, or\n * by a `snap()` that revealed everything. Correct at the time: a finished\n * stream owes the caller every byte it has. But the controller supports\n * RESUMING (a tool call or a user turn ends the round, then more text\n * arrives), and an offset that was a source end need not be a cluster\n * boundary of the longer string. `hold` protects boundaries confirmed by\n * streaming; it never saw this one. Cleared once segmentation has\n * confirmed a boundary beyond it.\n */\n let seam: number | undefined;\n /** Deadline (clock ms) by which a finished stream must be fully revealed. */\n let drainDeadlineAt: number | undefined;\n let initialized = false;\n\n let visibleCache = '';\n let credit = 0;\n let lastTickAt = 0;\n let cancelFrame: (() => void) | undefined;\n let disposed = false;\n\n // Arrival statistics for the adaptive law. Reset by snap(): a content\n // replacement is a new stream whose cadence the old estimates don't\n // describe. `undefined` = pre-stats regime (first burst).\n let rateEma: number | undefined;\n let intervalEma: number | undefined;\n let lastArrivalAt: number | undefined;\n\n const listeners = new Set<() => void>();\n\n /** Live-resolves preset + per-field overrides, sanitizing every number. */\n const resolveParams = (): SmoothStreamPacingParams => {\n const preset =\n SMOOTH_STREAM_PACING_PRESETS[options.pacing as SmoothStreamPacing] ?? SMOOTH_STREAM_PACING_PRESETS.balanced;\n return {\n bufferFactor: finiteOr(options.bufferFactor, preset.bufferFactor),\n correctionTauMs: finiteOr(options.correctionTauMs, preset.correctionTauMs),\n emaTauMs: finiteOr(options.emaTauMs, preset.emaTauMs),\n minCharsPerSecond: finiteOr(options.minCharsPerSecond, preset.minCharsPerSecond),\n drainMs: finiteOr(options.drainMs, preset.drainMs),\n };\n };\n\n /**\n * Irregular-sampling EMA update: α = 1 − e^(−gap/τ) weighs each sample\n * by the time it spans, so bursty arrival timing doesn't bias the\n * estimates the way a fixed-α EMA would. `added` is in UTF-16 units —\n * close enough to the grapheme-denominated backlog for control purposes\n * (emoji-heavy text mildly over-estimates the rate, which only pads the\n * buffer).\n */\n const recordArrival = (t: number, added: number) => {\n if (added <= 0) return;\n if (lastArrivalAt === undefined) {\n lastArrivalAt = t;\n return;\n }\n const gap = Math.max(1, t - lastArrivalAt);\n lastArrivalAt = t;\n const tau = Math.max(1, resolveParams().emaTauMs);\n // A gap longer than the smoothing horizon is a PAUSE, not cadence: at\n // that length α → 1 and this one sample would rewrite both estimates\n // (R̂ → ~0, Î → the pause), making the resume crawl at the floor while\n // B* pegs at its cap, then whoosh when Î decays. Start a new epoch\n // instead — keep the pre-pause estimates and let normal samples adapt.\n if (gap > tau) return;\n const alpha = 1 - Math.exp(-gap / tau);\n const instantRate = (added * 1000) / gap;\n // Zero-prior blend, no assignment special case: the FIRST sample also\n // enters at weight α, so a connect-flush pair ~1ms apart seeds a\n // bounded estimate instead of `added × 1000` chars/s (which would\n // track a phantom rate and disable smoothing for seconds). Early\n // under-estimation is harmless — with small R̂ the adaptive law\n // algebraically coincides with the pre-stats reveal.\n rateEma = (rateEma ?? 0) + alpha * (instantRate - (rateEma ?? 0));\n intervalEma = (intervalEma ?? 0) + alpha * (gap - (intervalEma ?? 0));\n };\n\n const notify = () => {\n visibleCache = source.slice(0, visibleEnd);\n for (const listener of [...listeners]) listener();\n };\n\n const cancelScheduled = () => {\n cancelFrame?.();\n cancelFrame = undefined;\n };\n\n const ensureScheduled = () => {\n if (disposed || cancelFrame || pending.length === 0) return;\n lastTickAt = now();\n credit = 0;\n cancelFrame = schedule(tick);\n };\n\n const tick = () => {\n cancelFrame = undefined;\n if (disposed) return;\n const t = now();\n const dt = Math.max(0, t - lastTickAt);\n lastTickAt = t;\n\n const params = resolveParams();\n let rate: number;\n if (finished && drainDeadlineAt !== undefined) {\n // Drain regime: remaining backlog over remaining time-to-deadline —\n // reaches zero BY the deadline instead of decaying asymptotically.\n rate = Math.max(params.minCharsPerSecond, (pending.length * 1000) / Math.max(1, drainDeadlineAt - t));\n } else if (rateEma !== undefined && intervalEma !== undefined) {\n // Adaptive regime: feedforward on the estimated source rate,\n // feedback steering the backlog toward the target buffer. The\n // feedback dips below the source rate on purpose when the buffer\n // runs low — that is how it refills instead of running dry.\n // Clamp order matters: the \"at least one grapheme\" floor applies\n // AFTER the lag cap, so a tiny-R̂ stream cannot end up with a\n // sub-1 target.\n const targetBuffer = Math.max(\n 1,\n Math.min(params.bufferFactor * rateEma * (intervalEma / 1000), (rateEma * MAX_TARGET_BUFFER_MS) / 1000)\n );\n rate = Math.max(\n params.minCharsPerSecond,\n rateEma + ((pending.length - targetBuffer) * 1000) / Math.max(1, params.correctionTauMs)\n );\n } else {\n // Pre-stats regime (first burst after construction/snap): no\n // arrival estimate yet — reveal over roughly one correction window.\n rate = Math.max(params.minCharsPerSecond, (pending.length * 1000) / Math.max(1, params.correctionTauMs));\n }\n credit += (rate * dt) / 1000;\n\n const reveal = Math.min(Math.floor(credit), pending.length);\n if (reveal > 0) {\n visibleEnd = pending[reveal - 1];\n pending = pending.slice(reveal);\n // Leftover credit only carries while a backlog remains; otherwise a\n // quiet spell would bank credit and dump the next chunk instantly.\n credit = pending.length > 0 ? credit - reveal : 0;\n notify();\n }\n // Re-check both guards after notify: a subscriber may have called\n // dispose() (don't schedule past it) or update() (ensureScheduled\n // already booked the next frame — booking a second would orphan its\n // cancel handle and fork the tick chain).\n if (!disposed && !cancelFrame && pending.length > 0) cancelFrame = schedule(tick);\n };\n\n /** Re-segments the unrevealed tail from the last confirmed boundary.\n *\n * Only the LAST cluster stays tentative, because appending can merge it\n * with what follows — with one exception: when the source ends inside a\n * surrogate pair, that lone high surrogate is a cluster of its own, and\n * the cluster BEFORE it would be confirmed even though the completed pair\n * merges the two (`\"👩‍👧‍👦x\"` cut at 5 revealed `\"👩‍\"` — a break inside a\n * cluster, which the module contract says never happens; 2026-08-19\n * review r2 P2-6). Two clusters stay tentative there.\n *\n * A resume needs more than that — see `seam`. The seam is dropped from\n * the schedule if it is still only scheduled, and the tail around it is\n * re-segmented with left context instead of from the seam itself\n * (2026-08-20 A2). */\n const resegmentTail = () => {\n if (seam !== undefined && seam < source.length && pending[pending.length - 1] === seam) {\n // Confirmed but not yet shown, and no longer a boundary we trust.\n // Only the last entry can be the seam: it is a source end, so nothing\n // confirmed later is smaller, and this runs before the new ends land.\n pending.pop();\n }\n const from = pending.length > 0 ? pending[pending.length - 1] : visibleEnd;\n let anchor = from;\n if (seam !== undefined && from <= seam) {\n // Text already revealed cannot be taken back — one frame showing\n // U+FFFD is the documented cost — but segmenting FROM a position\n // whose cluster break depends on what precedes it corrupts every\n // boundary after it too, and that part is avoidable. `\"👩‍👧‍👦x\"`\n // resumed at 4 segmented as [\"\\uDC67‍\", \"👦\", \"x\"] and revealed the\n // family in visibly broken pieces.\n anchor = Math.max(0, from - RESUME_LOOKBACK);\n if (isMidSurrogatePair(source, anchor)) anchor -= 1;\n // GB12/GB13 pair regional indicators off from the START of their run,\n // so parity is the one thing a bounded window cannot recover. Walk the\n // whole run instead: `\"🇺🇸🇬🇧🇫🇷\"` resumed at 2 read 🇸 and 🇬 as one flag.\n while (anchor >= 2 && isRegionalIndicatorAt(source, anchor - 2)) anchor -= 2;\n } else {\n seam = undefined;\n }\n const ends = graphemeEnds(source.slice(anchor), anchor);\n if (ends.length === 0) {\n tentativeEnd = from;\n return;\n }\n tentativeEnd = ends[ends.length - 1];\n let hold = 1;\n if (!finished && ends.length > 1) {\n const last = source.charCodeAt(source.length - 1);\n // The completed character may merge with the cluster before the lone\n // surrogate, so that cluster's end is not settled either. Screening the\n // predecessor for \"could it absorb this\" is a trap: an earlier version\n // required a non-ASCII predecessor, but GB9 lets ANY character take a\n // following Extend, and the supplementary plane is full of them —\n // `a` + U+1D165 (musical symbol) and `a` + U+E0101 (variation selector\n // supplement) both revealed a bare `a` that the next frame merged away.\n // Two clusters stay tentative whenever the source ends mid-pair; the\n // cost is one cluster of extra latency for one frame.\n if (last >= 0xd800 && last <= 0xdbff) hold = 2;\n }\n const confirmedEnds = finished ? ends : ends.slice(0, -hold);\n // A backed-up anchor re-derives boundaries at or before `from`; those\n // are settled already (revealed, or still-trusted entries in `pending`).\n for (const end of confirmedEnds) if (end > from) pending.push(end);\n };\n\n const snap = (next: string) => {\n disposed = false;\n initialized = true;\n finished = false;\n drainDeadlineAt = undefined;\n // A replacement is a new stream: the old cadence estimates are noise.\n rateEma = undefined;\n intervalEma = undefined;\n lastArrivalAt = undefined;\n source = next;\n visibleEnd = next.length;\n tentativeEnd = next.length;\n pending = [];\n seam = next.length;\n credit = 0;\n cancelScheduled();\n if (visibleCache !== next) notify();\n };\n\n /**\n * Un-latches a disposed controller AND reschedules any surviving\n * backlog. Rescheduling here is load-bearing: the StrictMode replay\n * re-runs effects with UNCHANGED props, so `update` takes its\n * identical-string early-return and `finish` its already-finished one —\n * neither would reach ensureScheduled on its own, and a mid-animation\n * backlog would freeze forever.\n */\n const revive = () => {\n if (!disposed) return;\n disposed = false;\n ensureScheduled();\n };\n\n return {\n update(next: string) {\n revive();\n if (initialized && next === source) return;\n if (!initialized || !next.startsWith(source)) {\n snap(next);\n return;\n }\n finished = false;\n drainDeadlineAt = undefined;\n const previousLength = source.length;\n source = next;\n resegmentTail();\n recordArrival(now(), next.length - previousLength);\n ensureScheduled();\n },\n finish() {\n revive();\n if (finished) return;\n finished = true;\n // The pause between rounds (tool call, user turn) must never become\n // a gap sample: drop the arrival clock so the resume's first update\n // re-seeds it. The EMAs persist — same stream, likely same cadence.\n lastArrivalAt = undefined;\n drainDeadlineAt = now() + resolveParams().drainMs;\n if (tentativeEnd > (pending.length > 0 ? pending[pending.length - 1] : visibleEnd)) {\n pending.push(tentativeEnd);\n }\n seam = source.length;\n ensureScheduled();\n },\n snap,\n flush() {\n disposed = false;\n // Unfinished stream: the unconfirmed trailing grapheme (`tentativeEnd`,\n // never in `pending`) stays held — revealing it here would expose a\n // possibly-broken cluster to the parser, the one thing the module's\n // grapheme discipline promises never happens (2026-08 project review,\n // eng-stream-04). Finished streams have confirmed it into `pending`.\n const target = finished ? source.length : pending.length > 0 ? pending[pending.length - 1] : visibleEnd;\n if (target <= visibleEnd) return;\n visibleEnd = target;\n pending = [];\n credit = 0;\n cancelScheduled();\n notify();\n },\n subscribe(listener: () => void) {\n revive();\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n getVisible: () => visibleCache,\n isDrained: () => visibleEnd === source.length,\n dispose() {\n disposed = true;\n cancelScheduled();\n listeners.clear();\n },\n };\n};\n","/**\n * LaTeX preprocessing pipeline.\n *\n * Normalizes raw markdown so that LaTeX expressions survive the remark/rehype\n * rendering pipeline intact. The main entry point is {@link preprocessLaTeX},\n * which splits content into protected regions (code blocks, inline code, HTML\n * tags) and applies a sequence of transformations to the unprotected text:\n *\n * 1. Escape mhchem commands (`\\ce`, `\\pu`)\n * 2. Escape currency dollar signs (e.g. `$100`, `$1,000.50`)\n * 3. Convert bracket delimiters (`\\[...\\]`, `\\(...\\)`) to dollar delimiters\n * 4. Escape pipes inside closed LaTeX blocks to prevent GFM table interference\n * 5. Escape pipes inside unclosed LaTeX blocks (streaming partial content)\n * 6. Escape underscores inside `\\text{...}` commands\n * 7. Convert single-dollar delimiters to double-dollar delimiters\n * 8. Truncate trailing unclosed LaTeX blocks (streaming protection)\n *\n * Thanks to the implementations from the following repositories:\n * - https://github.com/lobehub/lobe-ui/blob/master/src/hooks/useMarkdown/latex.ts\n * - https://github.com/danny-avila/LibreChat/blob/main/client/src/utils/latex.ts\n *\n * @module preprocessors/latex\n */\n\ninterface Segment {\n text: string;\n isCode: boolean;\n}\n\ntype FenceMarker = '`' | '~';\n\nfunction getRepeatedMarkerLength(content: string, start: number, marker: FenceMarker): number {\n let end = start;\n while (end < content.length && content[end] === marker) {\n end += 1;\n }\n return end - start;\n}\n\n/**\n * Sticky regex for matching known HTML tags at a specific position.\n * The `y` (sticky) flag anchors the match at `lastIndex`, avoiding the need\n * to create a substring for each `<` character encountered during scanning.\n */\nconst HTML_TAG_REGEX =\n /<\\/?(span|div|p|br|hr|img|a|em|strong|b|i|u|s|sub|sup|code|pre|table|tr|td|th|thead|tbody|tfoot|ul|ol|li|dl|dt|dd|h[1-6]|blockquote|details|summary|figure|figcaption|section|article|aside|nav|header|footer|main|mark|del|ins|small|abbr|cite|dfn|kbd|samp|var|ruby|rt|rp|bdo|wbr|input|button|select|textarea|label|fieldset|legend|output|iframe|video|audio|source|canvas|svg|math|time)(?:\\s[^>]*)?\\/?>/iy;\n\n/**\n * Tags whose inner text must be treated as literal (never processed as LaTeX).\n * For these, an opening tag triggers protection of the entire paired region\n * `<tag>...</tag>` rather than just the tag itself, so dollar signs and other\n * LaTeX-looking characters inside (e.g. `<code>$x^2$</code>`) survive untouched.\n */\nconst LITERAL_CONTENT_TAGS = new Set(['code', 'pre', 'kbd', 'samp', 'math', 'svg']);\nconst LITERAL_CONTENT_CLOSE_REGEX: Record<string, RegExp> = {\n code: /<\\/code\\s*>/gi,\n pre: /<\\/pre\\s*>/gi,\n kbd: /<\\/kbd\\s*>/gi,\n samp: /<\\/samp\\s*>/gi,\n math: /<\\/math\\s*>/gi,\n svg: /<\\/svg\\s*>/gi,\n};\n\n/** True when only spaces/tabs (and an optional `\\r`) follow `pos` up to the\n * next `\\n` or EOF — CommonMark's closing-fence rule. Without it\n * ` ``` not-a-closer ` closed the fence and inverted the open/close phase\n * for the rest of the document (v2.4.1 review P2). */\nfunction restOfLineIsBlank(content: string, pos: number): boolean {\n for (let i = pos; i < content.length; i++) {\n const c = content[i];\n if (c === '\\n') return true;\n if (c !== ' ' && c !== '\\t' && c !== '\\r') return false;\n }\n return true;\n}\n\n/** A backtick fence's info string may not contain a backtick — such a line\n * is a paragraph (possibly holding code spans), not an opener. */\nfunction lineHasBacktick(content: string, pos: number): boolean {\n for (let i = pos; i < content.length && content[i] !== '\\n'; i++) {\n if (content[i] === '`') return true;\n }\n return false;\n}\n\n/**\n * The run at `pos` is the first non-blank thing on its line. Any amount of\n * leading indentation is accepted: CommonMark's 0–3 space limit is measured\n * RELATIVE to the enclosing container, and this text-level pass has no\n * container model — a fence nested two list levels deep sits at column 4+\n * (v2.4.2 review P1-3: `- a\\n - b\\n ~~~\\n price = $100\\n ~~~`\n * had its `$` rewritten). Accepting a deeper-indented fence can only\n * OVER-protect (an indented code block that happens to hold a fence line\n * is treated as one), which is the safe direction for a preprocessor.\n */\nfunction lineIndentBefore(content: string, pos: number): number {\n let i = pos - 1;\n let indent = 0;\n while (i >= 0 && (content[i] === ' ' || content[i] === '\\t')) {\n indent += content[i] === '\\t' ? 4 : 1;\n i--;\n }\n return i < 0 || content[i] === '\\n' || content[i] === '\\r' ? indent : -1;\n}\n\n/**\n * Find the next run of *exactly* `n` consecutive backticks at or after\n * `start`. Runs of any other length are skipped over. Returns the start\n * index of the matching run, or `-1` if no such run exists.\n *\n * Used to locate the closing delimiter of a CommonMark inline code span:\n * the closer must be a backtick run of the *same* length as the opener.\n */\nfunction findClosingBacktickRun(content: string, start: number, n: number): number {\n let i = start;\n while (i < content.length) {\n const ch = content[i];\n if (ch === '`') {\n const runLen = getRepeatedMarkerLength(content, i, '`');\n if (runLen === n) return i;\n i += runLen;\n } else if (ch === '\\n' || ch === '\\r') {\n // A code span cannot cross a blank line (it ends the paragraph): two\n // lone backticks in different paragraphs are literal, and pairing\n // them would shield every `$…$` in between from conversion\n // (2026-08-19 review P2-2 — inline sibling of the v2.4.1 fence fix).\n // Line endings are `\\n`, `\\r\\n` and a lone `\\r` (r2 P3): a blank line\n // is an ending, optional spaces/tabs, then another ending (or EOF).\n let j = i + 1;\n if (ch === '\\r' && content[j] === '\\n') j += 1;\n while (j < content.length && (content[j] === ' ' || content[j] === '\\t')) j += 1;\n if (j >= content.length || content[j] === '\\n' || content[j] === '\\r') return -1;\n i += 1;\n } else {\n i += 1;\n }\n }\n return -1;\n}\n\n/**\n * Split content into alternating text and protected segments.\n * Protected segments (isCode: true) are excluded from LaTeX processing:\n * - fenced multiline code blocks: 3+ backticks or tildes at the *start of a\n * line* (any indentation — container-relative limits are not modelled).\n * Mid-line runs are never fence openers. INDENTED code blocks (4+ spaces\n * after a blank line, outside any container) are NOT modelled: without a\n * container model they cannot be told from a list item's continuation\n * paragraph, and protecting them would silence math in nested lists.\n * Known limitation — `$` inside an indented code block may be rewritten.\n * - inline code spans: a run of N backticks closed by another run of exactly\n * N backticks. May span newlines. Multi-backtick forms (e.g. `` `` `x` ``)\n * are supported so literal backtick characters can appear inside.\n * - HTML tags (e.g. `<span>$</span>` where `$` should not be treated as LaTeX).\n */\nexport function splitByProtectedRegions(content: string): Segment[] {\n const segments: Segment[] = [];\n let lastIndex = 0;\n let multilineStart = -1;\n let multilineFenceMarker: FenceMarker | null = null;\n let multilineFenceLength = 0;\n let multilineFenceIndent = 0;\n\n function pushProtected(start: number, end: number) {\n if (start > lastIndex) {\n segments.push({ text: content.substring(lastIndex, start), isCode: false });\n }\n segments.push({ text: content.substring(start, end), isCode: true });\n lastIndex = end;\n }\n\n let i = 0;\n while (i < content.length) {\n const char = content[i];\n\n // Inside a fenced code block: only look for a closing fence line.\n if (multilineStart !== -1) {\n if (char === multilineFenceMarker) {\n const runLen = getRepeatedMarkerLength(content, i, multilineFenceMarker);\n // A closer may be indented at most 3 columns MORE than its opener\n // (CommonMark, container-relative): a ` ```` line inside a\n // column-0 fence is content, not a closer — accepting it closed the\n // block early and exposed its body (adversarial review of the\n // any-indent opener change).\n const closerIndent = lineIndentBefore(content, i);\n if (\n runLen >= multilineFenceLength &&\n closerIndent !== -1 &&\n closerIndent <= multilineFenceIndent + 3 &&\n restOfLineIsBlank(content, i + runLen)\n ) {\n pushProtected(multilineStart, i + runLen);\n multilineStart = -1;\n multilineFenceMarker = null;\n multilineFenceLength = 0;\n i += runLen;\n continue;\n }\n i += runLen;\n continue;\n }\n i += 1;\n continue;\n }\n\n // Outside code: check fence opener, inline code span, then HTML tag.\n if (char === '`' || char === '~') {\n const runLen = getRepeatedMarkerLength(content, i, char);\n\n // Fenced code block opener: ≥3 markers and at a valid line start.\n const openerIndent = lineIndentBefore(content, i);\n if (runLen >= 3 && openerIndent !== -1 && !(char === '`' && lineHasBacktick(content, i + runLen))) {\n multilineStart = i;\n multilineFenceMarker = char;\n multilineFenceLength = runLen;\n multilineFenceIndent = openerIndent;\n i += runLen;\n continue;\n }\n\n // Inline code span: only backticks (tildes are never inline delimiters).\n if (char === '`') {\n const closeIdx = findClosingBacktickRun(content, i + runLen, runLen);\n if (closeIdx !== -1) {\n pushProtected(i, closeIdx + runLen);\n i = closeIdx + runLen;\n continue;\n }\n }\n\n // Unmatched run — skip the whole run so we don't re-interpret its\n // individual backticks on subsequent iterations.\n i += runLen;\n continue;\n }\n\n if (char === '<') {\n // Only match known HTML tags to avoid false positives with angle brackets\n // in markdown links (<Slides Demo>), math comparisons ($a < b$), etc.\n // Use sticky regex to match at position i without creating a substring.\n HTML_TAG_REGEX.lastIndex = i;\n const tagMatch = HTML_TAG_REGEX.exec(content);\n if (tagMatch) {\n let endIndex = i + tagMatch[0].length;\n // For literal-content tags (code/pre/math/...), protect the paired\n // <tag>...</tag> region so inner `$` never enters LaTeX processing.\n const tagName = tagMatch[1].toLowerCase();\n const isOpeningPairedTag =\n content[i + 1] !== '/' && !tagMatch[0].endsWith('/>') && LITERAL_CONTENT_TAGS.has(tagName);\n if (isOpeningPairedTag) {\n const closeRegex = LITERAL_CONTENT_CLOSE_REGEX[tagName];\n closeRegex.lastIndex = endIndex;\n const closeMatch = closeRegex.exec(content);\n if (closeMatch) {\n endIndex = closeMatch.index + closeMatch[0].length;\n } else {\n // Streaming: closing tag hasn't arrived yet. Protect everything\n // to the end of input so inner `$` etc. aren't mutated before\n // the closer shows up in a later chunk.\n endIndex = content.length;\n }\n }\n pushProtected(i, endIndex);\n i = endIndex;\n continue;\n }\n }\n\n i += 1;\n }\n\n if (multilineStart !== -1) {\n pushProtected(multilineStart, content.length);\n }\n\n // Push remaining text\n if (lastIndex < content.length) {\n segments.push({ text: content.substring(lastIndex), isCode: false });\n }\n\n return segments;\n}\n\n/**\n * Escape mhchem commands in LaTeX expressions to ensure proper rendering.\n *\n * @param text Input string containing LaTeX expressions with mhchem commands\n * @returns String with escaped mhchem commands\n * @from https://github.com/lobehub/lobe-ui/blob/master/src/hooks/useMarkdown/latex.ts\n */\nfunction escapeMhchemCommands(text: string) {\n return text.replaceAll('$\\\\ce{', '$\\\\\\\\ce{').replaceAll('$\\\\pu{', '$\\\\\\\\pu{');\n}\n\nconst CURRENCY_REGEX = /(?<![\\\\$])\\$(?!\\$)(?=\\d+(?:,\\d{3})*(?:\\.\\d+)?(?:[KMBkmb])?(?:\\s|$|[^a-zA-Z\\d]))/g;\n// Match \\[...\\] and \\(...\\) as LaTeX delimiters, but exclude:\n// - !\\[...\\] (markdown image)\n// - \\[...\\]( (markdown link)\nconst DELIMITERS_REGEX = /(?<!!)\\\\\\[([\\S\\s]*?[^\\\\])\\\\](?!\\()|\\\\\\((.*?)\\\\\\)/g;\nconst ARRAY_COL_SPEC_OR_PIPE_REGEX = /(\\\\begin\\{(?:array|tabular[x*]?)\\}\\{[^}]*\\})|(?<!\\\\)\\|/g;\n// Display $$ allows multiline; inline $ forbids newlines (consistent with SINGLE_DOLLAR_REGEX).\n// Both display delimiters use EXACTLY the delimiter lexicon of\n// findUnclosedDelimiterStart / isEscapedByBackslashRun: a `$$` preceded by\n// an EVEN run of backslashes (zero included) is a delimiter, an odd run\n// escapes it — nothing else matters, in particular not a preceding `$`\n// (`$$$$` is an empty display, `\\$$$x$$` opens at the second `$`). The\n// incremental wrapper freezes on that lexicon's verdict, so any other rule\n// here diverges from it: the old escape-blind opener let `Cost \\$$x$ … |\n// table |` pair with a `$$` far below and rewrite the table's pipes\n// (2026-08-19 review r2 P1-1), and a `(?<![\\\\$])` guard disagreed on `$$$$`\n// / `\\$$$` (oracle re-check). Inline stays as it was (line-local; the cut is\n// a line start, so it cannot pair across a freeze).\nconst EVEN_BACKSLASHES = String.raw`(?<=(?:^|[^\\\\])(?:\\\\\\\\)*)`;\nconst LATEX_BLOCK_REGEX = new RegExp(\n String.raw`${EVEN_BACKSLASHES}\\$\\$([\\S\\s]*?)${EVEN_BACKSLASHES}\\$\\$|(?<![\\\\$])\\$(?!\\$)((?:[^$\\n]|\\\\\\$)*?)(?<![\\\\` +\n '`' +\n String.raw`])\\$(?!\\$)`,\n 'g'\n);\nconst TEXT_COMMAND = '\\\\text{';\nconst SINGLE_DOLLAR_REGEX = /(?<![\\\\$])\\$(?!\\$)((?:[^$\\n]|\\\\[$])+?)(?<!\\\\)(?<!`)\\$(?!\\$)/g;\n\n/** Bare `$` count in `str[from, to)`: a `$` not preceded by `\\\\` or `$` and\n * not followed by `$` (the old NO_ESCAPED_DOLLAR_REGEX rule), with the\n * characters just outside the range supplied so a range can be counted in\n * isolation and summed with its neighbours: `prev` stands in for\n * `str[from - 1]`, `next` for `str[to]`. */\nfunction countBareDollars(str: string, from: number, to: number, prev: string, next: string): number {\n let n = 0;\n for (let j = from; j < to; j++) {\n if (str.charCodeAt(j) !== 36 /* $ */) continue;\n const before = j > from ? str[j - 1] : prev;\n const after = j + 1 < to ? str[j + 1] : next;\n if (before !== '\\\\' && before !== '$' && after !== '$') n += 1;\n }\n return n;\n}\n\n/**\n * Escape currency dollar signs (e.g. $100, $1,000.50) so they are not\n * misinterpreted as LaTeX delimiters.\n *\n * The tricky part: a `$` followed by digits might still be inside a LaTeX\n * expression (e.g. `$8.29 \\text{ B} \\times 4$`). We detect this by checking\n * whether there is an odd number of unescaped `$` on the same line after the\n * current match — if so, the current `$` is a LaTeX opener, not currency.\n */\nfunction escapeCurrencyDollarSigns(text: string): string {\n const parts: string[] = [];\n let lastIndex = 0;\n const currencyMatches = Array.from(text.matchAll(CURRENCY_REGEX));\n\n // Track the processed content of the current line incrementally, together\n // with its bare-`$` COUNT: the parity check below used to re-scan the whole\n // processed line on every match, O(line²) for a line with many currency\n // hits (12 KB table row: 59 ms per frame; 8 KB: 243 ms — 2026-08-19\n // review r2 P2-1). Appending a piece adds its own count plus a seam\n // correction (the previous last `$` loses its \"not followed by `$`\" when\n // the piece starts with `$`).\n let currentLineProcessed = '';\n let currentLineDollars = 0;\n const appendToLine = (piece: string): void => {\n if (piece.length === 0) return;\n const prevLast = currentLineProcessed.length > 0 ? currentLineProcessed[currentLineProcessed.length - 1] : '';\n const prevBeforeLast = currentLineProcessed.length > 1 ? currentLineProcessed[currentLineProcessed.length - 2] : '';\n const prevLastCounted = prevLast === '$' && prevBeforeLast !== '\\\\' && prevBeforeLast !== '$';\n if (prevLastCounted && piece[0] === '$') currentLineDollars -= 1;\n currentLineDollars += countBareDollars(piece, 0, piece.length, prevLast, '');\n currentLineProcessed += piece;\n };\n const resetLine = (rest: string): void => {\n currentLineProcessed = '';\n currentLineDollars = 0;\n appendToLine(rest);\n };\n\n for (let i = 0; i < currencyMatches.length; i++) {\n const match = currencyMatches[i];\n const segment = text.substring(lastIndex, match.index);\n parts.push(segment);\n\n // Update currentLineProcessed: keep only content after the last newline.\n const newlineIdx = Math.max(segment.lastIndexOf('\\n'), segment.lastIndexOf('\\r'));\n if (newlineIdx !== -1) {\n resetLine(segment.substring(newlineIdx + 1));\n } else {\n appendToLine(segment);\n }\n\n let needEscape = true;\n // Only the FIRST line after this match matters below; bound the slice\n // by the next line ending instead of splitting the whole remainder into\n // a line array on every match — O(remainder) per frame on the hot path\n // for the last match (2026-08-19 review).\n const restStart = match.index + 1;\n const restEnd = i < currencyMatches.length - 1 ? currencyMatches[i + 1].index : text.length;\n let firstLineBeforeNextMatch = '';\n if (restEnd - restStart > 0) {\n let eol = restEnd;\n for (let k = restStart; k < restEnd; k++) {\n const c = text.charCodeAt(k);\n if (c === 10 /* \\n */ || c === 13 /* \\r */) {\n eol = k;\n break;\n }\n }\n firstLineBeforeNextMatch = text.substring(restStart, eol);\n }\n const restDollars = countBareDollars(firstLineBeforeNextMatch, 0, firstLineBeforeNextMatch.length, '', '');\n if (restDollars % 2 !== 0) {\n // Parity of `currentLineProcessed + firstLineBeforeNextMatch` (the\n // current `$` itself excluded), summed from the two counts with the\n // seam corrected both ways.\n const L = currentLineProcessed;\n const lLast = L.length > 0 ? L[L.length - 1] : '';\n const lBeforeLast = L.length > 1 ? L[L.length - 2] : '';\n const lLastCounted = lLast === '$' && lBeforeLast !== '\\\\' && lBeforeLast !== '$';\n const f0 = firstLineBeforeNextMatch[0];\n let whole = currentLineDollars + restDollars;\n // L's last `$` is now followed by F's first char.\n if (lLastCounted && f0 === '$') whole -= 1;\n // F's first `$` was counted with an empty predecessor; L supplies one.\n if (f0 === '$' && (lLast === '\\\\' || lLast === '$') && firstLineBeforeNextMatch[1] !== '$') whole -= 1;\n if (whole % 2 !== 0) needEscape = false;\n }\n\n const replacement = needEscape ? '\\\\$' : '$';\n parts.push(replacement);\n // Append to currentLineProcessed so subsequent parity checks on the same\n // line see the correct count of unescaped `$` (e.g. a left-as-`$` opener\n // that the next match's check must count).\n appendToLine(replacement);\n lastIndex = match.index + 1;\n }\n parts.push(text.substring(lastIndex));\n return parts.join('');\n}\n\n/**\n * Convert LaTeX bracket delimiters to dollar sign delimiters.\n * Converts \\[...\\] to $$...$$ and \\(...\\) to $...$\n *\n * @param text Input string containing LaTeX expressions\n * @returns String with LaTeX bracket delimiters converted to dollar sign delimiters\n * @modified from https://github.com/lobehub/lobe-ui/blob/master/src/hooks/useMarkdown/latex.ts\n */\nfunction convertLatexDelimiters(text: string): string {\n return text.replaceAll(\n DELIMITERS_REGEX,\n (match: string, squareBracket: string | undefined, roundBracket: string | undefined): string => {\n if (squareBracket !== undefined) {\n return `$$${squareBracket}$$`;\n } else if (roundBracket !== undefined) {\n return `$${roundBracket}$`;\n }\n return match;\n }\n );\n}\n\n/**\n * Helper function: replace unescaped pipes with \\vert in LaTeX math fragments\n * @from https://github.com/lobehub/lobe-ui/blob/master/src/hooks/useMarkdown/latex.ts\n */\nconst replaceUnescapedPipes = (formula: string): string =>\n // Use \\vert{} so the control sequence terminates before the next token.\n // Preserve `|` inside \\begin{array}{...} / \\begin{tabular}{...} column specifiers.\n formula.replaceAll(ARRAY_COL_SPEC_OR_PIPE_REGEX, (match, colSpec: string | undefined) =>\n colSpec !== undefined ? match : '\\\\vert{}'\n );\n/**\n * Escape pipes in LaTeX expressions to prevent them from being interpreted as\n * column separators in markdown tables.\n *\n * @param text Input string containing LaTeX expressions\n * @returns String with pipes escaped in LaTeX expressions\n * @modified from https://github.com/lobehub/lobe-ui/blob/master/src/hooks/useMarkdown/latex.ts\n */\nfunction escapeLatexPipes(text: string): string {\n return text.replaceAll(LATEX_BLOCK_REGEX, (match, display, inline) => {\n if (display !== undefined) return `$$${replaceUnescapedPipes(display)}$$`;\n if (inline !== undefined) return `$${replaceUnescapedPipes(inline)}$`;\n return match;\n });\n}\n\n/**\n * Whether the character at position `pos` is escaped by the immediately\n * preceding backslash run. An even-count run (including zero) means the\n * `$` is unescaped; an odd count means it is escaped. Example: `\\\\$` has\n * two preceding backslashes — the `\\` escapes the `\\`, leaving `$` real.\n */\nfunction isEscapedByBackslashRun(text: string, pos: number): boolean {\n let count = 0;\n let j = pos - 1;\n while (j >= 0 && text[j] === '\\\\') {\n count++;\n j--;\n }\n return count % 2 === 1;\n}\n\n/**\n * Find the start index of the trailing unclosed `$$` or `$` delimiter.\n *\n * Scans through all dollar-sign tokens tracking open/close state.\n * Returns the index of the last *opening* delimiter that was never closed,\n * or `-1` if every delimiter is paired.\n *\n * @param text Input string to scan.\n * @param mode `'both'` tracks `$$` and `$`; `'double-only'` tracks only `$$`.\n */\nfunction findUnclosedDelimiterStart(text: string, mode: 'both' | 'double-only'): number {\n let unclosedStart = -1;\n let i = 0;\n while (i < text.length) {\n if (text[i] === '$' && i + 1 < text.length && text[i + 1] === '$' && !isEscapedByBackslashRun(text, i)) {\n unclosedStart = unclosedStart === -1 ? i : -1;\n i += 2;\n } else if (\n mode === 'both' &&\n text[i] === '$' &&\n !isEscapedByBackslashRun(text, i) &&\n (i + 1 >= text.length || text[i + 1] !== '$')\n ) {\n unclosedStart = unclosedStart === -1 ? i : -1;\n i += 1;\n } else {\n i += 1;\n }\n }\n return unclosedStart;\n}\n\nfunction escapeLatexPipesInUnclosed(text: string): string {\n const unclosedStart = findUnclosedDelimiterStart(text, 'both');\n if (unclosedStart === -1) return text;\n\n // Escape pipes only in the unclosed tail\n const before = text.substring(0, unclosedStart);\n const delimLen = text[unclosedStart + 1] === '$' ? 2 : 1;\n const delim = text.substring(unclosedStart, unclosedStart + delimLen);\n const tail = text.substring(unclosedStart + delimLen);\n return before + delim + replaceUnescapedPipes(tail);\n}\n\n/**\n * Truncate trailing unclosed `$$` blocks (streaming protection).\n *\n * During streaming, an unclosed `$$` at the start of a line triggers\n * remarkMath's `mathFlow` tokenizer, which treats all subsequent content\n * as part of a display math block until a closing `$$` fence is found.\n * Since the closing fence hasn't arrived yet, the entire remainder of the\n * document is swallowed into one giant math node — producing a wall of\n * red KaTeX error text.\n *\n * This function detects the trailing unclosed `$$` and removes it\n * (including any preceding whitespace/newlines) so that remarkMath never\n * sees the incomplete delimiter. Once the closing delimiter arrives in\n * a later streaming chunk, the complete block will render normally.\n *\n * Only tracks `$$` — single `$` does not trigger mathFlow and is harmless\n * when `singleDollarTextMath` is `false`.\n */\nfunction truncateUnclosedLatexBlock(\n text: string,\n unclosedStart = findUnclosedDelimiterStart(text, 'double-only')\n): string {\n if (unclosedStart === -1) return text;\n\n // Strip the unclosed $$ block and any trailing whitespace before it.\n return text.substring(0, unclosedStart).trimEnd();\n}\n\n/**\n * Escape unescaped underscores within `\\text{...}` commands in LaTeX expressions.\n * For example, `\\text{node_domain}` becomes `\\text{node\\_domain}`, but\n * `\\text{node\\_domain}` stays unchanged.\n *\n * The body scan is brace-aware: nested groups `\\text{outer {inner}_x}`\n * are matched via a depth counter that respects `\\{` / `\\}` escapes and\n * the escape for `\\\\` itself, so the entire body (depth ≥ 0) is scanned\n * before we escape its underscores. An unclosed `\\text{` body (missing\n * closing brace, e.g. during streaming) is left untouched.\n *\n * @param text Input string that may contain LaTeX expressions\n * @returns String with unescaped underscores escaped within `\\text{...}` commands\n */\nfunction escapeTextUnderscores(text: string): string {\n let out = '';\n let i = 0;\n while (i < text.length) {\n const start = text.indexOf(TEXT_COMMAND, i);\n if (start === -1) {\n out += text.substring(i);\n return out;\n }\n\n out += text.substring(i, start);\n const bodyStart = start + TEXT_COMMAND.length;\n let depth = 1;\n let j = bodyStart;\n while (j < text.length && depth > 0) {\n const c = text[j];\n if (c === '\\\\' && j + 1 < text.length) {\n // Skip the escaped character so `\\{`, `\\}`, `\\\\` don't affect depth.\n j += 2;\n continue;\n }\n if (c === '{') depth++;\n else if (c === '}') {\n depth--;\n if (depth === 0) break;\n }\n j++;\n }\n\n if (depth !== 0) {\n // Unclosed \\text{ — leave the remainder as-is so a later streaming\n // chunk can complete it.\n out += text.substring(start);\n return out;\n }\n\n const body = text.substring(bodyStart, j);\n const escapedBody = body.replaceAll(/(?<!\\\\)_/g, '\\\\_');\n out += `\\\\text{${escapedBody}}`;\n i = j + 1; // past closing `}`\n }\n return out;\n}\n\n/**\n * Convert single dollar delimiters to double dollar delimiters.\n * e.g. $x^2$ → $$x^2$$\n */\nfunction convertSingleToDoubleDollar(text: string): string {\n return text.replaceAll(SINGLE_DOLLAR_REGEX, (_match, content: string) => `$$${content}$$`);\n}\n\n/**\n * Main LaTeX preprocessor entry point.\n *\n * Splits the input into protected regions (code blocks, inline code, HTML tags)\n * and applies the full normalization pipeline to unprotected text segments.\n * Returns the input unchanged when no LaTeX-related characters (`$`, `\\[`, `\\(`)\n * are detected.\n *\n * @param str - Raw markdown string.\n * @returns The preprocessed string with normalized LaTeX delimiters.\n */\nexport function preprocessLaTeX(str: string): string {\n // Return early if no LaTeX patterns are found.\n if (!hasLatexTrigger(str)) return str;\n // The transform chain itself lives in `processSlice` — the incremental\n // preprocessor needs the same chain with quiescence probes, and until\n // 2.5.2 the two were written out separately and kept byte-equal BY HAND.\n // Byte-equality is a hard contract (the incremental wrapper freezes a\n // prefix of this function's output), so a chain that can drift is a defect\n // waiting to happen rather than a duplication to tolerate. The only thing\n // that was ever genuinely different is the whole-string early-exit above,\n // which a slice must not re-decide — see `processSlice`.\n return processSlice(str, false).out;\n}\n\n// ─── Incremental (append-aware) wrapper ─────────────────────────────────────\n//\n// `preprocessLaTeX` is O(n) per call and runs on every revealed frame during\n// smooth streaming. The wrapper below freezes the transformed output of the\n// settled prefix and re-processes only the active tail, byte-identical to\n// `preprocessLaTeX(full)` at every step — INCLUDING the whole-string\n// early-exit's quirks (that equivalence, not idealized semantics, is the\n// contract; pinned by the replay/property suites in latex.incremental.test.ts).\n//\n// Safe-cut rules (oracle-amended design, 2026-08-05 review):\n// - a cut sits at a LINE START (preceding char strictly `\\n`; lone-`\\r`\n// documents never cut and gracefully degrade to full reprocessing),\n// - inside a TEXT segment of the active region's own split (never inside a\n// fence / inline span / protected tag region),\n// - with no dangling backtick run between the last blank line and it (an\n// unmatched run can pair with a run arriving later and re-segment the\n// past — but a code span cannot cross a blank line, so a blank settles\n// every run before it),\n// - with no LATENT html tag before it — a viable `<`+letter start whose `>`\n// has not arrived: HTML_TAG_REGEX admits newlines in attributes, so the\n// match window spans lines and only a `>` anywhere after the `<` settles\n// it permanently (B1 counterexample),\n// - and, decided on the TRANSFORMED slice (raw-text checks are unsound both\n// ways because currency escaping rewrites the `$` token stream — B5):\n// quiescence — no tail-sensitive transform engaged at slice end.\n\n/** The original whole-string early-exit predicate (shared verbatim). */\nfunction hasLatexTrigger(str: string): boolean {\n return str.includes('$') || str.includes('\\\\[') || str.includes('\\\\(');\n}\n\n/** Does `text` contain an unclosed `\\text{` body? Mirrors the escape-aware\n * brace walk of `escapeTextUnderscores`'s unclosed branch. */\nfunction hasUnclosedTextCommand(text: string): boolean {\n let i = 0;\n while (i < text.length) {\n const start = text.indexOf(TEXT_COMMAND, i);\n if (start === -1) return false;\n let depth = 1;\n let j = start + TEXT_COMMAND.length;\n while (j < text.length && depth > 0) {\n const c = text[j];\n if (c === '\\\\' && j + 1 < text.length) {\n j += 2;\n continue;\n }\n if (c === '{') depth++;\n else if (c === '}') depth--;\n j++;\n }\n if (depth !== 0) return true;\n i = j;\n }\n return false;\n}\n\n/** A convertible (non-image) `\\[` still present after delimiter conversion —\n * its `\\]` has not arrived, so a later append changes this segment. */\nconst RESIDUAL_OPEN_BRACKET_RE = /(?<!!)\\\\\\[/;\n\n/** Segment whose first non-whitespace bytes are a `$$` — the only shape\n * whose B3 seam flag can be set (see processSlice). */\nconst LEADING_DOUBLE_DOLLAR_RE = /^\\s*\\$\\$/;\n\ninterface SliceResult {\n out: string;\n /** No tail-sensitive transform engaged: safe to freeze this output. */\n quiescent: boolean;\n /** `truncateUnclosedLatexBlock` fired in the slice's FIRST segment with\n * only whitespace before the `$$` opener — the original's `trimEnd`\n * would cross the seam into the frozen output (B3). */\n truncatedAtSeamStart: boolean;\n}\n\n/** THE LaTeX transform chain — the single definition of it. Both entry\n * points come through here: {@link preprocessLaTeX} with `probe: false`\n * (output only), the incremental preprocessor with probes on.\n *\n * `probe` adds the quiescence flags and never touches `out`, so the two\n * callers cannot diverge on output. The whole-string early-exit stays OUT\n * of here on purpose: a slice must not re-decide it, because `\\text{a_b}`\n * in a trigger-free slice still transforms when the FULL string carries a\n * `$` elsewhere. */\nfunction processSlice(slice: string, probe = true): SliceResult {\n const segments = splitByProtectedRegions(slice);\n const parts: string[] = [];\n let quiescent = true;\n let truncatedAtSeamStart = false;\n for (let index = 0; index < segments.length; index++) {\n const segment = segments[index];\n if (segment.isCode) {\n parts.push(segment.text);\n continue;\n }\n let text = segment.text;\n text = escapeMhchemCommands(text);\n text = escapeCurrencyDollarSigns(text);\n text = convertLatexDelimiters(text);\n if (probe && RESIDUAL_OPEN_BRACKET_RE.test(text)) quiescent = false;\n text = escapeLatexPipes(text);\n if (probe && findUnclosedDelimiterStart(text, 'both') !== -1) quiescent = false;\n text = escapeLatexPipesInUnclosed(text);\n if (probe && hasUnclosedTextCommand(text)) quiescent = false;\n text = escapeTextUnderscores(text);\n text = convertSingleToDoubleDollar(text);\n // The tail pass (`probe: false`) only needs the FIRST segment's flag,\n // and that flag needs the segment's first non-blank bytes to be a `$$`\n // opener — cheap to rule out before the O(segment) unclosed scan (plain\n // prose is one segment; this scan was the last ~20% over stateless).\n // The scan result feeds truncateUnclosedLatexBlock too — one O(segment)\n // pass, not two (r2 P2-2: a tail starting with `$$`, the streaming\n // display block's steady state, scanned twice per frame).\n let unclosedDouble: number | undefined;\n if (probe || (index === 0 && LEADING_DOUBLE_DOLLAR_RE.test(text))) {\n unclosedDouble = findUnclosedDelimiterStart(text, 'double-only');\n if (unclosedDouble !== -1) {\n quiescent = false;\n if (index === 0 && text.slice(0, unclosedDouble).trim() === '') {\n truncatedAtSeamStart = true;\n }\n }\n }\n text = truncateUnclosedLatexBlock(text, unclosedDouble);\n parts.push(text);\n }\n return { out: parts.join(''), quiescent, truncatedAtSeamStart };\n}\n\n/** A raw line holding only spaces / tabs / CR — a CommonMark blank line. */\nfunction isBlankRawLine(text: string, from: number, to: number): boolean {\n for (let i = from; i < to; i++) {\n const c = text.charCodeAt(i);\n if (c !== 32 && c !== 9 && c !== 13) return false;\n }\n return true;\n}\n\n/**\n * Last raw-safe cut in `active`, or -1. Raw conditions only (line start\n * inside a text segment, no dangling backtick run before the last blank\n * line, no latent `<`); the transformed-output quiescence check happens on\n * the candidate slice afterwards.\n */\nfunction findRawSafeCut(active: string): number {\n const segments = splitByProtectedRegions(active);\n let offset = 0;\n let lastCut = -1;\n let backtickHazard = false;\n let latentLt = false;\n for (const segment of segments) {\n if (segment.isCode) {\n // Protected regions contain no cuts; a matched tag/span/fence carries\n // no cross-append state. `>` inside one still discharges a latent `<`\n // (HTML_TAG_REGEX scans raw text, blind to our segmentation).\n if (segment.text.includes('>')) latentLt = false;\n offset += segment.text.length;\n continue;\n }\n const text = segment.text;\n // Whether the segment's first (possibly partial) line starts at a real\n // line start — only then may it count as a blank line below.\n let atLineStart = offset === 0 || active.charCodeAt(offset - 1) === 10;\n let lineStart = 0;\n while (lineStart <= text.length) {\n const nl = text.indexOf('\\n', lineStart);\n const lineEnd = nl === -1 ? text.length : nl;\n // A dangling backtick run can only be re-segmented by a run arriving\n // later that PAIRS with it, and a code span cannot cross a blank line\n // (findClosingBacktickRun stops there; a mid-line run cannot become a\n // fence, which needs a line-start run of 3+). So a blank line settles\n // every backtick before it: the hazard latch releases and lines\n // after the blank are candidates again — instead of a lone backtick\n // freezing nothing for the rest of the stream (2026-08-19 review\n // P2-3; oracle-checked: the span search is the only segmentation\n // decision that looks past a finished line). The blank must be a\n // WHOLE raw line, exactly what findClosingBacktickRun stops at:\n // terminated by `\\n` inside this segment, only spaces/tabs/CR, and\n // starting at a real line start — a segment's first partial line sits\n // after a protected span on the same line, and the remainder after\n // its last `\\n` is the START of a line that continues in the next\n // segment (property-suite counterexample: an empty remainder released\n // the latch and a cut landed past a still-unpaired backtick).\n if (atLineStart && nl !== -1 && isBlankRawLine(text, lineStart, lineEnd)) backtickHazard = false;\n for (let i = lineStart; i < lineEnd; i++) {\n const ch = text[i];\n if (ch === '`') backtickHazard = true;\n else if (ch === '>') latentLt = false;\n else if (ch === '<') {\n const next = text[i + 1];\n if (next !== undefined && (next === '/' || /[A-Za-z]/.test(next))) latentLt = true;\n }\n }\n if (nl === -1) break;\n if (!backtickHazard && !latentLt) lastCut = offset + nl + 1;\n lineStart = nl + 1;\n atLineStart = true;\n }\n offset += text.length;\n }\n return lastCut;\n}\n\n/** Only attempt a freeze once the unfrozen region exceeds this many chars —\n * below it the extra pipeline pass costs more than it saves. */\nconst DEFAULT_FREEZE_ATTEMPT_THRESHOLD = 512;\n\n/**\n * Append-aware `preprocessLaTeX`: one instance per streaming lineage (the\n * component holds it like the smooth-stream controller). Byte-identical to\n * `preprocessLaTeX(full)` on every call; non-append input resets all state;\n * identical input replays the cached output (StrictMode/idempotence).\n *\n * @param options.freezeThreshold Active-region size below which no freeze\n * is attempted. Tests pass `0` so SHORT pinned counterexamples actually\n * exercise the freeze path instead of passing vacuously through the\n * full-reprocess fallback.\n * @internal Wired by the renderer; not part of the public API.\n */\nexport function createIncrementalLatexPreprocessor(options?: {\n freezeThreshold?: number;\n /** Failure backoff (default on). Tests that rely on `freezeThreshold: 0`\n * to attempt a freeze on EVERY call turn it off, so 1-char chunkings keep\n * exercising the cut rules instead of skipping most attempts; backoff\n * can only freeze LESS, so passing without it implies passing with it.\n * @internal */\n backoff?: boolean;\n /** Test hook: called once per freeze ATTEMPT (a scan of the active\n * region) with the region's length and how many source bytes the\n * attempt froze (0 = failed), so the backoff bound and freeze progress\n * can be pinned. @internal */\n onAttempt?: (info: { activeLength: number; frozenBytes: number }) => void;\n}): (content: string) => string {\n const freezeThreshold = options?.freezeThreshold ?? DEFAULT_FREEZE_ATTEMPT_THRESHOLD;\n const onAttempt = options?.onAttempt;\n const backoff = options?.backoff ?? true;\n let prevSource = '';\n let prevOutput = '';\n let frozenSrcEnd = 0;\n let frozenOut = '';\n let triggered = false;\n // Failure backoff (2026-08-19 review P2-3): a candidate that is not\n // quiescent stays that way for as long as it is the candidate (its bytes\n // never change under append — an early stray `$` keeps parity odd for\n // every later slice), yet each frame paid a full active-region scan plus\n // a wasted candidate pass on top of the unavoidable tail pass (3× the\n // stateless cost on such documents). After a failed attempt the next one\n // waits until the active region has doubled; failed-attempt cost is then\n // a geometric series (≤ 4·O(n) over the whole stream). Freezing later\n // never changes output — every frame equals `preprocessLaTeX(full)`.\n let nextAttemptLen = 0;\n\n return function incrementalPreprocessLaTeX(source: string): string {\n if (source === prevSource) return prevOutput;\n const isAppend = source.length > prevSource.length && source.startsWith(prevSource);\n if (!isAppend) {\n frozenSrcEnd = 0;\n frozenOut = '';\n triggered = false;\n nextAttemptLen = 0;\n }\n if (!triggered) {\n // Monotone gate (B4): while the ACCUMULATED string has no trigger, the\n // original early-exits with the identity — freezing transformed output\n // in that regime would diverge the moment a later `$` arrives and the\n // full run starts transforming the prefix (`\\text{a_b}` quirk). Only\n // the appended chunk plus one char of overlap needs checking (`\\[` /\n // `\\(` can straddle the seam).\n const checkFrom = isAppend ? Math.max(0, prevSource.length - 1) : 0;\n if (!hasLatexTrigger(source.slice(checkFrom))) {\n prevSource = source;\n prevOutput = source;\n return source;\n }\n triggered = true;\n }\n let active = source.slice(frozenSrcEnd);\n if (active.length > freezeThreshold && active.length >= nextAttemptLen) {\n const activeLength = active.length;\n let advanced = false;\n let frozenBytes = 0;\n const freeze = (cut: number, slice: SliceResult) => {\n frozenOut += slice.out;\n frozenSrcEnd += cut;\n active = source.slice(frozenSrcEnd);\n advanced = true;\n frozenBytes = cut;\n };\n const cut = findRawSafeCut(active);\n if (cut > 0) {\n const candidate = processSlice(active.slice(0, cut));\n if (candidate.quiescent) freeze(cut, candidate);\n }\n // A shorter fallback cut (largest cut before the first non-quiescent\n // segment) was designed and rejected: quiescence is segment-granular\n // (plain prose is ONE segment) and, with the threshold, the unfrozen\n // prefix before trouble is < threshold bytes anyway — the backoff\n // alone brings a permanently-failing document to ≈ the stateless\n // cost (oracle review, 2026-08-19).\n nextAttemptLen = advanced || !backoff ? 0 : active.length * 2;\n onAttempt?.({ activeLength, frozenBytes });\n }\n // Tail pass: transforms only — its `quiescent` is never read, only the\n // first segment's B3 flag, so the per-segment probes are skipped (they\n // were ~40% on top of the stateless cost for a document whose freeze\n // never succeeds; the backoff had already removed the other 2×).\n const tail = processSlice(active, false);\n // B3 seam correction: the original's segment-level `trimEnd` reaches\n // back across our cut when the truncated `$$` block's segment starts\n // with nothing but whitespace. Applied at COMPOSE time only — the\n // frozen output itself stays untrimmed, because the block will close\n // in a later append and the untrimmed bytes become correct again.\n const head = tail.truncatedAtSeamStart ? frozenOut.replace(/\\s+$/, '') : frozenOut;\n const out = head + tail.out;\n prevSource = source;\n prevOutput = out;\n return out;\n };\n}\n","/**\n * Content preprocessing pipeline.\n *\n * Runs all preprocessors (built-in + user-supplied) in sequence before\n * the markdown string is handed to react-markdown. The built-in LaTeX\n * preprocessor always runs first, followed by any extra preprocessors\n * provided by the consumer.\n *\n * @module preprocessors\n */\n\nimport { AIMDContentPreprocessor } from './defs';\nimport { preprocessLaTeX } from './latex';\n\n/** Sequentially apply an array of preprocessor functions via left-fold. */\nfunction applyPreprocessors(value: string, ...fns: Array<AIMDContentPreprocessor>): string {\n return fns.reduce((result, fn) => fn(result), value);\n}\n\n/** Stable empty array to avoid re-renders when no extra preprocessors are given. */\nconst defaultExtraPreprocessors: AIMDContentPreprocessor[] = [];\n\n/**\n * Run the full preprocessing pipeline on raw markdown content.\n *\n * @param content - Raw markdown string.\n * @param extraPreprocessors - Optional user-supplied preprocessors appended after the built-in ones.\n * @param latexPreprocessor - The LaTeX stage. Defaults to the stateless\n * {@link preprocessLaTeX}; the renderer passes a per-instance\n * append-aware wrapper (byte-identical output, O(active tail) on\n * streaming appends) so per-frame reveals stop paying O(document).\n * @returns The preprocessed markdown string ready for rendering.\n */\nexport default function preprocessAIMDContent(\n content: string,\n extraPreprocessors: AIMDContentPreprocessor[] = defaultExtraPreprocessors,\n latexPreprocessor: AIMDContentPreprocessor = preprocessLaTeX\n) {\n return applyPreprocessors(content, latexPreprocessor, ...extraPreprocessors);\n}\n","/**\n * Optional streaming tail-repair preprocessor built on `remend` (the\n * markdown-termination engine extracted from Vercel's Streamdown).\n *\n * While a response streams, the tail of the markdown source is frequently\n * mid-construct — `**bold` without its closer, an unterminated `` `code ``\n * span, a half-typed `[link](url`. The stock pipeline renders those frames\n * literally (asterisks and all) until the closing bytes arrive. Wrapping the\n * content with this preprocessor completes the unterminated syntax so every\n * frame renders styled.\n *\n * NOT enabled by default — opt in per instance:\n *\n * ```tsx\n * const remend = createRemendPreprocessor();\n * <AIMarkdown content={content} contentPreprocessors={[remend]} />\n * ```\n *\n * Create the preprocessor ONCE (module scope or `useMemo`) — a fresh function\n * identity per render would defeat `contentPreprocessors`' stable-value\n * memoization and re-run the whole pipeline every frame.\n *\n * Interactions (see docs/content-preprocessors.md for the full discussion):\n *\n * - **block-memo**: zero conflict. Repairs only append/adjust the tail;\n * earlier blocks' bytes are untouched, so their hast digests still hit.\n * - **incremental parse** (`incrementalParse`): frames whose tail was\n * repaired are not byte-appends of the previous frame, so the engine's\n * append gate falls back to a full parse for exactly those frames (not\n * sticky — splicing resumes once the construct closes in the real bytes).\n * - **`preprocessLaTeX`**: user preprocessors run AFTER the built-in LaTeX\n * pass. Math repair is therefore disabled here (`katex`/`inlineKatex`\n * forced off) — the LaTeX preprocessor already owns `$` handling,\n * including truncating unclosed `$$` tails.\n * - **complete documents**: on well-formed text remend is a no-op, so the\n * final frame renders identically with or without it. A document that\n * legitimately ends inside an unterminated marker (a trailing lone `*`)\n * will get it closed — acceptable for streaming UIs, but don't apply this\n * preprocessor to static content.\n *\n * @module preprocessors/remend\n */\n\nimport remend, { type RemendOptions } from 'remend';\nimport type { AIMDContentPreprocessor } from './defs';\n\n/** Options accepted by {@link createRemendPreprocessor} — everything remend\n * supports except the math toggles, which this pipeline reserves for the\n * built-in LaTeX preprocessor. */\nexport type RemendPreprocessorOptions = Omit<RemendOptions, 'katex' | 'inlineKatex'>;\n\n/**\n * Build an {@link AIMDContentPreprocessor} that completes unterminated\n * markdown syntax at the streaming tail.\n *\n * Deviations from remend's own defaults:\n *\n * - `linkMode: 'text-only'` (overridable) — remend's default (`'protocol'`)\n * substitutes a `streamdown:incomplete-link` placeholder URL, but this\n * pipeline's URL sanitizer strips unknown protocols, which would leave a\n * dead `<a>` for the duration of the stream. Rendering the link text\n * plainly until the real URL arrives looks better under our sanitize\n * defaults.\n * - `katex`/`inlineKatex` forced off (NOT overridable — removed from the\n * option type) — the built-in LaTeX preprocessor (which runs first)\n * already rewrites and truncates `$`/`$$` constructs; two writers on the\n * same delimiters would fight.\n */\nexport function createRemendPreprocessor(options?: RemendPreprocessorOptions): AIMDContentPreprocessor {\n return (content) =>\n remend(content, {\n linkMode: 'text-only',\n ...options,\n katex: false,\n inlineKatex: false,\n });\n}\n"],"mappings":"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","names":["unreachable","unreachable","processor","i","masked","normalizeIdentifier","visit","normalizeIdentifier","node","boundary","unified","remarkParse","normalizeIdentifier","unified","remarkParse","visit","visit","SKIP","visit","visit","SKIP","global","SKIP","visit","visit","SKIP","remarkGfm","visit","visit","remarkGfm","sanitizeSchema","normalizeUri","Symbol","objectProto","nativeObjectToString","symToStringTag","funcProto","objectProto","funcToString","hasOwnProperty","Map","objectProto","hasOwnProperty","objectProto","hasOwnProperty","HASH_UNDEFINED","objectProto","hasOwnProperty","objectProto","hasOwnProperty","MAX_SAFE_INTEGER","argsTag","funcTag","freeExports","freeModule","moduleExports","objectProto","hasOwnProperty","objectProto","objectProto","hasOwnProperty","objectProto","hasOwnProperty","freeExports","freeModule","moduleExports","Buffer","objectProto","propertyIsEnumerable","nativeGetSymbols","Promise","Set","mapTag","objectTag","setTag","weakMapTag","dataViewTag","objectProto","hasOwnProperty","Uint8Array","boolTag","dateTag","mapTag","numberTag","regexpTag","setTag","stringTag","arrayBufferTag","dataViewTag","float32Tag","float64Tag","int8Tag","int16Tag","int32Tag","uint8Tag","uint8ClampedTag","uint16Tag","uint32Tag","mapTag","setTag","argsTag","arrayTag","boolTag","dateTag","errorTag","funcTag","genTag","mapTag","numberTag","objectTag","regexpTag","setTag","stringTag","symbolTag","weakMapTag","arrayBufferTag","dataViewTag","float32Tag","float64Tag","int8Tag","int16Tag","int32Tag","uint8Tag","uint8ClampedTag","uint16Tag","uint32Tag","key","CLONE_DEEP_FLAG","CLONE_SYMBOLS_FLAG","normalizeUri","id","cut"]}