@@ -74,12 +74,13 @@ describe('InterlinearNavContext', () => {
7474 expect ( result . current . liveScrRef ) . toEqual ( ref ) ;
7575 } ) ;
7676
77- it ( 'normalizes a chapter-level (verse 0) reference to verse 1 in liveScrRef' , ( ) => {
77+ it ( 'passes a chapter-level (verse 0) reference through to liveScrRef unchanged' , ( ) => {
78+ // Verse 0 is a real verse (a Psalm superscription), so it is no longer mapped to verse 1 here.
79+ // The loader resolves it to verse 1 only when the loaded book has no verse-0 segment.
7880 const ref : SerializedVerseRef = { book : 'GEN' , chapterNum : 3 , verseNum : 0 } ;
7981 const { result } = renderNav ( makeScrollGroupHook ( ref ) ) ;
8082
81- expect ( result . current . liveScrRef ) . toEqual ( { book : 'GEN' , chapterNum : 3 , verseNum : 1 } ) ;
82- // The raw reference still reports verse 0 so the editable nav controls reflect the selection.
83+ expect ( result . current . liveScrRef ) . toEqual ( ref ) ;
8384 expect ( result . current . rawScrRef ) . toEqual ( ref ) ;
8485 } ) ;
8586
@@ -100,9 +101,29 @@ describe('InterlinearNavContext', () => {
100101 expect ( result . current . liveScrRef ) . toEqual ( { book : 'GEN' , chapterNum : 3 , verseNum : 7 } ) ;
101102 } ) ;
102103
103- it ( 'normalizes a verse-0 reference that names a different chapter (a real chapter jump)' , ( ) => {
104+ it ( 'passes a same-chapter verse-0 echo through when it matches a fresh internal-nav marker' , ( ) => {
105+ // Selecting a verse-0 superscription navigates the host to verse 0 of the chapter already shown,
106+ // so the host's echo is shaped exactly like the spurious post-nav chapter echo. A fresh
107+ // internal-nav marker for that verse-0 key marks it as our own deliberate move, so the stickiness
108+ // exception lets it through to the superscription rather than holding the prior verse.
109+ const { result, setRef, rerender } = renderNavMutable ( {
110+ book : 'GEN' ,
111+ chapterNum : 3 ,
112+ verseNum : 7 ,
113+ } ) ;
114+
115+ act ( ( ) => result . current . navigate ( { book : 'GEN' , chapterNum : 3 , verseNum : 0 } , 'internal' ) ) ;
116+
117+ act ( ( ) => setRef ( { book : 'GEN' , chapterNum : 3 , verseNum : 0 } ) ) ;
118+ rerender ( ) ;
119+
120+ expect ( result . current . liveScrRef ) . toEqual ( { book : 'GEN' , chapterNum : 3 , verseNum : 0 } ) ;
121+ } ) ;
122+
123+ it ( 'passes a verse-0 reference for a different chapter through as a real chapter jump' , ( ) => {
104124 // A verse-0 reference for a chapter other than the one shown is a genuine chapter navigation, not
105- // an echo, so it still normalizes to that chapter's first verse.
125+ // an echo, so it is honored as verse 0 (the loader maps it to verse 1 if that chapter has no
126+ // verse-0 segment).
106127 const { result, setRef, rerender } = renderNavMutable ( {
107128 book : 'GEN' ,
108129 chapterNum : 3 ,
@@ -112,7 +133,7 @@ describe('InterlinearNavContext', () => {
112133 act ( ( ) => setRef ( { book : 'GEN' , chapterNum : 4 , verseNum : 0 } ) ) ;
113134 rerender ( ) ;
114135
115- expect ( result . current . liveScrRef ) . toEqual ( { book : 'GEN' , chapterNum : 4 , verseNum : 1 } ) ;
136+ expect ( result . current . liveScrRef ) . toEqual ( { book : 'GEN' , chapterNum : 4 , verseNum : 0 } ) ;
116137 } ) ;
117138
118139 describe ( 'duplicate host deliveries' , ( ) => {
@@ -136,10 +157,10 @@ describe('InterlinearNavContext', () => {
136157 expect ( result . current . liveScrRef ) . toBe ( liveBefore ) ;
137158 } ) ;
138159
139- it ( 'keeps liveScrRef identity when a verse-0 chapter jump is followed by its verse-1 form' , ( ) => {
140- // A chapter jump can arrive as a verse-0 reference (normalized to verse 1) followed by the
141- // explicit verse-1 reference. The raw references differ, but both normalize to the same
142- // verse, so the committed liveScrRef object must be reused for the second delivery .
160+ it ( 'treats a verse-0 chapter jump and its verse-1 form as two distinct deliveries ' , ( ) => {
161+ // A chapter jump can arrive as a verse-0 reference followed by an explicit verse-1 reference.
162+ // Verse 0 and verse 1 are now distinct verses (verse 0 is the superscription), so the second
163+ // delivery is a genuine move to verse 1 rather than a deduped duplicate .
143164 const { result, setRef, rerender } = renderNavMutable ( {
144165 book : 'GEN' ,
145166 chapterNum : 3 ,
@@ -149,12 +170,12 @@ describe('InterlinearNavContext', () => {
149170 act ( ( ) => setRef ( { book : 'GEN' , chapterNum : 4 , verseNum : 0 } ) ) ;
150171 rerender ( ) ;
151172 const liveAfterJump = result . current . liveScrRef ;
152- expect ( liveAfterJump ) . toEqual ( { book : 'GEN' , chapterNum : 4 , verseNum : 1 } ) ;
173+ expect ( liveAfterJump ) . toEqual ( { book : 'GEN' , chapterNum : 4 , verseNum : 0 } ) ;
153174
154175 act ( ( ) => setRef ( { book : 'GEN' , chapterNum : 4 , verseNum : 1 } ) ) ;
155176 rerender ( ) ;
156177
157- expect ( result . current . liveScrRef ) . toBe ( liveAfterJump ) ;
178+ expect ( result . current . liveScrRef ) . toEqual ( { book : 'GEN' , chapterNum : 4 , verseNum : 1 } ) ;
158179 } ) ;
159180
160181 it ( 'reuses the previous reference when a duplicate differs only in the verse segment string' , ( ) => {
@@ -271,16 +292,20 @@ describe('InterlinearNavContext', () => {
271292 }
272293 } ) ;
273294
274- it ( 'matches a verse-0 internal mark against the host-normalized verse-1 reference' , ( ) => {
275- // An internal navigation stamped at chapter granularity (verse 0) must still be consumable
276- // when the host echoes it back normalized to the chapter's first verse (verse 1) — the keys
277- // are computed through the same normalization so they cannot diverge on the verse-0 boundary.
295+ it ( 'keys a verse-0 internal mark to verse 0, distinct from verse 1' , ( ) => {
296+ // Verse 0 (a superscription) is its own verse, so a verse-0 internal navigation is consumable
297+ // only by a verse-0 reference — not by verse 1 of the same chapter.
278298 const { result } = renderNav (
279299 makeScrollGroupHook ( { book : 'GEN' , chapterNum : 1 , verseNum : 1 } ) ,
280300 ) ;
281301
282302 act ( ( ) => result . current . navigate ( { book : 'GEN' , chapterNum : 3 , verseNum : 0 } , 'internal' ) ) ;
283303 expect ( result . current . consumeInternalNav ( { book : 'GEN' , chapterNum : 3 , verseNum : 1 } ) ) . toBe (
304+ false ,
305+ ) ;
306+
307+ act ( ( ) => result . current . navigate ( { book : 'GEN' , chapterNum : 3 , verseNum : 0 } , 'internal' ) ) ;
308+ expect ( result . current . consumeInternalNav ( { book : 'GEN' , chapterNum : 3 , verseNum : 0 } ) ) . toBe (
284309 true ,
285310 ) ;
286311 } ) ;
0 commit comments