Skip to content

fix(crawl): --grep no longer scans gitignored files the indexer skips — the leak was in the crawl, not the verb - #87

Merged
joyful-ii-V-I merged 3 commits into
mainfrom
claude/beautiful-tu-163424
Sep 9, 2026
Merged

fix(crawl): --grep no longer scans gitignored files the indexer skips — the leak was in the crawl, not the verb#87
joyful-ii-V-I merged 3 commits into
mainfrom
claude/beautiful-tu-163424

Conversation

@joyful-ii-V-I

Copy link
Copy Markdown
Collaborator

--grep was scanning files the crawl had already decided not to index.

The leak was upstream of the verb, in the crawl: recordPreSizeDrop and collectSources in src/ingest_crawl.h admitted gitignored files whose extension the indexer does not handle, so --grep walked and read them. grepCollectAux itself was never wrong — it was being handed the wrong file set. docs/ARCHITECTURE.md §1 said ".gitignore is not consulted", which had been stale since N6-C; that paragraph is corrected, and the documented directory denylist was cross-checked entry-for-entry against kCrawlSkipDirs (22 names, including cmake-build-* and the CMakeCache.txt sentinel).

test/grepignorecheck.sh is the gate. Gate count 569 → 570.

Scope, honestly reported: §2–§5 of docs/ARCHITECTURE.md (data model, determinism, honesty, the two build flavours) were not audited and are unreviewed rather than clean.


A gate-header prose leak, and the vector is worth naming. This lane's first push put the private validation corpus's name into test/grepignorecheck.sh's own header — the paragraph describing the defect the gate measures cited the corpus and its directory. Not run output, not a path: documentation. It was scrubbed forward at 3d9ea048, and it is squash-merged here because 4c249fd0 still carries the name in the branch's history.

Three of nine lanes in this round leaked that string, by three different routes — benchmark run output, a commit's absolute paths, and this one. The general rule the round settled on: a gate header may name what it measured and how, never where — unless the corpus is public, in which case name it.

