Task: has_pagination knob is a silent-failure footgun in the Qt client model template

Table of Contents

This page documents a task in the Fix codegen template drift story. It captures the goal, current status, acceptance, and any notes or results.

Goal

cpp_qt_client_model.cpp.mustache generates a fetch method whose behaviour is a binary fork on the :has_pagination: Qt-facet flag: set true, it sends real offset=/=limit to the server and reports the server's true total_available_count; unset (the silent default), it ignores offset/limit entirely, always fetches the server's default page, and reports the fetched page's own size as if it were the total — masking the truncation instead of surfacing it. Every entity's MdiWindow unconditionally shows a full PaginationWidget (Next/Previous/Load All/page size) regardless of this flag, so an entity with the flag off looks identical to one with it on right up until its row count exceeds 100, at which point rows silently become unreachable with no error, warning, or visual cue. 61 of the app's ~89 Qt list entities currently have the flag unset — see the tracking task for the full list and the fix (set the flag, regenerate).

The narrower fix (setting the flag everywhere) doesn't address the shape of the footgun: a knob that silently defaults to the broken behaviour, with no build-time or run-time signal distinguishing "deliberately unpaginated, all rows always fit" from "someone forgot to set the flag." Worth reconsidering the underlying design once the narrow fix lands:

  • Generate the paginated fetch path unconditionally (drop the has_pagination fork) and let every entity always send real offset/limit and report the real total — the branch exists presumably as an optimisation/simplification for small, truly bounded lookup tables, but the two code paths are barely different and the unconditional one is strictly more correct.
  • Or, if a genuinely unpaginated mode is still wanted for small fixed lookup tables, gate the widget on the same flag too, so an unpaginated entity's MdiWindow doesn't render Next/Previous/Load All controls that don't do anything — the mismatch between "looks paginated" and "is paginated" is what let this go unnoticed across 61 entities.
  • Either way, a codegen lint/validation pass that flags entities whose generated model and generated window disagree on pagination support would catch the next occurrence of this drift at generation time rather than in production data.

Status

Field Value
State BACKLOG
Parent story Fix codegen template drift
Now Not yet started.
Waiting on Nothing.
Next Begin implementation.
Last touched 2026-08-06

Acceptance

Plan

(Implementation strategy. Written when work starts; key decisions are distilled into the parent story's * Decisions at close, but the plan itself stays — it is the historical record of what we did.)

Notes

Test Scenarios

Manual QA scenarios (scaffolded via compass add test_scenario, run through the QA Validation Runner panel) that verify this task. Link new ones here as they're created; the scenario doc itself links back via its "Verifies task" field.

Scenario State Notes
     

PRs

PR Title
   

Review

Comment summary File Decision Notes
       

Result

Promoted from capture

Captured 2026-07-19 in the product backlog; promoted preserving the UUID.

What

cpp_qt_client_model.cpp.mustache generates a fetch method whose behaviour is a binary fork on the :has_pagination: Qt-facet flag: set true, it sends real offset=/=limit to the server and reports the server's true total_available_count; unset (the silent default), it ignores offset/limit entirely, always fetches the server's default page, and reports the fetched page's own size as if it were the total — masking the truncation instead of surfacing it. Every entity's MdiWindow unconditionally shows a full PaginationWidget (Next/Previous/Load All/page size) regardless of this flag, so an entity with the flag off looks identical to one with it on right up until its row count exceeds 100, at which point rows silently become unreachable with no error, warning, or visual cue. 61 of the app's ~89 Qt list entities currently have the flag unset — see the tracking task for the full list and the fix (set the flag, regenerate).

The narrower fix (setting the flag everywhere) doesn't address the shape of the footgun: a knob that silently defaults to the broken behaviour, with no build-time or run-time signal distinguishing "deliberately unpaginated, all rows always fit" from "someone forgot to set the flag." Worth reconsidering the underlying design once the narrow fix lands:

  • Generate the paginated fetch path unconditionally (drop the has_pagination fork) and let every entity always send real offset/limit and report the real total — the branch exists presumably as an optimisation/simplification for small, truly bounded lookup tables, but the two code paths are barely different and the unconditional one is strictly more correct.
  • Or, if a genuinely unpaginated mode is still wanted for small fixed lookup tables, gate the widget on the same flag too, so an unpaginated entity's MdiWindow doesn't render Next/Previous/Load All controls that don't do anything — the mismatch between "looks paginated" and "is paginated" is what let this go unnoticed across 61 entities.
  • Either way, a codegen lint/validation pass that flags entities whose generated model and generated window disagree on pagination support would catch the next occurrence of this drift at generation time rather than in production data.

Why

Discovered while investigating a real bug during manual QA of the calendar Qt screens task: the Currencies list showed "Showing all records (100)" with 68 currencies (including USD) silently unreachable. The immediate fix is per-entity (tracked here); this capture is about the generator-level anti-pattern that made the bug possible and easy to reintroduce on the next new entity.

References

Emacs 29.3 (Org mode 9.6.15)