Onboarding Overview: the loading skeleton matches the page

Before and after on stage, using a synthetic company with no email setup chosen yet, so its page has no inbox row. The skeleton is shown with the checklist read held open.

5 Oct 2026 · branch fix/onboarding-hub-overview-ghost-parity · captured against propflow-stage · at b159edabd6f+local

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 (main): skeleton, desktop, light

Main, with the checklist read held open so the page sits in its loading state. The skeleton draws every possible row. That includes Connect your shared leasing inbox and the leasing sign-offs, which this company does not get because it has no email setup chosen yet. It also draws a full Propflow is doing card. When the read lands, those rows disappear and every card below moves up.

Asserted in the captured DOM — Before Clara goes live · Connect your shared leasing inbox · Choose which buildings Clara works in · Choosing the address Clara writes from. The inbox row and a Propflow line are in the skeleton, so it draws rows this company's page does not have.

Before (main): skeleton, desktop, light
Provenance. Captured from commit 79870eadc0f, read from the worktree the server was started from (/Users/miniclaw/code/PropFlow/wt-ghost-main) — 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.
Sections 2–12 and notes

2 · Before (main): skeleton, desktop, dark

Main, with the checklist read held open so the page sits in its loading state. The skeleton draws every possible row. That includes Connect your shared leasing inbox and the leasing sign-offs, which this company does not get because it has no email setup chosen yet. It also draws a full Propflow is doing card. When the read lands, those rows disappear and every card below moves up.

Asserted in the captured DOM — Before Clara goes live · Connect your shared leasing inbox · Choose which buildings Clara works in · Choosing the address Clara writes from. The inbox row and a Propflow line are in the skeleton, so it draws rows this company's page does not have.

Before (main): skeleton, desktop, dark
Provenance. Captured from commit 79870eadc0f, read from the worktree the server was started from (/Users/miniclaw/code/PropFlow/wt-ghost-main) — 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.

3 · Before (main): skeleton, phone, light

Main, with the checklist read held open so the page sits in its loading state. The skeleton draws every possible row. That includes Connect your shared leasing inbox and the leasing sign-offs, which this company does not get because it has no email setup chosen yet. It also draws a full Propflow is doing card. When the read lands, those rows disappear and every card below moves up.

Asserted in the captured DOM — Before Clara goes live · Connect your shared leasing inbox · Choose which buildings Clara works in · Choosing the address Clara writes from. The inbox row and a Propflow line are in the skeleton, so it draws rows this company's page does not have.

Before (main): skeleton, phone, light
Provenance. Captured from commit 79870eadc0f, read from the worktree the server was started from (/Users/miniclaw/code/PropFlow/wt-ghost-main) — 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.

4 · Before (main): skeleton, phone, dark

Main, with the checklist read held open so the page sits in its loading state. The skeleton draws every possible row. That includes Connect your shared leasing inbox and the leasing sign-offs, which this company does not get because it has no email setup chosen yet. It also draws a full Propflow is doing card. When the read lands, those rows disappear and every card below moves up.

Asserted in the captured DOM — Before Clara goes live · Connect your shared leasing inbox · Choose which buildings Clara works in · Choosing the address Clara writes from. The inbox row and a Propflow line are in the skeleton, so it draws rows this company's page does not have.

Before (main): skeleton, phone, dark
Provenance. Captured from commit 79870eadc0f, read from the worktree the server was started from (/Users/miniclaw/code/PropFlow/wt-ghost-main) — 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.

5 · After (this PR): skeleton, desktop, light

This branch, with the same read held open. The skeleton draws only the rows every company gets (admin account, team, billing, buildings, team briefed, try Clara) and the questions, under the same four headings in the same order. Nothing in it can disappear when the read lands. Rows that depend on the company (inbox, calendar, the leasing sign-offs, residents told) and the Propflow lines are added when the read lands. The Propflow card is last, so nothing above it moves.

Asserted in the captured DOM — Before Clara goes live · Your admin account is set up · Choose which buildings Clara works in · Brief your team on what changes. Only rows every company has are asserted; the parity test pins that the skeleton draws no other row.

After (this PR): skeleton, desktop, light

6 · After (this PR): loaded, desktop, light

The loaded page on this branch, same company. Every heading and every row the skeleton drew is here, in the same place. The rows that depend on the company (calendar, the leasing sign-offs, residents told) and the Propflow card are added. The inbox row is gone because no email setup has been chosen. A row with nothing to say yet, such as an unticked sign-off, keeps its detail line's height, so its height doesn't change when the read lands.

Asserted in the captured DOM — Before Clara goes live · Choose which buildings Clara works in · Connect a calendar for everyone who gives tours · Setting up your phone line

After (this PR): loaded, desktop, light

7 · After (this PR): skeleton, desktop, dark

This branch, with the same read held open. The skeleton draws only the rows every company gets (admin account, team, billing, buildings, team briefed, try Clara) and the questions, under the same four headings in the same order. Nothing in it can disappear when the read lands. Rows that depend on the company (inbox, calendar, the leasing sign-offs, residents told) and the Propflow lines are added when the read lands. The Propflow card is last, so nothing above it moves.

Asserted in the captured DOM — Before Clara goes live · Your admin account is set up · Choose which buildings Clara works in · Brief your team on what changes. Only rows every company has are asserted; the parity test pins that the skeleton draws no other row.

After (this PR): skeleton, desktop, dark

8 · After (this PR): loaded, desktop, dark

The loaded page on this branch, same company. Every heading and every row the skeleton drew is here, in the same place. The rows that depend on the company (calendar, the leasing sign-offs, residents told) and the Propflow card are added. The inbox row is gone because no email setup has been chosen. A row with nothing to say yet, such as an unticked sign-off, keeps its detail line's height, so its height doesn't change when the read lands.

Asserted in the captured DOM — Before Clara goes live · Choose which buildings Clara works in · Connect a calendar for everyone who gives tours · Setting up your phone line

After (this PR): loaded, desktop, dark

9 · After (this PR): skeleton, phone, light

This branch, with the same read held open. The skeleton draws only the rows every company gets (admin account, team, billing, buildings, team briefed, try Clara) and the questions, under the same four headings in the same order. Nothing in it can disappear when the read lands. Rows that depend on the company (inbox, calendar, the leasing sign-offs, residents told) and the Propflow lines are added when the read lands. The Propflow card is last, so nothing above it moves.

Asserted in the captured DOM — Before Clara goes live · Your admin account is set up · Choose which buildings Clara works in · Brief your team on what changes. Only rows every company has are asserted; the parity test pins that the skeleton draws no other row.

After (this PR): skeleton, phone, light

10 · After (this PR): loaded, phone, light

The loaded page on this branch, same company. Every heading and every row the skeleton drew is here, in the same place. The rows that depend on the company (calendar, the leasing sign-offs, residents told) and the Propflow card are added. The inbox row is gone because no email setup has been chosen. A row with nothing to say yet, such as an unticked sign-off, keeps its detail line's height, so its height doesn't change when the read lands.

Asserted in the captured DOM — Before Clara goes live · Choose which buildings Clara works in · Connect a calendar for everyone who gives tours · Setting up your phone line

After (this PR): loaded, phone, light

11 · After (this PR): skeleton, phone, dark

This branch, with the same read held open. The skeleton draws only the rows every company gets (admin account, team, billing, buildings, team briefed, try Clara) and the questions, under the same four headings in the same order. Nothing in it can disappear when the read lands. Rows that depend on the company (inbox, calendar, the leasing sign-offs, residents told) and the Propflow lines are added when the read lands. The Propflow card is last, so nothing above it moves.

Asserted in the captured DOM — Before Clara goes live · Your admin account is set up · Choose which buildings Clara works in · Brief your team on what changes. Only rows every company has are asserted; the parity test pins that the skeleton draws no other row.

After (this PR): skeleton, phone, dark

12 · After (this PR): loaded, phone, dark

The loaded page on this branch, same company. Every heading and every row the skeleton drew is here, in the same place. The rows that depend on the company (calendar, the leasing sign-offs, residents told) and the Propflow card are added. The inbox row is gone because no email setup has been chosen. A row with nothing to say yet, such as an unticked sign-off, keeps its detail line's height, so its height doesn't change when the read lands.

Asserted in the captured DOM — Before Clara goes live · Choose which buildings Clara works in · Connect a calendar for everyone who gives tours · Setting up your phone line

After (this PR): loaded, phone, dark

What keeps it from drifting

onboarding-hub-ghost.parity.test.tsx used to load only the full set of rows, which is the one case where skeleton and page agreed. It now loads the row sets the server really sends (all modules; leasing off with no phone line; leasing with no inbox; maintenance only; and a failed read). For each one it checks that the skeleton is the loaded page with the company-dependent rows taken out: same headings, same labels, same order, and the same room kept for the dot and the detail line.

PropFlow Docs