vibe-qc bug-hunt brief¶
This is the binding operating manual for any chat or contributor running a bug hunt on vibe-qc. If you’re a Claude Code chat that’s been told to bug-hunt vibe-qc, this is your policy document: read it end-to-end before doing any work.
Status: active for the current
mainline (the v0.15 development cycle). Latest tagged release: v0.15.3 (Neese’s Cheetah). Last updated 2026-06-29.
Canonical source is main. This file lives on main and is the
authoritative copy. The release branch is fast-forward-only from a tag
and carries whatever version of the brief shipped with that tag. Always
read it from main:
git fetch origin main
git show origin/main:docs/bug_hunt_brief.md | less
Or consult the canonical copy at
https://vibe-qc.com/bug_hunt_brief.html once the docs site
auto-deploys.
1. Scope (priority order)¶
You hunt for and fix:
Wrong answers: energies, gradients, properties that disagree with PySCF / CRYSTAL / ORCA at validated tolerances. Highest priority.
Crashes / segfaults: anything that exits without a Python traceback.
Ergonomic dead-ends: confusing errors, missing input validation, footguns that lead users into invalid states.
Documentation accuracy: code blocks in tutorials and docstrings that don’t actually run on a clean checkout.
Bias toward (1) before (2 to 4). If you find a (2 to 4) issue while hunting (1), drop a one-liner in your reply rather than getting derailed.
2. Branch model: work on main, never touch release¶
Branch lock
You work on main. Land every fix there (rebase-then-push, § 4).
main is the shared development line and other chats push to it in
parallel, so always git pull --rebase origin main before you push.
You never push to release and never open an MR against it.
release is protected and fast-forward-only: it advances only when the
release chat fast-forwards it to a new tag. You also never cut a tag
(§ 5). GitLab protected-branch and protected-tag rules enforce both, so a
direct push or tag attempt is rejected outright. (CLAUDE.md § 2, § 13.)
3. Setup¶
git clone ssh://git@gitlab.peintinger.com:26/mpei/vibeqc.git
cd vibeqc
git checkout main
./scripts/setup_native_deps.sh
python3 -m venv .venv
.venv/bin/pip install -e '.[test]'
.venv/bin/python -c "from vibeqc.banner import print_banner; print_banner()"
# On main the banner prints the dev version, e.g. 0.15.x.dev0+<sha>
# (a release tag would print Release vX.Y.Z).
Establish the green baseline before any other work. The CI
build-test job is a build-break gate only (canonical bootstrap,
import vibeqc, pytest --collect-only); it runs no tests. The
authoritative full-suite verdict comes from scripts/test_gate/ on a
dev box (per-file isolation plus a known_reds_baseline.json of
pre-existing failures):
python scripts/test_gate/run_full_suite.py # capture pass / skip / xfail
python scripts/test_gate/gate_verdict.py # compare against the known-reds baseline
Record the green baseline. Any new red beyond the known-reds baseline means stop and find out why before touching source. (CLAUDE.md § 2, § 14.)
4. Workflow per bug¶
Reproduce minimally. Reduce to the smallest failing case.
Pin it as a regression test. Add a test to
tests/test_bug_repros.py(create it if missing). It must fail before your fix and pass after; the docstring gives a one-line description plus the reproducing scenario.Fix. Edit the source. Keep the diff small (about 300 lines or fewer, ideally one subsystem). Bigger or cross-subsystem means stop and escalate (§ 6). No papering over periodic-SCF bugs (CLAUDE.md § 7): an oscillation or an impossible (Madelung-scale over-bound) energy is the bug, not a damping-tuning problem.
Run the gate.
scripts/test_gate/run_full_suite.pymust show your new test passing and no new reds versus the § 3 baseline.If you touched docs, build clean:
.venv/bin/sphinx-build -b html docs /tmp/sb
If your work adds anything citable (a method, functional, basis, ECP, linked library) add the entry plus its route to the citation database in the same commit (CLAUDE.md § 8).
Commit. Use this format:
fix(<area>): <one-line summary> <2-4 line problem description: what was wrong, what symptom> <2-4 line fix description: what changed, why it is the right fix> Found via: <e.g. "PySCF cross-check on ZnO / B3LYP / pob-TZVP"> Reproducer: tests/test_bug_repros.py::test_<name> Patch-candidate: v0.15.x # only if it should ride the next patch; omit otherwise Co-Authored-By: <your model identifier> <noreply@anthropic.com>
The
Patch-candidate:trailer is the only channel for asking that a fix ride a patch release; the release chat scansmainfor it (CLAUDE.md § 13). For an already-pushed commit, attach it viagit notesrather than amending (never amend pushed history).Land on
main(rebase-then-push):git fetch origin --quiet git pull --rebase origin main git push origin HEAD:main
After every rebase, re-read what landed (
git log --oneline <last-sync>..origin/main) and re-run the affected tests: parallel chats movemain(CLAUDE.md § 14).
6. Hard escalation gates: STOP and ask before any of these¶
Push or MR to
release(ever). Cut a git tag (ever).A change over 300 lines, or touching more than 5 files unrelated to the bug under investigation.
A new dependency (Python or system): needs a roadmap conversation (CLAUDE.md § 9).
Bumping the major or minor version in
pyproject.toml.Force-push, history rewrite, branch deletion, protected-ref changes, or any hook bypass (
--no-verify) (CLAUDE.md § 2).Bundling, vendoring, or fetching new data without checking its redistribution terms (CLAUDE.md § 1).
Any operation you are not sure is reversible.
When in doubt, escalate. A stop-and-ask is far cheaper than an unauthorized destructive action.
7. Hand-off protocol¶
Findings that need to leave the bug-hunt chat route through the
multi-chat drop-box convention (CLAUDE.md § 3) plus a short note under
bug_repros/notes/<short-name>.md:
Needs feature-level work (new C++ kernel, public-API restructure, anything bigger than a fix): note it, surface tagged
engineering-chat-needed.Bug is in tutorial / docs / website prose (not code logic): note it, surface tagged
docs-chat-needed.Touches periodic-SCF correctness: reproduce against PySCF.pbc.GDF on the same system, file a regression test capturing the symptom, and bring it to the periodic-SCF chat. Don’t fix-and-forget (CLAUDE.md § 7).
bug_repros/notes/ is free-form scratch space that ships with the repo.
8. Reference values for spot-checks¶
These canaries should always pass. If any regress, the bug is upstream of whatever you were hunting: stop, investigate, and report.
System |
Spec |
Expected |
Pinned in |
|---|---|---|---|
H₂ |
STO-3G / RHF |
−1.11675931 Ha |
|
Zn²⁺ |
LANL2DZ ECP / 6-31G / UHF |
matches PySCF to µHa |
|
NaCl |
Madelung constant |
−1.7475645946… |
|
H atom |
any DFT functional / UKS |
⟨S²⟩ = 0.75 |
|
Multi-k Ewald [1,1,1] |
molecular-limit cell |
matches Γ-only to 1e-10 Ha |
|
The former H₂O / 6-31G* RHF canary (
tests/test_h2o.py, −76.0107 Ha) was retired in the test-suite reorganisation. Re-pin it to the current molecular-RHF reference test before relying on it.
9. Stop criteria for a session¶
End and report when you have either (a) made a full pass through the § 10
targets, or (b) accumulated 5 to 10 fixes on main, whichever comes
first. In your reply, surface:
Bugs found / fixed / escalated.
SHAs landed on
main(one-line summary each) plus theirPatch-candidate:trailers.Paths of any
bug_repros/notes/*.mdhand-offs.Recommendation: is the v0.12.x line patch-worthy now, or keep hunting?
Quality over breadth.
10. Active hunt: current main (v0.15 cycle)¶
The high-value hunt areas for the current line. These are the newest,
least-validated surfaces; don’t invent your own targets until you’ve
explored them. Each traces to a CHANGELOG [Unreleased] or v0.15.x
entry: read that entry’s caveats first.
BIPOLE multi-k corrected-gauge exchange. The v0.13 flagship: the q≠0 long-range exchange channels (option (b), Phase 3). Cross-check a real crystal at a genuine k-mesh against the matched-k CRYSTAL reference (the BIPOLE-to-CRYSTAL gate): energies, band gaps, and gauge consistency.
Megacell periodic MP2 + DLPNO-CCSD(T) (local-correlation Stage 6). New periodic correlation via the finite-supercell to molecular route. Check supercell-size convergence of the correlation energy and the molecular limit against canonical MP2 / DLPNO-CCSD(T).
Periodic broken-symmetry: READ / ATOMSPIN / SPINLOCK plus per-spin Fermi-Dirac smearing for multi-k GDF. Drive an antiferromagnetic or ferrimagnetic crystal (NiO, MnO, …) to a broken-symmetry ground state from an
atomic_spinsseed; confirm the spin density, ⟨S²⟩, and that SPINLOCK releases cleanly afterspinlock_iterations.Experimental / gated routes warn and stay gated. Native D4 (defective reference dataset,
D4NativeExperimentalWarning), GPW / GAPW (GAPWExperimentalWarning),caspt2(engine="cases"), and the MSINDO CIS analytic gradient (_experimental=True). Confirm each emits its warning, is genuinely opt-in, and that enabling it never silently changes a default-path result.EWALD_3D retirement and fail-closed behaviour (§ 7 discipline). EWALD_3D is retired as a user route, and Γ-only drivers must fail closed on image-overlapping (tight) cells rather than return a Madelung-scale over-bound energy. Probe tight cells and the
auto_optimize_truncation=Falsecutoff floor: you must get a clear error, never a wrong number.Changed default: Γ closed-shell RHF/GDF
exxdiv='ewald'. The new default targets PySCF parity. Verify it on ionic crystals and confirm no regression versus pre-change reference energies.Periodic analytic gradients. The corrected-gauge Γ analytic gradients (all four drivers) and the multi-k RKS/UKS GGA-σ Pulay fix. Validate analytic forces against finite differences on a GGA system at Γ and at multi-k.
Docs and new public APIs run on a clean checkout. Every tutorial (now descriptive-named, no number prefixes, under
docs/tutorial/) must execute end-to-end. So must the new first-class surfaces: canonical CCSD(T), CCSDtriples=, AutoCIcitype=, periodic Pipek-Mezey / Foster-Boys localization, K6 generalized k-grids, and the CIF / Extended-XYZ readers.
11. Closed hunts¶
Prior hunt lines (v0.4.x through v0.12.x) are closed. Their targets and
known limitations live in each tag’s CHANGELOG.md § Limitations; this
brief tracks only the current main line.