fix: preserve truthful queue recovery status
All checks were successful
CI / lint (pull_request) Successful in 2m35s
CI / build-release (pull_request) Successful in 5s
CI / browser-journey (pull_request) Successful in 1m53s
CI / release-candidate (pull_request) Has been skipped

This commit is contained in:
timmy 2026-08-17 21:55:00 +00:00
parent ce2f04ab6d
commit 5bf0f97df8
4 changed files with 9 additions and 5 deletions

View File

@ -376,7 +376,7 @@
onStatus: (state, detail = {}) => { onStatus: (state, detail = {}) => {
const status = qs('#today-sync-status'); const status = qs('#today-sync-status');
status.textContent = state === 'saved' ? 'Today saved to account.' : status.textContent = state === 'saved' ? 'Today saved to account.' :
(state === 'recovered' ? `Recovered ${detail.discarded} Today edit${detail.discarded === 1 ? '' : 's'} · discarded ${detail.discarded} unreadable device record${detail.discarded === 1 ? '' : 's'}.` : (state === 'recovered' ? `Today queue recovered · discarded ${detail.discarded} unreadable device record${detail.discarded === 1 ? '' : 's'}.` :
(state === 'retrying' ? `Today saved on this device · retrying in ${Math.ceil(detail.delayMs / 1000)}s.` : (state === 'retrying' ? `Today saved on this device · retrying in ${Math.ceil(detail.delayMs / 1000)}s.` :
(state === 'pending' ? 'Today saved on this device · sync pending.' : (state === 'pending' ? 'Today saved on this device · sync pending.' :
(state === 'full' ? 'Another device filled Today · showing its saved plan.' : (state === 'full' ? 'Another device filled Today · showing its saved plan.' :

View File

@ -303,8 +303,12 @@ function createTodaySync({ storage, getLogin, fetchJson, onRemoteIds, onRemotePl
cancelRetry(); cancelRetry();
return !hadConflict; return !hadConflict;
} catch (error) { } catch (error) {
if (pending().length) scheduleRetry(error, ownerKey); const stillPending = pending().length;
else onStatus?.('error'); if (discardedCount) recoveryNotice = { discarded: discardedCount, until: now() + 5000 };
const recovered = recoveryNotice.until > now() ? recoveryNotice.discarded : 0;
if (stillPending) scheduleRetry(error, ownerKey);
else onStatus?.(recovered ? 'recovered' : 'error', recovered ? { discarded: recovered } : {});
discardedCount = 0;
return false; return false;
} }
} }

View File

@ -105,7 +105,7 @@ def test_release_artifact_plans_hands_off_and_opens_next_mobile_issue(tmp_path:
page.reload(wait_until="networkidle") page.reload(wait_until="networkidle")
expect(page.locator("#my-work-status")).to_contain_text("2") expect(page.locator("#my-work-status")).to_contain_text("2")
expect(page.locator("#today-sync-status")).to_have_text( expect(page.locator("#today-sync-status")).to_have_text(
"Recovered 1 Today edit · discarded 1 unreadable device record." "Today queue recovered · discarded 1 unreadable device record."
) )
assert page.evaluate("""() => !Object.keys(localStorage).some( assert page.evaluate("""() => !Object.keys(localStorage).some(
key => key.startsWith('stackchain.today-sync.v1.timmy.operation.') key => key.startsWith('stackchain.today-sync.v1.timmy.operation.')

View File

@ -143,7 +143,7 @@ const sync=createTodaySync({{storage,getLogin:()=> 'timmy',
def test_today_sync_reports_queue_recovery_instead_of_plain_saved_status(): def test_today_sync_reports_queue_recovery_instead_of_plain_saved_status():
source = DASHBOARD.read_text() source = DASHBOARD.read_text()
assert "Recovered ${detail.discarded} Today edit" in source assert "Today queue recovered" in source
assert "discarded ${detail.discarded} unreadable device record" in source assert "discarded ${detail.discarded} unreadable device record" in source