fix: resolve document-level custom properties in the fail-closed visibility checker - #45
Merged
Merged
Conversation
…bility checker `_style_state` only looked up `var()` inside the declaration block being evaluated, so a template that sets its tokens on `:root` and consumes them as bare `var(--token)` in later rules made `body` ambiguous under `fail_closed=True`. `visible_html_evidence()` then returned no text and `--check-content content.json filled.html` ended in "coverage is indeterminate" for every shipped template. Add a document-level custom property table with a narrow rule: a name is resolvable across blocks only when every declaration of it in the document (every rule body in every `<style>` block plus every inline `style` attribute, collected through HTMLParser so unquoted and entity-encoded values are seen) normalizes to the same value. Names declared with two different values stay unresolved, and any `@property` registration disables the table, so hidden evidence can never turn into a coverage pass. Local declarations in the evaluated block still override the table. Thread the table through `_css_hidden_filters`, the text evidence parser, and the resource evidence parser in `content.py`. Add regression coverage: the `:root` case, every shipped template producing visible text, and adversarial documents (ancestor override, media redefinition, `@property`, inline redefinition in three attribute syntaxes) that must not leak. Regenerate the plugin mirror and the release archive. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@jsiu93 is attempting to deploy a commit to the Faberon Team on Vercel. A member of the Team first needs to authorize it. |
# Conflicts: # dist/kami.zip
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #44.
Summary
var(--x)across declaration blocks in the fail-closed visibility checker when the document defines--xwith one value everywhere (:root { --ink: ... }in one rule,body { color: var(--ink) }in another)style="--x: ..."redefinition, or any@propertyregistration still leaves thevar()unresolved and the element ambiguous:rootcase, every shipped template producing visible text underfail_closed=True, and adversarial documents that must not leak hidden textWhy
_style_stateparses one declaration block at a time and itsresolved()helper only looks upvar()inside that block. Every shipped template writes its tokens on:rootand consumes them as barevar(--token)in later rules, so underfail_closed=Truethe checker marksbodyambiguous andvisible_html_evidence()returns no text at all. As a resultpython3 scripts/build.py --check-content content.json filled.htmlends in "content coverage is indeterminate" (exit 2) for a document filled from any of the 27 templates inassets/templates/. Isolating the ambiguity per rule showed barevar()was the only source in all 27; the test suite never exercised the coverage gate against a shipped template, which is why this went unnoticed.The fix adds a document-level custom property table with a deliberately narrow rule: a name is resolvable only when every declaration of it in the document (every rule body in every
<style>block, plus every inlinestyleattribute) normalizes to the same value. An undefinedvar()falls back to inherit/initial in the browser and cannot hide content on its own, so resolving to the one value the document ever gives it is either exact or conservative. It never turns hidden evidence into a coverage pass, which keeps the invariant stated in the_css_hidden_filtersdocstring.Validation
python3 scripts/tests/test_build.py: Passed: 290 | Skipped: 0 | Failed: 0 (284 before this change; the new test adds 6 checks)python3 scripts/build.py --checkpython3 scripts/build_metadata.py --checkbash scripts/package-skill.sh dist/kami.zip: package audit passed (466,097 bytes)python3 scripts/build.py --check-content <letter content> assets/templates/letter-en.htmlmoves from "coverage is indeterminate" (exit 2) to reporting the unfilled placeholders as definitely missing (exit 1), which shows the checker now reads the template textlong-doc.html,portfolio.html,slides-weasy.html) still report the SVG<text>labels as indeterminate; that is the existing rule in_svg_position_stateand is untouched here