Commit Graph

6 Commits

Author SHA1 Message Date
Worktrunk Bot 9bcc071222 ci: bump pinned Nushell to 0.115.1 (#3972)
## Summary

Weekly pin bump: Nushell 0.115.0 → 0.115.1 across all seven pinned
sites. Split from the week's other pin bumps
([#3971](https://github.com/max-sixty/worktrunk/pull/3971)) because the
shell-integration suite runs `--all-features`, so a Nushell version
change can move PTY snapshots — on its own branch, a red matrix decides
only this bump.

Sites moved together, per the weekly checklist: the five
`hustcer/setup-nu` `version:` inputs (`coverage.yaml`, `nightly.yaml`,
`benchmarks.yaml`, and both
`.github/actions/{test,tend}-setup/action.yaml`), plus the two places
that pin Nushell outside `.github/` and are kept level with `test-setup`
— `.codex/cloud.sh`'s `NU_VERSION` and `Taskfile.yaml`'s `setup-web`.

## Verification

The version is the current upstream release (`nushell/nushell`
`0.115.1`, published 2026-08-23). This PR's own `test
(linux|macos|windows)` and `full-tests` legs are where the snapshot
question actually gets answered — I have not run the PTY suite against
0.115.1 locally, since the weekly runner installs no Nushell.

<details><summary>Upstream changes in 0.115.1</summary>

A patch release, mostly completion and config fixes. Nothing that
obviously touches the prompt or wrapper surfaces worktrunk's snapshots
capture, but the completion and REPL changes are the ones to watch if a
snapshot does move:

- `fix(config): merge keybindings by name and key instead of name alone`
(#18870)
- `feat(completions): add a background-completions opt-out` (#18764)
- `fix(completions): keep the REPL usable when a completer runs fzf or
input list` (#18881)
- `Completor Fixes` (#18868)
- `allow $ans to still work after invalid operation` (#18863)
- `fix update to work better with custom values` (#18865)
- `allow boolean comparison with semver` (#18854)
- `Update h2 do to RUSTSEC-2026-0258` (#18875)

</details>

Co-authored-by: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com>
2026-08-31 11:36:14 -07:00
Worktrunk Bot f2ae1c5fb5 chore(ci): weekly renovation 2026-08-23 (#3880)
## Summary

Weekly CI renovation. Rust stable moved to 1.98.0 on 2026-08-20, so MSRV
and the development toolchain go to 1.97 (latest stable − 1); one
cargo-install pin had drifted. Everything else is already current.

- **MSRV + toolchain: 1.96 → 1.97** — `Cargo.toml`,
`tests/helpers/wt-perf/Cargo.toml`, `rust-toolchain.toml` (`1.97.0`),
plus the `flake.lock` refresh the channel bump requires.
- **`cargo-llvm-cov`: 0.8.7 → 0.9.0** — `coverage.yaml`. MSRV 1.87, well
under the pinned toolchain.

Toolchain compatibility for every other pinned crate against 1.97.0:
`cargo-affected` 0.4.0 (1.94), `cargo-insta` 1.48.0 (1.66.0),
`cargo-nextest` 0.9.143 (1.91), `cargo-llvm-cov` 0.9.0 (1.87),
`cargo-msrv` 0.19.3 (1.91.1), `lychee` 0.24.2 (1.88.0), `worktrunk`
0.74.0 (1.96), `cargo-udeps` 0.1.61 (unspecified). All build under
1.97.0.

- **Pinned nightly: `nightly-2026-03-01` → `nightly-2026-08-01`** —
`nightly.yaml` ×2. Not drift: the MSRV bump *broke* these two jobs, see
below.
- **The skill's `flake.lock` recipe** — the in-session Nix install it
pointed at can never run. The setup step that fixes that lives in #3891,
not here; see below.

The remaining commits are fallout from the same sweep: `cargo-llvm-cov`
0.9.0 changes the shape of the `--show-missing-lines` column
`tests/CLAUDE.md` sends you to during a codecov investigation, and the
weekly statusline cache-check has been reporting two duplicates that are
artifacts of its own `-vv` flag.

## The MSRV bump broke two nightly jobs; that is fixed here

`check-unused-dependencies` and `minimal-versions` each pin their own
toolchain, and `nightly-2026-03-01` is `1.96.0-nightly` — so raising
`rust-version` to 1.97 made cargo refuse the workspace outright, before
either job ran its actual check:

```
error: rustc 1.96.0-nightly is not supported by the following packages:
  worktrunk@0.74.0 requires rustc 1.97
```

Both are now on `nightly-2026-08-01` (`1.99.0-nightly`), which clears
the new MSRV with headroom rather than landing on it. Reproduced locally
in both directions: `cargo +nightly-2026-03-01 check` fails with the
error above, `cargo +nightly-2026-08-01 check` passes. The coupling is
easy to miss because neither failure mentions udeps or minimal versions,
so both lines now say so, and the weekly MSRV file table gained a row
for the pins. The rule on that row is a date, not a version: bump only
when the pinned date is more than three months old. Nightly runs two
channels ahead of stable and MSRV tracks stable − 1, so a pin that
recent is still a release above the new MSRV — which makes staleness
checkable from the pinned date alone, where reading it off the rustc
version means fetching that day's `channel-rust-nightly.toml`.
`nightly-2026-03-01` was five and a half months old, which is exactly
what the rule catches.

## The `flake.lock` bump was computed by hand — and the recipe that
forced that is fixed here

`rust-toolchain.toml` moving to `1.97.0` forces a lock refresh: the
locked `rust-overlay` (`4a408e1f`, 2026-06-02) carries stable manifests
only up to `1.96.0`, so `nix flake check` cannot resolve the new
channel. `rust-overlay` is bumped to `f60c1b57` (2026-08-23), which has
`1.97.0.nix`. `nixpkgs` and `crane` are left alone — only `rust-overlay`
has to know about the new channel, and a full `nix flake update` is a
wider change than this PR needs.

This session could not run `nix flake update`: the weekly runner has no
Nix, and the agent runs as a sandbox user with no sudo, so the installer
the skill pointed at stops at `sudo: a password is required`. The lock
entry was therefore computed directly from the NAR serialisation, and
the method was validated first by recomputing the **existing**
`rust-overlay` entry from its own revision and getting
`sha256-7mDa7OBAaf7MU6ZovT9ENfD62kH911SsSazBb4KTDF0=` back byte-for-byte
— the value already in `flake.lock`. The same script then produced the
new entry.

That should not have been the answer, and it no longer is. #3891 has
merged (`2960bfb`), so `tend-setup` installs Nix and next week's refresh
runs `nix flake update rust-overlay` for real. This branch briefly
carried its own `cachix/install-nix-action@v31` step in the same file;
`adbeb76` dropped it in favour of #3891's, which asserts the multi-user
install branch directly and doesn't couple to `github.workflow ==
'tend-weekly'`, a gate that stops firing if the generated workflow is
renamed. `.github/actions/tend-setup/action.yaml` on this branch is
byte-identical to `main`.

What stays here is the skill side: the in-session install recipe and the
NAR-serialisation fallback are both deleted, because the Determinate
installer they rest on cannot run in the sandbox. Both PRs rewrote that
section and converged on nearly the same wording, so they merged clean
while both were open — but #3891's squash collapsed its five commits
into one, and its last two had moved the "if `nix` isn't on the PATH"
line and folded the flake-input rationale into the code block. That
turned the section into the merge's one conflict, resolved by taking
`main`'s wording wholesale; the section is now byte-identical to
`main`'s, and this branch's own additions to that file are untouched by
it.

That is a strong check but not the real one. `nightly`'s `nix-flake` job
runs `nix flake check` and fires on this PR (the paths filter matches
`rust-toolchain.toml`, `Cargo.toml`, and `flake.lock`), so it is the
gate that actually proves the lock evaluates. **It has now run on this
head and passed**, so the computed lock resolves the 1.97.0 channel and
the flake's checks build under it. Flagging the provenance anyway, since
a hand-written lock entry deserves a second look on review.

<details><summary>How the hash was computed</summary>

Nix serialises the unpacked flake input as a NAR and reports SHA-256 of
that stream in SRI form. The format is length-prefixed strings padded to
8 bytes, with directory entries in bytewise-sorted order; a ~90-line
Python script reproduces it from the GitHub tarball with the top-level
`<repo>-<rev>` directory stripped, which is the same tree Nix hashes.

```
rust-overlay 4a408e1fc99ad517b4cb402fd0de7464f40c05e1 (currently locked)
  computed  sha256-7mDa7OBAaf7MU6ZovT9ENfD62kH911SsSazBb4KTDF0=
  in lock   sha256-7mDa7OBAaf7MU6ZovT9ENfD62kH911SsSazBb4KTDF0=   ✓

rust-overlay f60c1b57ff805a46b5175c76fc981fb4f81efbcc (new)
  computed  sha256-r4LDUF+zmJnkftvCVkCrUhSJazsf6EVJF+V2l4/MYbI=
  lastModified 1787454509 (committer date 2026-08-23T03:08:29Z)
```

</details>

## Already up to date

- `cargo-affected` 0.4.0, `cargo-insta` 1.48.0, `cargo-nextest` 0.9.143,
`cargo-msrv` 0.19.3, `cargo-udeps` 0.1.61, `lychee` 0.24.2, `worktrunk`
0.74.0 (matches the newest crates.io release)
- Nushell 0.115.0 — all four call sites, and `dev/codex.sh`
- Codex Cloud pins in `dev/codex.sh`: pre-commit 4.6.2, cargo-insta
1.48.0, cargo-nextest 0.9.143, PowerShell 7.6.5; `setup-web`'s own
Nushell and PowerShell pins agree
- Runner images `ubuntu-24.04` and `windows-2022` (the latter
deliberately pinned — actions/runner-images#12677)

## Found, not bumped: `macos-15` is no longer what `macos-latest`
resolves to

`ci.yaml`'s header comment says `ubuntu-24.04, macos-15` are "pinned to
current -latest equivalents". That is still true of Ubuntu but no longer
of macOS: `macos-latest` now resolves to **macOS 26 arm64**, and
`macos-15` has become the older of the two GA images — which, under the
runner-images deprecation policy ("deprecation of the oldest image label
begins once the newest OS image label has been released to GA"), is the
one that starts aging out next. `macos-14` already carries the
deprecated badge.

Not bumped here, because it is an OS upgrade rather than a version pin,
and this repo drives PTY and shell-integration snapshots on macOS that a
new image and Xcode can move. There is also nothing this session can do
to check it — the only macOS available to it is the `test (macos)` job
on a PR, and a red macOS matrix would have blocked the MSRV bump
alongside it. Flagging rather than guessing at the timing: whether to
take macOS 26 now or wait for the deprecation announcement is a call
about this repo's snapshot surface. Happy to open it as its own PR if
you want the signal.

## CI

Fully green on `7940a97`, the first merge of `main`: all 33 non-skipped
checks, including `msrv`, all three `test` legs, `full-tests` on every
platform, `nix-flake`, `minimal-versions`, `check-unused-dependencies`,
`check-docs`, `link-check`, `feature-powerset`, and `codecov/patch`.
That head is where the hand-written lock entry and the nightly pins were
proven against the current `main`.

`main` has since moved four commits (#3886, #3893, #3895, #3897) and is
merged in again at `d8d1553`, alongside the nightly-pin rule above.
#3895 touches `nightly.yaml`, so the pins were re-checked after that
merge: still exactly two sites, `minimal-versions` and
`check-unused-dependencies`, both on `nightly-2026-08-01`. Locally
`pre-commit run --all-files` and `test_docs_are_in_sync` pass on this
head.

## Weekly checks that produced no change

- **LLM model pins** — no drift. `gpt-5.6-luna` is still how OpenAI's
models page positions the "fast and affordable … lowest cost in the
family" 5.6 variant; `gpt-5.3-codex-spark` is a Pro-only research
preview, not a default. `haiku` / `claude-haiku-4.5` is still the
smallest current Anthropic model.
- **Statusline cache-check** — clean. `command_count` was 27, which
includes the three calls the `-vv` diagnostic collector makes after the
render, so the render itself is ~24 against a ~29 baseline measured
before the recipe used `-vv`. The two duplicates the report flagged (`gh
--version`, `git worktree list --porcelain`) are that same collector,
not the render. Both the baseline arithmetic and the trap are now
written down in the skill.
- **Agent app integration surfaces** — nothing that changes what
Worktrunk consumes. Claude Code 2.1.239 fixed `metadata.pluginRoot`
resolution, but `.claude-plugin/marketplace.json` names an explicit
`./plugins/worktrunk` source rather than a bare name, so it is
unaffected; the `WorktreeCreate`/`WorktreeRemove` hooks and the
statusline stdin schema are unchanged (`workspace.git_worktree` and
`workspace.repo` exist but predate this window by several hundred
releases). Codex, Gemini CLI, and OpenCode shipped only routine
releases.
- **README month** — already "August 2026".
- **Dependency PRs** — none open.

<details><summary>Verification</summary>

- `rustup` resolves the new channel: `cargo 1.97.0 (c980f4866
2026-06-30)`, `rustc 1.97.0 (2d8144b78 2026-07-07)`, `clippy 0.1.97`.
- `cargo clippy --all-targets --all-features -- -D warnings` passes on
1.97.0 — the check that matters most for a toolchain bump, since it
compiles every target and feature under the new rustc and holds the new
clippy to zero warnings. Doctests passed too.
- Unit tests pass on 1.97.0: 979 + 11 + 1, zero failures.
- Integration tests: 2000 passed, 1 failed —
`test_copy_ignored_preserves_file_executable_permissions`, which expects
`0644` and got `0664`. That is this sandbox's `umask 0002`, not the
toolchain; the `test (linux|macos|windows)` matrix is the real gate.
- `cargo run -- hook pre-merge --yes` is not a clean local signal on
this runner: it ends on `pre-commit: exit status: 127` because
pre-commit isn't installed in the tend sandbox, unrelated to the bump.
- `cargo msrv verify` was not run locally (it rebuilds the graph per
candidate); `ci.yaml`'s `msrv` job covers it.
- Every version above was read from its upstream source of truth: `cargo
info` / crates.io for the cargo tools,
`static.rust-lang.org/dist/channel-rust-stable.toml` for Rust stable
(1.98.0, 2026-08-20), the `nushell/nushell` and `PowerShell/PowerShell`
release APIs, PyPI for pre-commit, `actions/runner-images` README for
the image labels, and the vendors' own model pages for the LLM pins.
- `rust-overlay` at the currently-locked revision was confirmed to stop
at `1.96.0.nix`, and at the new revision to contain `1.97.0.nix` — this
is why the lock has to move at all.

</details>



> _This was written by Claude Code on behalf of max-sixty_

---------

Co-authored-by: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com>
Co-authored-by: Maximilian Roos <m@maxroos.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-24 13:54:54 -07:00
Worktrunk Bot 1b278042de chore(ci): weekly renovation 2026-08-16 (#3826)
## Summary

Weekly CI renovation check found the following updates:

- `worktrunk`: 0.72.0 → 0.74.0 (MSRV 1.96, compatible with our 1.96.0) —
`ci.yaml` ×2, `nightly.yaml`
- `nushell`: 0.114.1 → 0.115.0 — `nightly.yaml`, `benchmarks.yaml`,
`coverage.yaml`, `actions/test-setup`, and
`scripts/codex-cloud/Taskfile.yaml`
- `pre-commit`: 4.6.1 → 4.6.2 — `scripts/codex-cloud/Taskfile.yaml`
- `PowerShell`: 7.6.4 → 7.6.5 — `scripts/codex-cloud/Taskfile.yaml` and
the root `Taskfile.yaml`'s `setup-web` task

The Codex Cloud archive checksums were recomputed from the new upstream
tarballs, and the resulting `Taskfile.yaml` digest (`f14dbc89…`) is
copied into both README launcher commands.

The `setup-web` PowerShell pin came in as a follow-up commit: the
initial sweep only grepped `.rs`/`.md`/`.toml` for stale versions, so
the root `Taskfile.yaml`'s `PWSH_VERSION="7.6.4"` was missed. Nothing
tests the two PowerShell pins against each other, so that one drifts
silently — worth a note for future renovation runs. The
`powershell_7.6.5-1.deb_amd64.deb` asset the `setup-web` branch
downloads is present in the v7.6.5 release.

## Already up to date

- Rust stable is 1.97.1, so MSRV and toolchain stay at 1.96 (latest
stable − 1) — `Cargo.toml`, `tests/helpers/wt-perf/Cargo.toml`,
`rust-toolchain.toml` need no change, and `flake.lock` is untouched.
- `cargo-insta` 1.48.0, `cargo-nextest` 0.9.143, `cargo-llvm-cov` 0.8.7,
`cargo-msrv` 0.19.3, `cargo-affected` 0.4.0, `cargo-udeps` 0.1.61,
`lychee` 0.24.2
- Task 3.52.0 (mise, Codex Cloud)
- Runner images: ubuntu-24.04, macos-15, windows-2022

## Held back: zola 0.22.1 → 0.23.3

Not bumped. Zola 0.23.0 shipped [Tera2 +
refactoring](https://github.com/getzola/zola/pull/3105), which is a
templating-engine swap rather than a routine release. Building `docs/`
with the 0.23.3 binary fails at the first line of `templates/base.html`:

```
ERROR error: Unknown tag
 --> base.html:1:4
  |
1 | {% import "macros.html" as macros %}
  |    ^^^^^^
```

`templates/base.html` and `templates/macros.html` are the two files that
use the `import`/`macro` pair, so the migration looks small, but it is
template work with its own review rather than a pin bump — kept out of
this PR so the rest can land. Raised separately.

<details><summary>Verification</summary>

- Every version above was read from the upstream source of truth:
`crates.io` for the cargo tools, `nushell/nushell` and
`PowerShell/PowerShell` releases, PyPI for pre-commit, and
`static.rust-lang.org/dist/channel-rust-stable.toml` for Rust stable
(1.97.1).
- Checksums were computed from the downloaded archives and the extracted
binaries were run (`nu --version` → `0.115.0`); the archive layouts
(`nu-<ver>-x86_64-unknown-linux-gnu/nu`, top-level `pwsh`) are
unchanged, so the `install_binary` paths still resolve.
- All six edited YAML files parse.
- The nushell bump was exercised against the shell-integration suite:
`cargo test --features shell-integration-tests --test integration --
nushell` with 0.115.0 on `PATH`. 13 of 14 pass;
`test_nushell_install_target_is_a_vendor_autoload_dir` fails — but it
fails identically on the currently-pinned 0.114.1, and passes on *both*
versions when run alone. It is a pre-existing shared-state race in the
sandbox, not a regression from this bump: the test asserts against the
real user `$nu.vendor-autoload-dirs` entry rather than one under its
temp `HOME` (nu resolves the home dir from the passwd database, so the
test's `HOME` override does not move it), and a sibling uninstall test
in the same filter removes `wt.nu` from that shared directory. Noted
rather than fixed here — it is unrelated to the pins.
- The zola failure above was reproduced with the official 0.23.3
`x86_64-unknown-linux-gnu` release binary against this repo's `docs/`.

</details>

---------

Co-authored-by: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com>
2026-08-17 01:48:26 -07:00
Worktrunk Bot ec574b6c35 ci: bump pinned cargo-nextest 0.9.143 and worktrunk 0.72.0 (#3783)
## Summary

Weekly CI pin check found the following drift (these inline `version:`
strings are invisible to Dependabot — it follows `Cargo.toml` deps and
`uses: foo@vN` refs, not pinned versions inside `with:` blocks):

- `cargo-nextest`: 0.9.140 → 0.9.143 (MSRV 1.91, compatible with our
1.96) — pinned in `coverage.yaml`, `actions/test-setup`, and
`actions/claude-setup`; all three moved together.
- `worktrunk`: 0.71.0 → 0.72.0 (MSRV 1.96, compatible with our 1.96) —
the CI-installed `wt` that runs `wt hook pre-merge`, bumped to the
current release; pinned in `ci.yaml` (×2) and `nightly.yaml`.

## Already up to date

- `cargo-affected`: 0.4.0, `cargo-insta`: 1.48.0, `cargo-llvm-cov`:
0.8.7, `cargo-msrv`: 0.19.3, `cargo-udeps`: 0.1.61, `lychee`: 0.24.2
- `hustcer/setup-nu` (nushell): 0.114.1 — matches the current nushell
release across all four call sites
- Runner images: ubuntu-24.04, windows-2022

## Notes

- windows-2022 stays pinned
([actions/runner-images#12677](https://github.com/actions/runner-images/issues/12677)
— windows-2025 lacks the D: drive).
- **cargo-nextest 0.9.143 has nothing config-facing to adjust.** The
0.9.140 → 0.9.143 range is dynamic-library-search-path fixes (build-dir
layout v2, `build.build-dir`, `[[example]]` targets), archive filterset
fixes, an opt-in `junit.report-skipped` setting we don't set, and a
listing progress bar. The one behavior change — ordering the Cargo
artifact directory ahead of `deps` on the dylib search path, matching
Cargo since 1.93 — doesn't affect this repo, which links no `dylib`
dependency.
- **worktrunk 0.72.0 is only exercised through `wt hook pre-merge`** in
these three jobs, so the release's `wt merge` / `wt step push` two-tree
changes and the `branch_outcome` JSON rename don't reach CI. The
relevant one is the opposite direction: 0.72.0 fixes `wt` writing ANSI
to a pipe and exiting 101 on `Broken pipe`, which is exactly the non-tty
shape these jobs run in.
- **`zola` is deliberately left at 0.22.1** — see below.

## Deferred: zola 0.22.1 → 0.23.2

`taiki-e/install-action`'s `tool: zola@0.22.1` in `check-docs` (and the
matching pin in `publish-docs.yaml`) is behind, but 0.23.0 is not a
routine bump. Upstream calls it "probably the most breaking version of
Zola that will happen"
([CHANGELOG](https://github.com/getzola/zola/blob/master/CHANGELOG.md)):
**shortcodes are removed entirely** and Tera is updated to v2 with its
own [migration
guide](https://github.com/Keats/tera/blob/master/MIGRATION.md).
`docs/templates/shortcodes/` and `docs/templates/macros.html` both
exist, so this needs a real docs-site migration rather than a
version-string change, and it would land in the same PR as the live-site
publish pin. Left for a separate change; flagging it here so it isn't
silently skipped each week.

Co-authored-by: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com>
2026-08-09 04:56:50 -07:00
Maximilian Roos 1b35950a9c test: simplify the integration suite (#3657)
This reduces duplicated and false-confidence integration coverage while
preserving the suite's semantic and user-facing contracts.

## What changed

- Replaces three overlapping list-layout suites with two representative
CLI integrations, leaving exhaustive geometry at the direct layout
layer.
- Groups Git error render variants into labeled family snapshots and
removes command-by-shell wrapper cross-products while retaining
shell-specific conformance and regression cases.
- Updates test-authoring guidance around boundary choice, minimal
contrasts, and PTY use, and runs local and CI coverage through Nextest
isolation.

## Results

- Test catalog: 4,642 to 4,562
- Snapshots: 1,193 to 1,131
- Warm all-feature runtime: 84.70s to 78.17-80.35s
- Full coverage: 97.32% of lines

## Testing

- `cargo run -- hook pre-merge --yes`
- `cargo llvm-cov nextest --features shell-integration-tests
--summary-only`

> _This was written by Claude Code on behalf of max_.
2026-07-29 18:54:19 -07:00
Maximilian Roos 4202cffe61 fix(ci): split ci by cadence so coverage uploads on every main commit (#3608)
## What prompted this

Getting #3605 green ran into codecov reporting a `base_commit` three
commits
older than the real merge-base. This audits whether our config causes
that.

## The cause

Codecov picks a PR's base by walking back to the newest ancestor that
has a
coverage report. It used the real merge-base for PRs #3480, #3532 and
#3602,
and a stale one for #3603 and #3605. The difference is whether the
merge-base
uploaded a report. **29 of the last 40 main commits did not.**

`ci` had one concurrency group for main pushes, and GitHub cancels the
*pending* run in a group whenever a newer one joins, even with
`cancel-in-progress: false`. So the question is how long a run holds the
group,
and a run isn't done until its slowest job is:

| job | duration on main |
|-----|------------------|
| `fast-checks` | 2 min |
| `code-coverage` | 3-4 min |
| `test (windows)` | 11 min |
| `collect affected coverage (windows)` | 110-129 min |

Each main run held the group for ~2 hours, so nearly every subsequent
main push
was cancelled while queued, taking the 4-minute coverage job with it.
Every
cancelled main run's `updated_at` lands within a second of the next
push's
`created_at`.

The 2 hours is real work, not queue: 2-5s from `created_at` to
`started_at`,
then 108 minutes inside `cargo affected collect` — 4181 tests under
`-C instrument-coverage` with a per-test LLVM profile, ~5 GB of profraw.

## The fix: one workflow per cadence

The three groups of jobs have incompatible needs, and one group was
serving all
of them.

| workflow | cadence on main | why |
|----------|-----------------|-----|
| `ci` | every commit, ~11 min | required gate + fast checks |
| `coverage` | every commit, keyed per-sha | a skipped upload leaves
later PRs on a stale base |
| `affected` | sampled, ~2 h | a DB a few commits old still anchors a
correct superset |

`affected` keeps exactly the grouping it has today, so its sampling is
unchanged and deliberate. It just no longer drags the other two along.

### Scope of the impact

The posted `codecov/patch` check scopes to the PR's own GitHub diff, so
a stale
base did **not** score PRs against other people's lines. On #3605 the
posted
91.66% is exactly `github.rs`'s 11/12, while the stale-base compare
object
reported 64/65 across 13 files. What a stale base costs:

- `codecov/project` reports "compared to \<stale sha\>"
- the patch `auto` target is the stale base's project coverage (0.02pp
here)
- the compare API object widens to `base..head`, which is what made the
  investigation look like silence

Separately, `test`/`lint`/`fast-checks` also stopped completing on main.
Nothing
load-bearing rode on that (they already ran on the PR), but it left
`tend-ci-fix` with nothing to watch, since it doesn't fire on cancelled
runs.

## Two smaller fixes

- `ignore: "**/tests/**"` compiles to `.*/tests/.*` (confirmed against
codecov's validator), which needs a leading directory and so never
matched
`tests/` itself. Inert today since `cargo llvm-cov` reports only `src/`
(verified against a downloaded `cobertura.xml`), but now correct if that
  changes. Now `tests/**`.
- `fail_ci_if_error` gated on `github.repository_owner`, which is the
*base*
repo's owner on a fork PR too, so the soft-fail its comment describes
never
  applied. It keys off the head repo now.

## Docs

The API behaviour was ours to misuse, not codecov's to explain. Three
traps,
all confirmed against the live API:

- `file_report/<path>/` 404s with `coverage info not found` because the
route
swallows the trailing slash into the path. Without it the endpoint
returns
  `line_coverage`.
- `?pullid=N` always compares the PR's **current** head. `?base=&head=`
asks
  about an earlier commit.
- the compare response has no `patch_totals` key, and `.name` is
`{base, head}` rather than a string, so a filename lookup silently
matches
  nothing.

A working recipe already existed in `running-tend`, but that skill is
scoped to
CI. `tests/CLAUDE.md` owns coverage investigation, so the queries go
there and
`running-tend` points at them instead of keeping a second copy.

Re-running the corrected query against #3605's failing commit reproduces
the
miss exactly: `src/git/remote_ref/github.rs:164`, the `gh repo
set-default`
hint, matching what the session eventually found by hand.

## This PR demonstrates it

It changes no Rust at all, only YAML and markdown. Codecov still
reported a
**10-file, 111-line patch** on its first commit, because it based the
comparison on `203603909` rather than the real merge-base `32f380a27`.
Every
main commit in between has no report:

| commit | ci run | report |
|--------|--------|--------|
| `32f380a27` | queued | no |
| `9645e3e13` | cancelled | no |
| `bcd1ffdfd` | cancelled | no |
| `8865f20ab` | cancelled | no |

Every one of those 111 patch lines belongs to somebody else's merged
commit. It
passed at 100% only because those commits are well covered.

> _This was written by Claude Code on behalf of @max-sixty_

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com>
2026-07-26 20:19:15 -07:00