refactor(pagination): single Paged representation across β/γ/local (fixes defect 1 & 5) - #145
Merged
Merged
Conversation
…indmap #14) Lands the five-step plan from the orthogonality review's pagination- representation finding. The four pagination numbers (limit/offset/order/ direction) used to change shape ~10 times across 3 transport mechanisms with 2 merge implementations and a double read of the same raw args. - ① paged_from_selection(): the SINGLE dispatch-layer read of raw selection args (fetch_remote_subtree resolves once when no merged Paged arrived); the loader's in-loader GAP B fallback re-parse is deleted. Resolved fallback params join the split key, so their isolation now matches the merged-params isolation. - ② the γ create-time closure defaults (order/direction/limit/offset — dead config, the only caller never passed them) and their eff_* merge chain are deleted; the side-channel Paged is the single source. - ③ paged_wire_params(): the single Paged → wire-fields mapping; the β gql renderer and the γ JSON body both consume it. - ④ page params join the loader split key via the existing params_key mechanism — fixes defect 1: REMOTE_PAGED selections wrap {items, pagination} so the selection fingerprint was always None, force_split never fired, and concurrent limit=5/limit=10 loads shared ONE instance, overwriting each other's side-channel params. - ⑤ Paged.clamp(): the single clamping implementation, applied at the β dispatch layer against the relationship's max_page_size — fixes defect 5 (federation limits were forwarded unclamped; the bound existed only on the local PageArgs path). limit=None (full-fetch) semantics unchanged. γ has no boundary declaration surface today — noted as a follow-up decision. API change: create_dto_remote_loader drops its four dead pagination kwargs (never effective in-tree; its only direct test updated to the side-channel contract, which also locks the explicit limit=0 vs omitted distinction). Tests: defect-1 regression (params_key isolation + root-cause lock), federation limit clamp (100000 → 100 on the wire), γ full-fetch back-compat, loader-never-rereads-args contract. Full suite 1683 passed. Co-Authored-By: Claude <noreply@anthropic.com>
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
Lands the five-step plan from the full-project orthogonality review (mindmap node #14 / 收敛路线⑤ pagination half): the four pagination numbers (limit / offset / order / direction) used to change shape ~10 times across 3 transport mechanisms, with 2 merge implementations and a double read of the same raw args. This PR makes the merged
Pagedthe single representation end to end — and fixes two of the five confirmed defects on the way.The five steps
paged_from_selection()— the single dispatch-layer read of rawselection.arguments; the paginated loader's in-loader GAP B fallback re-parse is deletedorder/direction/limit/offset— dead config, the only caller never passed them) and theireff_*merge chain deletedResolver._merge_paged)paged_wire_params()— single Paged → wire-fields mapping; β gql renderer and γ JSON body both consume itparams_keymechanismPaged.clamp()— single clamping implementation, applied at the β dispatch layer against the relationship'smax_page_sizeDefect 1 — concurrent param overwrite (data correctness)
REMOTE_PAGEDselections are wrapped in{items, pagination}— neither key is a target-entity field, so the selection fingerprint (type_key) was alwaysNonethere andforce_splitnever fired: concurrentreviews(limit:5)/reviews(limit:10)loads shared one loader instance and overwrote each other's_remote_page_params. Params now join the split key (the same per-params mechanism γ already used); identical params still share an instance so batching is preserved.Defect 5 — federation limits forwarded unclamped
max_page_sizeclamping existed only on the localPageArgspath; β/γ forwarded limits as-is (limit=100000vs a declared max of 100 went straight to the member).Paged.clamp()is now the single implementation, applied at the β dispatch layer.limit=None(remote full-fetch) semantics unchanged. γ has no boundary declaration surface today (RelationshipInfois a β concept) — noted in-code as a follow-up decision.API change
create_dto_remote_loaderdrops its four dead pagination kwargs — never effective in-tree (the only caller never passed them); its only direct test is updated to the side-channel contract, which also locks the explicitlimit=0vs omitted distinction.Verification
type_key is Noneroot-cause lock, wire clamp (100000 → 100), γ full-fetch back-compat, loader-never-rereads-args contractruff check src/clean🤖 Generated with Claude Code