feat(reports): reinstate partial and deposit-reduced legend sentences (#1965) - #1979
Conversation
Replace the old 'footnotes always empty' describe block in buildReportContent.test.ts with 6 new tests covering AC 1.1–1.5 (split flag, depositReduced flag, both flags, neither flag, deduplication, excluded invoice). Update realRender.test.ts: the footnotes assertion now expects length 2 (split + depositReduced entries) instead of empty, removes the deposit-reduced sentence from goneFootnotes, and adds a positive check that the deposit-reduced legend sentence appears in the rendered PDF content tree. Fixes #1965 Co-Authored-By: Claude qa-integration-tester <noreply@anthropic.com>
…#1965) Push split/depositReduced footnote entries from buildReportContent when the corresponding invoice sets are non-empty; preview and PDF consume them automatically. Fixes #1965 Co-Authored-By: Claude frontend-developer <noreply@anthropic.com> Co-Authored-By: Claude qa-integration-tester <noreply@anthropic.com>
|
[ux-designer] Verdict: APPROVED Scope reviewed: no CSS changes, no new components, no new i18n keys — the only visual change is that Token adherence: nothing to flag — zero CSS changes in this PR. i18n copy accuracy: all four keys referenced in
The non-breaking spaces in the inline-label values are correct and intentional (per existing parity-test notes for multi-word inline labels). Test assertions: the No design-system concerns. |
|
[product-architect] PR review — #1979 (story #1965) Verdict: CHANGES_REQUIRED (one high finding: the change makes a currently-green E2E scenario fail, and leaves the E2E page-object contract asserting the opposite of the new behaviour). What I verified
FindingsHIGH 1 — E2E Scenario 18 now asserts the opposite of the shipped behaviour
await expect(wizard.footnotesBlock).toHaveCount(0);
await expect(wizard.footnoteItems).toHaveCount(0);
...
expect(pageText).not.toContain('Amount shown reflects only the portion allocated to this source.');With this PR those rows put Fix it as this PR, and invert rather than delete: assert Scenario 17 ( HIGH 2 — the page-object contract instructs future agents to do the wrong thing
These are now false, and unlike a stale comment they are a directive — the next agent touching this POM will follow them. Update all four sites to describe the reinstated legend (shared, unnumbered, one entry per flag, joined to rows by the inline-label token) and drop the "never assert a positive count" rule. MEDIUM 3 — the new assertions are weaker than the ACs require
MEDIUM 4 — wiki debt this PR reopens (ADR-034)
LOW 5 — stale in-code comments
INFO — inherited proxy limitationThe legend inherits the Requested changes: HIGH 1, HIGH 2, MEDIUM 3, MEDIUM 4. LOW 5 is welcome in the same push. |
|
[product-owner] Verdict: CHANGES_REQUIREDReviewed What I verified as met
Also confirmed the legend stays non-editable and report-level, as the story required:
Blocking findings1. HIGH — the preview renders
<span className={styles.footnoteMarker}>{note.marker}:</span>
{note.text}The whitespace between This code path was unreachable in production while 2. HIGH — AC 1.4, AC 1.5 and AC 3.1 are asserted at the array level only, which AC 1.5 explicitly excludes
I am not treating this as a checklist item. #1965 exists because #1959 emptied Needed (routes to
Non-blocking (fix before merge or file as follow-up)3. MEDIUM — AC 4.1 has no measured layout assertion. No test renders a report with both flags present and measures the legend block against the printable area. Real overflow risk is low (two short, space-wrappable sentences; longest unbreakable token is 4. LOW — 5. LOW / informational — 6. LOW — the N>1 dedup case is covered for ScopeClean. Additive, producer-only, four files, no drive-by changes, no scope creep. The agent-memory file is expected per CLAUDE.md. |
Replace two weak negative marker assertions (not.toContain symbol) with positive equality checks against content.labels, add locale-aware text assertions proving real i18n resolution, add rendered-surface check for the split legend sentence (AC 3.1), and update the ReportContentEditor fixture from stale dagger/double-dagger symbols to current inline-label style. Note: getByText with a string fails when the marker contains NBSP — the lib normalizes element text (NBSP→space) but does NOT normalize the matcher string before ===. Use a regex (/^less\sdeposit:$/) which IS tested against the already-normalized text. Co-Authored-By: Claude qa-integration-tester <noreply@anthropic.com>
- Fix JSX whitespace in ReportContentEditor footnote list (preview/PDF parity) - Invert Scenario 18 E2E assertions: expect 1 legend entry, not 0 - Update POM directive and spec header for new footnotes behaviour Co-Authored-By: Claude dev-team-lead <noreply@anthropic.com> Co-Authored-By: Claude frontend-developer <noreply@anthropic.com> Co-Authored-By: Claude e2e-test-engineer <noreply@anthropic.com>
Co-Authored-By: Claude product-architect <noreply@anthropic.com>
…rrection Co-Authored-By: Claude product-architect <noreply@anthropic.com>
|
[product-architect] Re-review — #1979 (story #1965), HEAD Verdict: CHANGES_REQUIRED — narrow and mechanical. Three of my four requested changes are fully discharged and the production code is unchanged and still correct. What remains is the other half of HIGH 2: two of the four enumerated docstring sites still carry the "nothing populates Verified fixedHIGH 1 — E2E Scenario 18 inverted. Discharged, and better than I asked for. MEDIUM 3 — assertions strengthened correctly. MEDIUM 4 — ADR-034 corrected thoroughly. Wiki submodule bumped on-branch to Bonus, correctly caught: the JSX whitespace fix at POM field declaration + spec header (2 of 4 HIGH 2 sites) are correctly rewritten and now describe the reinstated behaviour, including which scenarios expect zero vs one. Remaining — HIGH 2 (residual)My original finding named four sites. Two are fixed; the two with the strongest wording are not. 1. 2.
This is the site that matters most. The spec header ( 3. Why I'm not waving these through. Concrete failure path: agent reads the POM directive → opens Scenario 18 → sees a title claiming no footnote list over a body asserting one → concludes the body drifted → reverts to Fix: reword sites 1 and 2 to match the (already correct) field-declaration comment at Non-blocking follow-ups (welcome in the same push)
Everything else — producer placement, dedup-by-construction, ordering, additive-only behaviour, |
…e fix pattern Discharge the owed-ADR-034 note now that PR #1979 landed the B4 rewording, legend addendum, and Deviation Log. Record the re-review pattern: an enumerated multi-site doc fix comes back covering only the sites adjacent to the changed code, and a test title can state the inverse of its body. Co-Authored-By: Claude product-architect <noreply@anthropic.com>
|
[product-owner] — round 2 Verdict: APPROVEDRe-reviewed Two cheap MUST FIX items below — neither is an acceptance-criteria gap, and neither blocks the verdict. Round-1 finding 1 (HIGH — preview rendered
|
| What I asked for | What landed |
|---|---|
| Both sentences asserted present in rendered output, per locale | realRender.test.ts:1061-1066 — deposit and split sentence asserted in the collected rendered PDF tree, en and de |
| No key-echo / no fixture-agreement escape | realRender.test.ts:1017-1023 — footnotes[0].text / [1].text compared to the literal English and German sentences, against real i18n bundles |
| Occurrence count for the N>1 dedup case, in the rendered preview DOM | reportWizardEditableContent.spec.ts:1730-1737 — Scenario 18's fixture has two split invoices and now asserts footnotesBlock count 1 and footnoteItems count 1, plus the sentence present in main's text |
| Negative case on a rendered surface | Scenario 17 (:1632) asserts footnotesBlock count 0 in a real DOM for the constituted-deposit row |
Fixture markers stop being †/‡ (round-1 finding 4) |
ReportContentEditor.test.tsx:938-961 — now partial / less deposit |
Two things landed beyond the ask and are worth calling out:
realRender.test.ts:1019-1021replaced the weakexpect(marker).not.toContain('†')withexpect(footnotes[0].marker).toBe(content.labels.splitNote). That is now a direct assertion of AC 2.3's shared-token property — legend marker and row label proven byte-identical (including the deliberate U+00A0) rather than inferred from two call sites happening to use the same key. This closes round-1 finding 5 as a risk.ReportWizardPage.ts:469-479no longer instructs future authors "Never assert a positive count on these." That page-object comment was the contract-level half of the problem — a locator documented as negative-only is a locator nobody will ever use to catch the legend disappearing again.
Credit where due: the rendered-preview occurrence count arrived as the fix for product-architect's HIGH-1 (Scenario 18 asserting the opposite of shipped behaviour). It happens to be precisely the AC 1.5 coverage I was asking for, and on a better surface than the jsdom fixture I proposed. Verified executed, not just written: E2E shard 2/16, test 161 — [desktop] reportWizardEditableContent.spec.ts:1649:3 — passed.
Acceptance criteria — final state
| AC | Verdict | Notes |
|---|---|---|
| 1.1 | met | verified round 1 |
| 1.2 | met | verified round 1 |
| 1.3 | met | order pinned in buildReportContent.test.ts:485-487 and realRender.test.ts:1013-1016 |
| 1.4 | met | array negative (:494, :524) + rendered preview DOM negative (Scenario 17). Rendered-PDF-text negative → #1980 |
| 1.5 | met | rendered preview DOM count asserted with N=2 → 1. PDF-text count → #1980 |
| 2.1 | met | verified round 1 — still additive, no label/cell/CSS change |
| 2.2 | met | realRender.test.ts glyph absence with positive control, retained |
| 2.3 | met | strengthened — marker/label identity now directly asserted |
| 3.1 | met | both sentences, both locales, real render; preview surface covered in a real browser (split) and in jsdom (both) |
| 3.2 | met | both keys retained, no locale file touched |
| 3.3 | met | skip block still first, *N numbering untouched (overviewPdf.ts:834-869) |
| 4.1 | not met | no measured layout assertion. Accepted as a tracked follow-up, not waived — see #1980 AC 1 |
On AC 4.1: I flagged this as non-blocking MEDIUM in round 1 and said I would accept a bounded version. It was not addressed, so rather than let "approved with follow-ups" absorb it, it is now criterion 1 of #1980 (tech-debt, Should Have, Backlog) together with the three residual assertion gaps and the missing deposit-reduced dedup case. The residual gaps are each covered transitively today — the array length is pinned and overviewPdf.ts's verbatim append is pinned by its own case, so a duplicate or a deletion cannot reach the PDF without failing something — which is why they are follow-ups rather than blockers.
MUST FIX before merge (not verdict-blocking, both one-liners)
M1 — the separator that finding 1 just fixed is unguarded. ReportContentEditor.test.tsx:954-961 asserts getByText('partial:') and getByText(/Amount shown…/) as two independent matches, and the E2E asserts the sentence against main.textContent() — where partial:Amount and partial: Amount are indistinguishable. Re-removing the space regresses silently, which is the same shape of gap as finding 1 itself. Assert the joined string on the <li>:
const items = screen.getAllByRole('listitem');
expect(items[0]).toHaveTextContent('partial: Amount shown reflects only the portion allocated to this source.');
expect(items[1]).toHaveTextContent('less deposit: This position reflects deposits claimed separately.');toHaveTextContent collapses runs of whitespace but never inserts any, so a missing space fails the match. The collapse also converts the marker's U+00A0 to a plain space — type the expected string with a plain space, which incidentally makes the /^less\sdeposit:$/ workaround at :961 unnecessary. Routes to qa-integration-tester.
M2 — two stale statements in the E2E spec now assert the opposite of the shipped behaviour. The file docstring and the in-body comments were updated; these two were not:
reportWizardEditableContent.spec.ts:1643-1645(section banner): "Every split invoice carries its own inline(partial)label and there is no footnote list at all":1649-1650(thetest()title): "…with no †/‡ marker and no footnote list anywhere on the page"
The body now asserts footnotesBlock count 1. The title is the worse of the two because it is what appears in CI output and the Playwright report — shard 2's log line above literally advertises "no footnote list anywhere on the page" for a test proving one exists. This is the same class of problem as the page-object comment the architect flagged, and leaving it invites a future author to "fix" the assertions back to 0 — re-breaking the exact thing #1965 exists to repair. Routes to e2e-test-engineer.
Scope
Clean across both rounds. Producer-only, additive, no drive-by production changes. The E2E inversion is required by the behaviour change and stays within it. Wiki submodule bump (ADR-034 legend correction) and agent-memory updates are expected per CLAUDE.md. #1965 is correctly In Progress on the board.
One process note: the PR body's Test plan still describes only the round-1 state (buildReportContent.test.ts / realRender.test.ts); it does not mention the JSX separator fix or the E2E inversion. Worth a refresh before merge so the squash body reflects what shipped, but purely cosmetic.
…POM comments - Add toHaveTextContent parity guard on footnote <li> to detect missing space - Update ReportWizardPage POM: remove stale "never populate" directives, document that footnotesBlock/footnoteItems are now populated for split/depositReduced rows - Correct Scenario 18 test title and section banner to reflect one legend entry Co-Authored-By: Claude qa-integration-tester <noreply@anthropic.com> Co-Authored-By: Claude e2e-test-engineer <noreply@anthropic.com>
|
[product-architect] Final re-review — APPROVED All three blocking sites from my previous review are correctly fixed in 1. 2. I cross-checked the DOM-absence claim against the producer: 3. M1 parity guard — verified adequate. Architecture/contract checks: no schema, API-contract, or shared-type surface touched; ADR-034's B4 rule and legend addendum plus the Deviation Log entry are on the wiki submodule ref carried by this branch; Non-blocking follow-up (medium — docstring structure, no functional impact): The new
The information is all correct and present — only the attribution is misleading. Fix by moving the Note: VERDICT: APPROVED |
|
🎉 This PR is included in version 2.13.1-beta.3 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
|
🎉 This PR is included in version 2.14.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
Summary
buildReportContent.ts— the only missing piece was pushing entries to the already-declaredfootnotes[]arrayseparatelyis the load-bearing word for bank auditors)content.footnotes— no other files needed changingFixes #1965
Test plan
buildReportContent.test.ts: 64 tests pass including 6 new AC 1.1–1.5 scenariosrealRender.test.ts: 70 tests pass; deposit-reduced legend sentence now asserted present🤖 Generated with Claude Code