Bundle review table

Eutrophication Is a Switch — test 05

Supplied working report; original verdicts not validated.

Review status: Needs review. This is an archival source note, not a passed proof.

README.md

# Eutrophication Is a Switch — test 05

**Preprint draft — not peer reviewed.** This test was designed and executed with AI
assistance (DeepSeek, via its coding agent), from a pre-specification written before any
model was fitted. See the disclosure at the end.

## Result

The threshold claim does not survive a like-for-like comparison. On 1,028 lakes from the US
EPA National Lakes Assessment 2007, a continuous breakpoint model with four parameters fits
log10 chlorophyll a against log10 total phosphorus *worse* than a natural cubic spline with
the same four parameters: ΔBIC = −29.2 (`delta_bic.hockey_vs_smooth`), where a positive
value would have favoured the breakpoint. The residuals of the smooth fit are unimodal —
Hartigan's dip is 0.0066 with a simulation p of 0.776 (`dip.statistic`, `dip.p_value`) — so
there is no second algal mode waiting behind the phosphorus relationship. The best
breakpoint the model can find sits at 230 µg/L (`breakpoint.tau_ugl`), with a 95% bootstrap
interval of 93 to 468 µg/L (`breakpoint.bootstrap.lo_ugl`, `breakpoint.bootstrap.hi_ugl`)
that runs past the 90th percentile of total phosphorus at 255 µg/L
(`descriptives.tp_ugl_p90`). All three pre-specified support conditions fail, and the
verdict is **REFUTE** (`verdict.threshold`) in the exact sense fixed in
[hypothesis.md](hypothesis.md).

The proposal's second sentence — that the switch is *not reversed* when phosphorus returns
to a level the lake held before — **was not tested here, and this design cannot test it**
(`hysteresis_verdict`: "not testable here"). One summer snapshot per lake has no before and
no after. Nothing in this report bears on hysteresis, and the refutation above applies to
the threshold sentence only.

## What was asked

The proposal, from *Original Theory Notebook* Volume XVI, entry 10:

> A lake switches to algal dominance above a phosphorus threshold rather than degrading
> gradually, and the switch is not reversed by returning to the same concentration.

Two claims travel together here and need different evidence. The first is about the shape
of a relationship across lakes, which a cross-section can test. The second is about the
path one lake takes through time, which no cross-section can.

The pre-specified rule required all three of: ΔBIC ≥ 6; a bootstrap interval strictly
inside the 10th and 90th percentiles of total phosphorus; and a dip test rejecting
unimodality at p < 0.05. Refutation required ΔBIC < 2 with dip p > 0.10. Observed: −29.2
(`delta_bic.hockey_vs_smooth`), an interval of 93 to 468 µg/L that straddles those
percentiles, and p = 0.776 (`dip.p_value`). No leg is close.

## Data

The NLA 2007 archive (`data/raw/nla2007_alldata.zip`, 4,674,683 bytes,
`provenance.zip_bytes`; SHA-256 in [SOURCE.md](SOURCE.md)) holds a site-visit table with
both variables in the same row: `NLA2007_Chemical_ConditionEstimates_20091123.csv`, columns
`PTL` (total phosphorus, µg/L) and `CHLA` (chlorophyll a, µg/L). The key is `SITE_ID`;
maximum depth comes from `NLA2007_SampledLakeInformation_20091113.csv` on `SITE_ID` and
`VISIT_NO`. The brief's NLA 2017 fallback was not used, because the 2007 archive has a
usable join.

Rows fall 1,252 → 1,157 (index visit) → 1,033 (probability sample only) → **1,028**
(phosphorus and chlorophyll both above zero), as recorded under `sample.filters` and
`sample.n`. The 124 hand-picked `REF_Lake` sites are excluded from the primary sample
(`sample.ref_lakes_excluded`); they return in sensitivity S-e. Spearman ρ between the two
logs is 0.747 (`correlation.value`, permutation p 0.0002, `correlation.p_perm`), so the
question is about the shape of a strong gradient, not its existence.

## Method

