feat: add healthchecks.io pings to run-stories.sh and run-profiles.sh

Start/finish pings wired through gdl-cron.sh via HC_URL, finish ping
carries the run's log as its body (visible in the dashboard, no SSH
needed to diagnose a failure). Exit code is the trailing URL segment
by convention, so the existing "stories: 0 to sync" -> exit 75 remap
already reaches the dashboard as a failure too.

Also fixes the actual bug that would have made this useless: the
routine chown-permission rsync warning (the archive share is never
owned by the ssh user) made gdl-sync.py return 1 on every clean run,
not just failing ones -- harmless when a human reads the log, but it
would have pinged every successful run as a failure. publish() now
only masks that one specific, verified-benign error shape; a real
transfer failure sharing the same exit code (23) still fails loudly.
6 new tests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011qAds5qr7nZRq5R4yAuxUk
This commit is contained in:
2026-09-14 14:01:17 -04:00
co-authored by Claude Sonnet 5
parent 8275416b6e
commit 9b2c33766f
6 changed files with 114 additions and 1 deletions
+21 -1
View File
@@ -748,7 +748,27 @@ def publish(staging: Path, dest: str, dry_run: bool) -> int:
return 0
cmd = rsync_command(staging, dest, dry_run)
print(" " + " ".join(cmd))
return subprocess.run(cmd).returncode
result = subprocess.run(cmd, capture_output=True, text=True)
sys.stdout.write(result.stdout)
sys.stderr.write(result.stderr)
if result.returncode == 0:
return 0
# The archive share is never owned by the ssh user, so rsync's `chown`
# step fails on every single run -- exit 23 ("some files/attrs were not
# transferred"), even though every file landed. This is long documented
# (TOOLING.md "Reading the output") as something to read past, not a
# real failure -- but until now the exit CODE didn't know that, so it
# was 1 on every clean run too, silently. Only mask it when every rsync
# error line is that specific permission warning; anything else (a real
# transfer failure sharing the same exit code) still fails loudly.
err_lines = [l for l in result.stderr.splitlines() if l.startswith("rsync:")]
if (result.returncode == 23 and err_lines
and all("failed to set permissions" in l for l in err_lines)):
print(" (rsync exit 23 was only the expected chown-permission "
"warning; files landed)")
return 0
return result.returncode
def run_post_urls(args) -> int: