Skip to content

fix(devx): R3-1 - one truthful build path for every test runner - #422

Merged
pftg merged 3 commits into
masterfrom
claude/devx-r3-harness-truth
Jul 31, 2026
Merged

fix(devx): R3-1 - one truthful build path for every test runner#422
pftg merged 3 commits into
masterfrom
claude/devx-r3-harness-truth

Conversation

@pftg

@pftg pftg commented Jul 31, 2026

Copy link
Copy Markdown
Member

What

Round-3 DevX: make the local test harness truthful and fast. All four test runners (bin/test, bin/qtest, bin/dtest, bin/dtest-all) now build through one shared helper, and the lies the multi-agent audit found are fixed:

  • New bin/build-if-stale <dest> [base-url]: routes every test build through bin/hugo-build (PurgeCSS cold-start warm-up guard — the 2026-07-19 .sr-only incident class) and skips the rebuild when the dest tree is newer than every source tree. Staleness probe now also watches assets/, static/, package.json, bun.lockb (previously blind to badge/static-asset edits). FORCE_BUILD=1 overrides.
  • bin/test no longer breaks bin/dtest: DEST honors a caller-preset HUGO_DEFAULT_PATH, and the build is skipped entirely when PRECOMPILED_ASSETS is already set — previously it exported _dest/public-test over the container's _dest/public-dtest and pointed the Docker suite at the wrong tree (or hugo: command not found on a stale one).
  • bin/qtest shares bin/test's warm tree (_dest/public-test): the per-micro-commit gate stops paying a ~26s private rebuild on every invocation (measured warm skip: 0.02s).
  • bin/qtest --changed counts untracked files: a brand-new pages/foo.css previously produced "no visual-affecting changes" and a false green exit 0.
  • Pre-push hook rescued into the repo: the R2 hook ran two test files in one ruby invocation (only the first executes — the guard suite was silently skipped), now split into two invocations. Bigger find: the hook file itself had never been committed — the .gitignore .* rule swallowed .githooks/, so every fresh clone had core.hooksPath pointing at nothing. Added the !.githooks negation and committed the hook.
  • 3 new bin_scripts_test guards: no bare hugo --environment production outside hugo-build/build-if-stale; pre-push must not pass multiple test files to one ruby; bin/test must default DEST from HUGO_DEFAULT_PATH.
  • Doc truth: bin/README.md listed four scripts that don't exist and omitted eleven that do — rewritten to match the directory. .okf test-gates concept updated (drops the stale "CI does NOT run screenshot diffs" claim, superseded by ci(visual): R2 Phase B - screenshot tests on the pinned rendering stack + report-only PR gate #413/fix(ci): make the visual harness truthful - build drafts, allow first baselines #417) + log entry.
  • Removed 3.7 GB of orphan _dest/public-test-[0-9] trees left by the old rand(5) bucket fan-out (local cleanup, not in the diff).

