The "Fish on the way" card on the Clearwater, Salmon, Grande Ronde and Imnaha pages. Written 2 October 2026. Everything here is reproducible from the scripts named in the last section; numbers are the hindcast's, not hand-picked.
When do fish that have passed Bonneville reach the water people actually fish: the South Fork Clearwater, the upper Salmon, the Wallowa, the Imnaha? Dam counts answer "how many are in the system". This card answers "how many are headed here, how many have arrived, and what to expect in the next two and four weeks".
Every PIT-tagged steelhead that was released as a juvenile in one of these rivers and later crossed an adult ladder at Bonneville (BO1 to BO4, or the adult fish facility) is a fish we know is bound for that river. We follow each one to Lower Granite and then to the first antenna array it reaches inside the drainage. Fourteen complete seasons, MY2013 to MY2026, 32,400 bound crossings, 71,400 tag-by-site arrivals at 451 sites.
Two things are deliberately left out:
Snake fish do not run straight up. The median time from Bonneville to first detection at a sub-basin array (training seasons MY2024 to MY2026):
| sub-basin | arrays | median days Bonneville to here | median arrival date |
|---|---|---|---|
| South Fork Clearwater | SC1, SC2, SC3 | 136 | 3 Feb |
| North Fork / Dworshak trap | DWL | 156 | 22 Feb |
| Lochsa | LRL, LRU | 219 | 11 Apr |
| Upper Salmon | USE, USI, SAWT, STL, YFK | 201 | 20 Mar |
| Pahsimeroi | PAHH | 203 | 27 Mar |
| Wallowa | WALH, WR1, WR2, BCANF | 202 | 28 Feb |
| Imnaha River | IR1, IR2, IR3 | 207 | 5 Mar |
| Sheep Creeks (Imnaha) | LSHEEF, BSC, LSC | 227 | 22 Mar |
Arrival is set by the calendar, not by travel time. South Fork Clearwater fish that crossed Bonneville in July, August, September or October all reach the SC1 array around the same date (median day of year 57 to 67, late February to early March). The delay simply shrinks for later cohorts. Fewer than a quarter of September crossers reach the South Fork before mid-January. They hold in the mainstem and lower river through the winter.
Flow moves them. Measured on the South Fork Clearwater arrivals against USGS 13338500 (SF Clearwater at Stites), October to March, 2012 to 2026: on days after a three-day flow rise of 25 percent or more, arrivals per day run
| month | after a rise | other days | ratio |
|---|---|---|---|
| October | 0.76 | 0.17 | 4.5x |
| November | 1.33 | 0.15 | 8.9x |
| December | 0.78 | 0.27 | 2.9x |
| January | 1.34 | 0.26 | 5.2x |
| February | 4.55 | 1.85 | 2.5x |
| March | 3.65 | 2.10 | 1.7x |
The year-level version of the same signal is weaker (Spearman 0.26 between October to December mean flow and the share arriving before 1 January, 14 seasons) because most years sit in a narrow flow range. The one extreme year is extreme both ways: fall 2025 had the second-highest October to December flow on record at Stites (mean 355 cfs, 19 days over 600 cfs, against 225 cfs and 0 days the fall before), and 60 percent of MY2026 South Fork arrivals came before 1 January against 0 to 31 percent in every other season. The antennas did not change: SC1 and SC2 have had the same configuration since September 2019.
Researchers describe regime shifts in Columbia steelhead over this record. The 2014 to 2016 northeast Pacific marine heatwave and the 2015 drought and heat year in the river; the collapse of Snake River returns in 2017 to 2020, especially the two-ocean Clearwater fish; and a partial recovery from 2023. Adult steelhead are also known to stage in cool tributaries in hot summers and to overwinter in the mainstem before entering natal streams, so warm, low years and cool, high years can look different in both route and timing. (The overwintering and cool-water staging behaviour is described in Keefer and colleagues, 2008, and High and colleagues, 2006; the heatwave and the Snake collapse are documented by NOAA, ISAB and IDFG. Paul has been told by researchers that the record spans about four eras; the specific boundaries below are our reading and should be checked against theirs before the site cites them.)
The hypothesis we tested, as era blocks of migration years: MY2011 to 2015 (high abundance, strong B-run), MY2016 to 2020 (the heat year and the collapse), MY2021 to 2023 (trough), MY2024 onward (recovery).
The test: forecast each season from only the prior seasons in the same era, against forecasting from all prior seasons, the last five, the last three, the last two, the last one, and the three prior seasons whose Bonneville crossing curve most resembled the season being forecast. Rest-of-season count error, median absolute percent, calendar method, cutoffs 1 October to 1 February, nine sub-basins:
| era of the forecast season | same era | all prior | last 5 | last 3 | last 2 | last 1 |
|---|---|---|---|---|---|---|
| MY2011 to 2015 | 0.34 | 0.34 | 0.34 | 0.37 | 0.34 | 0.32 |
| MY2016 to 2020 | 0.19 | 0.37 | 0.29 | 0.18 | 0.14 | 0.14 |
| MY2021 to 2023 | 0.25 | 0.36 | 0.22 | 0.21 | 0.25 | 0.31 |
| MY2024 to 2026 | 0.21 | 0.36 | 0.16 | 0.18 | 0.21 | 0.16 |
What this says. The eras are real in the sense that training on everything is bad in every era (0.34 to 0.37) and training on recent seasons is good. But the era blocks never beat the simple recency windows, and in the recovery era the last three to five seasons beat the era block. The research is right that the past is not uniform; the data says the right response is to lean on the most recent two or three seasons, not to pick block boundaries. So the forecast trains on the last three complete seasons, the eras are reported here as context, and the per-season table in outputs/arrival_eras.parquet is where a break would show up first.
One place the eras matter and the forecast does not yet handle: a break between last season and this one. MY2026's South Fork timing (above) was unlike any other season. A forecast trained on MY2024 to MY2026 carries one third of that pattern into MY2027. That is the right weight if fall 2026 flows are ordinary and too little if they are high again, which is why the card shows the live flow state next to the forecast.
Five methods were scored the same way on every season and cutoff. "Rest" is the rest-of-season count, "28 d" the next 28 days, both median absolute percent error pooled over cutoffs 1 October to 1 February and the nine sub-basins (490 forecasts each). Timing is the mean absolute error of the cumulative-fraction curve for the rest of the season.
| method | rest | 28 d | timing |
|---|---|---|---|
| copy last season, as is | 0.33 | 0.25 | 0.052 |
| last season's curve, scaled by this season's Bonneville count to date | 0.18 | 0.10 | 0.052 |
| calendar: Bonneville count times last three seasons' arrival rate, on their arrival calendar | 0.20 | 0.14 | 0.052 |
| cohort: per-tag delay distributions by crossing month, conditioned on not yet arrived | 0.19 | 0.23 | 0.059 |
| published: mean of the scaled-last-season and calendar forecasts | 0.19 | 0.12 | 0.052 |
Three findings drove the choice.
Calibration. The number shown as the middle is the blend's point forecast times the median of actual over forecast in the hindcast for that sub-basin at the nearest cutoff date; the range is the 20th to 80th percentile of the same ratios. Where fewer than three tags are expected, the range is taken from the actual counts in hindcast seasons like this one.
The hindcast was rerun for every river with a page, 23 sub-basins in 15 rivers (the Deschutes arrays have under 300 bound arrivals and get no card), with half-monthly cutoffs from 1 September to 1 March. Pooled over the cutoffs 1 October to 1 February, 2,691 forecasts: the published blend has median rest-of-season error 0.27 and next-28-days error 0.16, against 0.43 and 0.20 for copying last season. The era test gives the same answer on the wider set: the research-era block never beats the last two or three seasons.
The flow outlook was tested before it was shown. The question was whether scaling each day of the forecast by the sub-basin’s measured flow-rise multiplier improves the count, using the flow that actually happened (a perfect flow forecast, so the best a real outlook could do), with the multipliers measured leaving the forecast season out. It did not: the two-week count error went from 1.78 to 1.95 tags pooled, and the flow version won in fewer than half the forecasts in every sub-basin. What the flow term does improve is which day: the correlation of the daily forecast with daily arrivals over the next 28 days rose from 0.04 to 0.08 pooled, and in 75 percent of South Fork Clearwater forecasts. Both numbers are small because daily arrivals are a handful of tags, but the direction is consistent with the flow-rise table above.
So the card does two things with flow. The counts stay flow-free. The flow column carries the NOAA NWPS deterministic forecast for the gauge nearest the arrays (about eight days ahead) and names the days on which a three-day rise of 25 percent or more is forecast, with the measured multiplier for the current month. The per-sub-basin test result is in arrival_forecast.json under flow_hindcast and is quoted in the card’s own note.
Two gauges have no NOAA forecast point (Tucannon, Asotin), the Imnaha gauge is dead, and the North Fork Clearwater below Dworshak is regulated; those sub-basins show the live three-day change where a gauge exists and nothing else.
On every river page except the Deschutes: tagged fish bound for the river that are past Bonneville and past the next dam up this season (Lower Granite, Ice Harbor, Rock Island, Rocky Reach, Wells, McNary, John Day or The Dalles; the Klickitat enters below The Dalles and has only Bonneville), how many have reached any array in the drainage, and per sub-basin: arrived so far (with the same date in the last three seasons), expected in the next two and four weeks and the rest of the season with the range, the usual arrival window (25th to 75th percentile dates), the live three-day flow change at the nearest gauge with the measured flow-rise effect for the current month, and a weekly cumulative chart of the last three seasons, this season, and the forecast. The mobile river cards carry the two counts.
Published sub-basins need at least 300 bound arrivals over the record. Sub-basins whose arrays catch under 5 percent of bound fish, or where the forecast beat copying last season in under half the hindcasts, are marked low confidence.
precomputed/ptagis_site_config.parquet holds every configuration change and is the place to check.python3 measure_arrival_delays.py precomputed/arrival_pairs.parquet, bon_adult_cohorts.parquet, the delay summaries python3 hindcast_arrival.py outputs/arrival_hindcast_scores.parquet, arrival_eras.parquet, the tables above python3 arrival_flow_check.py the flow-rise table python3 build_arrival_forecast.py site/data/arrival_forecast.json, what the card reads
arrival_subbasins.py maps array codes to sub-basins; arrival_model.py holds the shared arithmetic; arrival_panel.py is the card.