Skip to content

Theme compile failures are structured hard errors, not silent DEFAULT_CSS (bd-jsvetdea) - #661

Merged
cscheid merged 4 commits into
mainfrom
feature/bd-jsvetdea-theme-compile-error
Sep 8, 2026
Merged

Theme compile failures are structured hard errors, not silent DEFAULT_CSS (bd-jsvetdea)#661
cscheid merged 4 commits into
mainfrom
feature/bd-jsvetdea-theme-compile-error

Conversation

@cscheid

@cscheid cscheid commented Sep 8, 2026

Copy link
Copy Markdown
Member

Summary

A grass failure while compiling the theme bundle used to be caught in variant_css, logged as a Warn trace event (which no CLI observer receives), and replaced by the static 7 KB DEFAULT_CSS. The render reported success. A one-line unit mistake in a user theme ($grid-body-width: 52rem) silently shipped an unstyled page.

Every theme compile failure is now a PipelineError::Structured through theme_diagnostic:

  • Q-14-6 "Theme SCSS compilation failed": the grass / dart-sass text verbatim, anchored at the whole theme: value (the compiler only knows lines of the assembled bundle), with a hint saying so. Applies to the themed path, the no-user-input default bundle, and the reveal path (which used to fall back to the vendored stock theme).
  • Q-14-7 "Theme file has no layer boundary markers": InvalidScssFile, anchored at the offending theme: entry when its resolved path matches one, else at the whole value.

Plumbing: the three compile wrappers keep SassError instead of stringifying it; InvalidScssFile gains a location field; theme_diagnostic gains sass_error_to_parse_error_at(err, fallback_location, candidates). Because the anchor is a _quarto.yml span, the render summary's source-location coalescing prints one report per project with an "Affected files" tail.

Closes bd-jsvetdea and bd-qmpygp02; resolves bd-36vmz7nk (decision: fatal). Follow-ups filed: bd-c1gf9xmk (layer provenance so Q-14-6 can name theme.scss:2), bd-e1psgogt (audit remaining Warn trace sites; -v filter never matches quarto_core).

Plan: claude-notes/plans/2026-09-08-theme-scss-compile-error-swallowed.md.

Verification

  • Unit, diagnostic, and CLI e2e tests written first and observed failing on the old tree (exit 0 / Ok(DEFAULT_CSS) / no code).
  • cargo nextest run --workspace: 13753 passed. Clippy and cargo xtask lint clean. hub-client npm run build:all (WASM leg) succeeds.
  • End to end on the repro fixture (claude-notes/plans/theme-scss-compile-error-swallowed-investigation/repro/):
$ cargo run --bin q2 -- render <repro>
error: while rendering …/repro/index.qmd
Error: [Q-14-6] Theme SCSS compilation failed
   ╭─[ …/repro/_quarto.yml:5:12 ]
 5 │     theme: [cosmo, theme.scss]
   │            ─────────┬─────────
   │                     ╰─────────── compiling the theme SCSS bundle failed:
Error: Incompatible units px and rem.
3269 │ $grid-body-column-min: quarto-math.min(500px, $grid-body-column-max) !default;
./stdin:3269:24
ℹ Does a variable in a theme file set a value Bootstrap's arithmetic cannot use (…)? …
Rendered 0 of 1 files … — 1 error

A two-page site prints the block once, followed by Affected files: …/about.qmd, …/index.qmd.

  • docs/ renders 271/271 pages with no Q-14-6 (nothing previously masked turns red).

Note: the hub-client vitest leg of cargo xtask verify is red locally under Node 26 (localStorage undefined), unrelated to this change — filed as bd-lh30hlvd.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Xwth8pr6ewSbExXRBNpQWY

cscheid and others added 2 commits September 8, 2026 11:54
Plan skeleton + repro fixture. The Err arm in variant_css ships
DEFAULT_CSS on any grass failure; the Warn trace event goes to a
NoopObserver, so nothing reaches the CLI at any verbosity. grass points
at a Quarto-internal line of the assembled bundle, not the user's file.
Hub-client vitest leg of pre-flight verify is red under Node 26
(localStorage undefined) — filed as bd-lh30hlvd.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xwth8pr6ewSbExXRBNpQWY
…_CSS (bd-jsvetdea, bd-qmpygp02)

