Editorial
The editorial module is where the platform’s thesis becomes code. Five editorial constraints — topical diversity, recency / freshness, sentiment balance, editorial promotion, and sensitive-topic guard — applied to a candidate set through the ranker.
The ranker is the platform’s headline deep module: a pure function from
(candidate_set, constraint_configuration) to a ranked list of articles.
That’s the entire interface. Everything else in the module is in service of
making that function trustworthy, testable, and editorially defensible.
The runnable rep
Section titled “The runnable rep”Rep #5 is a self-contained lesson:
tutorial/editorial/lesson-01-editorial-constraints.py.
It takes one candidate set and re-ranks it under three editor policies, so you
see the platform-leverage thesis instead of reading about it.
make -C tutorial/editorial run # rank one candidate set under three policiesmake -C tutorial/editorial check # assert the rankings + the checkpointmake -C tutorial/editorial clean # nothing to clean (pure in-memory)The lesson is a compact, readable version of the production ranker: the three
soft terms (diversity, recency, sentiment) and the two hard rules (promotion,
sensitivity guard), as a pure (candidates, policy) -> ranked function. It then
runs three policies over the SAME six candidates:
- click-only baseline (all weights 0) → pure relevance:
a1 a2 a3 a4 a5 a6 - diversity-forward (diversity 0.5) →
a1 a3 a5 a2 a6 a4 - front-page promotion (force
a6to the top) →a6 a1 a2 a3 a4 a5
Same model output, three different slates — chosen by the editor, not the model. That is the whole thesis in one runnable file.
The checkpoint, worked
Section titled “The checkpoint, worked”Between the click-only baseline and the diversity-forward policy, which article makes the biggest jump up the list, and why?
a5 (culture) jumps from position 5 to position 3 — the biggest upward
move. Under pure relevance it sits behind two politics articles and a sports
article. The moment diversity is weighted, repeating a category is penalised:
once a1 (politics) and a3 (sports) lead, a fresh category beats the
second-best politics article (a2). The editor changed one weight — not a
single relevance score — and the reader sees a broader front. That is editorial
judgment exercised at the platform layer, exactly where ADR-0004 argues it
belongs.
What makes this a good rep
Section titled “What makes this a good rep”Following the foundations template (ADR-0033): the lesson is a
pure function with no I/O, so make run is instant and deterministic, make check asserts every policy’s exact order plus the checkpoint, and there is
nothing to clean. The compact ranker mirrors the production one in
serving/ranker.py
— drilling the toy is what makes the grown-up version legible.
What the code looks like
Section titled “What the code looks like”The ranker lives at
tutorial/serving/src/serving/ranker.py.
It is dependency-free — no database connection, no HTTP framework, no
filesystem. That isolation is deliberate (ADR-0010
explains why) and is what makes the test suite
fast and exhaustive: every config, every constraint, every edge case
covered with seeded inputs.
The sensitive-topic detector is its own deep module:
- Code:
tutorial/serving/src/serving/sensitivity.py - Tests:
tutorial/serving/tests/test_sensitivity.py - dbt-side enrichment:
article_sensitivity.py
The editorial configuration is a table, not code:
constraint_configurations.sql.
That table is what the editor interface reads and writes, and it is part of
the analytical contract analysts can query directly.
Hard rules vs soft weights
Section titled “Hard rules vs soft weights”The mixed-enforcement model (ADR-0010) refuses the temptation to make every editorial concern a numeric preference.
Soft constraints (weighted into a score):
- Topical diversity — anti-overlap with already-ranked articles in the list
- Recency / freshness — exponential decay against article age, half-life tunable
- Sentiment balance — Wasserstein-style penalty against a target sentiment distribution; degrades gracefully when sentiment scores are absent
Hard rules (applied after sorting):
- Editorial promotion — articles in the always-include list are inserted at their target positions, period
- Sensitive-topic guard — a hard cap on the share of sensitive articles per list, dropping from the bottom until the cap holds
A promoted investigation cannot vanish into a low weight. A sensitive-topic cap cannot be overridden by a high relevance score. That asymmetry is the editorial promise this module makes.
The full math is documented
Section titled “The full math is documented”ADR-0015 spells out the exact formulas: the score combination, each soft-term shape, the configuration schema, and the defaults. Anyone reading the ranker code can compare line-for-line against the ADR.
After this module
Section titled “After this module”The ranker is consumed by serving through /recommendations/
and /preview endpoints. The editor module gives editors
sliders + toggles + an always-include list management UI that all read and
write the constraint_configurations table the ranker references. The
evaluation module sweeps configurations and produces the
Pareto chart that makes the editorial-cost-of-clicks argument visible.