glm-5.2 @ disabled · api

apidisabled
config
glm-5.2-eff-disabled--api--official--dev
batch
2026-07-19--unified
transport
bigmodel-openai-compat
protocol
api · metered
served model
glm-5.2
captured
Jul 18, 2026, 11:54 AM · N=4
variant
live
slot 0 · P-q · sandboxed iframe
glm-5.2 @disabled · api P-q slot 0 screenshot

The screenshot is the exact frozen pixels the similarity channels measured. Run live re-executes the raw output in a sandboxed iframe; its rendering depends on your browser and fonts and is not guaranteed to match the measured pixels.

similarity neighbors

within session 2026-07-19--unified

similarity measures convergence within this session — not quality.

Fidelity — does the card show the right data?

  • namematch
  • conditionmatch
  • datematch
  • max tempmismatchshown: 13.4
  • min tempmismatchshown: 52.52
  • hourlymismatchcoverage 0/24 · 0 match · 1 mismatch · 23 not shown
  • request sidematch0 violation(s)

extractor fidelity-extractor-v1+Berlin-2026-07-15

Source — raw model output, one byte unchanged

download card.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Weather Card</title>
<style>
  *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

  :root {
    --bg-0: #07090d;
    --bg-1: #0f1419;
    --card-1: rgba(28, 34, 42, 0.65);
    --card-2: rgba(18, 22, 28, 0.55);
    --border: rgba(255, 255, 255, 0.08);
    --border-strong: rgba(255, 255, 255, 0.16);
    --text: #f3f5f8;
    --text-mid: #a3adba;
    --text-dim: #6b7684;
    --accent: #f5b942;
    --accent-2: #ff8a5b;
    --cool: #6dd5ed;
    --cool-2: #4aa3df;
    --live: #4ade80;
  }

  html, body {
    width: 1280px;
    height: 800px;
    overflow: hidden;
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
    color: var(--text);
    background: var(--bg-0);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
  }

  body {
    background:
      radial-gradient(900px 600px at 75% -10%, rgba(245, 185, 66, 0.10), transparent 60%),
      radial-gradient(800px 600px at 10% 110%, rgba(109, 213, 237, 0.07), transparent 60%),
      linear-gradient(180deg, #0a0d12 0%, #07090d 100%);
    position: relative;
  }

  /* Fine grain noise overlay */
  body::before {
    content: "";
    position: fixed;
    inset: 0;
    pointer-events: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.025 0'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");
    opacity: 0.6;
    mix-blend-mode: overlay;
    z-index: 1;
  }

  /* Grid lines for texture */
  body::after {
    content: "";
    position: fixed;
    inset: 0;
    pointer-events: none;
    background-image:
      linear-gradient(rgba(255,255,255,0.018) 1px, transparent 1px),
      linear-gradient(90deg, rgba(255,255,255,0.018) 1px, transparent 1px);
    background-size: 80px 80px;
    z-index: 1;
  }

  .stage {
    position: relative;
    width: 1280px;
    height: 800px;
    padding: 36px 48px;
    display: flex;
    flex-direction: column;
    z-index: 2;
  }

  /* ---------- Top bar ---------- */
  .topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 28px;
  }

  .brand {
    display: flex;
    align-items: center;
    gap: 14px;
  }

  .brand-mark {
    width: 38px;
    height: 38px;
    border-radius: 11px;
    background: linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 100%);
    display: grid;
    place-items: center;
    box-shadow:
      0 8px 22px -8px rgba(245, 185, 66, 0.55),
      inset 0 1px 0 rgba(255,255,255,0.25);
    position: relative;
  }
  .brand-mark svg { width: 20px; height: 20px; }

  .brand-text { line-height: 1.1; }
  .brand-text .name {
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--text);
  }
  .brand-text .sub {
    font-size: 11px;
    color: var(--text-dim);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    margin-top: 3px;
  }

  .topbar-right {
    display: flex;
    align-items: center;
    gap: 22px;
    font-size: 12px;
    color: var(--text-mid);
    letter-spacing: 0.08em;
  }

  .meta-chip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    border-radius: 999px;
    background: rgba(255,255,255,0.03);
    border: 1px solid var(--border);
    font-variant-numeric: tabular-nums;
  }
  .meta-chip .dot {
    width: 6px; height: 6px; border-radius: 50%;
    background: var(--live);
    box-shadow: 0 0 8px var(--live);
  }
  .meta-chip .label { color: var(--text-dim); text-transform: uppercase; font-size: 10px; letter-spacing: 0.14em; }
  .meta-chip .value { color: var(--text); font-weight: 600; }

  /* ---------- Main grid ---------- */
  .main {
    flex: 1;
    display: grid;
    grid-template-columns: 1.05fr 1fr;
    gap: 28px;
    min-height: 0;
  }

  .panel {
    position: relative;
    border-radius: 24px;
    border: 1px solid var(--border);
    background:
      linear-gradient(180deg, var(--card-1) 0%, var(--card-2) 100%);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    box-shadow:
      0 30px 60px -30px rgba(0,0,0,0.7),
      0 0 0 1px rgba(255,255,255,0.02) inset,
      0 1px 0 rgba(255,255,255,0.05) inset;
    overflow: hidden;
  }

  /* ---------- Hero panel ---------- */
  .hero {
    padding: 36px 40px 32px;
    display: flex;
    flex-direction: column;
  }

  .hero::before {
    content: "";
    position: absolute;
    top: -40%;
    right: -20%;
    width: 90%;
    height: 90%;
    background: radial-gradient(circle, rgba(245, 185, 66, 0.12) 0%, transparent 65%);
    pointer-events: none;
  }

  .location-row {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    margin-bottom: 28px;
  }

  .location {
    display: flex;
    align-items: center;
    gap: 12px;
  }
  .location svg { width: 18px; height: 18px; color: var(--accent); flex-shrink: 0; }
  .location .loc-name {
    font-size: 26px;
    font-weight: 700;
    letter-spacing: -0.01em;
    line-height: 1.1;
  }
  .location .loc-coords {
    font-size: 11px;
    color: var(--text-dim);
    letter-spacing: 0.1em;
    margin-top: 4px;
    font-variant-numeric: tabular-nums;
  }

  .date-block {
    text-align: right;
    line-height: 1.2;
  }
  .date-block .day {
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--accent);
  }
  .date-block .full {
    font-size: 13px;
    color: var(--text-mid);
    margin-top: 4px;
    letter-spacing: 0.04em;
    font-variant-numeric: tabular-nums;
  }

  .condition-wrap {
    display: flex;
    align-items: center;
    gap: 22px;
    margin-bottom: 18px;
  }

  .icon-frame {
    width: 124px;
    height: 124px;
    border-radius: 28px;
    background:
      radial-gradient(circle at 30% 30%, rgba(255,255,255,0.06), transparent 60%),
      linear-gradient(135deg, rgba(245, 185, 66, 0.18), rgba(255, 138, 91, 0.08));
    border: 1px solid var(--border-strong);
    display: grid;
    place-items: center;
    position: relative;
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.08), 0 14px 30px -16px rgba(0,0,0,0.6);
    flex-shrink: 0;
  }
  .icon-frame svg { width: 78px; height: 78px; }

  .condition-text .label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.18em;
    color: var(--text-dim);
    margin-bottom: 8px;
  }
  .condition-text .value {
    font-size: 30px;
    font-weight: 700;
    letter-spacing: -0.015em;
    line-height: 1.05;
  }
  .condition-text .sub {
    font-size: 13px;
    color: var(--text-mid);
    margin-top: 6px;
  }

  /* Big temp block */
  .temp-block {
    margin-top: auto;
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 30px;
  }

  .temp-current {
    display: flex;
    align-items: flex-start;
    line-height: 1;
  }
  .temp-current .num {
    font-size: 156px;
    font-weight: 200;
    letter-spacing: -0.06em;
    background: linear-gradient(180deg, #ffffff 0%, #c8ccd2 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    font-variant-numeric: tabular-nums;
  }
  .temp-current .unit {
    font-size: 38px;
    font-weight: 300;
    color: var(--text-mid);
    margin-top: 18px;
    margin-left: 4px;
  }
  .temp-current .caption {
    margin-left: 18px;
    margin-bottom: 18px;
    font-size: 10px;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--text-dim);
    writing-mode: vertical-rl;
    transform: rotate(180deg);
  }

  .temp-range {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding-bottom: 14px;
    min-width: 180px;
  }
  .range-item {
    display: flex;
    align-items: center;
    gap: 12px;
  }
  .range-item .pill {
    width: 30px; height: 30px;
    border-radius: 9px;
    display: grid; place-items: center;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.04em;
  }
  .range-item.high .pill {
    background: linear-gradient(135deg, rgba(245, 185, 66, 0.25), rgba(255, 138, 91, 0.15));
    color: var(--accent);
    border: 1px solid rgba(245, 185, 66, 0.3);
  }
  .range-item.low .pill {
    background: linear-gradient(135deg, rgba(109, 213, 237, 0.18), rgba(74, 163, 223, 0.10));
    color: var(--cool);
    border: 1px solid rgba(109, 213, 237, 0.28);
  }
  .range-item .info { line-height: 1.15; }
  .range-item .info .lab {
    font-size: 10px;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--text-dim);
  }
  .range-item .info .val {
    font-size: 24px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
    margin-top: 2px;
  }
  .range-item .info .val .deg { font-size: 14px; color: var(--text-mid); margin-left: 2px; }

  /* Sparkline mini */
  .spark-mini {
    margin-top: 18px;
    height: 50px;
    width: 100%;
    position: relative;
  }

  /* ---------- Hourly panel ---------- */
  .hourly {
    padding: 30px 32px 28px;
    display: flex;
    flex-direction: column;
  }

  .hourly-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    margin-bottom: 22px;
  }
  .hourly-head .title {
    font-size: 16px;
    font-weight: 700;
    letter-spacing: -0.005em;
  }
  .hourly-head .title .accent {
    color: var(--accent);
    margin-right: 6px;
  }
  .hourly-head .sub {
    font-size: 11px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--text-dim);
  }

  .chart-wrap {
    flex: 1;
    position: relative;
    min-height: 0;
  }

  #chart {
    width: 100%;
    height: 100%;
    display: block;
  }

  .chart-legend {
    display: flex;
    justify-content: space-between;
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid var(--border);
    font-size: 11px;
    color: var(--text-dim);
    letter-spacing: 0.08em;
  }
  .chart-legend .leg {
    display: inline-flex; align-items: center; gap: 8px;
  }
  .chart-legend .swatch {
    width: 18px; height: 3px; border-radius: 2px;
  }
  .chart-legend .swatch.curve { background: linear-gradient(90deg, var(--cool), var(--accent)); }
  .chart-legend .swatch.dot { width: 8px; height: 8px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 10px rgba(245,185,66,0.6); }

  /* ---------- Tooltip ---------- */
  .tooltip {
    position: absolute;
    pointer-events: none;
    background: rgba(8, 11, 16, 0.92);
    border: 1px solid var(--border-strong);
    border-radius: 10px;
    padding: 10px 14px;
    font-size: 12px;
    color: var(--text);
    backdrop-filter: blur(8px);
    box-shadow: 0 14px 30px -12px rgba(0,0,0,0.8);
    transform: translate(-50%, -120%);
    opacity: 0;
    transition: opacity 0.15s ease;
    z-index: 10;
    white-space: nowrap;
    line-height: 1.4;
  }
  .tooltip.show { opacity: 1; }
  .tooltip .t-time {
    font-size: 10px;
    color: var(--text-dim);
    letter-spacing: 0.14em;
    text-transform: uppercase;
  }
  .tooltip .t-temp {
    font-size: 18px;
    font-weight: 600;
    margin-top: 2px;
    font-variant-numeric: tabular-nums;
  }
  .tooltip .t-temp .deg { color: var(--text-mid); font-size: 12px; }

  /* ---------- Error state ---------- */
  .error-state {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: 18px;
    padding: 40px;
  }
  .error-state .icon {
    width: 78px; height: 78px;
    border-radius: 22px;
    background: rgba(255, 138, 91, 0.12);
    border: 1px solid rgba(255, 138, 91, 0.25);
    display: grid; place-items: center;
    color: var(--accent-2);
  }
  .error-state .icon svg { width: 38px; height: 38px; }
  .error-state h2 {
    font-size: 22px;
    font-weight: 700;
    letter-spacing: -0.01em;
  }
  .error-state p {
    font-size: 13px;
    color: var(--text-mid);
    max-width: 420px;
    line-height: 1.6;
  }
  .error-state .code {
    font-size: 11px;
    color: var(--text-dim);
    font-family: 'SF Mono', Menlo, monospace;
    margin-top: 6px;
    letter-spacing: 0.04em;
  }

  /* ---------- Footer ---------- */
  .footer {
    margin-top: 18px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-size: 10px;
    color: var(--text-dim);
    letter-spacing: 0.16em;
    text-transform: uppercase;
  }
  .footer .right { display: flex; gap: 18px; }

  /* ---------- Loading state ---------- */
  .loading-overlay {
    position: absolute;
    inset: 0;
    background: rgba(8, 11, 16, 0.85);
    backdrop-filter: blur(6px);
    display: grid; place-items: center;
    z-index: 5;
    transition: opacity 0.3s ease;
  }
  .loading-overlay.hide { opacity: 0; pointer-events: none; }
  .loader {
    width: 44px; height: 44px;
    border-radius: 50%;
    border: 2px solid rgba(255,255,255,0.1);
    border-top-color: var(--accent);
    animation: spin 0.9s linear infinite;
  }
  @keyframes spin { to { transform: rotate(360deg); } }

  @keyframes float-up {
    from { opacity: 0; transform: translateY(14px); }
    to   { opacity: 1; transform: translateY(0); }
  }
  .anim { animation: float-up 0.7s cubic-bezier(0.2, 0.7, 0.2, 1) both; }
  .anim.d1 { animation-delay: 0.05s; }
  .anim.d2 { animation-delay: 0.15s; }
  .anim.d3 { animation-delay: 0.25s; }
  .anim.d4 { animation-delay: 0.35s; }
