"""Unit: the verbatim panel client and the answer's Copy buttons (phase 182, task 07). The browser half of the story lives in the phase's Playwright suite (task 08); this module pins the SOURCE contract of ``frontend/assets/verbatim.js`` and the three client surfaces that consume it, in the established ``test_frontend_*`` convention — plus a node-driven half (skipped when node is unavailable, the phase-44/138/180/182 idiom) that runs the panel's PURE logic (caption, gutter, locator match, block guard) against the real file. Why these particular pins (the phase's drift risks, in order): * **ONE locator grammar.** ``markdown.js::borLocator`` is the client's single normalizer (task 06); hydration may only compare the server's canonical ``locator`` against the already-normalized ``data-bor-locator`` with a plain string ``===``. A second grammar in a second file is the phase's main way to break silently — so this module pins that no normalizer exists in ``verbatim.js`` (no ``borLocator``, no range regex, no ``parseInt``). * **The model's bytes never reach the screen or the clipboard.** The panel's text node is ``pre.textContent = block.text`` (server bytes, verbatim) and the Copy button copies the same string — never the DOM, never the gutter, never the model's re-typed fence body (which task 06 dropped upstream). * **The claim is carried by words, not colours** (LOCKED A5): the badge text is ``VERBATIM``, the honest state is the pinned sentence ``I could not verify this against the knowledge base``, and an ordinary code block gets a Copy button with NO badge. * **Parity.** The live turn, the reload restore and the anonymous shared page call the SAME globals, in the SAME order (hydrate → append the unlocated → settle the code blocks, all inside the ``answer_image`` band and BEFORE the source clusters), so one answer cannot render three different ways. * **The mid-turn pass settles ONLY what it matches** (phase 192, task 02): the additive ``verbatim_block`` frame carries ONE block, and ``hydrateVerbatimNow`` may replace only the pending placeholders that block matches — every other placeholder STAYS ``.verbatim-pending`` for the ``done`` / failure path, because burning a fence for a block that has not arrived yet is how a resolved panel turns into "I could not verify this". * **One canonical locator, one panel** (phase 192, A3): a mid-turn block that no fence named yet is appended at the answer position, and when the answer fences it later the hydration drops that appended twin (``dropPlacedTwin``, bounded by the ``.msg`` wrap) — the scan is PER LOCATOR, so two honest ranges of one file stay two panels. * **No panel is ever left lying.** Every terminal path — the ``error`` frame, the 300 s guard, the Stop action, the failed-turn funnel — settles the leftover placeholders; nothing reads "Retrieving the exact text…" after the turn is over. * **CSP + the house XSS rule.** Everything is ``createElement`` + ``textContent``, every handler is ``addEventListener``, and there is no ``innerHTML``/``onclick=``/``oncopy=`` anywhere in the new client. """ from __future__ import annotations import json import re import shutil import subprocess from pathlib import Path from typing import Any import pytest FRONTEND = Path(__file__).resolve().parents[2] / "frontend" ASSETS = FRONTEND / "assets" VERBATIM_JS = ASSETS / "verbatim.js" APP_JS = ASSETS / "app.js" SHARED_JS = ASSETS / "shared.js" DOCUMENT_JS = ASSETS / "document.js" MARKDOWN_JS = ASSETS / "markdown.js" STYLES_CSS = ASSETS / "styles.css" INDEX_HTML = FRONTEND / "index.html" SHARED_HTML = FRONTEND / "shared.html" CONTAINERFILE = FRONTEND.parent / "Containerfile" HAVE_NODE = shutil.which("node") is not None #: The labelled phase-182 CSS region (task 06's markers — task 07 extends #: INSIDE it, so the palette-only and contiguity pins keep holding). BLOCK_BEGIN = "/* ---------- Verbatim panels (phase 182, task 06) — BEGIN ----------" BLOCK_END = "/* ---------- Verbatim panels (phase 182, task 06) — END ---------- */" #: The honest state (pinned copy — task 07's Testing section). UNRESOLVED_COPY = "I could not verify this against the knowledge base" #: The badge's WORD (LOCKED A5) and the tooltip that explains it. BADGE_TEXT = "VERBATIM" BADGE_TITLE = "These bytes are copied from the knowledge base, not written by the model." #: The Copy control's accessible name template — the FULL path, never a #: clipped stand-in (the phase-156 clipped-label rule). COPY_ARIA = "Copy ${shown} lines from ${identity}" #: The globals task 07 exposes for the two page modules. PUBLIC_GLOBALS = ( "buildVerbatimPanel", "hydrateVerbatim", "hydrateVerbatimNow", # phase 192 (task 02): the MID-TURN pass "appendUnlocatedVerbatim", "settleVerbatimPlaceholders", "enhanceAnswerCodeBlocks", "copyTextWithFallback", ) def _text(path: Path) -> str: assert path.is_file(), f"missing file: {path}" return path.read_text(encoding="utf-8") def _strip_comments(text: str) -> str: """Comments out — the CSP and literal pins below are about CODE. The file's own header documents the very patterns it forbids (``onclick=``, ``javascript:``), and a prose-blind grep would flag the documentation of the rule as the rule.""" text = re.sub(r"/\*[\s\S]*?\*/", "", text) return re.sub(r"(?m)^\s*//.*$", "", text) def _fn(js: str, name: str) -> str: """The source of a top-level (optionally ``async``) ``function ``.""" start = js.find(f"function {name}(") assert start != -1, f"{name}() must exist" return js[start : js.find("\n}\n", start) + 4] def _body(js: str, name: str) -> str: return _fn(js, name) def _doc(js: str, name: str) -> str: """The ``/* … */`` doc comment that sits directly above ``function `` — the house docstring-pinning convention for the clients: the prose IS the contract record, so a refactor that "simplifies" the rule away has to delete the sentence in the same change.""" start = js.find(f"\nfunction {name}(") assert start != -1, f"function {name}() must exist" open_ = js.rfind("/*", 0, start) close = js.find("*/", open_) assert open_ != -1 and close != -1 and close < start, ( f"{name}() must carry the doc comment above it" ) return js[open_ : close] def _flow(text: str) -> str: """Comment prose as one line — the pins quote the SENTENCE, not its wrapping (the `` * `` line leaders come out with the wrap).""" lines = [re.sub(r"^\s*\*+\s?", " ", line) for line in text.splitlines()] return " ".join(" ".join(lines).split()) # --------------------------------------------------------------------------- # the client ships, and ships in the right shape # --------------------------------------------------------------------------- def test_verbatim_js_is_a_classic_script_after_markdown_on_both_pages() -> None: """Both pages load it as a PLAIN ``' in index assert '' in shared assert index.index('src="assets/markdown.js"') < index.index('src="assets/verbatim.js"'), ( "verbatim.js hydrates markdown.js's placeholders — it loads after it" ) assert index.index('src="assets/verbatim.js"') < index.index( 'type="module" src="/assets/app.js"' ), "the globals must exist before app.js evaluates" assert shared.index('src="/assets/markdown.js"') < shared.index('src="/assets/verbatim.js"') assert shared.index('src="/assets/verbatim.js"') < shared.index( 'type="module" src="/assets/shared.js"' ) tag = next(line for line in index.splitlines() if "verbatim.js" in line and " None: """Stage 1 builds it the way it builds ``markdown.js``: ``--minify`` WITHOUT ``--bundle`` (bundling a classic script would break the global exposure), and the source itself stays free of top-level ``import``/``export``.""" container = _text(CONTAINERFILE) line = next( row for row in container.splitlines() if "assets/verbatim.js" in row ) assert "--minify" in line assert "--outfile=/out/assets/verbatim.js" in line assert "--bundle" not in line, "a classic script is never bundled" assert "--format=esm" not in line js = _text(VERBATIM_JS) assert "\nimport " not in js and "\nexport " not in js def test_every_public_global_exists() -> None: """The API the two page modules call, as top-level function declarations (the ``markdown.js`` exposure pattern — a classic script's top-level functions ARE the globals).""" js = _text(VERBATIM_JS) for name in PUBLIC_GLOBALS: assert f"function {name}(" in js, f"verbatim.js must expose {name}" def test_no_locator_normalizer_is_re_implemented() -> None: """THE phase's drift pin: hydration compares the server's canonical ``locator`` against the ``data-bor-locator`` markdown.js already normalized, with a PLAIN string compare. No grammar here — no ``borLocator``, no range regex, no en-dash handling, no ``parseInt``, no ``L``-prefix stripping (a second grammar in a second file is how a resolved block stops hydrating).""" js = _text(VERBATIM_JS) assert "function borLocator" not in js assert "parseInt" not in js assert "\u2013" not in _fn(js, "matchVerbatimBlock"), "no en-dash parsing here" for pattern in ("[Ll]", "L?\\d", "#L", "trimStart", "normalize("): assert pattern not in js, f"{pattern} looks like a re-implemented grammar" match = _fn(js, "matchVerbatimBlock") assert "block.locator === key" in match, "the exact match is a plain string compare" hydrate = _fn(js, "hydrateVerbatim") assert 'node.getAttribute("data-bor-locator")' in hydrate, ( "hydration reads the attribute markdown.js wrote — it never re-derives it" ) # --------------------------------------------------------------------------- # the panel's contract (LOCKED A2/A5/A7) # --------------------------------------------------------------------------- def test_panel_is_a_labelled_group_keyed_by_the_servers_locator() -> None: """``role="group"`` + ``aria-label="Verbatim text from , lines N\u2013M"`` + ``data-bor-locator`` = the SERVER's canonical locator (the key ``appendUnlocatedVerbatim`` later recognises, which is why a re-render never duplicates a panel).""" panel = _fn(_text(VERBATIM_JS), "buildVerbatimPanel") assert 'root.setAttribute("role", "group")' in panel assert 'root.setAttribute("aria-label", verbatimPanelLabel(block))' in panel assert "root.dataset.borLocator" in panel assert "block.locator" in panel, "the server's locator is the panel's identity" label = _fn(_text(VERBATIM_JS), "verbatimPanelLabel") assert '"Verbatim text from' in json.dumps(label) or "Verbatim text from" in label def test_badge_is_a_word_with_the_pinned_explanation() -> None: """LOCKED A5: the claim is the WORD ``VERBATIM`` (never an icon or a colour), with the tooltip that says what it means.""" js = _text(VERBATIM_JS) assert f'badge.textContent = "{BADGE_TEXT}"' in js assert BADGE_TITLE in js assert 'badge.className = "verbatim-badge"' in js def test_unresolved_state_is_the_pinned_sentence_and_nothing_else() -> None: """The honest state for a locator the server did not resolve: the pinned sentence, plus the document link ONLY when the identity parsed into a ``source/path``. NO badge, NO body, NONE of the model's bytes — and the builder creates neither a badge nor a ``
`` node at all, which is
    stronger than hiding one."""
    js = _text(VERBATIM_JS)
    assert f'"{UNRESOLVED_COPY}"' in js
    node = _fn(js, "buildVerbatimUnresolved")
    assert 'root.className = "verbatim verbatim-unresolved"' in node
    assert 'state.className = "verbatim-state"' in node
    assert "verbatim-badge" not in node, "an unresolved panel never badges"
    assert 'createElement("pre")' not in node, "and never has a body"
    assert 'createElement("ol")' not in node, "nor a gutter"
    assert "indexOf(" in node and "slash > 0" in node, (
        "the link appears only when the identity split into a source and a path"
    )


def test_copy_button_names_the_full_path_and_copies_the_servers_bytes() -> None:
    """The completion criterion at source level: the panel's Copy control is
    built from ``block.text`` (never from the DOM, never with the gutter's
    digits), and its accessible name is ``Copy N lines from `` —
    the full path, because the visible label is the CSS clip target
    (phase 156)."""
    js = _text(VERBATIM_JS)
    panel = _fn(js, "buildVerbatimPanel")
    assert COPY_ARIA in panel
    build = panel[panel.index("buildCopyButton(") :]
    assert '"verbatim-copy"' in build
    assert "block.text," in build.split("\n)")[0], (
        "the copied string is `block.text` — the exact bytes the panel shows"
    )
    control = _fn(js, "buildCopyButton")
    assert 'btn.setAttribute("aria-label", ariaLabel)' in control
    assert 'label.textContent = "Copy"' in control
    assert 'label.textContent = "Copied"' in control, "the state is TEXT (WCAG 1.4.1)"
    assert 'btn.classList.add("copied")' in control
    clipboard = _fn(js, "copyTextWithFallback")
    assert "await navigator.clipboard.writeText(text)" in clipboard, (
        "the caller's string goes to the clipboard untouched — no DOM read"
    )


def test_body_is_the_servers_text_with_the_servers_line_numbers() -> None:
    """The bounded body: the ``
    `` gutter (``aria-hidden`` — the range rides the panel's label, and the digits are ``user-select: none`` in CSS so a selection never drags them into the clipboard) and the ``
    ``
        whose ``textContent`` is ``block.text``, byte for byte."""
        js = _text(VERBATIM_JS)
        panel = _fn(js, "buildVerbatimPanel")
        assert 'body.className = "verbatim-body"' in panel
        assert 'numbers.className = "verbatim-lines"' in panel
        assert 'numbers.setAttribute("aria-hidden", "true")' in panel
        assert 'pre.className = "verbatim-text"' in panel
        assert "pre.textContent = block.text" in panel
        assert "li.textContent = row.number" in panel
        gutter = _fn(js, "verbatimGutter")
        assert 'split("\\n")' in gutter, "one gutter row per line of the SERVER text"
    
    
    def test_truncated_block_says_the_rest_is_in_the_document() -> None:
        """A capped block appends ONE muted line plus the same viewer link — the
        panel never pretends the slice is the whole file."""
        panel = _fn(_text(VERBATIM_JS), "buildVerbatimPanel")
        assert "if (block.truncated)" in panel
        assert 'more.className = "verbatim-more"' in panel
        assert "the rest is in the document" in panel
        assert "buildVerbatimOpenLink(" in panel.split("if (block.truncated)")[1]
    
    
    def test_open_link_is_a_real_href_with_the_modal_hook() -> None:
        """The panel links to the document viewer: an always-same-origin
        ``/document.html?source=…&path=…`` built with ``encodeURIComponent`` (so a
        path can never turn into ``javascript:``/``data:``), plus the chat page's
        click-to-modal hook through ``opts.onOpen`` — attached with
        ``addEventListener``, never an inline attribute."""
        js = _text(VERBATIM_JS)
        link = _fn(js, "buildVerbatimOpenLink")
        assert 'link.className = "verbatim-open"' in link
        assert "link.addEventListener(" in link
        assert "event.preventDefault()" in link
        assert "opts.onOpen(source, path, link)" in link
        href = _fn(js, "verbatimDocumentHref")
        assert "/document.html?source=" in href
        assert "encodeURIComponent(source)" in href and "encodeURIComponent(path)" in href
        code = _strip_comments(js)
        assert "javascript:" not in code and "data:" not in code, (
            "no scheme is ever assembled into a link target"
        )
    
    
    def test_plain_answer_code_blocks_get_copy_and_never_a_badge() -> None:
        """``enhanceAnswerCodeBlocks``: every ``
    `` in an answer bubble that
        is NOT inside a ``.verbatim`` gets ``.code-block`` + ``.code-block-copy``.
        NO badge and NO caption — verbatim-and-badged OR plainly the model's,
        never a hybrid (LOCKED A5). Idempotent: a ``
    `` already inside a
        ``.code-block`` is left alone."""
        fn = _fn(_text(VERBATIM_JS), "enhanceAnswerCodeBlocks")
        assert 'box.className = "code-block"' in fn
        assert '"code-block-copy"' in fn
        assert 'pre.closest(".verbatim")' in fn, "a panel owns its own Copy button"
        assert 'parent.classList.contains("code-block")' in fn, "idempotent on re-render"
        assert "verbatim-badge" not in fn
        assert "verbatim-caption" not in fn
    
    
    def test_hydration_is_idempotent_and_never_throws_on_garbage() -> None:
        """Only ``.verbatim-pending`` is replaced, so a hydrated panel (or one
        restored from storage) survives a re-run with its ``Copied`` state and
        scroll position; a missing/malformed ``blocks`` settles to the honest
        state instead of throwing."""
        js = _text(VERBATIM_JS)
        hydrate = _fn(js, "hydrateVerbatim")
        assert ".verbatim-pending[data-bor-locator]" in hydrate
        assert (
            "verbatim-unresolved"
            not in hydrate.split("matchVerbatimBlock")[1].split("replaceWith")[1].split("\n")[0]
        ), "the unresolved node comes from its own builder"
        assert "replaceWith(" in hydrate
        assert "try {" not in hydrate, "the guards make it total — no exception path"
        assert "verbatimBlocks(blocks)" in hydrate
        guard = _fn(js, "verbatimBlocks")
        assert "Array.isArray(blocks)" in guard, "a missing frame key is not an error"
    
    
    def test_midturn_hydration_settles_only_the_placeholders_one_block_matches() -> None:
        """Phase 192 (task 02, A2) — the heart of the mid-turn pass. The additive
        ``verbatim_block`` frame carries ONE block, and ``hydrateVerbatimNow``:
    
        * walks the SAME pending set as the done pass
          (``.verbatim-pending[data-bor-locator]``, the attribute ``markdown.js``
          normalized — no second grammar);
        * matches through the ONE rule (``matchVerbatimBlock`` with a one-block
          list) so the mid-turn pass and the ``done`` pass can never disagree
          about which fence this block owns;
        * replaces ONLY the matched nodes (``buildVerbatimPanel``) — the unmatched
          stay ``.verbatim-pending``, NEVER the honest unresolved state, which is
          the done/failure path's job (``settleVerbatimPlaceholders``);
        * returns the number settled (``0`` is the caller's signal to append);
        * is total without a ``try`` — a missing root, a root that is not an
          element, or a frame that is not a block all return ``0``."""
        js = _text(VERBATIM_JS)
        fn = _fn(js, "hydrateVerbatimNow")
        assert '.verbatim-pending[data-bor-locator]"' in fn, (
            "the mid-turn walk is the done path's pending set"
        )
        assert 'node.getAttribute("data-bor-locator")' in fn, (
            "the key is the attribute markdown.js wrote — never re-derived"
        )
        assert "matchVerbatimBlock(" in fn, "the ONE match rule, not a mid-turn variant"
        assert "const list = [block]" in fn, "the one-block frame rides the done list shape"
        assert "replaceWith(buildVerbatimPanel(" in fn, "only a MATCH builds a panel"
        assert "buildVerbatimUnresolved" not in fn, (
            "an unmatched fence stays pending mid-turn — settling is the terminal path's job"
        )
        assert "if (!matched) return" in fn, "the unmatched node is left in place"
        assert "settled += 1" in fn and "return settled" in fn, (
            "the count is the caller's append/no-append signal"
        )
        assert 'typeof root.querySelectorAll !== "function"' in fn, "a missing root is 0"
        assert "isVerbatimBlock(block)" in fn, "a malformed frame settles NOTHING"
        assert "try {" not in fn, "the guards make it total — no exception path"
        assert "innerHTML" not in fn
    
    
    def test_hydration_drops_the_midturn_twin_and_never_an_unresolved_one() -> None:
        """Phase 192 (A3): a block that arrived mid-turn before its fence was
        appended at the answer position; when its fence hydrates, that twin is
        removed so ONE locator keeps ONE panel and the panel sits where the model
        fenced it. The shape of the scan is the contract:
    
        * bounded by the message wrap (the appended panel lives in ``.msg-body``,
          beside the bubble — a bubble-local walk would miss it);
        * ``.verbatim-pending`` and ``.verbatim-unresolved`` are NOT placements
          (the ``appendUnlocatedVerbatim`` exclusion, shared);
        * the key is the ONE ``verbatimPlacedKey`` derivation (the same one the
          append-side scan reads — two derivations is how the dedupe drifts);
        * it compares the canonical LOCATOR (never an identity — two ranges of one
          file are two panels) and never removes the placeholder being hydrated."""
        js = _text(VERBATIM_JS)
        twin = _fn(js, "dropPlacedTwin")
        assert 'host.querySelectorAll(".verbatim[data-bor-locator]")' in twin
        assert 'el.classList.contains("verbatim-pending")' in twin
        assert 'el.classList.contains("verbatim-unresolved")' in twin
        assert 'el.getAttribute("data-bor-locator") !== placedKey' in twin, (
            "PER LOCATOR — an identity scan would collapse two honest ranges"
        )
        assert "verbatimSplitLocator" not in twin and "verbatimIdentity(" not in twin, (
            "no identity fallback in the twin scan"
        )
        assert "if (el === keep) return" in twin, "the hydrating placeholder is never the twin"
        assert "el.remove()" in twin
        hydrate = _fn(js, "hydrateVerbatim")
        assert 'root.closest(".msg")' in hydrate, "the scan is bounded by the message wrap"
        assert "if (block) dropPlacedTwin(host, block, node);" in hydrate, (
            "only a MATCHED placeholder drops a twin"
        )
        # The ONE key derivation, read by both dedupe sides.
        assert js.count("function verbatimPlacedKey(") == 1
        assert "verbatimPlacedKey(block)" in _fn(js, "appendUnlocatedVerbatim")
    
    
    #: The sentences the phase-192 (A3) prose must keep carrying. They are the
    #: only place a reader of ``verbatim.js`` learns the dedupe's two rules, and
    #: the fastest way to lose a rule is a refactor that drops its documentation
    #: first and its code second.
    TWIN_DOC_SENTENCES = (
        # PER LOCATOR, never per identity — the two-ranges-stay clause.
        "PER LOCATOR, never per identity: two different ranges of one file are"
        " two honest panels",
        # The in-text panel wins over the mid-turn appended twin.
        "The IN-TEXT panel wins",
    )
    
    
    def test_the_twin_dedupe_docstring_keeps_the_per_locator_clause() -> None:
        """Phase 192 (task 03, A3): the prose is part of the contract. The
        ``dropPlacedTwin`` docstring names the per-LOCATOR rule (and the
        two-honest-ranges clause that follows from it) and why the in-text panel
        wins; ``hydrateVerbatim``'s docstring says the matched placeholder drops
        that twin ("one locator, one panel, and it sits where the model fenced
        it"); and the module header states the same rule for whoever reads the
        file top-down."""
        js = _text(VERBATIM_JS)
        twin = _flow(_doc(js, "dropPlacedTwin"))
        for sentence in TWIN_DOC_SENTENCES:
            assert sentence in twin, f"the docstring lost: {sentence}"
        assert "appendUnlocatedVerbatim" in twin, (
            "the placement exclusion is documented as SHARED with the append side"
        )
        hydrate = _flow(_doc(js, "hydrateVerbatim"))
        assert "dropPlacedTwin" in hydrate
        assert "one locator, one panel, and it sits where the model fenced it" in hydrate
        header = _flow(js[: js.find("*/")])
        assert "ONE CANONICAL LOCATOR, ONE PANEL (phase 192)" in header
        assert "two honest ranges of one file stay two panels" in header
    
    
    def test_the_twin_scan_bounds_to_the_msg_wrap_or_the_root() -> None:
        """The scan's host is the message wrap (the appended twin lives in
        ``.msg-body``, beside the bubble), and when a root has no ``.msg``
        ancestor the ROOT bounds it — a missing wrap narrows the scan, it never
        switches the dedupe off."""
        hydrate = _fn(_text(VERBATIM_JS), "hydrateVerbatim")
        assert 'root.closest(".msg")' in hydrate
        assert 'root.closest(".msg") : null) || root' in hydrate, (
            "no .msg ancestor → the root bounds the scan"
        )
        assert "document.querySelectorAll" not in hydrate, (
            "never a page-wide scan — one message's twin, one message's panels"
        )
    
    
    def test_unlocated_blocks_land_in_the_answer_image_band() -> None:
        """The blocks no placeholder matched (a ``show_text`` call the prose never
        named) append to ``.msg-body`` — the same band as the answer image, below
        the text and above the source clusters, in frame order — and a block
        already placed (a panel carrying its canonical locator) is never
        appended twice."""
        fn = _fn(_text(VERBATIM_JS), "appendUnlocatedVerbatim")
        assert 'wrap.querySelector(".msg-body")' in fn
        assert "host.appendChild(buildVerbatimPanel(block, opts))" in fn
        assert "placed.add(" in fn and "if (placed.has(key)) continue" in fn
        assert "verbatim-unresolved" in fn, (
            "an unresolved placeholder is NOT a placement (the block still belongs on screen)"
        )
    
    
    def test_terminal_settle_renders_the_honest_state() -> None:
        """``settleVerbatimPlaceholders`` turns every leftover ``.verbatim-pending``
        into the unresolved node and records the ``kind`` for the next reader."""
        js = _text(VERBATIM_JS)
        fn = _fn(js, "settleVerbatimPlaceholders")
        assert 'root.querySelectorAll(".verbatim-pending")' in fn
        assert "buildVerbatimUnresolved(" in fn
        assert "replaceWith(" in fn, "the pending node is REPLACED, never patched"
        assert 'node.getAttribute("data-bor-locator")' in fn, (
            "the locator the model named rides into the honest state"
        )
        unresolved = _fn(js, "buildVerbatimUnresolved")
        assert 'root.dataset.verbatimState = (opts && opts.kind) || "unverified"' in unresolved, (
            "the settle kind is recorded for the next reader"
        )
        assert "state.textContent = verbatimUnresolvedCopy()" in unresolved
    
    
    # ---------------------------------------------------------------------------
    # CSP + the house XSS rule (the new client, and the new code in the pages)
    # ---------------------------------------------------------------------------
    
    
    def test_no_inline_handlers_and_no_html_anywhere_in_the_client() -> None:
        """CSP is ``default-src 'self'``: no ``onclick=``/``oncopy=`` attribute
        strings, no inline ``