Onboarding, end to end — every screen, every state

What a new customer admin and an invited teammate see, captured 2026-09-18 on the shape wave 3 left behind: step 4 is "Connect the inbox Clara works from" with both vendors and no calendar (#9367, #9373, #9443), and every leasing company walks it (#9377). Plus the staff side of the same flow.

18 Sept 2026 · branch lane-q-onboarding-evidence · captured against propflow-stage · at 7be50f114e

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 · 1 · Connect AppFolio — the one step nobody may skip

The wizard opens here, not on an account form: every admin arrives already known, invited by staff into a company that already exists (flow map, chapter 3). The bar reads 1 of 5 for a leasing company. There is no Skip and no Back on purpose — until AppFolio is connected there is nothing for Clara to work from, so the wizard meets the admin here on every sign-in rather than offering a way round it.

What to look at: one field, one sentence, one button. The other two credential fields reveal themselves progressively as each is completed, so the screen never asks three questions at once.

Asserted in the captured DOMConnect your AppFolio account. · Connect. The heading and the single primary action. What is absent — a Skip, a Back — is the point of this screen and is pinned by the step's own tests.

1 · Connect AppFolio — the one step nobody may skip

2 · 1 · Connect, pressed with nothing typed — the message lands under the field

Connect stays pressable with an empty form; pressing it reveals each field's own message beneath that field, in red, instead of greying the button out with an explanation parked somewhere else. The message names the thing to type — the part before .appfolio.com — not a rule.

Asserted in the captured DOMRequired — the part before .appfolio.com.. The validation sentence is in the DOM only after the press.

1 · Connect, pressed with nothing typed — the message lands under the field

3 · 1 · The same step on a phone

Below 640px the dialog fills the screen, the footer stops floating and becomes a full-width primary, and the theme toggle moves from the bottom-left (where it would sit on the footer) to the top-right corner. Nothing is clipped; the help disclosure keeps its place above the footer.

Asserted in the captured DOMConnect your AppFolio account. · Connect

1 · The same step on a phone

4 · 2 · Pick your buildings — the import, done (2 of 5)

Read the caption first: this is the wizard's built-in layout fixture — 28 invented buildings on invented Denver streets — because the real portfolio pull needs a stored AppFolio credential, which an anonymous capture does not have (the server answers not_connected and sends the admin back to step 1). The fixture exists precisely so this screen can be looked at with a portfolio big enough to scroll; nothing on it is a customer's.

What to look at: every building starts checked; a tile toggles on click; the counter in the footer's centre is live (28 of 28 properties · 140 units · 84 tenants) and stays put while the grid scrolls behind the footer's fade. Unselect all is a text link, not a second button competing with Continue.

Asserted in the captured DOMHere's what we found · 28 of 28 properties · Continue. The done heading, the live counter reading the full fixture, and Continue.

2 · Pick your buildings — the import, done (2 of 5)

5 · 2 · One building opened — the grid becomes a tile rail beside the detail

View details pivots the same tiles into a sticky column on the left and opens the building on the right: its units, tenants, leases, applications and work orders as collapsible counts. The tiles physically move rather than the screen switching, so the admin never loses where they were in the list.

Asserted in the captured DOMHere's what we found · Units · Tenants · Work orders

2 · One building opened — the grid becomes a tile rail beside the detail

6 · 2 · The import on a phone — one column, the counter above the button

Tiles stack one per row; the footer is static with Back, the counter and a full-width Continue, so the list can never scroll under a control that swallows taps (the defect Fede found on this exact screen on 2026-09-10).

Asserted in the captured DOMHere's what we found · 28 of 28 properties · Continue

2 · The import on a phone — one column, the counter above the button

7 · 3 · Here's what we imported (3 of 5) — with the escalation-owner line

Reached the way an admin reaches it — Continue from the import — so the counts are the fixture's real counts, not placeholders. The check mark beside the title is the one celebratory beat Fede asked for; the three tiles are the substance.

The sentence under the lead is #8944's: Anything Clara can't answer comes to you by email. Tell us if it should go to someone else and we'll change it. It says, on the screen where the buildings first appear, that the person finishing this wizard is every building's escalation owner until they say otherwise — and it names no Settings destination because no screen can change that yet (see not fixed here).

Asserted in the captured DOMHere's what we imported · Anything Clara can't answer comes to you by email. · PROPERTIES · UNITS · TENANTS · Imported properties · Continue. The heading, the escalation-owner sentence, the three stat labels and the property table's card title — all present after the walk from step 2. The three labels are asserted in capitals because that is what a person sees: the markup says "Properties" and the label carries `uppercase`.

3 · Here's what we imported (3 of 5) — with the escalation-owner line

8 · 3 · Review on a phone — the three counts stack

The stat card drops to one column and loses its dividers; the property rows keep name-and-address and ellipsize the address rather than wrapping the table.

Asserted in the captured DOMHere's what we imported · Anything Clara can't answer comes to you by email.

3 · Review on a phone — the three counts stack

9 · 4 · Connect the inbox Clara works from (4 of 5) — both buttons, one quiet alternative, no calendar

This screen was rebuilt on 2026-09-18 (wave 3, lane M) after Gera walked the wizard: make it more obvious that it's about the Gmail experience: connecting where Clara reads and writes from … we don't need the calendar there. The h1 is Connect the inbox Clara works from, and the one sentence under it says both halves — Clara reads new leads here and replies from this address — while carrying Fede's 2026-09-17 lesson from a customer who connected his personal Gmail by accident: not your personal email.

Under the sample card, both vendors at equal weight — Continue with Google and Continue with Microsoft — then the quiet alternative in muted type: Prefer Clara to write from a PropFlow address? We'll still read this inbox. That line is the whole of Gera's hidden but available option; it is never a picker between three addresses. Skip for now is the exit, and the footer's primary slot is deliberately empty — the provider buttons are the primary action, so no third Continue competes with them.

Three PRs built what is in this frame, and the order matters because the middle one is why an earlier capture of this page showed something different: #9367 redesigned the screen but had to REMOVE the Google button, because until then it connected a calendar; #9373 rewrote the Google company consent to ask for the inbox instead (gmail.send + gmail.readonly); #9443 then put the button back and shipped the quiet option with it. Every leasing company reaches this screen, including one whose replies go out from a PropFlow address (#9377). The company reads PropFlow Staff because an anonymous request resolves to the staff sentinel organisation — a real answer from the real endpoint.

Asserted in the captured DOMConnect the inbox Clara works from · Clara reads new leads here and replies from this address — connect your shared leasing inbox, not your personal email. · YOUR LEASING EMAIL — SAMPLE · Once connected, Clara reads new leads in this inbox and replies from it. · Not ready to connect? Skip for now and we'll set it up with you. · Continue with Microsoft · Skip for now · Continue with Google · Prefer Clara to write from a PropFlow address? We'll still read this inbox.. The h1, the read-and-write sentence, the sample card, both vendor buttons, the quiet PropFlow-outbound line and Skip. No footer Continue is asserted because none renders.

4 · Connect the inbox Clara works from (4 of 5) — both buttons, one quiet alternative, no calendar

10 · 4 · The inbox step on a phone — card, buttons and Skip in one viewport

One viewport at 390px: title, the read-and-write sentence, the sample card with its caption wrapped inside the card's border, then both vendor buttons, the quiet PropFlow-outbound line and the footer's Skip for now. The redesign deleted the paragraph and the Connect it now label that used to sit over the buttons and push them below the fold on a phone.

Asserted in the captured DOMConnect the inbox Clara works from · YOUR LEASING EMAIL — SAMPLE · Continue with Google · Continue with Microsoft · Prefer Clara to write from a PropFlow address? · Skip for now

4 · The inbox step on a phone — card, buttons and Skip in one viewport

11 · 4 · Leasing inbox connected — back from Microsoft with the company inbox

The company callback's happy landing. The screen has ONE heading and it is the outcome — Leasing inbox connected (it read Leasing email connected until the 2026-09-18 rename, and Connect… before Fede's 2026-09-11 finding) — with a check and Clara now answers from this inbox. The read-and-write sub-line is gone, because there is nothing left to do. The mailbox row that would print the address is absent here because the anonymous status read holds no mailbox; a real admin sees their address in a bordered row under the check, wearing its own vendor's mark.

Asserted in the captured DOMLeasing inbox connected · Clara now answers from this inbox. · Continue

4 · Leasing inbox connected — back from Microsoft with the company inbox

12 · 4 · Approval sent to the Microsoft 365 admin

The consent needed a tenant admin's OK and the request went out. Nothing is red: this is the system working. The footer carries the one exception the spec never covered — Connect a different mailbox, at Skip's weight beside Continue, for the 2026-09-11 case where the approval was requested against the wrong Microsoft account.

Asserted in the captured DOMApproval sent to your Microsoft 365 admin · Connect a different mailbox · Continue

4 · Approval sent to the Microsoft 365 admin

13 · 4 · The connect was refused

A raw access_denied on the URL is humanized before it reaches the screen: You said no to the Microsoft 365 permission. Try again when you're ready. The card is unchanged around it — an error about the mailbox does not take the rest of the screen with it.

Asserted in the captured DOMConnect the inbox Clara works from · You said no to the Microsoft 365 permission. Try again when you're ready.. The humanized sentence is on screen; the raw code is not asserted because it must not be.

4 · The connect was refused

14 · 4 · Which shared mailbox? — a colleague consented as themselves

At most companies the leasing address cannot sign in at all, so somebody consents as themselves and the only missing fact is which of the mailboxes that account can reach is the leasing one. One field, one primary (Use this mailbox, disabled until something is typed), and the address is verified against Microsoft before anything is stored.

Asserted in the captured DOMConnect the inbox Clara works from · Which shared mailbox should Clara reply from? Not a person's own inbox. · Shared leasing mailbox · Use this mailbox

4 · Which shared mailbox? — a colleague consented as themselves

15 · 4 · The Google calendar landing is gone — the same URL now shows the inbox connect

This frame is here because of what is no longer on it. Until 2026-09-18 a Google company consent connected a calendar, so pressing the Google button under an inbox heading landed on Calendar connected · Clara books tours on this calendar. Gera hit exactly that on his 01:15 walk-through and it is what put lane M on the board.

The same redirect parameter now falls through to the ordinary connect screen: there is no calendar outcome on this step at all. Pressing Continue with Google here asks for the INBOX — gmail.send + gmail.readonly, stored like the Microsoft shared mailbox (#9373) — and Clara writes from that connected Gmail (#9376). The button spent part of the day off the screen rather than lying about what it did; #9443 brought it back and deleted the stand-in line in the same hunk. No flag, no branch.

Asserted in the captured DOMConnect the inbox Clara works from · Continue with Google · Continue with Microsoft · Skip for now. The assertions this section carried on 2026-09-17 — Calendar connected / Clara books tours on this calendar. — cannot be satisfied any more, because the state they described was deleted. They are replaced by what the same URL actually renders, which is the point of the section.

4 · The Google calendar landing is gone — the same URL now shows the inbox connect

16 · 4 · The per-building shape of the same step

A company that runs a team per building gets the older three-row list — SMS (activates with the first property), Email and Calendar with a vendor button each. The Calendar row is the building's calendar, ruled to stay (2026-09-17); the tours question that briefly sat under these rows is gone from this shape too. This is the shape the gate falls to on an anonymous status read, so it is what a local capture shows without a company_* parameter.

Not fixed here: this shape still carries the heading Connect Clara to your channels and no email card, while the flow map says the screen is renamed. Renaming only the title would put a lead about an email sample over a screen that has none; the per-building email card is a product gap, not a copy fix.

Asserted in the captured DOMConnect Clara to your channels · SMS · Email · Calendar

4 · The per-building shape of the same step

17 · 5 · Add your team (5 of 5) — untouched

The last screen, and the bar is full. One row: an email and a role — no name field, and the hint says why (they add their own in their profile once they sign in). With nothing typed the only ending is Finish; a Skip for now beside it would skip nothing (Gera, 2026-09-16).

Two things this lane fixed on this screen are visible here: the email field and the role picker are the same height (they were 32px and 40px, a stepped row), and the heading sits at the top of the dialog where the previous three steps put theirs, instead of floating 170px lower.

Asserted in the captured DOMAdd your team · They'll get an email invite. You can add more later in Settings. · No name needed — they add their own in their profile once they sign in. · Finish

5 · Add your team (5 of 5) — untouched

18 · 5 · An address typed — Send invites, Skip for now, and the redesigned role card

Typing an address makes the row real, so the footer becomes two genuine choices: send those invites, or leave without sending. Under the row, the role card says what the default role — Property manager — can and cannot do, every line quoting a gate that ships today.

This is lane E's redesign as merged (#8993): a tinted role tile and the role's name, then two columns side by side under Can and Can't eyebrows, and a Compare with other roles fold in the card's footer. The boundary — what the admin is not handing over — is one eye movement from the capability list rather than a paragraph below it.

New since this page was last captured (#9304, wave 2, lane J): every role card ends with one line saying whether PropFlow asks that person for a calendar. This anonymous capture resolves a per-building company, so the line reads Their calendar lives on the building — we won't ask for a personal one. At a centralized company the same slot says we do ask.

Asserted in the captured DOMSend invites · Skip for now · Property manager · Run the day to day: leasing, maintenance, collections, residents and vendors. · Make somebody an organization admin. · Compare with other roles · Their calendar lives on the building — we won't ask for a personal one.. Both endings, the role the card is describing, one line from each column (so a column that silently emptied fails here), and the fold that opens the other four roles.

5 · An address typed — Send invites, Skip for now, and the redesigned role card

19 · 5 · "Compare with other roles" open — the fold, and the role beneath it

The fold's whole job: the admin has picked one role and now wants to know what the other four would have handed over. Opening it repeats the SAME block — tile, name, Can, Can't — once per role, so the comparison is a vertical scan of one layout rather than five differently-shaped paragraphs. The picked role gains (selected), which it does not say while it is alone on the card.

Why this is two frames and not one. The wizard's dialog is a fixed-height card with its own scroll — it does not grow with the window — so five role blocks do not fit in any one screenshot at any viewport. Rather than assert five role names beside a picture that shows two, this frame shows the fold and the role immediately under it, and the next frame scrolls to the last three. A tick beside text a reader cannot see is the failure this page exists to avoid.

The organization admin's card carries the ruling of 2026-09-17 in one sentence — We never ask them for a calendar here. — and names itself The default admin. A property manager is your per-building admin if you want one. (#9304).

Asserted in the captured DOMProperty manager (selected) · Compare with other roles · Organization admin · Add PropFlow staff to the company. · We never ask them for a calendar here.. The picked role marked as such, the fold, and the first compared role with one line from its Can't column.

5 · "Compare with other roles" open — the fold, and the role beneath it

20 · 5 · The same fold, scrolled — Leasing agent, Maintenance and View only

The rest of the same open card. Every line here is read off a gate that ships: role-grants.ts quotes the permissions matrix, the invite hierarchy and the building-scoping rule, and it imports nothing, so the onboarding step and the role catalog cannot drift apart. Open maintenance or vendors at all is a true sentence for a leasing agent because that role has no maintenance cell at all, not merely a read-only one — and Maintenance carries no a building they have not been given line on purpose, because it cannot open the buildings section for any building.

Each card's last line is its calendar answer: the three working roles say the calendar lives on the building, and View only says Nothing to connect.

Asserted in the captured DOMLeasing agent · Open maintenance or vendors at all. · Maintenance · Run work orders from start to finish, and manage vendors. · View only · Change or add anything, anywhere. · Nothing to connect.. The last three roles, each with one line of its own — a block that rendered its name and dropped its lists fails here.

5 · The same fold, scrolled — Leasing agent, Maintenance and View only

21 · 5 · The role picker open — the five roles, in plain words

The arsenal's own trigger (Gera, 2026-09-16: the old dropdown is not complying with our arsenal). Five options from the one role catalog, the current one ticked; no internal role names anywhere on screen.

Asserted in the captured DOMOrganization admin · Property manager · Leasing agent · Maintenance · View only

5 · The role picker open — the five roles, in plain words

22 · 5 · Two rows — the hint once, the card once per distinct role

+ Add another appends a row. The name hint stays under the first row only, and two rows on the same role share one card rather than repeating five sentences.

Asserted in the captured DOM+ Add another · Send invites

5 · Two rows — the hint once, the card once per distinct role

23 · 5 · On a phone — one field per line, primary on top

The row collapses to one column: email, its hint, the role, the card. The role card's two columns stack — Can above Can't — rather than squeezing to half a phone width. The footer stacks with Send invites above Skip for now, in both visual and tab order.

Asserted in the captured DOMAdd your team · Send invites · Skip for now

5 · On a phone — one field per line, primary on top

24 · Keyboard · Tab to the back arrow on the last step

The back arrow was an <a role="button"> with no href, which a browser leaves out of the tab order — every step's only way back was a mouse. It is in the order now, Enter and Space press it (once per press, never per auto-repeat), and it draws an outline for keyboard focus only. Four Tabs from the heading: email, role, + Add another, then the arrow.

Asserted in the captured DOMAdd your team · Finish

Keyboard · Tab to the back arrow on the last step

25 · Teammate · the invite link, when the link is not one

The page an invite email lands on, given a token nobody minted. One card, one heading, one sentence that tells them what to check and whom to ask — and never who invited them (Fede, 2026-09-09). The live invite (company name, the invited address, the terms checkbox and Continue) needs a real pending invite in stage and is not photographed; see the closing note.

Asserted in the captured DOMThis link doesn't work · Check that you opened the most recent invite email, or ask whoever invited you for a new one.

Teammate · the invite link, when the link is not one

26 · Teammate · terms — one last step

The same card, logo and checkbox row the invite page uses: an invitee who accepts on the invite page and a returning person caught by the gate are looking at one screen in two places. Continue stays disabled until the box is ticked. The company line reads PropFlow Staff here for the same reason the wizard's email card does — the anonymous dev session resolves to the staff sentinel.

Asserted in the captured DOMOne last step · I acknowledge that I have read and agree · Continue

Teammate · terms — one last step

27 · Teammate · terms on a phone

The card fills the width; the assent sentence wraps around its two links.

Asserted in the captured DOMOne last step · Continue

Teammate · terms on a phone

28 · Teammate · Connect your calendar — the leasing agent's one step

A leasing agent's first sign-in lands here (every other role goes straight to the dashboard). Two vendor buttons, the same component the wizard's inbox connect renders so the two can never drift, and a text-link Skip — the footer pairing rule again: the buttons are the primary action, so Skip is not a second button.

Asserted in the captured DOMConnect your calendar · Clara books tours on your calendar, so you only get offered times you're actually free. · Continue with Microsoft · Continue with Google · Skip for now

Teammate · Connect your calendar — the leasing agent's one step

29 · Teammate · calendar connected — the title says so

Back from the vendor. This lane's fix: the heading used to stay Connect your calendar over a check mark and Your calendar is connected. — an instruction over a done state. It now reads Your calendar is connected, like the wizard's own calendar screen, with Clara books your tours here. beneath and one button out.

This is the outcome view the vendor's redirect lands on, reached here by that redirect's own parameter. Nothing is connected behind it — the screen is real, the connection it reports is not this capture's.

Asserted in the captured DOMYour calendar is connected · Clara books your tours here. · Go to your dashboard

Teammate · calendar connected — the title says so

30 · Teammate · waiting on the Microsoft admin — not an error

The same finish as a success: a check, a neutral sentence, the same button. The title keeps the imperative because nothing is connected yet.

Asserted in the captured DOMConnect your calendar · Your Microsoft admin is reviewing Clara's access. Nothing else to do here. · Go to your dashboard

Teammate · waiting on the Microsoft admin — not an error

31 · Teammate · the vendor said no

The callback carries a plain sentence, never a code; it renders in red between the lead and the buttons, and both vendors stay offered.

Asserted in the captured DOMWe couldn't connect your calendar. Try again. · Continue with Microsoft · Skip for now

Teammate · the vendor said no

32 · Teammate · Connect your calendar on a phone

Nothing to reflow: the card was already one column.

Asserted in the captured DOMConnect your calendar · Skip for now

Teammate · Connect your calendar on a phone

33 · Staff · the go-live checklist, under the switch that needs it

Signed in as platform staff, on a deliberately thin fixture company. Six rows, read-only, real data or an honest Not yet: Nothing here blocks the switch — it is what to look at before you flip it. The card sits directly under Clara replies to email because that is what staff read just before they touch it (#8963). The Customer details rail carries the staff choices the wizard only shows — operating model, which address Clara replies from, one inbox for company or building.

Asserted in the captured DOMClara replies to email · Before you turn Clara on · Portfolio connected · Every building has an escalation owner · Email identity chosen · A phone line points at a building · A calendar is attached · Mailbox reading confirmed · Nothing here blocks the switch

Staff · the go-live checklist, under the switch that needs it

34 · Staff · the connections card, on a company with a mailbox to disconnect

The test company (its rail says so in as many words). The mailbox row carries Disconnect because it is connected; the AppFolio row, reading Not connected, carries nothing — a Disconnect beside Not connected is a button that can only fail. There is no Connect anywhere on this card and never will be (#8972).

This lane's fix is on the mailbox row's detail line: it read …@example.test · Connected… with the connected-on date ellipsized off the end; it wraps now and the date is readable.

Asserted in the captured DOMConnections · Company mailbox · Disconnect · Not connected · TEAM CALENDARS. TEAM CALENDARS is asserted in capitals on purpose: the markup says "Team calendars" and the label carries `uppercase`, so the visible text is what is checked.

Staff · the connections card, on a company with a mailbox to disconnect

35 · Staff · the Disconnect confirmation — what stops, and what is kept

Both sentences are load-bearing: Clara stops sending from this inbox, and stops reading new mail that arrives at it. and The record of what was connected is kept, and they can connect it again at any time. Danger tone on the one button that does it; Cancel beside it.

Asserted in the captured DOMDisconnect this company’s mailbox? · Clara stops sending from this inbox · The record of what was connected is kept · Cancel

Staff · the Disconnect confirmation — what stops, and what is kept

36 · Staff · the customer page on a phone

The rail drops under the main column. This lane's other fix on this page: the checklist's row titles wrap instead of clipping — Every building has an escalation owner used to read Every building has an escalation o… at this width.

This frame is the reason the gate exists. An earlier run of this very section shot the page while the checklist still said Checking… and Connections still said Loading…; the picture looked like a perfectly good phone layout, and the assertion is what refused it. It now waits for the loaded rows by name.

Seen here and not fixed, because it is not this page's lane: at 390px the two floating buttons the app layout pins bottom-left and bottom-right — the account badge and Clara's launcher — sit on top of the checklist's last rows. On a phone they cover Mailbox reading confirmed rather than floating clear of it.

Asserted in the captured DOMBefore you turn Clara on · Every building has an escalation owner · Connections · Company mailbox. The checklist row that used to clip, spelled out in full, plus the connections row beneath it — both waited for by name, because at this width the two cards render Checking… and Loading… first and a screenshot taken a beat early shows neither.

Staff · the customer page on a phone

37 · Dark · step 1

The wizard's own toggle, bottom-left, switched to dark; every frame from here down is in the same browser, so the choice carries. Tokens only — the card, the field, the lock badge and the progress track all come from the dark set.

Asserted in the captured DOMConnect your AppFolio account. · Connect

Dark · step 1

38 · Dark · the import

Selected tiles keep the primary border; the avatar tints are the same tokens.

Asserted in the captured DOMHere's what we found · 28 of 28 properties

Dark · the import

39 · Dark · review

The stat card and the property table on the dark card surface.

Asserted in the captured DOMHere's what we imported · Imported properties

Dark · review

40 · Dark · connect the inbox Clara works from

The sample card's three bands on the dark surface, under the retitled screen, with both vendor buttons, the muted PropFlow-outbound line and Skip beneath them.

Asserted in the captured DOMConnect the inbox Clara works from · Continue with Google · Continue with Microsoft · Skip for now

Dark · connect the inbox Clara works from

41 · Dark · add your team — the role picker has an edge again

This lane's arsenal fix. The button-variant FilterSelect drew its border as a hardcoded 8% black — invisible on the dark card, so Role: Property manager floated as bare text beside a bordered email field. It reads the border token now, in every button-variant select in the app.

Asserted in the captured DOMAdd your team · Compare with other roles

Dark · add your team — the role picker has an edge again

42 · Dark · add your team on a phone

The toggle sits top-right on a phone; the stacked footer keeps its hairline.

Asserted in the captured DOMAdd your team · Finish

Dark · add your team on a phone

43 · Dark · the teammate's calendar screen, in the same browser

No toggle on this screen — it follows the preference the wizard stored, as the invite and terms pages do.

Asserted in the captured DOMConnect your calendar · Continue with Google

Dark · the teammate's calendar screen, in the same browser

44 · Dark · the invite page

Same card, dark set.

Asserted in the captured DOMThis link doesn't work

Dark · the invite page

What changed since 2026-09-17, what could not be photographed, and what is not fixed here

What changed between this capture and the last one (2026-09-17). Two waves landed on top of it. Wave 2 put the calendar ask on the teammate's ROLE rather than on the modules the company bought (#9308, #9315), gave every role card a line saying whether we ask that person for a calendar (#9304), and gave the customer their own pre-launch checklist in Settings (#9320, #9333). Wave 3, on 2026-09-18, rebuilt step 4: the heading is now Connect the inbox Clara works from, the calendar question is gone from it entirely, the Google button now connects the INBOX rather than a calendar, a quiet write from a PropFlow address alternative sits under both buttons, and the step is walked by every leasing company (#9367, #9373, #9377, #9443). Three sections below carry assertions that were rewritten rather than dropped, because the screens they described genuinely changed shape — most visibly the Google Calendar connected landing, which no longer exists.

One thing this page contradicts. The run is four screens for a maintenance-only company, and that is the only four-screen case left. A company whose reply address PropFlow owns used to skip step 4 (#9321, 2026-09-17); since #9377 it walks all five, because the inbox is connected for the reading half whoever owns the address. The module that decides run LENGTH is resolveWizardRun (wizard-shape.ts): leasingEnabled ? FULL_WIZARD_RUN : NO_CHANNELS_WIZARD_RUN — it branches on that one fact and on nothing else, so a company with no leasing module is the four-screen case and a per-building company still walks five (its step 4 is the per-building shape, frame 15 below). Do not read that off resolveWizardSteps, which answers a different question — which steps are still OUTSTANDING, i.e. whether this admin is sent to the wizard at all — and which also returns an empty list for an admin who has explicitly completed onboarding, and drops company-mailbox on conditions of its own.

How this was captured. One run against a dev server bound to propflow-stage; the run's own guard confirmed the table before a browser launched, and a production frame is impossible by construction (scripts/ui-capture/target-guard.ts). Wizard, invite, terms and calendar frames are anonymous — the wizard layout redirects a signed-in platform admin to the dashboard, and a local dev server serves those pages to nobody-in-particular — using the tool's per-section anonymous flag shipped for this page (#9002). The staff frames are the smoke identity, platform staff, on stage fixture companies. The only writes the run makes are the activity-trail rows every page view already produces.

Every callback-outcome frame is reached by its redirect's own parameter, and nothing is connected behind it. The seven ?company_* frames and the three ?calendar_* ones are the screens a vendor's redirect lands on, mounted here by hand — the screen is real and the copy is the shipped copy, but no mailbox and no calendar was connected to make them. Where a real connection would have put an address or a vendor name on screen, these frames show that slot empty, and each one's caption says so rather than letting the gap read as a bug.

Reading the stamp, and the one thing on screen that is not the product. The commit stamped at the top of this page is the exact tree these frames were shot from, derived by the capture rather than typed here. Its base is origin/main at 921e3caae6, which includes #9443 (544ec2a0229a, merged 18:08Z — the last of wave 3); the branch on top of it adds only this page's own capture spec, evidence/onboarding-flow.json, so no product file differs from that main. Read the sha, not the date. Three PRs changed this very screen on 2026-09-18 and the third of them merged while an earlier version of this page was being published, so "captured on the 18th" does not identify which code you are looking at and the sha does. No product file differs from main, so every pixel below is main's code. And the round badge in the bottom-left corner of every wizard frame is Next.js's dev-server indicator, not a control PropFlow ships; it sits beside the wizard's own light/dark switch, which is.

Fixed by this lane, each its own small PR: the teammates row was stepped (a 40px role picker beside a 32px field) and its heading floated mid-dialog (#9004); the teammate calendar screen kept an imperative title over a done state (#9005); the button-variant select had no border in dark mode, an arsenal-wide token fix; the staff checklist and connections rows clipped their text with an ellipsis at phone width and at 1440px; the back arrow was not in the tab order; and the built-in layout fixture lost its portfolio to the wizard's own hydration race, so Review could not be photographed with data.

Not photographed, and why — no stage writes beyond the capture itself, no faking: the post-Finish screen (You're set up. PropFlow will confirm your setup and turn Clara on.) needs Finish to POST the completion route, a stage write; it is pinned by the teammates page tests. The maintenance-only four-screen run needs a company with no leasing module — an anonymous run defaults to the full run; pinned by onboarding-run-branches-on-modules.test.tsx. The per-building buildings picker on Add your team needs a per-building company session; pinned by five DOM cases in the teammates tests (#8953). Of the email card's states, the own-inbox, not-yet-connected one is photographed here — two frames of step 4 assert its caption, Once connected, Clara reads new leads in this inbox and replies from it, which resolveEmailPreview emits only for owner: 'client' with scope: 'company'. What is NOT here is the same state once a mailbox is attached (it prints a real address), the PropFlow-address states and the read-failed card, all of which need the status API to answer with that setup; pinned by the five-state table in email-preview.test.ts and the render cases in company-step.test.tsx. The import while running and the import error are transitions the fixture skips and a failure the server did not produce. A live invite link needs a pending invite token in stage, which is a credential; its pending, accepted, expired and wrong-account screens are pinned in invite/[token]/__tests__. Connected calendars with a named vendor need a real vendor round trip.

The admin-only Settings screens ARE photographed now — on their own page, and here is why it has to be its own page. They had gone unphotographed since 2026-09-14 for a reason that was never about effort: the capture tool had no identity that was both a company admin and already onboarded. scripts/seed-evidence-identity.ts mints a real customer admin through the product's own invite and sign-up routes, and the missing move was pointing it at a stage company somebody has already set up — a fresh org_admin at a fresh company is sent straight back into the wizard by shouldRouteUserToOnboarding, which is what ate every earlier attempt. That is now done: the two screens a customer admin sees after Finish, published 2026-09-18.

What keeps them off THIS page is the tool, not the identity. ui-evidence signs in ONCE per run and a spec may not name an identity — --identity is a flag on the whole run, and a section that tried to stage an auth cookie is refused by name (SpecStagedTheSession). This page needs the platform-staff session for its four staff frames, so the customer-admin frames it would take to photograph Settings › My calendar (#9326) and the customer's own pre-launch checklist (#9320) cannot be captured in the same run as them. so the second page is captured with --identity=non-staff on the same stage server, and stays a second page until the tool learns a per-section identity.

What this run caught. Two sets of assertions in the first draft of this page described screens that had since moved, and the run refused rather than publishing a picture beside a tick. The Review step's three counts are labelled Properties, Units and Tenants in the markup and PROPERTIES / UNITS / TENANTS on the screen, because the label carries uppercase — the assertions read the rendered text, so they are written the way a person sees them. And the role card's redesign (#8993) replaced What they can do / What they can't with the Can / Can't two-column block and a Compare with other roles fold; the three sections that still waited for the old heading timed out. A third run shot the staff customer page at 390px while its checklist still read Checking… and its connections card Loading… — a picture that looked like a perfectly good phone layout and contained none of the rows the section claimed to show. None of the three is a defect in the product; all three are the gate doing the one job it has.

Not fixed here — product gaps, not visual defects: the per-building shape of step 4 still says Connect Clara to your channels and shows no email sample, because it has no email card to sample; the Review step's escalation-owner sentence can name no Settings destination because no screen reads or writes that contact yet; and the 1px type difference between the 32px role trigger (13px) and the email field (14px) on the teammates row is noted from #9004's review and left for the shared step-column wrapper that five wizard screens are already asking for.

PropFlow Docs