orchestration: wave 4 prompts; decouple guard poll from lease renewal

Guard now polls every 30s but renews every 15 min. Coupling them meant a wave that
finished just after a renewal sat undetected for a full interval with the sprite
pinned hot.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-06 10:54:03 +00:00
parent 9bf5ff4d6c
commit 0088fda095
3 changed files with 165 additions and 3 deletions
+81
View File
@@ -0,0 +1,81 @@
You are Worker F1 on the Bookshelf project (~/bookshelf). Wave 4, part 1:
PROVE THE SYNC + COVER PIPELINE WORKS AGAINST THE REAL SERVER.
FIRST READ (contract — follow exactly, do not restate):
~/bookshelf/docs/SPEC.md (see "Sync design", "PocketBase schema")
~/bookshelf/docs/HANDOFF.md (state + hazards already paid for — read the hazards)
Waves 1-3 are DONE and verified: server, data layer, metadata/scanning, all six screens.
91 unit tests pass. But EVERYTHING so far was tested against FAKES. Worker C's own
report flagged the biggest hole:
"Cover pipeline is best-effort, not fully spec-complete. Download-on-create and
multipart upload-on-sync are UNTESTED against a real PocketBase (only via fakes).
Logic is sound but should get a real-server smoke test."
That is your job. This is the single most likely place a real bug is hiding.
## The live server
- PocketBase v0.40.2 at http://127.0.0.1:8090 (NOT internet-exposed, by design).
`curl -s http://127.0.0.1:8090/api/health` currently returns 200.
- Superuser creds: `server/.dev-credentials` (gitignored). Schema setup: `server/setup-schema.sh`
(idempotent). Create a normal app user with `server/create-user.sh`.
- If the server is down: `sprite-env services restart pocketbase`;
logs at `/.sprite/logs/services/pocketbase.log`.
- Create a THROWAWAY test user for this (e.g. livetest@example.com). Do NOT invent or
use the owner's real email addresses — they have not been provided.
## Your scope
Build a real end-to-end exercise, driven from JVM code (no emulator on this box), that
against the LIVE server proves:
1. auth: login as the test user, token used by PbAuthInterceptor
2. push: create bookcase -> shelf -> book locally (client-generated 15-char ids) and
PUSH them; verify by reading them back through the REST API that the ids were
preserved and NOT remapped
3. pull: mutate a record server-side, pull, confirm last-write-wins on `updated`
4. tombstones: soft-delete locally, push, confirm `deleted=true` propagates and the
record is filtered from local queries
5. **COVER ROUND-TRIP (the point of this task):** attach a cover image to a book,
multipart-upload it to the `cover` file field, then fetch the stored file back
through `/api/files/...` and assert the bytes match what was uploaded. Use a small
locally-generated PNG — do NOT depend on openlibrary.org being reachable.
6. cursor handling: the per-collection `updated` cursor advances and a second pull
is a no-op (no duplicate rows).
## CRITICAL — do not poison the normal test suite
This test hits a real server and MUST NOT run in the default `testDebugUnitTest`.
Machines without PocketBase must stay green. Gate it behind a system property, e.g.
`assumeTrue(System.getProperty("liveServer") != null)`, and provide a runner script
`server/live-sync-test.sh` that sets it. State plainly in your report how it is invoked.
## Boundaries — Worker F2 is running RIGHT NOW in this repo
- F2 owns `app/app/build.gradle.kts` (it is adding release signing), the root `README.md`,
and all Paparazzi/screenshot code. DO NOT TOUCH THOSE. If you need a build change,
REPORT it, do not make it.
- You own `server/` scripts and the live-test code. Put it in its own package
(e.g. `org.modg.bookshelf.livesync`) so it cannot collide with F2's screenshot tests.
- You MAY fix genuine bugs you find in data.repo / data.remote / data.local — that is
the expected outcome. Every fix must keep the existing 91 tests passing.
## Build/verify — use the serialized wrapper, never ./gradlew directly
~/bookshelf/tasks/gw assembleDebug
~/bookshelf/tasks/gw testDebugUnitTest
## Definition of done — actually run these, wait for them, report REAL exit codes
1. `~/bookshelf/tasks/gw assembleDebug` exits 0.
2. `~/bookshelf/tasks/gw testDebugUnitTest` exits 0, ZERO failures, and the live test is
SKIPPED in that run (prove it).
3. The live test, run explicitly against 127.0.0.1:8090, PASSES all six points above.
4. Report the actual bugs you found. "Everything worked first try" on an untested
pipeline is a suspicious claim — if that is genuinely the outcome, show the evidence
(the assertions that ran, the bytes compared).
## Do not repeat an earlier worker's mistake
A worker once ended its turn saying "tests are running in the background, I'll report
when done." That is a FAILURE. Run it, WAIT, report observed exit codes. A truthfully
reported gap is worth more than a false green.
## Report (short — read by a token-constrained orchestrator)
- real exit codes; how to invoke the live test; PASS/FAIL per numbered point above
- every bug found and how you fixed it
- anything you could NOT verify, and why