The recommendation engine is the pipeline that turns a user profile — goals, current supplements, medications, adherence history, tolerances, and logged outcomes — into a short ordered list of stack suggestions with confidence scores and one-line rationales. Unfair's engine is deterministic rather than opaque: every rank is a weighted sum of ingredient-level scores that a user can audit, and every suggestion carries a visible reason and at least one visible stop condition. It runs twice a day and on any event that materially changes the input space (new symptom log, new medication, adherence crossing a threshold).
The four-stage pipeline
The engine never collapses these stages into one. Each runs top-to-bottom, and a candidate must survive all four to appear on the ranked list.
| Stage | What runs | What disqualifies a candidate |
|---|---|---|
| Input assembly | Goal weights, medications, allergies, current stack, 28-day log window, wearable trend | Missing baseline, stale profile, or directly conflicting goals |
| Hard filters | Drug interaction checks, duplicate-ingredient detection, contraindication rules, form and route compatibility | Any hard flag — the candidate is removed, not demoted |
| Ranking | Weighted score across evidence tier, personalization weight, goal fit, adherence feasibility | Below minimum score threshold for the goal |
| Guardrails | Stimulant cap, novel-compound cap per cycle, monitoring-burden cap, confidence floor | Guardrail trip — the candidate is held until a prior compound clears |
Filters answer "should this ingredient be shown at all for this user." Ranking answers "given it is safe to show, where does it belong on the list." Conflating the two produces the worst failure mode of ranking systems — demoting unsafe items instead of removing them — which is what the stage separation exists to prevent.
A worked example
A user with goal set to sleep quality, one SSRI in the medication list, and 78% 14-day adherence on their current stack receives a candidate pool of 142 ingredients from the library. The hard-filter stage removes 31 for drug interaction, 6 for duplicates with the current stack, and 4 for route incompatibility. Ranking scores the remaining 101. Guardrails then drop the top-ranked item (an L-theanine + caffeine combination) because the user already runs two stimulant-adjacent compounds and the stimulant cap is set to 2. The list the user actually sees is the top 5 from the 100 that cleared every gate.
What the user can override
Overrides apply to ranking inputs, not to hard filters. Timing, preferred form, goal weight, and monitoring-burden tolerance are all adjustable in-app and feed back into ranking. Drug interactions, contraindications, and stimulant caps are not overridable — they are part of the stack composition logic that makes ranked output useful rather than optimistic. A user who wants to raise a stimulant cap can do so only by resolving the prior stop conditions (finishing a cycle, logging tolerance, or removing a compound).
When the engine refuses to rank
Three conditions cause the engine to return "not enough signal yet" instead of a ranked list.
- Baseline window shorter than 10 days for a trend-dependent goal.
- Conflicting goal weights — for example, max stimulation and best sleep both set high — that no single stack can satisfy.
- Adherence below 50% for two consecutive weeks, where optimization would operate on noise.
The refusal is the honest answer. Ranking a list under these conditions would be guessing in public.
Common rank movers between cycles
Three events account for most rank movement in practice. A stimulant-adjacent compound moves down when adherence stability drops below 70%. A magnesium form moves up after a cycle where subjective sleep score and sleep efficiency both rose. A new optional item enters the top 5 after a prior optional finished its cycle and either failed its stop condition or succeeded and graduated to core. Users who understand these three patterns rarely find rank changes surprising, because the changes track real changes in the user's own data rather than a hidden model decision.
Why the stages run in this order
The ordering is not cosmetic. Input assembly before filters keeps the engine from running costly interaction checks on stale data. Filters before ranking mean ranking only sees the eligible set, so a contraindicated ingredient can never appear as a "top result we chose not to show." Guardrails run last because they depend on the whole ranked set — a stimulant cap cannot fire until ranking has identified which candidates count as stimulants in the first place. Any reshuffle of these stages produces a worse answer, which is why the engine does not permit stage-skip configurations.
Determinism over opacity
The engine's ranking function is a weighted sum with a fixed schema, not a neural network. Two users with identical profiles produce identical ranks, and the same user produces the same rank twice if no inputs changed. This is a deliberate trade-off — a learned model might rank marginally better on population benchmarks, but it would not let a user read why a rank exists, and the whole product is built around the user reading why. Deterministic scoring also makes the engine easier to audit for the bias patterns that matter in supplementation (over-ranking novel compounds, under-ranking well-established ones), because the weights are inspectable rather than buried in parameters.
How this appears in Unfair
The ranked list appears on the home screen with the top result expanded, each card showing evidence tier, recommendation confidence, and the top three reasons the item moved up or down since the last cycle. Tapping "why this rank" opens the full input → filter → rank → guardrail trace so the user can see which inputs drove the result. Hard-filter removals and guardrail trips are logged with human-readable labels in the daily review so that a dropped or held candidate is never silent.
Clinical safety note
The engine is behavioral guidance software, not a diagnostic system. Hard flags for drug interaction, bleeding risk, and pregnancy-contraindicated compounds lock the relevant candidates and cannot be overridden in-app. Any new medication, hospital stay, or diagnosis should be added to the profile before acting on a rank — the engine cannot warn about a medication it does not know about.