Skip to content

refactor(pagination): single Paged representation across β/γ/local (fixes defect 1 & 5) - #145

Merged
allmonday merged 1 commit into
masterfrom
refactor/paged-single-representation
Sep 4, 2026
Merged

refactor(pagination): single Paged representation across β/γ/local (fixes defect 1 & 5)#145
allmonday merged 1 commit into
masterfrom
refactor/paged-single-representation

Conversation

@allmonday

Copy link
Copy Markdown
Collaborator

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 Paged the single representation end to end — and fixes two of the five confirmed defects on the way.

The five steps

# Change Effect
paged_from_selection() — the single dispatch-layer read of raw selection.arguments; the paginated loader's in-loader GAP B fallback re-parse is deleted Same intent parsed once, one layer
γ loader's create-time closure defaults (order/direction/limit/offsetdead config, the only caller never passed them) and their eff_* merge chain deleted One merge implementation (Resolver._merge_paged)
paged_wire_params() — single Paged → wire-fields mapping; β gql renderer and γ JSON body both consume it Adding a future param (e.g. cursor) = one field + per-codec formatting
Page params join the loader split key via the existing params_key mechanism Fixes defect 1 (see below)
Paged.clamp() — single clamping implementation, applied at the β dispatch layer against the relationship's max_page_size Fixes defect 5 (see below)

Defect 1 — concurrent param overwrite (data correctness)

REMOTE_PAGED selections are wrapped in {items, pagination} — neither key is a target-entity field, so the selection fingerprint (type_key) was always None there and force_split never fired: concurrent reviews(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_size clamping existed only on the local PageArgs path; β/γ forwarded limits as-is (limit=100000 vs 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 (RelationshipInfo is a β concept) — noted in-code as a follow-up decision.

API change

create_dto_remote_loader drops 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 explicit limit=0 vs omitted distinction.

Verification

  • New regressions: params_key isolation + the type_key is None root-cause lock, wire clamp (100000 → 100), γ full-fetch back-compat, loader-never-rereads-args contract
  • Full suite 1683 passed / 0 failed; ruff check src/ clean

🤖 Generated with Claude Code

…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>
@allmonday
allmonday merged commit afa6b12 into master Sep 4, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant