8000 feat(autoindex): add --walk-only so a large tree can be mapped without hashing by xerj-org · Pull Request #2006 · xerj-org/xerj · GitHub
[go: up one dir, main page]

Skip to content

feat(autoindex): add --walk-only so a large tree can be mapped without hashing - #2006

Merged
xerj-org merged 5 commits into
mainfrom
cursor/autoindex-walk-only-894b
Oct 21, 2026
Merged

xerj-org merged 5 commits into
mainfrom
cursor/autoindex-walk-only-894b

Conversation

@xerj-org
Copy link
Copy Markdown
Owner

Fixes #1912

What this changes, and why

xerj autoindex --dry-run walks a tree and then hashes every admitted file. On a large drive that hash is the slow part: the field report behind #1912 (rc.97, mirror #1884) measured about 6 MB/s with eta unknown on a 500 GB Windows tree (219,916 files, 507,811 MB), so the dry run itself was roughly a day. The walk's file counts, sizes and ignore-rule summary were already the useful overview, and autoindex map cannot answer until a real index exists.

--walk-only stops after that same walk. It prints each top-level folder's admitted file count and metadata size, what the ignore rules would drop and which rule, and the totals. It returns before content::resolve_reporting, so it does not hash or sniff file contents and it indexes nothing. --dry-run alone is unchanged: it still hashes, sniffs and prints the plan.

The flag implies --dry-run, so the existing "index nothing" guards stay armed (a pending generation, an object plan-only result, no publish). Combining it with --watch, an explicit --max-minutes / --approve / --yes, --label, map or status is refused. Ignore files are still read, as on every walk; help says that rather than claiming file contents are never opened.

Per-folder ignore lines come from the same record_* counters the walk already updates (IgnoreReport.by_top), not a second walk. IgnoreReport::summary_lines is printed verbatim. Ignored trees are counts, not byte totals: the deep count does not sum sizes.

Evidence

cargo +1.97.1 fmt -p xerj-autoindex -p xerj-server
cargo +1.97.1 test --locked -p xerj-autoindex --lib walk_only_is_accepted_and_dry_run_still_hashes -- --test-threads=8
# test result: ok. 1 passed; 0 failed
cargo +1.97.1 test --locked -p xerj-autoindex --lib walk_only_summarises_without_opening_file_contents -- --test-threads=8
# test result: ok. 1 passed; 0 failed
cargo +1.97.1 clippy --locked -p xerj-autoindex --all-targets -- -D warnings
# Finished `dev` profile, exit 0

The temp-dir test builds a small tree (admitted files, a *.log ignored by .gitignore, and a file inside a pruned target/), walks it with deep counting, and summarises. On Linux it watches the payload files with inotify IN_OPEN|IN_ACCESS and asserts the walk-plus-summary records no open or read, and that the rendered text does not contain the payload bytes.

Earlier in the same session, before a help/changelog wording edit that only changed string literals, these also passed on Rust 1.97.1 with --locked: ignore_rules::tests (18), walk:: (23), cli::tests (69). The parser test above was re-run after that wording edit.

Checks

  • cargo fmt for the crates touched (cargo +1.97.1 fmt -p xerj-autoindex -p xerj-server). Not cargo fmt --all.
  • Scoped release build of the crates touched: cargo build --release -j 32 -p <crate>
  • Relevant cargo test -p xerj-autoindex --lib tests listed above. Not the full crate suite.
  • ES-YAML conformance suite: not applicable. This change is the autoindex CLI and walk summary; no query or index wire behaviour changes.
  • New ES-compatible behaviour: not applicable, same reason.
  • Docs updated: xerj autoindex --help documents --walk-only, and CHANGELOG.md has an Unreleased bullet. landing/llms.txt was left alone.
  • Applicable audit in docs/CONTRIBUTION_REVIEW.md: product contract (--dry-run still hashes; walk-only implies dry-run so pending/object guards stay armed), no new durable field, return is before hashing and before any publish, machine-readable --json uses the same summary struct, and the inotify test pins "did not open contents" rather than only a help string.
  • Operational audit: N/A. This PR does not change an operational document or a runnable recipe.

Not run: cargo fmt --all; cargo build --release -j 32 -p xerj-autoindex; the full cargo test -p xerj-autoindex suite (lib plus integration targets); the ES-YAML runner.

