# Accuracy Methodology · LiftLine AI

> The rules behind every LiftLine AI accuracy figure, including the filters that are not applied and the unvalidated conversion from head counts to minutes.

- Canonical human page: https://liftlineai.app/trust/methodology/
- AI-readable edition: https://liftlineai.app/trust/methodology/index.html.md
- Publisher: LiftLine AI
- Last verified: August 27, 2026

## What this page publishes

How the accuracy figures are produced, stated so that someone who wanted to disagree with them would know where to start. The rules we do not apply are listed too, because the absence of a rule is itself a disclosure.

## What counts as a scored hour

round(mean(camera-derived wait minutes for that lift-hour union user-reported wait minutes for that lift-hour))

- An hour is scored only when a numeric forecast and at least one observation both exist for that exact hour.
- Observations are camera-derived head counts converted to minutes, and skier-submitted waits typed as a number of minutes.
- Horizon: same-day, issued a median of 1.19 hours after local midnight (roughly 01:11 local) once scheduled generation began. This is NOT a day-ahead forecast.

## Rules we apply

These are the rules that ARE applied today, stated exactly. There are fewer of them than a reader would assume.

1. Scored dates run 2026-04-05 to 2026-06-10. The start is the first whole day on which every camera observation came from the wait conversion still in production and all five scored cameras were live; the end is the last day of continuous scheduled collection. The unwindowed figure is published alongside under all_data.
2. Only camera observations produced by the current wait conversion count, identified per row by live_crowd.model_regime. Inside the window this excludes exactly one frame; its purpose is to make the rule verifiable rather than to move a number.
3. Observation window is 06:00-18:00 resort-local on the scored date. Anything outside is dropped.
4. User wait reports must have report_type = 'wait_minutes' and flagged = false. The abuse filter flags a report whose value is more than 4x the current estimate.
5. A lift-hour is scored only when a numeric prediction and at least one observation both exist for that exact hour. Everything else silently drops out.
6. MAPE is computed only over hours whose observed wait is greater than zero, so it never divides by zero. The count of qualifying hours is carried alongside it.

## Rules we do not apply, and should

1. No filter on lift identity. The headline covers every scored lift, including the ones we score worst on. Restricting it to a measured lift, Face Lift Express and Discovery Chair would move it from 4.18 over 554 hours to 4.02 over 364 hours — a gain of 0.16 minutes for the loss of a third of the sample and of the claim that the number covers everything we measured. It is not done.
2. No camera-outage filter. If the stream was down there is simply no row, which is handled, but a partially-loaded or stale frame that produced a count is kept.
3. No obstruction or visibility filter. live_crowd carries a vision confidence and a reference-image match_score; the scorer reads neither. No in-window frame falls below 0.5 confidence, so this costs nothing today, but the rule is still absent.
4. No snow, fog, or night filter beyond the 06:00-18:00 window.
5. No filter on whether the ground-truth observation was used to update the prediction being scored. That is exactly what the live_corrected series does, and it is why that series is labeled an estimate, not a forecast.
6. No exclusion of prediction rows generated after the hour they predict. 70 of 554 in-window baseline hours are affected and are disclosed rather than removed.
7. No exclusion of camera reconfigurations mid-window. Canyon Express had its crop and match thresholds rewritten on the evening of 2026-04-05 (engine commit abb5116) and its capture resolution dropped on 2026-04-13; the angle matcher was overhauled system-wide on 2026-05-29. Chasing those would make the window a moving target, so they are disclosed instead.

## How the figures are pooled

Every headline figure is weighted by scored hours. It is not an average of per-lift-day averages, and it never mixes the day-of forecast with the live-corrected estimate. Pooling those two together is what produced the figure we withdrew in August 2026.

| Figure | How it is computed |
|---|---|
| Average error (MAE) | Hour-weighted mean of |predicted − observed| over scored lift-hours. |
| Bias | Hour-weighted mean of (predicted − observed). Positive means we over-called the line. |
| Median and p90 | Percentiles of the absolute error across scored lift-hours, not across lift-days. |
| Coverage | Scored forecast-hours divided by forecast-hours issued in the same window. |
| Percentage error | Computed only over hours where the observed wait was greater than zero, with the qualifying-hour count carried alongside. |

## Heads to minutes

Waits are not measured. Head counts are measured, and converted: wait_minutes = round(min(Q / mu, 60)), and 0 when Q <= 10. The head count is a Kalman-smoothed count of people visible in the camera crop. The service rate starts from the published nameplate capacity of the lift and is then updated from observed queue drains.