Verification

  • bundle exec rake test:unit: 278 runs, 0 failures (275 pre-existing + 3 new guards); new guards verified red against the reverted patterns.
  • Warm path: bin/build-if-stale _dest/public-test twice — second run skips in 0.02s; touching a content file correctly re-triggers a build.
  • Untracked trigger: touch themes/beaver/assets/css/pages/zzz-fake.css → qtest sees it and aborts loudly (exit 1) instead of exiting 0 green.
  • Scoped bin/qtest homepage end-to-end on the pinned rendering stack: reused the warm tree, ran the scoped tests, and the dirty-baseline guard fired as designed. (The screenshot diffs themselves are the known old-baselines-vs-pinned-stack gap that the post-fix(ci): rebase before pushing recorded baselines (push race) #418 baseline re-record closes — environmental, reproduced identically in CI on master.)
  • bash -n / ruby -c clean on all edited scripts; pre-push hook ran green on the push of this branch.

Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Added smarter site builds that reuse up-to-date output and support custom destinations and base URLs.
    • Improved test workflows with shared build output, configurable paths, and detection of untracked files.
    • Added a pre-push validation hook with progress reporting and actionable failure messages.
  • Documentation

    • Expanded the script inventory and updated testing guidance to reflect current build and screenshot workflows.
  • Tests

    • Added safeguards for approved build execution, test-file handling, and configurable site output paths.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@pftg, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 53 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f2ba7202-8e6c-4eb1-8dfe-4cd207802d3d

📥 Commits

Reviewing files that changed from the base of the PR and between 36b49ab and 2884549.

📒 Files selected for processing (4)
  • .githooks/pre-push
  • Rakefile
  • bin/build-if-stale
  • test/unit/bin_scripts_test.rb
📝 Walkthrough

Walkthrough

The PR adds a repository-root pre-push validation hook, centralizes stale Hugo builds across test scripts, improves changed-file detection, documents the script inventory and test gates, and adds guard tests for build and hook behavior.

Changes

Build and validation workflow

Layer / File(s) Summary
Shared build routing
bin/build-if-stale, bin/dtest, bin/dtest-all, bin/qtest, bin/test, test/unit/bin_scripts_test.rb, bin/README.md, .okf/build/test-gates.md, .okf/log.md
Build and test scripts now use shared stale-build handling, configurable Hugo destinations, and shared test output. qtest includes untracked files in changed-file detection. Documentation and guard tests describe and verify the updated workflow.
Pre-push checks and hook tracking
.githooks/pre-push, .gitignore, test/unit/bin_scripts_test.rb
The pre-push hook runs CSS, course, toolchain, and bin-script checks, supports SKIP_CHECKS=1, and reports failures. Git tracking preserves .githooks/, and tests verify separate Ruby test-file execution.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: consolidating all test runners onto one truthful build path.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/devx-r3-harness-truth

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pftg
pftg marked this pull request as ready for review July 31, 2026 15:22
claude added 2 commits July 31, 2026 15:27
All four runners (test/qtest/dtest/dtest-all) now build through a shared
bin/build-if-stale helper that routes via bin/hugo-build (PurgeCSS
cold-start warm-up guard) and skips the rebuild on a warm tree:

- bin/test: DEST honors a caller-preset HUGO_DEFAULT_PATH and the build
  is skipped entirely under PRECOMPILED_ASSETS - un-breaks bin/dtest,
  whose container has no hugo and points at _dest/public-dtest
- bin/qtest: shares bin/test's _dest/public-test tree (warm reruns skip
  the ~26s rebuild it previously paid on every micro-commit), and
  --changed now counts untracked files (a brand-new pages/foo.css no
  longer exits 0 green with 'nothing to run')
- staleness list gains assets/ static/ package.json bun.lockb
- .githooks/pre-push: run each unit-test file in its own ruby
  invocation (ruby file1 file2 executes only file1) - and commit the
  hook itself: the .* gitignore rule had kept it out of the repo, so
  fresh clones got a hooksPath pointing at nothing (added !.githooks)
- bin_scripts_test: 3 new guards - no bare 'hugo --environment
  production' outside hugo-build/build-if-stale, pre-push multi-file
  ruby anti-pattern, bin/test HUGO_DEFAULT_PATH contract

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PXHeUErqoiyH9xN1mjC8cH
bin/README.md listed four scripts that do not exist (debug,
benchmark-dev, bunx, generate-cover-image) and omitted eleven that do
(qtest, dtest-all, setup-test-env, build-if-stale, hugo-build, ...).
Rewritten to match the actual directory contents.

