Skip to content

fix(system): fetch the Updates history grid from /api instead of server-rendering it (TIGER-383) - #366

Merged
WebTigers merged 2 commits into
mainfrom
fix/tiger-383-updates-grid-api
Oct 24, 2026
Merged

WebTigers merged 2 commits into
mainfrom
fix/tiger-383-updates-grid-api

Conversation

@WebTigers

Copy link
Copy Markdown
Owner

Found by the paradigm scanner in PR #364. The updates history was the one admin grid not following the client/server contract — the controller handed the view recent(15) and the view looped it into <tr> rows, where WEBSERVICES.md §5 says list/table data is fetched from /api.

There was a real gap behind the consistency argument

Dev has 24 history rows. The screen could only ever show 15. Nine update runs existed that nobody could reach — no paging, no search, no way to ask "what happened last month?". The paradigm violation was the symptom; this was the damage.

Converted to the house pattern, not a variant

Followed Cms_Service_Page::datatable and the Access user grid:

Piece Does
Tiger_Model_UpdateHistory::datatable() owns the query — search, sort, paging, both counts
System_Service_Updates::datatable() _dtParams() → finder → _dtResponse()
System_UpdatesController renders the shell, sets useDataTables
the view an empty <table>; init lives in the module's JS asset

A service never builds a predicate (AGENTS.md), so the finder is named and on the model. Rows are structured data only, never HTML — there's an assertion for that. This screen already loaded an external JS asset, so the grid init went there rather than adding an inline <script>.

The per-run step log became a DataTables child row, which is how DT expresses "detail under this row" — the old sibling <tr class="collapse"> has no equivalent. The log travels with the row payload, so expanding costs no second round trip.

history() is kept, and now says why

It was previously unwired from any UI. It survives because it's the plain read an API/MCP caller wants without DataTables semantics, and history is a READ_VERB — so a read-only token can reach it. The admin grid uses datatable().

Tests

Three service tests — the DataTables envelope with structured-rows-only (asserting no markup is built server-side), search narrowing recordsFiltered without moving the total, and a plain admin being denied — plus a new controller test.

The controller test asserts useDataTables, and that one earns its keep: without the flag the assets never load, the grid renders empty, and the page's JS dies after the failed init — silently, behind a 200, with nothing a casual look would catch. Mutation-checked: removing the flag fails it. A second test guards against a history view-var reappearing.

Verified in a browser

Signed in on tiger-dev as a superadmin: all 24 rows reachable and sortable, the child-row log expands with the full step list, 0 console errors.

And the scanner that filed this ticket now reports rendered_rows = 0.

Full unit suite green (1195 tests).

🤖 Generated with Claude Code

https://claude.ai/code/session_013vdyTeoDrGE4hKxt53TsE8

WebTigers and others added 2 commits October 24, 2026 13:16
…er-rendering it (TIGER-383)

The updates history was the one admin grid that did not follow the client/server
contract: the controller handed the view `recent(15)` and the view looped it into
<tr> rows. WEBSERVICES.md §5 is explicit that list/table data is fetched from /api,
never server-rendered.

The consistency argument is the point, but there was a real gap behind it: dev had
24 history rows and the screen could only ever show 15. Nine runs existed that
nobody could reach, with no paging, no search and no way to ask "what happened
last month?".

Converted to the house DataTables pattern, following Cms_Service_Page::datatable
and the Access user grid rather than inventing a variant:

  Tiger_Model_UpdateHistory::datatable()  owns the query — search, sort, paging,
      and both counts. A service never builds a predicate (AGENTS.md), so the
      finder is named and lives on the model.
  System_Service_Updates::datatable()     _dtParams() -> finder -> _dtResponse().
      Rows are STRUCTURED data only, never HTML; the step log rides along so the
      expandable detail costs no second round trip.
  The controller renders the shell and sets useDataTables.
  The view is an empty <table>; the grid init lives in the module's JS ASSET
      (this screen already loads one — no new inline <script>).

The per-run step log became a DataTables CHILD ROW, which is how DT expresses
"detail under this row"; the old sibling <tr class="collapse"> has no equivalent.

history() is KEPT, and now documents why: it is the plain read an API/MCP caller
wants without DataTables semantics, and `history` is a READ_VERB so a read-only
token can reach it. It was previously unwired from any UI.

Tests: 3 service tests (envelope + structured-rows-only + no markup; search
narrows recordsFiltered without moving the total; a plain admin is denied) and a
new controller test. The controller test asserts useDataTables — without that flag
the assets never load, the grid renders empty and the page's JS dies after the
failed init, silently, behind a 200. Mutation-checked: removing the flag fails it.
A second test guards against a `history` view-var reappearing.

Verified in a browser on tiger-dev as a superadmin: all 24 rows reachable and
sortable, the child-row log expands, 0 console errors. The paradigm scanner that
filed this ticket now reports rendered_rows = 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013vdyTeoDrGE4hKxt53TsE8
CI caught this and my local run did not: SystemControllerDispatchTest asserts the
Updates screen's view-vars, including `history` as an array — the very var this
change removes. I had filtered my local run to UpdatesService|UpdatesController,
and this file's name mentions neither, so it never ran.

The assertion is updated to the contract that now holds rather than the behaviour
being replaced: useDataTables is set, and `history` is absent because the rows come
from /api. Full integration suite run unfiltered this time: 1552 tests green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013vdyTeoDrGE4hKxt53TsE8
@WebTigers
WebTigers merged commit 9c44d2d into main Oct 24, 2026
14 checks passed
@WebTigers
WebTigers deleted the fix/tiger-383-updates-grid-api branch October 24, 2026 17:38
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