The outcome leads the renewal page

Item 66 is a claim about what a PM sees WITHOUT scrolling, so the comparison sections are viewport crops — the assertion haystack follows the crop, which is what makes a found string a proof rather than a decoration. 1440x780 is a 1440x900 laptop screen minus the browser's own chrome: the viewport a PM actually gets, not the display they bought. The BEFORE comes from a second dev server pinned to commit fa698b9437.

30 Aug 2026 · branch fix/renewals-review-nits-6631 · captured against propflow-stage · at 81fd035457

Data note. Every name and balance below comes from propflow-stage, which is anonymized by construction (ADR-0097/0110 — phones in the impossible +1000 NPA, emails @example.test). The identical capture against prod would carry real tenants' names and balances and is not safe to attach anywhere, which is why the generator refuses to run against one.

1 · BEFORE — the fold, on a renewal that is already done

A renewal that is finished — the tenant accepted and signed in the resident portal — captured from a second dev server pinned to fa698b9437. That is the last commit to touch this page before this change; everything between it and the origin/main tip this branch departed from is confined to resilience.ts, topic-labels.ts and tests, so this frame is what main rendered for this route before #6631. It is a commit rather than a branch, so it stays a BEFORE now that #6631 has landed.

This is one screen: the headline, the status pill, and the progress card. The outcome is not on it. That is not prose — it is the capture tool's own refusal. Point this section at the AFTER section's assertion list and the run aborts (route elided, tail kept):

section 1 (/leasing/renewals/lease_547ae6f7…): 1 assertion(s) are in the page but OUTSIDE the screenshot — "Lease signed in resident portal". This section is `fullPage: false`, so the image is cropped to the viewport and a reader cannot see these. Scroll them into view with an action, set `fullPage: true`, or drop the assertion — do not publish a claim the picture does not show.

A separate run — the one that trimmed this section's list down to the two strings asserted below — reported Approved, a field of the progress card's own Run row, as outside the frame as well. (Two runs, not one: evaluateAssertions emits a single off-frame line per section listing every off-frame string, and Approved is not in the AFTER list quoted above.) So the fold lands inside the card that sits above the answer.

#6463 had already hoisted the Resolution section above the other three phase sections, which is why the tracker row reads half-done. Above the earlier phases is not above the fold: the progress card is the tallest thing on this page and it sat between the header and the answer. The header's Countersign / Needs your review anchor was the only route there, and an anchor is a promise that the answer is somewhere else.

Asserted in the captured DOMRenewal progress · Run. Two strings, because two is what survives the crop — that is the finding, not a shortcut. The absence of the outcome is what this section is for and this tool checks strings that are PRESENT, so the absence is carried by the picture and by the quoted refusal above, which is the machine making the same claim.

The renewals detail page on main at a 1440x780 laptop viewport: header, status pill, and a progress card that fills the rest of the screen. No resolution rows are visible.
Provenance. Captured from commit fa698b9437, read from the worktree the server was started from (/Users/miniclaw/code/PropFlow/wt-renewals-before) — the server could not report its own commit, so this is the weaker of the two sources. That commit is already merged into origin/main.

2 · AFTER — the same fold, same renewal, same width

Same renewal, same crop, this branch. The outcome is the first card under the header: the LATEST eyebrow, the Resolution heading with its rolled-up status chip, and the rows themselves — Tenant accepted the offer and Lease signed in resident portal, dated. The progress card follows it, still fully on screen.

The section moved; nothing was summarised. That distinction is the design. This page's one rule is that every fact has exactly one author, and a summary card above the rail would be a second place saying what happened, free to drift from the rows below it. Moving the section moves the rows, so there is still exactly one of each — and no new primitive, on a page that just had four bespoke ones deleted (#6617). This is Card + SummaryCardHeader + the step rows the section already rendered, in a different slot.

The page now reads what happened → how far it got → how it got there. The eyebrow stays the word LATEST rather than becoming "Phase 1": the ordinals are positional, and numbering the outcome first would tell the PM it happened first.

Asserted in the captured DOMLATEST · Resolution · Tenant accepted the offer · Lease signed in resident portal · Renewal progress. This is the item-66 proof, and it only means anything because the section is `fullPage: false`: the haystack for these strings is the VIEWPORT text, so "Lease signed in resident portal" being FOUND is exactly the claim "a PM reads the outcome without scrolling". The identical string is reported OUTSIDE the frame on the BEFORE section above. A full-page capture could not have separated the two. "Tenant accepted the offer" and "Lease signed in resident portal" are authored by one branch of `buildTimeline` and appear nowhere else on the page; `Renewal progress` is asserted to show the progress card did not get pushed off in exchange.

