Skip to content

websem: repair ordinary-opacity source precision - #142

Draft
softmarshmallow wants to merge 1 commit into
mainfrom
rung/svg-opacity-precision
Draft

websem: repair ordinary-opacity source precision#142
softmarshmallow wants to merge 1 commit into
mainfrom
rung/svg-opacity-precision

Conversation

@softmarshmallow

@softmarshmallow softmarshmallow commented Sep 12, 2026

Copy link
Copy Markdown
Member

Landing paused; draft and unmerged. Hosted fresh Chromium disagrees with
the committed macOS reference in three .999 cases, although both n0 builds
match the baked pixels. See the independently verified CI verdict.
Local verification below remains valid for its declared environment, not a
claim of all-CI-green or environment-invariant Chromium output. No golden,
tolerance, required case, capture module or runner-platform change was made
to suppress the disagreement.

Summary

Repair the retained ordinary-opacity precision cases in #136,
and quarantine additional source combinations exposed by the investigation.
Keep that issue open for the remaining source-composition profiles.

The cause spans two layers:

  • Active source-dependent Gaussian blur was missing completed source
    materialization. It now uses the existing one-per-source preparation policy;
    zero, generated-input and unreachable blur branches do not activate it.
  • Ordinary opacity around bare paint-server draws lacked the complete local
    source enclosure. rframe now carries this checked fact separately from the
    numeric factor; both near-unit opacity restoration routes consume it.

An independent contract maintainer designed the rframe boundary before
producer and consumer adaptation. The enclosure is drawable source, not
geometry, damage, visible ink, a viewport or an allocation hint. Existing
blend-domain compatibility names remain available. Solid/neutral spans avoid
the new enclosure walk; changed-view reuse remains byte-identical to fresh.

Measured verdict

Baseline actual-CLI renders repeated in both admissions reproduced the issue:

Source Opacity .999: differing pixels / max delta Opacity .998: differing pixels / max delta
Native circle into blur 25 / 3 25 / 2
Repeating-pattern circle plus sibling 1 / 1 1 / 1
Rotated radial circle plus sibling 1,312 / 1 1,307 / 1

The reduced committed cases now match their own Chromium images exactly.
The no-opacity blur control also moves from 30 differing pixels at delta 1 to
exact. Native-circle and arc-path blur controls each retain their own oracle:
Chromium distinguishes their geometry, so substituting a path was not a fix.

36 new positive cells bring the primitive corpus to 1,575. Seventeen new
named-refusal witnesses bring the register to 368. The 16 sampled frames,
16 exact text cells and eight geometry witnesses are unchanged. The filter
estate is 459 cells, including six new blur controls. All previous 1,539
primitive records and oracle bytes are unchanged. New cells entered only via
just add; just bake created missing oracles without overwriting.

Boundaries and checklist disposition

Both opacity checklist rows reopen. The repaired source profile does not
cover all honored path, nested, resource-program or image-effect combinations.
Incomplete contributors, independently mapped children, shear/unequal scale,
complex strokes and unsupported source placement now refuse by stable name.
Root/host failures refuse at document level in both admissions; attributable
clients roll back as whole transactions in best effort.

The investigation also exposed bare multi-operation paint-server sources
feeding filters/masks without partial opacity. Those refuse separately by
name; completed child images are not reclassified as bare sources. Unequal-
scale controls also differ without opacity, so this does not claim to solve
#88. The radial element retains its tick under the now-open
opacity own-row precedent. No checklist row gains a tick.

The durable addendum distinguishes probe-only findings from committed cells.
No tolerance, existing oracle, pinned capture module, FLIP rule, CSS matcher
or conformance measure changes. Generic damage/geometry coverage, external
I/O, text and new filter vocabulary remain separate.

Assertion harness and sensitivity

The new opacity-source.json manifest contains six described render-exact
claims and two expected refusals. CI runs fresh Chromium and the actual CLI
alongside the unchanged three-case pilot, and retains its report in the
artifact's opacity-source subdirectory. It is not a second oracle or a score.

Three deliberately introduced regressions prove the gate is sensitive:

  1. Disabling blur preparation fails four new fixture cells and both blur
    assertions.
  2. Bypassing the source declaration in the initial 31-cell set fails nineteen
    cells, including the one-pixel pattern examples. The assertion gate fails
    all four pattern/radial claims and both expected-refusal claims.
  3. Disabling only zero-area source exclusion fails all five added disabled-box
    cells by 315 pixels at maximum delta 1 each.

