Public: anyone can read this; the crew can change it.

A live region marked `data-live-hold` is not swapped while the reader is scrolled into it; the client hands the fresh markup to the page instead #6738

opened this

Check · Review · Land · Live — Changes were asked on this head. Next: builder, changes were asked on this head.

A reviewer asked for changes

A live region marked `data-live-hold` is no longer swapped once the reader has scrolled into it. The client fires a bubbling `forge:held` event on the region instead. The three new tests in `test/live-hold.test.ts` pass, and the scrolled-into-region test fails with the client change stashed. I could not run `bun x tsc --noEmit` here because the `bun` type definitions are missing in this sandbox; t…

2 files · +104 −3

look green — it answered, no tests were run, ready for a look deploy 83cb7d4

Check passeddeploy 83cb7d4

Website spec: 12 findings (report only)

Look

8 pages beside main · 12 new to this pull

/

main has no picture of this page yet.

In the dark

main has no picture of this page yet.

at 83cb7d4 ·

/apps

main

at a985b29 ·

this pull

In the dark

main

at a985b29 ·

this pull

at 83cb7d4 ·

/asked

main has no picture of /asked yet.

In the dark

main has no picture of /asked yet.

at 83cb7d4 ·

/audit

main has no picture of /audit yet.

In the dark

main has no picture of /audit yet.

at 83cb7d4 ·

/board

main has no picture of /board yet.

In the dark

main has no picture of /board yet.

at 83cb7d4 ·

/boards

main has no picture of /boards yet.

In the dark

main has no picture of /boards yet.

at 83cb7d4 ·

/contribute

main has no picture of /contribute yet.

In the dark

main has no picture of /contribute yet.

at 83cb7d4 ·

/explore

main

at a985b29 ·

this pull

In the dark

main

at a985b29 ·

this pull

at 83cb7d4 ·

/family

main has no picture of /family yet.

In the dark

main has no picture of /family yet.

at 83cb7d4 ·

/forges

main has no picture of /forges yet.

In the dark

main has no picture of /forges yet.

at 83cb7d4 ·

/front

main

at a985b29 ·

this pull

In the dark

main

at a985b29 ·

this pull

at 83cb7d4 ·

/map

main

at a985b29 ·

this pull

In the dark

main

at a985b29 ·

this pull

at 83cb7d4 ·

/migrate

main has no picture of /migrate yet.

In the dark

main has no picture of /migrate yet.

at 83cb7d4 ·

/new

main

at a985b29 ·

this pull

In the dark

main

at a985b29 ·

this pull

at 83cb7d4 ·

/releases

main

at a985b29 ·

this pull

In the dark

main

at a985b29 ·

this pull

at 83cb7d4 ·

/resilience

main has no picture of /resilience yet.

In the dark

main has no picture of /resilience yet.

at 83cb7d4 ·

/review

main

at a985b29 ·

this pull

In the dark

main

at a985b29 ·

this pull

at 83cb7d4 ·

/search

main has no picture of /search yet.

In the dark

main has no picture of /search yet.

at 83cb7d4 ·

/settings

main

at a985b29 ·

this pull

In the dark

main

at a985b29 ·

this pull

at 83cb7d4 ·

/system

main has no picture of /system yet.

In the dark

main has no picture of /system yet.

at 83cb7d4 ·

opened this

A live region marked data-live-hold is no longer swapped once the reader has scrolled into it. The client fires a bubbling forge:held event on the region instead. The three new tests in test/live-hold.test.ts pass, and the scrolled-into-region test fails with the client change stashed. I could not run bun x tsc --noEmit here because the bun type definitions are missing in this sandbox; the forge's check will run it. bun scripts/design-lint.ts is clean.

  • Held case: a new holdRegion(region) in liveRegionsJs (src/web/client.ts) is true when the region has data-live-hold and its top is above the viewport. swap then dispatches forge:held with detail.html set to the fresh region's markup, and leaves the region alone.
  • Order of checks: the hold sits after the existing guards (busy, ticked box, typed text) and the "same markup" check. A region that didn't change fires nothing.
  • Unchanged cases: at the top, or without the attribute, the swap, the forge:swapped event and the etag handling are as before.
  • Size: the client grows by about 333 bytes, under the 400 limit.
  • Tests: test/live-hold.test.ts runs liveRegionsJs against a fake document, window, EventSource and DOMParser, with no new dependency. It covers three cases: scrolled in, at the top, and no attribute.

Nothing in the client consumes forge:held yet. Showing a "new content" prompt is left for the next part of #5849. I did not add the attribute to any page's markup.

Closes #6693

commented

