PR #6615 took the orb off the tenant page's zero work-order state and left unit detail behind. Same empty state, two treatments, one page apart. This closes it.
30 Aug 2026 · branch fix/unit-detail-zero-work-orders · captured against propflow-stage · at 72484077ac
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.
Captured from a second dev server running origin/main, so this is the state that shipped rather than a description of it. Look at the Work Orders card in the right rail.
The header already says Work Orders (0). Below it, ClaraEmptyState spends a 64px resting Clara orb and a py-12 centred column restating that zero in art, plus a second line — “Clara hasn't logged any issues here.” — that adds nothing the count did not.
This is exactly what Gera ruled on for the tenant page five days of commits ago: “for work orders, we don't need to show that like orb… If we have zero work orders, it could be kind of collapsed and just shows zero.” PR #6615 acted on it there and not here, which is what made this a consistency defect rather than a taste question — the two pages disagreed about the same empty state, and the disagreement was ours.
Asserted in the captured DOM — Work Orders (0) · No work orders for this unit. · Clara hasn't logged any issues here · Current Tenant. The second line is asserted on the BEFORE specifically. It is the string the AFTER frame asserts the ABSENCE of, so pinning it here is what makes that negative a real removal rather than a page that failed to render. “Current Tenant” is the rail's other card — present on both frames, so a blank capture cannot pass either one.
The same route on the branch, against the same record. The card is now a heading and one muted line: the count states the zero, the line names which surface is empty. Nothing else.
It is not a new idiom — that was the whole point. The line renders through EmptySectionNote, a new export of pms-card-primitives, and so do the two places that already collapsed: the tenant page's work-order card (PR #6615) and RecordsTableSection, which draws every empty AppFolio table on tenant detail. Three call sites, one component. Before this the same <p> was written out twice, which is how a third page ends up inventing a fourth treatment.
The orb component is not going anywhere. ClaraEmptyState is still right where the emptiness IS the view — the vendors list, the tenants list, the conversation list, the tours calendar. What it is wrong for is a small card section sitting under a header that already printed the count, where the art repeats what the reader just read. This removes one call site.
Asserted in the captured DOM — Work Orders (0) · No work orders for this unit. · Current Tenant. Same three strings the BEFORE carries, minus the one that was removed. The screenshot is what shows the orb is gone; the assertion that CANNOT be written here is a negative one, so the test suite carries it instead — `UnitDetailClient.zero-work-orders.test.tsx` asserts `.clara-orb-root` and `[class*="py-12"]` are absent from the card's DOM, and both were positive-controlled by re-adding the orb and watching them redden.
The counterpart frame, and the reason it is not optional: “collapsed and just shows zero” is a claim about one branch, and a change that quietly emptied the card for everybody would pass every assertion in the two frames above.
Unit 107 of the same property carries two work orders. The card renders them exactly as it did before — the title, the status badge, the category and date line, the bordered rows linking out to each work order. The populated branch of this file is byte-identical to origin/main; the diff touches only the length === 0 arm.
The unit test carries the same pairing, and goes one step further than text: it asserts the row is a real <a> pointing at the work order, so a regression that printed the title as a muted line would still redden.
Asserted in the captured DOM — Work Orders (2) · Work order (AppFolio) · Current Tenant. “Work Orders (2)” is the load-bearing one — it is the header on the populated branch, and it cannot appear on a card that collapsed for everybody. The absence of “No work orders for this unit.” on this frame is the mirror of its presence on the two above.
The loading ghost. UnitDetailLoading draws four skeleton work-order rows and keeps drawing them. A ghost cannot know the count it is standing in for, so it guesses the POPULATED shape — which is the only shape it can guess, and which this change does not move. #6615 had to touch its ghost because it added a Field that renders unconditionally; there is no equivalent here.
Everything else on the unit page. The rail's Current Tenant card, the signal timeline, the status banner, the header — all untouched. In particular the Work Orders card still titles itself with a plain h3 rather than SummaryCardHeader, which is live drift from the tenant page. Flagged rather than silently fixed: the ask was one empty state, and a “while I'm in here” restyle of a card nobody reviewed is how a one-file fix becomes a page redesign.
Four other surfaces still orb an empty state, and all four are correct. The tenants list, the vendors list, ConversationList, the tours calendar, the building calendar and TableEmptyState all render ClaraEmptyState. Every one of them is a full-bleed list or table where the emptiness is the entire view and there is no header count already saying zero — which is the distinction this change is drawn on, and the reason none of them were touched.