Confounder Control
The Problem
Food sensitivity data collected without controlling for confounders is nearly useless. A person with poor sleep, high stress, and a histamine-heavy dinner will have a bad symptom day — but the model can’t distinguish how much of that is the food vs. the sleep vs. the stress.
Worse, these confounders are correlated with food choices. Stress days often involve eating differently (comfort foods, more alcohol, fast food). Ignoring confounders doesn’t just add noise — it adds biased noise.
The Confounders We Track
Sleep
Why it matters: Sleep deprivation increases systemic inflammation, lowers pain threshold, and elevates baseline histamine through mast cell sensitization. A person who slept 4 hours will score their symptoms higher on average regardless of what they ate. See Sleep and Histamine for the full biochemistry — histamine is a wakefulness neurotransmitter, and sleep deprivation directly increases mast cell reactivity, creating a feedback loop.
What we track:
sleep_hours— total sleep (decimal, e.g. 6.5)sleep_quality— 1-5 self-reported quality
Data source: Manual entry or Apple HealthKit / Google Health Connect auto-population.
Stress
Why it matters: Psychological stress triggers mast cell degranulation directly via corticotropin-releasing hormone (CRH). It also increases gut permeability, alters motility, and amplifies visceral hypersensitivity. High-stress days systematically inflate symptom scores. See The HPA Axis and Mast Cells — CRH is a literal mast cell trigger via CRH Receptors, not a vague mind-body effect.
What we track:
stress_level— 1-5 self-reported
Exercise
Why it matters: Moderate exercise is anti-inflammatory. Intense exercise raises histamine (exercise-induced histamine release from mast cells), temporarily elevates gut permeability, and can trigger exercise-induced anaphylaxis in MCAS-adjacent individuals.
What we track:
exercise_intensity— none / light / moderate / intense
Model treatment: Moderate exercise is a positive control modifier (more reliable day). Intense exercise is a confound similar to high stress — flag and partially discount.
Ambient Temperature and Weather
Why it matters: Heat is a direct mast cell trigger — increased core and skin temperature increases membrane fluidity and can trigger degranulation. Cold exposure activates mast cells via distinct ion channel mechanisms. Barometric pressure changes are anecdotally reported by MCAS patients as flare triggers, though the mechanism is less clear (possibly related to sinus pressure changes activating nasal/airway mast cells, or effects on vascular tone).
What we track: daily_control_flags.flag_type = 'temperature_extreme' with values: hot, cold, pressure_change
Data source: Manual entry initially. Weather API auto-population is a straightforward future integration — store daily high/low temperature and barometric pressure delta from the user’s location and flag automatically when thresholds are exceeded.
Model treatment: Days with temperature extremes are partially discounted for all categories, since thermal mast cell activation adds mediator load independent of food.
Menstrual Cycle Phase
Why it matters: Estrogen upregulates histamine receptors and stimulates mast cell degranulation. See Estrogen and Mast Cells for the full mechanism, including the Histamine-Estrogen Feedback Loop.
The cycle phases affect mast cell biology as follows:
- Follicular phase (days ~1-13): Estrogen rises gradually. Mast cell priming increases as estrogen climbs, but progesterone is low — no stabilizing counterbalance. However, absolute estrogen is still moderate for most of this phase.
- Ovulatory (day ~14): Estrogen peaks sharply. This can be a symptom spike point due to acute estrogen-driven mast cell priming.
- Luteal phase (days ~14-28): Progesterone rises significantly and provides a partial mast cell stabilizing effect (see Progesterone and Mast Cells). Estrogen has a secondary mid-luteal rise. The estrogen-to-progesterone ratio is the key variable — when this ratio favors estrogen (early luteal before progesterone peaks, or late luteal as progesterone drops faster than estrogen), mast cell symptoms can flare.
- Perimenstrual (days ~25-3): Both hormones drop. Loss of progesterone’s stabilizing effect + estrogen withdrawal + prostaglandin release during menstruation. This is when many MCAS patients report their worst symptom days.
Correction from earlier version
A previous version stated the luteal phase has “low progesterone, relatively higher estrogen” — this is backwards. The luteal phase is the HIGH progesterone phase. The problematic period is the perimenstrual transition where progesterone drops precipitously. This distinction matters for the model: luteal-phase symptom data may actually be more reliable (progesterone is stabilizing), while perimenstrual data should be discounted for histamine-category analysis.
What we track: daily_control_flags.flag_type = 'menstrual_phase' with values: follicular / ovulatory / luteal / perimenstrual / menstrual
Data source: Manual entry. Apple Health and Google Health Connect expose menstrual tracking data from their respective health apps, which may be sufficient for auto-population. Clue’s public API was shut down years ago and has not been reliably restored — do not depend on it.
Model treatment: Perimenstrual and menstrual phases are the primary discount targets for histamine-category signal. Ovulatory phase (estrogen peak) is a secondary discount. Luteal phase (high progesterone) may actually represent a better testing window for histamine sensitivity, since the progesterone stabilizing effect creates a more controlled baseline — worth investigating with real data.
Illness and Medications
What we track: daily_control_flags with types: illness, antihistamine, nsaid, probiotic, mast_cell_stabilizer, etc.
Model treatment: Days with active illness are heavily discounted (inflammation baseline is elevated). NSAID use is flagged for salicylate category (NSAIDs are salicylates — see Salicylates for the COX shunting mechanism, and DAO for NSAID-driven DAO inhibition).
Antihistamine handling is category-specific
Antihistamines mask histamine-mediated symptoms but don’t affect FODMAP, oxalate, lectin, glutamate, or capsaicin pathways. The quality score should exclude antihistamine days from histamine-category correlations only, not from all analysis. Similarly, mast cell stabilizers (cromolyn, ketotifen) affect histamine AND other mast cell mediators (prostaglandins, leukotrienes), so they should discount histamine and salicylate categories but not FODMAP or oxalate.
This means the quality score needs to be per-category, not global. The MVP can use a simplified version (global score + categorical overrides for medication flags), but the architecture should support per-category scoring from the start.
Alcohol
Why it matters: Alcohol is both high-histamine, a histamine liberator, AND a DAO blocker. It’s one of the strongest confounders for histamine testing specifically. It also increases intestinal permeability acutely, which can affect all categories.
What we track: daily_control_flags.flag_type = 'alcohol' with optional value for quantity
Model treatment: Any alcohol discounts histamine-category signal heavily. Heavy alcohol (>2 drinks) discounts all categories due to gut permeability effects.
The Composite Quality Score
Each day gets a quality score that reflects how reliable that day’s symptom data is for statistical purposes.
MVP: Per-Category Quality Score
def quality_score(control, category: nil)
sleep_factor = control.sleep_quality / 5.0
stress_factor = 1.0 - ((control.stress_level - 1) / 4.0)
base_score = (sleep_factor + stress_factor) / 2.0
# Global flags — discount all categories
base_score *= 0.3 if control.flags.illness?
base_score *= 0.5 if control.flags.intense_exercise?
base_score *= 0.7 if control.flags.temperature_extreme?
# Category-specific flags
if category&.slug == 'histamine'
base_score *= 0.0 if control.flags.antihistamine?
base_score *= 0.3 if control.flags.alcohol?
base_score *= 0.5 if control.flags.perimenstrual? || control.flags.menstrual?
base_score *= 0.5 if control.flags.mast_cell_stabilizer?
elsif category&.slug == 'salicylate'
base_score *= 0.3 if control.flags.nsaid? # NSAIDs ARE salicylates
base_score *= 0.5 if control.flags.mast_cell_stabilizer?
end
# Heavy alcohol discounts all categories
base_score *= 0.5 if control.flags.heavy_alcohol? && category&.slug != 'histamine'
base_score.clamp(0.0, 1.0)
endHow It’s Used
The quality score is used as a weight in the correlation calculation, NOT as a multiplier on the symptom score. See MVP: Weighted Correlation with FDR Correction for the correct weighted correlation approach.
# The quality score weights the observation's INFLUENCE, not its VALUE.
# A quality=0.3 day still has its full symptom score — it just
# contributes less to the fitted correlation.
correlation = WeightedPearson(
x: ingredient_exposure,
y: symptom_scores, # raw, unmodified
weights: quality_scores # per-category weights
)This isn’t perfect statistics — it’s pragmatic weighting appropriate for a consumer app. The v0.2+ upgrade path is to ANCOVA (treat confounders as covariates directly) or mixed effects modeling (treat user as a random effect and confounders as fixed effects).
Why Not Just Exclude Bad Days?
Exclusion loses data. Weighting preserves the observation while appropriately discounting its reliability. Over 30 days, most people will have a mix of quality days — weighted averaging uses all of it, just proportionally.
Also: if someone has consistently poor sleep and consistently high symptoms, that’s a real signal that the model should surface — not suppress. The v0.2 mixed effects model can directly estimate the sleep-symptom relationship as a covariate, turning this confounder into useful information: “Your symptoms correlate more strongly with sleep quality than with any food” is a valuable finding.
UI Implications
The daily check-in should be fast — 30 seconds max. Pre-population from HealthKit handles sleep automatically for most users. The remaining manual fields: stress level (one tap 1-5), exercise (one tap), and optional flags.
The user never sees “quality score” or “weighted correlation.” They see: “Your data from Tuesday is marked as lower confidence due to poor sleep.”
Biochemical Basis
Each confounder tracked here has a specific biochemical mechanism affecting mast cell activity. The bucket model provides the theoretical framework: these confounders change the size of the bucket (capacity to handle mediators) independent of food. The app’s confounder weighting is a statistical implementation of that biochemical reality.
Further Reading
- ANOVA and Experimental Design — how confounder adjustment fits into the statistical model
- Hypothesis Engine — how the hypothesis engine uses washout windows (a form of temporal confounder control)
- Total Mediator Load — the biochemical framework these confounders map onto