import json import subprocess from pathlib import Path import pytest from tests.dashboard_bundle import dashboard OUTBOX = Path(__file__).parents[1] / "frontend" / "authored-outbox.js" def run_node(script: str): result = subprocess.run(["node", "-e", script], check=True, capture_output=True, text=True) return json.loads(result.stdout) def test_authored_outbox_quarantines_legacy_and_cross_account_messages(): script = f""" const createAuthoredOutbox = require({json.dumps(str(OUTBOX))}); const values = new Map([['stackchain.authored-outbox.v1', JSON.stringify({{version:1,items:[ {{id:'legacy',operationId:'legacy',kind:'issue-comment',repository:'o/r',number:1,body:'Old',status:'queued'}} ]}})]]); const storage = {{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v)}}; const calls = []; const outbox = createAuthoredOutbox({{ storage, getOwnerLogin:()=>'timmy', fetchJson:async url => {{calls.push(url); return {{id:1}};}}, }}); const bound = outbox.enqueue({{kind:'issue-comment',repository:'o/r',number:2,body:'Mine',operationId:'mine'}}); (async()=>{{ const wrong = await outbox.flush('alexander'); const right = await outbox.flush('timmy'); process.stdout.write(JSON.stringify({{bound,wrong,right,calls,remaining:outbox.list()}})); }})(); """ output = run_node(script) assert output["bound"]["ownerLogin"] == "timmy" assert output["wrong"]["blocked"] == 2 assert len(output["right"]["confirmed"]) == 1 assert [item["id"] for item in output["remaining"]] == ["legacy"] assert len(output["calls"]) == 1 def test_authored_outbox_persists_each_message_kind_and_flushes_sequentially(): script = f""" const createAuthoredOutbox = require({json.dumps(str(OUTBOX))}); const values = new Map(); const storage = {{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v),removeItem:k=>values.delete(k)}}; const calls = []; const outbox = createAuthoredOutbox({{ storage, getOwnerLogin:()=>'timmy', now:() => 1234, fetchJson:async (url, options) => {{ calls.push({{url,key:options.headers['Idempotency-Key'],body:JSON.parse(options.body)}}); return {{id:calls.length}}; }}, }}); outbox.enqueue({{kind:'issue-comment',repository:'stackchain/api',number:7,body:'Issue note',operationId:'issue-op'}}); outbox.enqueue({{kind:'pull-comment',repository:'stackchain/web',number:8,body:'PR note',operationId:'pull-op'}}); outbox.enqueue({{kind:'update-reply',notificationId:9,body:'Update note',operationId:'update-op'}}); const persisted = createAuthoredOutbox({{storage,fetchJson:outbox.fetchJson}}).list(); outbox.flush('timmy').then(result => process.stdout.write(JSON.stringify({{persisted,calls,result,remaining:outbox.list()}}))); """ output = run_node(script) assert [item["kind"] for item in output["persisted"]] == [ "issue-comment", "pull-comment", "update-reply" ] assert [item["operationId"] for item in output["persisted"]] == ["issue-op", "pull-op", "update-op"] assert output["calls"] == [ {"url": "api/v1/repos/stackchain/api/issues/7/comments", "key": "issue-op", "body": {"body": "Issue note"}}, {"url": "api/v1/repos/stackchain/web/pulls/8/comments", "key": "pull-op", "body": {"body": "PR note"}}, {"url": "api/v1/notifications/9/reply", "key": "update-op", "body": {"body": "Update note"}}, ] assert len(output["result"]["confirmed"]) == 3 assert output["remaining"] == [] def test_authored_outbox_persists_and_delivers_revision_checked_issue_content(): script = f""" const createAuthoredOutbox = require({json.dumps(str(OUTBOX))}); const values = new Map(); const calls = []; const storage = {{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v),removeItem:k=>values.delete(k)}}; const outbox = createAuthoredOutbox({{ storage, getOwnerLogin:()=> 'timmy', fetchJson: async (url, options) => {{ calls.push({{url,method:options.method,key:options.headers['Idempotency-Key'],body:JSON.parse(options.body)}}); return {{repository:'stackchain/dashboard',number:17,title:'Ship',body:'- [x] Test',updated_at:'2026-08-15T11:00:00Z'}}; }}, }}); const queued = outbox.enqueue({{ kind:'issue-content',repository:'stackchain/dashboard',number:17,operationId:'check-op', title:'Ship',body:'- [x] Test',expectedUpdatedAt:'2026-08-15T10:00:00Z', }}); const restored = createAuthoredOutbox({{storage}}).list()[0]; outbox.flush('timmy').then(result => process.stdout.write(JSON.stringify({{queued,restored,calls,result,remaining:outbox.list()}}))); """ output = run_node(script) assert output["queued"]["expectedUpdatedAt"] == "2026-08-15T10:00:00Z" assert output["restored"]["title"] == "Ship" assert output["calls"] == [{ "url": "api/v1/repos/stackchain/dashboard/issues/17/content", "method": "PATCH", "key": "check-op", "body": { "title": "Ship", "body": "- [x] Test", "expected_updated_at": "2026-08-15T10:00:00Z", }, }] assert output["result"]["confirmed"][0]["body"] == "- [x] Test" assert output["remaining"] == [] def test_durable_issue_content_admission_coalesces_latest_body_on_original_revision(): script = f""" const createAuthoredOutbox = require({json.dumps(str(OUTBOX))}); const values = new Map(); const mirrors = []; const ids = ['check-1', 'check-2']; const storage = {{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v)}}; const outbox = createAuthoredOutbox({{ storage, getOwnerLogin:()=> 'timmy', createOperationId:()=>ids.shift(), backgroundSync:{{ reconcile:async items=>mirrors.push(items.map(item=>({{...item}}))), requestSync:async()=>{{}}, }}, }}); (async()=>{{ await outbox.enqueueDurably({{kind:'issue-content',repository:'stackchain/dashboard',number:17, title:'Ship',body:'- [x] Build\\n- [ ] Test',expectedUpdatedAt:'server-revision'}}); const second = await outbox.enqueueDurably({{kind:'issue-content',repository:'stackchain/dashboard',number:17, title:'Ship',body:'- [x] Build\\n- [x] Test',expectedUpdatedAt:'pending-local-revision'}}); process.stdout.write(JSON.stringify({{items:outbox.list(),second,mirrors}})); }})(); """ output = run_node(script) assert len(output["items"]) == 1 assert output["items"][0]["id"] == "check-1" assert output["items"][0]["operationId"] == "check-2" assert output["items"][0]["body"] == "- [x] Build\n- [x] Test" assert output["items"][0]["expectedUpdatedAt"] == "server-revision" assert output["second"]["item"] == output["items"][0] assert len(output["mirrors"][1]) == 1 assert output["mirrors"][1][0]["operationId"] == "check-2" def test_failed_durable_issue_content_replacement_restores_previous_intent(): script = f""" const createAuthoredOutbox = require({json.dumps(str(OUTBOX))}); const values = new Map(); const ids = ['check-1', 'check-2']; let admissions = 0; const storage = {{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v)}}; const outbox = createAuthoredOutbox({{ storage, getOwnerLogin:()=> 'timmy', createOperationId:()=>ids.shift(), backgroundSync:{{ reconcile:async()=>{{if (++admissions === 2) throw new Error('IndexedDB unavailable');}}, requestSync:async()=>{{}}, }}, }}); (async()=>{{ await outbox.enqueueDurably({{kind:'issue-content',repository:'o/r',number:9, title:'Ship',body:'- [x] Build\\n- [ ] Test',expectedUpdatedAt:'server-revision'}}); let error = ''; try {{ await outbox.enqueueDurably({{kind:'issue-content',repository:'o/r',number:9, title:'Ship',body:'- [x] Build\\n- [x] Test',expectedUpdatedAt:'server-revision'}}); }} catch (caught) {{ error = caught.message; }} process.stdout.write(JSON.stringify({{error,items:outbox.list()}})); }})(); """ output = run_node(script) assert output["error"] == "IndexedDB unavailable" assert len(output["items"]) == 1 assert output["items"][0]["operationId"] == "check-1" assert output["items"][0]["body"] == "- [x] Build\n- [ ] Test" def test_authored_outbox_persists_and_delivers_desired_blocker_state(): script = f""" const createAuthoredOutbox = require({json.dumps(str(OUTBOX))}); const values = new Map(); const calls = []; const storage = {{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v),removeItem:k=>values.delete(k)}}; const outbox = createAuthoredOutbox({{ storage, getOwnerLogin:()=> 'timmy', fetchJson: async (url, options) => {{ calls.push({{url,method:options.method,key:options.headers['Idempotency-Key'],body:JSON.parse(options.body)}}); return {{repository:'stackchain/dashboard',number:17,dependencies_available:true,dependencies:[]}}; }}, }}); const queued = outbox.enqueue({{ kind:'issue-blocker',repository:'stackchain/dashboard',number:17,operationId:'blocker-op', blockerRepository:'stackchain/api',blockerNumber:9,present:false, }}); const restored = createAuthoredOutbox({{storage}}).list()[0]; outbox.flush('timmy').then(result => process.stdout.write(JSON.stringify({{queued,restored,calls,result,remaining:outbox.list()}}))); """ output = run_node(script) assert output["queued"]["blockerRepository"] == "stackchain/api" assert output["queued"]["blockerNumber"] == 9 assert output["queued"]["present"] is False assert output["restored"]["present"] is False assert output["calls"] == [{ "url": "api/v1/repos/stackchain/dashboard/issues/17/blockers", "method": "PATCH", "key": "blocker-op", "body": {"repository": "stackchain/api", "number": 9, "present": False}, }] assert output["result"]["confirmed"][0]["dependencies"] == [] assert output["remaining"] == [] def test_authored_outbox_exposes_sending_then_preserves_transient_attempt_details(): script = f""" const createAuthoredOutbox = require({json.dumps(str(OUTBOX))}); const values = new Map(); const storage = {{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v)}}; let release; const gate = new Promise(resolve => release = resolve); const outbox = createAuthoredOutbox({{ storage, getOwnerLogin:()=>'timmy', now:()=>777, fetchJson:async()=>{{await gate; const error=new Error('Network unavailable');error.status=503;throw error;}}, }}); outbox.enqueue({{kind:'issue-comment',repository:'o/r',number:1,body:'Wait',operationId:'attempt'}}); const pending=outbox.flush('timmy'); const sending=outbox.list()[0]; release(); pending.then(()=>process.stdout.write(JSON.stringify({{sending,after:outbox.list()[0]}}))); """ output = run_node(script) assert output["sending"]["status"] == "sending" assert output["after"]["status"] == "queued" assert output["after"]["lastAttemptAt"] == 777 assert output["after"]["lastAttemptError"] == "Network unavailable" def test_authored_outbox_persists_and_delivers_complete_pull_review_payload(): script = f""" const createAuthoredOutbox = require({json.dumps(str(OUTBOX))}); const values = new Map(); const calls = []; const storage = {{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v),removeItem:k=>values.delete(k)}}; const outbox = createAuthoredOutbox({{ storage, getOwnerLogin:()=> 'timmy', fetchJson: async (url, options) => {{ calls.push({{url, options}}); return {{id:44}}; }}, }}); let queued; try {{ queued = outbox.enqueue({{ kind:'pull-review', repository:'stackchain/web', number:8, operationId:'review-op', body:'Looks good', decision:'approve', expectedHeadSha:'abc123', comments:[{{path:'app.js',body:'Nice',new_position:4}}], draftKey:'stackchain.review-draft.v1:stackchain/web#8@abc123', progressKey:'stackchain.review-progress.v1:stackchain/web#8@abc123', draftFingerprint:'draft', progressFingerprint:'progress', }}); }} catch (error) {{ process.stdout.write(JSON.stringify({{error:error.message}})); }} if (queued) {{ storage.setItem(queued.draftKey, 'draft'); storage.setItem(queued.progressKey, 'progress'); outbox.flush('timmy').then(result => process.stdout.write(JSON.stringify({{ queued, calls:calls.map(call=>({{url:call.url,key:call.options.headers['Idempotency-Key'],body:JSON.parse(call.options.body)}})), result, remaining:outbox.list(), draft:storage.getItem(queued.draftKey), progress:storage.getItem(queued.progressKey), }}))); }} """ output = run_node(script) assert "error" not in output, output.get("error") assert output["queued"]["kind"] == "pull-review" assert output["queued"]["comments"] == [{"path": "app.js", "body": "Nice", "new_position": 4}] assert output["calls"] == [{ "url": "api/v1/repos/stackchain/web/pulls/8/review", "key": "review-op", "body": { "body": "Looks good", "decision": "approve", "expected_head_sha": "abc123", "comments": [{"path": "app.js", "body": "Nice", "new_position": 4}], }, }] assert output["remaining"] == [] assert output["draft"] is None assert output["progress"] is None def test_authored_outbox_requires_explicit_retry_to_authorize_issue_closure(): script = f""" const createAuthoredOutbox = require({json.dumps(str(OUTBOX))}); const values = new Map(); const calls = []; const storage = {{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v),removeItem:k=>values.delete(k)}}; const outbox = createAuthoredOutbox({{ storage, getOwnerLogin:()=> 'timmy', fetchJson: async (url, options) => {{ calls.push({{url,options}}); return {{number:27,state:'closed'}}; }}, }}); const queued = outbox.enqueue({{ kind:'issue-close',repository:'stackchain/dashboard',number:27,operationId:'close-op' }}); (async()=>{{ const automatic = await outbox.flush('timmy'); const awaitingAuthorization = outbox.list(); const explicit = await outbox.retry(queued.id, 'timmy'); process.stdout.write(JSON.stringify({{ queued,automatic,awaitingAuthorization,explicit,calls,remaining:outbox.list() }})); }})(); """ output = run_node(script) assert output["queued"]["kind"] == "issue-close" assert output["automatic"]["confirmed"] == [] assert output["awaitingAuthorization"][0]["status"] == "queued" assert output["calls"] == [{ "url": "api/v1/repos/stackchain/dashboard/issues/27/close", "options": { "method": "PATCH", "headers": {"Accept": "application/json", "Idempotency-Key": "close-op"}, }, }] assert output["explicit"]["confirmed"] == [{"number": 27, "state": "closed"}] assert output["remaining"] == [] def test_queued_closure_stays_durable_through_background_skip_then_closes_from_explicit_retry(): sync = Path(__file__).parents[1] / "frontend" / "background-issue-sync.js" script = f""" const createAuthoredOutbox=require({json.dumps(str(OUTBOX))}); const createBackgroundIssueSync=require({json.dumps(str(sync))}); const values=new Map();const records=new Map();let tail=Promise.resolve();const calls=[]; const storage={{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v),removeItem:k=>values.delete(k)}}; const transaction=work=>{{const run=tail.then(()=>work({{ get:async id=>records.get(id),getAll:async()=>[...records.values()].map(value=>({{...value}})), put:async value=>records.set(value.id,{{...value}}),delete:async id=>records.delete(id), }}));tail=run.catch(()=>{{}});return run;}}; const fetchJson=async(url,options={{}})=>{{ calls.push({{url,key:options.headers?.['Idempotency-Key'] || ''}}); return url==='api/v1/background-identity'?{{login:'timmy'}}:{{number:27,state:'closed'}}; }}; (async()=>{{ const store=createBackgroundIssueSync.createIssueSyncStore({{transaction}}); const background=createBackgroundIssueSync({{store,fetchJson}});background.requestSync=async()=>{{}}; const outbox=createAuthoredOutbox({{storage,fetchJson,getOwnerLogin:()=>'timmy',backgroundSync:background}}); const admitted=await outbox.enqueueDurably({{kind:'issue-close',repository:'stackchain/dashboard',number:27,operationId:'close-op'}}); const automatic=await background.flush(); outbox.reconcileBackground(await background.snapshot()); const foregroundFlush=await outbox.flush('timmy'); const explicit=await outbox.retry(admitted.item.id,'timmy'); process.stdout.write(JSON.stringify({{automatic,foregroundFlush,explicit,calls,remaining:outbox.list(),snapshot:await background.snapshot()}})); }})(); """ output = run_node(script) assert output["automatic"]["confirmed"] == [] assert output["foregroundFlush"]["confirmed"] == [] assert output["calls"] == [ {"url": "api/v1/background-identity", "key": ""}, {"url": "api/v1/repos/stackchain/dashboard/issues/27/close", "key": "close-op"}, ] assert output["explicit"]["confirmed"] == [{"number": 27, "state": "closed"}] assert output["remaining"] == [] assert output["snapshot"][0]["status"] == "sent" def test_authored_outbox_classifies_failures_and_continues_past_attention_items(): script = f""" const createAuthoredOutbox = require({json.dumps(str(OUTBOX))}); const values = new Map(); const storage = {{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v),removeItem:k=>values.delete(k)}}; let phase = 'permanent'; const calls = []; const outbox = createAuthoredOutbox({{ storage, getOwnerLogin:()=>'timmy', fetchJson:async (_url, options) => {{ const body = JSON.parse(options.body).body; calls.push(body); if (body === 'Bad' && phase === 'permanent') {{ const e = new Error('Reply rejected'); e.status=422; throw e; }} if (body === 'Later' && phase === 'transient') {{ const e = new Error('Offline'); e.status=503; throw e; }} return {{id:calls.length}}; }}, }}); const bad=outbox.enqueue({{kind:'issue-comment',repository:'o/r',number:1,body:'Bad',operationId:'a'}}); outbox.enqueue({{kind:'pull-comment',repository:'o/r',number:2,body:'Good',operationId:'b'}}); outbox.flush('timmy').then(async first => {{ phase='transient'; outbox.enqueue({{kind:'update-reply',notificationId:3,body:'Later',operationId:'c'}}); const second=await outbox.flush('timmy'); process.stdout.write(JSON.stringify({{first,second,calls,remaining:outbox.list(),badId:bad.id}})); }}); """ output = run_node(script) assert output["calls"] == ["Bad", "Good", "Later"] assert len(output["first"]["confirmed"]) == 1 assert output["remaining"][0]["id"] == output["badId"] assert output["remaining"][0]["status"] == "attention" assert output["remaining"][0]["error"] == "Reply rejected" assert output["remaining"][1]["status"] == "queued" def test_authored_outbox_requires_deliberate_rekey_after_uncertain_delivery(): script = f""" const createAuthoredOutbox = require({json.dumps(str(OUTBOX))}); const values = new Map(); let sequence=0; const calls=[]; const storage = {{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v)}}; const outbox = createAuthoredOutbox({{ storage, getOwnerLogin:()=>'timmy', createOperationId:()=> 'verified-' + (++sequence), fetchJson:async (_url, options) => {{ const key=options.headers['Idempotency-Key']; calls.push(key); if (key === 'uncertain-key') {{ const e=new Error('Verify it was not posted before retrying.'); e.status=422; e.code='delivery_uncertain'; throw e; }} return {{id:calls.length}}; }}, }}); const uncertain=outbox.enqueue({{kind:'issue-comment',repository:'o/r',number:1,body:'Check',operationId:'uncertain-key'}}); outbox.enqueue({{kind:'pull-comment',repository:'o/r',number:2,body:'Continue',operationId:'other-key'}}); (async()=>{{ const first=await outbox.flush('timmy'); const attention=outbox.list()[0]; const retried=await outbox.retry(uncertain.id,'timmy'); process.stdout.write(JSON.stringify({{first,attention,retried,calls,remaining:outbox.list()}})); }})(); """ output = run_node(script) assert output["calls"] == ["uncertain-key", "other-key", "verified-1"] assert len(output["first"]["confirmed"]) == 1 assert output["attention"]["status"] == "attention" assert output["attention"]["deliveryState"] == "uncertain" assert output["remaining"] == [] def test_authored_outbox_retry_is_single_flight_and_edit_rotates_identity(): script = f""" const createAuthoredOutbox = require({json.dumps(str(OUTBOX))}); const values = new Map(); const storage = {{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v),removeItem:k=>values.delete(k)}}; let release; const gate=new Promise(resolve=>release=resolve); let calls=0; let sequence=0; const outbox=createAuthoredOutbox({{ storage, getOwnerLogin:()=>'timmy', createOperationId:()=> 'new-' + (++sequence), fetchJson:async()=>{{calls++; await gate; return {{id:1}};}}, }}); const item=outbox.enqueue({{kind:'issue-comment',repository:'o/r',number:1,body:'Old',operationId:'old'}}); const edited=outbox.update(item.id,{{body:'New'}}); const flush=outbox.flush('timmy'); const retry=outbox.retry(item.id, 'timmy'); release(); Promise.all([flush,retry]).then(results=>process.stdout.write(JSON.stringify({{edited,calls,results,remaining:outbox.list()}}))); """ output = run_node(script) assert output["edited"]["body"] == "New" assert output["edited"]["operationId"] == "new-1" assert output["calls"] == 1 assert output["remaining"] == [] def test_authored_outbox_deduplicates_repeated_queue_attempts_by_operation_id(): script = f""" const createAuthoredOutbox = require({json.dumps(str(OUTBOX))}); const values = new Map(); const storage = {{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v)}}; const outbox=createAuthoredOutbox({{storage,getOwnerLogin:()=>'timmy'}}); const first=outbox.enqueue({{kind:'issue-comment',repository:'o/r',number:1,body:'Same',operationId:'stable'}}); const second=outbox.enqueue({{kind:'issue-comment',repository:'o/r',number:1,body:'Same',operationId:'stable'}}); process.stdout.write(JSON.stringify({{first,second,items:outbox.list()}})); """ output = run_node(script) assert output["first"] == output["second"] assert len(output["items"]) == 1 def test_authored_outbox_deduplicates_pull_review_for_same_head_after_reload(): script = f""" const createAuthoredOutbox = require({json.dumps(str(OUTBOX))}); const values=new Map();let sequence=0; const storage={{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v)}}; const make=()=>createAuthoredOutbox({{storage,getOwnerLogin:()=>'timmy',createOperationId:()=> 'op-' + (++sequence)}}); const first=make().enqueue({{kind:'pull-review',repository:'o/r',number:7,expectedHeadSha:'abc',decision:'approve',body:'Ready'}}); const second=make().enqueue({{kind:'pull-review',repository:'o/r',number:7,expectedHeadSha:'abc',decision:'approve',body:'Ready'}}); process.stdout.write(JSON.stringify({{first,second,items:make().list()}})); """ output = run_node(script) assert output["first"] == output["second"] assert len(output["items"]) == 1 def test_authored_outbox_rejects_changed_feedback_while_same_head_is_queued(): script = f""" const createAuthoredOutbox = require({json.dumps(str(OUTBOX))}); const values=new Map();const storage={{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v)}}; const outbox=createAuthoredOutbox({{storage,getOwnerLogin:()=>'timmy'}}); outbox.enqueue({{kind:'pull-review',repository:'o/r',number:7,expectedHeadSha:'abc',decision:'approve',body:'First'}}); let error='';try{{outbox.enqueue({{kind:'pull-review',repository:'o/r',number:7,expectedHeadSha:'abc',decision:'request_changes',body:'Changed'}});}}catch(e){{error=e.message;}} process.stdout.write(JSON.stringify({{error,items:outbox.list()}})); """ output = run_node(script) assert output["error"] == "A review for this saved head is already queued. Open Drafts to inspect or discard it first." assert len(output["items"]) == 1 def test_confirmed_review_keeps_draft_edits_made_after_it_was_queued(): script = f""" const createAuthoredOutbox = require({json.dumps(str(OUTBOX))}); const values=new Map();const storage={{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v),removeItem:k=>values.delete(k)}}; const draftKey='draft-key';const progressKey='progress-key';storage.setItem(draftKey,'old-draft');storage.setItem(progressKey,'old-progress'); const outbox=createAuthoredOutbox({{storage,getOwnerLogin:()=>'timmy',fetchJson:async()=>({{id:1}})}}); outbox.enqueue({{kind:'pull-review',repository:'o/r',number:7,expectedHeadSha:'abc',body:'Queued',draftKey,progressKey,draftFingerprint:'old-draft',progressFingerprint:'old-progress'}}); storage.setItem(draftKey,'newer-draft');storage.setItem(progressKey,'newer-progress'); outbox.flush('timmy').then(()=>process.stdout.write(JSON.stringify({{draft:storage.getItem(draftKey),progress:storage.getItem(progressKey)}}))); """ output = run_node(script) assert output == {"draft": "newer-draft", "progress": "newer-progress"} def test_authored_outbox_mirrors_to_background_sync_and_reconciles_worker_results(): script = f""" const createAuthoredOutbox = require({json.dumps(str(OUTBOX))}); const values = new Map(); const mirrors=[]; let requested=0; const storage = {{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v)}}; const backgroundSync = {{ reconcile: async (items, lane) => mirrors.push({{items:items.map(item=>({{...item}})),lane}}), requestSync: async () => {{requested += 1;}}, }}; const outbox=createAuthoredOutbox({{storage,getOwnerLogin:()=>'timmy',backgroundSync}}); const sent=outbox.enqueue({{kind:'issue-comment',repository:'o/r',number:1,body:'Sent',operationId:'sent'}}); const failed=outbox.enqueue({{kind:'update-reply',notificationId:2,body:'Fix me',operationId:'failed'}}); setTimeout(() => {{ const reconciled=outbox.reconcileBackground([ {{...sent,status:'sent'}}, {{...failed,status:'attention',error:'Reply rejected'}}, ]); setTimeout(() => process.stdout.write(JSON.stringify({{mirrors,requested,reconciled}})), 0); }}, 0); """ output = run_node(script) assert output["mirrors"][0]["lane"] == "authored" assert [item["operationId"] for item in output["mirrors"][-1]["items"]] == ["failed"] assert output["requested"] >= 1 assert [(item["operationId"], item["status"]) for item in output["reconciled"]] == [ ("failed", "attention") ] def test_authored_outbox_reconciles_uncertain_worker_delivery_state(): script = f""" const createAuthoredOutbox = require({json.dumps(str(OUTBOX))}); const values=new Map(); const storage={{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v)}}; const outbox=createAuthoredOutbox({{storage,getOwnerLogin:()=>'timmy'}}); const item=outbox.enqueue({{kind:'issue-comment',repository:'o/r',number:7,body:'Maybe',operationId:'maybe'}}); const reconciled=outbox.reconcileBackground([{{...item,status:'attention',deliveryState:'uncertain',error:'Verify first'}}]); process.stdout.write(JSON.stringify(reconciled[0])); """ output = run_node(script) assert output["status"] == "attention" assert output["deliveryState"] == "uncertain" def test_authored_outbox_waits_for_durable_background_admission(): script = f""" const createAuthoredOutbox = require({json.dumps(str(OUTBOX))}); const values = new Map(); const storage = {{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v)}}; let release; const gate = new Promise(resolve => release = resolve); const events = []; const outbox = createAuthoredOutbox({{ storage, getOwnerLogin:()=> 'timmy', backgroundSync: {{ reconcile: async (_items, lane) => {{ events.push('mirror:' + lane); await gate; events.push('committed'); }}, requestSync: async () => events.push('registered'), }}, }}); const admission = outbox.enqueueDurably({{ kind:'issue-comment',repository:'o/r',number:1,body:'Do not lose',operationId:'message-1' }}).then(result => {{ events.push('confirmed'); return result; }}); Promise.resolve().then(async () => {{ const pending = events.slice(); release(); const result = await admission; process.stdout.write(JSON.stringify({{pending,events,result,items:outbox.list()}})); }}); """ output = run_node(script) assert output["pending"] == ["mirror:authored"] assert output["events"] == ["mirror:authored", "committed", "registered", "confirmed"] assert output["result"]["durability"] == "background" assert output["items"][0]["operationId"] == "message-1" def test_authored_outbox_foreground_send_uses_atomic_background_delivery(): script = f""" const createAuthoredOutbox = require({json.dumps(str(OUTBOX))}); const values = new Map(); let backgroundCalls=0; let directCalls=0; const storage = {{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v)}}; const backgroundSync = {{ reconcile: async()=>{{}}, requestSync:async()=>{{}}, send: async (item, owner) => {{backgroundCalls += 1; return {{message:{{id:3,owner}}}};}}, }}; const outbox=createAuthoredOutbox({{ storage,getOwnerLogin:()=>'timmy',backgroundSync, fetchJson:async()=>{{directCalls += 1; return {{id:4}};}}, }}); outbox.enqueue({{kind:'pull-comment',repository:'o/r',number:2,body:'Review',operationId:'once'}}); (async()=>{{ const result=await outbox.flush('timmy'); process.stdout.write(JSON.stringify({{backgroundCalls,directCalls,result,remaining:outbox.list()}})); }})(); """ output = run_node(script) assert output["backgroundCalls"] == 1 assert output["directCalls"] == 0 assert output["result"]["confirmed"] == [{"id": 3, "owner": "timmy"}] assert output["remaining"] == [] def test_authorization_hold_can_resume_in_foreground_with_original_review_identity(): script = f""" const createAuthoredOutbox = require({json.dumps(str(OUTBOX))}); const values=new Map();const sent=[]; const storage={{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v)}}; const outbox=createAuthoredOutbox({{ storage,getOwnerLogin:()=>'timmy', backgroundSync:{{reconcile:async()=>{{}},requestSync:async()=>{{}}, send:async item=>{{sent.push({{operationId:item.operationId,status:item.status, head:item.expectedHeadSha,decision:item.decision}});return{{message:{{id:91}}}};}}}}, }}); outbox.enqueue({{kind:'pull-review',repository:'o/r',number:7,operationId:'review-stable', body:'Ship it',decision:'approve',expectedHeadSha:'abc123'}}); outbox.reconcileBackground([{{id:'review-stable',kind:'pull-review',status:'authorization', error:'Fresh authorization required'}}]); (async()=>{{const held=outbox.list()[0];const result=await outbox.retry(held.id,'timmy'); process.stdout.write(JSON.stringify({{held,sent,result,remaining:outbox.list()}}));}})(); """ output = run_node(script) assert output["held"]["status"] == "authorization" assert output["sent"] == [{ "operationId": "review-stable", "status": "authorization", "head": "abc123", "decision": "approve", }] assert output["result"]["confirmed"] == [{"id": 91}] assert output["remaining"] == [] @pytest.mark.anyio async def test_mobile_dashboard_loads_and_operates_authored_message_outbox(): html = await dashboard() assert '' in html assert "const authoredOutbox = createAuthoredOutbox({" in html assert "activeFlushLogin = contextIdentityFresh ?" in html assert "flushAuthoredOutbox();" in html assert "await authoredOutbox.enqueueDurably" in html assert "Saving for background delivery…" in html assert "Saved for next launch; background delivery unavailable." in html assert "authoredOutbox.retry(item.outbox_id, activeFlushLogin)" in html assert "authoredOutbox.discard(item.outbox_id)" in html assert "if (result?.queued)" in html assert "backgroundSync: backgroundIssueSync" in html assert "authoredOutbox.reconcileBackground(records)" in html def test_screenshot_comment_admits_blob_to_indexeddb_without_putting_bytes_in_localstorage(): script = f""" const createAuthoredOutbox = require({json.dumps(str(OUTBOX))}); const values = new Map(); const mirrors=[]; const storage = {{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v),removeItem:k=>values.delete(k)}}; const outbox=createAuthoredOutbox({{ storage,getOwnerLogin:()=>'timmy', backgroundSync:{{reconcile:async(items,lane)=>mirrors.push({{items,lane}}),requestSync:async()=>{{}}}}, }}); (async()=>{{ const blob=new Blob(['PRIVATE-IMAGE-BYTES'],{{type:'image/png'}}); const admission=await outbox.enqueueDurably({{ kind:'issue-comment',repository:'stackchain/dashboard',number:477, body:'Broken at 320px',operationId:'comment-image-477', attachment:{{filename:'phone.png',contentType:'image/png',blob}}, }}); const durable=mirrors[0].items[0].attachment; process.stdout.write(JSON.stringify({{admission,local:values.get('stackchain.authored-outbox.v1'), mirrored:{{lane:mirrors[0].lane,isBlob:durable.blob instanceof Blob,size:durable.blob?.size,text:await durable.blob?.text()}}}})); }})(); """ output = run_node(script) assert "PRIVATE-IMAGE-BYTES" not in output["local"] local_item = json.loads(output["local"])["items"][0] assert local_item["attachment"] == { "filename": "phone.png", "contentType": "image/png", "stored": True } assert output["mirrored"] == { "lane": "authored", "isBlob": True, "size": 19, "text": "PRIVATE-IMAGE-BYTES" } assert output["admission"]["durability"] == "background" def test_screenshot_comment_failed_indexeddb_admission_is_not_accepted_locally(): script = f""" const createAuthoredOutbox=require({json.dumps(str(OUTBOX))}); const values=new Map(); const storage={{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v),removeItem:k=>values.delete(k)}}; const outbox=createAuthoredOutbox({{storage,getOwnerLogin:()=>'timmy',backgroundSync:{{ reconcile:async()=>{{throw new Error('IndexedDB unavailable');}},requestSync:async()=>{{}}, }}}}); (async()=>{{ let error='';try{{await outbox.enqueueDurably({{kind:'issue-comment',repository:'o/r',number:1, body:'Keep me',operationId:'image-op',attachment:{{filename:'a.png',contentType:'image/png',data:'abc'}}}});}} catch(caught){{error=caught.message;}} process.stdout.write(JSON.stringify({{error,items:outbox.list()}})); }})(); """ output = run_node(script) assert output == {"error": "IndexedDB unavailable", "items": []} def test_pull_screenshot_comment_persists_blob_only_in_indexeddb(): script = f""" const createAuthoredOutbox=require({json.dumps(str(OUTBOX))}); const values=new Map();const mirrors=[]; const storage={{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v)}}; const outbox=createAuthoredOutbox({{storage,getOwnerLogin:()=>'timmy',backgroundSync:{{ reconcile:async items=>mirrors.push(items),requestSync:async()=>{{}}, }}}}); (async()=>{{const blob=new Blob(['PULL-PRIVATE-BYTES'],{{type:'image/webp'}}); await outbox.enqueueDurably({{kind:'pull-comment',repository:'stackchain/web',number:31, body:'Mobile proof',operationId:'pull-image-31', attachment:{{filename:'proof.webp',contentType:'image/webp',blob}}}}); const local=values.get('stackchain.authored-outbox.v1');const durable=mirrors[0][0].attachment; process.stdout.write(JSON.stringify({{local,metadata:JSON.parse(local).items[0].attachment, durable:{{isBlob:durable.blob instanceof Blob,text:await durable.blob.text()}}}})); }})(); """ output = run_node(script) assert "PULL-PRIVATE-BYTES" not in output["local"] assert output["metadata"] == { "filename": "proof.webp", "contentType": "image/webp", "stored": True } assert output["durable"] == {"isBlob": True, "text": "PULL-PRIVATE-BYTES"}