Bundle review table

Hub Proteins Are Essential

Supplied working report; original verdicts not validated.

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

README.md

# Hub Proteins Are Essential

**preprint draft — not peer reviewed**

*Test 03 of the Incoprea hypothesis tests, 30 October 2026. Pre-specified criteria:
[`hypothesis.md`](hypothesis.md). Sources and hashes: [`SOURCE.md`](SOURCE.md).*

## The result

The proposal does not survive. Adding partner redundancy to a degree-only logistic
model lifts out-of-fold AUC from **0.7597** to **0.7771**, a
gain of **+0.0174** (95% CI
+0.0109 to +0.0240;
2,000 label permutations, one-sided p =
**0.250**). That is well short of the
pre-specified 0.05 AUC bar, and not distinguishable from
what the same four-term model extracts from shuffled labels. Adding only mean
partner degree — the brief's single-term reading — does not help at all
(-0.0017, 95% CI -0.0049
to +0.0016).

The decisive analysis runs the wrong way. Inside degree deciles the top redundancy
tercile is **more** often essential than the bottom one, by
+0.049 across deciles
4–7
(permutation p = 0.0163),
and the contrast is positive in nine of ten deciles (Figure 1). The proposal predicts
the opposite sign. **Verdict: REFUTE.**

## What was asked

The proposal, verbatim: *"The probability that a protein is essential is set by the
ratio of its interaction degree to the redundancy of its partners, not by degree
alone."* The brief reads redundancy as three partner statistics — mean partner
degree, mean partner clustering, and the mean number of joint neighbours shared by a
protein's partners — and asks whether any adds predictive value over degree.

## What was done

**5,338** yeast proteins, **1,178**
essential (base rate **0.221**, a
3.53:1 class balance), from the largest
connected component of the STRING v12.0 graph at `combined_score >= 700`:
**104,138** edges on 5,716
proteins, after removing the duplicate direction STRING writes for every pair.
Essentiality is from SGD null-allele phenotypes; `SOURCE.md` records what that file
actually says, and it differs from the brief's guess in two places.

Redundancy is unweighted; the score only includes or excludes an edge.
The models are the pre-specified ones, fitted by hand-rolled IRLS (scikit-learn is
not installed) and checked against two closed forms, the score equations and an
independent scipy optimiser.
Cross-validation is 10-fold repeated
20 times under seed 20261030;
intervals are percentile bootstraps over genes, 2,000 resamples.

## What happened

Table 1. Keys: `auc.<model>.mean|lo|hi` and `auc.delta.<pair>.mean|lo|hi`.

| Model | Terms | AUC | 95% CI | ΔAUC vs M0 | 95% CI |
|---|---|---|---|---|---|
| M0 | log degree | 0.7597 | 0.7452–0.7747 | — | — |
| M1 | log degree + mean partner degree | 0.7579 | 0.7432–0.7724 | -0.0017 | -0.0049–+0.0016 |
| M2 | log degree + all three redundancy terms | 0.7771 | 0.7627–0.7916 | +0.0174 | +0.0109–+0.0240 |

The two extra terms in M2 carry some signal, but about a third of the AUC margin the
proposal needs, and adding mean partner degree on its own adds nothing. Redundancy is
entangled with degree (Spearman rho
0.72 for mean
partner degree, 0.76
for shared neighbours), so only the within-degree test can separate them.

## The within-degree test

Genes are ranked by degree into ten equal bins, then split into terciles of mean
partner degree within their own bin. The pre-specified bar was the top tercile at
least 0.10 below the bottom in the middle deciles,
with a consistent sign. What we see is the mirror image. Table 2 lists
`deciles.mean_partner_degree.table[i]` (`n`, `low`, `middle`, `high`,
`high_minus_low`; `i` from zero).

| Decile | n | Low | Middle | High | High − low |
|---|---|---|---|---|---|
| 1 | 534 | 0.034 | 0.051 | 0.045 | +0.011 |
| 2 | 534 | 0.017 | 0.034 | 0.073 | +0.056 |
| 3 | 534 | 0.034 | 0.062 | 0.079 | +0.045 |
| 4 | 534 | 0.079 | 0.112 | 0.140 | +0.062 |
| 5 | 533 | 0.129 | 0.213 | 0.192 | +0.063 |
| 6 | 534 | 0.185 | 0.225 | 0.213 | +0.028 |
| 7 | 534 | 0.230 | 0.230 | 0.275 | +0.045 |
| 8 | 534 | 0.287 | 0.388 | 0.444 | +0.157 |
| 9 | 534 | 0.348 | 0.556 | 0.494 | +0.146 |
| 10 | 533 | 0.697 | 0.511 | 0.243 | -0.454 |

