Skip to content

fix(collection): filter with page visits, not a results frame - #9

Merged
plainprogrammer merged 4 commits into
mainfrom
004-filter-without-frames
Oct 2, 2026
Merged

plainprogrammer merged 4 commits into
mainfrom
004-filter-without-frames

Conversation

@plainprogrammer

@plainprogrammer plainprogrammer commented Oct 2, 2026 •

Copy link
Copy Markdown
Owner

Summary

Fixes the Back-button flake that failed PR #8's CI (run 37051089826): after filtering, Back to /collection showed "3 of 5 items" instead of "5 items".

Root cause. Turbo 8.0.23's frame advance (turbo-frame#results + data-turbo-action="advance") does this:

  1. Pushes the URL.
  2. Swaps the frame.
  3. Waits two repaints (FrameRenderer#render).
  4. Only then calls session.visit, which sets html[aria-busy] and runs navigator.stop().

Nothing is marked busy during step 3, so wait_for_turbo_idle passes. If Back lands in that gap, the late visit cancels the Back visit and the filtered page stays. The no-cache meta from #7 (fc8cff1) closed a different race (the snapshot cache), not this one.

Fix. The collection and search filter forms and their pagination are now plain Turbo Drive GET visits. Both pages keep turbo-cache-control: no-cache, so Back and Forward refetch them.

Changes

  • Removed the results turbo-frames and the frame-only _top targets. The frame: local on the pagination partial is gone.
  • Added two regression specs in spec/system/back_navigation_spec.rb. They slow repaints and delay the unfiltered fetch, which reproduces the race deterministically. Both fail on main.
  • Removed the url-sync Stimulus controller, which is dead now that these pages are never restored from a snapshot. The Back/Forward field specs pass without it.
  • Simplified wait_for_turbo_idle: the frame check and the frames: false workaround are gone.
  • Updated the app's pattern docs: SearchResults (records the deviation), Pager, ViewSwitchForm, TileAdd.
  • Updated the memory notes on the Turbo quirks and the PR feat: design system, accounts, adding cards and the collection grid (004) #5 follow-ups.

Design-system deviation

The design system's README says "the results sit in a Turbo Frame the form targets". This PR deliberately departs from that (maintainer ruling, 2026-10-02). The exported README.md, components/FilterBar.md and components/CollectionPage.md still describe the frame. They are left as exported, so the change needs to go into the published design system before the next export.

Behaviour notes

  • A new search or page now scrolls to the top instead of updating the results in place. Spec 004 AC-6.1 and AC-11.4 still hold: the URL carries the state, Back works, and there is no full page load (window state survives, as the __marker specs check).
  • Layout was not compared visually against the previews; the phone-width and narrow-page specs pass.

Test plan

  • bin/ci passes locally (484 examples, 0 failures)
  • New regression specs fail on main and pass on this branch
  • GitHub CI green

🤖 Generated with Claude Code

plainprogrammer and others added 4 commits October 2, 2026 16:49
Back after filtering could show the filtered results under the unfiltered
URL on slow CI runners. Turbo 8.0.23's frame advance pushes the URL and
swaps the frame, then waits two repaints before starting the page visit
that marks Turbo busy. Back in that gap was cancelled by the late visit
(navigator.stop()), so the filtered page stayed. The no-cache meta from
fc8cff1 closed a different path (the snapshot cache) and not this one.

The collection and search filter forms and their pagination are now
ordinary Turbo Drive GET visits, so there is no gap. The pages keep
turbo-cache-control: no-cache, so Back and Forward refetch them. The
_top targets that only escaped the frame, and wait_for_turbo_idle's
frame check, are removed.

New regression specs slow repaints and the unfiltered fetch to reproduce
the race deterministically on both pages; they fail on main.

Deviates from the design system's "results sit in a Turbo Frame the form
targets" (README); maintainer ruling 2026-10-02.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It reset the filter fields after Turbo restored a page snapshot. With
the filter pages uncached and filtered by page visits, Back and Forward
always refetch server-rendered fields, so it no longer runs on any page
that needs it. The Back/Forward field specs pass without it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SearchResults records the deviation from the design system's results
frame and why; Pager, ViewSwitchForm and TileAdd lose their frame
targets. The exported README, FilterBar and CollectionPage still
describe the frame and need the change upstream.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ters

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@plainprogrammer
plainprogrammer merged commit 2bdef9d into main Oct 2, 2026
1 check passed
@plainprogrammer
plainprogrammer deleted the 004-filter-without-frames branch October 2, 2026 20:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant