Board row ui-s-d (S-D · The consumer sweep): captured on three surfaces. The hard-load half of the bar is met. The soft-switch half is NOT met on any of the three — and the way it fails is not the same on each, which is why this took two instruments to state honestly.
17 Sept 2026 · branch ui-s-d-selection-capture · captured against propflow-stage · at dfdef4381b
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.
This section exists so the ones after it can fail. Every figure below belongs to JPCO: Inquiries 83 / 29 still at this stage, Tours 40 / 2 upcoming, Applications 23 / 4 awaiting review, and the pipeline header counting 83 prospects. The other company in this artifact renders 53 / 17 still at this stage, 34 / none upcoming and 0 / 0 awaiting review in those same places.
That the two are genuinely different was not assumed — it was executed. A throwaway one-section spec pointing at this same JPCO route while asserting the other company's four strings was run before this artifact was built, and the generator aborted naming all four: 53 prospects, 17 still at this stage, 0 awaiting review, none upcoming. None of them is satisfiable by JPCO's page, which is what makes the identical assertions in sections 3, 4 and 5 evidence rather than decoration.
One trap worth recording: /api/leasing/stats reports activeLeadsInWindow: 53 for both companies. An assertion on a bare 53 would have passed on either page and proved nothing. Every string asserted here is label-bearing for that reason.
Asserted in the captured DOM — JPCO · 83 prospects · 29 still at this stage · 4 awaiting review · 2 upcoming. JPCO's compartments and pipeline count. The four Fairhaven strings were separately proven absent from this page by a deliberate failing run.
A cold navigation — a real document load, server-rendered from scratch — at Fairhaven Residential (TEST)'s address. Not one of JPCO's figures survives: the strip reads 53 / 17 / 34 / none upcoming / 0 / 0 awaiting review, and the pipeline counts 53.
This is the hard half of the row's bar, and it lands on the first paint: the selection is the read scope on the SSR seed, not a portfolio-wide render that re-filters after hydration. Here the switcher trigger also names the right company — worth noting, because section 3 is where that stops being true.
Asserted in the captured DOM — Fairhaven Residential (TEST) · 53 prospects · 17 still at this stage · 0 awaiting review · none upcoming. Fairhaven's four compartments and its pipeline count, reached by a fresh document load. All four were proven absent from JPCO's page.
A fresh tab — its own browser context (newContext: true), so no other section's state can leak into it — loaded at section 1's JPCO address and then driven through the picker: open [data-org-scope-trigger], tick Fairhaven Residential (TEST), untick JPCO, close. Closing is what commits — OrgScopeSwitcher's close is setOpen(false); commit(), and commit is a client-side router.push. No document load happens between this tab's own JPCO first paint and the state photographed here.
The figures move. All four of JPCO's numbers are replaced by Fairhaven's — 53, 17 still at this stage, 0 awaiting review, none upcoming — and the property column fills with Fairhaven's buildings. Read on its own, that is the data layer doing the right thing.
The requirement is still not met, and this section is the evidence of that, not evidence against it. The bar this row sets is that the rendered page shows the selected company's numbers — the name and the figures belonging to one company. Look at the top-left: it reads JPCO, beside a page that is entirely Fairhaven's. A page that names one company while counting another does not show the selected company's numbers; it shows two companies at once and lets the reader pick. So: captured, mismatch observed, soft-switch requirement NOT met. An earlier draft of this artifact marked this section as satisfying the clause. That was wrong and is withdrawn — recording a defect and satisfying an acceptance are different acts.
It is not a slow frame. Instrumented runs sampled the trigger every 250 ms for 22.5 seconds after the commit, twice: the URL became Fairhaven's at ~3 s and ~13 s respectively, the numbers followed at ~8 s and ~18 s, the propflow-selection cookie was written to Fairhaven — and the trigger read "JPCO" in 90 of 90 samples. It never catches up. A hard reload (section 2) clears it.
Where it comes from — read on one side, inferred on the other. Read: selection-provider.tsx's commit() calls setProposal(null) before router.push, and draft is proposal === null ? selection : deriveSelection(...) — so the moment the proposal is cleared, draft falls back to the selection prop, which (workspace)/layout.tsx minted at the last document load. OrgScopeSwitcher derives its label from that same draft. Inferred, not read: that a searchParams-only router.push re-renders the page segment while leaving the layout segment — and therefore SelectionProvider's selection prop — untouched. What the sampling establishes without needing that inference is the observable split itself: the page segment ends up showing the new selection and the layout segment never does, and only a document load reconciles them. Stated as a hypothesis; no product code was changed to test it.
Why it matters beyond tidiness is written in the component's own source — the label is the one control whose entire job is to state that scope
, and a wrong one is a true-looking sentence about other people's data
. A viewer who switches company and glances at the corner is told they are still in the previous one.
Asserted in the captured DOM — 53 prospects · 17 still at this stage · 0 awaiting review · none upcoming · JPCO. The first four are Fairhaven's figures, present after an in-app switch with no page load — all four proven absent from JPCO's page. The fifth, "JPCO", is asserted because it should NOT be here: it is the previous company's name, still on screen beside another company's figures. It is pinned so this artifact stops generating the day the defect is fixed. Asserting it is a record of the mismatch, NOT a pass. The falsifier that was executed ran on this route: JPCO's prospects page asserting these same four Fairhaven strings, and it aborted naming all four. The pin in the other direction — that "JPCO" would be absent from a correctly rendered Fairhaven page — was not separately executed.
The strictest reading of a fresh page load at that selection
. The URL is bare — /leasing/prospects, no ?org=, no ?prop= — and the only thing naming a company is the stored propflow-selection value staged on this section's own browser context. requestProposal falls to the cookie precisely when the address says nothing at all, and the page renders Fairhaven's figures off it.
This rules out the weakest reading of section 2 — that the page merely echoes its own query string — and it is the shape ADR-0137 is moving toward (the selection as a stored per-user setting rather than a URL parameter), photographed at the stage the code is actually at today. The value staged here is the same one the soft switch in section 3 wrote for itself.
Asserted in the captured DOM — Fairhaven Residential (TEST) · 53 prospects · 17 still at this stage · 0 awaiting review · none upcoming. A bare URL. The company is named only by the stored selection, and the rendered figures are Fairhaven's.
The same hard load at the width most of this actually gets read on. The strip stacks and the figures are the same figures: 53 / 17 still at this stage, 34 / none upcoming, 0 / 0 awaiting review.
The assertions change here and the reason is a real constraint rather than a preference. At 390 px the pipeline header's 53 prospects span is hidden — an earlier run of this very spec failed on it, with the generator reporting the locator resolving to a hidden element 34 times. Asserting it anyway would have published checked ✓
beside a picture that does not contain it. The three strings below are the ones a 390 px viewport genuinely shows, and each differs from JPCO's (29 still at this stage, 2 upcoming, 4 awaiting review).
Asserted in the captured DOM — 17 still at this stage · none upcoming · 0 awaiting review. The three strip compartments that are visible inside a 390×844 fold. The pipeline count is hidden at this width and is deliberately not asserted.
The same switch on the phone tier, where the rail is a drawer: open it with [data-pf-nav-trigger], use the same picker, commit by closing it, then close the drawer before the shot. That last step is not cosmetic. The frame-text check asks whether an element's rectangle is inside the viewport, not whether something is painted on top of it — a strip photographed behind an open drawer overlay would still count as in-frame, and the artifact would claim numbers the reader cannot see.
The figures are Fairhaven's after an in-app switch with no page load, exactly as on the desktop tier. But be precise about what this section can prove: at 390 px the company label lives inside the drawer, and the drawer is closed in this shot — so there is no company name in this frame to agree or disagree with the numbers. This section evidences that the figures follow a soft switch at phone width. It is silent on the name/number agreement the row actually asks for, and it must not be read as the phone tier passing where the desktop tier fails.
The one identity signal that is in this frame is the property column, which reads FHN on every row — Fairhaven's ticker, not JPCO's. That corroborates the figures; it is not the company label, which is the control the row's bar is about.
Asserted in the captured DOM — 17 still at this stage · none upcoming · 0 awaiting review. Fairhaven's three phone-visible compartments, after committing the switch in the drawer's picker and closing the drawer. JPCO's page reads 29 / 2 upcoming / 4 awaiting review in these places.
The row's bar names the dashboard as well as the leasing page, and within it the metric shelf, the pipeline counts and the conversations list. This section is the dashboard's control, the same job section 1 does for /leasing/prospects: every figure here belongs to JPCO, and each one is label-bearing rather than a bare number.
The contrast is wide enough that no assertion here is satisfiable by the other company. Occupancy 87.9% on 204 of 232 occupied against Fairhaven's 0.0% on 0 of 14 occupied; monthly revenue $341,012 against an em-dash and No rent recorded in view yet
; 22 open work orders against 0; $32,604 total past due · 17.8% of tenants past due against $0 · 0%.
One vacuity trap found here and avoided, the same shape as the 53 trap in section 1: the LEADS BY SOURCE card reads 53 in last 30 days
for both companies. Nothing in this artifact asserts it.
Asserted in the captured DOM — JPCO · 204 of 232 occupied · 28 vacant · 1 on notice · 13 of 45 decided have renewed or transferred · total past due · 17.8% of tenants past due. JPCO's metric shelf and its pipeline counts. Fairhaven renders 0 of 14 occupied, 14 vacant · 0 on notice, no renewal decisions this cycle, and $0 / 0% past due in these same places.
A cold navigation at Fairhaven's address. The whole shelf turns over: occupancy 0.0% on 0 of 14 occupied, the leasing pipeline 14 available · 14 vacant · 0 on notice, the renewals card No decisions yet this cycle
, collections $0 total past due · 0% of tenants past due.
And the rail names Fairhaven. That is the half of the bar this section carries and section 9 does not: on a hard load the company's name and the company's figures agree. Hard-load requirement met on the dashboard.
Note also what an empty company proves that a busy one cannot: a shelf that rendered JPCO's numbers under Fairhaven's name would be obvious here, because Fairhaven's correct answer to almost every card is zero or an em-dash. There is nowhere for a stale figure to hide.
Asserted in the captured DOM — Fairhaven Residential (TEST) · 0 of 14 occupied · 14 vacant · 0 on notice · No decisions yet this cycle · total past due · 0% of tenants past due. Fairhaven's metric shelf and pipeline counts on a fresh document load, plus the rail naming Fairhaven. All five are absent from JPCO's dashboard.
A fresh tab at JPCO's dashboard, driven through the same picker as section 3 — tick the other company, untick JPCO, close to commit. Then wait 70 seconds and photograph it.
Nothing happens. Not the figures, not the label. Occupancy still reads 87.9% on 204 of 232 occupied, collections still $32,604, the rail still JPCO. This section asserts the same five strings section 7 asserts on a plain JPCO page, because after the switch it is a plain JPCO page.
The switch did commit — that is the part a screenshot cannot show, so it was instrumented. Driving the same sequence under a sampler, every 3 seconds for 120 seconds (40 samples): the address became the other company's at ~3 s and stayed there for all 40; the rendered figures were JPCO's in 40 of 40; the label read "JPCO" in 40 of 40; and the propflow-selection cookie was never written — it still said JPCO at 120 seconds. So the URL is the only thing in the browser that knows a switch happened.
This is worse than the defect section 3 records, and it is a different one. On /leasing/prospects the figures do follow — only the name lags. Here nothing follows. A reader who switches company on the dashboard is shown the previous company's occupancy, revenue, maintenance backlog and past-due balances, under the previous company's name, with no visible cue at all that the page is stale. An earlier draft of this artifact asserted the other company's figures here and described the shelf 'turning over'. That was never observed; it was inferred from section 8's hard load. It is withdrawn.
Asserted in the captured DOM — 204 of 232 occupied · 28 vacant · 1 on notice · 13 of 45 decided have renewed or transferred · total past due · 17.8% of tenants past due · JPCO. These are JPCO's dashboard figures and JPCO's label — the SAME five strings section 7 asserts on a plain JPCO hard load. They are asserted here because after a committed switch to the other company they are all still on screen. A passing section is therefore a record that nothing changed, NOT a pass. The picker actions would abort this run if the listbox never opened, so a section that reaches the shot is one where the control really was driven.
The third surface the row's bar names. JPCO's list is populated and its header counts 100 of 385 — a page of a hundred out of three hundred and eighty-five in scope.
This section is shot at the fold (fullPage: false) rather than the full scroll height, and the assertions are correspondingly few. That is deliberate: the frame-text check is scoped to what the screenshot shows, so a long list captured full-page would let an assertion pass on a row far below anything a reader sees. The count in the header is the claim, and it is in the frame.
Every person shown is anonymized by construction — the +1 (000) numbers are the sanctioned impossible-NPA convention (ADR-0097/0110), which is why the contact scan passes on a page that is nothing but a list of contacts.
Asserted in the captured DOM — JPCO · 100 of 385. JPCO's conversation count and the rail naming JPCO. Fairhaven's list reads 0 of 285 and renders no rows.
A cold navigation at Fairhaven's address. The list is empty — No conversations found.
— and the header reads 0 of 285 where JPCO's reads 100 of 385. The rail names Fairhaven. Hard-load requirement met on the conversations list.
An empty list is a stronger control than a full one here. If the list were leaking across companies, JPCO's hundred rows would be sitting in this frame; instead there are none, and the count agrees with them.
One thing this capture records without explaining, because diagnosing it is not this lane's job: the denominators differ (385 versus 285), so the second number is scoped, but Fairhaven's page pairs a scoped denominator of 285 with zero rows and a zero numerator. Whether 285 is the right denominator for a company with no conversations in view is a question this artifact raises and does not answer.
Asserted in the captured DOM — Fairhaven Residential (TEST) · 0 of 285 · No conversations found.. Fairhaven's empty list and its count, plus the rail naming Fairhaven. JPCO's page reads 100 of 385 and renders rows.
The same switch on the conversations list. The hundred rows do not clear, the header still reads 100 of 385, the rail still reads JPCO — the other company's empty list (No conversations found.
, section 11) never appears.
Instrumented the same way, every 3 seconds for 120 seconds (40 samples): the address became the other company's at ~3 s, JPCO's count was still rendered in 40 of 40, and the label read "JPCO" in 40 of 40. One difference from the dashboard is worth recording, because it rules out the simplest explanation: here the propflow-selection cookie was written to the other company, at ~3 s. So the selection genuinely committed and was persisted — and the list still did not follow it. On the dashboard the cookie was never written at all. Same visible outcome, two different states underneath.
An earlier draft described the rows clearing and the header falling to the other company's count. That was never observed either, and is withdrawn.
Asserted in the captured DOM — 100 of 385 · JPCO. JPCO's conversation count and JPCO's label — the same two strings section 10 asserts on a plain JPCO hard load, still on screen after a committed switch to the other company. A record that nothing changed, NOT a pass.
The bar. Board row ui-s-d asks that the rendered page show the selected company's numbers after a soft switch and after a hard load, proven by capture at both. The name and the figures have to belong to the same company.
Hard load — MET. Sections 2, 4, 8 and 11. A fresh document load at a company's selection renders that company's figures under that company's name on /leasing/prospects, /dashboard and /conversations at desktop width — and, in section 4, even when the address names no company at all and only the stored propflow-selection cookie does.
Section 5 is deliberately not in that list. It is the hard load at 390 px, and it asserts three figures and no company name, because at that width the label lives in a closed drawer. It evidences that the figures are right on a phone; it says nothing about name/number agreement — the same limit section 6 states for the soft switch.
Soft switch — NOT MET, on all three surfaces. But not in the same way, and that distinction is the most useful thing here.
| after a committed switch | address | propflow-selection | figures follow | company name follows |
|---|---|---|---|---|
/leasing/prospects (§3) | yes, ~3–13 s | written | yes, ~8–18 s | no — 90 of 90 samples |
/dashboard (§9) | yes, ~3 s | never written | no — 40 of 40 | no — 40 of 40 |
/conversations (§12) | yes, ~3 s | written, ~3 s | no — 40 of 40 | no — 40 of 40 |
Defect one — the company label never follows a soft switch, on any surface. The argument that this is a single bug rather than three is from source rather than from these captures: OrgScopeSwitcher renders in (workspace)/layout.tsx and derives its label from draft; commit() calls setProposal(null) before it pushes, and draft is proposal === null ? selection : deriveSelection(...), so it falls back to the selection prop the layout minted at the last document load. Nothing in that path mentions a page. One component, one page-independent mechanism.
Defect two — on /dashboard and /conversations the page body does not follow either. This one is not shared: /leasing/prospects refetches and the other two do not, so it is per-surface and has to be established per surface, which is what sections 9 and 12 do. It is also the more serious of the two. A reader who switches company on the dashboard is shown the previous company's occupancy, revenue, maintenance backlog and past-due balances under the previous company's name, with nothing on screen to say the page is stale — only the address bar disagrees. The cookie split (never written on the dashboard, written on conversations) says these two are not even the same state underneath, so it is offered as an observation rather than a diagnosis.
No product code was changed. This is a capture lane. Sections 3, 9 and 12 assert the stale values on purpose, so this artifact stops generating the day either defect is fixed.
The assertions can fail. A throwaway one-section spec pointing at JPCO's prospects page while asserting the other company's four leasing strings was executed before this artifact was built, and the generator aborted naming all four. That run covered the prospects route only; the dashboard and conversations sections rest on the captured contrast in sections 7, 8, 10 and 11 rather than on a falsifier run. Two vacuity traps were found and avoided: /api/leasing/stats reports activeLeadsInWindow: 53 for both companies, and the dashboard's LEADS BY SOURCE card reads 53 in last 30 days
for both. Nothing here asserts a bare number.
What this does not touch. This addresses the row's capture clause and does not close it — the clause closes when these defects are fixed and this spec re-runs unchanged. Two further clauses are open regardless: the acceptance record (eight of thirteen merged references carry no query shape, keys or payload) and an unruled dependency on the contract row's pre-merge gate. Neither is fixable by a capture. Three surfaces are also not a sweep of every consumer of the selection, and the screenshots are not pixel-diffed — the gate is on rendered text, so a layout that drifted while keeping its labels would still publish.
Provenance. Captured against this branch's own dev server on its own port, whose /api/health reported table: propflow-stage — anonymized by construction (ADR-0097/0110) and on target-guard.ts's allowlist, not a !/prod/ check. The identity is smoke@propflowai.co, an active platform_admin: fleet grants are what put more than one company in the picker, and a single-grant viewer gets a plain label with no panel to open. The contact scan over every captured page's rendered text was clean — but read its scope exactly: it classifies reachable email and phone only, so that means no reachable contact was rendered, not that no real person appears. For names and figures the stage allowlist is the only defence.