Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8733ed6
plan(bd-xvdop): experiment to consolidate integration tests per crate
cscheid May 28, 2026
1b420d6
pampa(bd-xvdop): consolidate integration tests into single binary
cscheid May 28, 2026
b32dcca
bd-xvdop: Phase 3 partial — pampa pilot measurements + controlled deb…
cscheid May 28, 2026
535f61b
bd-xvdop: Phase 3 complete — controlled release rerun lands
cscheid May 28, 2026
0ad8a40
quarto-core(bd-xvdop): consolidate 33 integration tests into single b…
cscheid May 28, 2026
0d345c7
qmd-syntax-helper(bd-xvdop): consolidate 20 integration tests into si…
cscheid May 28, 2026
86dcd0c
quarto-preview(bd-xvdop): consolidate 7 integration tests into single…
cscheid May 28, 2026
1ad8b11
quarto-sass(bd-xvdop): consolidate 7 integration tests into single bi…
cscheid May 28, 2026
91cd5b7
quarto-brand(bd-xvdop): consolidate 4 integration tests into single b…
cscheid May 28, 2026
e8a9d07
quarto-citeproc(bd-xvdop): consolidate 2 integration tests into singl…
cscheid May 28, 2026
1d03f3f
quarto-csl(bd-xvdop): consolidate 2 integration tests into single binary
cscheid May 28, 2026
136a5c8
quarto-doctemplate(bd-xvdop): consolidate 2 integration tests into si…
cscheid May 28, 2026
6651b1d
quarto(bd-xvdop): consolidate 7 integration tests into single binary
cscheid May 28, 2026
8dc679e
quarto-highlight(bd-xvdop): consolidate 6 integration tests into sing…
cscheid May 28, 2026
ce21467
quarto-yaml-validation(bd-xvdop): consolidate 5 integration tests int…
cscheid May 28, 2026
6f8b150
comrak-to-pandoc(bd-xvdop): consolidate 5 integration tests into sing…
cscheid May 28, 2026
e398979
bd-xvdop: relocate insta snapshots + update nextest filter for new la…
cscheid May 28, 2026
1592e8c
bd-xvdop: Phase 6 — full-workspace measurement lands
cscheid May 28, 2026
da44c52
bd-xvdop: document integration-test layout convention
cscheid May 28, 2026
5185b54
bd-xvdop: fix hardcoded snapshot path in userGrammarParity.wasm test
cscheid May 28, 2026
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
1 change: 1 addition & 0 deletions .beads/issues.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@
{"id":"bd-xly8b","title":"Catalog/corpus drift: markdown Q-2-X assignments diverge between error_catalog.json, pampa/resources/error-corpus/, and production-emit sites","description":"While authoring docs/errors/markdown/ pages (bd-lgxdr), found multiple drift cases between the three sources of truth:\n\n1. **Q-2-5**: catalog title 'Unclosed Emphasis' (generic), but corpus Q-2-5.json and production code (json.rs:328) use 'Unclosed Underscore Emphasis'. Catalog says Q-2-14 is the underscore-specific one. Production behavior collapses to Q-2-5; Q-2-14 is never actually emitted with the *with_code* API.\n\n2. **Q-2-35**: catalog says 'Invalid List-Table Structure' (matches production emits at treesitter_utils/postprocess.rs:785,976), but corpus Q-2-35.json claims 'Indented code blocks are not supported'. The corpus appears stale.\n\n3. **Q-2-36, Q-2-37, Q-2-38**: present in pampa/resources/error-corpus/ as Q-2-36.json (Old-style knitr chunk options), Q-2-37.json (Line break in link destination), Q-2-38.json (Unclosed Attribute Specifier) — and Q-2-36 is emitted in production (treesitter.rs:1244) — but NONE are in error_catalog.json. The catalog jumps Q-2-35 → Q-2-39.\n\n4. **Q-2-6, Q-2-8**: in catalog but never emitted in production. Reserved for future strict-mode (Q-2-6) and upgraded-to-error-and-renumbered (Q-2-8 → Q-2-36).\n\nPlan: the catalog is authoritative for docs_url; the corpus needs to be reconciled to match. Add missing Q-2-36/37/38 to the catalog (or remove from corpus if they should not exist). Fix Q-2-5 and Q-2-35 corpus titles to match catalog. Decide whether Q-2-14 should be deprecated or whether production should be updated to emit it for the underscore variant specifically.\n\nDiscovered from: bd-lgxdr (markdown subsystem error-docs pages).","status":"open","priority":3,"issue_type":"bug","created_at":"2026-05-22T20:38:32.703765Z","created_by":"cscheid","updated_at":"2026-05-22T20:38:32.703765Z","source_repo":".","compaction_level":0,"original_size":0,"labels":["documentation","error-reporting","markdown"],"dependencies":[{"issue_id":"bd-xly8b","depends_on_id":"bd-lgxdr","type":"discovered-from","created_at":"2026-05-22T20:38:32.703765Z","created_by":"cscheid","metadata":"{}","thread_id":""}]}
{"id":"bd-xm7l","title":"Audit non-cargo / vendored dependencies and expand upgrade skill","description":"Expand the upgrade-cargo-deps skill (or add a sibling audit-vendored-deps skill) so the bi-weekly dependency audit also covers non-Cargo vendored assets — Bootstrap SCSS/Icons, chicago-author-date CSL, tree-sitter highlight queries, quarto-cli built-in extensions, knitr R scripts, Pandoc HTML template, quarto-system-runtime JS bundles, reveal.js-menu CSS, etc. Discovery strategies and a per-asset inventory live at claude-notes/research/vendored-dependencies-inventory.md. Plan + phased work items at claude-notes/plans/2026-05-04-vendored-deps-audit.md.","status":"open","priority":2,"issue_type":"epic","created_at":"2026-05-04T21:14:02.442855Z","created_by":"cscheid","updated_at":"2026-05-04T21:14:02.442855Z","source_repo":".","compaction_level":0,"original_size":0,"labels":["deps","vendored"]}
{"id":"bd-xs2u","title":"Em-dash / en-dash in document titles breaks something in hub-client","description":"User reported during L3 testing (2026-05-06): when uploading a project containing em-dash characters (U+2014, '—') in document titles, hub-client exhibits some bug. The user worked around it by replacing em-dashes with regular dashes in the Automerge documents.\n\nI (Claude) did not reproduce the bug myself; I only observed that the workaround (replace em-dash with single dash) made hub-client behave correctly afterwards. The bug could be in any of:\n- pampa parser handling of unicode dashes in YAML strings\n- hub-client / Monaco display of titles with non-ASCII characters\n- The Automerge text sync round-trip (less likely; bytes round-tripped identically in my test)\n\nReproduction (potentially):\n1. Create a Q2 .qmd with 'title: \"Some — text\"' (em-dash) in the frontmatter.\n2. Upload via scripts/upload-project.mjs to wss://sync.automerge.org.\n3. Open in hub-client and observe whatever the user observed.\n\nTo investigate: have the user describe the exact symptom (render error? blank title? wrong rendering?), then bisect against the affected component.\n\nDiscovered while testing L3 (bd-ml8z) listings via hub-client; see claude-notes/plans/2026-05-06-listings-L3-resolve-transform.md §\"Hand-off summary\".","status":"open","priority":2,"issue_type":"bug","created_at":"2026-05-06T22:08:24.119375Z","created_by":"cscheid","updated_at":"2026-05-06T22:08:24.119375Z","source_repo":".","compaction_level":0,"original_size":0,"dependencies":[{"issue_id":"bd-xs2u","depends_on_id":"bd-ml8z","type":"discovered-from","created_at":"2026-05-06T22:08:24.119375Z","created_by":"cscheid","metadata":"{}","thread_id":""}]}
{"id":"bd-xvdop","title":"Experiment: consolidate integration tests to reduce target/ size","description":"Rust defaults give each tests/*.rs file its own test binary, fully linked against the crate + all transitive deps. We have 164 integration test files across 20 crates; target/debug is currently 251 GB while target/release is 2.7 GB, suggesting per-file debug binaries are the dominant bloat. The ark project applied matklad's tests/integration/ consolidation pattern (posit-dev/ark#1240) and saw a ~57% drop in fresh cargo clean size and a ~3x drop in CI runner footprint. This issue tracks an experiment to measure the same change on Q2 from a macOS dev machine, piloting pampa (57 files) first before deciding on a full rollout. Plan: claude-notes/plans/2026-05-28-integration-test-consolidation.md","status":"open","priority":3,"issue_type":"chore","created_at":"2026-05-28T16:16:18.200610Z","created_by":"cscheid","updated_at":"2026-05-28T16:16:18.200610Z","source_repo":".","compaction_level":0,"original_size":0}
{"id":"bd-xwq8","title":"Suppress page-nav for custom-layout pages","description":"Q1 hides the prev/next strip when a page sets page-layout: custom. Phase 4 ships without this; defer until a real page hits the edge case. See Phase 4 plan non-goals.","status":"open","priority":3,"issue_type":"feature","created_at":"2026-04-24T22:47:57.195184Z","created_by":"cscheid","updated_at":"2026-04-24T22:47:57.195184Z","source_repo":".","compaction_level":0,"original_size":0,"dependencies":[{"issue_id":"bd-xwq8","depends_on_id":"bd-nwun","type":"discovered-from","created_at":"2026-04-24T22:47:57.195184Z","created_by":"cscheid","metadata":"{}","thread_id":""}]}
{"id":"bd-xxul","title":"Non-.qmd input extensions in project discovery (.md, .ipynb, .Rmd)","description":"Phase 1 of the website epic explicitly discovers only .qmd files. The plan §File-list expansion defers the decision about which non-.qmd extensions are renderable documents (to include in project.files) vs. source artifacts (to treat like resources). Needs a user conversation about semantics for .md (literal markdown — render? copy?), .ipynb (converted at render time in Q1), .Rmd. Once settled, extend discovery and the pipeline's SourceType handling.","status":"open","priority":2,"issue_type":"task","created_at":"2026-04-24T01:05:32.255233Z","created_by":"cscheid","updated_at":"2026-04-24T01:05:32.255233Z","source_repo":".","compaction_level":0,"original_size":0,"dependencies":[{"issue_id":"bd-xxul","depends_on_id":"bd-w5os","type":"discovered-from","created_at":"2026-04-24T01:05:32.255233Z","created_by":"cscheid","metadata":"{}","thread_id":""}]}
{"id":"bd-y1fs3","title":"q2 preview: CodeBlock DOM mismatches q2 render — classes go on <code> instead of <pre>, sourceCode class missing","description":"q2 render emits '<pre class=\"sourceCode r cell-code\"><code><span class=\"hl-…\">…</span></code></pre>'; q2 preview emits '<pre><code class=\"r cell-code\"><span class=\"hl-…\">…</span></code></pre>'. Two divergences: (1) language/role classes are on <code> in preview, but on <pre> in render (native writer's behavior, see crates/pampa/src/writers/html.rs:963-975); (2) the 'sourceCode' class — prepended to <pre>'s class list whenever data-hl-spans is present (write_code_container_attr at line 487-495) — is entirely missing from preview. Both differences break Quarto theme rules that key off .sourceCode and pre.sourceCode, causing the visible spacing/indentation drift the user reported. Fix in React CodeBlock: move classes + data-* kvs to <pre>; bare <code>; prepend 'sourceCode' to <pre>'s class list when data-hl-spans is non-empty.","status":"closed","priority":2,"issue_type":"bug","created_at":"2026-05-18T17:39:17.866285Z","created_by":"cscheid","updated_at":"2026-05-18T17:44:55.722896Z","closed_at":"2026-05-18T17:44:55.722758Z","close_reason":"Implementation complete: React CodeBlock now mirrors the native HTML writer's DOM shape — classes + data-* kvs on <pre>, bare <code>, sourceCode prepended when data-hl-spans is present. Verified end-to-end: pre.className matches between q2 render and q2 preview ('sourceCode r cell-code' on both), code.className empty on both. 2 tests rewritten, 0 new added; 150/150 SPA integration tests green; cargo xtask verify 12/12 green.","source_repo":".","compaction_level":0,"original_size":0,"dependencies":[{"issue_id":"bd-y1fs3","depends_on_id":"bd-kw93","type":"parent-child","created_at":"2026-05-18T17:39:17.866285Z","created_by":"cscheid","metadata":"{}","thread_id":""},{"issue_id":"bd-y1fs3","depends_on_id":"bd-nxslt","type":"related","created_at":"2026-05-18T17:39:17.866285Z","created_by":"cscheid","metadata":"{}","thread_id":""}]}
Expand Down
94 changes: 94 additions & 0 deletions .claude/rules/integration-tests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Integration test layout