A grass failure while compiling the theme bundle used to be caught in
variant_css, logged as a Warn trace event (which no CLI observer
receives), and replaced by the static 7 KB DEFAULT_CSS; the render
reported success. A one-line unit mistake in a user theme
($grid-body-width: 52rem) silently shipped an unstyled page.

Every compile failure is now a PipelineError::Structured through
theme_diagnostic:

- Q-14-6 "Theme SCSS compilation failed": the grass / dart-sass text
  verbatim, anchored at the whole `theme:` value (the compiler only
  knows lines of the assembled bundle), with a hint saying so. Applies
  to the themed path, the no-user-input default bundle, and the reveal
  path (which fell back to the vendored stock theme).
- Q-14-7 "Theme file has no layer boundary markers": InvalidScssFile,
  anchored at the offending `theme:` entry when its resolved path
  matches one, else at the whole value.

The three wrappers keep SassError instead of stringifying it;
InvalidScssFile gains a location field; theme_diagnostic gains
sass_error_to_parse_error_at(err, fallback_location, candidates).
Because the anchor is a _quarto.yml span, the render summary's
source-location coalescing prints one report per project with an
"Affected files" tail.

Resolves bd-36vmz7nk (decision: fatal). Catalog entries, docs pages,
and sidebar entries added; unit, diagnostic, and CLI e2e tests written
first and verified failing on the old behavior.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xwth8pr6ewSbExXRBNpQWY
@posit-snyk-bot

posit-snyk-bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

cscheid and others added 2 commits September 8, 2026 14:35
… (bd-jsvetdea)

Four *.wasm.test.ts files load the WASM module by hand and render
without calling setVfsCallbacks, so dart-sass cannot resolve the
Bootstrap bundle's `@import "vendor/rfs"`. The theme stage used to mask
that by silently shipping DEFAULT_CSS, and the tests only inspected
HTML, so they passed against an unstyled page. Now that a default-bundle
compile failure is a Q-14-6 hard error, 20 tests failed in CI.

Add src/test-utils/wasmSassVfs.ts (wireSassVfs) mirroring the
production wiring in preview-runtime's wasmRenderer.ts, and call it
from each file's beforeAll. npm run test:wasm: 133/133.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xwth8pr6ewSbExXRBNpQWY
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xwth8pr6ewSbExXRBNpQWY
@cscheid

cscheid commented Sep 8, 2026

Copy link
Copy Markdown
Member Author

CI finding on the first run: 20 hub-client WASM tests failed with Q-14-6 ("Can't find stylesheet to import vendor/rfs"). Four *.wasm.test.ts files load the WASM module by hand and render without calling setVfsCallbacks, so dart-sass could never resolve the Bootstrap bundle's imports. The old DEFAULT_CSS fallback masked that, and the tests only inspected HTML, so they passed against an unstyled page. This is the "surfacing currently-masked failures" risk from bd-36vmz7nk, realised in the test suite.

Fixed in c0a6230: a shared hub-client/src/test-utils/wasmSassVfs.ts (wireSassVfs) mirroring the production wiring in preview-runtime's wasmRenderer.ts, called from each file's beforeAll. npm run test:wasm is 133/133 locally.

@cscheid
cscheid merged commit f56af6c into main Sep 8, 2026
10 checks passed
@cscheid
cscheid deleted the feature/bd-jsvetdea-theme-compile-error branch September 8, 2026 20:14
cscheid added a commit that referenced this pull request Sep 8, 2026
Resolves the expected overlap with the theme-compile-error work:
theme_diagnostic keeps both the Q-14-7 (InvalidScssFile) and Q-14-8
(InvalidBrandFontWeight) arms and the Q-14-6 catch-all replaces this
branch's old code-less fallback; SassError::with_location and
sass_error_location cover both new variants; the errors sidebar lists
Q-14-6, Q-14-7, Q-14-8 in code order. The brand-file bind candidate and
main's fallback_location coexist in sass_error_to_parse_error_at.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NE1UEmUUagZwZ5APMZYfra
cscheid added a commit that referenced this pull request Sep 9, 2026
…bering

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CoQm2W4rtvPQNDtkYKdb6D
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.

2 participants