Skip to content

Treat verse 0 as an ordinary verse; remove liveScrRef stickiness guard#134

Open
alex-rawlings-yyc wants to merge 3 commits into
mainfrom
remove-verse-0-guards
Open

Treat verse 0 as an ordinary verse; remove liveScrRef stickiness guard#134
alex-rawlings-yyc wants to merge 3 commits into
mainfrom
remove-verse-0-guards

Conversation

@alex-rawlings-yyc

@alex-rawlings-yyc alex-rawlings-yyc commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

A chapter's pre-verse-1 superscription is a real, focusable verse-0 segment,
but liveScrRef held a stickiness guard that swallowed any same-chapter verseNum: 0 reference naming the verse already shown. That guard was added
(b9dec18, "fix verse-0 echo nav") before verse 0 was a parsed verse, to absorb
the host's spurious post-verse-nav chapter echo. It could not distinguish that
echo from a genuine external < (previous-verse) from verse 1 — both are
same-chapter, verse 0, and markerless on the global selector path — so it also
ate the intentional <, leaving the extension stuck on verse 1 instead of
moving to the superscription.

Verified in a live session (probe logging liveScrRef/rawScrRef) that the host
no longer emits the spurious echo: exactly one delivery per navigation, never
an unsolicited trailing verse 0. With the echo gone the guard defended against
nothing, so remove it. Verse 0 now passes through verbatim; the host's < from
verse 1 lands on the chapter's superscription (the loader resolves verse 0 to
the superscription segment, else to verse 1).

The internal-nav marker machinery is retained — it still classifies internal/external navigations for the recenter fade. Only its former role
inside the verse-0 guard is gone.

Tests: collapse the two sticky-behavior tests into one pass-through regression
test; flip the mid-reveal fade test to expect the curtain to re-engage for a
verse-0 navigation arriving during fade-in (verse 0 is now an ordinary mid-reveal move).


This change is Reviewable

Summary by CodeRabbit

  • Documentation

    • Clarified navigation behavior descriptions for verse-0 references and fade/reveal transitions.
    • Updated explanatory notes to better reflect how live navigation behaves during chapter and cross-book changes.
  • Tests

    • Adjusted test expectations for verse-0 handling during live navigation.
    • Updated coverage for fade transitions when navigation changes arrive mid-reveal.

@alex-rawlings-yyc alex-rawlings-yyc self-assigned this Jun 29, 2026
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@alex-rawlings-yyc, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 26 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c9a323f6-6851-4cd2-bb1e-d3ea6fc84fa2

📥 Commits

Reviewing files that changed from the base of the PR and between 8b4cc27 and e51905e.

📒 Files selected for processing (4)
  • src/__tests__/components/InterlinearNavContext.test.tsx
  • src/__tests__/components/Interlinearizer.test.tsx
  • src/components/InterlinearNavContext.tsx
  • src/components/Interlinearizer.tsx
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch remove-verse-0-guards

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@alex-rawlings-yyc alex-rawlings-yyc linked an issue Jun 29, 2026 that may be closed by this pull request
@alex-rawlings-yyc

This comment was marked as outdated.

@coderabbitai

This comment was marked as outdated.

@alex-rawlings-yyc alex-rawlings-yyc marked this pull request as ready for review June 29, 2026 21:41
@imnasnainaec

Copy link
Copy Markdown
Contributor

Devin has a bug and some flags on this pr: https://app.devin.ai/review/sillsdev/interlinearizer-extension/pull/134

alex-rawlings-yyc and others added 2 commits July 2, 2026 11:19
A chapter's pre-verse-1 superscription is a real, focusable verse-0
segment,
but `liveScrRef` held a stickiness guard that swallowed any same-chapter
`verseNum: 0` reference naming the verse already shown. That guard was
added
(b9dec18, "fix verse-0 echo nav") before verse 0 was a parsed verse, to
absorb
the host's spurious post-verse-nav chapter echo. It could not
distinguish that
echo from a genuine external `<` (previous-verse) from verse 1 — both
are
same-chapter, verse 0, and markerless on the global selector path — so
it also
ate the intentional `<`, leaving the extension stuck on verse 1 instead
of
moving to the superscription.

Verified in a live session (probe logging liveScrRef/rawScrRef) that the
host
no longer emits the spurious echo: exactly one delivery per navigation,
never
an unsolicited trailing verse 0. With the echo gone the guard defended
against
nothing, so remove it. Verse 0 now passes through verbatim; the host's
`<` from
verse 1 lands on the chapter's superscription (the loader resolves verse
0 to
the superscription segment, else to verse 1).

The internal-nav marker machinery is retained — it still classifies
internal/external navigations for the recenter fade. Only its former
role
inside the verse-0 guard is gone.

