fix(hashing): op.Directory hashing now uses FileHasher cache (ITL-511)#215
Conversation
…file cache (ITL-511) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Document the file_hasher injection requirement for BasicDirectoryHasher in the v0.1 context changelog.
…ryHasher in tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wire the same CachedFileHasher into DirectoryHandler so that op.Directory traversal consults the per-file cache. A file cached via op.File hashing is a cache hit during directory traversal.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
…uses-filehasher-cache-document
There was a problem hiding this comment.
Pull request overview
This PR fixes op.Directory hashing so it reuses the injected FileContentHasherProtocol (and therefore the file-hash cache) instead of re-hashing file leaves from scratch, and extends enable_file_hash_caching() to patch both FileHandler and DirectoryHandler with the same cached hasher instance.
Changes:
BasicDirectoryHashernow requires afile_hasherand delegates file-leaf hashing to it during Merkle traversal.- Default context wiring updated (v0.1.json + builtin handler fallback) so directories receive the same
FileHasherinstance as files. enable_file_hash_caching()now patchesDirectoryHandlertoo, sharing oneCachedFileHasherinstance across file + directory hashing; adds tests + documentation.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
src/orcapod/hashing/directory_hashers.py |
Use injected file_hasher for file leaves; make file_hasher required. |
src/orcapod/hashing/semantic_hashing/builtin_handlers.py |
Fallback BasicDirectoryHasher construction now passes file_hasher. |
src/orcapod/contexts/__init__.py |
enable_file_hash_caching() now also patches DirectoryHandler with the same cached hasher instance. |
src/orcapod/contexts/data/v0.1.json |
Inject file_hasher reference into BasicDirectoryHasher config; add changelog entry. |
tests/test_hashing/test_directory_handler.py |
Update all BasicDirectoryHasher() call sites to pass file_hasher=FileHasher(). |
tests/test_hashing/test_directory_hash_caching.py |
New integration tests for directory hashing cache behavior + wiring. |
tests/test_hashing/test_hash_cachers.py |
Extend cache-enablement tests to include DirectoryHandler patching and shared instance assertions. |
docs/concepts/file-hash-caching.md |
New user documentation describing caching and activation. |
superpowers/specs/2026-07-08-itl-511-directory-hash-caching-design.md |
Design/spec for the change set. |
superpowers/plans/2026-07-08-itl-511-directory-hash-caching.md |
Implementation plan/checklist for the work. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| To inspect cached entries using the SQLite command-line tool: | ||
|
|
||
| ```bash | ||
| sqlite3 ~/.orcapod/file_hash_cache.db "SELECT path, method FROM file_hashes LIMIT 10;" |
There was a problem hiding this comment.
Fixed — corrected table name from file_hashes to file_hash_cache and updated the SELECT columns to valid schema columns (path, size, cached_at) — the actual schema has no method column.
| Orcapod can cache the SHA-256 digest of files so that re-hashing the same | ||
| unchanged file — across pipeline runs or between `op.File` and `op.Directory` | ||
| accesses — skips the disk read entirely. This page explains how the cache | ||
| works, how to turn it on, and when it helps. |
There was a problem hiding this comment.
Fixed — changed 'SHA-256 digest' to 'content hash (SHA-256 by default, configurable via the algorithm argument)' so it's accurate for any configured algorithm.
| called the file hasher directly, bypassing the per-file cache even when | ||
| caching was enabled. | ||
|
|
||
| After ITL-511, the `DirectoryHandler`'s `BasicDirectoryHasher` uses the |
There was a problem hiding this comment.
Do NOT mention Linear issue numbers anywhere in the documentation -- these issue numbers are NOT helpful.
There was a problem hiding this comment.
Fixed — removed the ITL-511 reference from the directory hashing section. The paragraph now reads as timeless documentation without any internal issue numbers.
There was a problem hiding this comment.
Follow-up fix: also removed the issue number from the v0.1.json changelog entry we added in this PR. The entry now reads as plain prose without any Linear reference.
…hema - enable_file_hash_caching(): add explicit RuntimeError when no DirectoryHandler is registered (mirrors existing FileHandler guard) - docs: fix SQLite table name in inspect/clear examples (file_hashes -> file_hash_cache); fix SELECT columns (method -> size, cached_at); describe FileHasher as returning a content hash (SHA-256 by default) rather than implying SHA-256 is the only algorithm
Review round summaryFour issues fixed in a single commit (
All 507 hashing tests still pass after the changes. |
Review round summaryRemoved the remaining issue number reference from The changelog entry added by this PR previously ended with All 507 hashing tests still pass. |
Summary
BasicDirectoryHasher._hash_dir()was callinghash_utils.hash_file()directly, bypassing the injectedFileContentHasherProtocolentirely. This meantop.Directoryhashing always recomputed every file hash from scratch, making the file hash cache dead weight for directory-heavy workloads.enable_file_hash_caching()only patchedFileHandler;DirectoryHandlerwas untouched.Changes
BasicDirectoryHasher:file_hasher: FileContentHasherProtocolis now a required first argument;_hash_dir()delegates to it for per-file leavesv0.1.json: wires{"_ref": "file_hasher"}intoBasicDirectoryHasherconfig so the default context injects the sameFileHasherinstanceenable_file_hash_caching(): also patchesDirectoryHandlerusing the sameCachedFileHasherinstance asFileHandler— a file cached viaop.Fileis a cache hit during directory traversaltest_directory_hash_caching.pycovering cache write/hit/invalidation and theenable_file_hash_caching()wiringtest_directory_handler.py: allBasicDirectoryHasher()calls now passfile_hasher=FileHasher()test_hash_cachers.py: fixture restoresDirectoryHandler; 2 new tests for DirectoryHandler patchingdocs/concepts/file-hash-caching.md: explains the caching architecture, activation, directory behaviour, storage, and trade-offsTest plan
uv run pytest tests/test_hashing/ -v— all hashing tests passuv run pytest tests/ -q— full suite passes (4160 passed, 56 skipped)Fixes ITL-511