Install any skill in seconds. Free to start, no credit card required.
Get Started Free →The test_documents submodule — a bucket-fetched fixture corpus that is not committed, the read_test_fixture helper that keeps a missing fixture out of the build, why a git worktree is not a valid A/B control, and the submodule push order. Load before running the Rust test suite on a fresh clone, setting up an A/B control, adding a fixture-backed test, or diagnosing "missing fixture" failures.
.claude/skills/xberg-io-test-corpus/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 2% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 25% | 0% |
| case-03 | ✗→✓ | ▲ Improved | -33% | 0% |
| case-07 | ✗→✓ | ▲ Improved | -3% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 9% | 0% |
test_documents is a git submodule (.gitmodules → xberg-io/test_documents). Its binary fixtures — 654 objects, ~581 MiB per test_documents/corpus.lock.json — are not committed. They are materialised from a public GCS bucket over anonymous HTTPS, with no credentials and no SDK.
bashpython3 test_documents/scripts/fetch_corpus.py # everything python3 test_documents/scripts/fetch_corpus.py --include 'pdf/**'
Fetched files are gitignored inside the submodule, so neither the submodule nor the superproject goes dirty. CI does the same thing with xberg-io/actions/fetch-test-documents@v1, narrowing with include: where the job's fixture surface is known (see ci-rust.yaml).
Tests that read from test_documents fail with missing-file errors, not assertion failures. Read the message before concluding the suite regressed.
include_bytes! a corpus fixtureBaking corpus bytes in at compile time turns a missing fixture into a build failure for the whole crate — this is what broke the workspace-wide clippy run in CI. Use the canonical helper instead:
rust// crates/xberg/src/utils/mod.rs — #[cfg(test)], pub(crate) let Some(bytes) = crate::utils::read_test_fixture("images/test.heic") else { return; };
read_test_fixture prints a greppable SKIP: fixture … not available line naming the missing path and returns None. It lives in utils deliberately: utils compiles unconditionally, while extraction::image and extraction::email are feature-gated.
A None is "not run", never "passed".
git worktree add does not populate submodules, so a control worktree has an empty test_documents. Every fixture-guarded test skips silently and the run reports green — a vacuous control inverts the verdict. The tell is the runtime: finished in 0.00s means the binary did nothing.
Two more worktree traps: a relative [patch.crates-io] path dependency (the root Cargo.toml currently patches liter-llm to ../liter-llm/…) resolves relative to the worktree, not the main checkout; and a shared CARGO_TARGET_DIR will thrash.
Working setup:
bashgit worktree add /tmp/ctl <ref> --detach rmdir /tmp/ctl/test_documents && ln -sfn <main-tree>/test_documents /tmp/ctl/test_documents CARGO_TARGET_DIR=/tmp/ctl-target cargo test ...
When the goal is only build isolation, prefer a dedicated CARGO_TARGET_DIR in the main checkout over a worktree — it avoids all three traps.
Bucket-managed fixtures are published from inside the test_documents submodule with the authenticated gcloud storage wrapper. Preview the exact object and manifest changes first:
bashcd test_documents python3 scripts/publish_corpus.py --bucket xberg-test-documents --dry-run python3 scripts/publish_corpus.py --bucket xberg-test-documents python3 scripts/verify_corpus.py --bucket xberg-test-documents
The publisher writes content-addressed objects, refreshes corpus.lock.json, skips objects that already exist, refuses tracked corpus binaries, and probes bucket write access. Publish the object before committing or pushing the refreshed lock file; CI can verify public reads but cannot publish working-tree binaries.
Push the submodule commit before the superproject gitlink. A local-only submodule commit builds and tests green on the machine that made it and turns every CI workflow red at checkout with Fetched in submodule path 'test_documents', but it did not contain <sha>. Check with git branch -r --contains <sha> inside the submodule.
fixtures/fixtures/ at the repo root is committed and safe to include_bytes!. Only test_documents/ is bucket-fetched.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 16,178 | 8,352 | -48% | 1 | 1 | 0% | 2,428 | 2,471 | +2% | 0 | 0 | — |
case-02 | fail→pass | 28,372 | 17,785 | -37% | 1 | 1 | 0% | 2,396 | 2,988 | +25% | 0 | 0 | — |
case-03 | fail→pass | 15,008 | 5,760 | -62% | 1 | 1 | 0% | 2,613 | 1,750 | -33% | 0 | 0 | — |
case-04 | pass→pass | 17,012 | 46,456 | +173% | 1 | 1 | 0% | 3,265 | 4,167 | +28% | 0 | 0 | — |
case-05 | pass→fail | 15,849 | 12,255 | -23% | 1 | 1 | 0% | 2,514 | 2,985 | +19% | 0 | 0 | — |
case-06 | pass→pass | 8,097 | 9,090 | +12% | 1 | 1 | 0% | 1,434 | 2,470 | +72% | 0 | 0 | — |
case-07 | fail→pass | 12,015 | 6,087 | -49% | 1 | 1 | 0% | 1,997 | 1,945 | -3% | 0 | 0 | — |
case-08 | fail→pass | 11,610 | 4,976 | -57% | 1 | 1 | 0% | 1,691 | 1,848 | +9% | 0 | 0 | — |
case-09 | fail→pass | 12,757 | 5,660 | -56% | 1 | 1 | 0% | 1,783 | 1,692 | -5% | 0 | 0 | — |
case-10 | fail→pass | 17,312 | 11,506 | -34% | 1 | 1 | 0% | 2,245 | 2,838 | +26% | 0 | 0 | — |
case-11 | fail→pass | 17,206 | 2,410 | -86% | 1 | 1 | 0% | 1,183 | 1,256 | +6% | 0 | 0 | — |
case-12 | fail→pass | 15,866 | 8,926 | -44% | 1 | 1 | 0% | 2,568 | 2,383 | -7% | 0 | 0 | — |
case-13 | pass→pass | 7,618 | 3,862 | -49% | 1 | 1 | 0% | 1,196 | 1,330 | +11% | 0 | 0 | — |
case-14 | fail→pass | 17,001 | 7,850 | -54% | 1 | 1 | 0% | 2,411 | 2,219 | -8% | 0 | 0 | — |
case-15 | pass→pass | 11,696 | 3,996 | -66% | 1 | 1 | 0% | 1,921 | 1,541 | -20% | 0 | 0 | — |
case-16 | fail→pass | 18,488 | 3,048 | -84% | 1 | 1 | 0% | 3,270 | 1,387 | -58% | 0 | 0 | — |
case-17 | fail→pass | 26,215 | 3,074 | -88% | 1 | 1 | 0% | 1,635 | 1,313 | -20% | 0 | 0 | — |
case-18 | pass→pass | 8,463 | 3,359 | -60% | 1 | 1 | 0% | 1,302 | 1,423 | +9% | 0 | 0 | — |
case-19 | pass→pass | 14,362 | 3,650 | -75% | 1 | 1 | 0% | 1,222 | 1,454 | +19% | 0 | 0 | — |
case-20 | pass→pass | 20,030 | 3,302 | -84% | 1 | 1 | 0% | 2,146 | 1,434 | -33% | 0 | 0 | — |
case-21 | fail→pass | 12,172 | 2,350 | -81% | 1 | 1 | 0% | 1,931 | 1,287 | -33% | 0 | 0 | — |
case-22 | pass→pass | 15,910 | 3,994 | -75% | 1 | 1 | 0% | 2,109 | 1,507 | -29% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 21 counted toward the lift figure. The other 1 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +55 percentage points is the difference between those two pass rates over the 21 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.