Daniel M. Jin Email

Migration 5 min read

What Kansas City 311 stopped measuring

Kansas City's 311 switch, read from its open data, shows seven checks that make a silent KPI change visible.

The switch

Kansas City replaced its 311 system in March 20211. The requests kept flowing; one of the city's measures did not.

The city publishes both eras as open data, so anyone can check the change2. That makes it a rare public view of a private problem. When a dashboard moves from Tableau to Power BI, or back, the charts move first. The definitions underneath can change with no error message at all.

Two systems, one city

The PeopleSoft CRM dataset starts with one request in December 20063. The MyKCMO dataset starts in February 20213. As of 24 September 2026, they held 2,395,529 service requests: 1,563,215 from PeopleSoft and 832,314 from MyKCMO2.

The two share no record key, so I did not match requests. I asked a narrower question. What would a dashboard built on the old data show on the new data?

MeasurePeopleSoftMyKCMOWhat changed
Source columns301840.0% fewer
Classification and routing fields63Only department → work group formed a full tree
Request types in use a year526.5 (2017–2020)289.25 (2022–2025)45.1% fewer
Effective types, traffic-weighted90.571.620.9% fewer
Requests over estimated time30.9%Not recordedCannot be computed
Neighborhood250-name text field; computed region, 97.4%Computed region, 97.3%Text field dropped; computed region kept

Source: Kansas City Open Data, queried 24 September 20263.

Seven checks before you trust the new numbers

1. Reconcile every total to the source

An unpaginated pull of the city's 2019 data returned 1,000 rows4. The year holds 166,021 requests3. The pull kept 0.6% of them and raised no warning. Counted by lines, the file held 3,000 data lines, because each address spans three.

All 13 grouped results in this study reconcile to the source's own count(*)3. In a BI migration, the same trap hides in extract filters, refresh windows and connector row limits.

2. Compare like with like

The old taxonomy nearly tripled in 2015, from 220 to 637 request types a year3. So its all-time total of 1,236 types mixes several eras. My first version of this study compared all-time totals and overstated the change. That version also carried generated figures; the audit post explains how they got there.

The fix was to compare four full years on each side: 2017–2020 against 2022–2025. A one-year check, 2020 against 2022, gives 48.2% fewer. All 16 pairings of an old year with a new year point the same way3.

3. Weight categories by traffic

A distinct count treats a type used twice like a type used every day. An effective count, weighted by traffic (entropy), does not. By that measure the drop is 20.9%, not 45.1%.

The gap suggests the drop sits mostly in low-traffic types, though no crosswalk can prove which ones went. Show both numbers side by side. Either one alone tells a different story.

4. Read the category names

Old request types often carried geography in the name. Eleven PeopleSoft pothole types, mostly split by district or area, became three MyKCMO sub-types3. Matched by keyword, they hold 52,443 requests over 2006–2021 and 46,945 over 2021–2026.

A filter on the old Streets / Roadways / Alleys-Pothole-District 3 type finds nothing in the new data. The district now has to come from location, not from the label. A group or filter built on old names does not error. It just stops matching.

5. Name the KPIs that cannot survive

PeopleSoft flagged each request that exceeded its estimated timeframe. Of all PeopleSoft requests, 30.9% did3. MyKCMO has no such field.

Days to close survives in name only. MyKCMO's column also counts days for issues still open, so compare resolved requests only5. Whether those days were late does not survive. No chart breaks; the measure simply has no data after the cutover.

6. Check what survived before calling it lost

The 250-name neighborhood text field was dropped. My first published version called neighborhood tracking lost. It was not: the portal's computed region tags 97.3% of MyKCMO requests with one of 246 neighborhoods3. That same region already covered 97.4% of PeopleSoft requests.

Parcel ID and police district are gone for real. Joins on parcel ID go with them. A spatial join on latitude and longitude remains.

7. Test the cutover; do not assume it

