Split inbound links out of Page Detail into listInboundLinks (#235) - #243
Merged
Conversation
…ndLinks
A page's referrer count can reach the hundreds of thousands on a large
site, too large to embed in a single getPageDetail response — this
split lets callers page through referrers instead of loading them all
at once.
listInboundLinks reads viewer_anchor_facts (the read model) exclusively,
with no legacy fallback: answering "who links here" without the
dest_page_id index would require the exact full anchor_edges scan this
function exists to avoid. It throws an actionable error when the read
model is missing or stale, via the new requireViewerReadModel guard.
viewer_anchor_facts gains a first_text_id column (references text_refs,
schema v21->v22) so anchor text resolves without a second anchor_edges
round-trip. The new viewer-inbound-links-cursor/ module is a dedicated
per-table cursor (not a reuse of viewer-anchor-facts-cursor, whose
filterKey is scoped to status for broken/external link listing, not
destPageId) supporting forward/backward keyset pagination plus a direct
offset read for MPA page-number jumps, and a limit: 0 short-circuit for
count-only reads.
BREAKING CHANGE: PageDetail no longer has an inboundLinks field. Use
listInboundLinks(accessor, { url }) instead.
Mirrors the query package's split of inbound links out of get_page_detail: exposes listInboundLinks as its own cursor-paginated tool instead of embedding referrers (which can number in the hundreds of thousands) in the page-detail payload. get_page_detail's description no longer claims to include inbound links.
/api/pages/inbound-links (register-inbound-links-route.ts) exposes
listInboundLinks with no legacy fallback — in stub mode (a live crawl),
where viewer_anchor_facts can never exist, it responds
{ available: false } instead of calling a query that would only throw.
Page Detail no longer embeds the full inbound-links list: it fetches
only the referrer count (limit: 0) and links to the new
/pages/inbound-links view for the full, paginated list (MPA and
virtual-scroll both supported). Retry is disabled on both hooks since a
missing-read-model error won't resolve on retry.
Adds a dedicated e2e fixture/config (generate-inbound-links-fixture.mjs,
playwright.inbound-links.config.ts) since the shared fixture
deliberately never builds the viewer read model.
Mirrors get_page_detail's split: exposes listInboundLinks via the existing query CLI, with --url required and --limit/--offset/--cursor/ --direction for pagination, matching resource-referrers/duplicates/ mismatches' flag conventions. Documents the sub-command and backfills the --cursor/--direction rows the full-option table was missing for those existing cursor-paginated sub-commands.
…e step Updates the alias_of_id caller list, the inbound-link counting-grain invariant (now listInboundLinks instead of getPageDetail.inboundLinks), and adds the no-legacy-fallback / stub-mode-unavailable invariants for listInboundLinks alongside directory-tree's existing precedent. Also registers the new dedicated inbound-links Playwright suite as its own step in the Viewer E2E workflow.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
getPageDetailinto a dedicated, cursor-paginatedlistInboundLinksquery — a page's referrer count can reach the hundreds of thousands on a large site, too large to embed in a single response (issue ページ詳細の inboundLinks が巨大サイトで実用に耐えない件(要検討: 見せ方から) #235).listInboundLinksreads exclusively from theviewer_anchor_factsread model (no legacy fallback) and throws an actionableviewer-builderror when the read model is missing or stale, via a newrequireViewerReadModelguard.viewer_anchor_factsgains afirst_text_idcolumn (referencestext_refs, read-model schema v21→v22) so anchor text resolves without a secondanchor_edgesround-trip./api/pages/inbound-linksroute + dedicated/pages/inbound-linksview (MPA and virtual-scroll). Page Detail now shows only the referrer count with a link to the full list. In stub mode (live crawl), the route responds{ available: false }instead of throwing, since the read model can never exist there.inbound-linksquery sub-command. MCP: newlist_inbound_linkstool;get_page_detail's description no longer claims to include inbound links.ARCHITECTURE.md,docs/query.md, andmcp-server/README.mdupdated to match.Breaking change:
PageDetail.inboundLinksis removed. Package is at0.14.0(0.x), so this is a normal breaking change — no migration guide required.Test plan
yarn lint:check(no--fix) — cleanyarn build— all 13 packages buildyarn test— 561 files / 3963 tests pass/qa-engineer,/product-manager, and/code-review medium; all actionable findings fixed (a few findings verified as pre-existing patterns shared with siblingviewer_*cursor functions, out of this PR's scope)🤖 Generated with Claude Code