Recommended catalog continuation
Problem and behavior
The baseline Recommended endpoint treated its bounded recommendation candidate pool as the entire catalog. In the same English guest scope, production reported 247 Recommended cards while ordinary catalog browsing reported 559. Its separate 600-offset guard also returned an artificial end. Public cursor rollout is zero, and private cursor readers can enter this baseline path when admission is full.
Clean Recommended now serves the ranked candidate pool first, followed by every other eligible world in stable ID order. A low recommendation score or absence from candidate retrieval no longer removes a story from the whole feed. The returned total describes eligible inventory, including the continuation. This does not claim that the unranked tail has personalized relevance ordering.
Publication, access, audience, language, content settings, blocked creators and global saved/dismissed exclusions still apply. Signed-in readers do not receive their own worlds. Language-group exclusion also hides translated siblings of saved worlds. These rules distinguish eligible discovery inventory from the raw database count. The catalog is finite; no endpoint can supply infinite unique eligible stories. Search, explicit tag/creator/following filters and other feed modes retain their existing behavior.
Implementation
- Rank a bounded candidate pool and revalidate it against the same conditions used for the catalog count and continuation.
- Exclude the entire eligible ranked pool from the continuation, page only IDs, then hydrate the requested page without embeddings.
- Use a unique world-ID tie-breaker for popularity/newness retrieval so tied counters and timestamps do not arbitrarily change candidate membership.
- Remove the 600-offset cutoff only for clean Recommended. Reject unsafe integer offsets and short-circuit requests beyond the eligible count.
- Apply the existing 180-request/minute discovery origin limiter to baseline Recommended requests too. Already admitted cursor requests are counted once.
- Apply a 2.5-second deadline to each catalog query. This is a per-query limit, not a total request timeout. A failure returns a noncacheable, retryable 503; it never reports false exhaustion or silently switches to default ordering.
- Version recommendation page-cache keys to v5 so old truncated totals are not reused. No database migration or Railway variable change is required.
Continuity and scale limits
This repairs the legacy offset fallback. Coverage is complete for unchanged inventory, profile and ranking inputs; concurrent publication, exclusions or ranking updates can still move offset boundaries. The rotation bucket does not freeze a visit. Client delivered-ID tracking suppresses duplicates, but cannot prove that no story was skipped during such changes.
The existing stateful cursor path remains the intended path for stable visits. Its public rollout and richer personalization flags are unchanged. Counts and deep SQL offsets still grow with catalog size, although delivery hydration is bounded to one page and the ranking pool stays bounded. Do not describe this fallback as having constant query cost at arbitrarily large scale.
Verification
Regression coverage uses the real Hono route and an isolated PGlite catalog of 713 worlds. Before the fix, a guest received only 208 stories, and the signed-in capacity fallback only 207 of its 712 eligible stories. Tests traverse the full catalog without duplicates and beyond offset 600, including the signed-in admission fallback with a saved story excluded.
Additional cases cover tied retrieval ordering, ranked-to-catalog page boundaries, partial final pages, empty ranked pools, extremely large offsets, saved-story changes, retryable query failure, and a real origin-limit rejection that performs no catalog query. Release verification results are recorded in the pull request. No interactive browser verification is part of this change.
Local validation: 73 focused server tests pass; hosted typecheck (8 tasks), build (5 tasks) and client edition boundary pass. Independent review reran all 13 HTTP route tests and found no remaining blocker after the retrieval tie-breaker fix.
