Skip to content

fix(spatch): make multi-file writes transactional #8

Description

@ClaudiuCeia

Finding

Non-interactive patching currently analyzes and writes files concurrently. A later analysis or write failure can therefore leave earlier files modified. Interactive patching preflights all selected files, but its sequential write phase can still partially apply a multi-file patch.

Portable filesystem APIs cannot provide a truly atomic project-wide commit, so the implementation must expose that limitation rather than overstate its guarantees.

Proposed approach

  • Separate file analysis from filesystem mutation in packages/spatch/src/phases/rewrite.ts.
  • Stage replacement and rollback content for every changed file before modifying any target.
  • Preflight all targets against their analyzed source content.
  • Commit in deterministic absolute-path order with a final stale-content check before each rename.
  • On commit failure, roll back committed files in reverse order without overwriting concurrent external edits.
  • Throw an explicit PartialCommitError listing affected files if rollback cannot fully restore the original state.
  • Route interactive and non-interactive writes through the same transaction implementation in packages/spatch/src/file-write.ts.

Acceptance criteria

  • Analysis, staging, or global preflight failure modifies no target files.
  • Commit order is deterministic regardless of analysis concurrency.
  • A later commit failure restores earlier writes when rollback succeeds.
  • Incomplete rollback produces a stable typed error with deterministic affected-file paths.
  • Concurrent edits are preserved rather than overwritten during commit or rollback.
  • Dry-run, check mode, result shape, and CLI output remain compatible.
  • Tests cover staging failure, stale preflight, commit failure with successful rollback, rollback failure, and concurrent edits.

Metadata

Metadata

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions