iceboundrock / iceboundrock/AutoForge
quarantine_state_file: fall back when hard links are unavailable; document the link+unlink crash window
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 0
- Forks
- 0
- Avg merge
- 8h 56m
- Merged PRs (30d)
- 40
Description
Follow-up from the round-4 review Observations on #28 (issue #11). Neither point loses data today; both concern the availability and tidiness of the run --force recovery path.
1. Hard-link availability
quarantine_state_file() reserves state.json.corrupt-<timestamp>[.n] with os.link(src, dst, follow_symlinks=False) because link fails atomically with EEXIST and never replaces an existing archive. Some filesystems do not support hard links (exFAT/vfat, several FUSE and SMB/CIFS mounts, some container overlays). There run --force currently fails closed with StateError("cannot move corrupted state file ... aside: ...") and the original stays put, so nothing is lost, but the documented recovery path is unavailable and the user has to move the file by hand.
Proposed: on EPERM / ENOTSUP / EOPNOTSUPP from os.link, fall back to an equally no-replace reservation, e.g. os.open(dst, O_CREAT | O_EXCL | O_WRONLY) + copy bytes + fsync + unlink source (for a symlink entry: os.symlink(os.readlink(src), dst), which is also atomic no-replace). Keep the bounded numeric-suffix retry. Add tests that force the fallback by monkeypatching os.link.
2. link + unlink is two steps
Reservation and removal of the source are separate syscalls. A crash between them leaves both state.json (still corrupt) and state.json.corrupt-<ts> with identical content. The next run --force archives the leftover again under a new name, so the outcome is a duplicate copy, never a lost one.
Options: use renameat2(RENAME_NOREPLACE) on Linux (not exposed by the stdlib; would need ctypes and a fallback), or simply document the duplicate-copy possibility in state.py and the README. Documenting is probably enough.
Priority: low. No behaviour change is needed for the #11 contract.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in state.py at quarantine_state_file() and inspect the existing run --force recovery tests. Add coverage that monkeypatches os.link for the listed unsupported errors and verifies the bounded no-replace fallback, including symlinks. Update state.py and the README to describe the link-and-unlink crash window; done means recovery works without hard links and the duplicate-copy possibility is documented.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- cli
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 65/100