Skip to content

Create a sync destination's parent, and retry a lost create-script - #53

Merged
titouanmathis merged 2 commits into
mainfrom
fix/rsync-parent-and-create-sentinel
Sep 8, 2026
Merged

Create a sync destination's parent, and retry a lost create-script#53
titouanmathis merged 2 commits into
mainfrom
fix/rsync-parent-and-create-sentinel

Conversation

@titouanmathis

Copy link
Copy Markdown
Contributor

Two bugs found by a real first deploy of www.alloayiti.fr, neither of them covered by the tests.

rsync never creates the destination's parent

rsync web/index.php → server:~/www/preview-462--app/web/index.php
rsync: [Receiver] change_dir#3 ".../web" failed: No such file or directory (2)

rsync makes the destination directory itself, but not its parent. So a single file whose parent is missing fails, and whether a deploy worked depended on the order of --sync: a project listing web/index.php before the web/wp that would have created web/ never got past the first file. Scalian only escaped it because its path order happened to create web/ first.

The parent is now created by --rsync-path, which runs in the remote shell and therefore works with any rsync version. Not --mkpath: that needs rsync 3.2.3 at both ends, and a runner older than that would fail on the option itself.

A failed first deploy lost its create-script for good

That failure exposed a worse one. The create-script was keyed on the project directory being absent — but the failed deploy had already cloned, so every later deploy treated it as an existing project and skipped the create-script. The environment stayed unseeded permanently, with no recovery but to destroy it.

On the server it left exactly that:

dir exists: yes   .git: yes   vendor: yes
.env: MISSING     web: no

.env was written by the create-script, so no retry would ever produce it.

It is now keyed on a marker written only after the script succeeds, so a create-script that fails runs again next time. Three cases, all tested:

State on the server Create-script
.trafic-created present skipped
.trafic-cloned present, .trafic-created absent runs again — a first deploy of this version that failed before it
neither, but the directory exists skipped and recorded — predates the markers

That last row is deliberate: re-running a seed against a database that has been live for weeks is worse than skipping a step that was probably already done. .trafic-cloned is what separates it from a genuine retry.

Tests

482 pass. Five new tests for the create-script decision (including the two cases above, which the old logic got wrong) and four for parentOf and the --rsync-path argument. CLI coverage 97.16% statements / 93.37% branches, above the gate added in #52.

Two bugs found by a real first deploy, neither covered by the tests.

rsync makes the destination directory itself but never its parent, so a
single file whose parent is missing fails with "No such file or directory".
Whether a deploy worked therefore depended on the order of --sync: a project
listing web/index.php before the web/wp that would have created web/ never
got past the first file. The parent is now created by --rsync-path, which
runs in the remote shell, rather than --mkpath, which needs rsync 3.2.3 at
both ends and would fail on the option itself on an older runner.

That failure exposed the second bug. The create-script was keyed on the
project directory being absent, so the failed deploy — which had already
cloned — left every later deploy treating it as an existing project and
skipping the create-script. The environment stayed unseeded for good, with no
recovery but to destroy it; here it left a project whose .env was never
written and never would be. It is now keyed on a marker written only after
the script succeeds, so a create-script that fails runs again next time.

An environment created before this release carries no marker and is assumed
to have been seeded: re-running a seed against a database that has been live
since is worse than skipping a step that was probably already done. A
.trafic-cloned marker separates that case from a first deploy of this version
that failed before its create-script.

Co-authored-by: Claude <claude@anthropic.com>
Claude-Session: https://claude.ai/code/session_016xdQPh3UcnZfjM5HS36ABP
@codecov

codecov Bot commented Sep 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 82.30%. Comparing base (0b6831d) to head (85b65e1).

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #53      +/-   ##
==========================================
+ Coverage   82.12%   82.30%   +0.18%     
==========================================
  Files          35       35              
  Lines        1466     1481      +15     
  Branches      374      375       +1     
==========================================
+ Hits         1204     1219      +15     
  Misses        219      219              
  Partials       43       43              
Flag Coverage Δ
integration 67.54% <100.00%> (+1.80%) ⬆️
unit 82.10% <100.00%> (+0.18%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

`test:integration:ci` collects coverage for Codecov's `integration` flag, so
it inherited the thresholds from vite.config.ts. Those are the unit suite's
floor; the integration suite exercises ssh.ts against a real SSH server and
touches little else, so it reports 66% and the run failed with all of its
tests passing. CI has been red on main since 0.1.39 was released — the gate
from #52 was measuring the wrong suite.

Also adds the regression test for the parent-directory bug, against real
rsync in the container. Verified to have teeth: with the fix removed it fails
with the same "change_dir ... failed: No such file or directory" the
deployment hit, and passes with it. 14 integration tests.

Co-authored-by: Claude <claude@anthropic.com>
Claude-Session: https://claude.ai/code/session_016xdQPh3UcnZfjM5HS36ABP
@titouanmathis
titouanmathis merged commit 956d435 into main Sep 8, 2026
10 checks passed
@titouanmathis
titouanmathis deleted the fix/rsync-parent-and-create-sentinel branch September 8, 2026 13:17
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