Skip to content

Add phrase spans, page-built token maps and undo step locations - #528

Merged
alex-rawlings-yyc merged 5 commits into
450-segment-page-analysisfrom
451-segment-page-phrase-spans
Oct 29, 2026
Merged

alex-rawlings-yyc merged 5 commits into
450-segment-page-analysisfrom
451-segment-page-phrase-spans

Conversation

@alex-rawlings-yyc

@alex-rawlings-yyc alex-rawlings-yyc commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Part of #426; closes #451. Stacked on #527.

Summary

This PR adds phrase spans to session segment pages, builds the WebView's token-level lookups from pages, and gives each undo step a location or a summary.

interlinearizer.getSegments({ sessionId }, bookCode, range) -> SegmentPage, now with phraseSpans
interlinearizer.undoEdit / redoEdit -> CommandReply, now with the step undone or redone

src/utils/page-indexes.ts   # buildPageIndexes, outlineRangeOf
src/services/editSteps.ts   # catalogStepOf, deletionStepOf, phraseStartOf
src/types/edit-step.ts      # EditStep and StepSummary, moved out of useDraftProject
  • Phrase spans. A session page's phraseSpans gives, for each phrase link that the page names, every word token of that link wherever it sits in the book. Each token comes with its segment, its document order and its gap text. A token that the book no longer holds is left out.
  • Page indexes. buildPageIndexes builds, from the outline and the pages held, the lookups that the WebView reads through the whole book's maps today: tokenSegmentMap, tokenDocOrder, fullTokenOrder, gapTextByWordRef, wordTokenByRef and the segment maps. It also builds the boundary guard, straddledBoundaryRefs. Spans fill in the tokens of phrases that reach past the held pages. The token walk (indexSegmentTokens) and the guard (straddledRefs) are shared with buildBookIndexes and Interlinearizer.tsx.
  • Jumps to unloaded targets. outlineRangeOf finds the outline range to load for a segment id or token ref whose page isn't held. It reads the verse from the token ref, as the Render the continuous view from segment pages #467 comment proposes, through positionOf, which now lives in verse-ref.ts.
  • Undo steps carry a location or a summary, as afterHistoryMove reads them on main (the Add apply with inverse capture and per-session undo #486 comment). Every command except the stale-place reviews passes its step to AnalysisSessions.edit. Token, phrase, boundary and free-translation edits locate theirs at the token or segment edited. Catalog edits, deletions and discards record a StepSummary. A kept stale breakdown is located at its token when kept from a token chip, and otherwise recorded as a catalog edit; the WebView now records the same, where before it recorded no step. Stale-place reviews (discarding or reapplying a stale analysis, keeping or discarding a stale free translation) record none, as the WebView does, because the view makes them at no place. EditHistory keeps each step, and an undo or redo hands it back in the reply.
  • Phrase payloads keep senseRef (the Resolve lexicon-linked glosses for display #514 comment), because pages carry whole phrase payload records.

Nothing calls page-indexes until Phase 4.

Evidence

The #407 tiers are checked only by npm run perf:pages, run by hand. CI runs only the unit tests, which use a small fixture.

  • npm run perf:pages now builds page indexes from every other segment's page on the Data layer: capture a performance baseline before the database migration #407 datasets and checks them against the whole book's lookups. It compares each phrase's text, arc order, split previews and segments, the boundary guard on the held tokens, and where each token's segment lies in the outline.
  • The same harness jumps to a token and to a segment whose page isn't held. Each jump loads the range that outlineRangeOf returns, and the harness checks that the page holds the target. Whether the jump lands focus waits for 4a ([4a] Wire the WebView to the host behind a feature flag #453), where the WebView first calls page-indexes.
  • At e41143a, perf:pages reports 0 differences on every tier:
    • small: 6 phrases reach unheld segments, 12 jumps.
    • medium: 89 phrases reach unheld segments, 260 jumps.
    • large-loadable: 26 phrases reach unheld segments, 260 jumps.
  • page-indexes.test.ts (11 cases) checks token placement against the whole book's, for held pages and for a phrase in a segment not held. It also checks the boundary guard, including a phrase that names a token the book lacks. outlineRangeOf cases cover tokens, segment ids, a verse that begins inside a segment begun mid-verse, and a verse or heading that the book lacks.
  • editSteps.test.ts (7 cases) covers a catalog step that names the analysis left holding its row or none; single, unused and multiple deletions; and a phrase step at its first token or at no place when the phrase isn't stored.
  • sessionPages, editHistory, analysisSessions and main tests check the spans on a page and the step that each command records and that undo and redo hand back.
  • The full suite passes at 100% coverage; lint and tsc are clean.

Decisions with a strong alternative

  • Spans carry tokens, not segments. A page names each phrase's member tokens with where they sit, rather than shipping the segments that hold them. That keeps a page's size bounded by its phrases, not by the segments they reach.
  • Catalog commands return the analysis left holding the edited row. That is the analysis itself, the payload it was folded into, or none, so the step names the survivor even when no link moved to it.
  • EditStep and StepSummary move to src/types/edit-step.ts, so the host can build them without importing a hook. Their docs are unchanged.

Merge Danger

Door: two-way

The WebView doesn't use sessions or page indexes yet. Moving the step types changes only imports.

Blast Radius: getSegments' session form (a new phraseSpans field), the undo and redo replies (a new step), AnalysisSessions.edit and EditHistory.apply (a new step option), and every command in main.ts, each of which now passes a step. buildBookIndexes and the WebView's boundary guard now run through the walk and guard they share with the page indexes. Phase 4 must read jump targets through outlineRangeOf and announcements through the reply's step.

🤖 Generated with Claude Code

Stack created with GitHub Stacks CLI • Give Feedback 💬


This change is Reviewable

@coderabbitai

coderabbitai Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 68635e3d-43e3-4ea4-a067-45eae99fa948
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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 marked this pull request as ready for review October 28, 2026 17:38
@alex-rawlings-yyc
alex-rawlings-yyc force-pushed the 451-segment-page-phrase-spans branch 2 times, most recently from 795a8fc to eea9aa0 Compare October 28, 2026 20:24
@alex-rawlings-yyc
alex-rawlings-yyc force-pushed the 451-segment-page-phrase-spans branch 2 times, most recently from dda053f to f497972 Compare October 28, 2026 20:57

@imnasnainaec imnasnainaec left a comment

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.

⛏️ Evidence doesn't report the run's numbers. Per tier, perf:pages prints how many phrases reach unheld segments and how many jumps ran. Those numbers are what show that the case of phrases spanning unloaded segments actually ran. Could you add them, as #527 and #529 do?


Drafted by Claude Opus 5.5; barely reviewed by me.

Comment thread perf/pages/cli.ts Resolved
@alex-rawlings-yyc

Copy link
Copy Markdown
Contributor Author

⛏️ Evidence doesn't report the run's numbers. Per tier, perf:pages prints how many phrases reach unheld segments and how many jumps ran. Those numbers are what show that the case of phrases spanning unloaded segments actually ran. Could you add them, as #527 and #529 do?

Done: the Evidence now gives each tier's phrases that reach unheld segments and its jumps. One correction to the old text: the held pages are every other segment's, not random sets.

imnasnainaec

This comment was marked as resolved.

@imnasnainaec imnasnainaec left a comment

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.

@imnasnainaec reviewed 43 files and all commit messages, and resolved 5 discussions.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on alex-rawlings-yyc).

@alex-rawlings-yyc
alex-rawlings-yyc enabled stacked auto-merge (squash) October 29, 2026 19:50
stacked auto-merge was automatically disabled October 29, 2026 19:50

Auto-merge was disabled for another pull request in the stack

…ook code, per review

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@alex-rawlings-yyc
alex-rawlings-yyc force-pushed the 451-segment-page-phrase-spans branch from b827dab to e41143a Compare October 29, 2026 20:04

@imnasnainaec imnasnainaec left a comment

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.

@imnasnainaec reviewed 5 files and all commit messages.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on alex-rawlings-yyc).

@alex-rawlings-yyc
alex-rawlings-yyc merged commit e49ed4b into main Oct 29, 2026
13 checks passed
@alex-rawlings-yyc
alex-rawlings-yyc deleted the 451-segment-page-phrase-spans branch October 29, 2026 20:27
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.

[3l] Add phrase spans to segment pages

2 participants