Tests: collapse the two sticky-behavior tests into one pass-through
regression
test; flip the mid-reveal fade test to expect the curtain to re-engage
for a
verse-0 navigation arriving during fade-in (verse 0 is now an ordinary
mid-reveal move).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@imnasnainaec

Copy link
Copy Markdown
Contributor

I want to test this behavior out in the Psalms before approving:

src/components/InterlinearNavContext.tsx:248
Removing verse-0 stickiness relies on the host no longer sending spurious verse-0 echoes
The old code explicitly guarded against the host re-broadcasting the chapter as a verseNum: 0 reference after every verse navigation (the comment at the removed lines said "After a verse navigation the host re-broadcasts the chapter as a separate verseNum: 0 reference"). With the stickiness removed (src/components/InterlinearNavContext.tsx:248-251), any verse-0 reference the host sends will pass through to liveScrRef and then to the loader's activeScrRef (src/components/InterlinearizerLoader.tsx:245-249). If the chapter has a verse-0 superscription segment, this would jump the view to the superscription after every same-chapter verse navigation. The loader's fallback (resolving verse 0 to verse 1 when no segment exists) only helps chapters without superscriptions. If the host's echo behavior described in the old comment still exists, this could cause unexpected view jumps in chapters with superscriptions (e.g., many Psalms).

@imnasnainaec

Copy link
Copy Markdown
Contributor

The behavior is fine for me in the Psalms, so I think this is valid to act on:

src/components/InterlinearNavContext.tsx:248
liveScrRef and rawScrRef are now functionally equivalent after stickiness removal
With the verse-0 stickiness removed, both rawScrRef (line 217-220) and liveScrRef (line 248-251) perform the same deduplication logic: compare the incoming reference against their respective previous values using areScrRefsEqual, and reuse the old object on match. Since liveScrRef now always equals rawScrRef in value, the two refs will always converge to the same identity chain. The separation is still conceptually meaningful (raw host value vs. active reference) and retains its own identity-stable track for the context value's useMemo, so this is not a correctness issue — but it is now redundant logic that could be simplified if the design solidifies.

@imnasnainaec

Copy link
Copy Markdown
Contributor

I want to test this behavior out in the Psalms before approving:

src/components/InterlinearNavContext.tsx:248 Removing verse-0 stickiness relies on the host no longer sending spurious verse-0 echoes The old code explicitly guarded against the host re-broadcasting the chapter as a verseNum: 0 reference after every verse navigation (the comment at the removed lines said "After a verse navigation the host re-broadcasts the chapter as a separate verseNum: 0 reference"). With the stickiness removed (src/components/InterlinearNavContext.tsx:248-251), any verse-0 reference the host sends will pass through to liveScrRef and then to the loader's activeScrRef (src/components/InterlinearizerLoader.tsx:245-249). If the chapter has a verse-0 superscription segment, this would jump the view to the superscription after every same-chapter verse navigation. The loader's fallback (resolving verse 0 to verse 1 when no segment exists) only helps chapters without superscriptions. If the host's echo behavior described in the old comment still exists, this could cause unexpected view jumps in chapters with superscriptions (e.g., many Psalms).

And perhaps see if a new test or two could target this regression concern.

@alex-rawlings-yyc

Copy link
Copy Markdown
Contributor Author

I believe the most recent commit suffices to simplify the logic. I had done a bit of testing on my own and found that the host was no longer sending echoes. I didn't tell you because I got distracted working on the other PR and I also wanted to see if you could find any issues with the host that I didn't see

// verse before rendering. The alias keeps the intent-revealing name and marks the seam where any
// future raw→active mapping would live; `rawScrRef` already reuses the previously committed object
// on a value-equal re-send, so a duplicate delivery never reads as a fresh navigation.
const liveScrRef = rawScrRef;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the stickiness gone I think this can go one step further: stableRawScrRefRef and liveScrRefRef now hold the same object at every point they're read — both are set to the same object during render, and each is read before its own write. So the two refs can merge into one that serves both jobs (the duplicate-delivery identity guard and the mid-reveal prev comparison):

const prevScrRefRef = useRef<SerializedVerseRef>(hostScrRef);
const prevScrRef = prevScrRefRef.current;
const scrRef = areScrRefsEqual(hostScrRef, prevScrRef) ? prevScrRef : hostScrRef;
prevScrRefRef.current = scrRef;

with the mid-reveal guard comparing liveKey !== verseKey(prevScrRef). Behavior is unchanged (first render, duplicate deliveries, and StrictMode double-render all read the same values as today).

On keeping the rawScrRef/liveScrRef pair for the seam: the loader's activeScrRef is now where the real raw→active mapping lives — and any such mapping needs the loaded book, which this layer explicitly doesn't have (as this field's own doc notes). So I'd collapse the interface to a single scrRef and reintroduce the split only if a book-independent mapping ever turns up. Not a blocker either way.

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.

Follow global ref into verse 0 (superscription)

2 participants