</style>
</head>
<body>
  <div class="stage">
    <!-- Top bar -->
    <header class="topbar anim d1">
      <div class="brand">
        <div class="brand-mark">
          <svg viewBox="0 0 24 24" fill="none" stroke="#1a1208" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round">
            <circle cx="12" cy="12" r="4"/>
            <path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"/>
          </svg>
        </div>
        <div class="brand-text">
          <div class="name">Atmos / Daily</div>
          <div class="sub">Meteorological summary</div>
        </div>
      </div>
      <div class="topbar-right">
        <div class="meta-chip">
          <span class="dot"></span>
          <span class="label">Live</span>
          <span class="value" id="live-time">--:-- UTC</span>
        </div>
        <div class="meta-chip">
          <span class="label">Source</span>
          <span class="value">Open-Meteo</span>
        </div>
      </div>
    </header>

    <!-- Main grid -->
    <main class="main" id="main">
      <!-- Hero panel -->
      <section class="panel hero" id="hero">
        <div class="loading-overlay" id="hero-loader"><div class="loader"></div></div>
        <div id="hero-content" style="display:flex;flex-direction:column;flex:1;">
          <div class="location-row anim d2">
            <div class="location">
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                <path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/>
                <circle cx="12" cy="10" r="3"/>
              </svg>
              <div>
                <div class="loc-name" id="loc-name">Berlin</div>
                <div class="loc-coords" id="loc-coords">52.52° N, 13.41° E</div>
              </div>
            </div>
            <div class="date-block">
              <div class="day" id="date-day">TODAY</div>
              <div class="full" id="date-full">— — —</div>
            </div>
          </div>

          <div class="condition-wrap anim d3">
            <div class="icon-frame" id="icon-frame"></div>
            <div class="condition-text">
              <div class="label">Condition</div>
              <div class="value" id="cond-value">—</div>
              <div class="sub" id="cond-sub">Weather code —</div>
            </div>
          </div>

          <div class="temp-block anim d4">
            <div class="temp-current">
              <div class="num" id="temp-avg">--</div>
              <div class="unit">°C</div>
              <div class="caption">Daily mean</div>
            </div>
            <div class="temp-range">
              <div class="range-item high">
                <div class="pill">H</div>
                <div class="info">
                  <div class="lab">High</div>
                  <div class="val"><span id="temp-max">--</span><span class="deg">°C</span></div>
                </div>
              </div>
              <div class="range-item low">
                <div class="pill">L</div>
                <div class="info">
                  <div class="lab">Low</div>
                  <div class="val"><span id="temp-min">--</span><span class="deg">°C</span></div>
                </div>
              </div>
            </div>
          </div>

          <svg class="spark-mini" id="spark" viewBox="0 0 400 50" preserveAspectRatio="none"></svg>
        </div>
      </section>

      <!-- Hourly panel -->
      <section class="panel hourly" id="hourly">
        <div class="loading-overlay" id="hourly-loader"><div class="loader"></div></div>
        <div class="hourly-head anim d3">
          <div class="title"><span class="accent">24h</span> Temperature curve</div>
          <div class="sub">Hourly · °C</div>
        </div>
        <div class="chart-wrap anim d4">
          <svg id="chart" preserveAspectRatio="none"></svg>
          <div class="tooltip" id="tooltip">
            <div class="t-time">—</div>
            <div class="t-temp"><span class="t-val">--</span><span class="deg">°C</span></div>
          </div>
        </div>
        <div class="chart-legend">
          <span class="leg"><span class="swatch curve"></span>Temperature</span>
          <span class="leg"><span class="swatch dot"></span>Hover for detail</span>
        </div>
      </section>
    </main>

    <footer class="footer anim d4">
      <span>Atmos · Single-day meteorological card</span>
      <div class="right">
        <span>Timezone: UTC</span>
        <span>Units: Celsius</span>
      </div>
    </footer>
  </div>

