Navigation surface: a page map with both numbers, and edges a model can follow

↗ view on GitHub · Eli Ziff · 2026-07-31 · 559b3841

The deterministic structure work got substantially stronger today and stayed
almost entirely unreachable. A model could read a whole document, Ctrl+F it,
read one section by handle, and see a flat rendered outline. It could not ask
for a page, walk to a sibling, or follow a single cross-reference -- so 4,414
resolved references were invisible to the only consumer that could use them,
and a contents page citing "Indemnification ... 47" was a dead end.

THE PAGE MAP. The engine already detects printed page labels
(universal-legal-pdf-engine `_assign_printed_page_labels`, header/footer
region, ambiguity left unresolved as a diagnostic), and
compileLegalPdfSourceDoc already lays both numbers onto the text plane --
`anchor: page=<physical>` with the printed label in `aliases`. Nothing needed
porting. The loss was downstream: the renderer prints `printed || physical`
as one `[page N]` marker, and extractLocalDocument kept only `.text`, so
every consumer saw one number and could not tell which sense it was.

extractLocalDocument now builds the map where the artifact is still in hand.
Recovered-from-markers is the fallback for text whose artifact is not (journal
bodies, A2AJ reports) and is labelled `source: "markers"`, with a numeric
marker carried under BOTH readings because the renderer genuinely collapsed
them -- claiming one would invent provenance.

Page requests resolve against both schemes. Front matter printed i-viii makes
"1" name two different sheets; a table of contents means the second and a
viewer means the first, so that request is REFUSED as ambiguous and the caller
qualifies it (`printed:1`, `pdf:1`). Ranges resolve endpoint by endpoint and
take the span by position, because a range across a numbering change is not
arithmetic on either label.

library_find gains `pages`: "47", "12-18", "3,5,9", "printed:iv - printed:2".
The filter runs on offsets AFTER the match so every `at` stays a document
offset that library_read offset= accepts -- scoping narrows where you look,
never renumbers what you find -- and the internal cap is raised first, since
applying max_results before the filter returns nothing whenever the leading
hits sit outside the scope.

library_links is new: stand at a provision and get its ancestors, siblings,
children, the references it makes and the references made to it, each as a
handle library_read accepts. Without a section it returns the reference census
and the hubs. A whole-document abstention is surfaced as `abstained` with its
note, because zero edges and "this skeleton is too thin to address" are
different answers and only one of them means the document has no references.

Two defects the tests found, both fixed here:
- "overlaps the page" is not "printed on the page". A node's span runs to the
  next heading, so the last section of page 1 laps onto page 2 by the marker
  line alone. pageSections splits `starts` from `continuedFrom`.
- a rendition whose provider compiler has not landed carries no blocks; that
  is "no pages", not a crash inside a read tool.

extractLocalDocument's return gains `pages` (additive; the existing shape
assertion is updated). No existing behaviour changes: section reads, windowed
reads, unscoped find and outline are untouched.

22 unit tests plus one end-to-end tool test over a mocked artifact whose front
matter is printed "i". tsc clean; localAssistantTools, localPdfLookup,
legalCrossReference and legalTextSkeleton suites pass (69 tests).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H9ToHYJVDxfeJcJwdzrP2H
Repository eliziff/Beaver
Author Eli Ziff <eliasziff@gmail.com>
Authored
Parents 1d09f681
Stats 4 files changed , +1115 , -7
Part of SourceDoc / DOCX engine: redlines, tracked changes, editing benchmark

Capture this commit into my fork

Download a Markdown prompt that tells Claude how to port this exact commit into your working tree. Run it via claude -p < capture-commit-559b3841.md from inside the repo you want the change in.

⬇ Download capture-commit-559b3841.md