diff --git a/.claude/skills/ci-push-checklist/SKILL.md b/.claude/skills/ci-push-checklist/SKILL.md index caa03801e..b774bbafe 100644 --- a/.claude/skills/ci-push-checklist/SKILL.md +++ b/.claude/skills/ci-push-checklist/SKILL.md @@ -17,6 +17,7 @@ See CLAUDE.md's "Using GitGalaxy's self-scan output for orientation" section for ## 1. Local & Unit Validation (~1 min) * **Standalone Regex Re-test:** Isolate the target regex (e.g., `func_start`) against the failing corpus file manually to ensure false positives and negatives are resolved without affecting real matches. +* **See what the engine actually extracted before re-deriving it from source:** `galaxyscope --db-only --debug --output ` and grep the log for `[WORKER-TRACE] extracted functions for` -- one line per file with the exact satellite/function names produced. Much cheaper than tracing `_slice_by_keywords`/`_slice_by_terminator`/etc. cold when the question is "what did the engine actually name/count here." See CLAUDE.md's "Debugging what detector.py actually extracted from a specific file" for the full recipe (DB cross-reference, etc.) -- not repeated here. * **Extraction Gauntlet & Strict Tests:** Run `pytest tests/extraction/languages/test_.py` and `test__strict.py` for the language you modified. ## 2. Static Analysis & Linting (~15s) @@ -27,6 +28,14 @@ See CLAUDE.md's "Using GitGalaxy's self-scan output for orientation" section for * **Run the Crucible Check (Mandatory):** Execute `python tests/tools/crucible_check.py` against the full ~80-repo corpus. * **Re-Bless Golden Masters:** If `crucible_check.py` shows expected, accurately traced diffs resulting from your fix, bless the new state: `python tests/tools/crucible_check.py --update --yes` + * Always go through `crucible_check.py --update`, never `python tests/tools/update_golden_master.py` + directly -- the latter only updates whichever ONE fixture matches whatever happens to be + importable in your current shell, with no automatic venv/PATH management; `crucible_check.py + --update` runs it once per mode through its own properly-scoped venv, no manual bookkeeping. + * **Claude Code note:** blessing a golden master is exactly the kind of action Auto Mode's + classifier treats as destructive-looking and blocks by default (even via `--yes`, even on a + clean tree where it would be a no-op) -- expect to explicitly ask the user for one-time + permission before this step rather than being surprised mid-task. * **Isolate exactly what your change touched, independent of whether the committed fixture is even current:** `python tests/tools/scope_check.py --expect [,]` scans your working tree AND a comparison ref (default `origin/main`) fresh, in separate venvs, and buckets every difference by language -- fails loudly if anything outside `--expect` changed. This answers "is my diff actually scoped to what I meant to touch" directly, without needing the committed golden master to be current first (useful mid-investigation, or after `main` has moved and the committed fixture reflects a bunch of OTHER PRs' legitimate changes you didn't make). Costs roughly 2x a single `crucible_check.py` run (it builds and scans two venvs, not one) -- background it. * **On the old "never clone a fresh corpus copy" folklore:** a fresh `language-crucible` clone is fine, and both `crucible_check.py` and `scope_check.py` do this routinely (the latter clones a temporary comparison-ref worktree every run). What actually causes massive, invalid-looking diffs is one of two SPECIFIC, now-automatically-checked things, not "metadata" in general (verified by direct repro, PR #2518, 2026-08-30/31 -- see `crucible_check.py`'s own module docstring for the full incident writeups): 1. **Wrong pin.** The corpus isn't on the tag `tests/_crucible_pin.py` names. `crucible_check.py` now warns about this automatically (`_check_corpus_pin`) -- if you see the warning, `git fetch --tags && git checkout ` in the corpus checkout. diff --git a/CLAUDE.md b/CLAUDE.md index 68d6f25ab..d85f2f13e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -150,6 +150,30 @@ diff be" is answered from data instead of a guess informed only by the issue tex `"scala"` key starts inside `language_standards.py`'s `LANGUAGE_DEFINITIONS`) — it's for orientation and prioritization, not symbol lookup. Read the actual file for that. +## Debugging what detector.py actually extracted from a specific file + +Before tracing `_slice_by_keywords`/`_slice_by_terminator`/etc. by hand to understand why a +signal looks wrong for some target file or corpus, check what the engine actually did first — +much cheaper than re-deriving it from the regex/slicing logic cold (#2547: confirmed the exact +root cause — a slicer-synthesized non-function bucket name being miscounted as an orphan — in a +few minutes this way, instead of hours of pure static reading): + +- `galaxyscope --db-only --debug --output ` and grep the resulting log for + `[WORKER-TRACE] extracted functions for` — one line per file, listing the exact satellite/ + function names `_function_slice` produced for it (`detector.py`'s own debug trace, gated + behind `logger.isEnabledFor(logging.DEBUG)`). This is the fastest way to see whether a + suspiciously-named entry (a synthetic bucket, a reused generic keyword, a truncated remnant) + is in play, before assuming the signal count itself is what's wrong. +- Cross-reference the aggregated per-file numbers in the recorder DB this same run produces + (`/_galaxy_master.db`, `file_data` table) — column names are the + `record_keeper.py`-renamed form of the raw equation keys (e.g. `orphaned_logic` → + `state_slop_orphans`, `api` → `arch_api`; confirm via `.schema file_data` since this evolves). +- For a control/golden corpus already checked out locally (e.g. `keyword-rosetta`, + `language-crucible`), point `galaxyscope` straight at it this way instead of writing a + standalone repro script — the census requires git-tracked files (see `census-requires-git- + tracked` in a corpus's own deviation ledger if one exists), so scan the real corpus checkout, + not an ad hoc copy. + ## Adding or hardening a language's structural signatures Full protocol (LLM generation prompt, the 12 numbered engine rules for ReDoS/boundary @@ -211,8 +235,17 @@ expected to be verified against `tests/golden_master_audit.json` / `tests/golden_master_zero_dep_audit.json` — snapshots diffed by the `crucible-audit` CI check against a ~80-repo corpus plus the PR's target repo. A failing diff means output changed: either a bug, or an intentional improvement that needs the baseline re-blessed. **Never hand-edit these -fixtures.** Regenerate with `python tests/tools/update_golden_master.py` (shows the diff, asks -for confirmation) and explain *why* in the PR description — CI flags any PR touching these files. +fixtures.** Regenerate with `python tests/tools/crucible_check.py --update --yes` (default +`--mode both`) — explain *why* the output changed in the PR description, CI flags any PR touching +these files. This handles BOTH fixtures (full-precision and zero-dependency each need their own +venv/interpreter) in one command with no manual `PATH`/`pip install -e .` bookkeeping — see the +"Verifying locally before pushing" paragraph just below for exactly what it automates and why +that matters. `python tests/tools/update_golden_master.py` (`--yes` to skip its own confirmation +prompt) is the underlying single-mode script `--update` shells out to per venv; call it directly +only if you're already inside one specific mode's venv and deliberately want just that fixture — +reaching for it from your default shell silently updates whichever ONE fixture matches whatever +happens to be importable there (#2547: this cost a full investigation cycle before landing on +`crucible_check.py --update` instead). The same PR paths also run `tri-comparison-audit.yml`, a baseline-gated regression check on GitGalaxy's own **validated** precision against tree-sitter+ctags (see `docs/self_scan/