Provenance

  • Written by: AI agent (Grok 4.7, Cursor), run for the account that opened this pull request.
  • Verified (commands run, output observed): the fmt, the two unit tests, and clippy commands in Evidence, all exit 0 on Rust 1.97.1 with --locked. The inotify assertion is inside walk_only_summarises_without_opening_file_contents and that test passed on this Linux host.
  • Assumed (not tested, and what would falsify it): a full xerj autoindex <folder> --walk-only against a running node was not executed, so the early return in run_index_report_inner (stdout summary, stderr note, xerj-done reason walk-only, exit 0) is covered by reading the call site, not by a process test. A hang, a hash progress line, or a non-zero exit on an empty or normal folder would falsify that. The non-Linux arm of the content test does not install an inotify watch; only this Linux run proved the files were not opened.
Open in Web Open in Cursor 

…t hashing

Motivation
----------
`xerj autoindex --dry-run` is the command an agent reaches for before
indexing a drive it has not seen. After the walk it hashes every admitted
file. A field report on rc.97 (issue #1912, mirror #1884) measured that
hash on a 500 GB Windows tree at about 6 MB/s with "eta unknown", so the
dry run itself was roughly a day. The walk's file counts, sizes and
ignore-rule summary were already the useful part, and `autoindex map`
cannot answer until a real index exists.

Root cause
----------
`run_index_report_inner` always continues from the walk into
`content::resolve_reporting`, which opens and xxh3-hashes every admitted
byte, even when `--dry-run` will throw the digests away after printing
the plan. There was no flag that stopped between those two steps.

Fix
---
`--walk-only` reuses that walk and `IgnoreReport::summary_lines`. It
returns immediately after them, before the empty-folder short-circuit
and before hashing. The same `record_*` counters now also keep a
per-top-level-folder breakdown (`by_top`), so the per-folder ignore
lines are not a second walk. Admitted files are grouped by the first
path component of their portable relative path; bytes are metadata
sizes of admitted files only. Ignored trees stay counts, not byte
totals, because the deep count does not sum sizes.

The flag implies `--dry-run` so the existing "index nothing" guards stay
armed (pending generation, object plan-only, no publish). `--dry-run`
alone is unchanged and still hashes, sniffs and prints the plan.
`--walk-only` with `--watch`, an explicit `--max-minutes`/`--approve`/
`--yes`, `--label`, `map` or `status` is refused rather than silently
ignored. Help and the changelog say the walk still reads ignore files
and that hashing and sniffing are what is skipped.

Evidence
--------
`cargo +1.97.1 fmt -p xerj-autoindex -p xerj-server`
`cargo +1.97.1 test --locked -p xerj-autoindex --lib walk_only_is_accepted_and_dry_run_still_hashes` — 1 passed
`cargo +1.97.1 test --locked -p xerj-autoindex --lib walk_only_summarises_without_opening_file_contents` — 1 passed
`cargo +1.97.1 clippy --locked -p xerj-autoindex --all-targets -- -D warnings` — exit 0

The temp-dir test watches the payload files with inotify (IN_OPEN |
IN_ACCESS) and asserts the walk-plus-summary records no open or read,
and that the rendered summary does not contain the payload bytes.

Fixes #1912.

Co-authored-by: xerj-org <xerj-org@users.noreply.github.com>
# Conflicts:
#	engine/crates/xerj-autoindex/src/cli.rs
@cla-bot
cla-bot Bot commented Oct 21, 2026
Copy link
Copy Markdown

Thank you for your pull request and welcome to our community. We could not parse the GitHub identity of the following contributors: Xerj Merger.
This is most likely caused by a git client misconfiguration; please make sure to:

  1. check if your git client is configured with an email to sign commits git config --list | grep email
  2. If not, set it up using git config --global user.email email@example.com
  3. Make sure that the git commit email is configured in your GitHub account settings, see https://github.com/settings/emails

@cla-bot cla-bot Bot removed the cla-signed label Oct 21, 2026
@xerj-org
Copy link
Copy Markdown
Owner Author

Xerj Merger made the fix: I merged main, which now has #2087 and #2102. One conflict in cli.rs: the map/status guard arms. I kept both, so the --walk-only refusal is followed by main's --max-minutes/--approve/--yes/--max-index-size/--plan refusal, and walk_only and the budget fields both go into IndexCfg. I checked the ordering in lib.rs: --walk-only implies dry_run, so the flood-stage refusal from #2087 doesn't apply, and the walk-only exit runs before #2102's budget gate, so a walk-only run never prompts or exits 4 for budget. Local CI on 1080019: cargo fmt --check OK, clippy --workspace --all-targets -D warnings OK, cargo test --profile ci-test --workspace -- --test-threads=2: 5774 passed, 0 failed. No workflow files. Squash-merging.

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.

autoindex --dry-run hashes every file (~6 MB/s on a 500 GB drive); add a walk-only / per-folder size summary mode

2 participants

0