Repository navigation
Optimize Constellation and Journal with incremental history - #21
Open
aakashH242 wants to merge 9 commits into
Open
aakashH242 wants to merge 9 commits into
aakashH242 wants to merge 9 commits into
Conversation
Member
Author
|
@codex review |
Member
Author
|
@codex review |
Member
Author
|
@codex review |
This was referenced Nov 12, 2026
20 tasks
This branch has not been deployed
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.
Large Journal histories used to mount every event and group header, and Constellation used to repeat layout and animation work across the full scene. The Journal now mounts a measured window around the viewport. Constellation keeps its existing scene nodes and limits repeated work to the state and geometry that changed.
Journal
The complete event, group and date order stays in a logical model. A cumulative height index finds rows around the viewport, with up to 400 px of overscan on each side. A shared ResizeObserver measures mounted rows and preserves the visible event's offset when heights change. The same anchor is used when history is replaced or extended.
Group headers remain native sticky disclosures. Collapsing a group retains its events in the model, and reveal can expand a collapsed group and scroll to an unmounted row. A focused row stays mounted across scroll and history changes, and Tab follows logical row order. The app cancels queued work before replacing the Journal or leaving the timeline. The virtualizer preserves event order and grouping.
On the 390 px Chromium fixture with 10,000 events in 5,000 dynamic groups, peak mounted event rows fell from 10,000 to 11 and headers from 5,000 to 6. Initial mount plus synchronous layout went from 1,070.60 to 31.60 ms median. On the 50,000-event single-group fixture, peak mounted event rows fell from 50,000 to 16, and median initial mount plus layout went from 3,500.50 to 95.90 ms. Scripted scrolling adds a small amount of mounting work per window. The 50,000-event jump step measured 1.70 ms median in Chromium. The virtualizer retains the loaded logical history in memory.
Constellation
The viewport change matched 483 Chromium baseline checkpoints. At 10,000 entries, four manual-scroll frames went from 40,000 label visits to 26 and from 239,616 spark/trail coordinate writes to 180. The existing Constellation nodes stay mounted.
Verification
Incremental history and exact totals
Issue #25 follows the timeline from SQLite to both layouts. The previous client awaited every page before rendering. XFlog now accepts one page of up to 50 records and renders it with the exact totals. Journal near-end scrolling, Constellation older navigation and the Load older activity control request one continuation at a time. Failed requests retain the accepted cursor and loaded rows for explicit retry. The scrubber loads on commit.
A shared request owner cancels stale requests on scope change or unmount, coalesces near-end callbacks, and lets older navigation preempt a live read. Live catch-up uses per-source insertion bounds, accepts up to three pages per poll, and exposes pending work while keeping the accepted older cursor. A selected event can refresh from local data without walking older pages. Profile resolution remains opt-in on the first ungrouped page. Aggregates and continuation pages use local data.
The first
/api/timelinepage returnsevents,next, andaggregate. The aggregate contains full-scope event and distinct-actor totals, counts by kind, an active-lens bucket breakdown, an opaque scope, the revision, the oldest matching receipt and the profile revision. Page membership and aggregate share a read-only SQLite WAL snapshot. Keyset continuations bind the account, subject, filter, receipt cutoff, lens, enabled settings and both source watermarks. Equal receipts retain source and sequence priority. Mutable profile and post fields reflect each request's local snapshot. The offline demo supports the same paging model and holds its initial synthetic clock across continuations. The Activity HUD endpoint keeps its existing contract.Activity and kind counts use SQL grouping. Account size, account age and verification stream the recorded attributes through the registered classifiers. Profile location uses the registered normalization and latest matching bucket descriptor. Previous encounters uses one chronological SQLite window over the saved account log, including history outside the current range and disabled event kinds. Both layouts distinguish loaded records from saved totals. Journal can show an aggregate-only bucket as a summary and promote it to a disclosure as pages arrive. Constellation shows a summary of groups with no loaded records and positions stars only for fetched events.
The server changes are in
app.py, the audience-group registry, andhistory/{timeline,timeline_queries,timeline_cursor,timeline_aggregate,demo}.py.history/store.pyandinteractions/store.pyadd four indexes for account receipt/sequence, actor receipt/sequence and interaction account/sequence seeks. No table migration or aggregate cache. The browser changes coverassets/{app,live-history,audience-groups,journal,journal-model,constellation,constellation-layout,constellation-colors,format}.js, the shell and timeline styles. The README documents paging. Tests cover the mixed SQL oracle and browser/Node histories and layouts.Measurements
Paired Chromium 156 runs used the actual shell and a mocked local API, 50 rows per page, one warmup and three samples on Linux with an i7-12700F. First useful DOM includes requests, JSON parsing and rendering and excludes SQLite. Heap is post-GC V8 used heap above baseline. Bytes are compact uncompressed history JSON bodies.
At 1,000 and 10,000 records the paired fixtures also dropped from 20 and 200 requests to one. All candidate fixtures retained 50 rows at first render. Sampled peak V8 heap at 50,000 went from 43.08 to 1.09 MB for Journal and 73.70 to 1.52 MB for Constellation. Browser-native memory and FPS were outside the measurement.
Separate Python 3.12.13 and SQLite 3.53.1 runs used one warmup and nine measured samples for the candidate. At 1k/10k/50k, mixed Activity first-page medians including the aggregate were 4.55/11.63/43.14 ms, older pages 3.32/3.26/2.60 ms, and 20-record live deltas 2.95/10.42/42.14 ms. The initial bodies were 33,986/34,104/34,221 bytes including 759/773/786 bytes of metadata. The old local eager drain at 1k/10k took 82.94 ms/11.99 s median and issued 60/600 data reads, versus four reads for the new first page. The old 50k run was censored after three minutes. Query plans verified bounded per-source candidates before enrichment and indexed delta sequence ranges. The 10k prior-encounter aggregate initially exposed a 1.86 s SQLite nested-scan plan. Removing the join and applying the scope after the chronology window brought the first page to 58.89 ms median.
A real offline SQLite walkthrough paged 50 → 100 → 150 loaded rows in the two layouts while keeping the 240-event and 47-person totals. The 50-row ungrouped Journal append probe at 50k retained events measured 67.65 → 0.65 ms median for synchronous controller work and retained mounted rows. Grouped Journal rebuilds the logical index while preserving compatible measurements and controls. Constellation rebuilds when membership changes because star positions, selected bindings and connection endpoints share a geometry generation. It restores focus, selection, zoom and anchor. The rebuild measured roughly 0.93 s at 10k retained stars, so very large manually loaded scenes remain costly.
Issue #25 verification
uv run --no-sync pytest -q -rapassed 653 tests, including 23 Chromium lifecycle cases. The held-response tests cover one-page initialization, retry, repeated cursors, layout switches, stale response delivery, focus/anchor retention, scrubber commit and a bounded live burst concurrent with older navigation.node tests/live_history_check.mjs src/xflog/assetsandnode tests/constellation_selection_check.mjs src/xflog/assetspassed.node tests/journal_check.mjs src/xflog/assets "$catalog"andnode tests/constellation_check.mjs src/xflog/assets "$catalog"passed with the all-enabled audience catalog fromxflog.audience_groups.catalog.uv run --no-sync ruff check src tests .github/scripts,uv run --no-sync ruff format --check src tests .github/scripts,git diff --check,bash -n install.sh,uv lock --checkanduv buildpassed. In a Gradio-free environment,uv run --no-sync pytest -q tests/test_runtime.py tests/test_identity.py tests/test_cli.pypassed 80 tests.13e6a51.Exact derived counts still scan local data and location metadata scales with the number of occupied buckets. The 50k synthetic location and previous-encounter first pages took 420 and 271 ms median. Loaded history grows as the user pages. In Previous encounters, a backdated arrival can update existing group assignments, including when the arrival is outside the current filters. The live keyset includes update-only corrections. They replace already-loaded records and share the same 50-row cap. Older pages retain their original membership and use the accepted aggregate revision for encounter classification. Ordinary arrivals bypass correction discovery after indexed receipt and sequence checks. In a 50,000-event local SQLite fixture, a 175-record chronological live burst used four pages with a 277.18 ms median first page including the aggregate and 8.39 ms total for the remaining pages. A 200-record backfill also corrected 400 older rows, took 12 pages, and measured 384.14 ms median for the full local batch. Both used seven samples after warmup. These backend measurements exclude HTTP and browser work. A large backfill can require several catch-up batches while the status shows that updates are pending.
Closes #20
Closes #22
Closes #23
Closes #24
Closes #25