commit 00ce72ee9e39b9bb3cb1265ef4b9fd8359699307
parent 94470940c0bd80b70cc7f976f789a6aa6d80cc50
Author: Erik Loualiche <eloualic@umn.edu>
Date: Sun, 1 Mar 2026 18:51:34 -0600
docs: add CLAUDE.md with build commands and gotchas
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat:
1 file changed, 26 insertions(+), 0 deletions(-)
diff --git a/CLAUDE.md b/CLAUDE.md
@@ -0,0 +1,26 @@
+# CLAUDE.md
+
+## Build & Test
+- `go build ./...` — build all packages
+- `go test ./...` — run all tests
+- `GOOS=darwin GOARCH=arm64 go build -ldflags="-s -w" -o esync-darwin-arm64 .` — trimmed release binary
+
+## Gotchas
+
+### macOS rsync
+- `/usr/bin/rsync` is Apple's `openrsync` — it lacks `--info=progress2` and other modern flags
+- `rsyncBin()` in `internal/syncer/syncer.go` resolves to homebrew rsync (`/opt/homebrew/bin/rsync`) when available
+- `exec.Command` does not use shell aliases, so the binary path must be resolved explicitly
+- `CheckRsync()` validates rsync >= 3.1.0 on startup
+
+### rsync output parsing
+- With `--info=progress2`, both per-file and overall progress lines contain `xfr#`/`to-chk=`
+- In `extractFiles()`, the 100% size-extraction check MUST come before the progress2 skip guard, or per-file sizes are lost
+- Fast transfers may skip the 100% progress line entirely, leaving per-file `Bytes: 0`
+- When per-file sizes are missing, `cmd/sync.go` distributes `BytesTotal` across groups weighted by file count
+- `extractStats()` must match `Total transferred file size:` (actual bytes sent), NOT `Total file size:` (entire source tree size)
+
+### TUI channels
+- Status-only messages use `"status:..."` prefix (e.g. `"status:syncing 45%"`)
+- Channel sends from the sync handler use non-blocking `select/default` to avoid deadlocks
+- `syncEvents` and `logEntries` channels are buffered (capacity 64)