Priority
P2 — searching can fail against the real API and pagination can repeat rows or open a false terminal page.
Problem
The shared user-data template list at /app/profile/user-data and /admin/users/:id/user-data does not match VpsUserData::Index:
- WebUI sends
vps_user_data[q], but the upstream Index declares and applies only user and format plus the inherited limit and from_id controls.
- WebUI derives Next with
cursorFromDescendingPage (the minimum visible ID), while upstream with_pagination is ascending and its resource spec requires every returned ID to be greater than from_id.
- WebUI requests exactly the visible limit and treats every full page as non-terminal, so an exact final page exposes a false Next action.
- The current Playwright mock invents server-side
q, sorts descending, and ignores the real cursor/limit contract, masking all three defects.
At origin/main commit 23c71925c9d7ec314534201396ade99bd904c936, the affected code is src/components/user/UserDataTemplatesPanel.tsx, src/lib/api/vpsUserData.ts, and e2e/specs/app/profile_user_data.spec.ts. The authoritative contract is in upstream api/lib/vpsadmin/api/resources/vps_user_data.rb and api/spec/api/resources/vps_user_data_spec.rb.
Legacy UI purpose is preserved: list templates for the signed-in owner or exact administrator-selected user, filter by the supported user scope, and manage create/edit/deploy/delete actions. It never sends a label-search parameter.
Required frontend resolution
- Send only supported Index parameters to HaveAPI.
- Preserve label/#ID search without inventing
q, using a bounded ascending client-side scan that retains exact user and format scope and fails explicitly if completeness cannot be established.
- Request one lookahead match, render only the selected page size, and derive continuation from the greatest valid visible ID.
- Rebuild forward edges from fresh data, hide stale descendants, and recover safely if deleting a template empties a cursor page.
- Keep URL filter/history state, member/admin scope, responsive behavior, and all existing mutations unchanged.
- Replace the permissive mock with the real
id > from_id, ascending, bounded contract.
Acceptance criteria
- No request contains
vps_user_data[q].
- Label and #ID search can find a match beyond the first raw API batch while retaining user/format scope.
- Traversing pages returns no repeated visible IDs under the documented ascending contract.
- Lookahead rows never leak into the table or local search.
- An exact terminal page has Next disabled.
- Member and administrator user routes are covered on desktop and mobile.
- Tests perform no live mutation.
Residual upstream risk
VpsUserData::Index does not explicitly order by ID even though its cursor predicate and spec are ascending. The frontend will use the only cursor compatible with id > from_id; the broader deterministic-order guarantee remains an upstream concern tracked in #189.
Priority
P2 — searching can fail against the real API and pagination can repeat rows or open a false terminal page.
Problem
The shared user-data template list at
/app/profile/user-dataand/admin/users/:id/user-datadoes not matchVpsUserData::Index:vps_user_data[q], but the upstream Index declares and applies onlyuserandformatplus the inheritedlimitandfrom_idcontrols.cursorFromDescendingPage(the minimum visible ID), while upstreamwith_paginationis ascending and its resource spec requires every returned ID to be greater thanfrom_id.q, sorts descending, and ignores the real cursor/limit contract, masking all three defects.At
origin/maincommit23c71925c9d7ec314534201396ade99bd904c936, the affected code issrc/components/user/UserDataTemplatesPanel.tsx,src/lib/api/vpsUserData.ts, ande2e/specs/app/profile_user_data.spec.ts. The authoritative contract is in upstreamapi/lib/vpsadmin/api/resources/vps_user_data.rbandapi/spec/api/resources/vps_user_data_spec.rb.Legacy UI purpose is preserved: list templates for the signed-in owner or exact administrator-selected user, filter by the supported user scope, and manage create/edit/deploy/delete actions. It never sends a label-search parameter.
Required frontend resolution
q, using a bounded ascending client-side scan that retains exact user and format scope and fails explicitly if completeness cannot be established.id > from_id, ascending, bounded contract.Acceptance criteria
vps_user_data[q].Residual upstream risk
VpsUserData::Indexdoes not explicitly order by ID even though its cursor predicate and spec are ascending. The frontend will use the only cursor compatible withid > from_id; the broader deterministic-order guarantee remains an upstream concern tracked in #189.