Curation v2 step 6: Behind the paper, stats, run report block, lock

Behind-the-paper chapter (behind.xhtml, both editions) built from the run's
StageCounts and candidate_runs near misses; daily-epub stats [--days N];
StageCounts gains knn/feed gates and verdicts_in_prompt, timings split
into summaries + brief, the four-line §15.4 info block logged once per
run and printed by print_report; src/lock.rs flock guard on
<database_path>.lock for generate, profile rebuild, features backfill and
backfill-social; README updated for the new CLI, env vars and costs.

Implemented by a Claude agent from docs/plans/curation-v2-briefs/step6.md;
reviewed against plan §5, §15.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A1rCLQeKBgnBo3oTgHuTMe
This commit is contained in:
thalladaandClaude Fable 5.1 committed 2026-09-02 16:21:06 +00:00
1 parent 05a74a0dcf
commit d261cd485d
22 files changed
+1583 -113

No files matched your search

+14 -3
View File
@@ -112,17 +112,28 @@ impl Curator {
}
}
/// Stage C: per-article summaries, section intros and the front page (§3.6).
/// Stage C: per-article summaries and the Brief (§14).
///
/// Never fails the run: a budget trip or an API error degrades to excerpts.
pub async fn editorial(&self, lineup: &Lineup) -> anyhow::Result<Editorial> {
Ok(self.editorial_timed(lineup).await?.0)
}
/// [`Self::editorial`] plus the `summaries` / `brief` stage timings (§15.4).
pub async fn editorial_timed(
&self,
lineup: &Lineup,
) -> anyhow::Result<(Editorial, editorial::EditorialTimings)> {
if self.llms.editor_or_bulk().is_none() {
tracing::info!("--skip-llm: using feed excerpts as summaries");
return Ok(editorial::fallback_editorial(lineup));
return Ok((
editorial::fallback_editorial(lineup),
editorial::EditorialTimings::default(),
));
}
let span = tracing::info_span!("llm_editorial", picks = lineup.picks.len());
let _guard = span.enter();
Ok(editorial::run(
Ok(editorial::run_timed(
&self.llms,
lineup,
&self.config.editorial,