Five models are fitted by ordinary least squares on log10 chlorophyll a: a natural cubic
spline with 4 degrees of freedom (`protocol.smooth_df`); a continuous two-slope breakpoint
(hockey stick, `y = a + bx + c(x − τ)₊`); a step model with two levels and a jump; a
discontinuous two-slope model; and a quadratic. Breakpoints are estimated by profile least
squares over 80 candidate values of τ (`protocol.breakpoint_grid_points`), with τ counted as
a parameter in every BIC. Because the spline and the hockey stick both carry four
parameters, the primary comparison is like for like: BIC of −1664.5 against −1635.3
(`models.smooth_spline_df4.bic`, `models.hockey.bic`). The spline also wins on plain fit,
R² 0.558 against 0.545 (`models.smooth_spline_df4.r2`, `models.hockey.r2`). The step model
is far behind (ΔBIC −208.5, `delta_bic.step_vs_smooth`) and the discontinuous two-slope
model does no better than the continuous one (−29.1, `delta_bic.twoslope_vs_smooth`).

The hockey stick that does get fitted bends the wrong way: slope 0.817 below the breakpoint
and −0.253 above it (`breakpoint.slope_below`, `breakpoint.slope_above`). A concave,
saturating response forces that negative upper slope, and it is exactly the shape a single
kink cannot represent.

Uncertainty comes from 1,000 pairs bootstrap resamples of lakes
(`breakpoint.bootstrap.n_boot`, `protocol.bootstrap_resamples`). The dip statistic is a port
of Hartigan's AS 217 algorithm; its p-value is a parametric bootstrap of 1,000 normal
samples of the same size and standard deviation, seeded (`dip.n_sim`, `dip.seed`), and the
same code computes observed and simulated values, so implementation constants cancel. Run
time stays far inside the ten-minute budget (`runtime_seconds`).

## Sensitivity

All nine pre-specified checks are in `sensitivity`. Seven leave the verdict at REFUTE.
Using the maximum chlorophyll value over all visits instead of the index value gives ΔBIC
−30.5 (`sensitivity.0.delta_bic`). Dropping lakes above the 99th
percentile of phosphorus gives −26.5 (`sensitivity.1.delta_bic`). Including the reference
lakes gives −31.6 (`sensitivity.6.delta_bic`). A coarser or finer breakpoint grid changes
ΔBIC only in the second decimal (`sensitivity.4.delta_bic`, `sensitivity.5.delta_bic`). The
dip test never rejects in any variant: p runs from 0.096 (`sensitivity.7.dip_p`) to 0.867
(`sensitivity.1.dip_p`), and every Benjamini–Hochberg q across the declared family is at
least 0.59 (`sensitivity.7.dip_q_bh`).

Two checks move the BIC leg, and they mark the honest limit of the verdict. Replace the
4-degree spline with a quadratic and the breakpoint model wins by 38.8
(`sensitivity.7.delta_bic`); replace it with a 3-degree spline and it wins by 37.0
(`sensitivity.8.delta_bic`). Under the pre-specified rule that configuration would be
PARTIAL rather than REFUTE, because the dip test still does not reject (p 0.096,
`sensitivity.7.dip_p`; p 0.151, `sensitivity.8.dip_p`). The BIC leg therefore depends on how
much flexibility the smooth benchmark is allowed; the “no second mode” leg does not. What
the data will not support, under any of the seven variants, is a second algal mode.

## What this design cannot see

This is a single summer snapshot, not a time series: each lake contributes one index visit,
so nothing here can describe a trajectory, a return or a reversal, and the hysteresis
sentence is out of reach by construction. Sampling design weights are **ignored**: `WGT_NLA`
is carried in `data.csv` but enters no fit, because the estimand is the shape of a
relationship rather than a population mean or total, so the curves describe the sampled
lakes and not the population of US lakes. Lake typology is a real confounder and is barely
addressed: depth, mixing regime, ecoregion, water colour and nitrogen are not in the model,
and the only typology check is the shallow/deep split, where the shallow half shows no
breakpoint signal at all (ΔBIC −0.4, `sensitivity.2.delta_bic`) while the deep half does
(−25.8, `sensitivity.3.delta_bic`). A breakpoint fitted to a mixture of lake types can be a
composition effect rather than a switch inside any lake, and this design cannot separate the
two. Both variables are single measurements with unmodelled analytical error, and
phosphorus values below reporting limits are carried at their reported value rather than
treated as censored.

## Hysteresis

The second half of the proposal gets the verdict **not testable here**
(`hysteresis_verdict`), which is a statement about the design, not about the evidence.
Testing it needs repeated measurements of the same lakes across enough years to contain
phosphorus reversals — a panel spanning a decade or more, with lakes that rise and fall,
ideally under load reductions — or a whole-lake manipulation with before-and-after
chlorophyll observations. Neither is available here. No secondary attempt was made: the
readily available national surveys resample lakes too irregularly to yield a reversal
design, and a two- or three-visit panel would confound hysteresis with season and with
interannual weather. A token attempt would have implied more than it could show.

## Files

`run.py` regenerates `data.csv` (1,028 rows), `results.json` and the three figures
(`figures/fig1_tp_chla_fits.png`, `figures/fig2_bic_profile.png`,
`figures/fig3_residuals.png`) from the committed archive; `hypothesis.md` holds the
pre-specification and `SOURCE.md` the provenance and row counts.

## Disclosure

This test, its code, its figures and this text were produced with AI assistance (DeepSeek,
via its coding agent) from a human-written brief and a pre-specified decision rule. It is a
preprint draft and has not been peer reviewed. Every random draw is seeded, and `run.py`
reproduces the archive-to-figure pipeline end to end.

hypothesis.md

# Hypothesis — Eutrophication Is a Switch

Source proposal: *Original Theory Notebook*, Volume XVI, entry 10, "Eutrophication Is a
Switch". Published at
<https://incoprea.com/research-library/original-theories-vol16-20261030/nave.html>

## The proposal, quoted verbatim

> A lake switches to algal dominance above a phosphorus threshold rather than degrading
> gradually, and the switch is not reversed by returning to the same concentration.

## What the proposal contains

Two separable claims.

1. **Threshold / abruptness.** Across lakes, the relationship between total phosphorus
   (TP) and chlorophyll a (CHLA) is better described by two regimes meeting at a
   breakpoint than by a smooth monotone curve. This is a claim about the *shape* of a
   cross-sectional relationship, and a single survey of many lakes can test it.
2. **Hysteresis.** Returning TP to a level the lake previously held does not return the
   lake to its previous algal state. This is a claim about the *path* a single lake takes
   through time, and no cross-section — however many lakes, however good the chemistry —
   contains that information. It is not tested here and no result below bears on it.

## Pre-specification (written 2026-10-30 12:36 America/Chicago, before any model was fitted)

Everything in this section was fixed before the first regression was run. The numbers are
in `results.json`; the mapping from claim to key is in `README.md`.

### Analysis sample

Source table: `NLA2007_Chemical_ConditionEstimates_20091123.csv` from the NLA 2007
archive. Site-visit level, one row per lake visit.

Filters, applied in this order and in this order only:

1. `VISIT_NO == 1` — the index visit. Ninety-five lakes have a second visit; the index
   visit keeps one row per lake and matches the `INDXSAMP_CHEM` convention of the file.
2. `SITE_TYPE == "PROB_Lake"` — the probability sample. The 124 `REF_Lake` sites are a
   hand-picked candidate-reference set with design weight zero; they are kept out of the
   primary sample because they are not a sample of lakes, and are used in sensitivity
   S-e.
3. `PTL > 0` and `CHLA > 0` — the log transform requires strictly positive values.
4. Analysis variables `x = log10(PTL)`, `y = log10(CHLA)`; units µg/L as supplied.

No design weight enters any fit. The estimand is the shape of the TP–CHLA relationship
across lakes, not a population total or mean; this is a documented limitation, not an
adjustment.

### Models, fitted by ordinary least squares on the primary sample

| id | model | form | parameters `k` |
| --- | --- | --- | --- |
| SMOOTH | natural cubic spline, df = 4, interior knots at the 1/3 and 2/3 quantiles of `x` | `y = f(x)` | 4 |
| HOCKEY | continuous two-slope breakpoint (**primary breakpoint model**) | `y = a + b·x + c·(x − τ)₊` | 4 |
| STEP | two intercepts and a jump | `y = a₁ + (a₂ − a₁)·1(x > τ)` | 3 |
| TWOSLOPE | discontinuous two-slope (secondary) | `y = a₁ + b₁·x + (Δa + Δb·x)·1(x > τ)` | 5 |
| QUAD | quadratic (secondary smooth) | `y = a + b·x + c·x²` | 3 |

