perf: fetch only what is shown, pause while hidden, stop drawing what nobody sees - #28
Merged
Merged
Conversation
… nobody sees Every 15 s the monitor re-downloaded AO's debates (2.2 MB for 10 rows, to show a topic and 100 characters), plans (read only as a length), ideas, and Algora's issues (read by nothing) — ~186 MB an hour per open tab, and a hidden tab kept the same schedule. Each read now has its own schedule on a small PollChain: signals and stats every 15 s (they carry LIVE and the sidebar), ideas / project total / Bridge outcomes and trust every 5 min, the three latest debates every 10 min, each with its own timeout and a 1 min retry. Issues and plans are no longer fetched. Polling pauses on visibilitychange and resumes with whatever fell due. Measured: ~186 MB/h -> ~3.4 MB/h. The AO funnel showed the fetch sizes (30 ideas, 20 plans, 20 projects) as totals when stats were missing; it now shows AO's own totals or a dash, and Bridge's `?? 0` fallbacks become dashes too. Rendering: 520 stars of 1-4 px were drawn as ~100-point polygons each and re-triangulated every frame, and the belt zones were drawn under the map's opaque backdrop. Stars are area-matched squares, and belt Graphics are hidden while the map is shown (their update() still runs, so the signal queue keeps draining). Main-thread time per Map frame: ~40 ms -> ~0.55 ms in software GL. The sidebar skips identical innerHTML rewrites, and the CentralMonitor strip reads its cadence from the constants. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Sep 21, 2026
mikim
changed the base branch from
claude/service-correctness-tests
to
main
September 22, 2026 03:23
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #27 (which is stacked on #26) — merge in order. This PR's diff is only its own commit.
Network: ~186 MB an hour per open tab → ~3.4 MB
Every 15 s the monitor re-downloaded AO's debate list and plans, its ideas, and Algora's issues:
/ao-api/debates?limit=10/ao-api/plans?limit=20.length, in a fallback, when/ao-api/statusalready hasplans_created/ao-api/ideas?limit=30/algora-api/issues?limit=30AO's debate list changes about four times a day (a debate starts every 6 h). It was fetched 5,760 times a day, with no ETag or Cache-Control to spare the bytes. A hidden tab kept exactly the same schedule.
Now each read has its own schedule, on a small
PollChain(src/services/poll-chain.ts). It chains runs and never overlaps them, has a real in-flight guard, supports pause and resume, and re-arms even after a throw.LIVE, the queue and the sidebar stand on. They are unchanged, with a 10 s timeout.limit=3, 141 kB gzip).visibilitychange. On show, whatever fell due runs at once and the rest wait out their remaining time. The first load always completes, so a tab opened in the background has something to show.Measured through a byte-for-byte production-like proxy (CDP
encodedDataLength):The biggest remaining item is
/algora-api/signals?limit=30, at ~150–190 kB decoded per 15 s, half of it served from the HTTP cache. It stays on the 15 s tier as a possible follow-up.Totals that were fetch sizes
When stats were missing, the AO funnel fell back to
ideaCache.lengthandplanCache.length. Those are 30 and 20, our page sizes, shown as AO's totals. The funnel now shows AO's own figures:ideas_generated,plans_created, and the project list envelope'stotal(fetched withlimit=1). A missing figure shows—. Bridge's?? 0fallbacks become—as well. A missing value is not a measured zero.CPU: ~40 ms → ~0.55 ms of main-thread time per Map frame
Phaser rebuilds a
Graphicsobject's triangles on every render, turns every arc into ~100 points whatever its radius, and culls nothing by bounds. So:h = size·√π/2). At that size the two look the same, and brightness is kept.update()keeps running, so Algora still drains the signal queue and each Graphics is current on its first visible frame.The numbers are from headless Chrome with SwiftShader, so read the ratio rather than the absolute figure. At 375×812 the main thread was saturated before (99.8% busy). Screenshots of the map and every belt tab look the same as before at 1440×900 and 375×812.
Also: the sidebar skips
innerHTMLrewrites when the markup is unchanged, which stops rebuilding the Service I/O panel every 500 ms. The CentralMonitor strip reads its cadence from the constants (Polling: 15s / 5–10m).What is verified, and what is not
check-health-jsonPollChain(chaining, in-flight guard, pause and resume timing, never two chains), DataBridge cadences and timeouts, a resume during init, and funnel/gauge totals. A test pins the constants to the values the README states.ideas_generatedandfinal_planwould cut the remaining ~141 kB per 10 min🤖 Generated with Claude Code