Every mutation was restored byte-for-byte before re-gating green.

Independent review and verification

No Workflow runner was exposed, so .agents/workflows/verify-rung.js could not
be invoked through scriptPath. Independent manual TICK/LAW and REPRO roles
are the fallback; this is not a claim that the saved Workflow ran.

TICK/LAW identified zero-area retained Rect/Ellipse nodes incorrectly enlarging
the source enclosure and a radial-control delta typo. Both are fixed. Geometry
and node identity remain intact; empty box coverage does not fabricate source
area. Five additional cells and producer/consumer tests guard the fix. The
renewed TICK/LAW audit passes with no remaining must-fix or should-fix items.

Local verification passes:

  • Full tests for cg, math2, csscascade, rframe, websem, n0-model,
    n0, n0_cli, animation-sampling and textlayout; after the audit fix,
    renewed full websem/n0_cli, n0 library/group/domain and trace tests.
  • cargo fmt --all --check and workspace cargo clippy --locked --no-deps -- -D warnings.
  • Complete fixture bake, gate and STATUS; 40 assertion-tool contract tests
    and typechecks; link checks and pre-PR public-repository audit.

Independent REPRO also passes with no remaining must-fix or should-fix items:
six fresh matrices, 95 sources and 380 actual CLI executions with stable
repeats and a fixed binary. It verified all new source/oracle identities,
expected refusal names and complete owner rollback, then renewed the full
gate and STATUS. All eight corrected assertions and the original three-case
pilot pass with empty integrity-error lists. It also rechecked the retained
mutation reports and exact restoration hashes without re-enacting mutations.
The known no-opacity unequal-scale control remains outside the claimed repair.

Carry complete isolated source domains across rframe, prepare active blur sources once, and quarantine unrepresented composition profiles. Reopen both opacity checklist rows; retain the radial element own-row precedent. Add 36 immutable Chromium cells, 17 named refusal witnesses and actual-CLI assertions. Independent manual TICK/LAW and REPRO pass; no Workflow runner was exposed.
@vercel

vercel Bot commented Sep 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
nothing Ready Ready Preview Sep 12, 2026 7:16pm UTC

Request Review

@coderabbitai

coderabbitai Bot commented Sep 12, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 4cf0a672-eb55-43f2-94dd-107119d89e90

📥 Commits

Reviewing files that changed from the base of the PR and between 549ece6 and c62e7f1.

