On the first push to a new remote project, push() launched the CODE_DIRS
rsyncs in parallel before anything had created ${HPC_BASE}/${PROJECT_NAME}.
rsync only creates the final path level, so all of them died with
"mkdir failed: No such file or directory". The later [root files] rsync
then created the base dir, so dataset/ synced and push exited 0 — the
failure stayed silent until sbatch could not find hpc/batch_gpu
(slope_hierarchy first push, job 330464 postmortem, 2026-07-16).
Two changes:
- ssh mkdir -p the remote project dir before the parallel rsyncs, matching
what pull/pull_logs/push_data_init already do. Skipped under --dry-run so
`status` stays side-effect free.
- Collect the background PIDs and wait on each one. Plain `wait` returns its
own status, so a failed backgrounded rsync was swallowed even under
`set -e`. push() now names the failing directory and returns 1, so
push-submit aborts instead of submitting against an incomplete tree.
Verified against a local fake-HPC harness (real rsync, stubbed ssh):
first push previously exited 0 without hpc/batch_gpu and now transfers the
full tree; an injected transfer failure now exits 1 and stops push-submit
before sbatch; re-push, --no-data and status are unchanged.
The bug
On the first push to a new remote project,
push()launched theCODE_DIRSrsyncs in parallel before anything had created${HPC_BASE}/${PROJECT_NAME}. rsync only creates the final path level, so every one of them died withmkdir failed: No such file or directory.The later
[root files]rsync then created the base dir as a side effect, sodataset/synced fine and the whole command exited 0. The failure stayed silent untilsbatchcould not findhpc/batch_gpu.Found during the
slope_hierarchyfirst push (job 330464 postmortem, 2026-07-16).Reproduced against the unmodified script with a local fake-HPC harness (real rsync, stubbed ssh):
The fix
Both changes are confined to
push().ssh mkdir -pthe remote project dir before the parallel rsyncs, matching whatpull,pull_logsandpush_data_initalready do. Skipped under--dry-runsostatusstays side-effect free.waitreturns its own status, so a failed backgrounded rsync was swallowed even underset -euo pipefail. The background PIDs are now collected and waited on individually;push()names the failing directory and returns 1, sopush-submitaborts instead of submitting against an incomplete tree.The second change is included because the reported damage was that the failure was silent until sbatch — the
mkdiralone fixes this instance, but any future first-push failure would still have been invisible.Verification
hpc/batch_gpumissingpush-submitwith a failuresbatchsbatch--no-datastatus(dry-run)statusexiting 1 is pre-existing on both fresh and existing remotes; the baseline was checked and is unchanged by this diff.Sibling repos
The same
push()exists inautofit_assistant(byte-identical file) andautogalaxy_assistant(differs only inCODE_DIRS). Both carry the same defect and have matching PRs.autocti_assistanthas nohpc/syncand is unaffected.Note on the
boundarycheckThe first
boundaryrun on this PR failed for a reason pre-existing onmainand unrelated to this diff (CHOOSING_YOUR_AI_TOOL.mdunclassified — see the comment below). That is now fixed and merged as PyAutoLabs/PyAutoBrain#228, so the check passes againstmaindirectly; the temporaryBrain-ref:declaration this PR carried while that was in flight has been removed.