The example shows two expected note rows and a zero-row empty case. C1 contains A & B with count 0 and Review with count 2; C2 is an empty list. The static prototype has Prototype A/99 and Prototype B/88. The reading tool switches those cases and computes the expected cells from editable context JSON. It is a local contract comparison, not execution of a Thymeleaf engine.

Give the source two purposes
In the native template, put th:remove="all-but-first" on tbody and th:each on the retained first row. Use th:text for the label and count, with literal Prototype A/99 as design placeholders. The second literal row is Prototype B/88. Keep caption and headings outside tbody. The official Thymeleaf tutorial documents this natural-prototype pattern; verify your installed engine, HTML mode, Standard Dialect, resolver and context representation before processing the source. A reference tutorial version is not proof of your runtime configuration.
Opening unprocessed HTML should show both prototype rows. That is not a failure when you intentionally inspect the static source. The processed C1 artifact should instead contain exactly A & B/0 and Review/2. Inspect data cells rather than searching every numeral in a whole document for 99 or 88. A prototype might have the same number in an unrelated caption or a later note; the requirement here is that sample data rows do not contaminate the native result.
Treat zero as supplied data
C1's zero must remain 0, not become 99, blank, or a no-notes message. Avoid a truthiness fallback that treats zero as missing. Supply A & B as ordinary text, not pre-escaped text. With escaped output, serialized markup contains A & B while the visible cell reads A & B. A visible entity string suggests double escaping; interpreted markup suggests the wrong text-output boundary. Keep serialized markup and rendered text as separate checks rather than assuming one screenshot proves both.
The page displays expected visible cells and escaped cell markup, calculated from the current JSON using safe text output. You can edit the labels and finite numeric counts, then rebuild expectations. Missing notes, malformed JSON and invalid counts are held, not converted into an empty list. This bounded helper assists test preparation, but cannot establish the resolver's ability to supply those values or the engine's behavior on an actual Java object. Preserve the native context representation with your later run record.
Test the empty list independently
C2 expects zero data rows while caption and headings remain. No stale Prototype A/99 or Prototype B/88 row should survive as a fallback. If an application needs a friendly empty-state sentence, specify and test it separately; this contract deliberately keeps the table structure with no body rows. Missing context and an engine exception are not known empty-list results and should retain their own diagnostics rather than being made to look like a clean empty table.
Keep source, context, configuration and actual output together when checking the processed template. If any changes, process the template again and inspect the new output. Inspect row count, escaping and zero preservation after native processing, then review the rendered table at the intended width. Keep earlier artifacts with their original revisions. The reading aid prepares exact expectations; a fresh native output and its actual rendered cells still provide the evidence that the template processed correctly.
Make your own working example
Build an original Thymeleaf contract comparison, explicitly not a native template engine. Include static prototype, C1 context, C2 empty list and Reset buttons. Static rows are Prototype A/99 and Prototype B/88. C1 notes are [{label:"A & B",count:0},{label:"Review",count:2}]; C2 notes is [].
Provide editable JSON context and Compute expectations. Derive visible Label/Count cells and escaped cell markup from current notes. Zero remains 0. A & B displays normally while serialized markup shows A & B. Reject missing notes, malformed JSON, nonstring labels and nonfinite/nonnumeric counts instead of replacing them with samples or empty data. Context edits clear stale results. C2 retains caption/headings with no data rows; include that rule in a static explanation beside the expected output.
Include a native-source pattern using tbody th:remove all-but-first, first tr th:each note : notes (native variable expression), and th:text cells; clearly identify it as source to process under a separately confirmed Thymeleaf HTML/Standard-Dialect setup. Native engine version/resolver/context and actual processed-output observations remain outside this helper. Show the contrast and row count early, with no fake Render/engine success button.
Use one self-contained HTML file with no remote dependency. Keep the initial sample, output, and labeled controls near the top. Use at least 16px text, strong contrast, visible focus, and a stacked layout at 360px without horizontal overflow. Use explicit type=button click handlers and explicit DOM selectors; do not depend on native form submission. Clear stale feedback when task inputs change. Render entered text safely. Keep practice data local to the current page; do not imply saving, sending, or production integration. Return only the finished HTML.
Explain the empty-list check
Keep native template and processed output together. For an HTML comparison, NOS lets you revise eligible static explanatory text visually without AI regeneration. Clarify why the zero-row case retains its headings, then check the actual native artifact against that statement.