# Closing Loop — AI Sales Orchestration for PropertyLab

*Design dossier · 30 Jul 2026 · grounded in the live petav3 codebase and the fleet's real 30-day ledgers*

**You built the workforce. Now build the closing loop.**

Five AI agents watch every channel — Zoom, phone, WhatsApp, showroom, portal. Today they observe, write up, and brief. This dossier designs the layer that turns their observations into **closed bookings** — and redesigns every agent page so the value is visible, not implied.

| Fleet, last 30 days | |
|---|---|
| Fleet actions | **831** |
| Total AI cost | **$45.72** |
| Follow-ups flagged | **48** |
| Follow-ups closed | **1** |
| Outbound already automated | **87%** |

---

## 01 · The honest diagnosis: you have sensors, not a nervous system

Every agent today is a superb **sensor**. The Zoom agent hears every meeting; the call agent hears every call; the showroom badge hears every walk-in; the Messages agent sees every chat; the portal agent sees what members do alone at midnight. Each one produces a write-up, a score, action items, and a brief.

But the fleet's own numbers show where the revenue leaks out — not in the sensing, in what happens **after**:

- **Leak 1 — Follow-ups die on the wall.** 48 flagged this month across Zoom + calls + showroom. **1 closed.** Every open one is a customer who was promised a next step.
- **Leak 2 — Channels don't talk.** A lead attends a webinar, books a Zoom, calls in, walks into the showroom — four agents each know a quarter of the story. Nobody assembles it.
- **Leak 3 — Signals expire silently.** A member ran 3 property analyses on Tuesday night — the hottest buying signal you own — and no salesperson heard about it by Wednesday morning.

> **The thesis:** you don't need more AI. You need the five agents to feed one decision loop — *Signal → Decision → Action → Outcome* — with a human hand on every customer-facing trigger, and every outcome written back so the loop learns what actually closes.

---

## 02 · The architecture: a Revenue Orchestrator over the fleet

One new layer, three components — built on spines that already exist in the codebase (`activity_logs`, the brief ledgers, `bookings` with real prices, the Notifier, the AiJob lanes).

```mermaid
flowchart TB
    subgraph SENSORS["THE FIVE AGENTS — today's sensors"]
        Z["Zoom Agent<br/>meetings · scores · action items"]
        C["Call Agent<br/>every call, automatic"]
        M["Messages Agent<br/>chats · flows · reminders"]
        F["Showroom Agent<br/>badge recordings"]
        P["Portal Agent<br/>analyses · AI chats · courses"]
    end
    subgraph ORCH["REVENUE ORCHESTRATOR — the new layer"]
        TL["1 · Lead Timeline<br/>one merged story per lead<br/>(activity_logs + channel ledgers)"]
        NBA["2 · Next-Best-Action engine<br/>rules first, AI ranking second"]
        Q["3 · Play Queue<br/>one task list, one owner, one SLA"]
    end
    subgraph ACT["ACTIONS — through existing rails"]
        A1["Nudge staff<br/>(Notifier / briefs)"]
        A2["Start a WhatsApp flow<br/>(human-approved)"]
        A3["Route the hot lead<br/>(lead distribution)"]
    end
    OUT["OUTCOMES<br/>engagements → bookings (price)"]
    Z --> TL
    C --> TL
    M --> TL
    F --> TL
    P --> TL
    TL --> NBA --> Q
    Q --> A1 & A2 & A3
    A1 & A2 & A3 --> OUT
    OUT -. "attribution written back —<br/>the loop learns what closes" .-> NBA
```

### Component 1 — The Lead Timeline (the shared memory)

One queryable, chronological story per lead across all five channels. 80% exists: `activity_logs` already records portal touches, sessions, payments; the channel ledgers hold the rest. The work is a **read model** — merge, don't migrate — exactly the pattern the Portal Activity feed already proved with its five-table `UNION ALL`. This becomes the grounding for **every** agent's cross-meeting memory (today each agent only remembers its own channel).

### Component 2 — The Next-Best-Action engine (rules first, AI second)

Deterministic rules generate candidate plays; the AI only **ranks and drafts** — it never invents a play. That division keeps the engine auditable and the spend bounded, the same discipline as the fleet's rule-based insights.

| Signal (from the timeline) | Play (the candidate action) | Executes via |
|---|---|---|
| Follow-up open > 48h | Escalating nudge: agent → leader → your phone. The SLA everyone can see. | Notifier + brief rails (exists) |
| 3+ portal analyses in a week | "Hot member" alert with the properties they analysed + a drafted opener | Notifier + AI draft (exists) |
| Webinar attended, no booking in 5d | Human-approved WhatsApp follow-up flow, seeded with webinar poll answers | Flows (exists) |
| Meeting score ≥ 8, no next meeting | Prompt the closer with a drafted proposal date; one tap books it | Calendar + Zoom (exists) |
| Showroom visit, untagged 24h | Nag until tagged — an untagged visit is an invisible customer | F2F next-steps (exists) |
| Lead silent 30d after high score | Revival: AI drafts a re-open referencing their last real conversation | WhatsApp draft mode (exists) |

### Component 3 — The Play Queue (one list, one owner, one clock)

Plays land in a single queue on the Copilot — each with the lead, the evidence (linked timeline), the drafted message or booked slot, an owner, and a countdown. A play is **Approve / Edit / Dismiss** — never silent auto-send to a customer. Dismissals are recorded with a reason, which is training data for the ranking.

### The guardrails (non-negotiable, and already your house style)

- **Human hand on customer-facing sends.** The Messages agent's draft-first discipline becomes fleet law: the orchestrator proposes, a person releases. Staff-facing nudges may auto-send.
- **Every play is ledgered.** Same as the brief ledgers: proposed / approved / dismissed / outcome, per play — so "what did the orchestrator do" is always answerable.
- **Caps and quality guards.** Per-lead contact frequency caps, quiet hours, WhatsApp quality-RED pause — all already built for broadcasts; the orchestrator inherits them.
- **Attribution honesty.** *Influenced* = the play touched the lead before the booking, window stated. Never claim "caused". Show the join, always.

### One play, end to end

```mermaid
sequenceDiagram
    participant PA as Portal Agent
    participant OR as Orchestrator
    participant KX as Kexin (closer)
    participant LD as Lead (Mr. Tan)
    PA->>OR: Signal — Mr. Tan ran 3 analyses of the same project tonight
    OR->>OR: Timeline check — attended webinar, scored 8/10 on last call, silent 12 days
    OR->>KX: Play (07:30 brief) — "Hot: Mr. Tan. Evidence + drafted WhatsApp opener"
    KX->>OR: Approve (edited one line)
    OR->>LD: WhatsApp — sent as Kexin, on her number
    LD->>KX: Reply → showroom visit booked
    Note over OR: Booking written back: play → outcome, RM tagged
```

The AI does the noticing, assembling, and drafting. The human does the relationship. The ledger does the proving.

---

## 03 · Making the value visible: the UX redesign

The current pages lead with **activity** ("I wrote up 38 meetings") when the reader needs **consequence** ("those write-ups touched RM 2.1M of pipeline and saved 11 staff-hours"). Activity is the receipt; value is the product. The fix is one principle applied everywhere:

> **Every agent page opens with a Value Strip — money, hours, and outcomes — computed from joins that already exist. Activity moves below, as evidence.**

### The Value Strip (replaces the current outcome tiles as the first row)

Mock — Zoom agent:

| Pipeline touched | Staff hours saved | Promises kept | My cost |
|---|---|---|---|
| **RM 2.1M** | **11.2h** | **1 / 34** | **$4.53** |
| bookings where I briefed the closer ≤14d prior | meeting minutes I listened to & summarised | follow-ups I flagged that got closed | ≈ RM 21 — vs ~RM 300 of listening labour |

Each tile is a **join**, not a guess — and each opens its evidence on click:

| Value metric | The honest computation (all tables exist) |
|---|---|
| Pipeline touched | `bookings.price` where the lead had this agent's touch (brief sent / analysis delivered) within N days before `booking_date` — window shown on the tile, list of the actual bookings one click away. |
| Hours saved | Σ recording minutes processed × (listening + summarising factor ≈ 1.3). Conservative, explained in the tooltip. |
| Promises kept | Follow-through closure already computed — promoted from a funnel footnote to a headline, because it is the number a manager can act on today. |
| Cost vs labour | The agent's AI spend beside the labour cost of doing the same listening by hand. The ROI line writes itself. |

### Per-surface changes, ranked by impact

| Surface | Change | Why it shows value |
|---|---|---|
| All 5 agent pages | Value Strip first; current tiles become row 2; diary stays as evidence | Money and hours before activity, everywhere, consistently |
| Copilot Summary | Fleet headline becomes **"RM X pipeline touched · Y hours saved · $45.72 spent"**; agent cards gain a "value" line; insights gain a *Revenue* tone | The fleet justifies itself in its first sentence |
| Copilot Activity | Each diary line gains its consequence where known: "Sent brief → Kexin closed the follow-up 3h later" | Turns the diary from a log into a chain of cause and effect |
| Zoom / Calls / F2F | "Coached moments" card: score trend per agent since briefs began — the before/after | Shows the agent improving *people*, not just documenting them |
| Messages | Response-coverage clock (median time-to-first-reply, after-hours answers count) + reminder→attendance join | Speed-to-lead is the most defensible messaging value there is |
| Portal | "Engaged → booked" funnel: members the AI served → who progressed to engagement/booking | Connects midnight portal usage to daytime revenue |
| Agent chats | Snapshots gain the value joins, so "are you worth it?" gets answered with pipeline, not vibes | The chat becomes the CFO conversation |

**Honesty rules for every value number:** influenced-not-caused language; the attribution window printed on the tile; empty states that say "no bookings touched yet — here's what I'm feeding the pipeline instead"; and RM figures only where a real `bookings.price` exists.

---

## 04 · The build sequence

1. **WEEK 1 — prove value with zero new AI spend: Attribution spine + Value Strips.** The booking↔touch join (one query per agent), hours-saved math, Value Strips on all six pages, Copilot ROI headline. Nothing new runs — the story already earned becomes visible.
2. **WEEK 2 — stop leak #1: Follow-up SLA enforcement.** The 48h escalating nudge through the existing Notifier + brief rails. Success metric is one number: promises-kept moves off 1/48. This alone likely pays for the whole fleet.
3. **WEEKS 3–4 — the shared memory: Lead Timeline read model + hot-signal alerts.** The merged per-lead timeline (UNION read model), surfaced on the Lead page and fed to every agent's memory context. Ship the two highest-value signal rules: hot-member and post-webinar-silent.
4. **MONTH 2 — the decision loop: NBA engine + Play Queue on the Copilot.** Rules propose, AI ranks and drafts, humans approve. Full play ledger. Dismissal reasons captured from day one — that's the training data.
5. **MONTH 3+ — earned autonomy: graduated auto-execution.** Play types with a proven approval rate ≥95% graduate to auto-run with a daily digest — one play type at a time, each behind its own DB-backed switch, reversible in one click. Autonomy is earned per play, never granted wholesale.

> **The one-sentence version:** Week 1 makes the value you already created visible; Week 2 closes the loop that's leaking it; the rest teaches the fleet to propose the next deal — while a human stays on every send that a customer will read.

---

*All RM figures in mocks are illustrative; every proposed metric maps to an existing table (`bookings`, `activity_logs`, brief ledgers, `ai_requests`).*


---

## 05 · Post-review addendum — audited 30 Jul 2026

Three independent reviews (Claude, Kimi, GPT) gated the plan on empirical questions. The audits ran same-day against the live database. Results and rulings:

| Audit | Result | Ruling |
|---|---|---|
| Booking price coverage | **38%** (101/268 non-cancelled have price > 0) | Below the ~50% gate → **hours-saved is the Value Strip headline**; pipeline shows the booking COUNT, with RM only where price is recorded. Shipped. |
| Identity match rate | Zoom **33%**, Calls **38%**, Showroom **0/4** tagged | Identity resolution is first-class Week 3–4 work, not a footnote. The match rate now surfaces as a Copilot insight — it is itself a value metric. Shipped. |
| Follow-up flag quality | ~half of sampled open items are expired trivia ("send the webinar link", 79d old) | The SLA chase is calibrated before its first run: **≤21 days old + lead-linked only** (22 actionable items vs 48 raw). Widen only after a flagging-precision pass. Shipped. |

Further rulings adopted from the reviews:

- **Attribution:** per-agent strips are *overlapping* views; only the Copilot's merged touch set is the *unique* fleet number (already implemented — a booking counts once at fleet level). Labels updated; a weighted-credit model is deferred until price coverage justifies it.
- **Autonomy graduation:** ≥95% approval **and ≥50 plays per type**, within a risk-tier model (staff-facing may auto-run; customer-facing drafts always need a hand; pricing/legal always human).
- **No ML ranking:** at this volume, ranking = rules priority + a Claude prompt. Dismissal reasons are captured as hygiene, not training data.
- **Hours-saved factor (×1.3):** to be calibrated against two weeks of instrumented staff review time; configurable per agent type.
- **Revised sequence:** Day 1–2 audits (done, above) → Week 1 with the audit-supported headline (shipped) → Week 2 calibrated chase (shipped) → Weeks 3–4 timeline **with identity stitching as the first-class deliverable and match-rate as its KPI** → Month 2 as written, minus learned ranking.


---

## 06 · 闭环工程 — Loop Engineering (the operating model)

*别人卖记录，我们卖闭环。* The flywheel is not an arrow on a diagram — every joint on the circle is a deliberately built feature with a measurable metric. Most SCRMs draw the same picture and only ever build CAPTURE. This section maps the five nodes onto this codebase: what exists, what gates what, and the metric ladder — **覆盖率 → 采纳率 → 提升率**, unlocked in order. 提升率 (lift) is the north star and the basis for pay-per-performance.

| Node | Metric | Built today | Baseline (31 Jul audit) | Gate / next |
|---|---|---|---|---|
| **01 CAPTURE 捕捉** (v0) | 覆盖率 — ≥80% of five-channel signals enter the system | Five agents live as sensors; match rate surfaced on the Copilot as a KPI | Zoom 33% · Calls 38% · Showroom 0/4 linked (~35% effective) | **The flywheel's first fight.** Identity stitching (Weeks 3–4) is what moves this; 覆盖不足 = 大脑在学噪音 |
| **02 LABEL 回填** (v0 · 人工) | 结果回填率 — conversation × outcome join completeness | The join exists (`ComputeInfluencedPipelineAction` ↔ `bookings`); the *backfill workflow* does not | 38% of bookings priced; **no lost-reason ledger at all** | **The 命门 — adopted from this vision, absent from the original dossier.** v0 feature: an outcome-backfill prompt on every closed play/engagement (带看了吗 · 签了吗 · 丢单原因), with 回填率 SLA-chased like follow-ups |
| **03 LEARN 提炼** (v2) | Monthly, auditable rule updates | Deferred deliberately — at 831 actions/month there is nothing to train on (all three reviews concurred) | — | Unlocks only after 01+02 pass their bars. Rule-mining from the ledgers ("交房时间话题 → 成交 0.71") fits the rules-first discipline; LoRA is out of reach on the current API-only stack |
| **04 GUIDE 指导** (v1) | 采纳率 — the action state machine 推送→已读→执行 | Partially free today: briefs ride WhatsApp with read receipts (推送→已读). The Play Queue's Approve/Edit/Dismiss ledger IS the adoption sensor — 一键发送按钮 = 采纳传感器; ignored plays are signal too | First calibrated chase digests: 22 clean items across 6 agents | Month 2 build. Dismissal reasons captured from day one as hygiene |
| **05 MEASURE 验证 ★** (v2) | 提升率 — adopted vs ignored A/B, with holdouts | Designed (play ledger + holdout groups); not built | — | **Gated by 01+02**: lift cannot be measured against outcomes nobody recorded. Once live, 提升率 is the north star and the pay-per-effect basis |

**The two rulings this section adds to the build sequence:**

1. **LABEL becomes an explicit v0 human workflow** — inserted before Week 3. The join without the backfill is a bridge to nowhere; 回填率 gets the same SLA-chase treatment as promises-kept.
2. **The ≥80% coverage bar is the formal gate** before LEARN and MEASURE unlock. Today's honest reading is ~35% — which is why identity stitching, not more AI, is the next milestone.

The ladder in one line: *build coverage until the brain hears clearly (01), record what actually happened (02), only then mine rules (03), sensor every suggestion (04), and charge for proven lift (05).*