⛔ Files ignored due to path filters (85)
  • fixtures/web-first/chromium/html-opacity-source-host-high.png is excluded by !**/*.png
  • fixtures/web-first/chromium/html-opacity-source-host-low.png is excluded by !**/*.png
  • fixtures/web-first/chromium/html-opacity-source-root-high.png is excluded by !**/*.png
  • fixtures/web-first/chromium/html-opacity-source-root-low.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-blur-absent.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-blur-arc.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-blur-high.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-blur-low.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-blur-srgb.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-blur-zero.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-disabled-ellipse-height.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-disabled-ellipse-width.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-disabled-rect-height.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-disabled-rect-width.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-disabled-rect.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-enclosing-clip.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-leaf-stroke.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-linear-simple.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-pattern-absent.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-pattern-fractional.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-pattern-high.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-pattern-low.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-pattern-mirror.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-pattern-stroke.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-pattern-translated.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-radial-absent.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-radial-fractional.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-radial-high.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-radial-low.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-radial-mirror.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-radial-simple.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-radial-stroke.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-radial-translated.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-radial-uniform.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-root-transparent.png is excluded by !**/*.png
  • fixtures/web-first/chromium/svg-opacity-source-use.png is excluded by !**/*.png
  • fixtures/web-first/svg-opacity-source-blur-absent.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-blur-arc.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-blur-high.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-blur-low.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-blur-srgb.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-blur-zero.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-disabled-ellipse-height.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-disabled-ellipse-width.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-disabled-rect-height.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-disabled-rect-width.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-disabled-rect.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-enclosing-clip.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-leaf-stroke.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-linear-simple.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-pattern-absent.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-pattern-fractional.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-pattern-high.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-pattern-low.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-pattern-mirror.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-pattern-stroke.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-pattern-translated.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-radial-absent.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-radial-fractional.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-radial-high.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-radial-low.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-radial-mirror.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-radial-simple.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-radial-stroke.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-radial-translated.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-radial-uniform.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-root-transparent.svg is excluded by !**/*.svg
  • fixtures/web-first/svg-opacity-source-use.svg is excluded by !**/*.svg
  • fixtures/web-first/unsupported/svg-opacity-source-child-transform.svg is excluded by !**/*.svg
  • fixtures/web-first/unsupported/svg-opacity-source-clipped-contributor.svg is excluded by !**/*.svg
  • fixtures/web-first/unsupported/svg-opacity-source-complex-stroke.svg is excluded by !**/*.svg
  • fixtures/web-first/unsupported/svg-opacity-source-enclosing-filter.svg is excluded by !**/*.svg
  • fixtures/web-first/unsupported/svg-opacity-source-enclosing-mask.svg is excluded by !**/*.svg
  • fixtures/web-first/unsupported/svg-opacity-source-marker-client.svg is excluded by !**/*.svg
  • fixtures/web-first/unsupported/svg-opacity-source-mask-program.svg is excluded by !**/*.svg
  • fixtures/web-first/unsupported/svg-opacity-source-nested-contributor.svg is excluded by !**/*.svg
  • fixtures/web-first/unsupported/svg-opacity-source-omitted-stroke.svg is excluded by !**/*.svg
  • fixtures/web-first/unsupported/svg-opacity-source-path.svg is excluded by !**/*.svg
  • fixtures/web-first/unsupported/svg-opacity-source-pattern-program.svg is excluded by !**/*.svg
  • fixtures/web-first/unsupported/svg-opacity-source-root-path.svg is excluded by !**/*.svg
  • fixtures/web-first/unsupported/svg-opacity-source-shear.svg is excluded by !**/*.svg
  • fixtures/web-first/unsupported/svg-opacity-source-transparent-contributor.svg is excluded by !**/*.svg
  • fixtures/web-first/unsupported/svg-opacity-source-unequal-scale.svg is excluded by !**/*.svg
  • fixtures/web-first/unsupported/svg-paint-server-source-filter.svg is excluded by !**/*.svg
  • fixtures/web-first/unsupported/svg-paint-server-source-mask.svg is excluded by !**/*.svg
📒 Files selected for processing (34)
  • .github/workflows/consolidation-gates.yml
  • crates/n0/README.md
  • crates/n0/src/drawlist.rs
  • crates/n0/src/glyphless.rs
  • crates/n0/src/paint.rs
  • crates/n0/tests/group_blending.rs
  • crates/n0/tests/opacity_source_domain.rs
  • crates/n0_cli/README.md
  • crates/rframe/README.md
  • crates/rframe/src/lib.rs
  • crates/rframe/src/scope.rs
  • crates/rframe/tests/blend_contract.rs
  • crates/rframe/tests/mask_contract.rs
  • crates/rframe/tests/opacity_source_domain.rs
  • crates/rframe/tests/scope_stream.rs
  • crates/websem/src/svg.rs
  • crates/websem/tests/opacity_contract.rs
  • crates/websem/tests/opacity_source_domain.rs
  • crates/websem/tests/paint_order_contract.rs
  • crates/websem/tests/unsupported_corpus.rs
  • docs/wg/consolidation/svg-engine-of-record.md
  • docs/wg/consolidation/web-checklist.md
  • fixtures/web-first/README.md
  • fixtures/web-first/STATUS.md
  • fixtures/web-first/html-opacity-source-host-high.html
  • fixtures/web-first/html-opacity-source-host-low.html
  • fixtures/web-first/html-opacity-source-root-high.html
  • fixtures/web-first/html-opacity-source-root-low.html
  • fixtures/web-first/justfile
  • fixtures/web-first/oracle-bake.json
  • fixtures/web-first/primitives.json
  • fixtures/web-first/unsupported/README.md
  • packages/grida-reftest/svg-assertions/README.md
  • packages/grida-reftest/svg-assertions/opacity-source.json

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


Walkthrough

The change adds isolated opacity source domains across rframe, SVG compilation, n0 execution, regression fixtures, and CI assertion gates. It also adds validation, refusal handling, rendering tests, and compatibility aliases.

Changes

Opacity source-domain pipeline

