Section 02Metrics framework

What we measure, how we calculate it, and why it matters.

Five core metrics aligned to real campus planning decisions. Each carries an explicit definition, calculation logic, source-of-truth, and the decision it informs — so the same number means the same thing across every report.

§ 02.1 — Design principle

OpenBlue is the authoritative source for space inventory. Every metric that touches “what space exists” reconciles to OpenBlue first. Other sources (sensors, badge, reservations) are layered on top — never substituted. This is the single most important decision in the framework. It eliminates the “which number is right?” conversation.

———————————————————————————————————————————
1 · Reliable seat supply

The count of seats available for assignment, by building × floor × space type, reconciled to OpenBlue and adjusted for unavailable inventory.

reliable_seats = openblue.seats - (out_of_service + reserved_executive + capital_project_floors)
Source of truth
OpenBlue (inventory) × FM service status × project plan
Decision informed
Allocation, re-stack capacity, sublease feasibility
Refresh
Weekly · last-known-good snapshot
Known assumption
Treats neighborhood-assigned seats as supply (not demand)
2 · Peak day utilization

The highest-day-of-week observed utilization rate, calculated over a rolling 8-week window. Used for capacity sizing — averaging hides the real demand.

peak_util = MAX(daily_occupied / reliable_seats) over rolling 8w window, by building × dow
Source of truth
Badge feed (presence) ÷ reliable_seats (OpenBlue)
Decision informed
Capacity risk, peak-day overflow planning
Refresh
Daily
Known assumption
Badge tailgating ~3-5% upward bias; documented & reported alongside
3 · Capacity risk index

A categorical signal flagging building × day-of-week combinations approaching unsafe density. Translates utilization into action thresholds.

risk = HIGH if peak_util > 0.85, MEDIUM if 0.70-0.85, LOW if < 0.70
Source of truth
Derived from peak_util
Decision informed
Where to add capacity, where to consolidate
Threshold rationale
85% reflects effective full-occupancy once collaboration spaces are excluded
Known assumption
Thresholds will be revisited after sensor coverage hits 90%+
4 · Space type performance

For each space type, the demand-adjusted utilization — accounting for booking no-shows on reservable spaces. Tells design which space types are working.

demand_index = utilization_pct × (1 - no_show_pct) × 100
Source of truth
Sensors (utilization) × reservation system (no-shows)
Decision informed
Future workspace design, mix changes, retrofit priorities
Verdict thresholds
>75% under-supplied · 40-75% balanced · <40% over-supplied
Known assumption
Sensor coverage is 71% — gaps documented & reported
5 · Allocation reconciliation

For each team, the gap between assigned seats and observed peak attendance. Surfaces over-allocation that could be reclaimed without footprint reduction.

over_under = assigned_seats - peak_day_attendance
Source of truth
OpenBlue (assignments) × badge (peak) × HR (team)
Decision informed
Team allocation negotiations, neighborhood right-sizing
Refresh
Weekly · trailing 8 weeks
Known assumption
Treats badged-into-building as "in-seat" — sensor-level upgrade in Phase 2
§ 02.2 — Calculation logic, in SQL

Every metric above is implemented as a Postgres view in our staging environment. Below: the canonical definitions, executable and version-controlled.

-- Metric 1: Reliable seat supply (by building × floor × space type)
create or replace view v_reliable_seat_supply as
select
  s.building_id,
  s.floor,
  s.space_type,
  count(*)                                              as seats_in_inventory,
  count(*) filter (where s.status = 'IN_SERVICE')       as reliable_seats,
  count(*) filter (where s.status = 'OUT_OF_SERVICE')   as out_of_service,
  count(*) filter (where s.status = 'CAPITAL_PROJECT')  as in_capital_project
from openblue.spaces s
group by s.building_id, s.floor, s.space_type;
-- Metric 3: Capacity risk by building × day-of-week (rolling 8-week window)
create or replace view v_capacity_risk as
with windowed as (
  select *
  from v_daily_building_utilization
  where day >= current_date - interval '8 weeks'
)
select
  building_id,
  day_of_week,
  avg(utilization_pct)   as avg_utilization,
  max(utilization_pct)   as peak_utilization,
  case
    when max(utilization_pct) > 0.85 then 'HIGH'
    when max(utilization_pct) > 0.70 then 'MEDIUM'
    else                                  'LOW'
  end                    as risk_level,
  count(*)               as observations
from windowed
group by building_id, day_of_week;