<script>
(function () {
  "use strict";

  // -------- URL params --------
  function getParams() {
    const p = new URLSearchParams(window.location.search);
    const lat = parseFloat(p.get("lat"));
    const lon = parseFloat(p.get("lon"));
    const name = p.get("name") || "Berlin";
    const dateStr = p.get("date");

    const todayUTC = new Date();
    const yyyy = todayUTC.getUTCFullYear();
    const mm = String(todayUTC.getUTCMonth() + 1).padStart(2, "0");
    const dd = String(todayUTC.getUTCDate()).padStart(2, "0");
    const todayStr = `${yyyy}-${mm}-${dd}`;

    let date = todayStr;
    if (dateStr && /^\d{4}-\d{2}-\d{2}$/.test(dateStr)) {
      date = dateStr;
    }

    return {
      lat: isFinite(lat) ? lat : 52.52,
      lon: isFinite(lon) ? lon : 13.405,
      name,
      date
    };
  }

  // -------- Date helpers --------
  const WEEKDAYS = ["SUNDAY","MONDAY","TUESDAY","WEDNESDAY","THURSDAY","FRIDAY","SATURDAY"];
  const MONTHS = ["January","February","March","April","May","June","July","August","September","October","November","December"];

  function parseDateUTC(s) {
    const [y, m, d] = s.split("-").map(Number);
    return new Date(Date.UTC(y, m - 1, d));
  }
  function isSameDay(a, b) {
    return a.getUTCFullYear() === b.getUTCFullYear()
        && a.getUTCMonth() === b.getUTCMonth()
        && a.getUTCDate() === b.getUTCDate();
  }
  function formatHour(h) {
    return String(h).padStart(2, "0") + ":00";
  }

  // -------- Weather codes --------
  function weatherInfo(code) {
    const map = {
      0:  { label: "Clear sky",        icon: "sun" },
      1:  { label: "Mainly clear",     icon: "sun-cloud" },
      2:  { label: "Partly cloudy",    icon: "sun-cloud" },
      3:  { label: "Overcast",         icon: "cloud" },
      45: { label: "Fog",              icon: "fog" },
      48: { label: "Rime fog",         icon: "fog" },
      51: { label: "Light drizzle",    icon: "drizzle" },
      53: { label: "Drizzle",          icon: "drizzle" },
      55: { label: "Heavy drizzle",    icon: "drizzle" },
      56: { label: "Freezing drizzle", icon: "drizzle" },
      57: { label: "Freezing drizzle", icon: "drizzle" },
      61: { label: "Light rain",       icon: "rain" },
      63: { label: "Rain",             icon: "rain" },
      65: { label: "Heavy rain",       icon: "rain" },
      66: { label: "Freezing rain",    icon: "rain" },
      67: { label: "Freezing rain",    icon: "rain" },
      71: { label: "Light snow",       icon: "snow" },
      73: { label: "Snow",             icon: "snow" },
      75: { label: "Heavy snow",       icon: "snow" },
      77: { label: "Snow grains",      icon: "snow" },
      80: { label: "Light showers",    icon: "rain" },
      81: { label: "Showers",          icon: "rain" },
      82: { label: "Violent showers",  icon: "rain" },
      85: { label: "Snow showers",     icon: "snow" },
      86: { label: "Snow showers",     icon: "snow" },
      95: { label: "Thunderstorm",     icon: "storm" },
      96: { label: "Thunderstorm",     icon: "storm" },
      99: { label: "Thunderstorm",     icon: "storm" }
    };
    return map[code] || { label: "Unknown", icon: "cloud" };
  }

  // -------- Icons (SVG strings) --------
  function iconSVG(name) {
    const wrap = (inner) => `<svg viewBox="0 0 64 64" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.4">${inner}</svg>`;
    const sun = `<circle cx="32" cy="32" r="11" fill="url(#sun-g)" stroke="#f5b942"/>
      <g stroke="#f5b942" stroke-width="2.6">
        <line x1="32" y1="8" x2="32" y2="14"/><line x1="32" y1="50" x2="32" y2="56"/>
        <line x1="8" y1="32" x2="14" y2="32"/><line x1="50" y1="32" x2="56" y2="32"/>
        <line x1="15" y1="15" x2="19" y2="19"/><line x1="45" y1="45" x2="49" y2="49"/>
        <line x1="15" y1="49" x2="19" y2="45"/><line x1="45" y1="19" x2="49" y2="15"/>
      </g>
      <defs><radialGradient id="sun-g"><stop offset="0%" stop-color="#fff1c7"/><stop offset="100%" stop-color="#f5b942"/></radialGradient></defs>`;
    const cloud = `<path d="M22 44h22a9 9 0 0 0 1-17.9 13 13 0 0 0-25.2 3.5A8 8 0 0 0 22 44z" fill="rgba(180,190,205,0.18)" stroke="#c8d0dc"/>`;
    const suncloud = `<circle cx="22" cy="22" r="7" fill="url(#sun-g2)" stroke="#f5b942"/>
      <g stroke="#f5b942" stroke-width="2.2">
        <line x1="22" y1="6" x2="22" y2="10"/><line x1="6" y1="22" x2="10" y2="22"/>
        <line x1="11" y1="11" x2="14" y2="14"/><line x1="33" y1="11" x2="30" y2="14"/>
      </g>
      <path d="M24 52h20a8 8 0 0 0 1-16 12 12 0 0 0-22.6 2.5A7 7 0 0 0 24 52z" fill="rgba(180,190,205,0.22)" stroke="#c8d0dc"/>
      <defs><radialGradient id="sun-g2"><stop offset="0%" stop-color="#fff1c7"/><stop offset="100%" stop-color="#f5b942"/></radialGradient></defs>`;
    const fog = `<path d="M18 34h28" stroke="#c8d0dc" stroke-width="3"/>
      <path d="M14 42h36" stroke="#c8d0dc" stroke-width="3" opacity="0.85"/>
      <path d="M20 50h24" stroke="#c8d0dc" stroke-width="3" opacity="0.7"/>`;
    const drizzle = `<path d="M22 38h22a9 9 0 0 0 1-17.9 13 13 0 0 0-25.2 3.5A8 8 0 0 0 22 38z" fill="rgba(180,190,205,0.18)" stroke="#c8d0dc"/>
      <line x1="24" y1="44" x2="22" y2="50" stroke="#6dd5ed" stroke-width="2.6"/>
      <line x1="32" y1="44" x2="30" y2="50" stroke="#6dd5ed" stroke-width="2.6"/>
      <line x1="40" y1="44" x2="38" y2="50" stroke="#6dd5ed" stroke-width="2.6"/>`;
    const rain = `<path d="M22 36h22a9 9 0 0 0 1-17.9 13 13 0 0 0-25.2 3.5A8 8 0 0 0 22 36z" fill="rgba(180,190,205,0.18)" stroke="#c8d0dc"/>
      <line x1="24" y1="42" x2="20" y2="54" stroke="#6dd5ed" stroke-width="2.8"/>
      <line x1="34" y1="42" x2="30" y2="54" stroke="#6dd5ed" stroke-width="2.8"/>
      <line x1="44" y1="42" x2="40" y2="54" stroke="#6dd5ed" stroke-width="2.8"/>`;
    const snow = `<path d="M22 36h22a9 9 0 0 0 1-17.9 13 13 0 0 0-25.2 3.5A8 8 0 0 0 22 36z" fill="rgba(180,190,205,0.18)" stroke="#c8d0dc"/>
      <g stroke="#e8f4ff" stroke-width="2.2">
        <line x1="24" y1="46" x2="24" y2="54"/><line x1="20" y1="50" x2="28" y2="50"/>
        <line x1="34" y1="46" x2="34" y2="54"/><line x1="30" y1="50" x2="38" y2="50"/>
        <line x1="44" y1="46" x2="44" y2="54"/><line x1="40" y1="50" x2="48" y2="50"/>
      </g>`;
    const storm = `<path d="M22 32h22a9 9 0 0 0 1-17.9 13 13 0 0 0-25.2 3.5A8 8 0 0 0 22 32z" fill="rgba(180,190,205,0.18)" stroke="#c8d0dc"/>
      <path d="M34 36 L26 50 L32 50 L28 60 L40 44 L34 44 L38 36 Z" fill="#f5b942" stroke="#f5b942" stroke-width="1.2"/>`;
    const icons = { sun, "sun-cloud": suncloud, cloud, fog, drizzle, rain, snow, storm };
    return wrap(icons[name] || cloud);
  }

  // -------- DOM refs --------
  const $ = (id) => document.getElementById(id);
  const heroLoader = $("hero-loader");
  const hourlyLoader = $("hourly-loader");
  const heroContent = $("hero-content");
  const mainEl = $("main");

  // -------- Render error --------
  function showError(message, detail) {
    heroLoader.classList.add("hide");
    hourlyLoader.classList.add("hide");
    mainEl.innerHTML = `
      <section class="panel" style="grid-column: 1 / -1; padding: 60px;">
        <div class="error-state">
          <div class="icon">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
              <path d="M12 9v4"/><path d="M12 17h.01"/>
              <path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/>
            </svg>
          </div>
          <h2>Weather data unavailable</h2>
          <p>${message}</p>
          <div class="code">${detail || ""}</div>
        </div>
      </section>`;
  }

  // -------- Render hero --------
  function renderHero(data, params) {
    const d = data.daily;
    const dateObj = parseDateUTC(params.date);
    const now = new Date();
    const todayUTC = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
    let dayLabel = WEEKDAYS[dateObj.getUTCDay()];
    if (isSameDay(dateObj, todayUTC)) dayLabel = "TODAY";
    else {
      const diff = Math.round((dateObj - todayUTC) / 86400000);
      if (diff === 1) dayLabel = "TOMORROW";
      else if (diff === -1) dayLabel = "YESTERDAY";
    }

    const info = weatherInfo(d.weather_code[0]);

    $("loc-name").textContent = params.name;
    $("loc-coords").textContent = `${Math.abs(params.lat).toFixed(2)}° ${params.lat >= 0 ? "N" : "S"}, ${Math.abs(params.lon).toFixed(2)}° ${params.lon >= 0 ? "E" : "W"}`;
    $("date-day").textContent = dayLabel;
    $("date-full").textContent = `${MONTHS[dateObj.getUTCMonth()]} ${dateObj.getUTCDate()}, ${dateObj.getUTCFullYear()}`;

    $("icon-frame").innerHTML = iconSVG(info.icon);
    $("cond-value").textContent = info.label;
    $("cond-sub").textContent = `WMO code ${d.weather_code[0]}`;

    const tmax = d.temperature_2m_max[0];
    const tmin = d.temperature_2m_min[0];
    const tavg = (tmax + tmin) / 2;

    $("temp-max").textContent = Math.round(tmax);
    $("temp-min").textContent = Math.round(tmin);
    $("temp-avg").textContent = Math.round(tavg);

    renderSpark(data.hourly);

    heroLoader.classList.add("hide");
  }

  // -------- Render mini sparkline --------
  function renderSpark(hourly) {
    const svg = $("spark");
    const W = 400, H = 50, pad = 4;
    const temps = hourly.temperature_2m;
    const min = Math.min.apply(null, temps);
    const max = Math.max.apply(null, temps);
    const range = Math.max(0.1, max - min);
    const step = (W - pad * 2) / (temps.length - 1);

    const pts = temps.map((t, i) => {
      const x = pad + i * step;
      const y = pad + (1 - (t - min) / range) * (H - pad * 2);
      return [x, y];
    });

    const path = pts.map((p, i) => (i === 0 ? `M${p[0]},${p[1]}` : `L${p[0]},${p[1]}`)).join(" ");
    const area = `${path} L${pts[pts.length-1][0]},${H} L${pts[0][0]},${H} Z`;

    svg.innerHTML = `
      <defs>
        <linearGradient id="spark-grad" x1="0" y1="0" x2="1" y2="0">
          <stop offset="0%" stop-color="#6dd5ed"/>
          <stop offset="100%" stop-color="#f5b942"/>
        </linearGradient>
        <linearGradient id="spark-fill" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stop-color="rgba(245,185,66,0.18)"/>
          <stop offset="100%" stop-color="rgba(245,185,66,0)"/>
        </linearGradient>
      </defs>
      <path d="${area}" fill="url(#spark-fill)"/>
      <path d="${path}" fill="none" stroke="url(#spark-grad)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
    `;
  }

  // -------- Render main chart --------
  let chartGeometry = null;

  function renderChart(hourly) {
    const svg = $("chart");
    const rect = svg.getBoundingClientRect();
    const W = rect.width, H = rect.height;
    svg.setAttribute("viewBox", `0 0 ${W} ${H}`);

    const padL = 48, padR = 24, padT = 26, padB = 38;
    const innerW = W - padL - padR;
    const innerH = H - padT - padB;

    const temps = hourly.temperature_2m;
    const times = hourly.time;

    const tmax = Math.max.apply(null, temps);
    const tmin = Math.min.apply(null, temps);
    const tAvgMax = Math.ceil(tmax + 1);
    const tAvgMin = Math.floor(tmin - 1);
    const range = Math.max(1, tAvgMax - tAvgMin);

    const stepX = innerW / (temps.length - 1);
    const xAt = (i) => padL + i * stepX;
    const yAt = (t) => padT + (1 - (t - tAvgMin) / range) * innerH;

    // Smooth path via Catmull-Rom -> Bezier
    const pts = temps.map((t, i) => [xAt(i), yAt(t)]);
    function smoothPath(points) {
      if (points.length < 2) return "";
      let d = `M ${points[0][0]},${points[0][1]}`;
      for (let i = 0; i < points.length - 1; i++) {
        const p0 = points[i - 1] || points[i];
        const p1 = points[i];
        const p2 = points[i + 1];
        const p3 = points[i + 2] || p2;
        const cp1x = p1[0] + (p2[0] - p0[0]) / 6;
        const cp1y = p1[1] + (p2[1] - p0[1]) / 6;
        const cp2x = p2[0] - (p3[0] - p1[0]) / 6;
        const cp2y = p2[1] - (p3[1] - p1[1]) / 6;
        d += ` C ${cp1x},${cp1y} ${cp2x},${cp2y} ${p2[0]},${p2[1]}`;
      }
      return d;
    }
    const linePath = smoothPath(pts);
    const areaPath = `${linePath} L ${pts[pts.length-1][0]},${padT + innerH} L ${pts[0][0]},${padT + innerH} Z`;

    // Y axis ticks
    const yTicks = [];
    const tickCount = 5;
    for (let i = 0; i <= tickCount; i++) {
      const val = tAvgMin + (range * i) / tickCount;
      yTicks.push({ val: Math.round(val), y: yAt(val) });
    }

    // X axis labels — every 3 hours
    const xTicks = [];
    for (let i = 0; i < temps.length; i += 3) {
      const hr = parseDateUTC(times[i]).getUTCHours();
      xTicks.push({ x: xAt(i), label: formatHour(hr), i });
    }

    // Find max & min points
    const maxIdx = temps.indexOf(tmax);
    const minIdx = temps.indexOf(tmin);

    // Build SVG
    let gridLines = "";
    let yLabels = "";
    yTicks.forEach(t => {
      gridLines += `<line x1="${padL}" y1="${t.y}" x2="${W - padR}" y2="${t.y}" stroke="rgba(255,255,255,0.05)" stroke-width="1"/>`;
      yLabels += `<text x="${padL - 10}" y="${t.y + 4}" text-anchor="end" font-size="10" fill="#6b7684" font-family="Inter, sans-serif" letter-spacing="0.05em">${t.val}°</text>`;
    });

    let xLabels = "";
    xTicks.forEach(t => {
      xLabels += `<text x="${t.x}" y="${H - padB + 18}" text-anchor="middle" font-size="10" fill="#6b7684" font-family="Inter, sans-serif" letter-spacing="0.05em">${t.label}</text>`;
    });

    // Markers for max & min
    const markers = `
      <g>
        <circle cx="${xAt(maxIdx)}" cy="${yAt(tmax)}" r="5" fill="#f5b942" stroke="#0a0d12" stroke-width="2"/>
        <text x="${xAt(maxIdx)}" y="${yAt(tmax) - 12}" text-anchor="middle" font-size="11" font-weight="600" fill="#f5b942" font-family="Inter, sans-serif">${Math.round(tmax)}°</text>
      </g>
      <g>
        <circle cx="${xAt(minIdx)}" cy="${yAt(tmin)}" r="5" fill="#6dd5ed" stroke="#0a0d12" stroke-width="2"/>
        <text x="${xAt(minIdx)}" y="${yAt(tmin) + 20}" text-anchor="middle" font-size="11" font-weight="600" fill="#6dd5ed" font-family="Inter, sans-serif">${Math.round(tmin)}°</text>
      </g>
    `;

    svg.innerHTML = `
      <defs>
        <linearGradient id="line-grad" x1="0" y1="0" x2="1" y2="0">
          <stop offset="0%" stop-color="#6dd5ed"/>
          <stop offset="55%" stop-color="#f5b942"/>
          <stop offset="100%" stop-color="#ff8a5b"/>
        </linearGradient>
        <linearGradient id="area-grad" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stop-color="rgba(245,185,66,0.22)"/>
          <stop offset="50%" stop-color="rgba(245,185,66,0.06)"/>
          <stop offset="100%" stop-color="rgba(245,185,66,0)"/>
        </linearGradient>
        <filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
          <feGaussianBlur stdDeviation="3" result="b"/>
          <feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
        </filter>
      </defs>
      ${gridLines}
      ${yLabels}
      ${xLabels}
      <path d="${areaPath}" fill="url(#area-grad)"/>
      <path d="${linePath}" fill="none" stroke="url(#line-grad)" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" filter="url(#glow)"/>
      ${markers}
      <line id="hover-line" x1="0" y1="${padT}" x2="0" y2="${padT + innerH}" stroke="rgba(255,255,255,0.25)" stroke-width="1" stroke-dasharray="3 3" style="opacity:0"/>
      <circle id="hover-dot" cx="0" cy="0" r="5" fill="#fff" stroke="#f5b942" stroke-width="2" style="opacity:0"/>
    `;

    chartGeometry = { pts, temps, times, padL, padR, padT, padB, innerW, innerH, W, H };
    attachHover(svg);
    hourlyLoader.classList.add("hide");
  }

  // -------- Hover interaction --------
  function attachHover(svg) {
    const tooltip = $("tooltip");
    const hoverLine = svg.querySelector("#hover-line");
    const hoverDot = svg.querySelector("#hover-dot");
    const wrap = svg.parentElement;

    function onMove(e) {
      if (!chartGeometry) return;
      const rect = svg.getBoundingClientRect();
      const x = e.clientX - rect.left;
      const { pts, temps, times, padT, padB, innerH } = chartGeometry;

      // nearest point
      let nearest = 0;
      let bestDist = Infinity;
      for (let i = 0; i < pts.length; i++) {
        const d = Math.abs(pts[i][0] - x);
        if (d < bestDist) { bestDist = d; nearest = i; }
      }
      const p = pts[nearest];
      hoverLine.setAttribute("x1", p[0]);
      hoverLine.setAttribute("x2", p[0]);
      hoverLine.setAttribute("y1", padT);
      hoverLine.setAttribute("y2", padT + innerH);
      hoverLine.style.opacity = 1;
      hoverDot.setAttribute("cx", p[0]);
      hoverDot.setAttribute("cy", p[1]);
      hoverDot.style.opacity = 1;

      const hr = parseDateUTC(times[nearest]).getUTCHours();
      tooltip.querySelector(".t-time").textContent = formatHour(hr) + " UTC";
      tooltip.querySelector(".t-val").textContent = Math.round(temps[nearest]);
      tooltip.style.left = p[0] + "px";
      tooltip.style.top = p[1] + "px";
      tooltip.classList.add("show");
    }
    function onLeave() {
      hoverLine.style.opacity = 0;
      hoverDot.style.opacity = 0;
      tooltip.classList.remove("show");
    }
    svg.addEventListener("mousemove", onMove);
    svg.addEventListener("mouseleave", onLeave);
  }

  // -------- Live clock --------
  function tickClock() {
    const now = new Date();
    const h = String(now.getUTCHours()).padStart(2, "0");
    const m = String(now.getUTCMinutes()).padStart(2, "0");
    $("live-time").textContent = `${h}:${m} UTC`;
  }
  setInterval(tickClock, 1000 * 30);
  tickClock();

  // -------- Fetch --------
  async function load() {
    const params = getParams();
    const dateObj = parseDateUTC(params.date);
    const todayUTC = new Date();
    todayUTC.setUTCHours(0, 0, 0, 0);
    const isPast = dateObj < todayUTC;

    const endpoint = isPast ? "/api/om/archive" : "/api/om/forecast";
    const qs = new URLSearchParams({
      latitude: params.lat,
      longitude: params.lon,
      daily: "temperature_2m_max,temperature_2m_min,weather_code",
      hourly: "temperature_2m",
      timezone: "UTC",
      temperature_unit: "celsius",
      start_date: params.date,
      end_date: params.date
    });
    const url = `${endpoint}?${qs.toString()}`;

    try {
      const res = await fetch(url, { headers: { "Accept": "application/json" } });
      if (!res.ok) {
        throw new Error(`API responded with status ${res.status}`);
      }
      const data = await res.json();
      if (!data || !data.daily || !data.hourly ||
          !data.daily.time || data.daily.time.length === 0 ||
          !data.hourly.time || data.hourly.time.length === 0) {
        throw new Error("Malformed response: missing data fields.");
      }
      // Filter hourly to only the requested date (in case archive returns adjacent hours)
      const filteredTemps = [];
      const filteredTimes = [];
      for (let i = 0; i < data.hourly.time.length; i++) {
        if (data.hourly.time[i].startsWith(params.date)) {
          filteredTimes.push(data.hourly.time[i]);
          filteredTemps.push(data.hourly.temperature_2m[i]);
        }
      }
      if (filteredTimes.length === 0) {
        throw new Error("No hourly data available for the requested date.");
      }
      data.hourly.time = filteredTimes;
      data.hourly.temperature_2m = filteredTemps;

      renderHero(data, params);
      // Render chart after layout settles
      requestAnimationFrame(() => renderChart(data.hourly));
    } catch (err) {
      console.error(err);
      showError(
        "We couldn't retrieve the meteorological data for the requested location and date. Please verify the parameters and try again.",
        err && err.message ? err.message : "Unknown error"
      );
    }
  }

  // Re-render chart on resize (kept simple; viewport is fixed)
  window.addEventListener("resize", () => {
    if (chartGeometry && chartGeometry.hourly) return;
  });

  load();
})();
</script>
</body>
</html>

