Wave 11 (M-authexpiry): refresh auth token every sync; recover rows lost to the expired-token sync

Committed by tasks/wave-chain.sh after its mechanical gate passed
(assembleDebug, testDebugUnitTest = 355 tests, verifyPaparazziDebug, no build
files touched, no "always 'false'"). ORCHESTRATOR REVIEW STILL PENDING.
Prompt: tasks/M-authexpiry.txt. Worker: $4.886013000000001, 123 turns.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Spriteandclaude committed 2026-09-17 02:54:41 +00:00
1 parent 81f63bffc0
commit 009cb9a7cc
30 files changed
+687 -17

No files matched your search

+1
View File
@@ -0,0 +1 @@
d109abe5-9e54-4496-912d-b200c51d373e
+18
View File
@@ -0,0 +1,18 @@
=== M-authexpiry-fix attempts=1 quota_waits=0 hard_fails=0 ===
cost=$1.3351339999999998 turns=44 err=?
--- result (tail) ---
ar onlineSearchJob` to `internal var onlineSearchJob`, matching the file's existing convention (same reasoning already documented on `performOnlineSearch`) of loosening visibility so tests can synchronize on it directly.
- `app/app/src/test/java/org/modg/bookshelf/ui/library/LibraryViewModelTest.kt`: after `gate.countDown()`, added `vm.onlineSearchJob?.join()` so the test genuinely waits for the cancelled job to finish before returning, with a comment explaining why.
No changes to the feature logic, SPEC, build files, or anything else — nothing else in the gate's failure pointed at the auth-expiry implementation itself.
**Verification:**
- `assembleDebug` → exit 0.
- `testDebugUnitTest` → exit 0, reran 4 more times with `--rerun` after the fix, all clean (previously failed on run 2 of 2 before the fix).
- Test count: 355 passed, 2 skipped, 0 failures (baseline was 337) — via summed XML.
- `verifyPaparazziDebug` → exit 0.
- Recorded the 4 new Paparazzi snapshots (`library-auth-expired-{light,dark}`, `settings-auth-expired-{light,dark}`) and viewed all four PNGs: library grid shows the "Signed out — sign in again to sync" sync bar; settings shows "Your session expired. Sign in again." with a "Sign in" button. Both match spec's design language in light and dark, and `git status` confirmed no other snapshots were touched by the record run.
- Grepped a forced recompile for Kotlin warnings in touched files: none.
- Final full sequence run in order (assembleDebug → testDebugUnitTest → verifyPaparazziDebug): all exit 0.
I did not re-review the original worker's auth-expiry design/logic (token refresh, full re-pull, AuthExpired propagation) since none of that was implicated by the gate failure — per instructions, I only touched what was making the gate red.
+1
View File
@@ -0,0 +1 @@
6bcc6e7a-a2a5-449e-b75a-a62eea1cc657
+13
View File
@@ -0,0 +1,13 @@
=== M-authexpiry attempts=1 quota_waits=0 hard_fails=0 ===
cost=$4.886013000000001 turns=123 err=?
--- result (tail) ---
ption` handler before it can reach a `code() == 404` branch, so it can never be misread as "deleted." A local dirty (`PENDING_*`) record is never touched by an `AuthExpired` result — the exception aborts the whole `sync()` before the offending DAO write and before any subsequent push/pull calls run.
**Full re-pull safety:** relied on `SyncEngine.shouldApplyRemote` (SyncEngine.kt, in the `applyIncomingBook`/`Shelf`/`Bookcase` helpers) — no local record → always inserted; a `SYNCED` local record only loses to a remote that's `>=` its own `updated`; a dirty (`PENDING_*`) local record only loses to a remote strictly newer than its own `updated`. So a full re-pull can only ever add back rows or apply genuinely newer server state — it can't clobber an unsynced local edit.
**Deviations:**
- I did not re-run baseline `testDebugUnitTest` before touching code — I trusted the prompt's stated 337/2-skipped baseline. I did do the required post-change runs.
- Added a small `internal` test-only method (`SettingsStore.resetFullRepullDoneForTesting`) purely to prevent DataStore's known cross-test-method state leak (the same issue `SettingsStoreTest` already documents) from corrupting the new repull tests. No production caller.
- Dropped one planned SetupViewModel test ("starts blank on first run") because it wasn't required and was fragile against the same cross-test DataStore leak; kept only the required pre-fill test, which is self-contained.
**Out of scope but noticed:** several pre-existing Kotlin deprecation warnings (`Icons.Filled.ArrowBack`, `Icons.Outlined.Sort`, `centerAlignedTopAppBarColors`, `Modifier.menuAnchor()`, `LocalLifecycleOwner`) and a nullable-`ClassLoader` warning in some metadata client tests — none in files I touched, all pre-existing, left alone.