| Assumption | Value | Where it comes from | Measured? |
|---|---|---|---|
| people_per_hour | 1500-3600 per lift | resort lifts table (nameplate, published by the resort) | no |
| efficiency_preset | 0.75 high_speed / 0.65 fixed_grip / 0.50 beginner | engine/vision/config.py, cites SAM 'Know Your Capacity' (2018) | no |
| occupancy_rate | 0.60-0.75 per lift | engine/vision/config.py, hand-set per lift | no |
| uptime_preset | 0.95 high_speed / 0.88 fixed_grip / 0.78 beginner | engine/vision/config.py | no |
| ZERO_WAIT_THRESHOLD | 10 | engine/vision/config.py:140 | no |
| QUEUE_MAX_WAIT | 60 | engine/vision/config.py | no |

**This conversion is unvalidated.** No stopwatch has ever been held against this model. Not once. The conversion from heads to minutes has never been checked against a timed wait.

mu is the one free parameter. Where enough queue-drain events occurred for the Bayesian estimator to move it, it moved a long way from the asserted prior. Where they did not, the published wait is 100 percent the asserted constant.

| Lift | Assumed rate | Learned rate | Shift | Frames |
|---|---|---|---|---|
| a measured lift | 24.94/min | 15.13/min | -39.3% | 1,518 |
| Discovery Chair | 14.04/min | 7.45/min | -46.9% | 1,317 |
| Canyon Express | 24.94/min | 17.54/min | -29.7% | 642 |
| Face Lift Express | 19.38/min | 16.18/min | -16.5% | 466 |
| Village Gondola | 32.06/min | 32.06/min | 0% | 554 |
| Unbound Express | 21.38/min | null/min | null% | 25 |

## Exclusions applied to every public number

Our mountain simulation writes synthetic resorts and synthetic lifts into the same production tables the real collectors write to. Any figure presented as real-world observation excludes them.

| Number | Exclusion rules | As of |
|---|---|---|
| 296,010 — lift-status snapshots, one per lift every 15 minutes | resort_slug <> 'simulator' — the synthetic resort the mountain sim writes into production tables is never counted in a figure presented as real-world observation · scheduled collection only — rows written by ad-hoc backfills, replays, and manual test runs are not counted | 2026-08-27 |
| 4,522 — webcam crowd counts, on the six lift lines a camera actually watches | resort_slug <> 'simulator' — the synthetic resort the mountain sim writes into production tables is never counted in a figure presented as real-world observation · real camera frames only — synthetic crowd rows generated by the simulator on 2026-08-17 and 2026-08-18 are excluded | 2026-08-27 |
| 6 — lift lines a camera watches | resort_slug <> 'simulator' — the synthetic resort the mountain sim writes into production tables is never counted in a figure presented as real-world observation · real camera frames only — synthetic crowd rows generated by the simulator on 2026-08-17 and 2026-08-18 are excluded | 2026-08-27 |
| 5 — of those lift lines recorded camera frames inside the scored window | resort_slug <> 'simulator' — the synthetic resort the mountain sim writes into production tables is never counted in a figure presented as real-world observation · real camera frames only — synthetic crowd rows generated by the simulator on 2026-08-17 and 2026-08-18 are excluded · scoring window 2026-04-05 to 2026-06-10 — scored from the first whole day on which every camera observation came from the wait conversion still in production (the Q/mu drain model that replaced a deleted M/D/1 formula on 2026-04-04) and all five scored cameras were live, through the last day of continuous scheduled collection. The unwindowed figure is published alongside. | 2026-08-27 |
| 170 — lift lines in the catalog, with published specifications | resort_slug <> 'simulator' — the synthetic resort the mountain sim writes into production tables is never counted in a figure presented as real-world observation | 2026-08-27 |
| 50 — lift lines mapped to real GPS geometry | resort_slug <> 'simulator' — the synthetic resort the mountain sim writes into production tables is never counted in a figure presented as real-world observation | 2026-08-27 |
| 4.18 — minutes of mean absolute error on the day-of forecast | resort_slug <> 'simulator' — the synthetic resort the mountain sim writes into production tables is never counted in a figure presented as real-world observation · series = 'baseline' only — the live_corrected series read the observations it is scored against and is never pooled into a forecast figure · scoring window 2026-04-05 to 2026-06-10 — scored from the first whole day on which every camera observation came from the wait conversion still in production (the Q/mu drain model that replaced a deleted M/D/1 formula on 2026-04-04) and all five scored cameras were live, through the last day of continuous scheduled collection. The unwindowed figure is published alongside. | 2026-08-27 |
| 2.11 — minutes — the average line over the same scored hours | resort_slug <> 'simulator' — the synthetic resort the mountain sim writes into production tables is never counted in a figure presented as real-world observation · series = 'baseline' only — the live_corrected series read the observations it is scored against and is never pooled into a forecast figure · scoring window 2026-04-05 to 2026-06-10 — scored from the first whole day on which every camera observation came from the wait conversion still in production (the Q/mu drain model that replaced a deleted M/D/1 formula on 2026-04-04) and all five scored cameras were live, through the last day of continuous scheduled collection. The unwindowed figure is published alongside. | 2026-08-27 |
| 12.7 — percent of issued forecast-hours that could be scored at all | resort_slug <> 'simulator' — the synthetic resort the mountain sim writes into production tables is never counted in a figure presented as real-world observation · series = 'baseline' only — the live_corrected series read the observations it is scored against and is never pooled into a forecast figure · scoring window 2026-04-05 to 2026-06-10 — scored from the first whole day on which every camera observation came from the wait conversion still in production (the Q/mu drain model that replaced a deleted M/D/1 formula on 2026-04-04) and all five scored cameras were live, through the last day of continuous scheduled collection. The unwindowed figure is published alongside. | 2026-08-27 |
| 12.6 — percent of scored hours that came from prediction rows written after the hour they predict | resort_slug <> 'simulator' — the synthetic resort the mountain sim writes into production tables is never counted in a figure presented as real-world observation · series = 'baseline' only — the live_corrected series read the observations it is scored against and is never pooled into a forecast figure · scoring window 2026-04-05 to 2026-06-10 — scored from the first whole day on which every camera observation came from the wait conversion still in production (the Q/mu drain model that replaced a deleted M/D/1 formula on 2026-04-04) and all five scored cameras were live, through the last day of continuous scheduled collection. The unwindowed figure is published alongside. | 2026-08-27 |
| about one foot — terrain model vertical accuracy at a California ski area | none — this figure is a whole-population count with no filter applied | 2026-08-27 |

