various edits

This commit is contained in:
Kevin Bell 2026-07-21 16:43:22 -06:00
parent 88161a6f16
commit c1e453d962
16 changed files with 526 additions and 31 deletions

View File

@ -57,6 +57,12 @@ contains a denied identifier-like field, the dashboard shows an unavailable
state and no estimates. Regenerate assets with the repository's private local
pipeline; never hand-edit public JSON to bypass suppression.
Previously published cohort definitions are frozen against cross-release
differencing. New canonical model families may be added only when the combined
family clears every publication threshold; aliases or trims must not be folded
into an existing public cell. Increment `PUBLICATION_POLICY_VERSION` whenever
an approved aggregation policy changes.
The site intentionally contains no vehicle lookup, individual estimator,
operational connection, or row-level prediction output. VINs, plates, ZIPs,
stations, technician identifiers, raw source JSON, credentials, and operational

View File

@ -126,7 +126,7 @@
</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>
<p class="chart-note">Availability only—this is not a county outcome ranking. Teal markers show counties represented in the sample; unmarked counties are unavailable, not zero.</p>
</article>
<article class="panel">
@ -177,7 +177,7 @@
<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>
<p class="filter-panel__note"><strong>Published grain:</strong> prior make and model. <strong>Combined model families:</strong> Chevrolet Silverado 1500; Dodge Ram 1500; Hyundai Elantra; Nissan Altima; Subaru Outback; and Toyota 4Runner, Corolla, and Tacoma. <strong>Exact source-label cohorts:</strong> Ford F150; Honda Accord and Civic; and Toyota Camry. County, age, fuel, program, and period slices are not available for these scorecards.</p>
</form>
</aside>
@ -200,7 +200,7 @@
<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>
<p class="chart-note">The filter note distinguishes combined model families from exact source-label cohorts. 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>

View File

@ -230,9 +230,16 @@ function updateExplorer() {
scorecardLabel(row).toLowerCase().includes(query),
);
visibleScorecards = sortedScorecards(matches, sortMode);
const cohortCount = visibleScorecards.length;
let summary = "0 supported sample cohorts.";
if (cohortCount > 0 && cohortCount <= 12) {
summary = `${cohortCount} supported sample cohort${cohortCount === 1 ? "" : "s"}; all shown.`;
} else if (cohortCount > 12) {
summary = `${cohortCount} supported sample cohorts; showing ${Math.min(cohortCount, 18)} cards and 12 chart rows.`;
}
setText(
"result-summary",
`${visibleScorecards.length} supported sample cohort${visibleScorecards.length === 1 ? "" : "s"}; showing up to 18 cards and 12 chart rows.`,
summary,
);
byId("empty-results").hidden = visibleScorecards.length > 0;
renderCohortDotPlot(byId("cohort-dot-plot"), visibleScorecards);

View File