L1 — cheap deterministic descriptors

bytes total38,538html / css / js4,836 / 13,599 / 20,103
dom nodes92dom depth12
css rules90js presentyes
brightness24.5contrast17.4
colorfulness10.6whitespace96.2%

This slot's telemetry

prompt tokens313completion tokens12,595
total tokens12,908wall133.4 s
costrequest id
config.json559 B
{
  "N": 4,
  "auth": {
    "credential_ref": "WCB_BIGMODEL_KEY",
    "method": "api-key"
  },
  "billing": "metered",
  "config_id": "glm-5.2-eff-disabled--api--official--dev",
  "effort": "disabled",
  "family": "glm",
  "m": {
    "min": 4,
    "q": 4
  },
  "model_id": "glm-5.2",
  "protocol": "api",
  "served_model": "glm-5.2",
  "telemetry": {
    "completion_tokens": 62679,
    "cost_usd": null,
    "prompt_tokens": 2472,
    "total_tokens": 65151,
    "wall_ms": 781803
  },
  "transport": "bigmodel-openai-compat",
  "vendor_sanction_ref": null
}
send-log4.6 KB
{
  "N": 4,
  "batch_id": "2026-07-20--official-glm",
  "config_id": "glm-5.2-eff-disabled--api--official--dev",
  "positions": [
    {
      "attempts": [
        {
          "attempt_index": 0,
          "backoff_ms": null,
          "charged": true,
          "ended_at": "2026-07-20T13:55:49.778640+00:00",
          "http_status": 200,
          "outcome": "valid",
          "reached_model": true,
          "reason": "ok",
          "request_id": null,
          "started_at": "2026-07-20T13:54:35.649134+00:00"
        }
      ],
      "block_index": 0,
      "model_reaching_attempt_index": 0,
      "slot_index": 0,
      "terminal_state": "valid",
      "variant": "P-min"
    },
    {
      "attempts": [
        {
          "attempt_index": 0,
          "backoff_ms": null,
          "charged": true,
          "ended_at": "2026-07-20T13:58:07.410206+00:00",
          "http_status": 200,
          "outcome": "valid",
          "reached_model": true,
          "reason": "ok",
          "request_id": null,
          "started_at": "2026-07-20T13:55:53.991127+00:00"
        }
      ],
      "block_index": 0,
      "model_reaching_attempt_index": 0,
      "slot_index": 0,
      "terminal_state": "valid",
      "variant": "P-q"
    },
    {
      "attempts": [
        {
          "attempt_index": 0,
          "backoff_ms": null,
          "charged": true,
          "ended_at": "2026-07-20T13:58:48.746307+00:00",
          "http_status": 200,
          "outcome": "valid",
          "reached_model": true,
          "reason": "ok",
          "request_id": null,
          "started_at": "2026-07-20T13:58:11.076804+00:00"
        }
      ],
      "block_index": 1,
      "model_reaching_attempt_index": 0,
      "slot_index": 1,
      "terminal_state": "valid",
      "variant": "P-min"
    },
    {
      "attempts": [
        {
          "attempt_index": 0,
          "backoff_ms": null,
          "charged": true,
          "ended_at": "2026-07-20T14:01:07.535466+00:00",
          "http_status": 200,
          "outcome": "valid",
          "reached_model": true,
          "reason": "ok",
          "request_id": null,
          "started_at": "2026-07-20T13:58:52.663415+00:00"
        }
      ],
      "block_index": 1,
      "model_reaching_attempt_index": 0,
      "slot_index": 1,
      "terminal_state": "valid",
      "variant": "P-q"
    },
    {
      "attempts": [
        {
          "attempt_index": 0,
          "backoff_ms": null,
          "charged": true,
          "ended_at": "2026-07-20T14:03:02.832266+00:00",
          "http_status": 200,
          "outcome": "valid",
          "reached_model": true,
          "reason": "ok",
          "request_id": null,
          "started_at": "2026-07-20T14:01:11.197130+00:00"
        }
      ],
      "block_index": 2,
      "model_reaching_attempt_index": 0,
      "slot_index": 2,
      "terminal_state": "valid",
      "variant": "P-q"
    },
    {
      "attempts": [
        {
          "attempt_index": 0,
          "backoff_ms": null,
          "charged": true,
          "ended_at": "2026-07-20T14:04:29.995173+00:00",
          "http_status": 200,
          "outcome": "valid",
          "reached_model": true,
          "reason": "ok",
          "request_id": null,
          "started_at": "2026-07-20T14:03:07.729113+00:00"
        }
      ],
      "block_index": 2,
      "model_reaching_attempt_index": 0,
      "slot_index": 2,
      "terminal_state": "valid",
      "variant": "P-min"
    },
    {
      "attempts": [
        {
          "attempt_index": 0,
          "backoff_ms": null,
          "charged": true,
          "ended_at": "2026-07-20T14:06:52.541402+00:00",
          "http_status": 200,
          "outcome": "valid",
          "reached_model": true,
          "reason": "ok",
          "request_id": null,
          "started_at": "2026-07-20T14:04:33.388379+00:00"
        }
      ],
      "block_index": 3,
      "model_reaching_attempt_index": 0,
      "slot_index": 3,
      "terminal_state": "valid",
      "variant": "P-q"
    },
    {
      "attempts": [
        {
          "attempt_index": 0,
          "backoff_ms": null,
          "charged": true,
          "ended_at": "2026-07-20T14:08:48.519668+00:00",
          "http_status": 200,
          "outcome": "valid",
          "reached_model": true,
          "reason": "ok",
          "request_id": null,
          "started_at": "2026-07-20T14:07:39.845687+00:00"
        }
      ],
      "block_index": 3,
      "model_reaching_attempt_index": 0,
      "slot_index": 3,
      "terminal_state": "valid",
      "variant": "P-min"
    }
  ],
  "retry_policy": {
    "max_unreachable_retries": 5,
    "rate_limit_backoff": {
      "max_attempts": 4,
      "max_total_ms": 60000
    }
  }
}