Skip to content

fix(driver-support): sort directory outputs before packing - #377

Merged
raphaelvigee merged 1 commit into
masterfrom
fix/dirpath-output-sort
Aug 6, 2026
Merged

fix(driver-support): sort directory outputs before packing#377
raphaelvigee merged 1 commit into
masterfrom
fix/dirpath-output-sort

Conversation

@raphaelvigee

Copy link
Copy Markdown
Member

What

A Content::DirPath output was walked with a bare walkdir::WalkDir, so its tar member order was read_dir order — hash order on ext4, insertion order on APFS, something else again on tmpfs.

That order is the artifact's hashout. So the same directory tree packed to two different hashouts on two machines: every downstream target folding it computed a different hashin, and the remote cache missed for byte-identical content. It surfaces as "heph is slow", never as an error. It can also trip reconcile_rebuilt_hashouts into declaring a rebuild's hashouts inconsistent with its manifest.

Content::Glob was never affected (the glob crate sorts). FilePath has no order to get wrong.

How

WalkDir::new(&dir_full).sort_by_file_name() — sorted per directory rather than by collecting the whole tree and sorting full paths, since walkdir already buffers each directory's entries and this reuses that buffer instead of allocating a second one.

Impact

This rekeys every directory-output target on any machine whose readdir order differs from sorted, which is most of them. One-time rebuild; the alternative is a permanent cross-machine cache miss.

oci_pull(layout = True) is the case that surfaced it — an OCI layout directory is a DirPath output, and "the same layout hashes the same everywhere" has to hold before a daemonless image builder can claim reproducibility.

Test

dir_output_packs_in_a_stable_order creates its files in reverse order on purpose: on an insertion-order filesystem an unsorted walk reproduces exactly that, so the test fails without the fix rather than passing by luck. Verified — without the sort it returns ["out/z.txt", "out/sub/b.txt", "out/sub/a.txt", "out/a.txt"] on APFS.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WqQZxsTqanJRWLWdPSchBo

A `Content::DirPath` output was walked with a bare `walkdir::WalkDir`, so
its tar member order was `read_dir` order — hash order on ext4, insertion
order on APFS, something else on tmpfs. That order is the artifact's
hashout, so the same directory tree packed to two different hashouts on
two machines: every downstream target folding it computed a different
hashin, and the remote cache missed for byte-identical content. It
surfaced as "heph is slow", never as an error, and it could also trip
`reconcile_rebuilt_hashouts` into calling a rebuild's hashouts
inconsistent with its manifest.

`Content::Glob` was never affected (the glob crate sorts); `FilePath`
has no order to get wrong.

Sorted per directory via `sort_by_file_name` rather than by collecting
the whole tree and sorting full paths — walkdir already buffers each
directory's entries, so this reuses that buffer instead of allocating a
second one.

This rekeys every directory-output target on any machine whose readdir
order differs from sorted, which is most of them. That is a one-time
rebuild, and the alternative is a permanent cross-machine cache miss.

The test creates its files in reverse order so an unsorted walk on an
insertion-order filesystem reproduces exactly that order — it fails
without the fix rather than passing by luck (verified on APFS).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WqQZxsTqanJRWLWdPSchBo
@raphaelvigee
raphaelvigee merged commit 9fcc269 into master Aug 6, 2026
22 checks passed
@raphaelvigee
raphaelvigee deleted the fix/dirpath-output-sort branch August 6, 2026 07:17
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