The rebase found a trap that has been recorded. Rebasing onto a main that had moved twice, git auto-merged README and EVALS (this branch's 570 survived) and conflicted only on the deck — because whether a count site conflicts depends on the surrounding lines, not the number. A uniform "take upstream, then bump" therefore reset only the deck to 569 while README and EVALS already read 570, and the bump script aborted on its own precondition without the shell stopping. Caught from git show HEAD:present/deck5_ripwire_build.js rather than from the worktree. The recipe fix: reset every count file explicitly from origin/main before bumping.

Also from this lane, now a durable note: the "900 s macOS timeout" that the h2h-graft round recorded without a name is runner starvation. Job wall 3,070 s against 1,474 s / 1,903 s on green main runs; ripwirepubliccheck 607 s on macOS against 79 s on ubuntu in the same run; the timing-out gate costs ~54 s locally. Compare the job's wall before debugging an rc=124, and never raise the gate's budget.

Verified before landing: tip contains current main; CI run 34410923221 26/26 green on the exact tip; gate count re-derived on the tip and all eight published sites confirmed at 570 from the commit (git show HEAD:), not the worktree; manifestcheck re-derived both sides independently and agreed; qschemetripcheck unchanged; leak sweep clean.

🤖 Generated with Claude Code

joyful-ii-V-I and others added 3 commits September 9, 2026 18:07
… — the unsupported-ext class consults the ignore verdict before it records a row

--grep/--regex additionally scan the crawl's unsupported-ext, text-looking population
(CrawlSkips::unsupported) and print those hits in the trailing <unindexed> block. That population was
recorded before the ignore set was consulted: collectSources classified the extension first
(recordPreSizeDrop) and asked git only about files that survived, so a file that was BOTH gitignored
AND of an unindexed extension was rowed as unsupported-ext and grep read it. Measured 2026-09-09:
--regex='^#include' --grep-in=any served four hits from a .cpp.bak the repository's own .gitignore
names (rg does not open it), and unindexed_files_scanned= / unsupported_ext= both counted it.

The fix keeps the ordering contract (the ignore lookup stringifies the path, so it is still not paid
for a binary asset or an --exclude'd file) and adds ONE consult for ONE class: the unsupported-ext
branch asks a lazy `ignored` predicate — the same predicate the indexable-file test already uses,
now defined once — before it records a row, and records nothing when the answer is yes. The file is
then in NO class, exactly as an --exclude'd unsupported-ext file already was: not unsupported-ext
(grep serves that list), and not ignored= (that counter describes only what would otherwise have been
indexed, the number the header's accounting invariant carries). --no-ignore makes the predicate
false, so the escape hatch restores the row and both counts with it.

Gate first: test/grepignorecheck.sh (written RED — arms A B C D G failed on the pre-fix binary,
every mutation control fired) pins the served set against an independent oracle
(`git ls-files -co --exclude-standard` piped to grep -l, plus rg where present), on both --grep and
the report's own --regex='^#include'; that unindexed_files_scanned= and the skipped verb's
unsupported_ext= describe what was actually scanned; that a tracked file matching the pattern and an
untracked-but-unignored file are still served (git's rule, not rg's textual one); the --no-ignore
and non-git escape hatches; the MCP grep twin; determinism; xmllint. Absorbed into regression.sh's
loop; the eight stated gate counts move 563 -> 564.

Also: the skipped legend's definition of unsupported_ext= now names both exclusions; ARCHITECTURE.md
still said ".gitignore is not consulted", which has been false since the N6-C lane — corrected.

Replayed on the reporting corpus (read-only, --no-cache): default run 0 hits in the .bak,
unindexed_files_scanned 409 -> 52 (+140 skipped = unsupported_ext 192, reconciled); --no-ignore
still serves it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…eader — ripwirepubliccheck arm 1

The header's measured-defect paragraph named the private validation corpus and its directory; CI run
34359885383 (Release clang shard 3/4) failed ripwirepubliccheck.sh arm 1 on it, the one gate that sweeps
every tracked file for exactly this. Fixed forward, not rewritten: the name stays in this branch's history
at 4c249fd, which makes the branch a squash-merge candidate at landing (the owner's call, as for the
tgrep and codeburn lanes this round). Wording only; the gate's arms and its fixture are untouched.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…569 -> 570 at the eight stated sites

The loop in test/regression.sh names 570 with grepignorecheck absorbed; the number is derived from the
loop on this tip, never carried from an earlier base (this lane and the tgrep lane both derived 568
against the same 567 main, each correct in isolation, and identical text at all eight sites merges
cleanly and silently). Sites: README.md x2, docs/EVALS.md x3 (incl. the §8 prose line),
present/deck5_ripwire_build.js x3. test/manifestcheck.sh green at 570.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@joyful-ii-V-I
joyful-ii-V-I merged commit c38d3ee into main Sep 9, 2026
52 of 53 checks passed
@joyful-ii-V-I
joyful-ii-V-I deleted the claude/beautiful-tu-163424 branch September 9, 2026 22:47
@coderabbitai

coderabbitai Bot commented Sep 9, 2026

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 801c5172-3a56-48ac-b97b-8781b0157f62

📥 Commits

Reviewing files that changed from the base of the PR and between 595c819 and 4e4e070.

📒 Files selected for processing (9)
  • README.md
  • docs/ARCHITECTURE.md
  • docs/EVALS.md
  • present/deck5_ripwire_build.js
  • src/ingest_crawl.h
  • src/model.h
  • src/verbs_report.h
  • test/grepignorecheck.sh
  • test/regression.sh

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting


📝 Summary

Summary by CodeRabbit

  • Bug Fixes

    • Git-ignored files are now excluded from crawl and auxiliary grep/regex scans when repository ignore rules apply.
    • Unsupported-extension and ignored-file counts no longer double-count files.
    • --no-ignore continues to include Git-ignored files, and non-Git scans remain unchanged.
  • Documentation

    • Updated ingest and skipped-file reporting guidance to clarify Git-ignore behavior and file-count categories.
    • Updated documented validation-suite totals from 569 to 570.
  • Tests

    • Added regression coverage for Git-ignore handling across command-line and MCP grep workflows.

Walkthrough

The crawl now applies Gitignore results before recording unsupported-extension drops. A new regression gate verifies CLI and MCP grep behavior, no-ignore behavior, non-Git roots, reporting, and deterministic output. Documentation and presentation references update the gate count to 570.

Changes

Gitignore-aware grep scanning

Layer / File(s) Summary
Crawl ignore accounting
src/ingest_crawl.h, src/model.h, src/verbs_report.h, docs/ARCHITECTURE.md
The crawl evaluates Gitignore status before recording unsupported-extension drops. Reports and documentation describe the resulting population.
Grepignore regression gate
test/grepignorecheck.sh, test/regression.sh
The new gate verifies ignored-file exclusion across CLI and MCP scans, --no-ignore, non-Git roots, counters, XML, and repeatability.
Gate count references
README.md, docs/EVALS.md, present/deck5_ripwire_build.js
Gate-script references change from 569 to 570.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Grep
  participant Crawl
  participant Git
  participant Report
  Grep->>Crawl: request source scan
  Crawl->>Git: evaluate Gitignore status
  Git-->>Crawl: ignored or not ignored
  Crawl->>Report: record eligible unsupported files
  Report-->>Grep: return files and scan counters
Loading

Suggested reviewers: mfreeman451, quaterniondrift, andriytyurnikov

✨ 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/beautiful-tu-163424

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

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.

1 participant