After a rewrite of the prompt rule and a few more live issues the line still read as a second abstract, so it goes entirely: the rule and the "why" key in the editor's JSON, the parsing and 14-word cap, the Pick field, the issue_articles and candidate_runs writes, the Brief prompt's per-pick why, the explain output, the dashboard "editor" columns, and the rendering on the web index, article and public pages, the Atom feed and both EPUB pages. The "Matches: …" interests line stays (restyled in the next commit). The issue_articles.why and candidate_runs.editor_why columns remain in the schema unused; stored issue snapshots that still carry "why" deserialize because Pick ignores unknown fields. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ESJbbzQ1b8fs5AA65tKw2q
66 lines
9.3 KiB
HTML
66 lines
9.3 KiB
HTML
{% extends "layout.html" %}{% block content %}<section class="dashboard">
|
||
<header class="page-head"><div>
|
||
<p class="page-eyebrow"><a class="text-muted no-underline hover:text-accent" href="/dashboard/runs">Runs</a> › {{ run.date }}</p>
|
||
<h1 class="mt-1 flex flex-wrap items-center gap-x-3 gap-y-1">Run {{ run.id }} <span class="badge {{ run.status }}">{{ run.status }}</span>{% if run.dry_run %} <span class="badge">dry run</span>{% endif %}</h1>
|
||
<p class="page-desc">Started {{ run.started }} · finished {{ run.finished }}.</p>
|
||
</div><nav class="page-actions" aria-label="Run navigation">{% if let Some(prev) = run.prev_id %}<a class="btn" href="/dashboard/runs/{{ prev }}">← Run {{ prev }}</a>{% endif %}{% if let Some(href) = run.issue_href %}<a class="btn" href="{{ href }}">Issue {{ run.date }}</a>{% else %}<span class="muted text-sm">No issue for {{ run.date }}</span>{% endif %}{% if let Some(next) = run.next_id %}<a class="btn" href="/dashboard/runs/{{ next }}">Run {{ next }} →</a>{% endif %}</nav></header>
|
||
|
||
<div class="tiles">
|
||
<div class="tile"><span class="tile-label">Issue date</span><span class="tile-num">{{ run.date }}</span><span class="tile-delta">run {{ run.id }}</span></div>
|
||
<div class="tile"><span class="tile-label">Duration</span><span class="tile-num">{{ run.duration }}</span><span class="tile-delta">wall clock</span></div>
|
||
<div class="tile"><span class="tile-label">Token cost</span><span class="tile-num">{{ run.total_cost }}</span><span class="tile-delta">every provider</span></div>
|
||
<div class="tile"><span class="tile-label">Warnings</span><span class="tile-num{% if !warnings.is_empty() %} text-warn{% endif %}">{{ warnings.len() }}</span><span class="tile-delta">{% if warnings.is_empty() %}clean{% else %}<a href="#warnings">see below</a>{% endif %}</span></div>
|
||
</div>
|
||
{% if let Some(error) = run.error %}<p class="error">{{ error }}</p>{% endif %}
|
||
|
||
<h2>Funnel</h2>
|
||
<div class="scroll-x"><table class="funnel-table">
|
||
<thead><tr><th>stage</th><th>share</th><th class="num">reached</th><th class="num">stopped here</th><th>why</th></tr></thead>
|
||
<tbody>{% for stage in funnel %}<tr>
|
||
<td class="cell-tight align-middle"><span class="badge {{ stage.stage }}">{{ stage.stage }}</span></td>
|
||
<td class="funnel-cell"><div class="funnel"><svg class="h-3" width="{{ stage.percent }}%" role="img" aria-label="{{ stage.reached }} reached"></svg></div></td>
|
||
<td class="num align-middle">{{ stage.reached }}</td>
|
||
<td class="num align-middle text-muted">{{ stage.stopped }}</td>
|
||
<td class="reasons cell-wrap align-middle text-muted">{% for reason in stage.reasons %}{{ reason.reason }} <span class="tabular-nums text-ink">{{ reason.count }}</span>{% if !loop.last %} · {% endif %}{% endfor %}</td>
|
||
</tr>{% endfor %}</tbody></table></div>
|
||
|
||
{% if has_report %}<div class="cards">
|
||
<section class="card"><h2>Admission mix</h2>{% if admission.is_empty() %}<p class="muted">Nothing admitted.</p>{% else %}<dl class="kv">{% for line in admission %}<dt>{{ line.name }}</dt><dd class="tabular-nums">{{ line.count }}</dd>{% endfor %}</dl>{% endif %}</section>
|
||
<section class="card"><h2>Preference state</h2><dl class="kv">
|
||
<dt>rated with embeddings</dt><dd class="tabular-nums">{{ preference.rated_with_embeddings }}</dd>
|
||
<dt>knn gate</dt><dd class="tabular-nums">{{ preference.knn_gate }}</dd>
|
||
<dt>feed gate</dt><dd class="tabular-nums">{{ preference.feed_gate }}</dd>
|
||
<dt>verdicts in prompt</dt><dd class="tabular-nums">{{ preference.verdicts_in_prompt }}</dd>
|
||
</dl></section>
|
||
<section class="card"><h2>Timings</h2><div class="scroll-x"><table><thead><tr><th>stage</th><th class="num">seconds</th></tr></thead><tbody>{% for line in timings %}<tr><td>{{ line.stage }}</td><td class="num">{{ line.seconds }}</td></tr>{% endfor %}<tr><th>total</th><th class="num">{{ timings_total }}</th></tr></tbody></table></div></section>
|
||
<section class="card"><h2>Provider usage</h2><div class="scroll-x"><table><thead><tr><th>provider</th><th class="num">in</th><th class="num">cached</th><th class="num">cache write</th><th class="num">out</th><th class="num">cost</th></tr></thead><tbody>{% for line in providers %}<tr><td>{{ line.provider }}</td><td class="num">{{ line.input }}</td><td class="num">{{ line.cached }}</td><td class="num">{{ line.cache_write }}</td><td class="num">{{ line.output }}</td><td class="num">{{ line.cost }}</td></tr>{% endfor %}</tbody></table></div></section>
|
||
<section class="card" id="warnings"><h2>Warnings</h2>{% if warnings.is_empty() %}<p class="muted">None.</p>{% else %}<ul class="list-disc pl-5 text-warn [overflow-wrap:anywhere]">{% for warning in warnings %}<li>{{ warning }}</li>{% endfor %}</ul>{% endif %}</section>
|
||
<section class="card"><h2>Feeds (top {{ feeds.len() }})</h2><div><table class="table-fixed"><thead><tr><th>feed</th><th class="num w-20">entries</th></tr></thead><tbody>{% for line in feeds %}<tr><td class="truncate" title="{{ line.name }}">{{ line.name }}</td><td class="num w-20">{{ line.count }}</td></tr>{% endfor %}</tbody></table></div></section>
|
||
</div>{% else %}<p class="muted text-sm">This run has no stored report; only the funnel and candidates are available.</p>{% endif %}
|
||
|
||
<h2>Config diff</h2>
|
||
{% if let Some(against) = diff_against %}{% if config_diff.is_empty() %}<p class="muted text-sm">No settings changed since <a href="/dashboard/runs/{{ against }}">run {{ against }}</a>.</p>{% else %}<p class="muted text-sm">Against the previous non-dry run, <a href="/dashboard/runs/{{ against }}">run {{ against }}</a>.</p>
|
||
<div class="scroll-x"><table class="diff"><thead><tr><th>key</th><th>before</th><th>after</th></tr></thead><tbody>{% for row in config_diff %}<tr><td><code>{{ row.key }}</code></td><td class="before cell-wrap text-muted">{{ row.before }}</td><td class="after cell-wrap text-ink">{{ row.after }}</td></tr>{% endfor %}</tbody></table></div>{% endif %}{% else %}<p class="muted text-sm">No earlier non-dry run to compare against.</p>{% endif %}
|
||
|
||
<h2>Near misses</h2>
|
||
{% if near_misses.is_empty() %}<p class="muted text-sm">None recorded.</p>{% else %}<div class="scroll-x"><table>
|
||
<thead><tr><th class="num">#</th><th class="num">score</th><th>title</th><th>feed</th><th class="num">quality</th><th class="num">fit</th><th>stage</th><th>reason</th></tr></thead>
|
||
<tbody>{% for miss in near_misses %}<tr><td class="num text-muted">{{ loop.index }}</td><td class="num">{{ miss.score }}</td><td class="cell-wrap"><a href="{{ miss.href }}">{{ miss.title }}</a></td><td class="cell-tight text-muted">{{ miss.feed }}</td><td class="num">{{ miss.quality }}</td><td class="num">{{ miss.fit }}</td><td class="cell-tight"><span class="badge {{ miss.stage }}">{{ miss.stage }}</span></td><td class="cell-wrap text-muted">{% if let Some(reason) = miss.reason %}{{ reason }}{% endif %}</td></tr>{% endfor %}</tbody></table></div>{% endif %}
|
||
|
||
<h2>Candidates</h2>
|
||
<form class="filters" method="get" action="/dashboard/runs/{{ run.id }}">
|
||
<label>Stage <select name="stage"><option value="">any</option>{% for name in stages %}<option value="{{ name }}"{% if let Some(current) = filters.stage %}{% if current.as_str() == *name %} selected{% endif %}{% endif %}>{{ name }}</option>{% endfor %}</select></label>
|
||
<label>Reason <select name="reason"><option value="">any</option>{% for name in reasons %}<option value="{{ name }}"{% if let Some(current) = filters.reason %}{% if current.as_str() == *name %} selected{% endif %}{% endif %}>{{ name }}</option>{% endfor %}</select></label>
|
||
<label>Admitted by <select name="admitted_by"><option value="">any</option>{% for name in retrievers %}<option value="{{ name }}"{% if let Some(current) = filters.admitted_by %}{% if current.as_str() == *name %} selected{% endif %}{% endif %}>{{ name }}</option>{% endfor %}</select></label>
|
||
<label>Flag <select name="flag"><option value="">any</option><option value="exploration"{% if let Some(current) = filters.flag %}{% if current == "exploration" %} selected{% endif %}{% endif %}>exploration</option><option value="auto"{% if let Some(current) = filters.flag %}{% if current == "auto" %} selected{% endif %}{% endif %}>auto-include</option></select></label>
|
||
<label>Title <input type="search" name="q" value="{% if let Some(q) = filters.q %}{{ q }}{% endif %}" placeholder="contains…"></label>
|
||
<label>Sort <select name="sort">{% for name in sorts %}<option value="{{ name }}"{% if filters.sort == *name %} selected{% endif %}>{{ name }}</option>{% endfor %}</select></label>
|
||
<div class="filter-actions"><button class="btn" type="submit">Apply</button> <a class="btn-quiet" href="/dashboard/runs/{{ run.id }}">Reset</a></div>
|
||
</form>
|
||
{% include "dashboard/_pager.html" %}
|
||
{% if candidates.len() > 1 %}<input type="search" class="table-filter" placeholder="Filter rows on this page" aria-label="Filter rows on this page" data-table-filter>{% endif %}<div class="scroll-x tall"><table class="candidates" data-filter>
|
||
<thead><tr><th>title</th><th>feed</th><th class="num">words</th><th>stage</th><th>reason</th><th>admitted by</th><th class="num">utility</th><th class="num">rank</th><th class="num">cluster</th><th class="num">triage</th><th class="num">quality</th><th class="num">fit</th><th>flags</th></tr></thead>
|
||
<tbody>{% for candidate in candidates %}{% include "_candidate_row.html" %}{% endfor %}{% if candidates.is_empty() %}<tr><td colspan="13" class="text-muted">No candidates match this filter.</td></tr>{% endif %}</tbody></table></div>
|
||
{% include "dashboard/_pager.html" %}
|
||
</section>{% endblock %}
|