Skip to content

Config paths Phase 1b: store marked paths in project-root pivot form (bd-okqrjh8v) - #956

Merged
cscheid merged 2 commits into
mainfrom
feature/bd-okqrjh8v-config-paths-phase-1b
Oct 28, 2026
Merged

cscheid merged 2 commits into
mainfrom
feature/bd-okqrjh8v-config-paths-phase-1b

Conversation

@cscheid

@cscheid cscheid commented Oct 28, 2026 •

Copy link
Copy Markdown
Member

Follows #955 (merged). Braid: bd-okqrjh8v. Plan: claude-notes/plans/2026-10-28-config-path-late-binding.md, §4.6 and Phase 1b.

What

Every marked config path (ConfigValueKind::Path) is now stored in pivot form (config_paths::pivot_form): the path relative to the project root with forward slashes, or absolute for a file outside the project. Before, the merge rebased each value to the consuming document's directory, so one declaration had a different spelling on every page: the SCSS cache-key misses of bd-79c4do6g, the .. chains of bd-s0jupmmv, a different q2 get-config answer per document, and a Lua-visible value that varied by page.

  • mark_format_path_values and adjust_paths_to_project_root (renamed from adjust_paths_to_document_dir) write the pivot, normalized lexically on every platform. The inherited platform fork ("keep .. off Windows for symlinks, collapse on Windows for MAX_PATH") is gone: the resolver normalizes at use anyway, pivot form has no long chains, and the fork gave the pivot a per-OS spelling. The symlink caveat is one documented sentence on pivot_form.
  • !path /x anchors at the project root, and adjust_paths_recursive classifies URLs with is_external_url instead of an http/https prefix list (two mechanism-2 defects from the sweep).
  • A front-matter !path is rewritten at the merge like every other layer, so no marked value is document-relative any more; resolve_config_path joins a relative marked value onto the project root.
  • The two consumers below quarto-core follow: ThemeContext is built on the project root (HTML and reveal), and pampa's citeproc base is the project root (the book single-file merge included).
  • FormatCssTransform: when a render is served from the source tree (no resource resolver, or VFS-root mode in the browser preview) the template emits the css entry verbatim as <link href>, which only worked while the stored form was document-relative. It now relativizes each marked entry to the page (the WASM smoke-all run of metadata/dir-metadata-paths caught this).
  • Docs: docs/guides/authoring/lua-filters.qmd notes that path-shaped keys reach filters project-root-relative, unlike Quarto 1's input-relative form, and points at quarto.project.directory.

Spelling decision (differs from the plan text)

The plan's §4.6 described the pivot with a leading /. The stored form here has no leading slash: a marked /x would be ambiguous on Unix with the OS-absolute form used for files outside the project (a built-in extension extracted to a temp dir), and the resolver cannot tell those apart without probing the filesystem. The value's kind already says "resolved", so consumers gain nothing from the slash; for Lua the rule is documented instead. The leading-/ spelling still applies to the unmarked, extension-rebased website.* strings (bd-0x1znhgb), where the string itself has to be self-describing.

Behaviour changes

  • Lua filters (accepted behaviour change, documented): a marked key such as include-in-header, css, bibliography or theme reads as assets/hdr.html on every page, not ../assets/hdr.html on a subdirectory page. New test lua_sees_marked_paths_in_project_root_form pins this.
  • An unmarked bibliography/csl (file missing at merge time) declared in a subdirectory document's front matter is now reported relative to the project root rather than the document; the file is missing either way.
  • No change to rendered output: css hrefs, copies and includes are derived from the resolved file, which is the same file as before (the smoke-all dir-metadata-paths golden still asserts ../../shared/styles.css in the page's link).

Tests

  • Unit expectations in format_paths, project::tests (adjust paths, directory metadata), config_paths, filter_resolve moved from document-relative to pivot strings; pivot_form unit test; metadata_merge test helper simplified.
  • tests/integration/config_path_consumers.rs::lua_sees_marked_paths_in_project_root_form.

Verification

  • cargo xtask verify --skip-hub-build: green, with the WASM artifact rebuilt first so the hub-client WASM suite (462 tests, smoke-all and pandoc-request goldens included) ran against this change; 17,476 Rust tests; hub-client unit 1,741 and integration 229.
  • cargo clippy -p quarto-core -p quarto-sass -p pampa --all-targets -- -D warnings: clean.
  • Windows cross-check of quarto-core is not possible from macOS (C build scripts). No platform-conditional code remains in the pivot path.

🤖 Generated with Claude Code

Every ConfigValueKind::Path value now holds the pivot form
(config_paths::pivot_form): the path relative to the project root with
forward slashes, or absolute for a file outside the project. Before,
mark_format_path_values and adjust_paths_to_document_dir rebased each
value to the consuming document's directory, so the same declaration
had a different spelling on every page (the SCSS cache-key misses of
bd-79c4do6g, the '..' chains of bd-s0jupmmv, a different get-config
answer per document, and a Lua-visible form that varied by page).

- mark_entry and adjust_paths_to_project_root (renamed) write the
  pivot; a leading / on an authored !path anchors at the project root
  and URLs are classified by is_external_url instead of a prefix list.
- resolve_config_path joins a relative marked value onto the project
  root; a front-matter !path is rewritten at the merge like every
  other layer, so no marked value is document-relative any more.
- The two below-quarto-core consumers follow: ThemeContext is built on
  the project root (HTML and reveal), and pampa's citeproc base is the
  project root (books included).
- Docs: the Lua filter guide notes that path-shaped keys reach filters
  project-root-relative, unlike Quarto 1's input-relative form.
- New test pins the Lua-visible form across pages; unit expectations
  updated from document-relative to pivot strings.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@posit-snyk-bot

posit-snyk-bot commented Oct 28, 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.

…view)

The platform fork inherited from adjust_paths_to_document_dir (keep '..'
off Windows for symlink faithfulness, collapse it on Windows for
MAX_PATH) gave the pivot a per-OS spelling, which is what the pivot was
meant to remove, and bought nothing: resolve_config_path normalizes
lexically at use anyway, and pivot form has no long '..' chains. Store
the normalized project-relative form everywhere; the symlink caveat is
documented on pivot_form. Removes every cfg!(windows) from the pivot
path and its tests.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@cscheid
cscheid merged commit 62601b9 into main Oct 28, 2026
17 checks passed
@cscheid
cscheid deleted the feature/bd-okqrjh8v-config-paths-phase-1b branch October 28, 2026 19:53
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