Nine of ten deciles point the wrong way; the tenth, the top degree decile, points
strongly the predicted way. Sign consistency fails, the middle-decile bar fails on
sign as well as size, and criterion 3 fails. Partner clustering
(+0.100) and shared
neighbours (+0.086) behave
the same way, so this is not an artefact of the primary statistic.

The top decile is where the proposal looks right
(-0.454, permutation p =
0.0001). There the
high-redundancy tercile is dominated by proteins whose partners are overwhelmingly
ribosomal-subunit genes (median partner ribosome fraction
0.83 against
0.34). Those
partners are not interchangeable alternatives but one dense module, which is what
high mean partner degree and near-maximal partner clustering
(0.68) look like
from inside. That reading is post hoc, not support.

## Sensitivity

Threshold and fold choices do not rescue the effect: score at or above
400 gives
+0.0264 on
5,783 genes, at or above
900 gives
+0.0073 on
4,151;
5-fold cross-validation gives
+0.0173, dropping the
534 genes below degree three gives
+0.0200, and dropping dubious
open reading frames gives +0.0178.
All stay far under the bar.

One tension matters. The bootstrap interval on the AUC difference
excludes zero while the permutation p-value does not; the permutation test is the right
one, because the bootstrap resamples genes with labels fixed and so
it describes the precision of this fitted model's AUC on this graph, not the evidence
against no association. The permutation null is not centred at zero
(+0.0063, sd 0.0165),
because a richer model is less anti-correlated with held-out labels than a one-term
model at this sample size; that null is what is reported.

## What this test cannot see

Three limits are structural. **PPI coverage bias**: STRING fuses evidence channels of
very uneven depth, and well-studied proteins accumulate both more interactions and
more literature, so degree measures how much has been looked at as much as how
connected a protein is. **Essentiality annotation bias**: a gene is called essential
when some null allele was inviable in some strain background, not when no null allele
can be constructed to grow; essential genes are over-represented among characterised
genes by construction, and 177 ORFs with null
records had no viable or inviable call and were dropped. **STRING edges are
predictions, not experiments**: the score fuses text-mining, co-expression,
co-occurrence and database transfer with physical evidence, so many edges are not
physical contacts and the graph is a probabilistic summary rather than an
interactome. On top of those, the design is cross-sectional, single-organism
and not causal: nothing here says what would happen if a protein were
removed.

## What would change the answer

A redundancy measure built on genetic interaction or paralogy would test the
proposal far more directly than mean partner degree. Restricting to experimentally
determined physical interactions would strip the co-expression and text-mining part
of the score. A larger label set would give the permutation test power to resolve an
effect of 0.017 AUC.

## Files and reproduction

`run.py` rebuilds `data.csv`, `results.json` and `figures/` from `data/raw/`
(`--fetch` re-downloads). Every measured number above is written by `run.py` into
`results.json`; this list is generated from the same values, so prose and results
cannot drift. `data.csv` holds 5,338 rows.

