fix(hardlink): name the mutable set directly, under both build-dir layouts #16

Merged
claude merged 4 commits from fix/layout-v2-selection into main 2026-08-27 20:03:41 +00:00
4 Commits
Author SHA1 Message Date
claude 4bb880b7a7 chore(ci): trigger CI after un-WIP
CI / shellcheck + selftests (pull_request) Successful in 1m21s
2026-08-27 14:52:11 -05:00
claude fb3c72aa28 docs(hardlink): withdraw the nlink claim, which asserted more than was measured
CI / shellcheck + selftests (pull_request) Skipped
The comments said hardlink count at link time was ruled out as the
discriminator between a rewritten executable and an intact one, citing a
lib+bin crate whose two test binaries were both `nlink == 1` and appeared to
behave differently. Re-checked on review: the intact one had not been rebuilt
at all — same content, same inode — so it demonstrated nothing, and forcing
both to rebuild rewrote both.

What was actually observed is narrower and now says so: every executable
measured intact had an uplift hardlink twin Cargo must re-create anyway, every
one measured rewritten had none, and whether the twin is the mechanism or a
correlate was not determined. The rule does not rest on the answer — exempting
twinned executables would recover none of the bytes this change newly copies.

This PR exists because a claim outlived its evidence; it should not ship one.
2026-08-27 14:50:53 -05:00
claude 0553a6b956 fix(hardlink): resolve an ambiguous out/ toward unsharing, and pin the linked-output scenario on a shape that exhibits it
CI / shellcheck + selftests (pull_request) Skipped
Two review findings on #16.

The `out/` discriminator keyed on Cargo's record of a build-script execution,
which Cargo writes only AFTER the script exits successfully. A build script
that populates OUT_DIR and then fails leaves a unit with no record at all, so
its OUT_DIR read as a compile unit's artifact directory and stayed shared —
a regression against the old `-name build` selection, which real-copied that
state by construction. Reproduced on cargo 1.93.1 stable.

An `out` directory now stays shared only when two independent signals agree:
it holds an `.rlib`/`.rmeta` of its own, and its unit carries no execution
record. Either one missing real-copies it. The cost is unchanged to the byte —
the newly-unshared directories hold only executables and `*.d`, both already
privately owned by the file rules.

The live linked-test-binary scenario was built on the lib+bin probe crate,
whose test binaries relink to a fresh inode — a shape gitdan-actions#17 records
as measured safe. Both halves passed green against the unfixed selection on
dep-info mutations the previous scenario already covers. It now builds a
bin-only crate with a unit test, reads only executables, and skips loudly with
a warning rather than passing quietly if the toolchain does not exhibit the
rewrite at all.

Also: drop a clause asserting the linker writes in place "whenever the path has
no other hard link", which this change's own evidence denies; move the
load-bearing comment block back above `unshare_mutable_paths`; correct a
superseded 99.998% figure; and record both cost rows in the README rather than
only the flattering whole-tree one.
2026-08-27 14:39:29 -05:00
claude e5b26a9368 fix(hardlink): name the mutable set directly, under both build-dir layouts
CI / shellcheck + selftests (pull_request) Skipped
`unshare_mutable_paths` selected `.fingerprint` and `build` directories. Under
Cargo's build-dir layout v2 the first clause matches nothing and the second
matches the whole tree, because v2 regroups artifacts under `build/` alongside
the metadata. Measured on one scratch crate: 39.3% of the tree real-copied
under v1, 99.996% under v2.

The selection now names the mutable set rather than the container it used to
live in: fingerprint directories under either spelling, layout v2's `run/`
directories, layout v1's loose build-script run metadata, and the `out`
directories that are a build script's OUT_DIR rather than a compile unit's
artifact directory. The two are told apart structurally, by Cargo's record of
the build-script execution sitting beside the OUT_DIR and nowhere else.

Verifying that turned up a second, layout-independent hazard: a linked
executable is written through whatever inode is already at its path, so a
`cargo test --no-run` inside a `cp -al` clone rewrites the source's own test
binary. Reproduced on cargo 1.93.1 stable, 1.96.0-nightly, 1.98.0-nightly and
1.100.0-nightly, under both layouts. Every executable is now real-copied;
`.rlib`, `.rmeta` and `incremental/` are what stay shared.

hardlink-clone-selftest.sh gains two file-only layout fixtures that pin the
partition in both directions without a compiler, and a live scenario that
relinks a test binary.
2026-08-27 14:12:01 -05:00