.okf test-gates: drop the stale 'CI does NOT run screenshot diffs'
claim (superseded by #413/#417), record the shared build-if-stale
warm-tree flow, qtest untracked-file detection, and the .gitignore
dot-path gotcha that had kept the pre-push hook out of the repo.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PXHeUErqoiyH9xN1mjC8cH
@pftg
pftg force-pushed the claude/devx-r3-harness-truth branch from 7a106a7 to 36b49ab Compare July 31, 2026 15:28

pftg commented Jul 31, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review


Generated by Claude Code

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

@pftg I will review the changes in #422.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.githooks/pre-push:
- Around line 27-32: Replace the direct Ruby invocations for
toolchain_pins_test.rb and bin_scripts_test.rb in the pre-push hook with a
repository-owned guard test task, and invoke that task through the project’s
bin/rake or another established test entrypoint. Add the task to the project’s
test configuration, then preserve the existing failure handling and descriptive
fail messages.

In `@bin/build-if-stale`:
- Around line 21-23: Update the stale-check logic around newest_src to detect
deletions within the watched source trees, rather than relying only on existing
files. Include directory timestamps or use a successful-build manifest so
removing a watched file marks the output stale, and add a regression test
covering deletion of a watched source file.

In `@test/unit/bin_scripts_test.rb`:
- Around line 47-78: Replace the source-text assertions in
test_no_bare_production_hugo_builds_outside_hugo_build,
test_pre_push_hook_runs_each_test_file_separately, and
test_bin_test_honors_preset_hugo_default_path with behavior-focused executions
using controlled commands or stubs. Assert the observed Hugo build routing, that
the pre-push hook runs each test file, and that bin/test uses a caller-provided
HUGO_DEFAULT_PATH, without relying on script text, file existence, assignments,
or invocation-pattern checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 4f16cac6-c71a-4d93-823d-9828a35cceb3

📥 Commits

Reviewing files that changed from the base of the PR and between c925275 and 36b49ab.

📒 Files selected for processing (11)
  • .githooks/pre-push
  • .gitignore
  • .okf/build/test-gates.md
  • .okf/log.md
  • bin/README.md
  • bin/build-if-stale
  • bin/dtest
  • bin/dtest-all
  • bin/qtest
  • bin/test
  • test/unit/bin_scripts_test.rb

Comment thread .githooks/pre-push Outdated
Comment thread bin/build-if-stale
Comment thread test/unit/bin_scripts_test.rb
- New `rake test:guards` task (toolchain pins + bin scripts, ~2s) is the
  pre-push hook's single test entrypoint - repo-provided command instead
  of direct ruby file invocations, and structurally immune to the
  multi-file-ruby trap
- bin/build-if-stale staleness probe now includes directory mtimes:
  deleting a source file leaves nothing to be -newer, but bumps its
  parent dir - verified warm tree goes stale on a removed content file
- pre-push guard test asserts the rake entrypoint is present (no longer
  passes vacuously if the hook drops its test invocation)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PXHeUErqoiyH9xN1mjC8cH
@pftg
pftg merged commit 11ee50c into master Jul 31, 2026
4 of 5 checks passed
@pftg
pftg deleted the claude/devx-r3-harness-truth branch July 31, 2026 16:07
pftg added a commit that referenced this pull request Jul 31, 2026
Correctness:
- hugo_stats.json gets its own EXACT-key-only cache (no restore-keys):
  a partial hit restored a stale stats file from an older tree, and the
  warm-up skip trusted it - PurgeCSS could purge classes live in the
  current tree (the 2026-07-19 .sr-only incident class, re-opened via
  cache). Exact hit = identical tree = valid stats
- test.yml PR runs check out the MERGE commit (default checkout);
  head_ref tested the tip without the base and breaks fork PRs. Record
  dispatches still check out the branch ref (needed for the push)
- record mode runs rake test:system (not the full suite - a unit
  failure used to abort AFTER 15+ min of recording), and the commit
  step is always()-gated + porcelain-guarded so recorded PNGs land even
  when one page's test is red
- visual + link-check paths filters gain root layouts/** and assets/**
  (root-level overrides skipped both gates)

Cost:
- sync fan-out gated: publish.yml and link-check.yml workflow_run jobs
  skip when the sync pushed nothing (head_sha == current master head) -
  'Sync articles' fires every 10 min 8-21 UTC and mostly commits
  nothing; that was ~84 no-op deploy+test cascades per day
- _dest dropped from the setup-hugo cache (~1-2 GB per job, evicting
  every other cache from the 10 GB quota; the build regenerates it)
- link-check builds ONCE: composite runs with build:'false', rake
  test:links does its own production build - the double build blew the
  10-minute timeout on cold caches (seen live on PR #422)


Claude-Session: https://claude.ai/code/session_01PXHeUErqoiyH9xN1mjC8cH

Co-authored-by: Claude <noreply@anthropic.com>
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