# Crystal 2 — orientation

Read `HANDOFF.md` before changing anything. It records why the code looks the
way it does, what has already been measured, and what is knowingly unfinished.

## What this is

Upload an EPG export, press one button, get an estimated average-minute
audience for every telecast in the file — including for markets that have
never broadcast that event.

    public/     PHP dashboard (Apache).  new.php -> api/upload.php -> run.php -> results.php
    worker/     Python service. Polls MySQL for PENDING runs. MySQL is the ONLY bridge.
    engine/     The estimator: EPG adapter, evidence retrieval, projection, calibration
    reference_cache/  parquet snapshot of tvviewers + calibration.json + evidence_index.pkl
    fixtures/   small synthetic set for offline tests. NOT the cache.

## Non-negotiables

- **`tvviewers` is read-only.** Everything written goes to the `crystal` schema.
- **The worker must be restarted after engine changes**, or it serves the code
  it imported at boot. `run_estimation()` now drops `engine.*` from
  `sys.modules` each run, so this is handled — do not remove that.
- **Never widen an interval or a confidence score without measuring it.** The
  numbers in `calibration.json` are estimated by `worker/fit_model.py` from
  global_sports itself. If you change the model, re-run it.
- **`vendor/` is on the path deliberately.** Apache runs as `www-data`, which
  has no `~/.local` site-packages. Third-party deps live there.
- **The Excel palette is the analysts', not GSIQ's.** Both workbooks use the
  teal of the book Joseph's colleagues hand-build (`vr_style.py`). Diverging
  from the dashboard indigo is the point. See `HANDOFF.md` §6b.
- **A fix that "did not work" is usually a cached artefact.** Three caches can
  serve stale output — see `HANDOFF.md` §4 items 15–17. Regenerate before
  re-diagnosing.

## Running things

    python3 worker/build_cache.py     # refresh the reference snapshot (nightly)
    python3 worker/fit_model.py       # re-measure curves, exponents, sigma
    python3 worker/worker.py          # the estimator service
    python3 worker/make_pdf.py in.html out.pdf "Footer"
    python3 worker/refresh_chartdata.py   # after adding a headline figure to
                                          # the dashboard payload; old runs are
                                          # otherwise missing the key silently

## Style

Match the surrounding code. Comments explain *why*, especially where a value
was measured rather than chosen — those are the lines a reviewer will
challenge. Do not add a factor to the model without also adding the evidence
that justifies its magnitude.