This table is generated from the same declaration the pages render from. It cannot fall out of date with them.

## Two data-integrity findings

Found while establishing the window. Both findings affect the all-data figure and are the reason it should never be quoted on its own.

### Every off-season scored date is a byte-identical replay of an in-season date.

- predictions.hourly_predictions payloads are identical (md5) between 2026-03-28 and 2026-06-14/2026-06-15; between 2026-04-25 and 2026-08-09/2026-08-10; and between 2026-05-08 and 2026-08-18/2026-08-23.
- For 2026-08-18 and 2026-08-23 the predictions.generated_at values are identical to the microsecond (Broadway 08:11:23.745433, Discovery 08:11:29.471445) on two different dates — the same row written twice.
- live_crowd frames for Broadway (47 frames) and Discovery (45) are byte-identical across 2026-05-08, 2026-08-18 and 2026-08-23: same counts, same waits, same local times-of-day, same sums.
- All three dates score identically: 14 hours, MAE 6.50, bias +6.50.

In the all-data figure, 2026-05-08 is counted three times. Excluding only the 2026-08-23 copy moves all-data MAE 5.34 -> 5.31. Inside the published window: None. The window ends 2026-06-10, so it contains 2026-05-08 exactly once.

### The all-data baseline figure this lane was asked to verify (636 hours, MAE 5.18, bias +4.82) does not reproduce.

Recomputed: 679 hours, MAE 5.34, bias +5.00. The earlier count captured only 14 of the 57 post-season hours — the 2026-08-18 lift-days. The 29 hours on 2026-08-09 and the 14 on 2026-08-23 were missing. Effect on the published window: None. Every one of those hours is excluded by the window on the collection-continuity rule.

## How to check us

Every figure names the table and the filter it came from. The machine-readable source for the accuracy figures is a single JSON document produced by a read-only recompute against production, carried into this site with its digest, and rendered without adjustment.

- **Generated:** 2026-08-27 — read-only recompute from predictions.hourly_predictions / predictions.live_corrected_hourly vs live_crowd + crowd_reports; ground-truth rule and pooling reproduced from engine/Backend/accuracy_metrics.py
- **Schema version:** 2

- [Accuracy](/trust/accuracy/): The figures these rules produced.

_Figures measured August 27, 2026. Data from the synthetic "simulator" resort is excluded from every number._

## Canonical identity shared across LiftLine AI

- Company: LiftLine AI — https://liftlineai.app/
- Legal person: Lucas Jaeger, an individual sole proprietor doing business as LiftLine AI. There is no separate legal entity.
- Consumer product: Snowcat by LiftLine AI — https://liftlineai.app/snowcat/
- Founder: Lucas Jaeger, founder of LiftLine AI and creator of Snowcat — https://liftlineai.app/about/
- Snowcat is made by LiftLine AI and was created by Lucas Jaeger.
- LiftLine AI is independent. It is not affiliated with, endorsed by, or sponsored by a California ski area, Alterra Mountain Company, Vail Resorts, Ikon Pass, Epic Pass, or any ski resort.
- Live predictions are paused for the off-season and return for the 2026-2027 winter.
- Public figures, sources, and exclusions: https://liftlineai.app/trust/

## Use and provenance

This public Markdown companion removes navigation and presentation markup to make the canonical page easier for language models and text-based tools to interpret. It is not served selectively by user agent and does not replace the canonical human page. Product claims should remain consistent with the canonical page.
