From 79c8f1626b48ce1f7af7c85de9bc81c7f5bfeac2 Mon Sep 17 00:00:00 2001 From: timmy Date: Mon, 10 Aug 2026 01:33:55 +0000 Subject: [PATCH] perf: bound Today readiness latency (#441) --- frontend/service-worker.js | 2 +- frontend/today-readiness.js | 10 +++-- tests/test_later_sync.py | 2 +- tests/test_markdown_renderer.py | 2 +- tests/test_mobile_composer_integration.py | 2 +- tests/test_plan_today.py | 2 +- tests/test_service_worker.py | 18 ++++----- tests/test_today_readiness.py | 49 ++++++++++++++++++++--- tests/test_today_sync.py | 2 +- 9 files changed, 66 insertions(+), 23 deletions(-) diff --git a/frontend/service-worker.js b/frontend/service-worker.js index c53e623..5262706 100644 --- a/frontend/service-worker.js +++ b/frontend/service-worker.js @@ -1,6 +1,6 @@ const BASE = new URL('./', self.location.href).pathname; importScripts(BASE + 'static/background-issue-sync.js'); -const CACHE = 'stackchain-dashboard-shell-v73'; +const CACHE = 'stackchain-dashboard-shell-v74'; const OFFLINE_LEASE_URL = new URL(BASE + '__offline-session-lease', self.location.origin).href; const OUTAGE_STATUSES = new Set([500, 502, 503, 504]); const NAVIGATION_TIMEOUT_MS = self.__STACKCHAIN_NAVIGATION_TIMEOUT_MS || 4000; diff --git a/frontend/today-readiness.js b/frontend/today-readiness.js index dea83a2..94ce965 100644 --- a/frontend/today-readiness.js +++ b/frontend/today-readiness.js @@ -32,15 +32,19 @@ const candidates = preferredIndex >= 0 ? ordered.slice(preferredIndex).concat(ordered.slice(0, preferredIndex)) : [preferred].concat(ordered); - const states = []; - for (const item of candidates) states.push({ item, ...(await classify(item)) }); + const targetState = { item:preferred, ...(await classify(preferred)) }; if (request !== generation) return 'superseded'; - const targetState = states[0]; if (targetState.status === 'ready') { pending = null; onOpen(action, preferred); return 'opened'; } + const fallbackStates = await Promise.all(candidates.slice(1).map(async item => ({ + item, + ...(await classify(item)), + }))); + const states = [targetState, ...fallbackStates]; + if (request !== generation) return 'superseded'; const nextReadyState = states.slice(1).find(state => state.status === 'ready'); pending = { action, diff --git a/tests/test_later_sync.py b/tests/test_later_sync.py index 4567bbf..7ff1f73 100644 --- a/tests/test_later_sync.py +++ b/tests/test_later_sync.py @@ -347,5 +347,5 @@ async def test_dashboard_syncs_every_later_change_and_exposes_account_status(): def test_later_sync_ships_atomically_in_the_offline_shell(): source = (Path(__file__).parents[1] / "frontend" / "service-worker.js").read_text() - assert "stackchain-dashboard-shell-v73" in source + assert "stackchain-dashboard-shell-v74" in source assert "BASE + 'static/later-sync.js'" in source diff --git a/tests/test_markdown_renderer.py b/tests/test_markdown_renderer.py index 7d02150..68a30e4 100644 --- a/tests/test_markdown_renderer.py +++ b/tests/test_markdown_renderer.py @@ -137,4 +137,4 @@ def test_markdown_work_bodies_are_mobile_safe_block_containers(): assert ".markdown-content { min-width:0; max-width:100%; overflow-wrap:anywhere;" in css assert ".markdown-content pre { max-width:100%; overflow-x:auto;" in css assert ".markdown-content a { min-height:44px;" in css - assert "stackchain-dashboard-shell-v73" in worker + assert "stackchain-dashboard-shell-v74" in worker diff --git a/tests/test_mobile_composer_integration.py b/tests/test_mobile_composer_integration.py index f3e086d..6b87c6e 100644 --- a/tests/test_mobile_composer_integration.py +++ b/tests/test_mobile_composer_integration.py @@ -35,4 +35,4 @@ def test_offline_shell_contains_every_local_dashboard_runtime_asset(): shell_assets = set(re.findall(r"BASE \+ '([^']+)'", worker.split("async function sessionCsrf", 1)[0])) assert local_assets <= shell_assets, f"Offline shell is missing: {sorted(local_assets - shell_assets)}" - assert "stackchain-dashboard-shell-v73" in worker + assert "stackchain-dashboard-shell-v74" in worker diff --git a/tests/test_plan_today.py b/tests/test_plan_today.py index 765b267..fc1249b 100644 --- a/tests/test_plan_today.py +++ b/tests/test_plan_today.py @@ -232,6 +232,6 @@ async def test_plan_today_wires_cancel_back_and_success_through_overlay_history( def test_plan_today_controller_is_available_in_the_offline_shell(): source = SERVICE_WORKER.read_text() - assert "stackchain-dashboard-shell-v73" in source + assert "stackchain-dashboard-shell-v74" in source assert "BASE + 'static/plan-today.js'" in source assert "BASE + 'static/plan-today-preview.js'" in source diff --git a/tests/test_service_worker.py b/tests/test_service_worker.py index f4f6cd5..5bd4171 100644 --- a/tests/test_service_worker.py +++ b/tests/test_service_worker.py @@ -122,7 +122,7 @@ async function dispatchNotificationClick(route) {{ def test_resumable_today_session_ships_in_a_new_offline_shell(): source = WORKER.read_text() - assert "stackchain-dashboard-shell-v73" in source + assert "stackchain-dashboard-shell-v74" in source assert "BASE + 'static/my-work.js'" in source assert "BASE + 'static/dashboard.js'" in source assert "BASE + 'static/dashboard.css'" in source @@ -131,7 +131,7 @@ def test_resumable_today_session_ships_in_a_new_offline_shell(): def test_offline_review_next_ships_today_completion_atomically(): source = WORKER.read_text() - assert "stackchain-dashboard-shell-v73" in source + assert "stackchain-dashboard-shell-v74" in source assert "BASE + 'static/today-completion.js'" in source assert "BASE + 'static/dashboard.js'" in source @@ -139,7 +139,7 @@ def test_offline_review_next_ships_today_completion_atomically(): def test_duplicate_aware_capture_ships_in_a_new_offline_shell(): source = WORKER.read_text() - assert "stackchain-dashboard-shell-v73" in source + assert "stackchain-dashboard-shell-v74" in source assert "BASE + 'static/create-issue-sheet.js'" in source assert "BASE + 'static/dashboard.js'" in source @@ -147,14 +147,14 @@ def test_duplicate_aware_capture_ships_in_a_new_offline_shell(): def test_exact_later_picker_ships_atomically_in_a_new_offline_shell(): source = WORKER.read_text() - assert "stackchain-dashboard-shell-v73" in source + assert "stackchain-dashboard-shell-v74" in source assert "BASE + 'static/later-picker.js'" in source def test_navigation_deadline_ships_in_a_new_shell_cache(): source = WORKER.read_text() - assert "stackchain-dashboard-shell-v73" in source + assert "stackchain-dashboard-shell-v74" in source assert "BASE + 'static/dashboard.css'" in source assert "BASE + 'static/dashboard.js'" in source assert "BASE + 'static/install-app.js'" in source @@ -163,21 +163,21 @@ def test_navigation_deadline_ships_in_a_new_shell_cache(): def test_today_convergence_ships_in_a_new_shell_cache(): source = WORKER.read_text() - assert "stackchain-dashboard-shell-v73" in source + assert "stackchain-dashboard-shell-v74" in source assert "BASE + 'static/today-sync.js'" in source def test_mobile_search_viewport_ships_in_a_new_offline_shell(): source = WORKER.read_text() - assert "stackchain-dashboard-shell-v73" in source + assert "stackchain-dashboard-shell-v74" in source assert "BASE + 'static/mobile-search-viewport.js'" in source def test_update_ownership_flow_ships_atomically_in_a_new_offline_shell(): source = WORKER.read_text() - assert "stackchain-dashboard-shell-v73" in source + assert "stackchain-dashboard-shell-v74" in source assert "BASE + 'static/update-ownership.js'" in source @@ -358,7 +358,7 @@ def test_one_session_bound_csrf_proof_is_reused_for_a_background_drain(): def test_queue_today_ships_atomically_in_a_new_offline_shell(): source = WORKER.read_text() - assert "stackchain-dashboard-shell-v73" in source + assert "stackchain-dashboard-shell-v74" in source assert "BASE + 'static/queue-today.js'" in source diff --git a/tests/test_today_readiness.py b/tests/test_today_readiness.py index a7c6cb6..282f8cd 100644 --- a/tests/test_today_readiness.py +++ b/tests/test_today_readiness.py @@ -18,23 +18,59 @@ def run_node(script): ).stdout -def test_readiness_opens_ready_target_without_showing_a_gate(): +def test_readiness_opens_ready_target_without_inspecting_the_rest_of_the_queue(): script = f""" const createTodayReadiness = require({json.dumps(str(READINESS))}); const calls = []; +const inspections = []; const item = (number, kind='issue') => ({{kind, repository:'stackchain/dashboard', number, title:'Item ' + number}}); const readiness = createTodayReadiness({{ - inspect: async candidate => ({{available:true, dependencies:[]}}), + inspect: async candidate => {{ inspections.push(candidate.number); return {{available:true, dependencies:[]}}; }}, onOpen: (action, candidate) => calls.push(['open', action, candidate.number]), onGate: state => calls.push(['gate', state.status]), }}); -readiness.run('start', [item(1), item(2)]).then(result => - process.stdout.write(JSON.stringify({{result, calls}})) +readiness.run('start', [item(1), item(2), item(3)]).then(result => + process.stdout.write(JSON.stringify({{result, calls, inspections}})) ); """ assert json.loads(run_node(script)) == { "result": "opened", "calls": [["open", "start", 1]], + "inspections": [1], + } + + +def test_readiness_checks_fallbacks_concurrently_but_preserves_queue_order(): + script = f""" +const createTodayReadiness = require({json.dumps(str(READINESS))}); +const items = [1, 2, 3].map(number => ({{kind:'issue', repository:'r', number}})); +const starts = []; +const resolvers = {{}}; +const readiness = createTodayReadiness({{ + inspect: candidate => {{ + starts.push(candidate.number); + if (candidate.number === 1) return Promise.resolve({{available:true, dependencies:[{{state:'open'}}]}}); + return new Promise(resolve => {{ resolvers[candidate.number] = resolve; }}); + }}, + onOpen: () => undefined, + onGate: state => {{ globalThis.gated = state.nextReady.number; }}, +}}); +(async () => {{ + const running = readiness.run('start', items); + await new Promise(resolve => setImmediate(resolve)); + const startedTogether = starts.slice(); + if (resolvers[3]) resolvers[3]({{available:true, dependencies:[]}}); + resolvers[2]({{available:true, dependencies:[]}}); + await new Promise(resolve => setImmediate(resolve)); + if (!startedTogether.includes(3)) resolvers[3]({{available:true, dependencies:[]}}); + const result = await running; + process.stdout.write(JSON.stringify({{result, startedTogether, gated:globalThis.gated}})); +}})(); +""" + assert json.loads(run_node(script)) == { + "result": "gated", + "startedTogether": [1, 2, 3], + "gated": 2, } @@ -135,7 +171,10 @@ async def test_dashboard_exposes_mobile_today_readiness_gate_and_runtime(): def test_readiness_runtime_is_available_in_offline_shell(): - assert "BASE + 'static/today-readiness.js'" in SERVICE_WORKER.read_text() + service_worker = SERVICE_WORKER.read_text() + + assert "const CACHE = 'stackchain-dashboard-shell-v74';" in service_worker + assert "BASE + 'static/today-readiness.js'" in service_worker def test_mobile_readiness_gate_has_touch_safe_wrapping_actions(): diff --git a/tests/test_today_sync.py b/tests/test_today_sync.py index a0fd203..9a5f7bd 100644 --- a/tests/test_today_sync.py +++ b/tests/test_today_sync.py @@ -86,7 +86,7 @@ sync.enqueue('add', 'issue:r:1:'); def test_inflight_today_drain_ships_in_a_new_offline_shell(): source = (Path(__file__).parents[1] / "frontend" / "service-worker.js").read_text() - assert "stackchain-dashboard-shell-v73" in source + assert "stackchain-dashboard-shell-v74" in source assert "BASE + 'static/today-sync.js'" in source -- 2.43.0