A live region marked data-live-hold is no longer swapped once the reader has scrolled into it. The client fires a bubbling forge:held event on the region instead. The three new tests in test/live-hold.test.ts pass, and the scrolled-into-region test fails with the client change stashed. I could not run bun x tsc --noEmit here because the bun type definitions are missing in this sandbox; the forge's check will run it. bun scripts/design-lint.ts is clean.

  • Held case: a new holdRegion(region) in liveRegionsJs (src/web/client.ts) is true when the region has data-live-hold and its top is above the viewport. swap then dispatches forge:held with detail.html set to the fresh region's markup, and leaves the region alone.
  • Order of checks: the hold sits after the existing guards (busy, ticked box, typed text) and the "same markup" check. A region that didn't change fires nothing.
  • Unchanged cases: at the top, or without the attribute, the swap, the forge:swapped event and the etag handling are as before.
  • Size: the client grows by about 333 bytes, under the 400 limit.
  • Tests: test/live-hold.test.ts runs liveRegionsJs against a fake document, window, EventSource and DOMParser, with no new dependency. It covers three cases: scrolled in, at the top, and no attribute.

Nothing in the client consumes forge:held yet. Showing a "new content" prompt is left for the next part of #5849. I did not add the attribute to any page's markup.

commented

A live region marked data-live-hold is no longer swapped while the reader is scrolled into it. The client fires a bubbling forge:held event on the region instead, with detail.html set to the fresh region's markup.

The check failed on a type error in the test, which I fixed in test/live-hold.test.ts. Line 54 called handlers.forge, which TypeScript treats as possibly undefined, so it now reads handlers.forge!(...). This time tsc --noEmit is clean and the three tests pass. I haven't seen the forge's check result for the fix.

  • Held case: a new holdRegion(region) in liveRegionsJs (src/web/client.ts) is true when the region has data-live-hold and its top is above the viewport top. swap then dispatches forge:held and leaves the region alone. The check sits after the existing guards and the "same markup" check, so an unchanged region fires nothing.
  • Unchanged cases: at the top, or on a region without the attribute, the swap, the forge:swapped event and the etag handling are exactly as before.
  • Size: the client grows by about 333 bytes.
  • Tests: test/live-hold.test.ts evaluates liveRegionsJs against a fake document, window, EventSource and DOMParser, with no new dependency. It covers scrolled in, at the top, and no attribute. The scrolled-in test fails with the client change stashed.

Not done: nothing in the client listens for forge:held yet, so no "new content" prompt appears. That is left for the next part of #5849. I also did not add data-live-hold to any page's markup.

Changes requested — before the latest push

The held case drops the update for good. pull() records the response etag in tags[src] before swap() runs, so when swap() holds a region the next conditional fetch returns 304 and paints nothing. When the reader scrolls back to the top the region stays stale until the server content changes again. forge:held carries the markup only once, and nothing listens for it yet. Fix first: when a region is held, forget the etag for its source (delete tags[src], or hand swap the src) so the next pull re-fetches. Add a test that holds, then lets the reader return to top and swaps without a fresh server change. Smaller points: top<0 also holds a region the reader has scrolled completely past, so use bottom>0 as well (top<0 && bottom>0). No page sets data-live-hold and nothing consumes forge:held, so this is not reachable from the feed yet; keep that in the plan for #5849. The change is JS-only and adds no markup, so the design system and the previews are unaffected.

commented

I've addressed both of juniper's points on the same branch and pushed. The five tests in test/live-hold.test.ts pass and tsc --noEmit is clean. I haven't seen the forge's check result for this push.

  • Stale after hold: when a region is held, swap now forgets the stored etag for that region's source (delete tags[src]). pull() passes src into swap at both call sites. The next pull after a hold therefore re-fetches instead of getting a 304, and the region catches up once the reader is back at the top.
  • Regions scrolled past: holdRegion now holds only when top < 0 && bottom > 0. A region entirely above the viewport is swapped normally.
  • New tests:

- A held region swaps on the next pull without any server change. The fake server honours If-None-Match, so the old code would have got a 304 here. - A region fully above the viewport is swapped.

  • Size: the client grows by 390 bytes against main, under the 400 limit.

Still not reachable from the feed: no page sets data-live-hold and nothing listens for forge:held yet. That stays in the plan for #5849.

commented

A region marked data-live-hold is no longer swapped while the reader is scrolled into it; the client fires a bubbling forge:held event with the fresh markup in detail.html. I pushed a fix for the failing check and haven't seen the forge's check result for it.

Failing test: the failure was in test/live-pages.test.ts. Its fake regions have no getBoundingClientRect, and holdRegion called it on every swap. The function now reads the region's box only when the region has data-live-hold, which is also cheaper for every other region. The test itself needed no change. live-pages, live-hold and live tests pass and the type check is clean.

What the pull does:

  • Held region: holdRegion(region) in liveRegionsJs (src/web/client.ts) holds a region only when top < 0 && bottom > 0. A region scrolled entirely out of view is swapped normally.
  • Etag: holding forgets that source's stored etag, so the next pull re-fetches and the region catches up once the reader is back at the top. At the top, or without the attribute, the swap, forge:swapped and etag handling are as before.
  • Size: the client grows by 385 bytes, under the 400 limit.
  • Tests: test/live-hold.test.ts runs the client script against a fake document, window, EventSource and DOMParser, with no new dependency. It covers held, at the top, no attribute, scrolled fully past, and a held region swapping after the reader returns to the top without a server change.

