Skip to content

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

Draft
ClaudiuCeia with Copilot wants to merge 2 commits into
mainfrom
copilot/fix-spatch-make-multi-file-writes-transactional
Draft

fix(spatch): make multi-file writes transactional#11
ClaudiuCeia with Copilot wants to merge 2 commits into
mainfrom
copilot/fix-spatch-make-multi-file-writes-transactional

Conversation

Copilot AI commented Jul 25, 2026

Copy link
Copy Markdown

Non-interactive writes analyzed and wrote files concurrently, so a later write failure left earlier files modified. Interactive mode preflighted selected files but its sequential write loop could still partially apply across files.

Changes

file-write.ts — transaction primitives

  • Export FileWriteFs (was unexported)
  • Add TransactionEntry — staged write descriptor (filePath, originalText, rewrittenText, encoding, operationName)
  • Add PartialCommitError — typed error with deterministically sorted affectedFiles: readonly string[]; thrown when rollback cannot restore all committed files
  • Add commitTransaction(entries, options?):
    1. Sort entries by absolute path for deterministic commit order
    2. Preflight all targets (read + compare to originalText) — any mismatch aborts before any write
    3. Commit sequentially using the existing atomic write-rename
    4. On failure: rollback committed files in reverse order, skipping files with concurrent external edits (preserves them)
    5. Throw PartialCommitError on incomplete rollback; otherwise rethrow the original commit error

rewrite.ts — separate analysis from mutation

  • Split rewriteFile into analyzeFile, which reads/matches/renders but does not write
  • analyzeFile returns { fileResult, writeEntry }writeEntry is null for dry-run or no-change files
  • rewriteProject runs analyzeFile concurrently, collects TransactionEntry items, then calls commitTransaction once — any analysis failure aborts before any file is touched

run.ts (interactive) — route through shared transaction

  • Replace the per-file writeFileIfUnchangedAtomically loop with a single commitTransaction call over all prepared files

Tests

  • 8 new unit tests for commitTransaction: empty entries, multi-file write, deterministic order, stale preflight abort, commit failure + successful rollback, rollback failure → PartialCommitError, concurrent edit preserved, error shape
  • 2 new integration tests for multi-file non-interactive and interactive transactional write
Analysis failure  → commitTransaction never called → no files touched
Stale preflight   → aborts before first write      → no files touched
Commit failure    → rollback in reverse order      → committed files restored
Rollback failure  → PartialCommitError(affectedFiles: sorted absolute paths)
Concurrent edit   → rollback skips that file       → external edit preserved

Copilot AI changed the title [WIP] Fix multi-file writes to be transactional fix(spatch): make multi-file writes transactional Jul 25, 2026
Copilot AI requested a review from ClaudiuCeia July 25, 2026 13:20
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.

fix(spatch): make multi-file writes transactional

2 participants