HOCKEY, STEP and TWOSLOPE are fitted by profile least squares: for each τ on the grid the
model is linear in its other coefficients, so OLS is exact and only τ is searched. Grid:
80 equally spaced values of τ between the 5th and 95th percentiles of `x` restricted to
values leaving at least 30 observations on each side; τ itself counts as a parameter.

`BIC = n·ln(RSS/n) + k·ln(n)`, with `k` counting τ.

**Primary comparison:** `ΔBIC = BIC(SMOOTH) − BIC(HOCKEY)`; positive means the breakpoint
model wins. STEP and TWOSLOPE are reported alongside but do not decide the verdict.

### Dip test

Statistic: Hartigan's dip (Hartigan & Hartigan 1985) on the n residuals of SMOOTH,
computed from the greatest convex minorant on the left of the mode and the least concave
majorant on the right, minimised over the split point. Null calibration: parametric
bootstrap, 1000 samples of size n drawn from a normal with the residual mean and standard
deviation, dip recomputed each time, `p = (1 + #{D* ≥ D}) / 1001`, seed 20261031. The dip
statistic is location- and scale-invariant and asymptotically distribution-free under
unimodality, so a normal null is an admissible calibration; the same code computes the
observed and the simulated statistics, so any implementation constant cancels.

### Bootstrap interval for τ

Pairs bootstrap, 1000 resamples of lakes with replacement, HOCKEY refitted on each
(identical grid), percentile 2.5–97.5% interval, seed 20261030.

### Decision rule

Let `p10`, `p90` be the 10th and 90th percentiles of `x` in the primary sample.

* **SUPPORT** (threshold only) iff all three hold:
  1. `ΔBIC ≥ 6`;
  2. the τ bootstrap interval lies strictly inside `(p10, p90)`;
  3. dip `p < 0.05`.
* **PARTIAL** iff `ΔBIC ≥ 6` and dip `p ≥ 0.05`: a breakpoint in the mean response with no
  second mode in the residuals. The report must say exactly that and must not upgrade it.
* **REFUTE** iff `ΔBIC < 2` and dip `p > 0.10`.
* **INDETERMINATE** otherwise (for example `2 ≤ ΔBIC < 6`, or `ΔBIC ≥ 6` with the
  bootstrap interval reaching `p10` or `p90`, or `0.05 ≤ p ≤ 0.10`). The failing leg is
  named.

**Hysteresis: NOT TESTABLE HERE, by construction.** No branch of this rule, and no
outcome of any model above, provides evidence for or against the second sentence of the
proposal. A positive SUPPORT verdict is evidence about cross-lake shape only.

### Multiplicity

The decision family contains one test: the composite SUPPORT/REFUTE rule above, with its
three legs read jointly. No adjustment is applied to it and none is added afterwards. The
sensitivity analyses are descriptive; their dip tests form a second, clearly labelled
family and are reported with Benjamini–Hochberg q-values, but they do not enter the
verdict.

### Sensitivity analyses (all pre-specified, all reported)

| id | change |
| --- | --- |
| S-a | CHLA taken as the maximum of all CHLA measurements for the lake (WaterQuality table, all visits) instead of the index-visit value |
| S-b | drop lakes with PTL above the 99th percentile of the primary sample |
| S-c | split by maximum depth `DEPTHMAX` into shallow (< 5 m) and deep (≥ 5 m), models refitted in each class |
| S-d | breakpoint grid resolution 40 and 160 points instead of 80 |
| S-e | include the `REF_Lake` sites (all visit-1 lakes, n ≈ 1152) |
| S-f | QUAD in place of SMOOTH |
| S-g | SMOOTH with df = 3 in place of df = 4 |

### What this design cannot see (fixed in advance)

A single summer snapshot; no time dimension at all, so neither hysteresis nor any
within-lake trajectory is observable. Sampling design weights are ignored in the fits.
Lake typology — depth, mixing regime, ecoregion, colour, nitrogen — is not modelled
except in S-c, so any breakpoint is an average over a heterogeneous population of lakes
and could reflect composition (a mixture of two lake types) rather than a switch within
lakes. TP and CHLA are both single index-visit measurements, so within-season variance is
not separated from between-lake variance.

Included code and results