@ -205,37 +205,50 @@ export function renderCohortDotPlot(container, rows) {
);
}
// Simplified from the Census 2025 1:20m cartographic boundary for Utah
// (GEOID 49). Utah's defining step is on the northeast edge, not both sides.
const UTAH_OUTLINE_PATH = "M44 20H153V67H226V255H44Z";
// Census county centers projected into the same Utah map frame.
const COUNTY_POINTS = {
cache: [154, 40],
weber: [137, 86],
davis: [126, 108],
salt_lake: [133, 133],
"salt lake": [133, 133],
utah: [140, 170],
cache: [128, 33],
weber: [123, 54],
davis: [111, 65],
"salt lake": [121, 83],
utah: [131, 108],
};
function normalizeCountyName(county) {
return String(county).trim().toLowerCase().replaceAll("_", " ").replace(/\s+/g, " ");
}
function displayCountyName(county) {
return county.replace(/\b\w/g, (letter) => letter.toUpperCase());
}
export function renderUtahCoverage(container, coveredCounties) {
const normalized = new Set(coveredCounties.map((county) => county.toLowerCase()));
const normalized = new Set(coveredCounties.map(normalizeCountyName));
const points = [...normalized]
.map((county) => ({ county, coordinates: COUNTY_POINTS[county] }))
.filter((item) => item.coordinates);
const countyNames = [...normalized].map(displayCountyName);
container.innerHTML = `
<svg viewBox="0 0 270 300" aria-hidden="true" focusable="false">
<path d="M79 18h101v54l18 18v183H52V116l27-27V18Z" fill="var(--gray-100)" stroke="var(--gray-300)" stroke-width="3"></path>
<path d="M80 20h98v53l17 18v179H55V117l25-27V20Z" fill="none" stroke="var(--sand-200)" stroke-width="1.5" stroke-dasharray="4 5"></path>
<path data-map-feature="utah-outline" d="${UTAH_OUTLINE_PATH}" fill="var(--gray-100)" stroke="var(--gray-300)" stroke-width="3" stroke-linejoin="round" vector-effect="non-scaling-stroke"></path>
${points
.map(
({ county, coordinates }) => `
<circle cx="${coordinates[0]}" cy="${coordinates[1]}" r="8" fill="var(--teal-700)" stroke="var(--paper)" stroke-width="3"><title>${escapeText(county.replace("_", " "))} feed available</title></circle>`,
<circle cx="${coordinates[0]}" cy="${coordinates[1]}" r="8" fill="var(--teal-700)" stroke="var(--paper)" stroke-width="3" vector-effect="non-scaling-stroke"><title>${escapeText(displayCountyName(county))} County feed available</title></circle>`,
)
.join("")}
<text x="135" y="205" text-anchor="middle" class="state-label">UTAH</text>
<text x="135" y="288" text-anchor="middle" class="axis-label">Participating feeds highlighted</text>
</svg>`;
container.setAttribute(
"aria-label",
coveredCounties.length
? `Development-sample feed availability includes ${coveredCounties.join(", ")}. This is not an outcome ranking; other counties are unavailable.`
: "No county feed coverage is available.",
countyNames.length
? `Outline of Utah showing development-sample feed availability for ${countyNames.join(", ")} County feeds. This is not an outcome ranking; other counties are unavailable.`
: "Outline of Utah. No county feed coverage is available.",
);
}

View File

@ -1 +1 @@
{"development_preview":true,"population_estimate_allowed":false,"rows":[{"nonpass_rate":0.116,"prior_make":"FORD","prior_model":"F150","support_rounded":1100},{"nonpass_rate":0.09,"prior_make":"HONDA","prior_model":"ACCORD","support_rounded":400},{"nonpass_rate":0.073,"prior_make":"HONDA","prior_model":"CIVIC","support_rounded":300},{"nonpass_rate":0.086,"prior_make":"TOYOTA","prior_model":"CAMRY","support_rounded":500}],"schema_version":"dashboard_data_v1"}
{"development_preview":true,"population_estimate_allowed":false,"rows":[{"nonpass_rate":0.123,"prior_make":"CHEVROLET","prior_model":"SILVERADO 1500","support_rounded":500},{"nonpass_rate":0.117,"prior_make":"DODGE","prior_model":"RAM 1500","support_rounded":600},{"nonpass_rate":0.116,"prior_make":"FORD","prior_model":"F150","support_rounded":1100},{"nonpass_rate":0.09,"prior_make":"HONDA","prior_model":"ACCORD","support_rounded":400},{"nonpass_rate":0.073,"prior_make":"HONDA","prior_model":"CIVIC","support_rounded":300},{"nonpass_rate":0.094,"prior_make":"HYUNDAI","prior_model":"ELANTRA","support_rounded":500},{"nonpass_rate":0.128,"prior_make":"NISSAN","prior_model":"ALTIMA","support_rounded":500},{"nonpass_rate":0.084,"prior_make":"SUBARU","prior_model":"OUTBACK","support_rounded":600},{"nonpass_rate":0.08,"prior_make":"TOYOTA","prior_model":"4RUNNER","support_rounded":600},{"nonpass_rate":0.086,"prior_make":"TOYOTA","prior_model":"CAMRY","support_rounded":500},{"nonpass_rate":0.082,"prior_make":"TOYOTA","prior_model":"COROLLA","support_rounded":800},{"nonpass_rate":0.08,"prior_make":"TOYOTA","prior_model":"TACOMA","support_rounded":600}],"schema_version":"dashboard_data_v1"}

View File

@ -1 +1 @@
{"assets":["age_risk_curve.json","cohort_scorecard.json","coverage_quality.json","filter_catalog.json","model_diagnostics.json","overview_period_county.json"],"data_scope":{"first_year":2016,"last_year":2024,"model_names":["hist_gradient_boosting_platt","hist_gradient_boosting_raw","logistic_platt","logistic_raw","previous_episode_literal","training_prevalence"],"partitions":["train","tune","calibrate"]},"definitions":{"episode_gap_days":30,"locked_test_metrics_published":false,"support_rounding":100,"suppression_min_distinct_nonpass_vehicles":10,"suppression_min_distinct_pass_vehicles":10,"suppression_min_distinct_vehicles":100,"suppression_min_nonpass":10,"suppression_min_pass":10,"suppression_min_support":100,"target":"first-attempt next-episode binary non-pass rate"},"development_preview":true,"model_versions":["baseline_v1","hist_gradient_boosting_v1"],"population_estimate_allowed":false,"release_id":"7c1af8d22d3841b84d2cf4cd5ba7bce6a43578c78bc3d32a25d200b4b1986704","schema_version":"dashboard_data_v1"}
{"assets":["age_risk_curve.json","cohort_scorecard.json","coverage_quality.json","filter_catalog.json","model_diagnostics.json","overview_period_county.json"],"data_scope":{"first_year":2016,"last_year":2024,"model_names":["hist_gradient_boosting_platt","hist_gradient_boosting_raw","logistic_platt","logistic_raw","previous_episode_literal","training_prevalence"],"partitions":["train","tune","calibrate"]},"definitions":{"episode_gap_days":30,"locked_test_metrics_published":false,"support_rounding":100,"suppression_min_distinct_nonpass_vehicles":10,"suppression_min_distinct_pass_vehicles":10,"suppression_min_distinct_vehicles":100,"suppression_min_nonpass":10,"suppression_min_pass":10,"suppression_min_support":100,"target":"first-attempt next-episode binary non-pass rate"},"development_preview":true,"model_versions":["baseline_v1","hist_gradient_boosting_v1"],"population_estimate_allowed":false,"release_id":"7d207baa6389ff26d6d9fa39da8fd917500bca5f7bdc0ecd090e9ef1a7ca105e","schema_version":"dashboard_data_v1"}

View File

@ -1 +1 @@
{"age_bands":["0-3","4-7","8-11","12-15","16-20","21+"],"development_preview":true,"models":["hist_gradient_boosting_platt","hist_gradient_boosting_raw","logistic_platt","logistic_raw","previous_episode_literal","training_prevalence"],"partitions":["train","tune","calibrate"],"periods":[{"quarters":[1,2,3,4],"year":2016},{"quarters":[1,2,3,4],"year":2017},{"quarters":[1,2,3,4],"year":2018},{"quarters":[1,2,3,4],"year":2019},{"quarters":[1,2,3,4],"year":2020},{"quarters":[1,2,3,4],"year":2021},{"quarters":[1,2,3,4],"year":2022},{"quarters":[1,2,3,4],"year":2023},{"quarters":[1,2,3,4],"year":2024}],"population_estimate_allowed":false,"prior_make_models":[{"prior_make":"FORD","prior_model":"F150"},{"prior_make":"HONDA","prior_model":"ACCORD"},{"prior_make":"HONDA","prior_model":"CIVIC"},{"prior_make":"TOYOTA","prior_model":"CAMRY"}],"public_counties":["salt_lake","utah","weber"],"schema_version":"dashboard_data_v1"}
{"age_bands":["0-3","4-7","8-11","12-15","16-20","21+"],"development_preview":true,"models":["hist_gradient_boosting_platt","hist_gradient_boosting_raw","logistic_platt","logistic_raw","previous_episode_literal","training_prevalence"],"partitions":["train","tune","calibrate"],"periods":[{"quarters":[1,2,3,4],"year":2016},{"quarters":[1,2,3,4],"year":2017},{"quarters":[1,2,3,4],"year":2018},{"quarters":[1,2,3,4],"year":2019},{"quarters":[1,2,3,4],"year":2020},{"quarters":[1,2,3,4],"year":2021},{"quarters":[1,2,3,4],"year":2022},{"quarters":[1,2,3,4],"year":2023},{"quarters":[1,2,3,4],"year":2024}],"population_estimate_allowed":false,"prior_make_models":[{"prior_make":"CHEVROLET","prior_model":"SILVERADO 1500"},{"prior_make":"DODGE","prior_model":"RAM 1500"},{"prior_make":"FORD","prior_model":"F150"},{"prior_make":"HONDA","prior_model":"ACCORD"},{"prior_make":"HONDA","prior_model":"CIVIC"},{"prior_make":"HYUNDAI","prior_model":"ELANTRA"},{"prior_make":"NISSAN","prior_model":"ALTIMA"},{"prior_make":"SUBARU","prior_model":"OUTBACK"},{"prior_make":"TOYOTA","prior_model":"4RUNNER"},{"prior_make":"TOYOTA","prior_model":"CAMRY"},{"prior_make":"TOYOTA","prior_model":"COROLLA"},{"prior_make":"TOYOTA","prior_model":"TACOMA"}],"public_counties":["salt_lake","utah","weber"],"schema_version":"dashboard_data_v1"}

View File

@ -1 +1 @@
{"development_preview":true,"files":[{"name":"age_risk_curve.json","sha256":"5445d52365ad3494ba05f097e7f4f5e41fffeecfe50fbb2952d72044f496c925"},{"name":"cohort_scorecard.json","sha256":"2ae83d9d55aa1f2ccae6420c66350fb491405eedfa90374aa3df2782a4aa0bf1"},{"name":"coverage_quality.json","sha256":"35b7dbed50e1b8260aac18c269f5045010ea23649a649f984a4693f3f00a1e83"},{"name":"data_manifest.json","sha256":"b7196b04eb223683c928cfb5375ed618e1230fa03382bd8a889de24c589557a0"},{"name":"filter_catalog.json","sha256":"9e45d428cd38853002ebd0bda089eb46d0832cd1b7b6b05ac953bc8472b01eb5"},{"name":"model_diagnostics.json","sha256":"ebf99eb32436a5eabb7d754cd88109f2cc0981575dd28966757031ac7faafa57"},{"name":"overview_period_county.json","sha256":"fe2a4233563b47fa31fc87859b100983d3bfb574c5a7fbc7241b9cfb4661b038"}],"population_estimate_allowed":false,"schema_version":"dashboard_data_v1"}
{"development_preview":true,"files":[{"name":"age_risk_curve.json","sha256":"5445d52365ad3494ba05f097e7f4f5e41fffeecfe50fbb2952d72044f496c925"},{"name":"cohort_scorecard.json","sha256":"3acd3aa5a32f53e8f0a2baaad6fec8bb0610efaac8151d8ec4a88285faca23fd"},{"name":"coverage_quality.json","sha256":"35b7dbed50e1b8260aac18c269f5045010ea23649a649f984a4693f3f00a1e83"},{"name":"data_manifest.json","sha256":"8ed1593dd223ddd2fbdcd808040ee6a9f37f078011e821a058a1c7a6d94694d2"},{"name":"filter_catalog.json","sha256":"e78e65ae463edf4ea1b5c757e1a002b5fd953beb75c31381f8264e267295f48e"},{"name":"model_diagnostics.json","sha256":"ebf99eb32436a5eabb7d754cd88109f2cc0981575dd28966757031ac7faafa57"},{"name":"overview_period_county.json","sha256":"fe2a4233563b47fa31fc87859b100983d3bfb574c5a7fbc7241b9cfb4661b038"}],"population_estimate_allowed":false,"schema_version":"dashboard_data_v1"}

View File

@ -658,6 +658,22 @@ main {
margin: 0 auto 1rem;
}
.utah-map .axis-label,
.utah-map .state-label {
fill: var(--ink-650);
font-family: var(--font-sans);
}
.utah-map .axis-label {
font-size: 11px;
}
.utah-map .state-label {
font-size: 12px;
font-weight: 700;
letter-spacing: 0.16em;
}
.county-list {
display: flex;
flex-wrap: wrap;
@ -716,6 +732,10 @@ main {
align-items: start;
}
.explorer-results {
min-width: 0;
}
.filter-panel {
position: sticky;
top: 155px;
@ -1522,6 +1542,15 @@ fieldset:disabled .field select {
justify-content: flex-start;
}
.chart--scorecard {
overflow-x: auto;
overscroll-behavior-inline: contain;
}
.chart--scorecard svg {
min-width: 720px;
}
.locked-panel {
display: block;
}

View File

@ -12,6 +12,7 @@ import {
loadDashboardData,
validateAssetSet,
} from "../js/data.js";
import { renderUtahCoverage } from "../js/charts.js";
const DASHBOARD_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const PUBLIC_DATA = path.join(DASHBOARD_ROOT, "public", "data");
@ -84,13 +85,41 @@ test("narrow layouts constrain body content while preserving local nav scrolling
assert.match(css, /html\s*{[^}]*max-width:\s*100%;[^}]*overflow-x:\s*clip;/s);
assert.match(css, /body\s*{[^}]*max-width:\s*100%;[^}]*overflow-x:\s*clip;/s);
assert.match(css, /\.primary-nav__inner\s*{[^}]*overflow-x:\s*auto;/s);
assert.match(css, /\.explorer-results\s*{[^}]*min-width:\s*0;/s);
const mobile = css.match(/@media \(max-width: 660px\)\s*{[\s\S]*?(?=@media|$)/)?.[0];
assert.ok(mobile, "mobile breakpoint is present");
assert.match(mobile, /\.page-shell\s*{[^}]*width:\s*auto;[^}]*max-width:\s*calc\(100% - 2rem\);/s);
assert.match(mobile, /\.preview-banner\s*{[^}]*justify-content:\s*flex-start;/s);
assert.match(mobile, /\.chart--scorecard\s*{[^}]*overflow-x:\s*auto;/s);
assert.match(mobile, /\.chart--scorecard svg\s*{[^}]*min-width:\s*720px;/s);
assert.match(mobile, /overflow-wrap:\s*anywhere;/);
});
test("county coverage renders Utah's northeast step and geographically aligned feeds", () => {
const attributes = new Map();
const container = {
innerHTML: "",
setAttribute(name, value) {
attributes.set(name, value);
},
};
renderUtahCoverage(container, ["weber", "salt_lake", "utah"]);
assert.match(
container.innerHTML,
/data-map-feature="utah-outline" d="M44 20H153V67H226V255H44Z"/,
);
assert.doesNotMatch(container.innerHTML, /stroke-dasharray/);
assert.equal(container.innerHTML.match(/<circle\b/g)?.length, 3);
assert.match(container.innerHTML, /cx="123" cy="54"[^>]*><title>Weber County/);
assert.match(container.innerHTML, /cx="121" cy="83"[^>]*><title>Salt Lake County/);
assert.match(container.innerHTML, /cx="131" cy="108"[^>]*><title>Utah County/);
assert.match(container.innerHTML, />UTAH<\/text>/);
assert.match(attributes.get("aria-label"), /^Outline of Utah showing/);
assert.doesNotMatch(attributes.get("aria-label"), /_/);
});
test("model view declares the final model, benchmark role, and publication boundary", () => {
const html = readFileSync(path.join(DASHBOARD_ROOT, "index.html"), "utf8");
const modelView = viewSource(html, "model");
@ -120,6 +149,16 @@ test("every result-facing view visibly labels the sample and non-population scop
assert.match(html, /not a reliability ranking or population comparison/i);
});
test("cohort view discloses which rows are combined families", () => {
const html = readFileSync(path.join(DASHBOARD_ROOT, "index.html"), "utf8");
const cohortView = viewSource(html, "cohorts");
assert.match(cohortView, /Combined model families:/);
assert.match(cohortView, /Silverado 1500; Dodge Ram 1500; Hyundai Elantra; Nissan Altima; Subaru Outback;/);
assert.match(cohortView, /Toyota 4Runner, Corolla, and Tacoma/);
assert.match(cohortView, /Exact source-label cohorts:/);
assert.match(cohortView, /Ford F150; Honda Accord and Civic; and Toyota Camry/);
});
test("all required generated assets satisfy the browser contract", () => {
const validated = validateAssetSet(assetSet());
assert.equal(validated.manifest.schema_version, SCHEMA_VERSION);
@ -139,6 +178,14 @@ test("all required generated assets satisfy the browser contract", () => {
["train", "tune", "calibrate"],
);
assert.ok(validated.overview.rows.length > 0);
assert.equal(validated.scorecards.rows.length, 12);
assert.deepEqual(
validated.filters.prior_make_models,
validated.scorecards.rows.map(({ prior_make, prior_model }) => ({
prior_make,
prior_model,
})),
);
});
test("browser loader verifies every raw asset digest before rendering", async () => {

View File

@ -31,6 +31,13 @@ headlined, or described as population county performance.
### Sample cohorts
- Search and compare only supported, suppression-cleared make/model cohorts
- Combine documented source abbreviations and trim labels for newly published
model families before applying the unchanged publication thresholds
- Keep earlier public cohort definitions stable across releases so differences
cannot expose a formerly suppressed slice
- Identify Silverado 1500, Ram 1500, Elantra, Altima, Outback, 4Runner,
Corolla, and Tacoma as combined families; identify F150, Accord, Civic, and
Camry as exact source-label cohorts
- Show observed sample non-pass rates and rounded support
- Default sorting by support rather than risk
- Disable filters or adjusted views that the aggregate bundle cannot support

View File

@ -53,7 +53,9 @@ the “observed sample non-pass” label.
**Say:**
> This view contains only prior make-and-model cohorts that cleared the
> publication thresholds. I can search supported cohorts, but these are observed
> publication thresholds. Selected source abbreviations and trim labels are
> combined for new model families, while earlier published cohorts keep stable
> definitions. I can search supported cohorts, but these are observed
> development-sample associations—not reliability grades, rankings, or
> recommendations. Unsupported slices are not inferred in the browser, and
> suppressed rows are absent rather than hidden.

View File

@ -140,7 +140,9 @@ views:
1. **Overview** shows rounded support, sample outcome patterns, vehicle-age
patterns, and county feed coverage.
2. **Sample cohorts** shows only supported make/model sample aggregates; it does
2. **Sample cohorts** shows only supported make/model sample aggregates;
selected source abbreviations and trim labels are combined for new model
families while earlier published cohorts keep stable definitions. It does
not issue reliability ratings or recommendations.
3. **Model & benchmark** identifies calibrated logistic regression as final and
the boosted tree as benchmark-only. It shows pre-2025, 2024 calibration-fit

View File

@ -132,7 +132,8 @@ population or external-validation results.
- Page sampling is not population-representative.
- Source, program, time, and geography are entangled.
- Reject and abort are heterogeneous non-pass outcomes.
- Make/model aliases and incomplete feed coverage can distort cohorts.
- Residual make/model aliases outside the documented scorecard mappings and
incomplete feed coverage can distort cohorts.
- The one-time 2025 holdout is not an external validation dataset.
- No protected attributes are modeled, but that does not establish fairness.
- Sample calibration does not establish production calibration.

View File

@ -26,6 +26,7 @@ import duckdb
PROJECT_ROOT = Path(__file__).resolve().parents[1]
PUBLIC_DATA_ROOT = (PROJECT_ROOT / "dashboard/public/data").resolve()
SCHEMA_VERSION = "dashboard_data_v1"
PUBLICATION_POLICY_VERSION = "dashboard_publication_policy_v1"
ALLOWED_PARTITIONS = ("train", "tune", "calibrate")
PARTITION_ORDER = {name: index for index, name in enumerate(ALLOWED_PARTITIONS)}
LOCKED_PARTITION_ALIASES = ("test", "locked_test", "locked-test")
@ -641,7 +642,183 @@ def _age_risk_rows(connection: duckdb.DuckDBPyConnection) -> List[Dict[str, obje
def _scorecard_rows(connection: duckdb.DuckDBPyConnection) -> List[Dict[str, object]]:
raw = connection.execute(
"""
SELECT last_observed_make, last_observed_model,
WITH legacy_cells(prior_make, prior_model) AS (
VALUES
('FORD', 'F150'),
('HONDA', 'ACCORD'),
('HONDA', 'CIVIC'),
('TOYOTA', 'CAMRY')
),
make_aliases(raw_make, canonical_make) AS (
VALUES
('CHEVR', 'CHEVROLET'),
('HYUND', 'HYUNDAI'),
('NISSA', 'NISSAN'),
('SUBAR', 'SUBARU'),
('TOYOT', 'TOYOTA')
),
normalized AS (
SELECT
safe_mart.last_observed_make AS raw_make,
safe_mart.last_observed_model AS raw_model,
coalesce(
make_aliases.canonical_make,
upper(trim(safe_mart.last_observed_make))
) AS normalized_make,
upper(trim(safe_mart.last_observed_model)) AS normalized_model,
exact_legacy.prior_make IS NOT NULL AS is_exact_legacy,
display_legacy.prior_make IS NOT NULL AS collides_with_legacy,
safe_mart.vehicle_token,
safe_mart.target_nonpass
FROM safe_mart
LEFT JOIN make_aliases
ON upper(trim(safe_mart.last_observed_make)) = make_aliases.raw_make
LEFT JOIN legacy_cells AS exact_legacy
ON safe_mart.last_observed_make = exact_legacy.prior_make
AND safe_mart.last_observed_model = exact_legacy.prior_model
LEFT JOIN legacy_cells AS display_legacy
ON trim(safe_mart.last_observed_make) = display_legacy.prior_make
AND trim(safe_mart.last_observed_model) = display_legacy.prior_model
WHERE safe_mart.eligible_returning_target
AND safe_mart.target_nonpass IN (0, 1)
AND safe_mart.last_observed_make IS NOT NULL
AND safe_mart.last_observed_model IS NOT NULL
),
classified AS (
SELECT
CASE
-- Only the eight families introduced in this release use
-- alias folding. The four legacy cells never enter this
-- branch, so their published counts retain raw-key meaning.
WHEN normalized_make = 'TOYOTA'
AND (
normalized_model = 'COROLLA'
OR normalized_model LIKE 'COROLLA %'
)
AND normalized_model != 'COROLLA IM'
AND normalized_model NOT LIKE 'COROLLA IM %'
THEN 'toyota_corolla'
WHEN normalized_make = 'TOYOTA'
AND (
normalized_model = '4RUNNER'
OR normalized_model LIKE '4RUNNER %'
)
THEN 'toyota_4runner'
WHEN normalized_make = 'TOYOTA'
AND (
normalized_model = 'TACOMA'
OR normalized_model LIKE 'TACOMA %'
)
THEN 'toyota_tacoma'
WHEN normalized_make = 'DODGE'
AND (
normalized_model = 'RAM 1500'
OR normalized_model LIKE 'RAM 1500 %'
OR normalized_model = 'RAM PICKUP 1500'
OR normalized_model LIKE 'RAM PICKUP 1500 %'
OR normalized_model = 'RAM1500'
OR normalized_model LIKE 'RAM1500 %'
)
AND normalized_model NOT LIKE '% VAN'
AND normalized_model NOT LIKE '% VAN %'
THEN 'dodge_ram_1500'
WHEN normalized_make = 'CHEVROLET'
AND (
normalized_model = 'SILVERADO 1500'
OR normalized_model LIKE 'SILVERADO 1500 %'
OR normalized_model = 'SILVERADO 1500HD'
OR normalized_model LIKE 'SILVERADO 1500HD %'
OR normalized_model = 'SILVERADO C1500'
OR normalized_model LIKE 'SILVERADO C1500 %'
OR normalized_model = 'SILVERADO K1500'
OR normalized_model LIKE 'SILVERADO K1500 %'
OR normalized_model = 'C1500 SILVERADO'
OR normalized_model LIKE 'C1500 SILVERADO %'
OR normalized_model = 'K15 SILVERADO'
OR normalized_model LIKE 'K15 SILVERADO %'
OR normalized_model = 'K1500 SILVERADO'
OR normalized_model LIKE 'K1500 SILVERADO %'
)
THEN 'chevrolet_silverado_1500'
WHEN normalized_make = 'NISSAN'
AND (
normalized_model = 'ALTIMA'
OR normalized_model LIKE 'ALTIMA %'
)
THEN 'nissan_altima'
WHEN normalized_make = 'HYUNDAI'
AND (
normalized_model = 'ELANTRA'
OR normalized_model LIKE 'ELANTRA %'
)
THEN 'hyundai_elantra'
WHEN normalized_make = 'SUBARU'
AND (
normalized_model = 'OUTBACK'
OR normalized_model LIKE 'OUTBACK %'
OR normalized_model = 'LEGACY OUTBACK'
OR normalized_model LIKE 'LEGACY OUTBACK %'
)
THEN 'subaru_outback'
ELSE NULL
END AS new_family,
*
FROM normalized
),
publication_input AS (
-- Exact legacy keys are deliberately copied from the raw columns.
SELECT raw_make AS prior_make,
raw_model AS prior_model,
vehicle_token,
target_nonpass
FROM classified
WHERE is_exact_legacy
UNION ALL
-- Preserve the original raw-key behavior for unrelated cohorts.
-- A whitespace variant that would render as a legacy key is
-- withheld rather than creating a duplicate public identity.
SELECT raw_make AS prior_make,
raw_model AS prior_model,
vehicle_token,
target_nonpass
FROM classified
WHERE NOT is_exact_legacy
AND NOT collides_with_legacy
AND new_family IS NULL
UNION ALL
SELECT
CASE new_family
WHEN 'chevrolet_silverado_1500' THEN 'CHEVROLET'
WHEN 'dodge_ram_1500' THEN 'DODGE'
WHEN 'hyundai_elantra' THEN 'HYUNDAI'
WHEN 'nissan_altima' THEN 'NISSAN'
WHEN 'subaru_outback' THEN 'SUBARU'
WHEN 'toyota_4runner' THEN 'TOYOTA'
WHEN 'toyota_corolla' THEN 'TOYOTA'
WHEN 'toyota_tacoma' THEN 'TOYOTA'
ELSE NULL
END AS prior_make,
CASE new_family
WHEN 'chevrolet_silverado_1500' THEN 'SILVERADO 1500'
WHEN 'dodge_ram_1500' THEN 'RAM 1500'
WHEN 'hyundai_elantra' THEN 'ELANTRA'
WHEN 'nissan_altima' THEN 'ALTIMA'
WHEN 'subaru_outback' THEN 'OUTBACK'
WHEN 'toyota_4runner' THEN '4RUNNER'
WHEN 'toyota_corolla' THEN 'COROLLA'
WHEN 'toyota_tacoma' THEN 'TACOMA'
ELSE NULL
END AS prior_model,
vehicle_token,
target_nonpass
FROM classified
WHERE new_family IS NOT NULL
)
SELECT prior_make, prior_model,
count(*)::BIGINT AS n,
sum(target_nonpass)::BIGINT AS nonpass,
count(DISTINCT vehicle_token)::BIGINT AS vehicles,
@ -651,11 +828,7 @@ def _scorecard_rows(connection: duckdb.DuckDBPyConnection) -> List[Dict[str, obj
count(DISTINCT vehicle_token) FILTER (
WHERE target_nonpass = 1
)::BIGINT AS nonpass_vehicles
FROM safe_mart
WHERE eligible_returning_target
AND target_nonpass IN (0, 1)
AND last_observed_make IS NOT NULL
AND last_observed_model IS NOT NULL
FROM publication_input
GROUP BY 1, 2
HAVING count(*) >= 100
AND sum(target_nonpass) >= 10
@ -667,7 +840,7 @@ def _scorecard_rows(connection: duckdb.DuckDBPyConnection) -> List[Dict[str, obj
AND count(DISTINCT vehicle_token) FILTER (
WHERE target_nonpass = 1
) >= 10
ORDER BY n DESC, last_observed_make, last_observed_model
ORDER BY n DESC, prior_make, prior_model
LIMIT 200
"""
).fetchall()
@ -784,6 +957,7 @@ def _release_id(
) -> str:
material = {
"schema_version": SCHEMA_VERSION,
"publication_policy_version": PUBLICATION_POLICY_VERSION,
"mart_sha256": mart_digest,
"models": [
{"model_version": version, "metrics_sha256": metrics_digest}

View File

@ -117,6 +117,213 @@ class DashboardExportTests(unittest.TestCase):
}
self.assertEqual(first_bytes, second_bytes)
def test_release_id_includes_publication_policy_version(self) -> None:
mart_digest = "a" * 64
provenance = [("model_v1", "b" * 64)]
release_id = dashboard_export._release_id(mart_digest, provenance)
with mock.patch.object(
dashboard_export,
"PUBLICATION_POLICY_VERSION",
dashboard_export.PUBLICATION_POLICY_VERSION + "_changed",
):
changed_release_id = dashboard_export._release_id(
mart_digest, provenance
)
self.assertNotEqual(release_id, changed_release_id)
def test_scorecards_fold_only_new_family_aliases_before_suppression(self) -> None:
connection = duckdb.connect(":memory:")
try:
connection.execute(
"""
CREATE TABLE safe_mart (
vehicle_token VARCHAR,
eligible_returning_target BOOLEAN,
target_nonpass INTEGER,
last_observed_make VARCHAR,
last_observed_model VARCHAR
)
"""
)
rows = []
def add_group(make: str, model: str, nonpass: int = 10) -> None:
group_number = len(rows)
for index in range(60):
rows.append(
(
"group-{}-vehicle-{}".format(group_number, index),
True,
1 if index < nonpass else 0,
make,
model,
)
)
# Every raw-string group is below the 100-vehicle threshold. Each
# approved pair reaches 120 only after its explicit aliases merge.
canonical_groups = {
("CHEVROLET", "SILVERADO 1500"): (
("CHEVROLET", "SILVERADO 1500 LT"),
("CHEVR", "K15 SILVERADO"),
),
("DODGE", "RAM 1500"): (
("DODGE", "RAM 1500 QUAD"),
("DODGE", "RAM PICKUP 1500"),
),
("HYUNDAI", "ELANTRA"): (
("HYUNDAI", "ELANTRA GLS"),
("HYUND", "ELANTRA"),
),
("NISSAN", "ALTIMA"): (
("NISSAN", "ALTIMA 2.5 S"),
("NISSA", "ALTIMA"),
),
("SUBARU", "OUTBACK"): (
("SUBARU", "LEGACY OUTBACK 2.5I AWD"),
("SUBAR", "OUTBACK"),
),
("TOYOTA", "4RUNNER"): (
("TOYOTA", "4RUNNER SR5"),
("TOYOT", "4RUNNER 4WD"),
),
("TOYOTA", "COROLLA"): (
("TOYOTA", "COROLLA CE LE S"),
("TOYOT", "COROLLA"),
),
("TOYOTA", "TACOMA"): (
("TOYOTA", "TACOMA V6"),
("TOYOT", "TACOMA 4WD"),
),
}
for variants in canonical_groups.values():
for make, model in variants:
add_group(make, model)
# These separately marketed lines share a prefix with a canonical
# family but must remain distinct and suppressed at this support.
for make, model in (
("HONDA", "ACCORD CROSS TOUR EXL"),
("HONDA", "ACCORD CROSSTOUR"),
("HONDA", "CIVIC CRX SI"),
("HONDA", "CIVIC DEL SOL SI"),
("TOYOT", "CAMRY SOLARA"),
("TOYOTA", "COROLLA IM"),
("DODGE", "RAM 1500 VAN"),
("FORD", "F1500"),
("NISSAN", "ALTIMAX"),
("TOYOTA", "CAMRYX"),
):
add_group(make, model, nonpass=30)
connection.executemany(
"INSERT INTO safe_mart VALUES (?, ?, ?, ?, ?)", rows
)
scorecards = dashboard_export._scorecard_rows(connection)
finally:
connection.close()
self.assertEqual(
[(row["prior_make"], row["prior_model"]) for row in scorecards],
sorted(canonical_groups),
)
self.assertTrue(
all(row["support_rounded"] == 100 for row in scorecards)
)
self.assertTrue(all(row["nonpass_rate"] == 0.167 for row in scorecards))
def test_legacy_scorecard_cells_are_not_broadened_by_aliases(self) -> None:
connection = duckdb.connect(":memory:")
try:
connection.execute(
"""
CREATE TABLE safe_mart (
vehicle_token VARCHAR,
eligible_returning_target BOOLEAN,
target_nonpass INTEGER,
last_observed_make VARCHAR,
last_observed_model VARCHAR
)
"""
)
rows = []
def add_group(
make: str,
model: str,
n: int,
nonpass: int,
) -> None:
group_number = len(rows)
for index in range(n):
rows.append(
(
"group-{}-vehicle-{}".format(group_number, index),
True,
1 if index < nonpass else 0,
make,
model,
)
)
legacy_cells = {
("FORD", "F150"): 12,
("HONDA", "ACCORD"): 18,
("HONDA", "CIVIC"): 24,
("TOYOTA", "CAMRY"): 30,
}
aliases = {
("FORD", "F150"): (
("FORD", "F150 4WD"),
("ford", "f150"),
),
("HONDA", "ACCORD"): (
("HONDA", "ACCORD LX"),
("honda", "accord"),
),
("HONDA", "CIVIC"): (
("HONDA", "CIVIC EX"),
("honda", "civic"),
),
("TOYOTA", "CAMRY"): (
("TOYOTA", "CAMRY LE"),
("TOYOT", "CAMRY"),
),
}
for (make, model), nonpass in legacy_cells.items():
add_group(make, model, 120, nonpass)
# This raw key renders as the legacy key after safe-category
# trimming. It must not become a second public identity.
add_group(" " + make + " ", " " + model + " ", 120, 60)
# Each alias is suppressed alone but would pass support if the
# two were folded together, making accidental broadening clear.
for alias_make, alias_model in aliases[(make, model)]:
add_group(alias_make, alias_model, 60, 30)
connection.executemany(
"INSERT INTO safe_mart VALUES (?, ?, ?, ?, ?)", rows
)
scorecards = dashboard_export._scorecard_rows(connection)
finally:
connection.close()
self.assertEqual(len(scorecards), len(legacy_cells))
by_cell = {
(row["prior_make"], row["prior_model"]): row
for row in scorecards
}
self.assertEqual(set(by_cell), set(legacy_cells))
for cell, nonpass in legacy_cells.items():
with self.subTest(cell=cell):
self.assertEqual(by_cell[cell]["support_rounded"], 100)
self.assertEqual(
by_cell[cell]["nonpass_rate"], round(nonpass / 120, 3)
)
def test_unlocked_model_manifest_is_refused(self) -> None:
manifest = self._read_json(self.model_manifest)
manifest["locked_test_evaluated"] = True