fix: a failing sync now says so, and a test runs the loop for real #17

Merged
brian merged 1 commit from test into main 2026-08-13 14:30:17 +00:00
Owner

The four-day outage was not caused by a missing test so much as by a missing
symptom. Every push threw, each throw went to console.warn, and the badge
showed a pending count that never came down — which reads as "not synced yet",
not "this has been broken since Friday".

So both clients now separate the two. A record the server refuses is collected
into an error on the status object and rendered: "⚠ Sync failing" on the web,
"Sync failing" in the Android drawer, in the error colour and ahead of the
pending count. A pass that dies outright is reported the same way, and says so
at error level rather than warn. Being offline is deliberately not a failure —
it is a normal state that already reports itself, and marking it a fault would
make the warning meaningless, which is the other way for a real one to go
unnoticed.

The new test is the one that would have caught it. sync-loop.test.mjs loads
the shipped data.js with its storage and network layers swapped for fakes and
runs a real sync(): every store has to reach the server, a refused record has
to leave the rest of the pass alone and still let the pull run, and a failure
has to arrive at the status handler. The fake server keeps what it was sent,
because the pull prunes anything it doesn't list — a fake that forgot would
delete the records the push had just saved and hide the thing under test. It
exits 1 against the commit before the fix.

SyncEngineTest gets the same four cases on Android, where the engine had the
identical silence: a Log.w and a SyncStatus with nowhere to put an error.

Also records the test deployment's URL and the sync rules in CLAUDE.md, and
adds sync-loop to CI.

Co-Authored-By: Claude Opus 5 noreply@anthropic.com

The four-day outage was not caused by a missing test so much as by a missing symptom. Every push threw, each throw went to console.warn, and the badge showed a pending count that never came down — which reads as "not synced yet", not "this has been broken since Friday". So both clients now separate the two. A record the server refuses is collected into an error on the status object and rendered: "⚠ Sync failing" on the web, "Sync failing" in the Android drawer, in the error colour and ahead of the pending count. A pass that dies outright is reported the same way, and says so at error level rather than warn. Being offline is deliberately not a failure — it is a normal state that already reports itself, and marking it a fault would make the warning meaningless, which is the other way for a real one to go unnoticed. The new test is the one that would have caught it. sync-loop.test.mjs loads the shipped data.js with its storage and network layers swapped for fakes and runs a real sync(): every store has to reach the server, a refused record has to leave the rest of the pass alone and still let the pull run, and a failure has to arrive at the status handler. The fake server keeps what it was sent, because the pull prunes anything it doesn't list — a fake that forgot would delete the records the push had just saved and hide the thing under test. It exits 1 against the commit before the fix. SyncEngineTest gets the same four cases on Android, where the engine had the identical silence: a Log.w and a SyncStatus with nowhere to put an error. Also records the test deployment's URL and the sync rules in CLAUDE.md, and adds sync-loop to CI. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
fix: a failing sync now says so, and a test runs the loop for real
All checks were successful
Build and Deploy / test (push) Successful in 29s
Build and Deploy / build (push) Successful in 10s
Build and Deploy / deploy (push) Successful in 15s
Build and Deploy / deploy-main (push) Has been skipped
587c06626f
The four-day outage was not caused by a missing test so much as by a missing
symptom. Every push threw, each throw went to console.warn, and the badge
showed a pending count that never came down — which reads as "not synced yet",
not "this has been broken since Friday".

So both clients now separate the two. A record the server refuses is collected
into an error on the status object and rendered: "⚠ Sync failing" on the web,
"Sync failing" in the Android drawer, in the error colour and ahead of the
pending count. A pass that dies outright is reported the same way, and says so
at error level rather than warn. Being offline is deliberately not a failure —
it is a normal state that already reports itself, and marking it a fault would
make the warning meaningless, which is the other way for a real one to go
unnoticed.

The new test is the one that would have caught it. sync-loop.test.mjs loads
the shipped data.js with its storage and network layers swapped for fakes and
runs a real sync(): every store has to reach the server, a refused record has
to leave the rest of the pass alone and still let the pull run, and a failure
has to arrive at the status handler. The fake server keeps what it was sent,
because the pull prunes anything it doesn't list — a fake that forgot would
delete the records the push had just saved and hide the thing under test. It
exits 1 against the commit before the fix.

SyncEngineTest gets the same four cases on Android, where the engine had the
identical silence: a Log.w and a SyncStatus with nowhere to put an error.

Also records the test deployment's URL and the sync rules in CLAUDE.md, and
adds sync-loop to CI.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
brian merged commit 1b15180e7a into main 2026-08-13 14:30:17 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
brian/Journal!17
No description provided.