{% extends "layout.html" %}{% block content %}

Ratings

{{ summary_line }}

{% if no_embedding_count > 0 %}

{{ no_embedding_count }} rated articles have no embedding and cannot act as neighbours — run the features-backfill job (features backfill --rated-only).

{% endif %}
How ratings enter the algorithm
  1. Prompt verdict block. The {{ how.verdicts_in_prompt }} most recent non-cleared verdicts, newest first, are written into every LLM call's system prompt as one line each (LOVED | title | feed | summary). Only the rank matters here — a verdict never ages out of this block, it is pushed out by newer ones. Tune curation.feedback.verdicts_in_prompt.
  2. Weekly learned adjustments. Every {{ how.rebuild_interval_days }} days the editor model rewrites the profile's "Learned adjustments" bullets from the {{ how.max_ratings_in_rebuild }} most recent non-cleared verdicts, including notes and deep-assessment facets. See the Profile page.
  3. Rated-neighbour signal. Each verdict with an embedding is an example with weight value × 0.5^(age / {{ how.half_life_days }} days), where loved = {{ how.loved }}, good = {{ how.good }}, not for me = {{ how.not_for_me }}; ratings older than {{ how.lookback_days }} days are not loaded. A candidate's signal is the weighted mean cosine to its {{ how.neighbour_k }} nearest positive examples minus {{ how.negative_coefficient }} × the same over its nearest negative ones. The signal's preliminary weight ({{ how.knn_weight }}) is scaled by a gate that opens above {{ how.knn_floor }} embedded verdicts and is fully open at {{ how.knn_full }}. Tune curation.ranking.rating_half_life_days, knn_floor, knn_full, neighbour_k and weights.preliminary.knn.
  4. Feed affinity. The same decayed weight is credited to the rated article's direct feeds, split evenly; each feed's Beta-smoothed rate (up + 1) / (up + down + 2) becomes a candidate's signal (the mean over its rated direct feeds). Its weight ({{ how.feed_weight }}) is gated between {{ how.feed_floor }} and {{ how.feed_full }} attributable ratings. Tune curation.ranking.feed_floor, feed_full and weights.preliminary.feed.

Clearing a verdict removes it from all four paths without deleting history; ratings are append-only.

{% if tab == "events" %}
Reset

{{ pagination.total }} events, newest first. History is append-only; a later explicit event for the same article marks the earlier one superseded. Use the clear verdict to retract.

{% for event in events %} {% endfor %} {% if events.is_empty() %}{% endif %}
EventVerdictValueArticleIssueWhenSourceByNote
#{{ event.id }}{% if event.kind != "explicit" %} {{ event.kind }}{% endif %}{% if event.superseded %} superseded{% endif %} {{ event.verdict }} {{ event.value }} {{ event.title }} {% if !event.issue_date.is_empty() %}{{ event.issue_date }}{% endif %} {{ event.when }} {{ event.source }} {{ event.username }} {{ event.note }}
No rating events match.
{% else %}
Reset

One row per rated article (its latest explicit event), newest first. {% match last_run %}{% when Some with (run) %}"Used last run" counts the candidates of run #{{ run.id }} ({{ run.date }}, {{ run.status }}) that listed the article among their nearest rated neighbours, and how many of those were selected.{% when None %}No run has happened yet, so "Used last run" is empty.{% endmatch %}

{% for row in current %} {% endfor %} {% if current.is_empty() %}{% endif %}
VerdictArticleWhen · byNoteAge → decayNeighbour weightFeed creditIn promptIn rebuildUsed last run
{% let widget = row.widget %}{% include "_rating_widget.html" %} {{ row.title }}
{{ row.feed_title }}{% if !row.issue_date.is_empty() %} · {{ row.issue_date }}{% endif %}
{{ row.when }}
{{ row.source }} · {{ row.username }}
{{ row.note }} {{ row.age_days }} d → {{ row.decay }} {% if row.has_embedding && !row.neighbour_weight.is_empty() %}{{ row.neighbour_weight }}{% if row.beyond_lookback %} (beyond lookback){% endif %}{% else if row.badge == "cleared" %}{% else %}no embedding{% endif %} {% for credit in row.feed_credits %}{{ credit.title }} {{ credit.credit }}{% if !loop.last %}
{% endif %}{% endfor %}
{% if row.in_prompt %}{% endif %} {% if row.in_rebuild %}{% endif %} {% if row.used_total > 0 %}{{ row.used_total }} ({{ row.used_selected }} selected){% endif %}
No current verdicts match.
{% endif %}
{% endblock %}