The Control Tower has a lot of moving parts — five reports, a master workbook with fourteen reference tables, ten stages, multiple status vocabularies. This page is the dictionary. Open it before opening anything else; come back to it when a label, status or count looks unfamiliar.
The Control Tower is a single page with one sidebar nav. Every pane is generated from Unilever.xlsx and re-rendered on each run of control_tower.ipynb. Reports are independent of each other but share the same cell key — countries, brands and SOWs reconcile across panes.
A cell is one country × category × brand combination — for example Italy / Fabric Cleaning / Coccolino. Every report in the Control Tower aggregates over cells. The four-column key (business_group, country, category, brand) is the canonical join across every sheet; the cell_id slug (e.g. HC-IT-Fabric-Cleaning-Coccolino) is a convenience handle.
Each cell has a sponsor partner — Europe, Unilever, Google, TikTok or Pinterest — that determines who's funding and steering the work. It also has a cell status describing where it sits in its overall lifecycle, independent of the per-stage status detail.
The ten stages are the spine of the program. Every cell inherits the same sequence; what varies is who owns each stage (see the Team Structure pages) and what status each stage is in (see the Delivery report). The stage list is held in tbl_Stages on the Control sheet — notebooks always derive it from there, never hard-code it.
Each cell has ten stages, and each stage has a status. The status vocabulary below is fixed and lives in tbl_StageStatus. Read these as the column-language of the Delivery heatmap: every coloured tile in that report is one of these six.
The Data stage on Delivery rolls up a per-cell, per-data-type readiness inventory held on its own sheet. Every cell has fourteen data-type rows; each carries one of six lifecycle values. The stage status on Delivery should match the rollup — when every feed for a cell is Validated, the Data stage is Done.
Granularity Issue — feed arrived but the cut isn't usable (wrong geo level, wrong period). Blocked — feed not arriving, dependency named. Not in Scope — deliberate exclusion, scoped out at Design.
Each sub-notebook drops two artefacts to the reports/ folder: a standalone HTML (shareable on its own) and a sidecar JSON (the contract back to Mission Control). Sidecars persist between runs — the Control Tower can re-render without re-running everything.
Fail-loud. Any sub-notebook error aborts the whole run; we don't silently skip past failures. The master is opened in headless Excel after each notebook that writes, to recalc cached formula values for the downstream readers.
Every report in the Control Tower reads from Unilever.xlsx. The master is bidirectional with CORTEX — revenue flows out to CORTEX, resourcing flows in from CORTEX (via daily Talent IQ pulls into raw/resourcing/). Snapshots are cut daily into snapshots/ for audit and rollback.
Sheets that hold work state. Cells is the catalog (one row per cell, scope and admin). Delivery is the heartbeat — start dates, current stage, per-stage status / date / notes. Team_Structure is the ownership view — three metadata rows above the table for cluster SteerCo and stage leads, plus per-cell role columns. Data is the readiness inventory.
Sheets written by notebooks. Resourcing and Resourcing - Trends are rewritten on every resourcing.ipynb run (delete + recreate, hidden trends sheet re-hidden after writing). Everything else is admin-maintained.
Control sheet. Admin-owned reference data — every dropdown, every status vocabulary, the SteerCo and Stage Lead assignments. Fourteen tbl_ tables covering countries, business groups, category-brand pairs, scope, refresh frequencies, sponsors, stages, statuses, data types, team-structure roles. Notebooks read this; they never write to it. The status vocabularies on this page all come from here.
Why a workbook and not a database. Stakeholders who need to edit (new SOWs, new cells, status changes) work in Excel. Pushing this to a DB would close the loop on reads but break the write path.