fix: recover valid Today edits from corrupt queue
CI / lint (pull_request) Successful in 2m43s
CI / build-release (pull_request) Successful in 8s
CI / browser-journey (pull_request) Failing after 2m21s
CI / release-candidate (pull_request) Has been skipped

Closes #1042
This commit is contained in:
timmy committed 2026-08-17 21:26:40 +00:00
1 parent 66968d90c0
commit a6550f8b1f
4 files changed
+94 -11

No files matched your search

@@ -159,6 +159,26 @@ def test_release_artifact_plans_hands_off_and_opens_next_mobile_issue(tmp_path:
today = page.evaluate("JSON.parse(localStorage.getItem('stackchain.today-work.v1.timmy') || '[]')")
assert today == ["issue:acme/mobile:41:", "issue:acme/mobile:42:"]
page.evaluate("""() => {
const prefix = 'stackchain.today-sync.v1.timmy.operation.';
const snapshot = JSON.parse(localStorage.getItem('stackchain.today-sync-snapshot.v1.timmy') || '{}');
localStorage.setItem(prefix + 'broken', '{not-json');
localStorage.setItem(prefix + 'recover-remove', JSON.stringify({
queued_at: Date.now(),
operation: {
operation_id: 'recover-remove', action: 'remove',
item_id: 'issue:acme/mobile:42:', direction: null, base_revision: snapshot.revision,
},
}));
}""")
page.reload(wait_until="networkidle")
expect(page.locator("#today-sync-status")).to_have_text(
"Recovered 1 Today edit · discarded 1 unreadable device record."
)
assert page.evaluate("""() => !Object.keys(localStorage).some(
key => key.startsWith('stackchain.today-sync.v1.timmy.operation.')
)""")
assert page.evaluate("document.documentElement.scrollWidth <= window.innerWidth")
assert browser_errors == []
assert failed_responses == []
+39
View File
@@ -5,6 +5,7 @@ from pathlib import Path
TODAY_SYNC = Path(__file__).parents[1] / "frontend" / "today-sync.js"
COORDINATOR = Path(__file__).parents[1] / "frontend" / "outbox-coordinator.js"
DASHBOARD = Path(__file__).parents[1] / "frontend" / "dashboard.js"
def test_two_tabs_cannot_erase_each_others_today_edits_or_double_drain():
@@ -108,6 +109,44 @@ process.stdout.write(JSON.stringify(sync.pending().map(operation => operation.op
).stdout) == ["z-add-first", "a-move-second"]
def test_corrupt_queue_record_does_not_hide_or_strand_valid_today_edits():
script = f"""
const createTodaySync = require({json.dumps(str(TODAY_SYNC))});
const prefix = 'stackchain.today-sync.v1.timmy.operation.';
const values = new Map([
[prefix + 'first', JSON.stringify({{queued_at: 1000, operation: {{operation_id:'first', action:'add', item_id:'issue:r:1:'}}}})],
[prefix + 'broken', '{{not-json'],
[prefix + 'invalid', JSON.stringify({{queued_at: 1000, operation: {{operation_id:'invalid', action:'erase-everything'}}}})],
[prefix + 'second', JSON.stringify({{queued_at: 1001, operation: {{operation_id:'second', action:'move', item_id:'issue:r:2:', direction:'up'}}}})],
]);
const storage = {{get length(){{return values.size}},key:i=>[...values.keys()][i]||null,
getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v),removeItem:k=>values.delete(k)}};
const patches=[]; const statuses=[];
const sync=createTodaySync({{storage,getLogin:()=> 'timmy',
fetchJson:async(_url,options={{}})=>{{const operations=JSON.parse(options.body).operations;patches.push(...operations);return {{revision:1,ids:['issue:r:1:','issue:r:2:'],accepted_operation_ids:operations.map(x=>x.operation_id)}}}},
onRemoteIds:()=>{{}},onStatus:(state,detail={{}})=>statuses.push([state,detail.discarded||0])}});
(async()=>{{const result=await sync.flush();process.stdout.write(JSON.stringify({{
result,patches,statuses,remaining:[...values.keys()].filter(key=>key.startsWith(prefix)),pending:sync.pending()
}}));}})();
"""
result = json.loads(subprocess.run(
["node", "-e", script], check=True, capture_output=True, text=True
).stdout)
assert result["result"] is True
assert [item["operation_id"] for item in result["patches"]] == ["first", "second"]
assert result["pending"] == []
assert result["remaining"] == []
assert result["statuses"][-1] == ["recovered", 2]
def test_today_sync_reports_queue_recovery_instead_of_plain_saved_status():
source = DASHBOARD.read_text()
assert "Recovered ${detail.discarded} Today edit" in source
assert "discarded ${detail.discarded} unreadable device record" in source
def test_today_capacity_configuration_syncs_offline_and_adopts_remote_plan():
script = f"""
const createTodaySync = require({json.dumps(str(TODAY_SYNC))});