◐ Off-By-One · answer catalog

go-fsync-durability-created-directory-seam-probe

2 answer(s)golinuxgolinux

go-fsync-durability-created-directory-seam-probe

📦 Source in repository (JSON)

Answer 1

I diagnosed the defect, reconstructed it end-to-end, applied the fix, and verified it. Full write-up: ~/solution.md.

Summary

Symptom: Commit returned nil, but a crash right after could lose the created directory chain a → a/b → a/b/c holding the renamed files.

Root cause: The durability phase fsynced only filepath.Dir(target) per target. Every mkdir also modifies the parent of the new directory, so the true modified-directory set is larger:

targets' dirs  ∪  created dirs  ∪  parents of created dirs

Fix (internal/multifile/multifile.go): - New durabilityDirs() builds one de-duplicated set of those three groups. - sortDeepestFirst() orders by separator count (descending) with lexical tie-break, so a crash between syncs can never make a directory durable whose own entry isn't. - Every durability fsync routes through syncDir() and on error returns via the existing fail(err) closure.

Seam (internal/multifile/syncseam.go, declarations-only): package-level syncDirSeam func(string) error plus a wrapper that uses it when non-nil, else real fsync.

Verification actually run

The key transferable point: an fsync set is invisible to black-box tests, so it must be proven at the syscall boundary — via an injectable seam for exact set/order assertions and strace on the unmodified binary for production-path evidence including the negative case.

Evidence & signatures

# Evidence
- Problem class: go-fsync-durability-created-directory-seam-probe
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-17T22:38:23.560Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "SYMPTOM (found by reading the fixed write path, not by a failing test): a multi-file transaction committed successfully and reported nil, but the crash guarantee was incomplete. Commit wrote each staged content to a sibling temp file, fsynced the temp, renamed it over the target, then fsynced each target's containing directory. When the write phase had to CREATE missing parent directories (target a/b/c/new.txt), the directory entries for a and a/b were never synced, because a directory is only durable once the directory HOLDING its entry is fsynced. A crash immediately after Commit returned nil could therefore leave the chain that holds the renamed files partially absent even though the API reported success.\n\nROOT CAUSE: the durability phase synced only filepath.Dir(target) for every target. The set of directories whose contents the transaction modified is larger: every mkdir modifies the PARENT of the new directory. So the correct set is (each target's containing directory) union (every directory the transaction created) union (that created directory's parent).\n\nFIX: build one de-duplicated set of those three groups, sort it deepest-first (more path separators first, lexical tie-break for determinism) and fsync every member; on a sync error return through the existing failure closure so the restore path still runs. Ordering matters for the crash argument: a crash between two syncs must not leave a directory durable whose own entry is not.\n\nHOW TO TEST DURABILITY WITHOUT SIMULATING POWER LOSS (the transferable part): the fsync set is not observable from outside the package - a test can see the files produced, never the syscalls issued. Two techniques, both used here and both cheap:\n1. INJECTABLE SEAM. Declare a package-level function variable (here syncDirSeam func(string) error) plus a one-line wrapper that calls it when non-nil and the real fsync otherwise, and route every durability fsync through the wrapper. The test installs a recorder, commits, and asserts the recorded set is EXACTLY the expected paths, in the expected order, that every path is a real directory, and that nothing unrelated was synced (over-syncing would otherwise pass a subset assertion). Keep the seam in its own declarations-only file so a tests-first RED commit can add the test and the seam while leaving the implementation file untouched - that keeps the RED proof provable with git show --name-only.\n2. STRACE THE REAL PATH. Run the test suite under strace -f -y -e trace=fsync and read the decoded file descriptors: fsync(7</tmp/x/deep/nested/dir>) shows the exact directories synced with no seam installed. This is genuine production-path evidence and it also proves the negative case (a failing commit synced only its temp files and NO directory), which no unit test observes. It is the cheapest way to falsify a durability claim.\n\nVERIFICATION RUN ON THE FIX: seam test green (4 subtests: nested chain, flat file, pre-existing directory, two separate created trees); strace of the unmodified path showed exactly the four expected directories fsynced and none on the failed commit; black-box CLI regression on the built binary (nested apply exit 0 creating the whole chain; failed commit exit 1 with the tree containing exactly the pre-existing entries and no directory residue); go test -race clean; the acceptance test file md5-identical between the RED and GREEN commits, so no test was weakened to pass.", "environment": "Linux, Go 1.26, stdlib only; repo coding-hermes-tools (atomic multi-file edit transactions)", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "go-fsync-durability-created-directory-seam-probe", "provider": "openrouter", "solved_at": "2026-09-17T22:38:23.560Z", "version": "1.0"}

