Read by being seen without reloading the thread; redraw only what changed #254

Merged
littlefox merged 5 commits from issue-228-quiet-marks into main 2026-10-22 00:53:34 +00:00
Owner

Closes #228
Closes #226
Closes #256

  • The thread loader follows its own epoch signal (text actions), not tick: a post read by being seen no longer reloads and redraws the thread. Logins and logouts bump presence::CHANGES, not changes.
  • Cards seen within 300 ms are marked together: Kom::mark_read_many, one mark-as-read per channel.
  • SEEN_JS is event-driven (scroll, page changes, resize, tab back; once a frame at most, a timer only while a card waits out its second) instead of reading every card's layout every 250 ms.
  • Cards hold thread_view::Shared (an Rc<TextView> compared by pointer); previews go in 8 at a time or every 150 ms; the mention/search indexer no longer deep-copies every card on each preview; the thread and channel panes don't follow the 30 s clock.

Measured with tools/perf.sh (#225; this branch has #252 merged in for that), reading 120 cards by scrolling slowly past them:

baseline after
server calls 287 99 (−66 %)
layouts 119 35 (−71 %)
style recalcs 126 61 (−52 %)
main-thread busy 1.2 s 0.37 s (−69 %)

Reading 300 posts along the chain: style recalcs 2 358 → 1 578 (−33 %). Idle main-thread time 0.03 → 0.01 s per 20 s. Everything else unchanged within noise.

Also #256: soak.spec read the previous post's status line; it now waits for a new number (soak passes locally, 32 posts, 16 drops).

Verified: full e2e suite on desktop, Android and iPhone, 327 passed; lint three ways.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XJW2ocwLunyaLiUwCBHEP8

Closes #228 Closes #226 Closes #256 - The thread loader follows its own `epoch` signal (text actions), not `tick`: a post read by being seen no longer reloads and redraws the thread. Logins and logouts bump `presence::CHANGES`, not `changes`. - Cards seen within 300 ms are marked together: `Kom::mark_read_many`, one `mark-as-read` per channel. - `SEEN_JS` is event-driven (scroll, page changes, resize, tab back; once a frame at most, a timer only while a card waits out its second) instead of reading every card's layout every 250 ms. - Cards hold `thread_view::Shared` (an `Rc<TextView>` compared by pointer); previews go in 8 at a time or every 150 ms; the mention/search indexer no longer deep-copies every card on each preview; the thread and channel panes don't follow the 30 s clock. Measured with `tools/perf.sh` (#225; this branch has #252 merged in for that), reading 120 cards by scrolling slowly past them: | | baseline | after | |---|---|---| | server calls | 287 | 99 (−66 %) | | layouts | 119 | 35 (−71 %) | | style recalcs | 126 | 61 (−52 %) | | main-thread busy | 1.2 s | 0.37 s (−69 %) | Reading 300 posts along the chain: style recalcs 2 358 → 1 578 (−33 %). Idle main-thread time 0.03 → 0.01 s per 20 s. Everything else unchanged within noise. Also #256: soak.spec read the previous post's status line; it now waits for a new number (soak passes locally, 32 posts, 16 drops). Verified: full e2e suite on desktop, Android and iPhone, 327 passed; lint three ways. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01XJW2ocwLunyaLiUwCBHEP8
Measure first: a big meeting, a perf spec and a desktop memory run
Some checks failed
ci / e2e (push) Has started running
packaging / fedora (pull_request) Has started running
ci / check (push) Successful in 10m3s
packaging / arch (pull_request) Successful in 14m58s
ci / desktop (push) Successful in 19m39s
packaging / nix (pull_request) Successful in 22m28s
packaging / debian (pull_request) Successful in 26m4s
packaging / release (pull_request) Has been cancelled
c5abe1fe63
0.6 is about performance (D-057), and every fix should come with a
before/after number. tools/perf.sh seeds a big meeting (NEOKOM_SEED_PERF:
~2 800 texts, a 1 500-long chain, 300 more channels, 2 500 letters) on a
lyskomd kept in memory, puts 30 ms each way between relay and server,
and runs e2e/perf/perf.spec.ts in Chromium: memory (JS heap and the
app's wasm), DOM nodes, main-thread time, long tasks, frames while
scrolling, step times and server calls. tools/desktop-perf.sh measures
the desktop app's RSS and idle CPU. tools/perf-table.py compares runs.

The app exposes its wasm memory and the session's call count to the page
for this; Chromium shows no WebSocket frames sent from wasm.

Refs #225

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XJW2ocwLunyaLiUwCBHEP8
Every card read by being seen bumped the signal the thread loader follows,
so each one reloaded the thread and redrew every card, and so did every
login or logout on the server. Now:
- the thread loader follows its own signal, bumped by text actions, not
  by marks; logins and logouts bump presence::CHANGES instead of changes;
- cards seen within 300 ms go to the server together, one mark-as-read
  per channel (Kom::mark_read_many), and the counts change once;
- the seen check runs on scroll and page changes, at most once a frame,
  instead of reading every card's layout four times a second;
- cards hold their post as a Shared view compared by pointer, previews go
  in a few at a time, the mention/search indexer no longer deep-copies
  every card, and the panes don't redraw for the 30 s clock.

Closes #228
Closes #226

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XJW2ocwLunyaLiUwCBHEP8
Perf: a scenario for reading cards by scrolling past them
All checks were successful
ci / check (push) Successful in 11m50s
packaging / arch (pull_request) Successful in 16m51s
ci / desktop (push) Successful in 20m13s
packaging / debian (pull_request) Successful in 25m40s
ci / e2e (push) Successful in 34m34s
packaging / fedora (pull_request) Successful in 39m40s
packaging / nix (pull_request) Successful in 39m13s
packaging / release (pull_request) Has been skipped
91bc19544c
Reading with space marks few cards by being seen, the case #228 is
about. This scrolls slowly through a post's 120 unread replies.

Refs #225

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XJW2ocwLunyaLiUwCBHEP8
Merge remote-tracking branch 'origin/issue-225-measure' into issue-228-quiet-marks
Some checks failed
ci / check (push) Successful in 15m9s
ci / desktop (push) Successful in 17m11s
packaging / arch (pull_request) Successful in 18m2s
ci / e2e (push) Failing after 36m8s
packaging / debian (pull_request) Successful in 38m20s
packaging / nix (pull_request) Failing after 39m5s
packaging / fedora (pull_request) Successful in 42m42s
packaging / release (pull_request) Has been skipped
36977eae75
The previous post's status line matched until the new one replaced it,
so the check read the old number and failed.

Refs #256

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XJW2ocwLunyaLiUwCBHEP8
Merge remote-tracking branch 'origin/main' into issue-228-quiet-marks
All checks were successful
ci / check (push) Successful in 12m49s
packaging / arch (pull_request) Successful in 16m31s
ci / desktop (push) Successful in 24m58s
packaging / debian (pull_request) Successful in 34m48s
ci / e2e (push) Successful in 37m42s
packaging / fedora (pull_request) Successful in 38m58s
packaging / nix (pull_request) Successful in 43m6s
packaging / release (pull_request) Has been skipped
3a124bc112
littlefox referenced this pull request from a commit 2026-10-22 14:11:05 +00:00
Sign in to join this conversation.
No description provided.