Skip to content

fix(quarto-citeproc): stop false CSL lockfile mismatches#380

Merged
cderv merged 2 commits into
mainfrom
fix/csl-lockfile-runtime-check
Jul 8, 2026
Merged

fix(quarto-citeproc): stop false CSL lockfile mismatches#380
cderv merged 2 commits into
mainfrom
fix/csl-lockfile-runtime-check

Conversation

@cderv

@cderv cderv commented Jul 7, 2026

Copy link
Copy Markdown
Member

When csl_validate_manifest ran after a rebase, it reported "Lockfile mismatch: tests/csl_conformance.lock" even though enabled_tests.txt and test-data/csl-suite/ were unchanged and regenerating the lockfile produced a byte-identical file.

Root Cause

Two independent bugs, both making the check flaky rather than authoritative:

  1. csl_validate_manifest was generated by build.rs, which baked an "expected" lockfile string into the compiled test binary at build-script run time and compared it against the live file at test-run time. If Cargo didn't rerun build.rs when it should have, the baked value went stale relative to disk - a time-of-check/time-of-use gap.
  2. Separately, on Windows checkouts with the common core.autocrlf=true setting, tests/csl_conformance.lock gets checked out with CRLF line endings, while the generator that produces the "expected" string always emits LF-only. The raw byte compare then fails on line endings alone, with no real content divergence - crates/quarto-citeproc had no .gitattributes pinning the file, unlike crates/pampa, which already pins its fixtures the same way.

Fix

csl_validate_manifest is now a hand-written runtime test in tests/integration/csl_conformance.rs that reads test-data/csl-suite/ and enabled_tests.txt live at test-run time via env!("CARGO_MANIFEST_DIR") - a compile-time path constant, not a baked computed value - and compares against the lockfile in the same instant. build.rs keeps only per-fixture test codegen. Duplicate/nonexistent-entry detection moves from a soft cargo:warning to a hard test failure. UPDATE_CSL_LOCKFILE=1 auto-update behavior is unchanged.

crates/quarto-citeproc/.gitattributes now pins tests/csl_conformance.lock and tests/enabled_tests.txt to eol=lf, matching the existing crates/pampa/.gitattributes convention. This overrides core.autocrlf for these two paths in both directions, so regenerating the lockfile from Windows stays safe too.

@posit-snyk-bot

posit-snyk-bot commented Jul 7, 2026

Copy link
Copy Markdown

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.

@cderv

cderv commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

Retrying, but I think those CI errors are from main too

cderv added 2 commits July 8, 2026 10:54
csl_validate_manifest was generated by build.rs, which baked an "expected"
lockfile string at build-script run time and compared it against the live
tests/csl_conformance.lock at test-run time. If Cargo ever failed to rerun
build.rs when it should have, the baked value went stale relative to disk,
producing a false "Lockfile mismatch".

Investigation ruled out both directory-rerun-if-changed theories that were
suspected as the cause: add/remove detection was confirmed to work correctly
on the cargo version this repo pins (1.97.0-nightly, well past cargo#8973),
and the baked value never depended on fixture content in the first place, so
neither theory actually explains the failure. Rather than patch a mechanism
that was never proven broken, the check now reads test-data/csl-suite/ and
enabled_tests.txt live at test-run time via env!("CARGO_MANIFEST_DIR") - a
compile-time path constant, not a baked computed value - eliminating the
time-of-check/time-of-use gap structurally instead of trying to make
rerun-if-changed perfect.

build.rs keeps only per-fixture test codegen, which this doesn't touch.
Duplicate/nonexistent-entry detection moves from a soft cargo:warning to a
hard test failure. UPDATE_CSL_LOCKFILE=1 auto-update is preserved byte-for-
byte since scripts/csl-test-helper.py depends on it in three places.

The staleness bug itself isn't regression-testable - Cargo's build-script
rerun timing can't be forced deterministically - so it's fixed architecturally
rather than by a reproducing test. Added unit tests for the extracted
comparison/formatting logic instead (red before implementation, green after).
csl_validate_manifest byte-compares tests/csl_conformance.lock against a
generated LF-only string. With core.autocrlf=true and no .gitattributes,
Windows checkouts get CRLF for that file, producing a false "Lockfile
mismatch" unrelated to any real enabled_tests.txt/fixture divergence.

Pins tests/csl_conformance.lock and tests/enabled_tests.txt to eol=lf,
same pattern crates/pampa/.gitattributes already uses for its fixtures.
eol=lf overrides core.autocrlf for these paths in both directions, so
regenerating the lockfile from Windows stays safe too.
@cderv cderv force-pushed the fix/csl-lockfile-runtime-check branch from 217f521 to 57b305e Compare July 8, 2026 08:54
@cderv cderv merged commit 9f96e2c into main Jul 8, 2026
8 checks passed
@cderv cderv deleted the fix/csl-lockfile-runtime-check branch July 8, 2026 09:18
cderv added a commit that referenced this pull request Jul 9, 2026
Finishes the checklist to match the shipped resolution (PR #380,
9f96e2c): each item checked off or annotated as superseded / not
pursued. The plan's Resolution section already landed in that commit;
this completes the checklist below it.
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