mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-21 10:36:27 +03:00
The review threads on #840 found four ways the new rendered rules were still measuring something other than what the reader sees. - `line-length` read one `getClientRects()` box per direct text node and called each of them a rendered line. An inline `<strong>` in the middle of a sentence is its own text node, so one visual line arrived as two fragments and the paragraph's characters were divided between them — and the `<strong>`'s own text was never measured at all while its characters still counted toward `text_len`. Both halves of the measure are the same text now: the probe collects the rects of every text node under the element, and `Dom::text_line_rects` merges the ones that share a row back into the line they rendered as. A column of long lines split by inline markup used to charge nothing; it charges now, and a wrapped sentence in two fragments is one line, not two. - The same function divided every rect by the line box to recover a line count. On live per-line rects that was double-counting: a leading tighter than the glyph box makes `round(height / line_box)` 2, and one long line pushed twice satisfied "at least two long lines". Nothing is divided any more, because nothing that reaches the rule is a union. - The union was what a snapshot-backed scan had — the extension's offscreen document and any strict-CSP page — and a union of a long first line and a short tail is the same union as two even lines, so every line inferred from it was invented. The capture records the rects now (`dl`, with `textLines` on the snapshot saying it did), and a capture that did not answers `None`: the rule stands down rather than guessing. That is also what any other DOM that cannot split a wrapped run answers. - `ai-color-palette` accumulated its tell hues before the scoped ignores ran. A cyan tell inside a `data-impeccable-ignore="ai-color-palette"` subtree opened the page-wide two-hue gate and charged neon ink on an element nobody had waived. Ignored content now gets no vote. - `declared_component_selectors` took every backticked class in DESIGN.md as a declaration, including the ones the document writes down in order to forbid them. "Do not write a new `.hero-cta-primary`" exempted `.hero-cta-primary` from `kicker-above-heading` — the parser silencing exactly the misuse the document was written to catch. Each occurrence is read in the document's own structure now: the heading chain above it (a "Don't" section, and its subsections with it) and the clause it sits in, where a clause is cut on punctuation and on the phrases that turn a sentence around. "No ALL CAPS outside the `.eyebrow` class" still declares `.eyebrow`, because what "no" governs ends at "outside"; a class the document calls deprecated anywhere is declared nowhere. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LQBUunp8QttxZqihybNmtL
browser-bundle: the page-side JavaScript of the detector
Plain JavaScript that runs inside a page or the extension: the DOM probe the
wasm rule core calls back into, the page snapshot producer, the
visual-contrast sampling IO, the overlay UI, the scan API and the extension's
offscreen document. Measurement and presentation only; every rule decision
is a call into the wasm rule core built from crates/core (docs/ENGINE.md).
Two consumers:
crates/browserembeds15-snapshot.js(the snapshot producer the URL engine injects; no WebAssembly runs in the page).crates/bundle(theimpeccable-bundlelibrary) embeds every file here withinclude_str!and concatenates them, in filename order, with the wasm core into the in-page bundle plus the extension'sextension/detector/pieces.cargo xtask bundleis its caller inside this workspace: it writesdist/detect-antipatterns-browser.js, copies that bundle to the trackedcrates/live/assets/detect-antipatterns-browser.jsthe engine embeds, and writes the extension pieces. A downstream crate with its own rule pack calls the library directly (docs/ENGINE.md).
Because the files are embedded, a new one here has to be added to
PAGE_JS in crates/bundle/src/lib.rs (and to the order it is concatenated
in); a test fails when the two lists disagree.
15-snapshot.js lists the computed-style properties the rules read; the
bundle build checks that list against the core's and fails when they drift.