Repository navigation
v1.0.6 — Upload retry hardening
Patch release that hardens the binary upload pipeline against flaky-network and process-interrupt edge cases.
🛡 Stuck uploads recover automatically
A row whose upload was interrupted (process killed, JS crash, OS swept the app) used to sit orphaned in `upload_state='uploading'` forever. The drainer now treats that state the same as 'pending' — same row, fresh attempt — so the next sync pass cleans it up without any user action.
⏳ Per-row backoff (30s) so flaky networks don't burn the budget
Previously, five rapid syncs while offline could exhaust the `MAX_ATTEMPTS=5` budget in seconds, leaving the row quarantined even after connectivity returned. New `last_attempt_at` column gates each retry by a 30-second cooldown, and `MAX_ATTEMPTS` bumps to 10 — at least five minutes of intermittent connectivity before a row goes cold.
📡 Network reconnect resets the attempt counter
NetInfo offline→online transitions now call a soft reset on every not-yet-uploaded row before kicking the sync (3s debounce). A user who lost the network mid-batch and burnt 8 attempts during the outage gets a fresh budget the moment Wi-Fi reconnects.
🔁 "Retry stuck uploads" button on the Me screen
When the queue has anything pending, a new button appears beneath "Retry AI processing" that calls `resetFailedUploads` and forces an immediate sync. Self-service recovery without reinstalling.
Schema migration
`drizzle 0003` adds `last_attempt_at integer` to `job_photos` and `job_clips`. Auto-applies on first launch via the existing `useOfflineMigrations` hook — no user action required.
Distribution
Build and ship the Android APK to Firebase App Distribution: `./deploy.sh --notes "Upload retry hardening — see GitHub release v1.0.6"`