All integration tests in this workspace live in
`tests/integration/<name>.rs` + a `tests/integration/main.rs` that
declares each as `pub mod <name>;`. Cargo compiles **one
`integration` binary per crate** instead of one binary per file.

**Do not add new `tests/<name>.rs` files at the top level of any
crate's `tests/` directory.** Cargo would treat each one as its
own test binary that statically links the crate's full dependency
closure — pampa's closure alone is ~130 MB. That was the bloat we
removed in bd-xvdop (commits `1b420d65` through `1592e8cd`), worth
~9 GB in `target/debug` and ~6.5 GB in `target/release` at the
workspace level.

## Adding a new integration test

1. Create the test file: `crates/<crate>/tests/integration/<your_test>.rs`.
2. Register it in `main.rs`:
```rust
// crates/<crate>/tests/integration/main.rs
pub mod <your_test>;
```
Keep the list alphabetized.

That's it — nextest still runs each `#[test]` in its own process,
so test isolation is preserved. Filter expressions use the new
selector form `package(<crate>) & binary(integration) & test(<file>::)`.

## If you move test files

Any **source-file-relative path** in the moved files needs to be
re-evaluated against the new location. The pampa pilot migration
burned several iterations on insta `set_snapshot_path` calls that
silently resolved to the wrong directory.

