Skip to content

docs: add build-test-workflow and cross-revision-benchmark skills#1039

Merged
yingjerkao merged 36 commits into
masterfrom
docs/testing-skills
Jul 13, 2026
Merged

docs: add build-test-workflow and cross-revision-benchmark skills#1039
yingjerkao merged 36 commits into
masterfrom
docs/testing-skills

Conversation

@IvanaGyro

Copy link
Copy Markdown
Member

Problem

Two recurring gaps surfaced while working #853/#506 (OptimalTreeSolver::solve):

  1. No documented procedure for fast edit-compile-test iteration — rebuilding a single target in an existing build dir, running one gtest suite by filter, or wiring a standalone harness against libcytnx.a for a differential/fuzz check. Each of these was re-derived from scratch mid-session.
  2. No documented procedure for a fair cross-revision performance comparison — which files to check out per revision, how to avoid mixing numbers across sessions/machines, and the default scope (base vs tip).

Separately, comparing a heuristic planner's contraction order across revisions surfaced that a tie-break change (which of several equal-cost candidates gets picked) is itself an observable behavior change, not a no-op — CLAUDE.md's existing physics/numerical-correctness guardrail didn't cover it.

Fix

  • Add build-test-workflow (.claude/skills/build-test-workflow/SKILL.md), alongside the existing google-cpp-style / google-python-style skills: accumulated/incremental builds, running ctest/pytest without reconfiguring, per-suite --gtest_filter iteration with the ASAN_OPTIONS workaround, the requirement that a regression test be shown to fail on the pre-fix revision, and the exact link line for a standalone verification harness against libcytnx.a.
  • Add cross-revision-benchmark (.claude/skills/cross-revision-benchmark/SKILL.md): the checkout-files → rebuild-library-only → run → restore-tree procedure, default base-vs-tip scope, and reporting rules (named commits, same session/machine, stated aggregation, flagging baselines whose bugs change how much work they do).
  • Point CLAUDE.md's Test section at both skills.
  • Add a CLAUDE.md guardrail: tie-break/selection-order changes in a heuristic planner are observable behavior and need the same flag-and-sign-off treatment as physics/numerical changes. Mirror it in GEMINI.md's review priorities to keep the two files in sync, per CLAUDE.md's own instruction.

Testing

Documentation-only change (CLAUDE.md, GEMINI.md, two new SKILL.md files) — no buildable code touched, so the build-and-test cycle does not apply. pre-commit run over the changed files passes.

Draft — opening for early feedback on skill scope/content before requesting review.


Generated by Claude Code

IvanaGyro and others added 4 commits July 11, 2026 04:40
Add an agent skill covering fast edit-compile-test iteration: accumulated
incremental builds (rebuild one target in an existing build dir, never delete
build/), running ctest and pytest against already-built binaries, per-suite
--gtest_filter iteration with the ASAN_OPTIONS workaround, how much of the
suite to run while iterating vs before push, the requirement that a regression
test be shown to fail on the pre-fix code, and the link line for compiling a
standalone verification harness directly against libcytnx.a.

Co-Authored-By: Claude <noreply@anthropic.com>
Add an agent skill for fair performance comparisons across git revisions:
keep one fixed benchmark source that calls the library entry point directly,
check out only the differing src/include files per revision and rebuild just
the release library, run Google Benchmark with repetitions and aggregate
reporting, and restore the working tree afterwards. Reporting rules: default
to merge-base vs tip, name the exact commit for every column, run all columns
in the same session on the same machine, state the aggregation, and call out
baselines whose bugs change how much work they do.

Co-Authored-By: Claude <noreply@anthropic.com>
…skills

Point CLAUDE.md's Test section at the two agent skills that carry the
day-to-day mechanics, so agents invoke them instead of re-deriving build,
test, and benchmarking commands.

Co-Authored-By: Claude <noreply@anthropic.com>
Add a guardrail to CLAUDE.md: changing which of several equal-cost candidates
a greedy/heuristic planner picks (e.g. the contraction order chosen by
OptimalTreeSolver) changes user-visible results even though each choice is
individually valid, so such changes must be flagged for sign-off like
physics/numerical changes, and a reviewer's counterexample must be reproduced
on both revisions before it is accepted or disputed.

Mirror the point in GEMINI.md's review priorities so reviews call out
tie-break/selection-order changes instead of silently accepting them, keeping
the two files in sync per CLAUDE.md's own instruction.

Co-Authored-By: Claude <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces two new agent skills, build-test-workflow and cross-revision-benchmark, to document fast iteration and performance comparison procedures. It also updates CLAUDE.md and GEMINI.md to reference these skills and adds guidelines regarding heuristic tie-breaks in planners. The review feedback is highly constructive, pointing out a linker order issue in the standalone compilation example, a potential git checkout failure for newly introduced files, and an inconsistency in the benchmark executable name. All of these suggestions should be addressed to improve the accuracy and robustness of the documentation.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread .claude/skills/build-test-workflow/SKILL.md Outdated
Comment thread .claude/skills/cross-revision-benchmark/SKILL.md Outdated
Comment thread .claude/skills/cross-revision-benchmark/SKILL.md Outdated
Gemini review on PR #1039 flagged three inaccuracies, all confirmed:

- build-test-workflow's standalone harness link line placed -lopenblas before
  -llapacke/-larpack. Verified empirically that both orders link on this
  machine (all three are shared libraries here), but the correct and portable
  convention -- valid for static archives too, where order is not optional --
  is dependents before the library they call into. Reorder to
  -larpack -llapacke -lopenblas -lgomp and say why.
- cross-revision-benchmark's step 1 collected "files that differ" between two
  revisions and step 2 checked them out at each revision. Verified that
  `git checkout <rev> -- <path>` fails with a pathspec error when <path> was
  added by <tip> and does not exist at <rev>, and that checking out the
  containing directory instead avoids the error but does not delete the file
  -- silently leaving <tip>'s version of it in <rev>'s build. Split the diff
  by status (M vs A/D) and restrict the checkout-in-place recipe to M files;
  point A/D cases at the worktree fallback the Preconditions section already
  names for interface changes.
- The harness output name in step 2's benchmark invocation (./bench) did not
  match the -o harness used in build-test-workflow's link line. Renamed to
  ./harness for consistency between the two skills.

