exactly how the engine decides how sure it is — and how often each leg is the deciding factor. Nothing here is hidden.
every number the engine uses. Edit a value and press Enter (or leave the field) to write it — the whole universe re-rates instantly. No hidden settings.
⚠ These are live. A change here re-tiers every restaurant immediately. Use the Calibrate tab's sandbox if you want to preview cut changes before committing.
the mappings & word-lists that turn raw signal into a score: the award classifier, the gem/nope/complaint vocabularies, which categories count as credentials, and how each category routes to a weight. Every row has a plain-English description. Edits are live — the engine reads these directly.
these are the formulas and decision rules the engine runs. They reference the editable params above by name. They're shown here so nothing that influences a rating is hidden in code — but they're the engine's shape, not numbers to tune (changing them is a redesign, done via migration).
How a fact is weighted
fact_weight = trust × recency_decay
recency_decay = min(decay_max_weight, 0.5 ^ (age_in_days / half_life)) // half_life = decay_half_life_days, or decay_half_life_credential_days for credential categories; the clamp stops future-dated facts being amplified above 1.0
trust = the outlet's trust weight from the Source-trust table above (or trust_default if the outlet isn't registered)
The three confidence legs
E (evidence) = min(e_max, Σ trust-weighted merit evidence ÷ E_saturation)
A (agreement) = 1 − agreement_k · min(pos,neg) ÷ (pos+neg) // 0 if no merit signal
C (coverage) = min(1, cov_w_credential·[has credential] + cov_w_voices·[has gem/nope voices] + cov_w_evidence·[evidence > cov_evidence_min])
confidence = the weakest of E, A, C // LEAST() — a place is only as sure as its flimsiest leg
How the tier is decided (in this order)
1. closed, or min(E,C) < confidence_gate → no tier (not yet rated)
2. ≥ nope_min_voices nope-voices AND net merit < nope_hard_merit_max → Nope (1)
3. ≥ nope_min_voices nope-voices AND merit < nope_merit_max AND attention ≥ nope_attn_min → Worth Trying (2)
4. otherwise by cohort-percentile vs the cuts: ≥ cut_t5 → DAF(5) · ≥ cut_t4 → Delicious(4) · ≥ cut_t3 → Damn Good(3) · ≥ cut_t2 → Worth Trying(2) · else Nope(1)
Ranking basis (eff_pct)
eff_pct = a place's percentile of net merit within its cuisine cohort.
For cohorts smaller than cohort_smooth_min_n it blends pct_cohort_blend·(cuisine percentile) + (1−blend)·(global percentile).
Cohort = the restaurant's Google primary type (mapped to a cuisine); falls back to 'general' when Google has none.
Category special-cases (which signal does what)
cat 1 = Awards → the Award-classifier config · cat 5 = Local voice → the gem/nope vocabulary · cat 7 review_themes → the complaint vocabulary · cat 11 = Operational status → "closed" when business_status ≠ OPERATIONAL · all other category→weight routing is in the config tables above.
How the universe is built (which restaurants get in)
A discovered candidate is promoted into the universe only if it: resolves on Google Places · is a food/drink place · is open (not CLOSED_PERMANENTLY) · its Google match is within universe_radius_km of the city centre · and it is credentialed (an Award or Critic source) OR has ≥ universe_min_reviews Google reviews. // credentialed places skip the review floor — both gates are editable params above; the rest is identity/dedup, not tuning
Only genuine math is fixed in code: the 0.5 half-life base, the 1.0 ceilings/anchors, and the weakest-link (LEAST) combination. Everything else above is a param or a config row you can edit.