# K19 – Greenland–Longnecker inputs and assumptions in update2026

Every category set that update2026 turns into a per-100 g slope (main pool, multiverse alternatives, Vulcan sensitivity, and the 12 spline/linear sets). 15 sets in total. Generated from the database by `gl_check.py` (no pipeline module imported). Doses are on the natural scale (g/day); the outcome is natural log RR. Slopes are given as RR per 100 g/day with 95 % CI.

## Rules the pipeline applies (derive_per100.py = catsets.py; both are coded identically)

| Step | Rule as coded | Where |
|---|---|---|
| Which set | `estimates.csv` rows with `contrast_type = category`, the same `category_set_id`, no subgroup, sorted by `category_rank`; ≥ 3 categories; rank 1 must have RR = 1 (no re-referencing, otherwise the set is skipped) | derive_per100.py l.72–80, 115–118 |
| Dose | (a) printed `dose_point` if `dose_unit = g_day` and all categories have one (paper median or mean); otherwise (b) `g_day_assigned` from `dose_conversions.csv` + `dose_conversions_cup.csv`, priority `portion_source` paper > cup > us_assumed > blank; `as_used` rows are a separate variant that D() ignores by default | derive_per100.py l.83–91 |
| Portion | 120 g/serving where the CUP rule is used (Tiemersma, Larsson); 85 g from the paper (Yiannakou); none (unit conversion only) for Al Rajabi (g/week ÷ 7), Norat 2005 (already g/day); Ollberding: g/1000 kcal × assumed energy (CUP/SLR conversion) | dose_conversions*.csv |
| Open categories | Only through dose assignment: lowest closed category from 0, midpoint of closed categories, open top = cut-point + half the width of the adjacent category (CUP rule). No special treatment inside GL | dose_conversions*.csv notes |
| Cases | Printed `n_cases`; if any missing: total cases from `studies.csv cases_<outcome>` (else `cup_extraction`), split **proportional to RR** (= equal person-time). The lookup tries (study, outcome, sex) first, but totals are only stored under sex = all, so sex strata get the **whole-cohort total** (Al Rajabi men and women: 265 each) | derive_per100.py l.93–102 |
| Denominator | Printed person-years or `n_in_category` (n_participants / n_controls). If missing: (i) if cases are printed and the label is not a quantile label (q1/quintile/quartile/tertile/t1/quarter) → person-time := cases / RR (crude = adjusted; "CUP convention"); (ii) otherwise equal denominators (1,…,1), reported as `assumed_equal` | derive_per100.py l.103–113 |
| CI → variance | var(log RR_i) = ((ln hi − ln lo) / (2 × 1.959964))² | gl_doseresponse.py l.78 |
| Pseudo-counts | person-time and "none": closed-form rate model A_i* = RR_i A_0* N_i/N_0, Σ A_i* = Σ cases. n_participants **and** n_controls: odds model A_i* B_0*/(A_0* B_i*) = RR_i with A_i* + B_i* = N_i := printed denominator, Σ A_i* = Σ cases, solved by bisection | gl_doseresponse.py l.24–55 |
| Covariance | **Not textbook GL.** c0 = 1/A_0* (rate) or 1/A_0* + 1/B_0* (odds); pseudo variances pv_i = 1/A_i* (+1/B_i*) + c0; pseudo correlation r_ij = c0/√(pv_i pv_j); final S_ij = r_ij √(v_i v_j) with v_i the published variances. Textbook GL/Orsini uses S_ii = v_i and S_ij = c0 unchanged | gl_doseresponse.py l.79–92; mvmeta.py l.23–31 |
| Zero cells | No handling. A zero case cell gives 1/0 → exception → set written to `derived_per100g_skipped.txt`. None of the 15 sets has a zero cell; no "GL feilet" entries in the skipped file | — |
| Slope | GLS through the origin, x = dose_i − dose_ref, β = (x'S⁻¹x)⁻¹ x'S⁻¹y, SE = √(x'S⁻¹x)⁻¹; per 100 g: exp(100β ± 1.959964·100·SE). No log-dose, no intercept, no df correction (z, not t) | gl_doseresponse.py l.93–106 |
| Sex strata | update2026.fx(): inverse-variance fixed combination of the two per-sex rows **as rounded to 4 dp in derived_per100g.csv** | update2026.py l.51 (fx → pool.combine_fixed) |
| Linear two-stage | Per-set slope from mvmeta.gl_cov (same covariance as above), DL random effects on 100β, CI with z = 1.96 | update2026.py l.201–209 |

Not used anywhere: Hamling et al. 2008 (effective counts). The module docstring says "Greenland–Longnecker (1992) / Orsini (2006) … kovarians 1/A0*" – the code does something else (see the Covariance row).

## Per set

"Own re-implementation" = `gl_check.py`, variant PIPELINE (the documented rules above, coded independently). For the textbook values and the other variants see RAPPORT.md.

| # | Study / set id | Used in | K | Doses g/day (source) | Cases per category (source) | Denominator (source) | GL model inside pipeline | Pipeline slope RR/100 g (95 % CI) | Own re-implementation, same variant |
|---|---|---|---|---|---|---|---|---|---|
| 1 | pietinen1999 `pietinen1999_mv_colorectal_men_red_unprocessed` | main pool: ATBC (Pietinen 1999); spline + linear two-stage (12 sets) | 4 | 35, 52, 69, 99 — printed per-category paper_median (g/day) | 55, 35, 50, 45 — printed | — — ASSUMED: equal denominators (quantile categories) | rate pseudo-counts on equal denominators (1,…,1); c0 = 1/A0* | 0.8338 (0.4313–1.6119) | 0.8338 (0.4313–1.6119) |
| 2 | tiemersma2002 `tiemersma2002_mv_colorectal_all_red` | main pool: Netherlands MP (Tiemersma 2002); spline + linear two-stage (12 sets) | 3 | 25.71, 65.14, 97.71 — assigned: times_week -> g/day, rule=cup_rule, portion=120 g (cup) | 22, 35, 45 — printed | 157, 186, 194 — printed n_controls | odds pseudo-counts with M_i = n_controls (should be cases + controls); c0 = 1/A0* + 1/B0* | 1.9195 (0.8541–4.3141) | 1.9195 (0.8541–4.3141) |
| 3 | larsson2005 `larsson2005_mv_colorectal_women_beefpork` | main pool: SMC (Larsson 2005); spline + linear two-stage (12 sets) | 4 | 25.71, 42.86, 68.57, 94.29 — assigned: servings_week -> g/day, rule=paper_median, portion=120 g (cup) | 172.5, 194.9, 155.2, 210.4 — ASSUMED: total 733 (studies.csv cases_colorectal, not sex-specific) split proportional to RR (i.e. equal person-time) | — — ASSUMED: equal denominators (cases assumed) | rate pseudo-counts on equal denominators (1,…,1); c0 = 1/A0* | 1.2252 (0.8978–1.6721) | 1.2252 (0.8978–1.6721) |
| 4 | ollberding2012 `ollberding2012_redunp_mv_colorectal_all` | main pool: MEC (Ollberding 2012); spline + linear two-stage (12 sets) | 5 | 9.01, 23.04, 36.72, 52.04, 79.1 — assigned: g_per_1000kcal_day -> g/day, rule=paper_median, portion=- g (cup) | 654, 702, 712, 677, 659 — printed | 33,143, 33,143, 33,144, 33,144, 33,143 — printed n_participants | odds pseudo-counts with M_i = n_i (B = n − A); c0 = 1/A0* + 1/B0* | 0.9665 (0.8292–1.1264) | 0.9665 (0.8292–1.1264) |
| 5 | knuppel2020 `knuppel2020_m2_colorectal_all_red_unprocessed` | main pool: UK Biobank (Knuppel 2020); spline + linear two-stage (12 sets) | 4 | 6.5, 32.6, 45.1, 55.1 — printed per-category paper_mean (g/day) | 228, 1184, 1282, 507 — printed | 47,720, 184,617, 173,883, 62,119 — printed n_participants | odds pseudo-counts with M_i = n_i (B = n − A); c0 = 1/A0* + 1/B0* | 1.4956 (1.0964–2.0402) | 1.4956 (1.0964–2.0402) |
| 6 | alrajabi2021 `alrajabi2021_m2_colorectal_men_red` | main pool: Alberta's Tomorrow (Al Rajabi 2021); spline + linear two-stage (12 sets) | 4 | 16.57, 43.5, 68.86, 98.86 — assigned: g_week -> g/day, rule=cup_rule, portion=- g (no portion) | 58.1, 65.1, 60.4, 81.4 — ASSUMED: total 265 (studies.csv cases_colorectal, not sex-specific) split proportional to RR (i.e. equal person-time) | — — ASSUMED: equal denominators (quantile categories) | rate pseudo-counts on equal denominators (1,…,1); c0 = 1/A0* | 1.4102 (0.6885–2.8880) | 1.4102 (0.6885–2.8880) |
| 7 | alrajabi2021 `alrajabi2021_m2_colorectal_women_red` | main pool: Alberta's Tomorrow (Al Rajabi 2021); spline + linear two-stage (12 sets) | 4 | 9.5, 25.29, 40.14, 57.29 — assigned: g_week -> g/day, rule=cup_rule, portion=- g (no portion) | 68.5, 60.9, 76.7, 58.9 — ASSUMED: total 265 (studies.csv cases_colorectal, not sex-specific) split proportional to RR (i.e. equal person-time) | — — ASSUMED: equal denominators (quantile categories) | rate pseudo-counts on equal denominators (1,…,1); c0 = 1/A0* | 0.9363 (0.3077–2.8489) | 0.9363 (0.3077–2.8489) |
| 8 | yiannakou2022 `yiannakou2022_mv_colorectal_women_red_unprocessed` | main pool: BWHS (Yiannakou 2022); spline + linear two-stage (12 sets) | 3 | 6.07, 24.29, 48.57 — assigned: servings_week -> g/day, rule=cup_rule, portion=85 g (paper) | 139, 267, 158 — printed | 287,700, 510,430, 318,047 — printed person_years | rate (Poisson) pseudo-counts; c0 = 1/A0* | 1.6262 (0.8412–3.1436) | 1.6262 (0.8412–3.1436) |
| 9 | wada2017 `wada2017_mv_colorectal_men_red_unprocessed` | multiverse alt.: Wada 2017 (Takayama only); spline + linear two-stage (12 sets) | 4 | 19, 33, 44, 64 — printed per-category paper_median (g/day) | 105, 105, 104, 115 — printed | 45,951, 45,454, 45,400, 46,180 — printed person_years | rate (Poisson) pseudo-counts; c0 = 1/A0* | 2.1759 (1.2272–3.8581) | 2.1759 (1.2272–3.8581) |
| 10 | wada2017 `wada2017_mv_colorectal_women_red_unprocessed` | multiverse alt.: Wada 2017 (Takayama only); spline + linear two-stage (12 sets) | 4 | 12, 23, 32, 49 — printed per-category paper_median (g/day) | 98, 97, 69, 79 — printed | 55,685, 55,271, 57,089, 58,636 — printed person_years | rate (Poisson) pseudo-counts; c0 = 1/A0* | 1.0905 (0.4884–2.4351) | 1.0905 (0.4884–2.4351) |
| 11 | bradbury2020 `bradbury2020_mv_colorectal_all_red_unprocessed` | multiverse alt.: Bradbury 2020 (UK Biobank) | 4 | 8, 34, 44, 54 — printed per-category paper_mean (g/day) | 187, 947, 781, 661 — printed | 47,795, 184,816, 131,486, 104,813 — printed n_participants | odds pseudo-counts with M_i = n_i (B = n − A); c0 = 1/A0* + 1/B0* | 1.3871 (0.9939–1.9360) | 1.3871 (0.9939–1.9360) |
| 12 | vulcan2017 `vulcan2017_full_colorectal_men_redunproc` | sensitivity: Vulcan 2017 (Malmo DCS) | 5 | 21.3, 39.1, 52.1, 67, 96.3 — printed per-category paper_median (g/day) | 52, 65, 71, 79, 89 — printed | 24,888, 29,689, 31,959, 34,519, 43,588 — printed person_years | rate (Poisson) pseudo-counts; c0 = 1/A0* | 1.0043 (0.6554–1.5390) | 1.0043 (0.6554–1.5390) |
| 13 | vulcan2017 `vulcan2017_full_colorectal_women_redunproc` | sensitivity: Vulcan 2017 (Malmo DCS) | 5 | 21.3, 39.1, 52.1, 67, 96.3 — printed per-category paper_median (g/day) | 89, 82, 79, 67, 55 — printed | 60,792, 56,278, 53,682, 51,105, 42,426 — printed person_years | rate (Poisson) pseudo-counts; c0 = 1/A0* | 1.0262 (0.6659–1.5815) | 1.0262 (0.6659–1.5815) |
| 14 | norat2005 `norat2005_m2_colorectal_all_red_unprocessed` | spline + linear two-stage (12 sets) | 5 | 5, 15, 30, 60, 100 — assigned: g_day -> g/day, rule=cup_rule, portion=- g (no portion) | 132, 138, 323, 486, 250 — printed | 132, 138, 314, 419, 214 — ASSUMED: person-time proportional to cases/RR (crude RR = adjusted RR) | rate (Poisson) pseudo-counts; c0 = 1/A0* | (not in main pool; per-set slope only inside the linear two-stage) 1.2279 (1.0036–1.5023) | 1.2279 (1.0036–1.5023) |
| 15 | mehta2020 `mehta2020_adj_colorectal_women_red` | spline + linear two-stage (12 sets) | 4 | 7.31, 16.16, 27.75, 53.5 — printed per-category paper_median (g/day) | 51, 52, 50, 57 — printed | — — ASSUMED: equal denominators (quantile categories) | rate pseudo-counts on equal denominators (1,…,1); c0 = 1/A0* | (not in main pool; per-set slope only inside the linear two-stage) 1.0838 (0.4523–2.5969) | 1.0838 (0.4523–2.5969) |

Notes on the table
- Rows 6–7 (Al Rajabi): 265 is the whole-cohort CRC total; each sex stratum is given all 265. With the pipeline's covariance this has no numerical effect (see RAPPORT §3).
- Rows 12–13 (Vulcan): the two sex strata carry identical per-category medians (21.3 … 96.3 g/day), i.e. probably the sex-combined quintile medians. Not checked against the paper here.
- Row 14 (Norat 2005): person-time is assumed = cases/RR, so the fitted pseudo-cases equal the printed cases.
- Row 15 (Mehta 2020) and row 1 (Pietinen): printed cases exist but with equal denominators the printed case distribution does not enter the pipeline's result at all (RAPPORT §3).