Co-Authored-By: Claude <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 57.71%. Comparing base (aa62024) to head (522cc6b).
⚠️ Report is 12 commits behind head on master.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1039      +/-   ##
==========================================
+ Coverage   55.63%   57.71%   +2.07%     
==========================================
  Files         228      229       +1     
  Lines       32896    33468     +572     
  Branches       71       71              
==========================================
+ Hits        18303    19315    +1012     
+ Misses      14573    14132     -441     
- Partials       20       21       +1     
Flag Coverage Δ
cpp 57.64% <ø> (+2.09%) ⬆️
python 63.35% <ø> (+0.26%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
C++ backend 55.47% <ø> (+2.18%) ⬆️
Python bindings 71.99% <ø> (+1.63%) ⬆️
Python package 63.35% <ø> (+0.26%) ⬆️
see 91 files with indirect coverage changes

Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update aa62024...522cc6b. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@pcchen

pcchen commented Jul 11, 2026

Copy link
Copy Markdown
Collaborator

Posted by Claude Code on behalf of @pcchen

Review

Good additions — worth landing. I verified every command, target name, path,
and preset name in both skills against the repo; most check out exactly
(cytnx and pycytnx targets, build/<preset>/hptt/libhptt.a, the
ASAN_OPTIONS string, cpu-only / debug-* preset names, and the link-order
rationale for -larpack -llapacke before -lopenblas). The
regression-test-must-fail-on-pre-fix rule and the honest A/D-file caveat in
the checkout procedure are exactly the hard-won details these files should
carry.

Four accuracy issues. The common thread for 1–3: each is a command or file
reference that fails in a stock master checkout — and these files exist
precisely to be followed verbatim by agents in fresh sessions.

1. benchmarks/search_tree_bm.cpp does not exist on master

(cross-revision-benchmark, Preconditions.) The complete benchmarks/ tree is
benchmarks_main.cpp, Tensor_bm.cpp, UniTensor_bm.cpp, four
algo/*_bm.cpp, ten linalg/*_bm.cpp — no search_tree_bm.cpp, and no
reference to OptimalTreeSolver anywhere under benchmarks/. I assume the
file lives on the #853 branch (#1027), which hasn't merged. The skill presents
it as the worked example of a precondition check, so a future agent will look
for the named file, fail to find it, and either waste a search or start
distrusting the rest of the skill. Cite an existing file
(benchmarks/Tensor_bm.cpp follows the same pattern), mark it "(from #853,
pending)", or phrase the example generically.

2. ninja libcytnx.a assumes a Ninja generator that nothing configures

No preset in CMakePresets.json sets "generator", so a stock configure gets
the platform default — Unix Makefiles on Linux and macOS. In such a build dir
ninja libcytnx.a fails ("loading 'build.ninja': No such file or directory"),
and the Make spelling isn't a name swap either: the Make target is cytnx,
not libcytnx.a, so the "run the generator directly" idea is itself
generator-specific. The phrasing appears three times (build skill twice,
benchmark skill step 2 + its "after each ninja" note). The generator-agnostic
cmake --build build/openblas-cpu --target cytnx form the skills already give
is the one that always works — keep only that, or qualify with "if the build
dir was configured with -G Ninja".

3. benchmarks_main cannot be built in any preset-configured dir

The chain: CMakeLists.txt:188 defaults RUN_BENCHMARKS to OFF;
add_subdirectory(benchmarks) sits inside if(RUN_BENCHMARKS)
(CMakeLists.txt:433); both preset base blocks pin "RUN_BENCHMARKS": "OFF" and
nothing overrides it. So in the exact build/openblas-cpu dir the skill
prescribes, step 2's "either the benchmarks_main target, or a standalone
harness" fails with an unknown-target error on the first option — and the
skill's own (correct) advice not to reconfigure leaves an agent with no path to
it. Enabling the flag also runs find_package(benchmark REQUIRED), which
hard-fails configure when Google Benchmark isn't installed. Suggest one
sentence: building benchmarks_main needs a one-time reconfigure with
-DRUN_BENCHMARKS=ON (requires Google Benchmark installed) — or present the
standalone harness as the default path.

4. "-I build/<preset> covers generated headers" — there are none

The only configure_file in the build is the Doxyfile (CMakeLists.txt:592,
docs-only); a configured build root contains no .h/.hpp outside
CMakeFiles/, and no source includes a build-generated header. The flag is
harmless, but harness link lines are exactly what agents copy verbatim and then
debug when something breaks — a justification that doesn't correspond to
reality invites the wrong fix later. Drop the flag, or keep it with an honest
note ("harmless today; kept in case generated headers appear").

Minor (take or leave)

  • The harness link line is Linux-specific (g++, -lgomp,
    /usr/lib/x86_64-linux-gnu/libbenchmark_main.a). Right default for cloud
    agents — but a one-line note that macOS needs Homebrew paths and -lomp
    would save the next Apple Silicon session some archaeology (I hit exactly
    that delta building locally this week).
  • The build skill lists the CPU presets; mentioning openblas-apple would
    match CLAUDE.md's preset list.

What I explicitly like

  • The tie-break guardrail is a genuinely useful policy addition: a
    heuristic planner picking a different equal-cost candidate is observable
    behavior (different contraction order → different intermediates, memory
    profile, and floating-point rounding), and "reproduce a reviewer's
    counterexample on both revisions before accepting or disputing" is the right
    discipline. The GEMINI.md mirror correctly follows CLAUDE.md's own sync
    instruction.
  • The checkout-procedure failure note (checking out a directory at <base>
    silently leaves <tip>'s added files in the build) names a trap that
    actually costs sessions, and prescribing the worktree fallback instead of a
    workaround is the right call.
  • Frontmatter and scope match the existing google-*-style skills; CLAUDE.md
    pointing at the skills instead of inlining them keeps the main file short.

Recommendation: fix items 1–3 (item 4 optional) and this is good to merge.
On the draft's scope question: the scope is right — fast edit-compile-test
iteration and fair cross-revision comparison are precisely the two procedures
that get re-derived from scratch every session.

… checkout

@pcchen's review on PR #1039 verified every command, target, path, and preset
name against the repo and found four accuracy issues, all confirmed:

- cross-revision-benchmark's Preconditions example cited
  benchmarks/search_tree_bm.cpp, which does not exist on master (it lives on
  the unmerged #853/#1027 branch). Replaced with benchmarks/Tensor_bm.cpp,
  which does exist, and added a note that a comparison needs an existing
  benchmark file covering the function -- add one first rather than writing
  comparison code inline in a scratch harness.
- Both skills presented `ninja libcytnx.a` as equivalent to
  `cmake --build --target cytnx`. Confirmed no preset sets `generator`, and
  `cmake --system-information` on this machine reports the platform default as
  Unix Makefiles, not Ninja, even with Ninja installed -- so a stock preset
  configure does not produce a build.ninja file, and `ninja libcytnx.a` (wrong
  target name for Make besides) only works if that specific build dir happens
  to have been configured with -G Ninja. Kept only the generator-agnostic
  `cmake --build --target cytnx` form as the one safe to assume, and qualified
  the direct-generator shortcut with how to check which generator a build dir
  actually has.
- cross-revision-benchmark's step 2 offered the `benchmarks_main` CMake target
  as an alternative to the standalone harness with no caveats. Confirmed
  RUN_BENCHMARKS defaults OFF in every preset (CMakeLists.txt gates
  add_subdirectory(benchmarks) behind it) and also requires Google Benchmark
  installed via find_package(REQUIRED), so the target does not exist in a
  stock preset-configured build dir. Reordered to present the harness as the
  default path and note benchmarks_main's reconfigure precondition.
- The harness link line's `-I build/<preset>` was justified as "covers
  generated headers". Confirmed the only configure_file in the build is the
  Doxyfile (docs-only) and no build dir contains a generated header outside
  CMakeFiles/. Rephrased as harmless-but-currently-unnecessary instead of a
  false justification.

Also folded in the two minor suggestions: a macOS note (Homebrew paths, -lomp
in place of -lgomp) on the Linux-specific harness link line.

Co-Authored-By: Claude <noreply@anthropic.com>

@IvanaGyro IvanaGyro left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

  1. Consider to implement some scripts for all platform to cover these use cases. So that the bot can directly run the script to build stuff instead of composing the command. Notice that, the the build should use max CPUs, and the generator should be consistent between pip install and cmake. The script should also handle venv properly
    1. build preset openblas-cpu (pip editable install/gtest only)
    2. build preset mkl-cpu (pip editable install/gtest only)
    3. build preset debug-openblas-cpu (pip editable install/gtest only)
  2. Verify if turn RUN_BENCHMARKS on after building will trigger the full rebuild. If it will rebuild, always turn it on.

Comment thread .claude/skills/build-test-workflow/SKILL.md Outdated
Comment thread .claude/skills/build-test-workflow/SKILL.md Outdated
Comment thread .claude/skills/build-test-workflow/SKILL.md Outdated
Comment thread .claude/skills/build-test-workflow/SKILL.md Outdated
Review on PR #1039 asked for a script the bot can run directly instead of
composing pip/cmake commands by hand, covering openblas-cpu, mkl-cpu, and
debug-openblas-cpu in two modes: a pip editable install (enables pytest) and
a direct cmake configure+build (gtest/ctest only, no wheel). Requirements:
max-CPU builds, a generator consistent between the pip and cmake entry
points, and proper venv handling.

Add tools/build_preset.sh:
- `--pytest` creates (or reuses) a venv at build/<preset>-venv and runs
  `pip install --editable '.[dev]'` pinned to that preset's build dir.
- `--gtest-only` runs `cmake --preset <preset>` + `cmake --build --target
  test_main` directly, with BUILD_PYTHON=OFF on a fresh configure only (a
  plain `cmake --preset` needs pybind11 discoverable, which isn't available
  outside a venv, but --gtest-only doesn't need the Python target at all;
  an existing dir a --pytest run already configured with BUILD_PYTHON=ON is
  left untouched).
- Both modes read the CPU count via nproc/sysctl and pass --parallel/-j.
- The generator is never forced against an already-configured build dir
  (only a --gtest-only reconfigure error, from a genuinely mixed dir, would
  need a -G at all); a brand-new dir defaults to Ninja, matching
  pip/scikit-build-core's own default preference, so a --pytest and a
  --gtest-only build of the same fresh preset converge on the same
  generator without needing to agree in advance.

Tested end to end: --gtest-only on a fresh mkl-cpu dir builds test_main;
--pytest on an existing debug-openblas-cpu dir builds a working venv
(pytest passes against it) without touching that dir's already-Ninja
generator; --gtest-only against an existing --pytest-configured dir leaves
BUILD_PYTHON=ON as found.

Also verified empirically (fully-built build/openblas-cpu, `ninja -n`
before/after each toggle): flipping RUN_BENCHMARKS OFF then back ON from a
clean baseline triggers zero pending build steps in either direction. It is
a metadata-only change, not a rebuild trigger, so the script always turns it
(and RUN_TESTS) on rather than requiring a later reconfigure to enable them.

Update build-test-workflow to match:
- Point to tools/build_preset.sh as the default way to build a preset, and
  drop the "delete the build dir and reconfigure" recovery advice for a
  generator/cache mismatch -- recovery is building with --pytest first (so
  the dir starts on Ninja) or reconfiguring with no -G flag to keep the
  existing generator, never deleting a working dir.
- Scope the ASAN_OPTIONS workaround to the debug+CUDA presets specifically,
  not debug presets generally.
- Show running pytest against a specific preset's venv (source
  build/<preset>-venv/bin/activate) instead of a bare `pytest pytests/` with
  no stated venv.
- Add running the GPU test suite (gpu_test_main, ctest --preset
  cpu-and-cuda) when a GPU is actually present, alongside the existing
  GPU-less compile-check guidance.

Co-Authored-By: Claude <noreply@anthropic.com>
Comment thread .claude/skills/cross-revision-benchmark/SKILL.md Outdated
Comment thread .claude/skills/cross-revision-benchmark/SKILL.md Outdated
Comment thread .claude/skills/cross-revision-benchmark/SKILL.md Outdated
Comment thread CLAUDE.md Outdated
….md Test

Three more review points on PR #1039:

1. cross-revision-benchmark's Preconditions punted a changed-API comparison
   to "use worktrees instead" with no concrete procedure, and its checkout
   recipe was file-scoped (split by git diff --name-status) specifically to
   avoid a pathspec error on added files.

   Verified empirically (isolated git worktree, unrelated to any working
   branch): a full `git checkout <rev>` between two commits with a 5-file,
   460-line diff -- including one newly-added file -- left only 7 build
   steps pending in an already-built dir, the same incremental scope as the
   file-scoped approach. Git only rewrites files whose blob content actually
   differs, so a whole-tree checkout is exactly as cheap and additionally
   handles added/removed files correctly with no pathspec error and no
   directory-checkout-leaves-stale-files trap.

   Rewrote the procedure around a git worktree per revision on that basis:
   two named cases (Case A, benchmark source held fixed across revisions --
   overlay the tip's benchmark file *and* benchmarks/CMakeLists.txt, verified
   the CMakeLists.txt overlay is required or the new file silently isn't
   registered in the build, by building the #853/#1027 merge-base commit,
   which predates search_tree_bm.cpp, both with and without it; Case B, each
   revision's own benchmark source, for a changed interface). Worktrees also
   let independent revisions' builds run in parallel and never touch the
   current branch, removing the old restore-at-the-end step.

2. The run step now explicitly covers both benchmark forms: the committed
   Google Benchmark target (benchmarks_main) for any actual Cytnx function,
   and the standalone harness reserved for a language/stdlib question with
   no Cytnx dependency (e.g. std::vector vs std::unordered_set) that doesn't
   belong as a permanent benchmarks/*.cpp file. Builds may run in parallel
   across worktrees; benchmark runs may not, noted explicitly (CPU
   contention between simultaneous runs skews results).

3. Reporting rules now require a commit hash *and* a short readable label
   together for every column -- a bare hash goes stale the moment history is
   rewritten (rebase/squash/force-push), while the label is what the
   comparison is actually about and survives that.

Also: CLAUDE.md's Test section duplicated the build-test-workflow skill's
now-more-detailed mechanics (tools/build_preset.sh supersedes the raw preset
commands it had inline). Trimmed it to match the Coding style section's
existing pattern -- skill pointers plus a condensed list of the essential
project facts (RUN_TESTS requirement, ASan scoped to debug+CUDA, gpu_test_main
vs test_main, GPU-only-if-present, the pip/pytest invocation) -- and noted
that Claude Code's .claude/skills/ auto-discovery is not necessarily
available to every agent this file serves (e.g. Codex), but the files remain
plain markdown any agent can open directly, so the condensed facts are a
fallback rather than the file losing this information for agents that can't
invoke the skill.

Co-Authored-By: Claude <noreply@anthropic.com>

@IvanaGyro IvanaGyro left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Remove standalone benchmark case. Limit the skill to the benchmark will be committed.
Compact the skills. They are too long now.

Comment thread .claude/skills/build-test-workflow/SKILL.md Outdated
Comment thread .claude/skills/build-test-workflow/SKILL.md Outdated
Comment thread .claude/skills/cross-revision-benchmark/SKILL.md Outdated
IvanaGyro and others added 5 commits July 11, 2026 13:51
…ild+test entry point

Move tools/build_preset.sh under the skill directory
(.claude/skills/build-test-workflow/scripts/) and replace its four separate
run modes with one interface: `build_preset.sh <preset> [--target <target>]
[--test [args...]]`.

- `--target` defaults to `all` and picks whether the Python venv/pip-install
  path is needed (only `all`/`pycytnx` do); every other target skips Python
  setup and goes straight to `cmake --build`.
- The pip-install path now always pins `--config-settings=cmake.args=
  --preset=<preset>`. pyproject.toml hardcodes `cmake.args =
  ["--preset=openblas-cpu"]` as its own scikit-build-core default, so without
  this override every pip-driven build silently configured as openblas-cpu
  regardless of the preset the caller asked for.
- `--test [args]` runs the target's tests: pytest args pass through verbatim
  for a Python target (a path/-k filter replaces the default `pytests/`
  collection rather than adding to it), and a single arg becomes
  `--gtest_filter=<value>` against tests/test_main otherwise.
- `debug-*-cuda` presets get ASAN_OPTIONS='protect_shadow_gap=0:
  replace_intrin=0:detect_leaks=0' exported automatically before running
  test_main, instead of requiring the caller to remember the workaround.
- A build dir's generator is decided once by whichever call configures it
  first; the script never reconfigures or deletes an existing dir to fix a
  generator/cache mismatch, and never touches BUILD_PYTHON on a dir that is
  already configured.

Update build-test-workflow/SKILL.md to document this single entry point in
place of the four prior standalone command blocks, and to point the
standalone-harness section at cross-revision-benchmark for any benchmark of
an actual Cytnx function rather than describing that case inline.

Co-Authored-By: Claude <noreply@anthropic.com>
…ons, drop standalone-harness case

Switch the procedure from one worktree/build dir per revision (built in
parallel) to one dedicated worktree with a single shared build dir, switched
sequentially between revisions via `git checkout <rev>` in place. A separate
build dir per revision throws away the incremental-rebuild benefit a shared
dir gets from git only rewriting files whose blob content actually changed
between revisions, and running builds in parallel contends for the same CPUs
a sequential benchmark run also needs undisturbed.

Also remove the standalone-harness / language-feature-benchmark case: the
skill now only covers benchmarking a committed `benchmarks/*.cpp` (the
`benchmarks_main` target), not comparison code written in a scratch harness.

Compact the reporting-rules and case-selection sections.

Co-Authored-By: Claude <noreply@anthropic.com>
…enchmark target support

Replace build_preset.sh's non-Python --test path (a direct
tests/test_main invocation with --gtest_filter) with `ctest --test-dir
<build_dir> --output-on-failure`. test_main and gpu_test_main each
register their gtest cases as individual ctest tests via
gtest_discover_tests, so ctest gives per-test pass/fail output and matches
what CI runs, instead of dumping one binary's raw combined output.
--test-dir is used rather than --preset: CMakePresets.json's testPresets
are hardcoded to only debug-openblas-cpu/debug-openblas-cuda and don't
generalize to every preset the script accepts. A single --test arg now
becomes `-R <value>` (a ctest regex against ClassName.TestName) rather
than a gtest glob/`:`-joined filter.

Add a `--target benchmarks_main` case: since the Google Benchmark binary
has no ctest/add_test registration, --test runs it directly with the
given args passed through as its own CLI flags (e.g.
--benchmark_filter=...).

Let --target accept a space-separated list (e.g. "test_main
gpu_test_main") so the CUDA test suite's two binaries can be built in one
call; cmake --build's --target flag itself accepts multiple names.

Update build-test-workflow/SKILL.md to document the ctest/benchmark
behavior and route the GPU-suite instructions through the script instead
of raw cmake/ctest invocations, so ASAN_OPTIONS and the other
per-preset handling the script already does aren't duplicated by hand.

Co-Authored-By: Claude <noreply@anthropic.com>
… commands

- Point to build_preset.sh's actual location under
  .claude/skills/build-test-workflow/scripts/ instead of the old
  tools/ path.
- Replace the `ctest --preset cpu-only` fallback with `ctest --test-dir
  build/<preset> --output-on-failure`: the named testPreset is hardcoded
  to debug-openblas-cpu specifically and doesn't generalize to the other
  presets this fallback is meant to cover.
- Fix the pip install fallback: pin both --preset=<preset> and a
  preset-specific build-dir explicitly instead of the unqualified
  build-dir=build (pyproject.toml's own default silently configures
  openblas-cpu regardless of the intended preset), drop the
  CMAKE_BUILD_TYPE=Debug override since every preset already sets its own
  CMAKE_BUILD_TYPE, and add the venv create/activate step the command
  depends on.

Co-Authored-By: Claude <noreply@anthropic.com>
…through the script

Switch the procedure from a dedicated git worktree to checking out
revisions in place in the main working tree. A fresh worktree starts with
an empty build dir, so its first build is a full rebuild no matter how
small the diff between revisions is -- checking out in place instead
reuses whatever build/<preset> the build-test-workflow script has already
produced from ordinary development, which is what actually makes the
incremental-rebuild property useful. Add the stash-and-restore steps a
main-tree checkout needs that a worktree didn't.

Route every build and benchmark run through build_preset.sh (--target
benchmarks_main, then --target benchmarks_main --test <benchmark args>)
instead of raw cmake/binary invocations, so the script's existing
generator-reuse and max-parallelism handling apply here too.

Drop references to specific issue/PR numbers from the examples in favor
of generic descriptions, since a skill file outlives any single PR.

Co-Authored-By: Claude <noreply@anthropic.com>
@IvanaGyro
IvanaGyro marked this pull request as ready for review July 11, 2026 17:41
@IvanaGyro
IvanaGyro requested a review from pcchen July 11, 2026 17:42

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7c91cc7a9b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .claude/skills/build-test-workflow/scripts/build_preset.sh
…nchmarks_main

CMakeLists.txt runs find_package(benchmark REQUIRED) whenever
RUN_BENCHMARKS is on, regardless of which target is actually being
built. build_preset.sh was passing -DRUN_BENCHMARKS=ON (or the pip
equivalent) unconditionally, so a plain test_main or pycytnx build would
fail at configure time on any machine that never installed Google
Benchmark -- including CI's own native-dependency list, which does not
include it.

Gate RUN_BENCHMARKS on target == benchmarks_main in both the pip and raw
cmake configure paths. For an already-configured, non-fresh build dir
that didn't need it before, reconfigure in place with -DRUN_BENCHMARKS=ON
when benchmarks_main is requested -- the same zero-cost toggle already
relied on for RUN_TESTS, verified here by reusing an existing preset's
build dir and rerunning the benchmark target through it.

Co-Authored-By: Claude <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 40c346055f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .claude/skills/build-test-workflow/scripts/build_preset.sh Outdated
Comment thread .claude/skills/build-test-workflow/scripts/build_preset.sh Outdated
Comment thread .claude/skills/cross-revision-benchmark/SKILL.md Outdated
IvanaGyro and others added 3 commits July 11, 2026 17:56
…not just before ctest

gtest_discover_tests defaults to POST_BUILD discovery, which runs the
freshly built test binary as part of `cmake --build` itself to enumerate
its cases. build_preset.sh only exported the debug-*-cuda ASAN_OPTIONS
workaround in the later test-run block, so a gpu_test_main binary that
needs it could already abort during build-time discovery, before the
script ever reached that block -- e.g. `build_preset.sh
debug-openblas-cuda --target gpu_test_main --test` would fail at the
build step, not the test step.

Move the export to right after target/preset parsing, before any
configure or build happens, and drop the now-duplicate export from the
test-run block.

Co-Authored-By: Claude <noreply@anthropic.com>
… invocation

CI's pytest step (.github/workflows/ci-cmake_tests.yml) runs `pytest
pytests/ --doctest-modules`, and CLAUDE.md documents the same command.
build_preset.sh's default (no --test args) Python test path only ran
`pytest pytests/`, missing --doctest-modules -- a docstring regression
could pass through the script's advertised `--target pycytnx --test`
entry point and only surface later in CI.

Add --doctest-modules to the no-args default. An explicit filter/path
still replaces the default collection verbatim, as documented, and does
not get --doctest-modules added automatically.

Co-Authored-By: Claude <noreply@anthropic.com>
…next checkout

Case A's step 2 leaves benchmarks/<the_bm_file>.cpp and
benchmarks/CMakeLists.txt checked out from <tip> and locally modified
relative to the revision just benchmarked. Without restoring them, the
next iteration's `git checkout <rev>` either refuses (when the local
diff conflicts with <rev>'s own committed content) or, when it can
3-way-merge, silently carries <tip>'s content forward onto the wrong
revision -- verified both failure modes directly: reproduced a case
where the merge succeeds and leaves the wrong (tip's) benchmark file
present after switching to an older revision that never had it.

Add a step to restore the two overlaid files before moving to the next
revision, using `git restore --source=HEAD --staged --worktree` rather
than `git checkout HEAD -- <path>`: when <rev> predates the benchmark
file existing at all, `checkout HEAD -- <path>` errors with "did not
match any file(s) known to git" for a path HEAD doesn't have, while
`git restore --source=HEAD` correctly deletes it to match HEAD's
(absence) -- verified both the failing command and the working one
directly in an isolated worktree.

Co-Authored-By: Claude <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 34df70ad31

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .claude/skills/build-test-workflow/scripts/build_preset.sh Outdated
Comment thread .claude/skills/build-test-workflow/scripts/build_preset.sh Outdated
Comment thread .claude/skills/cross-revision-benchmark/SKILL.md Outdated
…E-relative path

The BASH_SOURCE-relative path count breaks the moment the script is
invoked from a copy living outside its normal
.claude/skills/build-test-workflow/scripts/ location -- e.g.
cross-revision-benchmark needs a stable copy of the script that survives
checking out revisions predating the script's own existence in the tree,
and the copy's repo-root computation would resolve to the wrong
directory entirely.

Use `git rev-parse --show-toplevel` instead: it only depends on the
caller's cwd being inside the target repo, not on where the script file
itself lives. Verified by running a copy from /tmp against this repo
while cwd stayed at the real repo root.

Co-Authored-By: Claude <noreply@anthropic.com>
IvanaGyro and others added 2 commits July 11, 2026 18:09
…hes the target

An existing (non-fresh) build dir was only ever reconfigured in place for
--target benchmarks_main (to flip RUN_BENCHMARKS on); every other target
just went straight to `cmake --build` with whatever RUN_TESTS state the
dir already happened to have. A dir first created without RUN_TESTS=ON
(e.g. by a plain `cmake --preset ...` outside the script, or a prior
benchmarks_main-only build) has no tests/ subdirectory at all, since
CMakeLists.txt only adds it under `if(RUN_TESTS)` -- so `--target
test_main --test` failed with "unknown target 'test_main'" instead of
building anything. Reproduced directly: build/openblas-cpu had
RUN_TESTS=OFF from an earlier benchmarks_main build in this session, and
`build_preset.sh openblas-cpu --target test_main --test` failed exactly
this way before the fix.

Reconfigure in place for every non-fresh build now, with RUN_TESTS=ON for
every target except benchmarks_main. benchmarks_main is deliberately
excluded: RUN_TESTS adds --coverage instrumentation to the cytnx library,
which benchmarks_main also links against, and that overhead would skew
benchmark timings -- so RUN_TESTS is left untouched (neither forced on
nor off) for that target, and a clean comparison needs a build dir that's
never had RUN_TESTS turned on.

Verified end to end: after the fix, `build_preset.sh openblas-cpu
--target test_main --test` on the same previously-broken dir reconfigures
RUN_TESTS=ON and passes all 1173 tests.

Co-Authored-By: Claude <noreply@anthropic.com>
…visions

Step 1's whole-tree `git checkout <rev>` touches .claude/ along with
everything else. For the common base-vs-tip comparison, <rev> is any
commit before this skill's own build_preset.sh existed in the tree (or
lived at tools/build_preset.sh, a different path), so "$S" pointed at a
path the checkout had just made disappear, and step 3 would fail before
measuring anything.

Copy the script to a stable temp path before the loop starts and use
that copy throughout, relying on build_preset.sh now resolving its repo
root via `git rev-parse --show-toplevel` rather than a path relative to
its own location, so the copy still operates on the right repo. Also
note the RUN_TESTS/coverage-instrumentation interaction from the
build-test-workflow fix: prefer a build dir this skill hasn't shared with
a test_main/pycytnx build, since --target benchmarks_main leaves an
already-set RUN_TESTS=ON untouched.

Co-Authored-By: Claude <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dcfe34b69c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .claude/skills/build-test-workflow/scripts/build_preset.sh Outdated
Comment thread .claude/skills/cross-revision-benchmark/SKILL.md Outdated
IvanaGyro and others added 3 commits July 11, 2026 18:44
gtest_discover_tests defaults to POST_BUILD discovery, which runs the
freshly built test binary as part of `cmake --build` itself to
enumerate its cases. For gpu_test_main (a CUDA-linked binary), this
means the build step itself invokes the binary, which aborts on a
machine with no GPU driver even though the binary compiled and linked
correctly -- contradicting the documented workflow of compile-checking
a CUDA preset without a GPU (CLAUDE.md, build-test-workflow skill).

Switch both test_main and gpu_test_main to DISCOVERY_MODE PRE_TEST,
which defers running the binary to enumerate tests until ctest is
actually invoked, matching the same fix already made for this in the
GPU CI workflow branch. Verified against the CPU suite:
debug-openblas-cpu still discovers and runs individual tests correctly
through ctest -R after this change.

Co-Authored-By: Claude <noreply@anthropic.com>
…n, strip coverage via a launcher

Replace the per-target conditional configure logic (RUN_TESTS forced on
except for benchmarks_main, RUN_BENCHMARKS only for benchmarks_main,
reconfigure-in-place when an existing dir was missing a flag the
current target needed) with a single rule: a fresh build dir's first
configure turns both RUN_TESTS and RUN_BENCHMARKS on unconditionally,
regardless of --target. Every dir this script creates can build
test_main/gpu_test_main/benchmarks_main from then on with no later
reconfigure, at the cost of requiring Google Benchmark to be installed
for any build through this script, not only a --target benchmarks_main
one -- expected on an agent's own dev machine, unlike a minimal CI
runner this script isn't targeting.

RUN_TESTS=ON normally adds --coverage instrumentation to the cytnx
library, which would skew benchmarks_main's timings too since it links
the same library. Add strip-coverage-launcher.sh, wired in via
CMAKE_CXX_COMPILER_LAUNCHER/CMAKE_CXX_LINKER_LAUNCHER at that same
first configure, which strips the literal --coverage token before it
reaches the real compiler/linker -- verified empirically that
-fno-profile-arcs/-fno-test-coverage do NOT cancel --coverage (a .gcno
file is still produced regardless of flag order), so token removal is
what actually works. Verified end to end: reconfiguring
debug-openblas-cpu with the launcher and rebuilding produced zero fresh
.gcno files across 169 recompiled translation units, and the resulting
test_main still built, linked (no gcov runtime), and passed its tests.

Also:
- Use a completion marker, not bin/activate's mere existence, to decide
  whether a Python target's first-build pip install still needs to
  run: `python3 -m venv` creates bin/activate before `pip install
  --editable` ever executes, so a venv left behind by a failed install
  (missing native deps, a compile error) would otherwise look "done"
  and silently skip the pip path on every retry.
- Revert the --doctest-modules default and drop "matches CI"
  framing from the ctest/pytest rationale throughout: this script
  targets an agent's own iteration loop, not CI parity.

Co-Authored-By: Claude <noreply@anthropic.com>
…table script copy

Three fixes to the same recipe:

- Revert the stable-copy-before-checkout step from the previous commit:
  step 1's whole-tree checkout only makes "$S" disappear for a revision
  that predates build_preset.sh's own existence in the tree, which is
  a one-time transitional concern for this branch's own history, not a
  standing property of comparisons entirely within this repo going
  forward. Note it as an edge case (copy the script out first) instead
  of the default recipe.

- Scope the Case A overlay to the one benchmark file under comparison:
  overlaying <tip>'s whole benchmarks/CMakeLists.txt could drag in
  other benchmark sources added or changed after <rev> that don't
  exist or don't compile against <rev>'s API, breaking the build over
  a benchmark that isn't even the one being measured. Only copy the
  .cpp and add its one line to <rev>'s own CMakeLists.txt when <rev>
  doesn't already list it; skip the overlay/restore steps entirely
  when it already does (the common case for an existing benchmark).

- Drop the "prefer a build dir this skill hasn't shared with a test
  build" caveat: build-test-workflow's script now strips --coverage
  from every build it produces (not only benchmarks_main ones), so a
  dir it already built for test_main/pycytnx is safe to reuse here.

Co-Authored-By: Claude <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0089a636f0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .claude/skills/cross-revision-benchmark/SKILL.md Outdated
Comment thread .claude/skills/build-test-workflow/scripts/build_preset.sh Outdated
Comment thread .claude/skills/cross-revision-benchmark/SKILL.md Outdated
IvanaGyro and others added 4 commits July 11, 2026 18:56
…t, not the script's location

coverage_launcher was derived from the running script's own path
(dirname "${BASH_SOURCE[0]}"), which breaks the moment the script is
copied elsewhere -- e.g. cross-revision-benchmark's documented edge
case of copying build_preset.sh to /tmp before comparing a revision
that predates it. A copy at /tmp/build_preset.sh would point CMake at
/tmp/strip-coverage-launcher.sh, which was never copied alongside it,
so the first compile/link through the launcher fails.

Resolve it from repo_root instead, the same way repo_root itself is
now resolved via git rather than the script's location: the real repo
checkout always has strip-coverage-launcher.sh at this fixed path,
regardless of where the running copy of build_preset.sh lives.

Co-Authored-By: Claude <noreply@anthropic.com>
…n CUDA presets

A CUDA preset's shared build dir registers both test_main's and
gpu_test_main's tests once RUN_TESTS=ON (both are added under
tests/CMakeLists.txt's if(RUN_TESTS) block once USE_CUDA=ON), regardless
of which one a given --target actually built. --test-dir alone doesn't
scope a ctest run to just the built binary, so e.g. --target test_main
--test on a CUDA preset would report gpu_test_main's tests as NOT_BUILT
(or, if gpu_test_main happened to be built already, run its tests too)
even though only test_main was requested.

Add a `gpu` ctest label to gpu_test_main's gtest_discover_tests
(tests/gpu/CMakeLists.txt), mirroring the GPU CI workflow's use of the
same label, and have build_preset.sh pick -LE gpu / -L gpu based on
which of test_main/gpu_test_main is actually in the requested --target,
reusing the already-computed target_words array. Verified the -LE gpu
exclusion is a no-op on a CPU preset (no gpu-labeled tests exist there):
build_preset.sh debug-openblas-cpu --target test_main --test
'TypeTest\..*' still filters and passes correctly.

Co-Authored-By: Claude <noreply@anthropic.com>
…rce in Case A

Step 2 only copied <tip>'s benchmark file when <rev>'s own
CMakeLists.txt didn't already list it -- but Case A's entire premise
is one *fixed* benchmark source across every column, so a revision
that already has its own (possibly different) version of the file
must never run that version. Skipping the overlay whenever <rev>
already lists the file meant that column silently ran its historical
benchmark body instead of <tip>'s, mixing a benchmark-code difference
into what should be a pure library comparison.

Copy the .cpp from <tip> unconditionally now; only the CMakeLists.txt
registration stays conditional (skipped when <rev> already lists the
file). Step 4's restore follows the same split: the .cpp is always
overlaid so it's always restored, while CMakeLists.txt is only touched
-- and only needs restoring -- when step 2 also edited it.

Also removed a duplicated paragraph (the git restore vs git checkout
HEAD rationale was stated twice, left over from an earlier edit).

Co-Authored-By: Claude <noreply@anthropic.com>
…t invocation

The default (no-args) pytest path now runs `pytest pytests/
--doctest-modules`, catching doctest regressions (stale/wrong `>>>`
examples in docstrings) through the same --target pycytnx --test entry
point used for the rest of the Python test suite. An explicit
filter/path still replaces the default collection verbatim and does
not get --doctest-modules added automatically.

Co-Authored-By: Claude <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: aa698f0406

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .claude/skills/build-test-workflow/scripts/build_preset.sh Outdated
Comment thread .claude/skills/cross-revision-benchmark/SKILL.md Outdated
Comment thread .claude/skills/cross-revision-benchmark/SKILL.md Outdated
Comment thread .claude/skills/build-test-workflow/SKILL.md Outdated
@IvanaGyro
IvanaGyro marked this pull request as draft July 11, 2026 19:37
IvanaGyro and others added 8 commits July 12, 2026 02:42
gtest_discover_tests's PROPERTIES LABELS only attaches to dynamically
discovered real tests, not to the <target>_NOT_BUILT sentinel test
CMake creates under DISCOVERY_MODE PRE_TEST when a binary is absent at
ctest time. That leaves -LE gpu/-L gpu unable to exclude an unbuilt
sibling binary's sentinel, so the scoping added in b5bb33f does not
actually solve the case it was meant to solve.

build_preset.sh now runs ctest --test-dir unfiltered again and its
--test doc recommends building --target "test_main gpu_test_main"
together on a CUDA preset for a clean run instead.

Co-Authored-By: Claude <noreply@anthropic.com>
…story

DISCOVERY_MODE PRE_TEST is a permanent property of these CMakeLists.txt
files now, not a workaround layered on top of a default; state it as
the current behavior instead of contrasting it with POST_BUILD. Same
for the ASan export: say when it happens, not why an alternative
timing would have been wrong.

Co-Authored-By: Claude <noreply@anthropic.com>
…rk-first ordering

CLAUDE.local.md's rule that a benchmark lands before the change it
measures guarantees the benchmark file and its CMakeLists.txt
registration already exist at every revision worth comparing, as long
as the earliest comparison point is chosen correctly: the commit where
the benchmark landed, or the base branch tip if the benchmark predates
the branch. That removes the need to overlay a fixed benchmark source
onto a revision that lacks it and restore the tree afterward, so the
Case A/B split and the associated git checkout/restore procedure are
gone. The procedure is now a plain sequential checkout-build-run loop
in the main working tree.

Also drops the "comparing against a revision predating this script"
note: the script did not exist before this PR, so there is no earlier
revision to compare against that would hit that case.

Co-Authored-By: Claude <noreply@anthropic.com>
…t -LE

An unbuilt sibling binary's <target>_NOT_BUILT sentinel (registered by
gtest_discover_tests's PRE_TEST discovery mode when the executable is
absent) never gets a PROPERTIES LABELS value, since labels only attach
to dynamically discovered real tests. -LE gpu ("run anything not
labeled gpu") let that unlabeled sentinel through; -L '^cpu$' ("run
only things labeled cpu") excludes it by construction instead, since
it has no label to match.

Re-adds PROPERTIES LABELS cpu/gpu to test_main/gpu_test_main's
gtest_discover_tests calls, and has build_preset.sh pick -L '^cpu$'/
-L '^gpu$' from the requested --target. Also adds --no-tests=error
(supported since CMake 3.25, the repo's floor) so a run that selects
zero tests fails loudly instead of reporting a silent pass, guarding
against the label ever going missing.

Verified against debug-openblas-cpu: -L '^cpu$' selects test_main's
tests correctly (Label Time Summary confirms 5/5 filtered tests ran
under the cpu label), and ctest -L '^gpu$' --no-tests=error against
that same non-CUDA build dir (no gpu-labeled tests exist) exits 8
with "No tests were found!!!" instead of silently reporting success.

Co-Authored-By: Claude <noreply@anthropic.com>
Trim both SKILL.md files down to what an agent needs at decision time:

build-test-workflow keeps the entry-point usage (presets, targets, the
target-dependent meaning of --test args), the two-phase build logic
(editable pip install first for pybind11/dev deps, plain incremental
cmake --build after), the GPU rules (compile check only without a GPU,
run the suite with one, ASAN_OPTIONS handled by the script), the
regression-test-must-fail-on-pre-fix-code rule, and the standalone
harness recipe. Script-internal mechanics (completion marker, generator
consistency, preset pinning, max parallelism) stay documented in the
script itself.

The --coverage-stripping rationale moves out of the testing skill: the
benchmark skill is where uninstrumented builds matter (timing fairness),
and strip-coverage-launcher.sh itself carries the full why. The entry
script's header now just points there.

cross-revision-benchmark is restructured around tip-vs-merge-base as the
default comparison, benchmark-as-first-commit, release presets with
in-place revision switching for incremental rebuilds, strictly
sequential execution, and reporting (label + SHA, aggregation, numbers
into the PR description).

Co-Authored-By: Claude <noreply@anthropic.com>
The Test section duplicated the skills' essential facts for agents
without .claude/skills/ auto-discovery. Supporting such agents is not a
goal, and the duplicated commands drift from the skills they summarize
(the pip/venv recipe already disagreed with what build_preset.sh
actually does). CLAUDE.md now just names the two skills.

Co-Authored-By: Claude <noreply@anthropic.com>
Back into build-test-workflow: never delete a build dir over a
generator/cache mismatch (reconfigure without -G instead), the "how
much to run, when" staging guidance (affected suite while iterating,
full CLAUDE.md gates before push), the literal ASAN_OPTIONS value the
script exports for debug-*-cuda presets, and the macOS variant of the
standalone-harness link line.

Back into cross-revision-benchmark: the correct-baseline caveat -- an
old revision that is buggy in a way that changes how much work it does
is not a fair baseline, and the report must say so.

Co-Authored-By: Claude <noreply@anthropic.com>
A skill's frontmatter description is what an agent reads when deciding
whether to load the skill at all -- the body is only seen afterward. A
topic summary loses that dispatch when the task's phrasing doesn't
overlap it; explicit trigger conditions ("use whenever ... must be
built or tested", "use whenever a performance claim must be made or
checked") match the decision the agent is actually making. CLAUDE.md's
two skill bullets get the same treatment: name the moment to invoke,
not the table of contents.

Co-Authored-By: Claude <noreply@anthropic.com>
@IvanaGyro
IvanaGyro marked this pull request as ready for review July 12, 2026 19:54

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 522cc6b561

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +190 to +191
--config-settings=cmake.args="-DCMAKE_CXX_COMPILER_LAUNCHER=${coverage_launcher}"
--config-settings=cmake.args="-DCMAKE_CXX_LINKER_LAUNCHER=${coverage_launcher}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Add a CUDA compiler launcher for coverage stripping

For fresh CUDA presets this only installs the coverage-stripping launcher for CXX compilations. Fresh evidence since the coverage workaround: cmake --help-command target_compile_options says these options apply to all languages unless guarded by COMPILE_LANGUAGE, and CMAKE_<LANG>_COMPILER_LAUNCHER is per-language and separately supports CUDA, so RUN_TESTS=ON still leaves the top-level --coverage option on cytnx's .cu/CUDA-language sources. That makes CUDA test/benchmark builds either fail under nvcc or remain coverage-instrumented despite the script promising uninstrumented builds; add CMAKE_CUDA_COMPILER_LAUNCHER here and in the raw configure_args path, or make the coverage option CXX-only.

Useful? React with 👍 / 👎.

@yingjerkao
yingjerkao merged commit ed49706 into master Jul 13, 2026
19 checks passed
@yingjerkao
yingjerkao deleted the docs/testing-skills branch July 13, 2026 08:35
yingjerkao added a commit that referenced this pull request Jul 13, 2026
Brings in #1039, #1047 (39 commits). Clean textual merge, but #1026's new
test `UniTensor_baseTest.rank_detects_label_bond_mismatch` desyncs bonds/labels
via `bonds().pop_back()` -- which no longer compiles now that this PR makes the
mutable `bonds()` accessor const (immutable Bond, #846). That desync is
unreachable through the public API by design, so the test now pokes the
internal `_bonds` vector (const_cast) to still exercise rank()'s defensive
size-mismatch guard.

Verified: openblas-cpu + RUN_TESTS build clean (CI's editable-install compile
gate reproduced locally); UniTensor_base/BlockFermionic/Bond gtests 38 passed.

Co-Authored-By: Claude Opus 4.8 (1M context) <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.

3 participants