<feed xmlns='http://www.w3.org/2005/Atom'>
<title>coinosv3.git/tools/feed-live-test.js, branch fdroid-v1.6</title>
<subtitle>coinos v3 — bitcoin, Ark, Lightning and nostr wallet (web + Android)</subtitle>
<id>https://git.coinos.io/coinosv3.git/atom?h=fdroid-v1.6</id>
<link rel='self' href='https://git.coinos.io/coinosv3.git/atom?h=fdroid-v1.6'/>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/'/>
<updated>2026-09-14T20:46:58Z</updated>
<entry>
<title>A new post opens up instead of appearing.</title>
<updated>2026-09-14T20:46:58Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-09-14T20:46:58Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=0c0ba1b0129a140dc540f0fb8588b3ffdd44350c'/>
<id>urn:sha1:0c0ba1b0129a140dc540f0fb8588b3ffdd44350c</id>
<content type='text'>
A post let in at the top of an open feed was there on the next paint —
one frame nothing, the next a whole row, the page shoved down by that
much. Now it opens over a third of a second: height from nothing to its
own, fading in as it goes, and a repaint mid-way resumes where it was.
The same happens to the posts the pill lets in.

That needed the morph to know which row is which. Children were matched
by position, so a new first row was patched onto the old first row's
node and every row below onto its neighbour's — the node the new post
was built as never reached the page. A list whose every child carries a
data-key is now reconciled by key: new rows are inserted as themselves,
the rest keep their nodes and move. Feed rows and their hairlines carry
the post id. Partially keyed lists keep the positional rule.

feed-live-test catches the arriving row mid-animation: shorter than it
will be, one animation running, and settled clean afterwards.

Co-Authored-By: Claude Fable 5.1 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01QYJfZ4A1TDCEY4Foq3CApR
</content>
</entry>
<entry>
<title>A post arrives whole.</title>
<updated>2026-09-14T19:59:57Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-09-14T19:59:57Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=d730ea49feb389b43362b1044964f5a9e03ae4ff'/>
<id>urn:sha1:d730ea49feb389b43362b1044964f5a9e03ae4ff</id>
<content type='text'>
A feed row painted the moment its event landed and then finished itself
over the next second or two: a punk turning into a photograph, a blank
gap becoming the picture. Now a post waits at the door until its author's
profile has landed and their face and the images in its body are fetched
and decoded — bounded by two seconds, so a slow host holds a post briefly
rather than the feed forever. This covers the first load, live arrivals
(which are counted behind the pill only once whole), paging older posts,
and profile pages. The cached page at boot still paints instantly and
warms in the background.

feed-live-test serves a deliberately slow picture and checks, from the
first instant the row exists, that its image is already decoded.

Co-Authored-By: Claude Fable 5.1 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01QYJfZ4A1TDCEY4Foq3CApR
</content>
</entry>
<entry>
<title>The feed keeps up, and stops moving the page while you read.</title>
<updated>2026-09-13T21:55:18Z</updated>
<author>
<name>Adam Soltys</name>
<email>adam@coinos.io</email>
</author>
<published>2026-09-13T21:55:18Z</published>
<link rel='alternate' type='text/html' href='https://git.coinos.io/coinosv3.git/commit/?id=b11ae2e1811bd5dc6965d127414d8f4f03f248cd'/>
<id>urn:sha1:b11ae2e1811bd5dc6965d127414d8f4f03f248cd</id>
<content type='text'>
A phone freezes a backgrounded tab: timers stop and the relay sockets are
cut, so the feed came back holding whatever it had when you left and only
caught up if you pulled it down by hand. Features now hear about the
return — app.js calls f.resumed(awayMs) on focus — and the feed answers
it by forcing a pass past the thirty-second throttle and rebuilding its
subscriptions, which were talking to sockets that no longer exist. A
blink between apps (under five seconds) is left alone.

That catch-up raises the second problem rather than solving it: dropping
eight posts in at the top moves the words under the thumb of whoever was
reading. So posts that arrive on their own — live, or as a catch-up —
wait when you're scrolled away from the top. A floating pill says how
many, and the tap that lets them in also takes you up to them. Scrolling
back to the top by yourself lets them in too, since up there they cost
nothing. Anything you actually asked for still goes straight in.

Also, on profiles that still show an npub: the batch now falls back to
the relays whose whole job is indexing kind 0 (purplepag.es and friends),
which we never read notes from and so never asked. profile-batch-test's
"handful of asks" bound was a fraction of the row count, which that
fallback broke; the property it means to assert is that the number does
NOT grow with the rows, so it is a constant now.

tools/feed-live-test.js drives a real signed event down a real open
subscription — an unsigned fake is dropped by the signature gate and
would prove nothing — and checks the page does not move, the pill says
"1 new post", tapping it scrolls to the top, and coming back from hidden
re-asks the relays on its own.

Co-Authored-By: Claude Opus 5 (1M context) &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
</content>
</entry>
</feed>