The same renewal on this branch at 1440x780: the Resolution card, labelled LATEST, sits directly under the header with both outcome rows visible, and the progress card below it.

3 · AFTER — when the outcome is an ACTION, not a receipt

The other half of "what happened": a renewal Clara could not finish on her own. Same crop, same branch.

Here the hoist is worth more than it is on a signed renewal, because the outcome is something the PM has to do something about. Needs your attention and the reason underneath it are the first thing on the page instead of the last card in the column. The header's Needs your review anchor still points at the same section; it is no longer the only way to reach it.

Asserted in the captured DOMLATEST · Resolution · Needs your attention · Renewal progress. `Needs your attention` is deliberately NOT the discriminator here — the same words also render inside the progress card's own callout on this renewal, so on its own it would pass whether or not the Resolution section moved. `LATEST` + `Resolution` are the strings only the hoisted section can produce, and they are what this section actually rests on.

A renewal that needs the PM's attention, on this branch: the Resolution card leads the page with a Needs your attention row and its reason.

4 · AFTER — the whole column, so the new order is legible

The same finished renewal, full page, so the reordering can be read end to end: Resolution (LATEST), then Renewal progress, then PHASE 1 Policy & Approval, PHASE 2 the PMS preparation, PHASE 3 Tenant Outreach. The offer summary keeps the standard right rail #6617 gave it.

Note what did not change: the remaining sections keep the 1..n they had, the outcome section is not renumbered into the sequence, and the phase cards are the same cards in the same order relative to each other. Only the outcome and the progress card swapped places.

Asserted in the captured DOMLATEST · Resolution · Renewal progress · PHASE 1 · PHASE 2 · Renewal offer summary. Full-page here on purpose — this section is a claim about the ORDER of the whole column, not about the fold, so the document is the right haystack. The eyebrows are asserted in the CSS-uppercased casing the DOM's innerText carries.

The full renewals detail page on this branch: Resolution first, then Renewal progress, then Phase 1, 2 and 3, with the offer summary in the right rail.

Item 67 has no picture here, and why

The second half of this PR rewords one status label in the shared derivation: Tenant signed becomes Tenant signed — pending your countersignature, and the h1 shortens to <name> signed the renewal so the pill — which DetailPage renders inside the h1 — is not a second sentence about the same handoff.

There is no capture of it, and I am not going to imply otherwise. That label renders only in the awaiting_countersign state, which is the transient window between the tenant's signature and the PM's countersignature. No renewal in the anonymized stage mirror is in it right now (checked through loadRenewals: tenantSignedAwaitingCountersign is false on all 79 rows), and none is in prod either. Manufacturing a row to photograph would make the picture the least trustworthy thing in this artifact.

What carries it instead is a DOM assertion that reads the badge element, not the page text: container.querySelector('h1 span.rounded-full') — the one pill the structured header's accessory slot renders — asserted equal to the exact label. That distinction is load-bearing. The h1, the resolution row and the header action all legitimately mention the signature, so a page-wide toContain('Tenant signed') would pass on a neighbour's text while the pill had quietly reverted. The same test then strips the pill's text out of the h1 and asserts the remainder says signed the renewal and does not match /countersign/i, which is the no-echo claim. Both were run as positive controls: reverting the label reddens 5 tests, restoring the old h1 reddens 2.

What these captures do not prove. The BEFORE section's absence — "the outcome is not on this screen" — is an absence, and this tool asserts strings that are present. It is carried by the picture and by the tool's own refusal: point the AFTER assertion list at the BEFORE section and the run aborts with "assertion(s) are in the page but OUTSIDE the screenshot" — quoted verbatim on section 1 — which is the machine saying the same thing. And a note on the viewport: at a bare 1440×900, with no browser chrome subtracted, the BEFORE's resolution rows scrape into the last two hundred pixels of the frame. The sections above are shot at 1440×780 because that is the viewport a maximised browser leaves on a 1440×900 laptop, and it is the honest number to judge a fold by — but the smaller claim is the true one either way: on main the outcome is the fifth thing on the page, after the whole progress card; on this branch it is the first.

PropFlow Docs