SummerProject2026/dashboard/index.html

386 lines
22 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Sample-based research on the first-attempt non-pass outcome of a returning vehicle's next emissions inspection.">
<meta name="referrer" content="no-referrer">
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; font-src 'self'; object-src 'none'; base-uri 'none'; form-action 'none'">
<title>Overview · Utah Vehicle Health</title>
<link rel="stylesheet" href="./styles.css">
<script type="module" src="./js/app.js"></script>
</head>
<body>
<a class="skip-link" href="#main-content">Skip to dashboard content</a>
<div id="preview-banner" class="preview-banner" role="status" hidden>
<span class="preview-banner__icon" aria-hidden="true"></span>
<div>
<strong id="preview-title">Development preview</strong>
<span id="preview-copy">Private 10,000-vehicle development sample · suppressed aggregates only · not population estimates.</span>
</div>
</div>
<header class="site-header">
<div class="site-header__inner">
<a class="brand" href="#overview" aria-label="Utah Vehicle Health overview">
<svg class="brand__mark" viewBox="0 0 56 56" aria-hidden="true">
<path d="M9 43 23 17l7 12 6-9 12 23H9Z" fill="currentColor"></path>
<path d="m18 43 9-16 6 10 4-6 6 12H18Z" fill="var(--sand-100)"></path>
</svg>
<span>
<span class="brand__name">Utah Vehicle Health</span>
<span class="brand__tagline">Returning vehicles · next first attempt</span>
</span>
</a>
<div class="header-status" id="header-status" aria-live="polite">
<span class="status-dot" aria-hidden="true"></span>
<span>Loading approved aggregates…</span>
</div>
</div>
<nav class="primary-nav" aria-label="Dashboard views">
<div class="primary-nav__inner">
<a href="#overview" data-route="overview" aria-current="page">Overview</a>
<a href="#cohorts" data-route="cohorts">Sample cohorts</a>
<a href="#model" data-route="model">Model &amp; benchmark</a>
<a href="#methods" data-route="methods">Data &amp; methods</a>
</div>
</nav>
</header>
<main id="main-content" tabindex="-1">
<section class="view" id="view-overview" data-view="overview" aria-labelledby="overview-heading">
<div class="page-shell">
<header class="page-heading page-heading--split">
<div>
<p class="eyebrow">Private 10,000-vehicle development sample</p>
<h1 id="overview-heading">The next inspection, in sample context</h1>
<p class="lede">The research question is intentionally narrow: predict whether a returning vehicle's next inspection episode has a first-attempt non-pass. Non-pass combines fail, reject, and abort.</p>
</div>
<div class="data-stamp" aria-label="Dataset status">
<span>Data through</span>
<strong id="data-cutoff">Unavailable</strong>
<small id="model-version">Waiting for manifest</small>
</div>
</header>
<aside class="scope-strip" aria-label="Result scope">
<strong>Sample-based only</strong>
<span>Every value on this page describes the private development sample and covered feeds—not Utah's vehicle population.</span>
</aside>
<div class="unavailable-state" data-unavailable hidden role="status">
<div class="unavailable-state__icon" aria-hidden="true">!</div>
<div>
<h2>Dashboard data is unavailable</h2>
<p data-unavailable-message>The approved aggregate files could not be validated. No estimates are being shown.</p>
</div>
</div>
<section class="kpi-grid" aria-label="Overview statistics" data-requires-data>
<article class="kpi-card">
<span class="kpi-card__label">Published episode support</span>
<strong id="kpi-eligible"></strong>
<small>Rounded total; sampled vehicles may contribute multiple eligible episodes</small>
</article>
<article class="kpi-card kpi-card--pass">
<span class="kpi-card__label">Observed sample pass rate</span>
<strong id="kpi-pass"></strong>
<small>Recognized first-attempt outcomes</small>
</article>
<article class="kpi-card kpi-card--nonpass">
<span class="kpi-card__label">Observed sample non-pass rate</span>
<strong id="kpi-nonpass"></strong>
<small>Fail + reject + abort</small>
</article>
<article class="kpi-card">
<span class="kpi-card__label">Covered county feeds</span>
<strong id="kpi-counties"></strong>
<small>Not statewide coverage</small>
</article>
</section>
<div class="dashboard-grid dashboard-grid--wide" data-requires-data>
<article class="panel panel--wide">
<header class="panel__header">
<div>
<p class="eyebrow">Sample association over time</p>
<h2>Observed first-attempt non-pass trend</h2>
</div>
<div class="chart-legend" aria-label="Outcome legend">
<span><i class="legend-swatch legend-swatch--fail"></i>Non-pass (fail + reject + abort)</span>
</div>
</header>
<div id="outcome-trend-chart" class="chart chart--large" role="img" aria-label="Quarterly inspection outcome rates"></div>
<p class="chart-note" id="outcome-trend-note">Partial periods and source changes are called out when present.</p>
</article>
<article class="panel">
<header class="panel__header">
<div>
<p class="eyebrow">Feed availability</p>
<h2>County coverage</h2>
</div>
</header>
<div id="utah-coverage-map" class="utah-map" role="img" aria-label="Utah county-feed coverage"></div>
<div id="county-coverage-list" class="county-list" aria-label="County availability list"></div>
<p class="chart-note">Availability only—this is not a county outcome ranking. Teal feeds are represented in the sample; gray counties are unavailable, not zero.</p>
</article>
<article class="panel">
<header class="panel__header">
<div>
<p class="eyebrow">Sample association by age</p>
<h2>Observed non-pass rate by vehicle age</h2>
</div>
</header>
<div id="age-risk-chart" class="chart" role="img" aria-label="Published non-pass risk by vehicle-age band"></div>
<p class="chart-note">Sample aggregates only, without confidence intervals. The pattern is descriptive and not a population estimate or causal effect.</p>
</article>
</div>
<aside class="callout" data-requires-data>
<span class="callout__icon" aria-hidden="true">i</span>
<p><strong>What this measures:</strong> sampled returning vehicles' next-episode first-attempt emissions-inspection outcomes in covered feeds. It is not a population estimate, mechanical diagnosis, safety assessment, or legal determination.</p>
</aside>
</div>
</section>
<section class="view" id="view-cohorts" data-view="cohorts" aria-labelledby="cohorts-heading" hidden>
<div class="page-shell">
<header class="page-heading">
<p class="eyebrow">Private 10,000-vehicle development sample</p>
<h1 id="cohorts-heading">Sample cohort explorer</h1>
<p class="lede">Explore supported prior make-and-model cohorts and their observed next-episode first-attempt non-pass rates. These are sample associations—not reliability grades or individual predictions.</p>
</header>
<aside class="scope-strip" aria-label="Result scope">
<strong>Not a ranking of population reliability</strong>
<span>Rates use rounded, suppressed episode support from sampled vehicles. Cohorts can differ in age, history, period, and coverage.</span>
</aside>
<div class="unavailable-state" data-unavailable hidden role="status">
<div class="unavailable-state__icon" aria-hidden="true">!</div>
<div><h2>Explorer unavailable</h2><p data-unavailable-message>Approved scorecards could not be validated.</p></div>
</div>
<div class="explorer-layout" data-requires-data>
<aside class="filter-panel" aria-labelledby="filter-heading">
<div class="filter-panel__heading">
<h2 id="filter-heading">Find a cohort</h2>
<button class="text-button" id="reset-filters" type="button">Reset</button>
</div>
<form id="explorer-filters">
<label class="field">
<span>Make or model</span>
<input id="cohort-search" type="search" autocomplete="off" placeholder="Search supported cohorts">
</label>
<p class="filter-panel__note"><strong>Published grain:</strong> prior make and model only. County, age, fuel, program, and period slices are not available for these scorecards.</p>
</form>
</aside>
<div class="explorer-results">
<div class="result-toolbar">
<p id="result-summary" aria-live="polite">Loading supported cohorts…</p>
<label class="field field--inline">
<span>Sort</span>
<select id="result-sort">
<option value="support">Largest support</option>
<option value="risk-desc">Highest observed sample rate</option>
<option value="risk-asc">Lowest observed sample rate</option>
<option value="name">Make and model</option>
</select>
</label>
</div>
<article class="panel">
<header class="panel__header">
<div><p class="eyebrow">Descriptive sample comparison</p><h2>Observed cohort associations</h2></div>
</header>
<div id="cohort-dot-plot" class="chart chart--scorecard" role="img" aria-label="Observed development-sample cohort non-pass rates"></div>
<p class="chart-note">Ordering is a viewing aid within this sample, not a reliability ranking or population comparison.</p>
</article>
<div id="cohort-cards" class="cohort-cards"></div>
<div class="empty-results" id="empty-results" hidden>
<h2>No supported cohorts match</h2>
<p>Try clearing one or more filters. Suppressed cohorts are never included in the browser bundle.</p>
</div>
</div>
</div>
</div>
</section>
<section class="view" id="view-model" data-view="model" aria-labelledby="model-heading" hidden>
<div class="page-shell page-shell--narrow">
<header class="page-heading">
<p class="eyebrow">Private 10,000-vehicle development sample</p>
<h1 id="model-heading">Model &amp; benchmark</h1>
<p class="lede">Calibrated logistic regression is the final development-prototype model for the next-episode first-attempt non-pass target. The boosted tree is retained only as a benchmark.</p>
</header>
<aside class="scope-strip" aria-label="Result scope">
<strong>Development evidence only</strong>
<span>These 2024 values come from the partition used to fit Platt calibration. They are sample-based calibration checks—not independent final-performance estimates, population estimates, or locked-test results.</span>
</aside>
<div class="unavailable-state" data-unavailable hidden role="status">
<div class="unavailable-state__icon" aria-hidden="true">!</div>
<div><h2>Model diagnostics unavailable</h2><p data-unavailable-message>The approved diagnostic summary could not be validated.</p></div>
</div>
<section class="model-comparison" data-requires-data aria-label="Development model comparison">
<article class="model-card model-card--final">
<div class="model-card__topline"><span class="decision-badge decision-badge--final">Final prototype</span><span>2024 calibration-fit check</span></div>
<h2>Calibrated logistic regression</h2>
<p>The selected model for the research conclusion and any prototype-level discussion. Platt scaling calibrates its probabilities.</p>
<dl class="metric-list">
<div><dt>PR-AUC</dt><dd id="final-ap"></dd></div>
<div><dt>ROC-AUC</dt><dd id="final-roc"></dd></div>
<div><dt>Brier ↓</dt><dd id="final-brier"></dd></div>
</dl>
</article>
<article class="model-card">
<div class="model-card__topline"><span class="decision-badge">Benchmark only</span><span>2024 calibration-fit check</span></div>
<h2>Calibrated boosted tree</h2>
<p>Retained for development comparison only. It does not replace the logistic model or define dashboard outputs.</p>
<dl class="metric-list">
<div><dt>PR-AUC</dt><dd id="benchmark-ap"></dd></div>
<div><dt>ROC-AUC</dt><dd id="benchmark-roc"></dd></div>
<div><dt>Brier ↓</dt><dd id="benchmark-brier"></dd></div>
</dl>
</article>
</section>
<aside class="callout" data-requires-data>
<span class="callout__icon" aria-hidden="true">i</span>
<p><strong>Calibration diagnostic—not a final performance estimate:</strong> Platt scaling was fit on this same 2024 partition. PR-AUC and ROC-AUC summarize discrimination; lower Brier is better for probability error. Opened 2025 holdout metrics are intentionally not displayed here.</p>
</aside>
<section class="publication-boundary" aria-labelledby="publication-boundary-heading">
<div>
<p class="eyebrow">Finished publication boundary</p>
<h2 id="publication-boundary-heading">No vehicle-level prediction service</h2>
<p>This static dashboard serves supported aggregate sample rates and diagnostic summaries only. It contains no vehicle lookup, personal inputs, operational connection, or row-level prediction output.</p>
</div>
<ul class="check-list">
<li>Returning-vehicle next-episode target only</li>
<li>First attempt; pass versus non-pass</li>
<li>Final model: calibrated logistic regression</li>
<li>Boosted tree: benchmark only</li>
</ul>
</section>
</div>
</section>
<section class="view" id="view-methods" data-view="methods" aria-labelledby="methods-heading" hidden>
<div class="page-shell">
<header class="page-heading">
<p class="eyebrow">Private 10,000-vehicle development sample</p>
<h1 id="methods-heading">Data &amp; methods</h1>
<p class="lede">How episodes, labels, temporal evaluation, coverage limits, and privacy controls shape every published result.</p>
</header>
<aside class="scope-strip" aria-label="Result scope">
<strong>Sample-based, not population-based</strong>
<span>All displayed rates and diagnostics come from the development sample. County displays communicate feed coverage only.</span>
</aside>
<div class="unavailable-state" data-unavailable hidden role="status">
<div class="unavailable-state__icon" aria-hidden="true">!</div>
<div><h2>Live diagnostics unavailable</h2><p data-unavailable-message>Static methodology remains below; no performance values are being shown.</p></div>
</div>
<section class="method-grid" aria-label="Core definitions">
<article class="method-card">
<span class="method-card__number">01</span>
<h2>Prediction unit</h2>
<p>The first attempt of the next inspection episode. Attempts no more than 30 days apart form one episode.</p>
</article>
<article class="method-card">
<span class="method-card__number">02</span>
<h2>Binary target</h2>
<p>Pass versus non-pass. Non-pass combines fail, reject, and abort; blanks and unrecognized outcomes are not labels.</p>
</article>
<article class="method-card">
<span class="method-card__number">03</span>
<h2>Point-in-time features</h2>
<p>Every history window ends before the target episode. Current-test results, diagnostics, stations, and later attempts are excluded.</p>
</article>
</section>
<section class="panel" data-requires-data>
<header class="panel__header"><div><p class="eyebrow">Availability by source era</p><h2>Coverage timeline</h2></div></header>
<div id="coverage-heatmap" class="heatmap" role="img" aria-label="Inspection source availability by year"></div>
<p class="chart-note">The <code>slc</code> and <code>slco</code> labels are source eras for Salt Lake County, not separate physical counties.</p>
</section>
<section class="split-section" aria-labelledby="split-heading">
<div class="split-section__copy">
<p class="eyebrow">No random row split</p>
<h2 id="split-heading">Chronological evaluation</h2>
<p>Historical events establish prior context. The 2025 development-sample holdout was evaluated once after model choices were frozen, so it is no longer a pristine final test. A later complete-data run is confirmatory; the partial 2026 feed is monitoring only.</p>
</div>
<ol class="timeline">
<li><span>201015</span><strong>Context</strong><small>History only</small></li>
<li><span>201622</span><strong>Train</strong><small>Fit preprocessing + model</small></li>
<li><span>2023</span><strong>Tune</strong><small>Select regularization</small></li>
<li><span>2024</span><strong>Calibrate</strong><small>Scale probabilities</small></li>
<li class="timeline__holdout"><span>2025</span><strong>One-time holdout</strong><small>Already evaluated</small></li>
<li><span>2026</span><strong>Shadow</strong><small>Partial-period drift</small></li>
</ol>
</section>
<div class="dashboard-grid" data-requires-data>
<article class="panel">
<header class="panel__header"><div><p class="eyebrow">Model governance</p><h2>Evidence status</h2></div></header>
<ul class="limitation-list">
<li>Calibrated logistic regression is the declared final prototype model.</li>
<li>The boosted tree remains a benchmark only.</li>
<li>Published diagnostics cover train, tune, and calibration partitions.</li>
<li>No locked-test result or population performance claim is published.</li>
</ul>
</article>
<article class="panel">
<header class="panel__header"><div><p class="eyebrow">Interpret with care</p><h2>Known limitations</h2></div></header>
<ul class="limitation-list" id="manifest-limitations">
<li>Participating inspection feeds do not cover all 29 counties.</li>
<li>Feed and program changes can resemble real-world trends.</li>
<li>The 10,000-vehicle draw retained 9,996 vehicles; page sampling can over-represent vehicles with more inspection records.</li>
<li>Reject and abort can reflect process or readiness issues.</li>
<li>Association is not causation or a mechanical diagnosis.</li>
</ul>
</article>
</div>
<section class="privacy-panel">
<div><p class="eyebrow">Publication boundary</p><h2>Only approved aggregates reach this site</h2></div>
<div class="privacy-flow" aria-label="Private-to-public data flow">
<span class="privacy-flow__private">Private source<br><small>Read-only local pipeline</small></span>
<span aria-hidden="true"></span>
<span>Suppression<br><small>Minimum support + complements</small></span>
<span aria-hidden="true"></span>
<span class="privacy-flow__public">Public assets<br><small>Suppressed summaries only</small></span>
</div>
<p>VINs, plates, ZIPs, stations, technician identifiers, private vehicle tokens, raw source JSON, credentials, operational records, and row-level predictions are outside this site and its public data contract.</p>
</section>
</div>
</section>
</main>
<footer class="site-footer">
<div class="page-shell site-footer__inner">
<div><strong>Utah Vehicle Health</strong><p>Private 10,000-vehicle development sample.</p></div>
<p>Sample-based research only—not a population estimate, diagnosis, certification, safety assessment, or guarantee of an inspection outcome.</p>
</div>
</footer>
<div id="route-announcer" class="sr-only" aria-live="polite"></div>
<noscript><div class="noscript">JavaScript is required to validate and display the approved aggregate data files. No estimates are shown without validation.</div></noscript>
</body>
</html>