The two datasets overlap for 253 days, from 18 February to 28 October 20213. That looks like a parallel run. The monthly totals point to a fast switch: by May, 99.7% of requests landed in MyKCMO3.

2021PeopleSoftMyKCMOCombined
January7,821—7,821
February8,878198,897
March2,2068,96311,169
April64910,19610,845
May3412,47912,513
June2313,47413,497
July1414,41814,432

Source: Kansas City Open Data, queried 24 September 20263.

March's combined 11,169 sits inside 2020's monthly range of 7,578 to 12,809. So traffic most likely moved, rather than being recorded twice. Without a shared key, that stays an inference, not a proof6.

What this means for your BI team

A migration can pass every visual review and still change what your numbers mean. The risk is not a broken chart. It is a working chart that answers a different question.

  • Ask for a KPI register before the first dashboard moves. List each KPI, its source fields, its definition and its owner. Kansas City's late-request rate would have shown up as a KPI with nowhere to land.
  • Decide in writing which measures retire. Some losses are fine. Silent ones are not.
  • Accept reconciliation, not screenshots. Ask for row counts to the source, totals by category, and both measures of change.
  • Budget for the taxonomy to regrow. MyKCMO used 274 sub-types in 2022 and 344 in 2026 through 22 September3. Governance does not end at go-live.
  • Ask whether a shared key exists. Without one, a parallel run proves less than it appears to.

These seven checks are where I would start a Tableau-to-Power BI move, or the reverse. The mechanical part lives in SchemaDrift, a small reconciliation tool from my lab. It runs six checks: schema, row counts, nulls, two distribution tests and category crosswalks7. SchemaDrift was not run on the city's data. Its demo plants five defects in a migrated copy of a 5,000-row table, and all six checks fire7. It reads CSV extracts today; warehouse adapters are not built yet7.

Kansas City still answers its 311 calls. Its public data can no longer say how many ran late.

Notes

  1. The MyKCMO dataset description, d4px-6rwg, says MyKCMO replaced PeopleSoft CRM on 4 March 2021. Schema snapshot: tableau/tableau-sources/raw/socrata/new_views.json. ↩︎
  2. Kansas City Open Data: PeopleSoft era, 7at3-sxhp and MyKCMO era, d4px-6rwg, both queried 2026-09-24 at 21:44 CDT (02:44 UTC on the 25th). Totals in tableau/tableau-sources/out/findings.json. ↩︎
  3. Seventeen Socrata query results, each hashed with sha256. Figures in tableau/tableau-sources/out/kc_311_taxonomy.json, graded in the portfolio audit, tableau/real-data-audit.md. Year pairings: tableau/tableau-sources/out/robustness.json; distinct drops 40.7% to 50.6%, entropy drops 13.3% to 33.7%, none 50% on both. ↩︎
  4. Re-run of the unpaginated 2019 pull, accessed 2026-10-17. It returned 1,000 records on 3,001 text lines; the JSON form also returned 1,000. The 2026-09-03 planning brief, creation-test/danieljin-site/claude-opus-5.5_max/site/three-viz-brief.html, had recorded 3,000. Raw responses and sha256 hashes: creation-test/danieljin-bi/content/checks/kc311_recheck_2026-10-17/manifest.json. ↩︎
  5. The d4px-6rwg field keeps the name days_to_close under the label "Days Open". Its note says that for an issue still open, the value is the days open so far. On 24 September, 832,298 rows carried a value and 784,688 had a resolved date. PeopleSoft's column has no note; its 1,536,700 values, fewer than its 1,550,513 closed dates, suggest closed requests only. Counts: new_summary.json and old_summary.json in tableau/tableau-sources/raw/socrata/. ↩︎
  6. Hypothesis H3 in tableau/real-data-audit.md puts 65% odds on no request, or too few to matter, sitting in both systems. It puts 30% on a duplicated block under 5% of March. ↩︎
  7. tableau/schemadrift/README.md. The demo data is synthetic: 5,000 rows against 4,998, with the defects planted on purpose; it fails with 8 findings. ↩︎