Skip to content

fix(sync): let auto-commit recognise its own translation output - #112

Open
sjsyrek wants to merge 1 commit into
mainfrom
fix/sync-auto-commit-ownership
Open

fix(sync): let auto-commit recognise its own translation output#112
sjsyrek wants to merge 1 commit into
mainfrom
fix/sync-auto-commit-ownership

Conversation

@sjsyrek

@sjsyrek sjsyrek commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

deepl sync --auto-commit treated only the files a given run wrote as its own. That broke in two directions, and both are fixed by deriving ownership from the sync's configured targets instead.

A translation left behind by an earlier refusal was never committable. A refused run still writes its translations to disk. On the next run that file was classed as an unrelated modification — so auto-commit refused because of a file it had produced itself, and kept refusing. The only escape was committing it by hand.

In --watch mode a trigger that translated nothing reported success while a commit was still owed. The same path runs once per trigger, and the checks were gated on that run having written files. When a trigger found nothing to translate, the checks were skipped entirely: no commit made, the translation still uncommitted, the tree still dirty, and no error.

Changes Made

  • Ownership derived from the lockfile's tracked source files, expanded across target_locales via the existing resolveTargetPath. Each source file is matched to its own bucket by include glob, so one bucket's target_path_pattern cannot claim another bucket's output.
  • Staging follows what is actually dirty rather than what the run claims it wrote. A rewrite that produced identical bytes no longer attempts an empty commit, and a leftover translation does get staged.
  • The fileResults.length > 0 gate is removed from the watch path, matching the one-shot path. A cycle with nothing to commit is now silent rather than skipped-but-reported-successful.
  • Commit message locales are derived from the files actually staged, with a lockfile-only fallback, so a retry produces a sensible message instead of an empty locale list.

Test Coverage

269 suites / 6098 tests green; lint and type-check clean.

Two new integration tests against a real git repo:

  • a translation left behind by a refusal is committed once the unrelated changes are dealt with, ending with a clean tree
  • repeated triggers in a refusing state report the refusal every time, and a subsequent trigger with nothing to commit neither throws nor commits

The unit tests needed correcting rather than adapting: they mocked git as reporting a clean tree while simultaneously asserting that files had just been written — a state git cannot produce. Each now presents the working tree its scenario implies, which is why several of them moved.

Backward Compatibility

✅ No API or flag changes.

⚠️ Two intentional behaviour changes, both replacing silence with either a commit or a stated reason: a run with nothing newly translated but pending translation output now commits it, and a watch cycle that cannot commit reports the refusal instead of passing quietly.

Size: Small ✓

One source file plus tests. The risk sits in the ownership derivation, which is covered by the two integration tests above running against real git rather than a mock.

🤖 Generated with Claude Code

Auto-commit treated only the files a given run wrote as its own, which broke
in two directions.

A translation left on disk by an earlier refused run was classed as an
unrelated modification, so every later run refused for the presence of a file
auto-commit had itself produced. The only way out was committing it by hand.

In --watch mode the same path runs once per trigger, and the checks were
skipped entirely when a trigger translated nothing. That reported success
while a commit was still owed: no commit made, the translation uncommitted
and the tree still dirty.

Ownership is now derived from the lockfile's tracked source files, each
matched to its own bucket by include glob so one bucket's target_path_pattern
cannot claim another bucket's output. Staging follows what is actually dirty
rather than what the run claims it wrote, so a rewrite producing identical
bytes no longer attempts an empty commit, and a cycle with nothing to commit
stays silent.

The unit tests mocked git as reporting a clean tree while also asserting that
files had just been written — a state git cannot produce. They now present the
working tree their scenario implies.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
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.

1 participant