Layer / File(s) Summary
Public opacity-group contract
crates/rframe/src/scope.rs, crates/rframe/src/lib.rs, crates/rframe/tests/*, crates/rframe/README.md
ScopeOpacityGroup now carries an optional IsolatedSourceDomain. The former blend-domain types remain available as aliases.
SVG source enclosure compilation
crates/websem/src/svg.rs, crates/websem/tests/*
SVG compilation tracks source completeness, computes drawable enclosures for supported paint-server sources, attaches domains to opacity scopes, and records refusals for unsupported contributors.
n0 source-domain execution
crates/n0/src/drawlist.rs, crates/n0/src/glyphless.rs, crates/n0/src/paint.rs, crates/n0/tests/*
n0 carries domains into private opacity items, validates source nodes, clips isolated layers to mapped domain bounds, restores the clip, and tests replay, mutation ordering, and rejection behavior.
Fixtures and assertion gates
fixtures/web-first/*, packages/grida-reftest/svg-assertions/*, .github/workflows/consolidation-gates.yml, docs/wg/consolidation/*
The change adds opacity-source fixtures, oracle entries, refusal records, six render assertions, two refusal assertions, documentation updates, and a CI gate invocation.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~60 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant SVGCompiler
  participant RFrame
  participant N0
  participant AssertionCLI
  SVGCompiler->>SVGCompiler: compute drawable source enclosure
  SVGCompiler->>RFrame: attach IsolatedSourceDomain
  RFrame->>N0: emit opacity scope with source domain
  N0->>N0: validate and clip mapped source bounds
  N0->>AssertionCLI: produce render or refusal result
Loading

Merge Risk: ⚪ Minimal · up to c62e7

No actionable regression remains in the reviewed opacity source-domain changes.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 65.71% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 70 functions across 15 files. (19 skipped… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely summarizes the main change: repairing ordinary-opacity source precision in websem.
Description check ✅ Passed The description is directly related to the changeset. It explains the source-materialization fix, source-domain API changes, refusal boundaries, test coverage, and verification results.
Full details: Docstring Coverage

Explanation

Docstring coverage is 65.71% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 70 functions across 15 files. (19 skipped: 18 unsupported, 1 too large.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rung/svg-opacity-precision

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copy link
Copy Markdown
Member Author

Landing paused: the Chromium reference is not environment-invariant

PR remains draft and unmerged at c62e7f1b. The local repair and independent macOS/arm64 reproduction pass, but the new Linux/x64 CI assertion run exposes a repeat-stable disagreement between Chromium environments. Per the standing instruction to stop on a contradicted premise, no renderer, capture, golden, tolerance, required case or runner-platform change has been made to turn this failure green.

Both runs identify Chromium 149.0.7827.55, the unchanged sole capture module SHA-256 069296201718c43d29efe356fbea893781b73250dca51de3b6d47468d74027b0, and the same source/manifest/tool bytes.

Group opacity .999 Linux Chromium vs committed macOS Chromium
Blur 1,926 differing pixels, maximum channel delta 1
Pattern 217 differing pixels, maximum channel delta 1
Radial gradient 1,168 differing pixels, maximum channel delta 1

For all six rendering cases, Linux n0, local n0 and the committed baked pixels agree exactly. All three .998 cases also agree across Chromium. Repeats are stable and both report integrity lists are empty. Therefore this is not an engine-output regression in these cases, but n0 does not match the observed Linux Chromium output for the high-opacity cases.

Independent artifact review re-decoded the PNGs and checked 96 recorded PNG/RGBA identities plus source/tool identities. It confirmed the split. The shear refusal's Chromium observations also differ by 1,192 pixels at delta 1; its exact named-refusal assertion still passes. The Linux observations are measured, not celled.

This establishes an environment association, not its cause: OS, CPU architecture, browser build/backend or another setting has not been isolated. Selecting whichever image agrees with n0 is not permitted by #140. A canonical reference environment must be explicitly investigated and reviewed before resuming this expansion; a version string alone is insufficient evidence of identical raster behavior.

Failed assertion job · original report and images

The original three-case pilot and all 40 tool-contract tests passed in that job. Automated review generated no actionable code comments. Other CI jobs may still finish independently; no all-CI-green or merge is claimed. The branch is clean and pushed; main remains 549ece62.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant