# Reference build — state as of 2026-08-27

A snapshot of one real Caldova build, kept so a later session (or another seller) can see what
"done" actually looks like, and what was still outstanding when the session ended.

**Org:** `<your-org>.crm.dynamics.com` · **F&O:** `caldovaf-odemo.operations.dynamics.com`
**Sales Hub appid:** `<guid>`
**CI – Journeys appid:** `<guid>`
**CI – Data instanceId:** `<guid>`
**Environment id (PPAC):** `<guid>`
**Tenant admin:** `admin@<your-tenant>.onmicrosoft.com`

---

## ✅ Complete

| Area | State |
|---|---|
| Environment | Production, 24 apps, connections + connection references bound |
| Branding | Custom header applied |
| Demo data reskin | CPG portfolio (Vireo, Kestrel, Orchard Press, Saltbrook, Nomad, Brightly, Nova Care) across 8 fictional retailers |
| **Leads** | **421** — 120 Qualified, 205 Disqualified, 96 Open |
| **Opportunities** | **133** — 49 Won, 41 Lost, 43 Open |
| **Cases** | **72** — 47 Resolved, 25 Active |
| Knowledge articles | 118, reskinned |
| **Field Service** | 13 incident types · 5 WO types · 45 assets · 45 work orders |
| **Field Service scheduling** | **8 bookable resources + 45 bookings**, Aug 19 – Sep 4. WO status auto-cascaded: 27 Scheduled / 16 Completed / 2 In Progress. Zero Unscheduled |
| **Predictive lead scoring** | **Published / Model Active** — 10 of 537 attributes |
| **Predictive opportunity scoring** | **Published / Model Active** — 7 of 382 attributes |
| **Customer Service** | **8 Active entitlements** (Premier 500 / Standard 250 / Essentials 100) + **3 Active SLAs**, cross-linked, now on a **`Caldova Service Hours` business-hours calendar**. **25 active cases routed** across 2 queues |
| **Service queues** | `Caldova Trade & Order Support` (13 cases) · `Caldova Consumer Care` (12 cases) |
| **Sales lifecycle** | **56 quotes / 135 quote lines / 35 orders / 20 invoices** off the 49 won opportunities, plus **60 products priced** on `Caldova Trade Price List` |
| **Territories & goals** | 4 territories (US East / Central / West / National Accounts) + 4 FY26 revenue goals on the stock `Revenue` metric |
| **Field Service agreements** | 4 recurring-maintenance agreements on accounts that already have work orders |
| **Reskin config layer** | Queues, case subjects and the price list renamed off `Contoso Coffee` — see `04-demo-data-reskin.md` |
| **CI – Data** | 11 sources, ~6,800 rows, **unified: 408 profiles / 262 matched / 0 duplicates** |
| **CI – Data activities** | `CaldovaTransactions` — retyped **Purchase → SalesOrder** and given the full **semantic field map** (Sales order ID / Order date / **Sales amount**). Joined on CustomerId. Run **Successful** |
| **CI – Data measures** | **5 Active**: `Total customer spend` (Sum TotalAmount), `Average order value` (Avg TotalAmount), `Purchase frequency` (Count TransactionId), `Last purchase date` (Max OrderDate), `Total units purchased` (Sum Quantity) |
| **CI – Data segment** | `Platinum loyalty members` — **Successful, 16 members** |
| **CI – Data segment** | `High value customers` (Total customer spend > 200) — **Successful, 50 members** |
| **CI – Data segment** | `Champions high RFM` — created from an AI suggestion (High R / High F / High M, ~29 members) |
| **CI – Data segment** | `Frequent low spenders` — created from an AI suggestion (High R / Med F / Low M, ~7 members) |
| **CI – Data segment suggestions** | **Successful — 22 RFM suggestions**, from `SalesOrder` / All time / All customers |
| **CI – Data segment insight** | `High value vs Platinum differentiators` — **Successful**, 10 attributes |
| **CI – Data predictions** | `Caldova customer lifetime value` (CLV, 12-month) — **Successful** · `Caldova transaction churn` (90-day window / 120-day churn def) — **Completed with warnings** |
| **F&O — foundation** | Built from scratch over OData: **USD** currency · legal entities **USRT** (Caldova Retail USA) + **USMT** (Caldova Manufacturing USA) · fiscal calendar `Caldova` + FY2025/26/27 · chart of accounts `Caldova` with **45 main accounts** · ledger bound (COA + calendar + USD) for both companies |
| **F&O — posting profiles** | Both companies: customer posting profile `GEN` → AR summary **110200**; automatic transaction accounts `ErrorAccount`→990100, `YearResult`→320100, `CustBalance`→110200, `VendBalance`→210100; customer + vendor groups |
| **CI – Data predictions** | **2 OOB models configured and running**: `Caldova transaction churn` (Transaction churn — 90-day prediction window / 120-day churn definition → `CaldovaTransactionChurn`) and `Caldova customer lifetime value` (CLV — 12-month horizon, model-calculated active interval and high-value percentile → `CaldovaCLV`). Both set to re-import **Monthly**. Training takes a few hours |
| **CI – Journeys journey** | **LIVE and delivered** — 40 sent, 40 delivered, 0 blocked, 0 failed. Branch fired: 39 → follow-up email |
| **Journey emails** | B2C 01 / 03 / 05 all **Ready to send** (statuscode 2) |
| **Sales agents** | ✅ **4 of 5 On** — `Caldova Lead Qualification Agent` (SQA Research) · `Caldova Opportunity Insights Agent` (Sales Opportunity) · `Data Enrichment` (Conversation / Sales Interaction Enrichment) · `Recommended Actions Agent` (auto-provisioned by SYSTEM). Entra app + Dataverse app user + AISalesperson role all in place |
| **Sales Close Agent** | ⚙️ **Fully configured and saved — cannot be started (product-side blocker).** `Caldova Deal Close Agent`. Six of seven sections green: agent user `# Caldova Sales Agent`, CKEditor signature, 8 products across all four brands with page URLs + descriptions, `Follow-Up to Our Meeting` template, Caldova CPG tone instructions, all 4 prerequisites ticked. **`Knowledge sources` spins forever**, which permanently greys `Start agent`. Uploading a PDF knowledge source (`Ready`), confirming Copilot Studio consent, and **publishing the bot** all failed to clear it — see the blocker section in `08-agents-and-sales-insights.md`. Target set verified as **5 opportunities, all contacts on `.example` domains** (RFC 2606, non-routable), so it is safe if it ever does start |

## ⏳ Watch

- **✅ CORRECTED — Sales agent start is not flaky.** The earlier "silently reverts to `Draft`
  overnight, just retry" note was a **misdiagnosis**. `Start agent` opens a **second confirmation
  prompt below the fold** — two identically-named buttons; you must click the **last in DOM order**.
  The agent was never actually starting. See the correction section in
  `08-agents-and-sales-insights.md`. Verify status in the **agent list grid**, not the record header.
  If it genuinely will not take after that, then suspect the app user's missing Exchange mailbox.

## 📬 Journey delivery — solved, and worth reading

The live send **worked**: 40 sent, 40 delivered, 0 blocked, 0 failed, and the engagement branch
routed 39 contacts to the follow-up email.

**The mail was in Junk Email**, not the demo folder — junk filtering runs *before* inbox rules, so
the plus-addressing rig's folder stayed empty and it looked like a total failure. The 40 first-touch
welcome emails never appeared at all (almost certainly Defender-quarantined as first contact from an
unknown domain); the 39 follow-ups reached Junk.

**Add the sending address to Safe Senders before demoing.**

⚠️ The reported **97.5% open rate is not real** — 44 opens, all from "Unknown" email clients, are
Defender scanning the tracking pixel. That is also what pushed 39 contacts down the *Email Opened*
branch. Branch on **Email Link Clicked** if you need believable behaviour. Full detail in
`06-customer-insights.md`.

## ❌ Outstanding

| Item | Note |
|---|---|
| CI – Data activities (8 tables) | Only Transactions has a usable key **in the currently loaded data**. The generator is now fixed — see below |
| CI – Data enrichment | Not started |
| **CI – Data segments** | **4 built.** More are cheap now: the suggestions job produced **22 RFM cells**, each with a one-click `Create segment`. That is the reliable path — see `06-customer-insights.md`; the quick-segment builder is flakier |
| **Churn model quality** | `Caldova transaction churn` finished **"Completed with warnings"** — almost certainly the thin training set (291 joinable customers). Open the model and read the warning before demoing it |
| **F&O — account structure** | 🚨 `Caldova P&L` **still `Draft` 70+ minutes after activation was queued**. The batch service is idle on this environment — this is now confirmed, not suspected. Check **System administration → Inquiries → Batch jobs** |
| **F&O — fiscal periods** | `LedgerFiscalPeriods` = **0**. Years exist, periods do not. Generate at **General ledger → Calendars → Fiscal calendars** |
| **F&O — vendor posting profiles** | No OData entity exists — **UI only** |
| **F&O — inventory posting** | No OData entity exists — **UI only**, and mandatory for anything touching stock (the key one for USMT) |
| **F&O — number sequences** | A company created over OData has none; they gate customer / vendor / sales-order creation |
| **F&O demo data** | ⭐ **Ask Murray Fife for a template first** (`{{USER_EMAIL}}`) — see `07-finance-and-operations.md`. The from-scratch OData build below is the fallback |
| **F&O MCP server** | ✅ **Live and Scout-enabled, nothing to do.** `/mcp` → 401 + `WWW-Authenticate`; `/.well-known/oauth-protected-resource` → 200. `Microsoft Scout` (`<guid>`) was already in the seeded first-party allow-list. **Useful only once the ERP has data** |

> **The F&O honest status:** the foundation is real and verified, but **no journal has been posted
> yet**. Five things gate that (account structure activation, fiscal periods, vendor posting
> profiles, inventory posting, number sequences) and each fails at a different layer with a
> different error. Don't call the GL done until a test journal actually posts.


## 🔧 CDP source data — generator fixed, re-upload is a judgement call

`gen-ci-data.py` now assigns every person a canonical `custid` (`WEB-1000NN`) and stamps a
**`CustomerId` column on all 9 activity sources**, so they can all join to
`CaldovaEcommerceCustomers` on its primary key. Regenerated and verified:

| | |
|---|---|
| Row counts | unchanged |
| loyalty ∩ ecom overlap | still 262 — identity-resolution difficulty preserved |
| Join coverage | Transactions and Subscriptions **100%**; the other 7 land **76–80%** (those people exist only in loyalty, which is realistic) |

**The tenant was deliberately NOT reloaded.** Doing so means re-ingesting 11 CSVs through Power
Query and re-running unification, which puts the verified **408 / 262 / 0** result at risk for the
gain of 8 extra timeline activity types. Worth doing on the next clean build; think twice about
doing it to a working demo.

---

## 🔑 The three findings that unblocked this build

### 1. API-created emails need their placeholder bindings written by hand

Emails authored via the Web API declare `CompanyAddress` / `PreferenceCenter` but never **bind**
them, so `Ready to send` silently does nothing and journey publish fails. Get the correct shape by
creating one email **in the designer** and reading its `msdynmkt_placeholders`:

```json
"binding": { "source": "LegalDataSource",
             "inputs": { "sourceType": { "value": "Default" } },
             "outputPath": "companyaddress",     // or "preferencescenterurl"
             "outputType": "unspecified" },
"touched": true
```

Also set **`msdynmkt_to` to `null`** — a designer-made email has no To token; the journey supplies
the recipient. Full detail in `06-customer-insights.md`.

### 2. The Sales agent needs `AISalesperson`, not System Administrator

And `Manual setup` is the click that unlocks the config sections. Full chain in
`08-agents-and-sales-insights.md`.

### 3. Activity tables join on the target's PRIMARY KEY

`CaldovaEcommerceCustomers` keys on **CustomerId**, `CaldovaLoyaltyMembers` on **LoyaltyId**. Only
`CaldovaTransactions` carries a matching key (291/291 verified); the other 8 are email-keyed, so no
valid path exists and they were deselected. The dialog will still let you build an
`Email → CustomerId` join and enable **Apply** — it matches nothing.

**Permanent fix:** regenerate the CSVs so every activity row carries a stable customer key.

---

## Suggested next order

1. **Add the CI – Journeys sender to Safe Senders**, then re-run the journey for a clean demo.
2. **Read the churn model's warning** before demoing it — "Completed with warnings" on 291 joinable
   customers is probably a training-volume complaint.
3. **Finish the segments** — four more planned. One at a time; see the automation caveat.
4. **Check the F&O batch service** — the account-structure activation has been queued and unrun for
   40+ minutes, which blocks everything else in the GL.
5. **⭐ Email Murray Fife** (`{{USER_EMAIL}}`) for F&O templates — cheapest path to a
   populated ERP by a wide margin, and it needs lead time.
6. **Demo the Sales agent** against the 96 open leads — it is On and running at Research level.
7. **Reload the CDP sources from the fixed generator** on the next clean build to recover all 9
   activity tables.

## 🔑 The one thing to read first if you only read one thing

**The CI-Data semantic field map.** It gates measures templates, every prediction model, and the
segment-suggestions wizard. An activity typed `Purchase` instead of `SalesOrder`, or one missing its
`Sales amount` binding, silently makes all three unavailable — with error messages that point at
your data rather than at the mapping. Full detail in `06-customer-insights.md`.




