Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 55 additions & 2 deletions .github/workflows/consolidation-gates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ jobs:
pnpm install --frozen-lockfile
pnpm -C packages/grida-reftest exec playwright install --with-deps chromium

- name: Verify assertion contracts and the actual n0 CLI pilot
- name: Verify assertion contracts and the actual n0 CLI suites
# The registry crate uses its packaged VCS identity for binary downloads.
# FORCE_SKIA_BINARIES_DOWNLOAD selects an upstream-checkout test path
# which instead builds Skia from source when no Git checkout exists.
Expand All @@ -197,7 +197,10 @@ jobs:
pnpm -C packages/grida-reftest exec vitest run svg-assertions --passWithNoTests=false
pnpm -C packages/grida-reftest exec tsx svg-assertions/cli.ts \
--manifest "$GITHUB_WORKSPACE/packages/grida-reftest/svg-assertions/pilot.json" \
--out "$RUNNER_TEMP/$SVG_ASSERTION_DIR"
--out "$RUNNER_TEMP/$SVG_ASSERTION_DIR" --obligation engine
pnpm -C packages/grida-reftest exec tsx svg-assertions/cli.ts \
--manifest "$GITHUB_WORKSPACE/packages/grida-reftest/svg-assertions/opacity-source.json" \
--out "$RUNNER_TEMP/$SVG_ASSERTION_DIR/opacity-source" --obligation engine

- name: Upload SVG assertion observations
if: always()
Expand All @@ -208,6 +211,53 @@ jobs:
if-no-files-found: warn
retention-days: 7

svg_reference:
# macos-26 provisions a candidate; the manifest's exact runtime identity
# decides whether it is the reference environment. Drift fails closed.
# Linux still must match these SAME immutable references independently.
name: SVG canonical reference
needs: scope
if: needs.scope.outputs.engine == 'true'
runs-on: macos-26
timeout-minutes: 40
steps:
- uses: actions/checkout@v4
with:
lfs: true
ref: ${{ needs.scope.outputs.head }}
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: 1.92.0
- uses: Swatinem/rust-cache@v2
with:
shared-key: svg-arm-capture
cache-on-failure: true
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: pnpm
- name: Install capture and build dependencies
run: |
brew install ninja
pnpm install --frozen-lockfile
pnpm -C packages/grida-reftest exec playwright install chromium
- name: Require canonical reproduction and ARM engine pixels
run: |
pnpm -C packages/grida-reftest exec tsx svg-assertions/cli.ts \
--manifest "$GITHUB_WORKSPACE/packages/grida-reftest/svg-assertions/pilot.json" \
--out "$RUNNER_TEMP/svg-arm-capture"
pnpm -C packages/grida-reftest exec tsx svg-assertions/cli.ts \
--manifest "$GITHUB_WORKSPACE/packages/grida-reftest/svg-assertions/opacity-source.json" \
--out "$RUNNER_TEMP/svg-arm-capture/opacity-source"
- uses: actions/upload-artifact@v4
if: always()
with:
name: svg-arm-capture-${{ github.run_id }}-${{ github.run_attempt }}
path: ${{ runner.temp }}/svg-arm-capture
if-no-files-found: error
retention-days: 14

legacy_pixel_sweep:
name: legacy pixel sweep
needs: scope
Expand Down Expand Up @@ -437,6 +487,7 @@ jobs:
- scope
- lock_additions_only
- seam_architecture
- svg_reference
- legacy_pixel_sweep
- n0_gate
- scoreboard_shape
Expand All @@ -448,6 +499,7 @@ jobs:
ENGINE_SCOPE: ${{ needs.scope.outputs.engine }}
LOCK_RESULT: ${{ needs.lock_additions_only.result }}
SEAM_RESULT: ${{ needs.seam_architecture.result }}
REFERENCE_RESULT: ${{ needs.svg_reference.result }}
PIXEL_RESULT: ${{ needs.legacy_pixel_sweep.result }}
N0_RESULT: ${{ needs.n0_gate.result }}
SCOREBOARD_RESULT: ${{ needs.scoreboard_shape.result }}
Expand All @@ -457,6 +509,7 @@ jobs:
fi
if [[ "$ENGINE_SCOPE" == true ]] && \
[[ "$SEAM_RESULT" != success || \
"$REFERENCE_RESULT" != success || \
"$PIXEL_RESULT" != success || \
"$N0_RESULT" != success || \
"$SCOREBOARD_RESULT" != success ]]; then
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/test-crates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,14 @@ jobs:
- name: Run cargo tests
env:
FORCE_SKIA_BINARIES_DOWNLOAD: "1"
N0_REFTEST_ARTIFACTS: ${{ runner.temp }}/n0-reftest-${{ github.run_id }}-${{ github.run_attempt }}
run: cargo test --workspace --exclude grida-canvas-wasm

- name: Preserve exact-reference failure diagnostics
if: always()
uses: actions/upload-artifact@v4
with:
name: n0-reftest-failures-${{ github.run_id }}-${{ github.run_attempt }}
path: ${{ runner.temp }}/n0-reftest-${{ github.run_id }}-${{ github.run_attempt }}
if-no-files-found: ignore
retention-days: 14
14 changes: 13 additions & 1 deletion crates/n0/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,19 @@ still apply, including to zero-sized paintless rectangles. This exemption does
not admit mapped or nonrectangular paintless geometry; every painted rectangle,
including a stroke-only rectangle, must still be enclosed. The glyphless module
tests pin these rules and byte-identical changed-view replay.
Ordinary undeclared scopes keep their existing profile.
`ScopeOpacityGroup` can carry the same checked `IsolatedSourceDomain` fact
without attaching an enclosure to the reusable numeric opacity factor.
Its glyphless profile additionally accepts co-mapped rectangles and ellipses,
including radial and repeating paints, with simple local strokes. A declared
opacity source rejects under-enclosure, independently mapped contributors,
paths, complex strokes, nested effects, enclosing filter/mask programs and
repeating-program placement with an owner-bearing error. Completed groups may
still sit inside ordinary opacity or geometric clipping. Both native opacity
restoration and the byte-255 Normal promotion consume the declaration;
neither widens geometry or reuses a previous source image.
`tests/opacity_source_domain.rs` independently tests this contract, changed-view
replay and rejection before destination mutation. These are consumer laws, not
browser pixel assertions. Ordinary undeclared scopes keep their existing profile.
The declaration targets the containing stream, independently of a scope item's
drawing map. Current-view mapping and device enclosure are recalculated for
every execution. Unsupported device bounds return an owner-bearing
Expand Down
1 change: 1 addition & 0 deletions crates/n0/src/drawlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,7 @@ pub enum ItemKind {
/// meaning and not a flag.
BeginIsolatedOpacity {
opacity: f32,
source_domain: Option<rframe::IsolatedSourceDomain>,
},
/// The resolved group's children start against transparent black. Blend
/// and opacity apply together when that completed source joins the
Expand Down
Loading
Loading