```
auc.M0.mean=0.7597
auc.M2.mean=0.7771
auc.delta.M2_minus_M0.mean=+0.0174
design.ci_level_pct=95
auc.delta.M2_minus_M0.lo=+0.0109
auc.delta.M2_minus_M0.hi=+0.0240
permutation.n_perm=2,000
permutation.p_one_sided=0.250
design.auc_bar=0.05
auc.delta.M1_minus_M0.mean=-0.0017
auc.delta.M1_minus_M0.lo=-0.0049
auc.delta.M1_minus_M0.hi=+0.0016
deciles.mean_partner_degree.middle_contrast=+0.049
design.middle_deciles.0=4
design.middle_deciles.3=7
deciles.mean_partner_degree.middle_p_two_sided=0.0163
analysis_set.n=5,338
analysis_set.essential=1,178
analysis_set.base_rate=0.221
analysis_set.class_ratio_1_to=3.53
design.score_threshold=700
graph.lcc_edges=104,138
graph.largest_component_proteins=5,716
design.cv_folds=10
design.cv_repeats=20
design.seed=20261030
design.n_boot=2,000
features.spearman_with_log_degree.mean_partner_degree=0.72
features.spearman_with_log_degree.mean_shared_neighbours=0.76
design.contrast_bar=0.10
deciles.mean_partner_clustering.middle_contrast=+0.100
deciles.mean_shared_neighbours.middle_contrast=+0.086
deciles.mean_partner_degree.top_decile_contrast=-0.454
deciles.mean_partner_degree.top_decile_p_two_sided=0.0001
exploratory.top_decile_partner_ribosome_fraction_median.high=0.83
exploratory.top_decile_partner_ribosome_fraction_median.low=0.34
exploratory.top_decile_partner_clustering_median.high=0.68
design.sensitivity_thresholds.0=400
sensitivity.threshold_400.delta_auc=+0.0264
sensitivity.threshold_400.n=5,783
design.sensitivity_thresholds.1=900
sensitivity.threshold_900.delta_auc=+0.0073
sensitivity.threshold_900.n=4,151
design.sensitivity_folds=5
sensitivity.folds_5.delta_auc=+0.0173
analysis_set.degree_lt3=534
sensitivity.exclude_degree_lt3.delta_auc=+0.0200
sensitivity.exclude_dubious.delta_auc=+0.0178
permutation.null_mean=+0.0063
permutation.null_sd=0.0165
labels.genes_excluded_no_call=177
data_rows.data_csv=5,338
validation.intercept_only.abs_diff=4e-16
validation.saturated_2x2.max_abs_diff=2e-16
validation.score_equations.max_abs_gradient=1e-13
validation.scipy_bfgs.max_abs_coef_diff=2e-10
validation.auc_vs_bruteforce.abs_diff=0e+00
```

![Essentiality rate by degree decile and redundancy tercile](figures/01-essentiality-by-degree-decile.png)

![ROC curves for M0 and M2](figures/02-roc-m0-m2.png)

The hand-rolled fit agrees with the closed forms to
4e-16 (intercept-only) and
2e-16 (saturated 2×2), leaves a
score of 1e-13 at the M2
solution, matches an independent scipy BFGS fit to
2e-10, and reproduces a
brute-force pairwise AUC to 0e+00.

## Disclosure

This test was designed and executed with AI assistance (DeepSeek, via its coding
agent) and is not peer reviewed. The data are public, the pre-specified criteria were
written to `hypothesis.md` before any outcome was computed, and `run.py` regenerates
every number and both figures from the raw downloads.

hypothesis.md

# Hypothesis, quoted verbatim, and pre-specified criteria

Test 03 — Hub Proteins Are Essential.
Suite: Incoprea hypothesis tests, 30 October 2026. Contract: `../../CONTRACT.md`.

## Source

Brief: `briefs/03-hub-proteins.md`.
Source proposal: *Original Theory Notebook*, Volume XVI, entry 60, "Hub Proteins Are
Essential". Published at
<https://incoprea.com/research-library/original-theories-vol16-20261030/nave.html>

## The hypothesis, verbatim

> The probability that a protein is essential is set by the ratio of its interaction
> degree to the redundancy of its partners, not by degree alone.

## The brief's statement of what the test has to decide, verbatim

> The centrality–lethality rule — high-degree proteins are more often essential — is one
> of the most replicated results in network biology. The proposal is narrower: degree
> alone is not enough; what matters is degree *relative to how replaceable the partners
> are*. A hub whose partners are themselves well connected has alternatives; a hub whose
> partners are leaves is a single point of failure.
>
> Operationalise redundancy with three partner-level statistics computed on the same
> graph: mean partner degree, mean partner clustering (transitivity), and the mean number
> of joint neighbours shared between the protein's partners. Test whether any of them
> adds predictive value for essentiality over and above degree.

## Pre-specified support / refute criteria (copied from the brief, unchanged)