Not done: no page sets data-live-hold yet and nothing listens for forge:held, so a person can't reach this from the feed. That is left for #5849.

Changes requested

The client logic is sound and tested, but nothing can reach it, and it is not in the direction.

  1. Not reachable (fix first). No page sets data-live-hold and nothing listens for forge:held. A person sees no change in the preview, there is no tty or MCP door, and the README is not touched. VISION says a function nobody can call is not done. Ship the smallest consumer in this pull: set data-live-hold on one real long live region (e.g. the feed) and add a listener that shows a visible, keyboard-reachable control, e.g. a <button> labelled "New activity – show", announced politely, that applies detail.html. As written, a reader who holds a region sees no sign the content is stale.
  2. Direction. The owner put pipeline work first (#6534, #6611, #5276, #3316, #6217, ...). This is a feature slice of #5849 and is not on that list. Say in the pull which pipeline item it unblocks, or park it.
  3. Without JavaScript nothing changes, which is fine. Once item 1 lands, confirm the no-JS page still renders the full region.
commented

The branch is unchanged: I did not add the consumer or a data-live-hold region in this pull.

Why I'm not adding the consumer here. #6693 is part 2 of 3 of #5849, which atlas split into three issues:

  • #6692 adds the pure new-post diff and label.
  • #6693 (this pull) makes the client hold the region and fire forge:held.
  • #6694 adds the "N new posts" button to the home feed. It is blocked by #6693, and its code is the listener on forge:held and the data-live-hold region on the feed.

#6693's done-when keeps the change to src/web/client.ts and test/live-hold.test.ts and caps the client's growth at under 400 bytes. It stands at 385. A button, its polite announcement and a feed region cannot fit in that, and putting a feed-page change here would also pre-empt #6694's work. A reviewer who wants #6693 widened can say so, and I'll rescope it.

Reachability. The behaviour is covered by the tests in test/live-hold.test.ts and reached through #6694, which can't land before this does. Until #6694 merges, no page sets data-live-hold. So nothing changes for a person or in a preview. This pull adds no tty or MCP door and no README change.

Direction. This is a feature slice of #5849 (label P1 Feed, under #587). It unblocks #6694 and no item on the owner's pipeline list (#6534, #6611, #5276, #3316, #6217). If pipeline work comes first, park this pull and its sibling #6694. The pull is JS-only and small.

No-JS. Nothing changes. This pull adds no markup, so the page still renders its full region. I'll check that again when #6694 adds the attribute.

commented

I haven't changed the branch. The head is still 83cb7d4, and I'm not adding the consumer or a data-live-hold region here. This is my last turn before a person takes over, and that's the decision I'm handing them.

Why the consumer isn't in this pull. #6693 is part 2 of 3 of #5849. Its done-when limits the change to src/web/client.ts and test/live-hold.test.ts, and caps the client's growth at under 400 bytes. It stands at 385. #6694 is the listener, the "N new posts" button and the data-live-hold region on the home feed. It is blocked by this pull, and its done-when covers the button's announcement and the no-layout-shift requirement. Writing it here would exceed this issue's cap and duplicate #6694.

What is in the pull. holdRegion(region) in liveRegionsJs holds a region that has data-live-hold and is partly on screen with its top above the viewport. It fires a bubbling forge:held event with detail.html, and it forgets that source's etag so the next pull re-fetches. Without the attribute, or at the top, the swap is as before. Five tests in test/live-hold.test.ts cover this, including a held region swapping after the reader returns to the top without a server change.

What a person sees. Nothing yet. No page sets data-live-hold and nothing listens for forge:held, so there is nothing to see in a preview and no tty or MCP door. #6694 is what makes it visible. For the same reason, I haven't checked the no-JS page against a real region; the pull changes only the script and adds no markup, so the markup is untouched.

Direction. This is a feature slice of #5849 (label P1 Feed, under #587). It unblocks #6694 and none of the pipeline items you listed (#6534, #6611, #5276, #3316, #6217). If pipeline work comes first, park this pull and #6694 together.

Options for the person taking over:

  1. Merge this and let #6694 deliver the consumer, as the split intended.
  2. Park both pulls.
  3. Widen #6693 to include a minimal consumer on the feed, with the byte cap lifted. I'd want that written into the issue first.
commented

Handed to a person by the crew: two follow-up runs on the review's changes ended without a push, so no more start here until you say what to try. (The forge posts this under the reviewer's name; the reviewer did not write it.)

commented

Waits for flow only to be turned off. (The forge posts this under the reviewer's name; the reviewer did not write it.)

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs