Why the team's tour card says only "From Email", why Anthony has three prospect rows, and why the source is wrong in our app and in the customer's AppFolio. Four reports, one hole, three decisions and one fix.
2026-10-29 · updated Oct 30 · Decided · Fede, Oct 30 — all 6 PRs live · audit read-only; the build plan is in Plan
One finding. Per-home rows are the design (Fede, Sep 22: "one card per person, one inquiry per home"). Where the person's facts live was never decided. The code puts the summary, preferences, Zillow facts, move-in and source on whichever row the current thread sits on, and every writer and reader touches exactly one row. The thin card, the wrong source and "why three prospects" are the same hole.
Tour confirmed · Ember Estates Anthony Mccleary — In person When: Thu, Oct 29 · 2:30 PM Unit type: 3 Bed Proposed unit: 363 Ember Ln Phone: +1 (970) ••• 9369 About the prospect: From Email
The empty Ember row and a third household were written inside the first booking attempt, the one refused for lack of a phone, 0.8 seconds in and before the phone check. That part is a plain bug. Fixing it alone would not have helped him: his facts would still be on the Morningside row.
Examples the team never saw: "do you require a credit check" and "four-bedroom in Orchard Mesa" (Western Slope, Oct 7); a student calling from abroad on her mother's phone (Camellia, Sep 23); "is it only street parking" and short-term lease pricing (Camellia, Jul 21). Also: a Zillow "pets: Not answered" renders as a chip reading "Not answered".
By design, one row is one renter at one home. Western Slope has 45 people with two or more rows, Situs Group 32, Camellia none. All 109 extra rows trace to a cause:
| # | Bug, plain English | Proven real rows | Fix belongs in |
|---|---|---|---|
| 1 | Adding a home to an existing AppFolio card sends no source | 4 of 4 | AppFolio adapter |
| 2 | Clara-made Zillow cards show "No Source Recorded" in AppFolio | 5 of 15 | Robot; read back and repair |
| 3 | A new row (new home, front door, after-call) takes the channel (email, text, phone) as its source, never the person's origin. Four create paths. | WS 3 · Camellia 3 | Core: new-row factory |
| 4 | A renter's first row labelled by channel though the lead was a Zillow relay or a website form | WS 2 · Camellia 2 | Lead intake |
| 5 | Merging two rows keeps the survivor's label and drops the Zillow origin | 2 (both with tours) | Core: merge |
| 6 | A booking writes "Email" / "Text" / "Phone" into AppFolio's Source; a call always writes "Phone Call" even when we know Zillow | 12 cards | AppFolio adapter |
| 7 | Two different text-to-source mappers disagree (Trulia → Zillow in one; Zumper, Realtor, Facebook → "website" in one) | not countable | Adapter: one mapper |
| 8 | Team card, cancellation card, owner report and dashboard count one renter once per home, under each row's label | every multi-home renter | Core readers |
Also found: a Zillow lead whose new row is labelled "email" may not get automatic text consent, because consent checks the row's source (inference, not measured). Rows keep no source history, so "a later email overwrote the origin" is visible in code but not countable.
Fede chose the person record: "if it's a fact about the person, that's separate from the home… it belongs on the person record." Both reviewers (Fable 5.1 and Opus 5.5, Oct 29) had argued against that destination. Their objection was the migration risk: 8 writers, 82 readers, and a one-shot fold that loses data. So the move is gradual, and nothing switches over at once:
| Field | Fallback fold, when the person record is empty |
|---|---|
| Summary | Newest, by its timestamp |
| Credit, income, pets, lease, bedrooms, move-in | Booked home's row first, else the newest row that has it; "Not answered" dropped |
| Wants, other homes | Union of every row |
| Source | Earliest real listing or website origin; never a channel (D3) |
Checked on Anthony's real rows: the newest summary is the rich Oct 29 one. Fede: "I just don't want anything to break. So feel free to run for 24 hours or however long you need."
Owner: lane 8 (identity, prospects, mirror).
Tour confirmed · Ember Estates Anthony Mccleary — In person When: Thu, Oct 29 · 2:30 PM Unit type: 3 Bed Proposed unit: 363 Ember Ln Phone: +1 (970) ••• 9369 About the prospect Two kids, wants a yard to play and a garage to work from. Wants to move before winter, sooner than the November date he first gave. Also asked about 2841 Morningside Ct and 2980 Emerald Cir. Credit 300 to 579 · Income about $86k · Has pets · 12-month lease · From Zillow For the team at the tour • Asked whether you have anything in the Redlands right now.
Summary, facts, origin and homes come from the person view (D1). "For the team at the tour" lists questions the renter asked that nobody answered. The asks declaration live today ran on first emails only for five weeks and and caught 4 asks while 26 real questions arrived on later turns (1 answered, 1 left hanging, 1 dismissed, 1 silently lost). The person-level notes log stays off the card (Sep 17 rule).
Detail changed by both reviewers: the freshness gate is deleted, not retuned (its own code comment says it always fires on an instant booking). Unanswered team asks: read from the raw messages at card time, up to three quoted questions, nothing new stored (Opus; recommended, lowest risk, matches the raw-transcript rule). Alternative (Fable): declare asks on every turn and open team-note matters; more notes to the team; deferred to a later cleanup.
Fede: "Lead source means it's not how they wrote to us. It's where they're coming from… a well-defined problem. We don't need to be reinventing the wheels… AppFolio already has it. If AppFolio is a system of record and it says something, we shouldn't try to mess with it." And: "when we create the guest card, like Clara, we should make sure that the lead source attribution is correct."
sourceChannel.Rows proven wrong today: 19 (Western Slope 8 and Situs 6 by a sibling record's listing-site evidence; JP&Co 5 from the raw conversation), 2 reached a team card.
| # | What | Kind | Proof before the next starts |
|---|---|---|---|
| 1 | Person view (fold only, nothing written) + the approved card on both layouts, freshness gate deleted, "Other homes" line | improvement | Replay all 118 real stored cards offline: every fact the old card showed is still there; the 7 multi-row cards show the diff. Fairhaven live: a second-home booking by email, card shows the summary and facts |
| 2 | Team asks on the card, read from the raw messages at card time (up to 3 quoted unanswered questions), nothing stored | improvement | Replay the deferred-asks cases plus a planted answered-question control; Fairhaven live |
| 3 | Person facts record + one write helper; the 8 writers write there (and still to the row); the view reads it first; move on touch | improvement | Replay: for every real renter the view reads the same before and after, field for field. Fairhaven live: a new renter's facts land on the person record; a booking at a second home shows them |
| 4 | Sweep for the remaining renters (ledgered, run once PR 3 has been live 24 h); fallback removal a week later as its own PR | ops + cleanup | Dry-run counts first; sample 20 renters before and after |
| 5 | Source on our rows: new rows inherit the origin, the channel goes to its own field, merges keep the earliest origin, two mappers become one | fix | Replay every real row: the 19 proven-wrong rows come out right, all others identical. Fairhaven live: a Zillow relay email gives origin Zillow, channel email |
| 6 | Source in the AppFolio write-back: add-home carries it, the PMS value is never overwritten, read-back repairs our blanks, calls keep a listing origin | fix | Write-back history replay; JP&Co Willows test property 45: create, add a home, read back; a planted blank gets repaired |
Order: 1, then 2, 3 and 5 in parallel; 6 after 5; 4 after 3 has been live a day. Acceptance test for 5 and 6: replay every card Clara created and show the Source each would carry now vs then. Fede: run for 24 hours or however long you need; nothing breaks.
The "prospects are strictly per-property" rule came from an Apr 17 PR written by Claude, merged with no review and no ADR, reversing the previous day's ruling that identity belongs to the person. Fede's own words that night were "you could call 2 different properties, that should be 2 different prospects" then "well lets think about it more"; in the May ADR Fede appears only as an AI persona stand-in.
Both reviewers' plans keep Fede's Sep 22 rule: one person, one inquiry per home. "Later cleanup" means its own PR after the plan.
| # | Pattern | Where it came from | What it costs today | Removed in |
|---|---|---|---|---|
| 1 | "Prospects are strictly per-property" written as a design rule | PR #175 (Apr 17), Claude-written, no review; repeated in the May ADRs | Every fact filed under one home: 109 extra rows, 7 cards read an empty sibling, four other readers take "first row" | PR 3 rewrites the rule to Sep 22's; the four readers in a later cleanup |
| 2 | Person facts stored on the per-home row (summary, Zillow facts, preferences, homes list, move-in) | May 26 ADR moved the old record's fields there; PR #4196 (Jul 20), PR #6703 (Aug 31), PR #10796 (Sep 22) added more | 15% of cards miss facts a sibling row holds; Zillow facts carry no date | PR 1 reads them as one; storage moves only if the replay shows real conflicts |
| 3 | Three different "fold the person" rules | PR #10115 (Sep 20) for the prospect page; PR #10292 (Sep 20) for the list; none for the card | Bare card; every new screen re-invents the fold | PR 1; the prospect page moves onto the view in a later cleanup |
| 4 | A freshness gate that always fires on an instant booking | PR #8083 (Sep 12); its own comment says "always, not sometimes" | 14 cards lost their summary; 39 more undecidable | PR 1 (deleted) |
| 5 | The person summary cut from the card | PR #4027 and PR #4190 (Jul 17 to 20), glance redesign; PR #9102 (Sep 17) hard-coded no notes | Cards with a summary fell from 85% (to Jul 19) to 11% (since Sep 26) | PR 1; the approved card is the newer ruling |
| 6 | The channel (email, text, phone) written into Source | An early April fix wrote "email" for email leads; PR #2741 (Jun 30) wrapped it; four create paths copy it | 19 proven-wrong rows; "From Email" on Anthony's card; possibly missed text consent (inference) | PR 3 |
| 7 | Two AppFolio label mappers that disagree, and stored labels never re-mapped after a fix | PR #5578 (Aug 9) beside the older shared mapper | Trulia and HotPads become Zillow; Zumper, Realtor.com and blanks become "website"; 7 stale rows | PR 4 |
| 8 | The AppFolio write-back drops or invents the source | PR #9105 (Sep 17) fixed "Phone Call"; PR #9581 (Sep 18) add-home with no source field | All 4 homes added at Western Slope show a blank source; 2 Zillow calls written "Phone Call" | PR 4 |
| 9 | A merge keeps the surviving row's label, not the origin | PR #9860 (Sep 19) carries engagement fields only | 2 renters, both with tours, lost "Zillow" and "website" | PR 3 |
| 10 | An asks tool that only echoes the forward tool | PR #12346 (Sep 25), first email turn only | 59 calls, 4 non-empty, all already forwarded; 0 notes sent; 26 later-turn questions missed | Later cleanup, after PR 2 |
| 11 | A team question marked "resolved" by an unrelated staff text | How team-question matters are closed | A lease-term question closed unanswered | Later cleanup, its own fix |
| 12 | One household per home | PR #5377 (Aug 4), "one household is one deal" | Anthony has three households | Later cleanup; the card does not need it |