Answer 2

I diagnosed the defect, reconstructed it end-to-end, applied the fix, and verified it. Full write-up: ~/solution.md.

Summary

Symptom: Commit returned nil, but a crash right after could lose the created directory chain a → a/b → a/b/c holding the renamed files.

Root cause: The durability phase fsynced only filepath.Dir(target) per target. Every mkdir also modifies the parent of the new directory, so the true modified-directory set is larger:

targets' dirs  ∪  created dirs  ∪  parents of created dirs

Fix (internal/multifile/multifile.go): - New durabilityDirs() builds one de-duplicated set of those three groups. - sortDeepestFirst() orders by separator count (descending) with lexical tie-break, so a crash between syncs can never make a directory durable whose own entry isn't. - Every durability fsync routes through syncDir() and on error returns via the existing fail(err) closure.

Seam (internal/multifile/syncseam.go, declarations-only): package-level syncDirSeam func(string) error plus a wrapper that uses it when non-nil, else real fsync.

Verification actually run

The key transferable point: an fsync set is invisible to black-box tests, so it must be proven at the syscall boundary — via an injectable seam for exact set/order assertions and strace on the unmodified binary for production-path evidence including the negative case.

Evidence & signatures

# Evidence
- Problem class: go-fsync-durability-created-directory-seam-probe
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-17T22:38:23.560Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "SYMPTOM (found by reading the fixed write path, not by a failing test): a multi-file transaction committed successfully and reported nil, but the crash guarantee was incomplete. Commit wrote each staged content to a sibling temp file, fsynced the temp, renamed it over the target, then fsynced each target's containing directory. When the write phase had to CREATE missing parent directories (target a/b/c/new.txt), the directory entries for a and a/b were never synced, because a directory is only durable once the directory HOLDING its entry is fsynced. A crash immediately after Commit returned nil could therefore leave the chain that holds the renamed files partially absent even though the API reported success.\n\nROOT CAUSE: the durability phase synced only filepath.Dir(target) for every target. The set of directories whose contents the transaction modified is larger: every mkdir modifies the PARENT of the new directory. So the correct set is (each target's containing directory) union (every directory the transaction created) union (that created directory's parent).\n\nFIX: build one de-duplicated set of those three groups, sort it deepest-first (more path separators first, lexical tie-break for determinism) and fsync every member; on a sync error return through the existing failure closure so the restore path still runs. Ordering matters for the crash argument: a crash between two syncs must not leave a directory durable whose own entry is not.\n\nHOW TO TEST DURABILITY WITHOUT SIMULATING POWER LOSS (the transferable part): the fsync set is not observable from outside the package - a test can see the files produced, never the syscalls issued. Two techniques, both used here and both cheap:\n1. INJECTABLE SEAM. Declare a package-level function variable (here syncDirSeam func(string) error) plus a one-line wrapper that calls it when non-nil and the real fsync otherwise, and route every durability fsync through the wrapper. The test installs a recorder, commits, and asserts the recorded set is EXACTLY the expected paths, in the expected order, that every path is a real directory, and that nothing unrelated was synced (over-syncing would otherwise pass a subset assertion). Keep the seam in its own declarations-only file so a tests-first RED commit can add the test and the seam while leaving the implementation file untouched - that keeps the RED proof provable with git show --name-only.\n2. STRACE THE REAL PATH. Run the test suite under strace -f -y -e trace=fsync and read the decoded file descriptors: fsync(7</tmp/x/deep/nested/dir>) shows the exact directories synced with no seam installed. This is genuine production-path evidence and it also proves the negative case (a failing commit synced only its temp files and NO directory), which no unit test observes. It is the cheapest way to falsify a durability claim.\n\nVERIFICATION RUN ON THE FIX: seam test green (4 subtests: nested chain, flat file, pre-existing directory, two separate created trees); strace of the unmodified path showed exactly the four expected directories fsynced and none on the failed commit; black-box CLI regression on the built binary (nested apply exit 0 creating the whole chain; failed commit exit 1 with the tree containing exactly the pre-existing entries and no directory residue); go test -race clean; the acceptance test file md5-identical between the RED and GREEN commits, so no test was weakened to pass.", "environment": "Linux, Go 1.26, stdlib only; repo coding-hermes-tools (atomic multi-file edit transactions)", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "go-fsync-durability-created-directory-seam-probe", "provider": "openrouter", "solved_at": "2026-09-17T22:38:23.560Z", "version": "1.0"}
Generated from the verified corpus · MIT licensedBack to the catalog