P2E Territory Control Panel
The "P2E Trixel Territory Control" panel is the 3D globe surface that appears at the top of the P2E Situation Room page in network-crm (route /p2e). It is the hero visual for PlayRoll's Italy GTM program — the place where venue candidates, field ambassadors, and contributor nodes are overlaid on a triangular subdivision of Italy.
This page exists because the panel mixes real Supabase-backed data with mock field-ops data, and that mix is not obvious to a viewer. Read this before quoting numbers from the panel in any decision.
Where it lives
- Component:
client/src/components/situation-globe.tsxinnetwork-crm. - Mounted in:
client/src/pages/p2e-dashboard.tsx(P2E Situation Room). - Backed by:
/api/v1/p2e/snapshot— programs, contributors, payment reviews, expansion theatres./api/v1/p2e/italy-places-candidates— 4 412 Italian venue candidates (Google Places sweep).
- Also mounted in
b2bandd2cdashboard modes, but those do not render the territory-control layer.
What the panel is
A Deck.gl globe (_GlobeView) centered on Italy with six layers stacked on top of each other. The user can drag-rotate, zoom (6 LOD bands from "Theatre" down to "Local"), click trixels to drill in, and toggle POI categories / review-verdict filters.
The name "Trixel Territory Control" is GTM-flavored phrasing for a triangular geographic subdivision. There is no game-theoretic territory mechanic underneath — the trixels are pure UI geometry.
Layers — what is shown and where it comes from
| # | Layer | Source | Trust |
|---|---|---|---|
| 1 | Italy land outline + country status fill | Natural Earth ne_50m_admin_0_countries.geojson (fetched at runtime from GitHub) | ✅ Geometry only |
| 2 | Trixel mask (6 LOD bands: Theatre → Macro → Region → Province → City → Local) | Computed in trixel.ts from the Italy polygon — pure geometry, no business data | ✅ Geometry only |
| 3 | POI cluster icons + count badges | Aggregated from italy_places_direct_deduped.geojson (Google Places sweep) | ⚠️ See "Venue data" below |
| 4 | Individual POI sprites (visible at high zoom or after a trixel is selected) | Same dataset, normalized by italy-places.ts | ⚠️ See "Venue data" below |
| 5 | Field ambassador avatars + selection panel | Hardcoded MOCK_P2E_AMBASSADORS in the client bundle | ❌ Mock — not real people |
| 6 | Ambassador referral lines (ambassador → contributor → POI) | Built from the mock ambassadors' hardcoded contributorIds / poiIds arrays | ❌ Mock — connects mock ambassadors to real contributor IDs by string match |
| 7 | Contributor graph nodes (yellow dots, LOD-aggregated) | useP2ESnapshot() → /api/v1/p2e/snapshot → Supabase | ✅ Live |
The bottom-right stats overlay (ACTIVE / NODES / REFS / R{n} TRIXELS / POI CLUSTERS) is computed from the live snapshot (expansion theatres, contributors, referral edges) plus the trixel/POI counts. The ACTIVE / NODES / REFS numbers are trustworthy; the trixel/cluster counts are trustworthy as render-state but they describe the geometry overlay, not the field operation.
Venue data — the ⚠️ case
The POI layer is the only one where the trust answer is "depends":
- Identity (this place exists, with this lat/lng/phone/address): high confidence. Comes from Google Places Text Search via the sweep in
script/p2e_google_places/. - Category membership (this place is actually a LAN center / internet cafe / arcade / TCG store): variable. The classifier is a regex + Google
primary_typepass infinalize_fresh_google_places_v4.py. Every venue is tagged with one of:A_explicit— name or type explicitly matches the category (~1 159 venues).B_probable/B_auxiliary— weak inference (~4 234 venues).C_review— fresh hit only, classifier abstained (~87 050 venues, hidden from the default frontend filter).
- Review verdict (the
REVIEW PROOF/UNCONFIRMED/CONFLICTfilters): a second-pass enrichment inenrich_google_places_reviews.pylooks at Google review text for category-specific words.R2_REVIEW_TEXT_SUPPORTS_SETmeans review text confirms the category;R1_REVIEWS_EXIST_NO_TEXT_MATCHmeans it has reviews but they don't prove anything.
Default filter behavior in the panel: only A_explicit + B_probable + B_auxiliary venues with at least one Google rating, restricted to R2_REVIEW_TEXT_SUPPORTS_SET verdicts. The "LOW CONF N" toggle lets you reveal the candidates that are below the confidence floor.
Full provenance of the dataset and the storage/security posture live in network-crm/docs/p2e-italy-venue-map-ops.md.
Mock data — the ❌ case
The six ambassadors (Ale Contour / Marco Relay / Giulia Node / Antonio South / Marta Cards / Sara Coast) and every line that originates from them are mock data hardcoded in client/src/components/situation-globe/mock-data.ts. Their reach, openLoops, currentMove, status, and the contributor/POI IDs they "refer" are placeholders. The mock connects to real contributor IDs by string match — so if a contributor id happens to coincide with a hardcoded one (e.g. c-marco), the line goes to a real point on the map but the relationship is fictional.
If/when real field ambassadors enter Supabase, this layer should be re-sourced from the same /api/v1/p2e/snapshot endpoint and the mock data file deleted. Until then, the ambassador panel is demo-grade.
Endpoint security
/api/v1/p2e/italy-places-candidates is gated by getControlIdentity({ requireAuth: true }) and served with a private cache header. Production access requires the Cloudflare Access header (cf-access-authenticated-user-email); local development falls back to a dev identity. Do not serve this endpoint publicly — it carries Google Places PII (phone numbers, addresses).
Operator checklist
When someone is about to act on what the panel shows:
- Numbers that come from the bottom-right stats overlay (ACTIVE / NODES / REFS) — trust.
- Yellow contributor dots and the cluster aggregations — trust.
- The 4 412 venues visible in default filter — identity trustworthy, category needs ambassador/manual confirmation before activation.
- Anything ambassador-related (avatars, focus, current move, lines) — do not quote. It is demo material.
Open questions
- Should the mock ambassador layer be hidden behind a feature flag so customer/investor demos can opt-in without baking mock data into prod? (Currently always rendered in p2e mode.)
- The
R{n} TRIXELScount in the stats overlay surfaces the geometry mesh size, not a business count. Worth keeping as a debug stat but should be styled differently from the real KPIs. - The 8.5 MB Google Places GeoJSON is committed to the repo. Migration to a CDN is tracked in
p2e-italy-venue-map-ops.md. Until then, panel boot pays a one-time fetch cost (now cached for 1h viaCache-Control: private, max-age=3600).