{# Spec 157 - Slot capacity page. Renders one ``SlotDemandSnapshot`` row per active config: a hero stat strip (avg / p95 / peak / idle), billing-mode context from reservation_id, and the demand-curve chart with horizontal reference lines for current + recommended reservation size. Empty state shows when no snapshot has been computed yet (typically a fresh install whose first scan hasn't run). Low-data state shows a soft caveat when fewer than 100 jobs went into the snapshot. #} {% extends "layout.html" %} {% block content %}

Slot Capacity

{% if not snapshot %}

No slot-capacity snapshot yet

Run a scan to compute the slot demand curve for your workload. It will appear here once at least one scan has completed.

Go to scan
{% else %} {% from "components/_stat_card.html" import stat_card %} {% from "components/_signal_chip.html" import signal_chip %} {% set posture = snapshot.billing_posture %}

Billing mode

{{ signal_chip(posture.mode_label, color=posture.mode_color, title="Derived from JOBS_BY_PROJECT.reservation_id for successful jobs in the scan window.") }} {% if posture.reserved_jobs %} {{ signal_chip("reserved slots", color="brand") }} {% endif %} {% if posture.on_demand_jobs %} {{ signal_chip("on-demand", color="teal") }} {% endif %}

{{ posture.mode_summary }}

Primary reservation

{% if posture.primary_reservation_id %}

{{ posture.primary_reservation_id }}

{% if not posture.has_primary_reservation %}

No reservation crossed the 80% primary threshold; this is the largest observed reservation.

{% endif %} {% else %}

None detected in this scan window.

{% endif %}
Successful jobs
{{ posture.total_jobs }}
Reserved jobs
{{ "%.0f%%" | format(posture.reserved_pct * 100) }}
{{ posture.reserved_jobs }} jobs
On-demand jobs
{{ "%.0f%%" | format(posture.on_demand_pct * 100) }}
{{ posture.on_demand_jobs }} jobs
Reservations seen
{{ posture.reservation_count }}
{% if posture.top_reservations %}
top: {{ "%.0f%%" | format(posture.top_reservations[0].pct * 100) }} of jobs
{% else %}
on-demand only
{% endif %}
{% if posture.primary_reservation_id and not snapshot.reservation_size_known %}
Reservation usage is known from each job's reservation_id, but the committed slot count was not available. Grant bigquery.reservations.get to draw the current-capacity line on the chart.
{% endif %}
{# Hero stat strip. Slot stats are unitless effective slots, measured per-minute over the scan window from the user's own jobs. #}
{{ stat_card("Avg slots used", "%.1f" | format(snapshot.avg_slots), tooltip="Average effective slot count across every 1-minute bucket of the scan window (zero-demand minutes included).") }} {{ stat_card("P95 slots used", "%.0f" | format(snapshot.p95_slots), tooltip="95th percentile demand - the 'burst floor': 95% of minutes used at most this many slots.") }} {{ stat_card("Peak slots used", "%.0f" | format(snapshot.peak_slots), tooltip="Maximum effective slot count in any 1-minute bucket of the scan window.") }} {{ stat_card("Idle fraction", ("%.0f%%" | format(snapshot.idle_fraction * 100)), accent="amber", tooltip="Fraction of 1-minute buckets with zero effective slot usage. High values suggest a bursty workload that could be split between a smaller reservation and on-demand overflow.") }}
{% if snapshot.low_data %}

Low-data caveat: Only {{ snapshot.low_data_job_count }} jobs in the scan window contributed to this snapshot. Below ~100 jobs the demand curve is noisy; rerun with a longer window or wait for more activity before drawing conclusions.

{% endif %} {# Demand chart - measured effective slots over time, with a horizontal reference line for the current reservation size when it's known (discoverable via bigquery.reservations.get). #}
{% from "components/_section_title.html" import section_title %}
{{ section_title( "Slot demand over the scan window", description="Per-minute effective slot usage, measured from your own jobs. Red line = current reservation size (when discoverable)." ) }}
{# Scan-window meta - lets the user verify they're looking at the right snapshot when reservations change over time. #}

Scan window: {{ snapshot.scan_window_start.strftime('%Y-%m-%d %H:%M UTC') }} → {{ snapshot.scan_window_end.strftime('%Y-%m-%d %H:%M UTC') }}

{# ECharts demand chart + copy-by-id helper. #} {% endif %}
{% endblock %}