Prerequisite chips, scroll-spy TOC, and Pagefind: the trio that closed the learning hub nav spec

The IntersectionObserver scroll-spy was working in the mockup before any component existed. The file was scratchpad/learning-toc-mockup.html and it had real chapter content in it, not lorem ipsum, so the right rail had something genuine to lock onto. Scroll down: the active heading highlights, the others dim, the rail holds position while the main column moves. That is the interaction you’re testing. You either see it working or you don’t. It worked.

That was P4 of seven. The spec was docs/specs/learning-hub/navigation.md. By the time P4 shipped on feat/learning-nav-p4-toc, phases P0 through P3 were already merged. All seven are now marked SHIPPED.

The thing worth writing down is why the spec narrowed to three patterns that actually moved the needle.

The spec’s shape

The navigation plan organised work into four categories. M was must-have, E was early win, N was navigation core, S was schema/SEO. Seven phases, P0 through P6, mapped across those categories. conventions.md tracked per-item status with ✅/⬜ markers: M1, E2, N1, N2, and so on. Nothing disappears into a list that never gets reviewed.

Phases P0 through P2 were necessary but mostly invisible. P0 was foundation plumbing. P2 was hub track sections with S1 JSON-LD. It was the first visible navigation change, and the first run through the full UI gate since the hub launched. I built an interactive approval mockup before writing any code. That is the gate: mockup first, explicit sign-off, then implementation. Every phase with a user-facing surface followed the same pattern.

P1 and P3 were schema and infrastructure. None of P0 through P3 are the interesting part.

P5: the single highest-value fix

conventions.md names N1 (prerequisite chips) “the single highest-value navigability fix.” That is a strong claim inside a spec that had six other phases. It is accurate.

The chip sits at the chapter head. A “Read first ↳” label followed by the prerequisite chapter name. One line. No prose. The reader sees it before they read anything.

What makes it high-value is not the UI. It is the dependency graph it forces you to maintain. You cannot write a prerequisite chip without knowing what all the chapters are and what order they should be consumed in. That knowledge exists implicitly in a well-structured learning property. The chip makes it explicit, queryable, and wrong in a way you will notice. A broken link in a prerequisite chip is a content error you catch in review. An implicit dependency that no one surfaced is not.

P5 shipped on feat/learning-nav-p5-prereqs. The devlog notes it is “unlike every other nav phase” in some respect. My read: every other phase is structural, changing how the hub is organised or labelled. The prerequisite chip is relational. It names a connection between two pieces of content that did not exist as a first-class data point before. That is the difference in category.

P4: the one client island

The in-chapter TOC is described in the devlog as “the subsystem’s one client island.” That phrase is doing real work. A learning hub built on a static-first Next.js site avoids client JavaScript wherever possible. The TOC is the exception, because scroll-spy needs the browser.

The IntersectionObserver approach is correct here. Register headings against an observer, track which one is currently visible, update the active state in the right rail. No scroll event listeners are needed. There are no manual offset calculations to maintain. The browser does the geometry.

The mockup at scratchpad/learning-toc-mockup.html had real chapter content in it, not a synthetic substitute. That matters because scroll-spy behaviour depends on how content is actually distributed down the page. Short sections, long sections, sections that run off-screen before the next heading appears: all of those affect when an IntersectionObserver fires. Testing against real content gives you real timing. The P4 implementation shipped from a mockup that had already answered those questions.

The “on this page” right rail closes a specific problem: once a chapter is long enough to scroll, readers lose their position. The TOC gives them back a map. It is also a trust signal. A reader consulting a long chapter can see at a glance what is covered and what has been deliberately omitted. That is useful even when they do not use it to jump.

P6: Pagefind

Site-wide search landed last. It shipped on feat/learning-nav-p6-search and the devlog marks it the “FINAL phase” of the navigation spec, now SHIPPED P0–P6.

Pagefind runs at build time, indexes the rendered HTML output, and ships a WASM runtime the browser loads on demand. No server, no query routing, no running process to maintain. The index updates on every deploy because every deploy builds the HTML.

The mockup at scratchpad/learning-search-mockup.html came first. Search has a particular reason to go mockup-first: the interaction states are more complex than they look. Empty state, query with results, query with no results, loading state between typing and index response. You want to see all of those before you wire up the real index.

Search is the hardest navigation problem to solve at the pattern level. It has to surface content across the entire property rather than within a single section. Prerequisite chips and the TOC are chapter-scoped. Search is site-scoped. That scope difference is also why it came last: you build the content, then you index it. Pagefind has nothing useful to index until P0 through P5 have shaped what the hub actually contains.

The three that mattered

P5, P4, and P6. Prerequisite chips, scroll-spy TOC, Pagefind. The devlog labels this combination “B-037’s highest-value trio.”

The payoff is asymmetric. P4 and P6 are navigation affordances that help readers who are already oriented. The TOC helps a reader who is in a chapter and wants to jump. Search helps a reader who knows what they are looking for but not where it is. Both serve the reader who is already engaged.

P5 is different in kind. Prerequisite chips help the reader who is not yet oriented. They answer the question before it is asked. A reader who hits a chapter they are not ready for will leave. A chip that reads “Read first ↳ [chapter name]” at the top gives them somewhere to go instead.

That sequencing function is what puts N1 at the top of the backlog. The other phases improve the experience of navigating. N1 improves the experience of entering.

Post-ship housekeeping

After P6 merged, the backlog in conventions.md got a full reconciliation pass: every M/E/N/S item updated to its actual status. The spec at docs/specs/learning-hub/navigation.md is marked SHIPPED P0–P6. The programme got a living atlas as its navigable living document.

The reconciliation step is easy to skip when you are shipping. It is not optional. A spec without post-ship status markers is indistinguishable from a spec with open items. Anyone returning to this property six months from now needs to know what is done and what is not without reconstructing it from commit history.

The navigation spec is done. The property it built navigability for is not.

All writing