Problem
exportResourceFor aborts the push when hydration fails (2f38ea4, ff4c2c9),
because a partially populated record PUT to the server overwrites the complete
copy there — alarms and attendees silently deleted for every other client.
That is right for a transient failure: the dirty flag stays set and the next
sync retries the whole resource. It has no answer for a deterministic one. If
one relation row fails to scan every single time — a NULL in a column
scan_helpers.go reads as a non-pointer after a hand-edited database or a
partially applied migration — then:
- every sync re-attempts that resource and fails identically,
- the resource stays dirty forever,
- the calendar shows a permanent sync-failure warning (the ⚠ sidebar glyph),
- and no other edit to that event ever reaches the server.
There is no path to convergence short of hand-editing the database, and nothing
tells the user that is what is required.
Why this was not just fixed
The obvious "fix" — give up and push anyway — is exactly the data loss 2f38ea4
was written to prevent. Failing loudly on unreadable local data is the correct
default. What is missing is not tolerance, it is a way out.
Proposed direction
Some combination of:
- Attempt tracking. Record consecutive push failures per
sync_resource.
After N identical failures, stop retrying every cycle (back off), so one
wedged resource does not make every sync report an error.
- A diagnosable message. The error should say which relation failed and
that the resource is stuck, not just hydrate event uid ....
- An escape hatch. Something like
chroncal sync doctor that lists wedged
resources and offers to push without the unreadable relation after
explicit confirmation — the user accepting the loss knowingly is very
different from us doing it silently.
(3) is the part that actually resolves the finding; (1) and (2) make it bearable
in the meantime.
Context
Found by code review of 781e70b^..HEAD, verdict PLAUSIBLE. Deliberately not
fixed in that round because every quick fix reintroduces silent amputation.
Problem
exportResourceForaborts the push when hydration fails (2f38ea4, ff4c2c9),because a partially populated record PUT to the server overwrites the complete
copy there — alarms and attendees silently deleted for every other client.
That is right for a transient failure: the dirty flag stays set and the next
sync retries the whole resource. It has no answer for a deterministic one. If
one relation row fails to scan every single time — a NULL in a column
scan_helpers.goreads as a non-pointer after a hand-edited database or apartially applied migration — then:
There is no path to convergence short of hand-editing the database, and nothing
tells the user that is what is required.
Why this was not just fixed
The obvious "fix" — give up and push anyway — is exactly the data loss 2f38ea4
was written to prevent. Failing loudly on unreadable local data is the correct
default. What is missing is not tolerance, it is a way out.
Proposed direction
Some combination of:
sync_resource.After N identical failures, stop retrying every cycle (back off), so one
wedged resource does not make every sync report an error.
that the resource is stuck, not just
hydrate event uid ....chroncal sync doctorthat lists wedgedresources and offers to push without the unreadable relation after
explicit confirmation — the user accepting the loss knowingly is very
different from us doing it silently.
(3) is the part that actually resolves the finding; (1) and (2) make it bearable
in the meantime.
Context
Found by code review of
781e70b^..HEAD, verdict PLAUSIBLE. Deliberately notfixed in that round because every quick fix reintroduces silent amputation.