> Primary model comparison, 10-fold cross-validation repeated 20 times (seeded), logistic
> regression:
>
> - M0: `essential ~ log(degree)`
> - M1: `essential ~ log(degree) + mean_partner_degree`
> - M2: `essential ~ log(degree) + mean_partner_degree + mean_partner_clustering + mean_shared_neighbours`
>
> **SUPPORT** requires all three:
>
> 1. M2 beats M0 on cross-validated AUC by at least 0.05, with a bootstrap 95% CI
>    excluding zero over genes.
> 2. A label-permutation test gives p < 0.001 for the ΔAUC.
> 3. Within degree deciles, the top redundancy tercile has a materially lower
>    essentiality rate than the bottom tercile (at least 10 percentage points in the
>    middle deciles, sign consistent across deciles).
>
> **REFUTE** if ΔAUC is within ±0.02 of zero with the CI spanning zero, or if
> within-degree essentiality is flat across redundancy terciles.
>
> **PARTIAL** if the direction is right and significant but the effect is smaller than
> the 0.05 AUC threshold — that is the most likely outcome and should be reported as
> "real but modest", not spun.
>
> The key confound to address head-on: redundancy statistics are correlated with degree.
> The within-degree-decile analysis is the part of the test that decides whether the
> proposal is more than a restatement of centrality.

## Fixed implementation choices, written before any outcome was computed

These are the places where the brief leaves a choice. Each was fixed here, before the
first AUC or decile contrast was calculated, and none was changed afterwards.

1. **Primary redundancy statistic** = `mean_partner_degree`. It is the most direct
   machine-readable reading of "how replaceable the partners are": a partner with many
   other connections has alternatives. `mean_partner_clustering` and
   `mean_shared_neighbours` are secondary statistics and are reported in full, but
   criterion 3 is pass/fail on the primary statistic only.
2. **"Middle deciles"** = degree deciles 4, 5, 6 and 7 (deciles numbered 1–10 by
   ascending degree). A decile meets the 10-point bar when
   (top tercile rate − bottom tercile rate) ≤ −0.10.
3. **"Sign consistent across deciles"** = the sign of (top tercile rate − bottom tercile
   rate) is negative in all ten deciles. Terciles are computed within decile, so the
   comparison holds degree approximately fixed.
4. **Degree deciles** are ten equal-sized groups of the analysis set, formed by ranking
   on degree with random tie-breaking under the analysis seed (degree is heavily tied and
   equal-size bins are needed for stable terciles). Mean degree is reported per decile to
   show the bins are narrow.
5. **Seed** = 20261030 for everything; fold assignment, tie-breaking, bootstrap,
   label permutation and the sensitivity runs each draw from it at a fixed offset.
6. **Bootstrap CI for ΔAUC**: 2000 resamples of genes with replacement. For each
   resample the 20 per-repeat ΔAUCs are recomputed on that resample and averaged. Fold
   assignment is held fixed, which is the usual repeated-CV bootstrap and is stated as a
   limit.
7. **Label permutation**: 2000 permutations of the essentiality vector, full 10-fold
   pipeline re-run per permutation with fixed folds. One-sided in the hypothesised
   direction (redundancy improves prediction), `p = (1 + #{ΔAUC_perm ≥ ΔAUC_obs}) / 2001`.
   The minimum attainable p is 1/2001 = 0.0005, so the p < 0.001 bar is reachable.
8. **Sensitivity**: edge thresholds 400 and 900 in place of 700, refitting M0 and M2 with
   10-fold × 5 repeats; and 5-fold × 20 repeats in place of 10-fold at threshold 700.
   Reported as ΔAUC; the verdict is decided at the pre-specified threshold 700 / 10-fold.
9. **Graph**: largest connected component, simple undirected, unweighted, no self loops.
   Node features are computed on the whole component; rows are then restricted to genes
   with a usable essentiality call. `mean_shared_neighbours` is undefined for degree < 2
   and is set to 0.0 for those genes (288 genes at threshold 700); this is a
   pre-specified convention, and a sensitivity fit excluding degree < 3 is reported.
10. **Essentiality encoding** (see `SOURCE.md` for what the file actually contains):
    a gene is essential if any `mutant_type == "null"` row has `phenotype == "inviable"`;
    non-essential if it has null rows and none is inviable but at least one is `viable`;
    excluded otherwise (no null row, or null rows with neither call).

The verdict is the brief's: SUPPORT only if all three criteria hold, REFUTE if ΔAUC is
within ±0.02 of zero with a CI spanning zero or the within-degree contrast is flat,
otherwise PARTIAL. The threshold was not moved after the numbers were seen.

Included code and results