9 Commits

Author SHA1 Message Date
Maximilian Roos 970976bd32 Consolidate benchmark recipes and cases (#3721)
Benchmark fixtures had accumulated around individual call sites, leaving
the same repository shapes and command modes expressed several ways.
This change makes repository state the organizing concept: benchmark
groups select semantic `FixtureRecipe`s, share table-driven cases, and
retain separate fixtures only when a controlled contrast, destructive
precondition, or disproportionate setup cost requires one.

The real-repository list benchmarks now share one pinned
`rust-lang/rust` fixture with eight worktrees and fifty branches spread
across history. The list matrix keeps default, branch, warm, and cold
coverage without maintaining several “real” repository handles. Remove
and prune cases share the same case machinery, while the destructive
large-repository prune state remains separate.

The scheduled workflow now converts Criterion estimates directly with
`jq`, removing the one-off Python converter and its tests. The benchmark
guide records the canonical-fixture principle and the remaining
recipe-to-group mapping.

Tests: `cargo run -- hook pre-merge --yes` (4,551 tests); `cargo bench
--bench list large_repository -- --test`; `cargo test -p wt-perf`;
benchmark check, clippy, formatting, and diff checks.

> _This was written by Codex on behalf of max-sixty_.
2026-08-05 10:30:34 -07:00
Maximilian Roos 06d2a3f862 ci(bench): append nightly results to worktrunk-bot gist (#2531)
## Summary

Today the nightly benchmark job uploads `target/criterion` as a 90-day
artifact and nothing else; results aren't queryable across runs. This
adds a JSONL append to a public gist so we can track regressions and
trends over time.

## Changes

`.github/scripts/criterion-to-jsonl.py` — walks
`target/criterion/**/new/estimates.json` and emits one JSON line per
benchmark group (timestamp, commit SHA, mean_ns, stddev_ns). Errors out
if no estimates are found, so a broken bench step fails the workflow
instead of silently skipping.

`.github/workflows/nightly-benchmark.yaml` — new step clones the gist
using the existing `WORKTRUNK_BOT_TOKEN` (already has `gist` scope),
appends new rows to `results.jsonl`, commits, and pushes. The 90-day
artifact upload is unchanged — it remains the per-run raw data; the gist
becomes the long-term time series.

## Gist

https://gist.github.com/worktrunk-bot/19bb23cb9658722abfe69479d0a4f9bf

Created locally as `worktrunk-bot`, contains a placeholder line that
will sit alongside real rows once the next nightly fires (or
`workflow_dispatch` triggers it manually).

## Test plan

- [ ] `actionlint` and `pre-commit` clean (verified locally)
- [ ] Smoke-tested the Python script against synthetic Criterion data —
produces correct JSONL, errors on empty tree
- [ ] Trigger `workflow_dispatch` post-merge to verify the first real
append lands in the gist

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

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-02 12:04:55 -07:00
Maximilian Roos 8078c0e3dc Remove redundant nightly survey script (#2026)
The nightly survey script is now shipped upstream in tend's plugin. The
local copy at `.github/scripts/todays-survey-files.sh` was nearly
identical — only the default file extensions differed. With the upstream
script now surveying all tracked files (no extension filter), there's no
need for a local override.

Depends on max-sixty/tend#200

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

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-08 18:07:12 -07:00
Maximilian Roos 4817604b81 Replace hand-written Claude workflows with generated ones (tend) (#1676)
## Summary

- Replaces 7 hand-written Claude CI workflow files with 6 generated by
`uvx tend init` from `.config/tend.toml`
- Consolidates 5 project-specific skills (`review-pr`, `triage-issue`,
`fix-ci`, `nightly-cleaner`, `running-in-ci`) into a single
`running-tend` overlay skill that extends the generic skills now in the
`tend` repo
- Moves `review-reviewers` skill to the `tend` repo (it's not
project-specific)
- Adds `.github/actions/claude-setup` composite action for project setup
steps
- Adds `.github/tend-security-model.md` documenting worktrunk-specific
security configuration
- Deletes `claude-hourly-review-reviewers.yaml` (moved to tend repo)

The generated workflows are produced by the
[tend](https://github.com/max-sixty/tend) generator, which handles
triggers, conditions, engagement verification, checkout, and the
composite action invocation. Project-specific config (bot name, secrets,
setup steps, watched workflows, cron schedules) lives in
`.config/tend.toml`.

Net: -1585 lines. The deleted code is now in the `tend` repo as reusable
infrastructure.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-23 21:15:53 -07:00
Maximilian Roos 0787a96a5e feat(ci): add rolling survey to nightly cleaner (#1522)
The nightly cleaner only reviews commits from the past 24 hours — code
that hasn't changed recently never gets a fresh look. This adds a
rolling survey phase that reviews ~10 existing files per night, covering
the full repo every 28 days.

Each file is deterministically assigned to a day via `cksum(path) mod
28`. A new script (`.github/scripts/todays-survey-files.sh`) outputs
today's slice. The cleaner reads each file and looks for bugs, stale
docs, dead code, simplification opportunities, missing tests, and
guideline drift.

Also fixes the early-exit behavior: quiet days (no commits in 24h) now
skip only the diff review, and still run issue management and the
survey.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-14 14:18:38 -07:00
worktrunk-bot d46c49dc6b fix(ci): remove CLICOLOR_FORCE=1 from Claude workflows (#1347)
## Summary

- Remove `CLICOLOR_FORCE: 1` from all 7 Claude workflow env blocks
- Simplify `list-recent-runs.sh` (no longer needs to unset
`CLICOLOR_FORCE`)

`CLICOLOR_FORCE=1` overrides `NO_COLOR` per the clicolors spec, causing
`gh` to emit ANSI color codes in JSON output even in non-TTY contexts.
This breaks `jq` parsing in 5 of 9 review sessions (2-5 wasted tool
calls each). `CARGO_TERM_COLOR: always` already handles cargo output
coloring.

Fixes #1346

## Test plan

- [ ] Verify `gh api ... | jq` works without ANSI codes in next review
session
- [ ] Verify `cargo test` still shows colored output (controlled by
`CARGO_TERM_COLOR`)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 15:17:23 -08:00
worktrunk-bot 05d37ad459 fix(ci): unset CLICOLOR_FORCE so NO_COLOR takes effect (#1325)
## Summary

- Unsets `CLICOLOR_FORCE` in `list-recent-runs.sh` before setting
`NO_COLOR=1`
- `CLICOLOR_FORCE=1` (set by the Claude Code environment) overrides
`NO_COLOR` per the [clicolors spec](https://bixense.com/clicolors/),
causing `gh` to emit ANSI codes in JSON output that break `jq` parsing

Fixes #1324

## Context

PR #1317 added `NO_COLOR=1` to fix ANSI codes in `gh` output, but the
Claude Code environment also sets `CLICOLOR_FORCE=1` which takes
precedence. Every hourly review run fails at startup because
`list-recent-runs.sh` can't parse the colorized JSON.

## Test plan

- [ ] Hourly review runs should no longer fail with `jq: parse error:
Invalid numeric literal`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 19:00:14 -08:00
worktrunk-bot 935279f0fd fix(ci): use NO_COLOR to prevent ANSI codes in list-recent-runs.sh (#1317)
## Summary

- Sets `NO_COLOR=1` in `list-recent-runs.sh` to prevent `gh` from
emitting ANSI escape sequences
- Fixes `jq: parse error: Invalid numeric literal` failures in the
hourly review workflow

Fixes #1315.

## Evidence

Run
[22777859584](https://github.com/max-sixty/worktrunk/actions/runs/22777859584)
hit this bug — `gh run list --json` output contained ANSI color codes
(`[1;38m[`, `[32m"skipped"`) that `jq` cannot parse. `gh` respects the
[`NO_COLOR`](https://no-color.org/) environment variable, so setting it
is cleaner than stripping codes after the fact.

## Test plan

- [ ] Script produces valid JSON output in CI environment

---------

Co-authored-by: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 00:01:59 +00:00
worktrunk-bot 4ea395eec6 refactor(ci): extract run-fetching into reusable script with time-window filtering (#1302)
## Summary

- Extracts run-fetching logic into a reusable
`.github/scripts/list-recent-runs.sh` script
- Dynamically discovers `claude-*` workflows instead of maintaining a
hardcoded list
- Uses a two-step time filter: fetches runs started in the past 3 hours,
then keeps only completed runs whose `updatedAt` is within the past hour
(see #1301 for why)
- Simplifies the hourly review workflow prompt to just reference the
script

Fixes #1301

## Test plan

- [ ] Next hourly review run should skip any in-progress jobs without
polling

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 10:30:58 -08:00