Bound and exhaust Content document discovery - #2659
Conversation
This comment has been minimized.
This comment has been minimized.
Visual recap — generation failedThe visual recap could not be generated for this pull request. This is informational only and does not block the PR. Diagnostic: No plan URL: Repair changed too much of targeted file plan.mdx; expected a localized parser fix. Agent output: Repaired recap-source.json: structural |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Builder reviewed your changes — looks good ✅
Review Details
Code Review Summary
PR #2659 bounds Content document discovery with deterministic, access-scoped pagination, explicit totals/continuations, exact-title filters, and a shared predicate used consistently by count and page queries. The UI now exhausts list pages before exposing the document tree and rejects missing, inconsistent, duplicated, or non-advancing pagination metadata rather than treating a clipped response as complete. The optimistic cache contract remains object-shaped internally while consumers continue to receive a document array.
Risk: Standard — this changes shared discovery/business logic and privacy-sensitive filtering, though it does not alter authentication or public API security boundaries.
No confirmed high- or medium-severity issues were found. The implementation has strong coverage for multi-page list/search results, exact-match cardinality, outsider isolation, soft-deleted database filtering, stable-key projection replay, and optimistic cache compatibility. Code-review agents also verified the relevant Content tests pass.
🧪 Browser testing: Skipped — dev server was available, but browser automation tooling was unavailable to all executors; backend endpoints were independently verified, while UI flows could not be exercised.
Purpose
Content is shared by two kinds of callers: people navigating the workspace and agents trying to find, reason about, or safely create documents. Both need the same basic guarantee: after discovery finishes, “I found nothing” must mean that no authorized match exists—not merely that the caller received a clipped first page.
That guarantee matters most for create-if-absent workflows. An agent commonly searches for a document or database before deciding whether to create it. If an incomplete search looks complete, the agent can falsely conclude that the object does not exist, create a duplicate, omit existing material from an analysis, or report that a projection is complete when records were silently missed.
Problem
Before this change, Content had two opposite discovery failures:
Callers therefore had no common way to ask for a finite amount of work and then prove that they had reached the end. Worse, the responses looked ordinary: no timeout, error, or “partial” marker warned an agent that an absence claim was unsafe. One path in the UI could also turn an unexpected response shape into an empty array, making a contract failure resemble a genuinely empty workspace.
Before and after
Before
After
offset,limit,totalItems,returnedItems,hasMore, andnextOffset.nextOffsetuntilhasMoreis false; only then is absence or completeness established.How the contract works
Access and Content visibility filters are applied before both the count and the page are constructed. This is important for privacy: an unauthorized caller receives neither private rows nor a total that reveals their existence.
Pages have a maximum size of 200 and stable ordering with an ID tie-breaker. The workspace UI requests pages of 200, accumulates them, and verifies that the declared total stays fixed for the read. If documents change during traversal, it fails and asks for a retry rather than presenting a mixed snapshot as complete.
The React Query cache remains object-shaped—
{ documents, pagination }—because optimistic create/update code writes that contract. UI consumers receive only the selected, fully exhaustedDocument[]. This prevents an optimistic create from briefly handing an object to components that iterate an array.Exact 124-Capability proof
The database proof deliberately uses a complete, non-trivial corpus rather than a three-row pagination toy:
created, and the test records each item/document identity.updatedwhile preserving the original identities.unchangedwith the same identities, proving stable-key idempotency rather than duplicate creation.0,37,74, and111. Every page reports a total of 124; no ID repeats; the exhausted ID set exactly equals all 124 source IDs; and every read-back identity matches the first upsert receipt.This is an isolated local test projection. It does not write Alice’s Content workspace or vault.
What changed
list-documentsand excluded trashed or soft-deleted database artifacts before counting and paging.search-documents, including all Content organizations the caller belongs to.Compatibility, safety, and limitations
list-documentsAction contract: omitting pagination now returns the first 50 records, not the whole corpus. The shipped Content UI follows every page. Other direct Action callers must do the same.Product roadmap impact
No roadmap record changes state in this PR.
Verification
Evidence is bound to head
f712a7b6c3b68d6e34a3e46523b0f7232c49f442:git diff --checkpass for the implementation diff.Review focus