Podcast · Lead-intake engine · Deep dive
Five bugs in one week were really one bug wearing five hats — and the design that survived two rounds of people trying to break it before anyone builds a line of it.
Companion to Lead-intake engine: where we are, where we’re going, the design record this episode is built from (revision 5, converged after four adversarial rounds: 25/19/17/5 findings). Everything here is proposed — nothing ships to a real customer without Fede’s own go.
ARTIFACT-STYLE.md § Where the audio comes from — the brief on this page goes in as the first Source, the outline as the second, and the twelve chapter titles below go in the focus prompt. It is never synthesised with a paid text-to-speech service (that route was tried and deleted 2026-09-02: worse audio, real cost per episode, and no API for the tool that does this well — a human still has to sit down with a browser). The recording is downloaded to artifacts/audio/lead-intake-engine.m4a, transcribed with Whisper for the .vtt and the transcript, measured with bin/make-peaks.mjs, and uploaded to R2 — the .m4a is never committed to git. Until it is in the bucket, this block is what you see; the moment it lands, the player picks it up with no other edit to this page. The finishing steps are in episodes/README-lead-intake-engine-podcast.md.One ordinary week produced five separate bugs in how a prospect's inquiry becomes a lead: two people quietly fused into one, two competing applicants merged into one, a cosigner marker ignored, one apartment showing up under two different addresses, and one dead identity marker taking an entire property's sync offline. Told one after another, the pattern is obvious: not five bugs, one bug wearing five hats. PropFlow has two separate places that turn a raw signal into a lead — one for Clara handling a call, text, or email directly, one for the periodic pull from the property-management system — and any rule that lives in only one of them is a place they can silently disagree.
Then the proof ground: the Willows, a real test property where real guest cards and real applications get run through the actual product and checked against the live database, because a written test never would have caught a family member getting silently fused to a known lead on a bare phone-number match with no name comparison at all.
Then the review: four full rounds, almost always two engineers each round with the explicit job of trying to break the design. The count shrank every round — 25, then 19, then 17, then 5 — among the findings a consent rule that only worked today by accident (twice, in two different ways), and a shared identity system capable of silently renaming a real tenant on a bare phone match.
Then the engine that survived all of it: every source gets a small adapter, one shared signal shape, one five-step pipeline, a written record of who said what and when, reply identity kept fully separate from intake, a four-mode setting for who owns a customer's data, and write-back built as its own careful, later step. Then the three decisions that are Fede's alone to make, and the build ladder every step of this has to survive — dark, proven at the Willows, clean against regression, run through the setup gauntlet — before any of it reaches a real customer.
Everything on this page is proposed, not built — a design record revised twice after four rounds of adversarial review, not a shipped feature. No real applicant or tenant name appears anywhere on this page or in the audio, once it exists: only the fictional test property (the Willows) and the customer names already public on the source page (Camellia, Yale 25 Station, Situs Group, Western Slope). The audio, once it exists, is a machine-generated overview of the brief below, and the transcript is machine-made from that recording; proper nouns and ticket numbers are fixed by hand before anything is quoted.
One chapter per major turn in the source brief. The list is hand-written — nothing derives it from audio — and the titles are also what goes in the recording tool's focus prompt. Each one already points at a transcript heading (#ch01…#ch12); the links go live the moment the transcript is pasted in, and until then a click is a deliberate no-op.
The brief this episode is generated from. It is the input to the recording tool, not a transcript of what the hosts said — and it is the only brief. The outline goes in beside it as the second Source; a second brief would not correct this one, it would argue with it.
Canonical Markdown on disk: episodes/lead-intake-engine-2026-09-09.md. The download is the rendered text of what you see here.
Source brief for a two-host technical deep dive. Audience: Fede and the team — smart, not necessarily engineers. The subject is a single design: how a prospect's inquiry gets from wherever it starts (a listing site, a phone call, a text, a property-management system) into PropFlow as one clean lead, and why the current setup keeps producing the same bug wearing a different hat. Plain English throughout — a technical term is explained the sentence it first appears, no PMS/ADR/ticket numbers without saying what they mean.
Everything in this design is proposed, not built. It is one document, revised twice after four rounds of adversarial review (two engineers each round, trying to break it), and nothing in it ships to a real customer without Fede's own go. No real applicant or tenant names appear anywhere below — only the fictional test property (the Willows) and customer names that are already public on the source page (Situs Group, Western Slope, Camellia, Yale 25 Station).
Start with a week, not a diagram. In one ordinary week, five different bugs showed up in how PropFlow turns a prospect's inquiry into a lead. Read them one after another and a pattern jumps out — they're not five bugs. They're one bug, wearing five different hats.
Bug one: two people became one. A phone number matched two different people, and the system quietly treated them as the same person. Why? Because there are two separate places in PropFlow's code that can turn a signal — an email, a guest card from the property-management system, a phone call — into a lead. Call them Door A and Door B. Door A trusted a matching phone number enough to merge two records into one. Door B did not. Neither is "the bug." The bug is that there are two doors with two different opinions, and a prospect can walk through either one depending on how they reached out.
Bug two: two competing applicants got fused into one. Same shape, different day. Two people applying for the same unit around the same time got treated as one applicant instead of two separate people who happen to want the same apartment. Again: one door caught this, the other didn't.
Bug three: the cosigner marker got ignored. When someone applies with a cosigner, the property-management system writes a small text marker — something like "(Co-signer for [name])" — into the application. One door reads that marker and understands it means "these two people belong together." The other door has no idea the marker exists. So depending on which door processed the application, a cosigner either got correctly grouped with their applicant or ended up as a random, ungrouped stranger.
Bug four: a unit showed up under two different addresses. One door was writing a unit identifier as just the unit number — "4B." The other door was writing it as the unit number plus which property it belongs to — "Willows-4B." Same physical apartment, two different keys in the database, so the system occasionally couldn't tell they were the same place.
Bug five: one dead sentinel broke an entire property. Somewhere in the identity system there are small marker rows whose job is to say "these two records refer to the same person, don't create a duplicate." One of those markers became orphaned — it pointed at a person record that no longer existed cleanly — and because only one of the two doors knew how to clean up an orphaned marker, the other door choked on it and stopped syncing that property's leads entirely. Not degraded. Stopped.
None of these are new kinds of bugs. They're the same design gap resurfacing five times in one week: PropFlow has two independent places that turn a raw signal into a lead — call it the conversation path (Clara on the phone or in a text or email) and the sync path (the property-management system feed) — and every rule that lives in only one of those two places is a place they can disagree. AppFolio, the property-management system most PropFlow customers use today, is one source. But it's already one of many a growing customer might use — other guest-card systems, other property-management platforms like Yardi, listing sites, a website contact form, a phone call, a text message. Chasing each disagreement as it turns up is whack-a-mole forever. The actual fix is one door, not two — one set of rules everything walks through, so adding a new source later means writing one small adapter, not re-litigating every rule from scratch.
Here's the shape of the problem as it exists in the code right now, in plain terms.
Writer A is the conversation path — Clara handling a phone call, a text, or an email, deciding to save a new prospect. It carries its own rule set: it refuses to save a prospect if someone other than the prospect tells Clara about them (a fair-housing-adjacent guard — nobody gets entered into the system as "interested" by a third party without the prospect's own say-so), it refuses to treat PropFlow's own outbound message bouncing back as if it were a new inbound lead, and it captures evidence of texting consent as part of saving the prospect.
Writer B is the sync path — the code that pulls guest cards and applications out of the property-management system on a schedule (every 15 minutes for guest cards, every 5 minutes for applications, today). It carries a completely different rule set: it matches on the property-management system's own record ID so a repeat delivery of the same card never creates a duplicate, it never lets a stage go backward (a prospect who applied doesn't get un-applied because of a stale, out-of-order update), and — this one matters a lot, more below — it never auto-enrolls a property-management-system-sourced prospect into Clara's own outreach and follow-up messages, because that person only consented to be texted by the property-management system's number, not by Clara's.
Both writers eventually feed the same identity system — the thing that decides "is this a brand-new person, or someone we already know" — and the same household system, which groups related people together (a cosigner with their applicant, roommates, a family). But upstream of that shared point, everything is duplicated, and duplicated rules drift. That's the whole story of the whack-a-mole week: a rule Writer B has, that Writer A never got told about, or vice versa.
There's a second, separate version of the exact same "one place should decide" problem sitting right next to this one. Today, which mailbox a lead arrives in and which mailbox Clara replies from are the same setting — one field on the property's record. That's fragile in the same way: a lead landing in any other mailbox is invisible to the system. Phone numbers and text messages already got this right — the number a prospect texts and the number Clara replies from are stored separately, which is exactly the pattern email needs to copy.
Before any of this becomes a real design, the team needed to know: does the identity and household logic actually work, or does it just look like it works on paper? The way to find out is not more unit tests — it's real guest cards and real applications, submitted through the actual product, at a real (test) property: the Willows.
That proof caught things a written test never would. It found, for instance, that a family member sharing a phone number with a known lead got auto-fused into the same person without ever comparing their names — the system adopted the match the instant it saw the shared phone number, name comparison came never. And it confirmed the opposite case works correctly: two total strangers who happen to share the same name stay two separate people, because a shared name alone was never treated as proof of anything.
This is the standard the whole redesign now has to clear: not "does it pass unit tests," but "does it survive real guest cards and real applications at a real property, checked against the production database." The team calls that the Willows proof, and nothing in this design counts as "done" until it clears that bar — not before.
Here's the part of the story that's easy to undersell: this design went through four separate rounds of review, almost always two different engineers per round, whose entire job was to try to break it — not read it and nod, actually try to find the case where it fails. The counts, round by round: 25, then 19, then 17, then 5.
Round one found 25 things wrong — 12 from one reviewer focused on scale and timing, 13 from another focused on identity and consent — including three genuine blockers: things that had to be fixed before the design could be called safe at all, not just polished. Round two ran the same exercise against the fixed version and still found 19 more, including two more blockers. Round three — a reviewer reading the whole thing cold, as the engineer who'd actually build the first step, plus a separate reviewer auditing every finding from the first two rounds for anything dropped or fudged — found 17 more, including one more blocker. Round four — one reviewer, fresh eyes, nothing but the current version in front of them — found 5: zero blockers, three must-fix items, one should-fix, one closing note.
That's the shape a real convergence takes: 25, 19, 17, 5 — smaller each time, never zero until the last round, and even the last round still found three things worth fixing. A document that came back clean after one pass would be far more worrying than one that took four passes to stop finding real problems, because it would mean either nobody looked hard, or the design got lucky once. Four rounds of people actually trying, with the count shrinking every time, is what "this has been checked" is supposed to feel like.
A few of what they found are worth walking through individually, because each one is a specific kind of mistake that's easy to make and expensive to miss.
The consent rule that only held by accident. ADR-0094 — an internal decision — says PropFlow should never auto-enroll a property-management-system-sourced prospect into Clara's own outreach messages, because their texting consent belongs to the property-management system's number, not Clara's. That rule exists today, but it lives entirely inside Writer B — the sync path — as a deliberately-never-called hook in the code. It is nowhere written down as something the new, unified pipeline has to keep. If the team had built the merged pipeline starting from Writer A's code instead of Writer B's — which never needed that restriction because it never had the problem — the rule could have silently vanished. Nobody would have noticed until real people who never consented to it started getting texted by Clara. The fix: every rule either door enforces today now has its own line in a table naming who owns it, where it lives in the code, and which automated regression test would fail if a future change dropped it.
A later round of review found an even sharper version of the exact same accident. The consent rule was written down, at that point, only for guest cards — but rental applications are a separate intake source in the same system, handled by a different piece of code, and that code is fully wired to the same outreach-enrollment switch. Nobody had ever flipped that switch on for applications, so in practice zero application-sourced prospects were getting auto-texted. But the reason was a coincidence, not a decision: a separate, unrelated function happened to always report an application's stage as one that stops outreach anyway. Change that one unrelated function — for a completely different reason, on a completely different day — and application-sourced prospects would start getting auto-enrolled in Clara's outreach with no consent check at all, silently. The fix generalizes the same discipline: every intake source now needs its own explicit line stating whether it enforces the never-auto-enroll rule by deliberate design or merely happens not to trigger it yet — "happens not to" is now a named, flagged state, not something that reads as safe just because nothing bad has happened yet.
The shared identity system that could rename a tenant. This is the sharpest one. The identity system — the shared code that decides "is this a new person or someone we know" — is used by more than just leasing prospects. It's also used for tenants, vendors, other categories of people. The fix applied in the first round of review (comparing names, not just phone numbers, before merging two records) was scoped only to the leasing side. It never reached the shared spine everyone else calls into. And on the tenant side specifically, a bare phone-number match is followed by an automatic overwrite of the tenant's name on file — not a merge, an actual rename, silently, on a live tenant record. That's a materially worse failure than the leasing bug the whole redesign exists to fix. It's now being fixed as a standalone piece of work, ahead of and separate from the rest of this design, precisely because it's live and it's worse.
The email that needed proof before it could be trusted. The original plan recommended using AppFolio's "new guest card" notification email as the fastest, no-setup-required way to catch new leads. The review asked a simple, unglamorous question: does that email actually and reliably carry the true identifier for the guest card it's about? Nobody had checked. If it doesn't, and a second, independent piece of code guesses at an identifier instead, you re-create the exact "two doors, two opinions" problem this whole design exists to kill — just with the email as a second door instead of the property-management-system sync. So the notification email got downgraded, for now, from "primary way in" to "a trigger that makes the real intake step in a moment early" — until a one-day check confirms the identifier is trustworthy enough to promote it.
The budget nobody had actually done the math on. The proposal to poll the property-management system for changes every 60 seconds sounded reasonable until someone worked out what it costs against a real customer's real size. It turns out request volume isn't actually the constraint — even Situs Group's 640 units at a 60-second cadence uses under 2% of what's technically allowed. The real, still-unmeasured risk is how much data comes back on each check, not how many checks happen — because the property-management system's report can't currently be filtered to "just what changed," so every check re-reads the entire list of guest cards. That's now a named, open measurement to take before anyone commits to a faster cadence for a large customer, instead of a number picked because it sounded fast enough.
None of these were fatal to the design. All of them were the kind of thing that's obvious in hindsight and invisible until someone is paid, specifically, to try to break the thing.
Here's the design that survived all four rounds.
Every source gets a small adapter, not a rewrite. A guest card from the property-management system, an email from a listing site, a phone call, a text, a website form, another property-management system entirely (Yardi is named specifically, since not every customer runs on the same system) — each one gets a small piece of code whose only job is to translate that source's particular shape into one common shape. Adding a new source later means writing one adapter. It does not mean touching the rules.
One shape, called a Lead Signal. Every adapter, regardless of source, has to produce the same handful of fields: which account/organization this came from (and which underlying database, since the same property-management-system vendor can host more than one separate customer database), which source produced it, that source's own record ID for it (so a repeat delivery never creates a duplicate), which property and unit it's about, the person's contact details, their name (kept cleanly separate from any role text a source might embed in it — the earlier cosigner bug, generalized so it can never happen again for any source), whether they're a cosigner or the primary applicant, which household group they belong to if the source knows, what consent evidence exists and for which specific channel, a pointer back to the original raw record for audit purposes, and when the source itself says this happened (which turns out to matter — see below).
One pipeline, five steps, every source runs through it. Normalize the signal, figure out who this person is, figure out which unit/property they mean, figure out which household they belong to, then write the result. That's it. Every rule either door enforces today — the consent rule, the never-demote-a-stage rule, the on-behalf refusal, the self-email guard, the cosigner-marker read, all of it — becomes one step in this one pipeline instead of being duplicated (or not) across two separate pieces of code.
A record of who said what, and when. Right now, if two sources disagree about someone's name or phone number, whichever one ran most recently just silently wins — there's no record of who overwrote what. The redesign borrows a pattern that already exists elsewhere in PropFlow for settings: every stored name or contact value carries who set it, when, and what it replaced. For a legal name, the property-management system's own record wins over a name transcribed from a phone call, because that's the system leasing staff already treat as the record of truth. For a phone number or email, the most recently confirmed value wins — someone who just texted from a new number outranks a stale email address from months ago. Nothing is ever deleted, just superseded, so a wrong call can be traced back and corrected later. The same record-keeping now also applies to household decisions — which group someone got folded into, and by which rule — because a wrong grouping decision was invisible before, exactly the way a wrong name overwrite used to be.
Reply identity stays a separate question from intake. How a lead reaches Clara and who Clara replies as are two different settings that don't have to match. A customer can have fast intake and a slow reply setup, or the reverse — fixing one doesn't fix the other. This split already exists for phone numbers (the number a prospect calls is set independently of anything else); the redesign extends that same separation to email and to any future channel, rather than continuing to bolt the two questions together the way today's single-mailbox setting does.
A per-customer setting for who "owns" the record — four modes, not three. The original policy (from an internal decision made in July) said PropFlow is always the system of record, full stop, and never writes back into a customer's property-management system. That was the right call for a customer with no other CRM of their own — which describes Camellia. It does not describe every customer. Yale 25 Station runs on a different system PropFlow is meant to fully replace. Some customers want to keep using their existing system as their record of truth and have PropFlow write into it. And — this is the one the original three-option framing genuinely couldn't express — a customer can be under an explicit, deliberate decision to allow PropFlow to read their data but never write to it during onboarding, which is Western Slope's actual situation right now: "it stays read-only, no writes there, the lock stays on," in Fede's own words. So the design now has four modes: PropFlow-only, PropFlow-replaces, read-only-during-onboarding, and write-back-to-their-system.
Write-back, when it exists, is its own separate step — never folded into the code that decides who someone is. If a customer's mode allows PropFlow to write into their property-management system, that write always searches for an existing matching record first — by contact details and a name check, never contact details alone, because a bare phone-number match at this exact boundary is a worse mistake than creating a duplicate: it can silently mutate a real, unrelated person's actual record in the customer's own system. Every write-back write also carries a marker identifying it as PropFlow's own, so the intake side never re-reads its own write and mistakes it for a brand-new incoming lead — the same pattern that already prevents this exact loop for outbound messages today.
Everything above is engineering direction — how the code should be shaped. Three questions in this design are not engineering questions. They're calls about what PropFlow is willing to promise a customer, and only Fede can make them.
One: does the July "PropFlow never writes back" policy get amended to the four-mode version above? The recommendation is yes — amend it, generalize it rather than reverse it, because the reasoning behind the original decision (two systems with different rules re-creates exactly the split-brain this whole redesign exists to kill) still holds; a single engine with one write-back adapter per mode doesn't reopen that problem, it's the same answer applied more broadly. The alternative — leave the old policy standing everywhere — would mean telling Situs Group and Western Slope that if they want their own system kept in sync, they either get a second engine built (the thing the original policy explicitly said not to do) or they get nothing.
Two: what's the primary way a new lead reaches the system? Recommended: the 60-second-per-database check of the property-management system stays the intake of record, and the "new guest card" notification email — once it's confirmed to reliably carry the real card identifier — is treated as a trigger that makes that check run early, not as an independent source with its own opinion about what counts as a new lead. The alternative that was on the table in the first draft — treat the notification email as the primary, fastest path — is exactly the thing round-one review found unproven, and unproven in a way that could quietly re-create a two-doors problem inside a single design meant to eliminate one.
Three: does PropFlow build a platform-wide opt-out list before write-back goes live anywhere? This is the one with real consequences for a real person if it's skipped. A prospect can text "STOP" to one customer's number. Today, there is nowhere in the system for that to be recorded in a way any other customer's outreach would ever check — so the same phone number could reach a second, unrelated customer weeks later as a brand-new lead, with no memory that the person opted out anywhere. Recommended: build a small, contact-value-keyed table, checked by every outbound message regardless of which customer it's for, reusing lookup code that already exists elsewhere in the product for a different purpose. This has to exist before write-back turns on for any customer, because write-back is specifically the feature that can trigger a property-management system's own automatic texts to someone who only ever agreed to hear from Clara's number.
None of this ships the way it's designed here in one motion. It ships in a specific order, and each step has a specific gate before the next one starts.
The order matters. The scale and reliability fixes — making sure the system doesn't check a customer's data twice at once, doesn't let one bad property's sync failure take down every other property's sync in the same run, and doesn't quietly grow unbounded as customers get bigger — move ahead of the notification-email trigger, because that email makes an unsafe-at-scale check run more often, and there's no point making something unsafe happen faster. A small table that blocks unwanted messages platform-wide gets its own dedicated step, ahead of write-back, instead of being a vague idea mentioned in passing — because an engineer building write-back needs to know, concretely, that this table exists and works before they depend on it.
Every step in the ladder follows the same standing rule that governs everything at PropFlow, not just this design:
That's the whole shape of it: five bugs in one week that were really one bug, a proof ground that catches what a written test can't, two full rounds of people trying to break the fix and mostly succeeding at finding real gaps, and a design that only gets called finished when it's survived all of that — not when the document reads well.
The focus guidance. It goes in as a second Source alongside the brief, and it answers “what should the hosts focus on?” — it is what stops a two-host format from wandering into a reading of the table of contents. It carries no facts of its own.
Canonical Markdown on disk: episodes/lead-intake-engine-2026-09-09-outline.md. Too long for the focus-prompt box, which is why it is a Source and the chapter titles are the prompt.
Paste this alongside the source brief as a second source. It answers "what should the hosts focus on in this episode?", and it is what stops a two-host format from wandering into a table-of-contents reading of the brief. It carries no facts of its own — every number and claim below is already in the source brief; this file is direction, not content.
Start with the five bugs in one week, told as a list of odd, specific incidents — two people fused into one, two competing applicants merged, a cosigner marker ignored, a unit under two different addresses, one dead marker taking down an entire property's sync — before naming the shared cause.
Land the reveal explicitly: these are not five bugs. They are one bug wearing five hats. Say that sentence early, it is the spine of the whole episode.
Do not open with "PropFlow has two writers." That is the mechanism, not the hook. The hook is that the same mistake kept costing a different customer a different way, all in the same week.
Establish the stakes in human terms: a prospect who reaches out through the "wrong" door — a text instead of a phone call, one property-management system's quirk instead of another's — could get silently mismatched, ungrouped, or dropped, and nobody would notice until it caused a visible problem.
PropFlow has two separate places that turn a raw signal — an inquiry, a guest card, an application — into a lead: one for Clara handling a call, text, or email directly, one for the periodic pull from the property-management system.
The core insight: any rule that lives in only one of those two places is a place they can silently disagree. That's the whole story, said once, cleanly, before the episode gets into specifics.
Name that AppFolio (the property-management system most customers use today) is only one source now, and the whole point of the redesign is that it won't be the only one for long — other systems, listing sites, phone calls, texts, website forms.
Avoid drowning this section in the two doors' actual rule lists yet — that's for section 3. Here it's just: two doors, two rulebooks, guaranteed drift.
Door A (the conversation path) cares about consent evidence, refusing to save a prospect on someone else's word about them, and never mistaking its own outbound message bouncing back for a new lead.
Door B (the sync path) cares about not creating duplicates when the property-management system redelivers the same card, never letting a prospect's progress go backward on a stale update, and — the big one — never auto-texting someone who only consented to the property-management system's own number.
Spend real time on why that last rule is dangerous precisely because it is invisible: it works today by nobody ever building the alternate path, not by being written down anywhere as a requirement the future pipeline must keep. Foreshadow that this comes back as one of the review's sharpest findings.
Resist the urge to list every single rule verbatim. Pick the two or three from each door that carry the most human consequence and let the rest be "and a handful more, all the same shape."
Explain the Willows as the one place the identity and household logic gets checked against real guest cards and real applications submitted through the actual product, not hand-written test cases.
Give the concrete finding: a family member sharing a phone number with a known lead got silently fused into the same person, with no name comparison happening at all — the match was adopted the instant a phone number matched. Sit with that for a beat; it is the clearest illustration of the whole problem.
Pair it with the case that worked correctly: two total strangers with the same name stayed two separate people, because a name alone was never sufficient to merge two records.
State the standard this sets for everything else in the episode: nothing in this redesign is "done" until it clears the same bar — real data, real property, checked against the live database.
Name the process honestly: the design was attacked twice, by two different engineers each time, whose only job was to find what would break it in production. Not a proofreading pass — an adversarial one.
Give the headline numbers plainly: 25 findings in round one, 19 more in round two, 17 more in round three, 5 in round four — shrinking every time, and every round still finding at least one genuine issue except the count never quite reaching zero. The pattern worth naming: a design that keeps getting hit, and hit smaller and less often each round, is a design that is actually converging — a design nobody can find anything wrong with because nobody looked would be the dangerous version of "clean."
Do not present this as embarrassing. Present it as the process working exactly as intended — the whole reason four rounds exist is that a design this size cannot be gotten right by one person thinking hard about it once.
Tell this one as a near-miss. The rule "never auto-text a property-management-system-sourced prospect using Clara's own number, because their consent belongs to a different number" is real and correct today — but it only exists inside one of the two doors, as a piece of code that is deliberately never called.
Make the danger concrete: if the unified pipeline had been built starting from the other door's code, which never had this restriction because it never needed it, the rule could have vanished with nobody noticing until real people who never agreed to it started getting texted.
Land the fix plainly: every rule either door enforces now has to be written down explicitly — who owns it, where it lives, which automated test would break if it were ever dropped — so the next person who touches this code cannot lose a rule by simply not knowing it existed.
This is the sharpest finding in the whole review and deserves the most careful, unhurried explanation. The system that decides "have we seen this person before" is shared — leasing prospects, tenants, vendors, all of it run through the same underlying code.
The first-round fix (compare names, not just phone numbers, before merging two records) only reached the leasing side. On the tenant side specifically, a bare phone match still triggers an automatic, silent rename of a real tenant's name on file.
Say clearly why this is worse than anything else found this episode: it is not a merge or a mismatch, it is an unprompted overwrite of a real person's name on a live record, with nobody asked and nothing flagged.
Note it is being fixed now, as its own standalone piece of work, ahead of and separate from the rest of this design — because it is live today, not a future risk.
The original idea: use the property-management system's own "new guest card" email as the fastest way to catch a new lead, no waiting for the next scheduled check.
The review asked one unglamorous question nobody had checked: does that email reliably contain the real identifier for the card it's about? If two independent pieces of code each guess at what identifies "the same lead," the two-doors problem returns inside the very design meant to kill it.
The resolution: the email is downgraded, for now, from primary path to a trigger that makes the real check run a few minutes early — a small, deliberate demotion, not a rejection, pending a one-day check of real examples.
The instinct going in was "check more often is obviously better and probably cheap." The review made someone actually do the math.
Show the surprising result: checking a database of hundreds of units every 60 seconds barely dents the technical ceiling — request volume was never the real risk.
Name the actual, still-unmeasured risk instead: how much data comes back on every single check, since the system currently has no way to ask for "only what changed" — every check re-reads the whole list. That is now an explicit thing to measure before committing to a faster schedule for a large customer, not a number picked because it sounded aggressive enough.
Now state the actual design, having earned it through the bugs and the reviews rather than opening with it. Each new source — a property-management-system feed, a listing-site email, a phone call, a text, a website form, a different property-management system entirely — gets one small adapter that translates it into one shared shape.
That one shape carries everything the pipeline needs: who this is, which source it came from, which property and unit, contact details, name kept clean of any role text a source might embed in it, cosigner status, household group, consent evidence per specific channel, and a pointer back to the original record.
One pipeline, five steps, every source runs through it: normalize, figure out who this person is, figure out the unit, figure out the household, write the result. Every rule from both doors becomes one step here instead of being duplicated or missing.
Add the two supporting ideas without over-explaining them: a record of who set which name or contact value and when, so disagreements are traceable instead of silently overwritten; and reply identity (who Clara replies as) staying a fully separate setting from intake (how a lead arrives), the same way phone numbers already work.
Explain the old policy first: PropFlow is always the system of record, never writes into a customer's own property-management system. Right for a customer with no CRM of their own — Camellia's situation.
Show why it stopped being enough: Yale 25 Station needs PropFlow to fully replace a different system; some customers want to keep their own system as the record of truth and have PropFlow write into it; and Western Slope is under an explicit decision to allow reads but forbid writes during onboarding — a real, current situation the old three-option framing had no way to describe at all.
Land the four modes cleanly by name: PropFlow-only, PropFlow-replaces, read-only-during-onboarding, write-back-to-their-system. Use Fede's own quoted line about Western Slope's lock staying on — it's the most concrete, human evidence that the fourth mode isn't hypothetical.
When a customer's mode allows writing into their system, that write always searches for a matching existing record first, using contact details and a name check — never contact details alone.
Explain why a bare-contact match is worse than a duplicate here specifically: it can silently attach to and mutate a real, unrelated stranger's actual record in the customer's own system, which is a bigger harm than creating an extra card.
Every write-back write also carries its own marker so the intake side recognizes it as PropFlow's own and never mistakes it for a brand-new incoming lead.
Frame this section explicitly as "these three are not engineering calls, they are calls about what PropFlow promises a customer, and they are Fede's to make."
One: amend the "PropFlow never writes back" policy to the four-mode version. State the recommendation and the one-sentence reasoning — it generalizes the original policy's own logic instead of reopening the problem the policy was written to prevent.
Two: what counts as the primary way a lead arrives — the scheduled check as intake of record, with the notification email only ever making that check run early once its identifier is proven trustworthy. State this as the corrected, safer answer to what the first draft got wrong.
Three: build the platform-wide opt-out list before write-back ships anywhere. Use the concrete human scenario — someone texts STOP to one customer's number, and today nothing stops a second, unrelated customer's outreach from reaching that same number weeks later with zero memory of the opt-out.
State the standing rule once, cleanly, as something that governs everything at PropFlow, not a special rule invented for this design: ships dark, proven at the Willows, checked clean against the full regression history, run through the setup-permutation gauntlet, and turning it on for a real customer is always a separate, later, Fede-approved decision.
Explain briefly why the ordering matters here specifically: the scale and reliability fixes move ahead of the notification-email trigger, because making an unsafe-at-scale check run more often is not an improvement, it's the same risk happening sooner. And the opt-out table gets its own dedicated step ahead of write-back, because write-back depends on it existing and working, not on it being a nice idea mentioned somewhere in the document.
Close on the permanent-test-case idea: any real failure this design or its Willows proof ever turns up becomes a permanent case forever after — reproduced as a failure on the old code, confirmed fixed on the new code — so the exact same mistake cannot quietly ship a second time.
Do not turn this into a tour of every one of the 62 setup combinations in the gauntlet, or every one of the roughly 44 individual review findings. Pick the handful that carry a real story (the ones named above) and let the rest be "and dozens more of the same shape."
Do not present the review findings as embarrassing or as evidence the first draft was bad. Present the number of findings shrinking round to round as the actual proof the process works.
Do not speculate about a launch date, a customer rollout order, or which decision Fede will make. This document takes no position on any of the three open decisions beyond stating the recommendation already on the page, and neither should the hosts.
Do not use any real applicant, tenant, or prospect name — use the fictional test property (the Willows) and only the customer names that are already public on the source page.
Do not resolve the episode with false confidence that this is finished. It is a design that has survived four adversarial rounds and a real-property proof ground so far — not a shipped feature. Close on that distinction, not on a summary of the engine.