Audit grep before declaring a move done — including **cross-language
references** (the bd-xvdop PR shipped without this audit and broke
a TypeScript test that hardcoded a Rust snapshot path):

```bash
# Rust side — source-file-relative paths inside the moved files
grep -nE 'include_str!|include_bytes!|include_dir!|#\[path|set_snapshot_path|"\.\./' \
crates/<crate>/tests/integration/*.rs

# Cross-language side — anything in hub-client / ts-packages /
# scripts / CI config that references the old paths
grep -rn 'crates/<crate>/tests/' \
--include='*.ts' --include='*.tsx' --include='*.js' --include='*.mjs' \
--include='*.json' --include='*.toml' --include='*.yml' --include='*.yaml' \
hub-client/ ts-packages/ scripts/ .github/ .config/
```

Each `../` needs to be re-checked: moving from `tests/foo.rs` to
`tests/integration/foo.rs` adds one directory level, so any
relative path inside the file usually needs one more `../`. And
any hardcoded `crates/<X>/tests/<Y>` path elsewhere in the repo —
typically a TS test that reads a Rust snapshot or fixture — needs
the new `tests/integration/<Y>` location.

Insta `.snap` files also live in a snapshot directory adjacent to
the test source by default. If you move a test that uses default
insta snapshot paths, the existing `.snap` files need to move too:

- Directory: `tests/snapshots/` → `tests/integration/snapshots/`
- Filename: gains an `integration__` prefix because insta's
`module_path!()`-based filenames now start with the binary's
name (`integration`)

## Why this matters (the measurements)

From bd-xvdop's Phase 6 measurement (controlled, back-to-back
`cargo clean` + `cargo build --workspace --tests`, alternating
between baseline and full rollout):

| | Before | After | Δ |
| -------------------------- | ------: | -------: | -----: |
| target/debug | 21 GB | 12 GB | −43 % |
| target/release | 11 GB | 4.5 GB | −59 % |
| Executables in deps/ | 220 | 76 | −65 % |
| Sum of executable bytes | 10.5 GiB | 2.5 GiB | −77 % |
| Release-mode build wall | 158 s | 120 s | −24 % |

The two extra `../` characters in a relative path are easy to get
wrong; the disk savings are not. Prefer the convention even when it
feels redundant.

## References

- `claude-notes/plans/2026-05-28-integration-test-consolidation.md`
- `claude-notes/research/2026-05-28-integration-test-bloat.md`
- [matklad: "Delete Cargo Integration Tests"](https://matklad.github.io/2021/02/27/delete-cargo-integration-tests.html)
- [posit-dev/ark#1240](https://github.com/posit-dev/ark/pull/1240) —
the precedent that motivated this change
14 changes: 11 additions & 3 deletions .config/nextest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,22 @@
# at most, in exchange for deterministic results.
#
# If you're adding a new integration test under `crates/quarto-preview/
# tests/` that calls `run_with_on_ready` or otherwise instantiates the
# file watcher, add its binary name to the override filter below.
# tests/integration/` that calls `run_with_on_ready` or otherwise
# instantiates the file watcher, add its module name to the regex
# in the override filter below.
#
# Layout note (2026-05-28, bd-xvdop): integration tests across the
# workspace now live in `tests/integration/main.rs` + sibling modules
# (matklad pattern), so each crate produces a single `integration`
# test binary instead of one binary per file. Filters that used to
# target per-file binary names now need `package(...) & test(...::)`
# selectors instead.

[test-groups]
# Quarto-preview integration tests that arm a `notify-rs` FSEvents
# watcher. Limited to one in-flight process at a time.
quarto-preview-fs-watcher = { max-threads = 1 }

[[profile.default.overrides]]
filter = "binary(staleness) | binary(eager_capture) | binary(boot)"
filter = "package(quarto-preview) & binary(integration) & test(/^(staleness|eager_capture|boot)::/)"
test-group = "quarto-preview-fs-watcher"
Loading
Loading