feat(library): attribute a run to a mission, and prove what it contributed
ci / gates (push) Failing after 7s
ci / rust (push) Skipped
ci / frontend (push) Skipped
ci / e2e (push) Skipped
ci / publish (push) Skipped

`corpus_items.mission_id` has existed since the table landed and nothing
could populate it. `POST /api/library/runs` now accepts `missionId`, which
is the seam the wizard needs: a mission-driven run is the same run, tagged.

`corpus::contributed()` answers the question a continuous mission has to
be able to answer — did THIS run add anything new. Because `record` never
reassigns mission_id on conflict, the mission that first found a source
keeps the credit, so a rerun cannot inflate its own count by re-recording
what an earlier run already held. The test asserts exactly that: two
missions see the same paper, the finder reports 1 and the rerun reports 0.

This is the check the 0030-0044 generation of continuous research did not
have. It could run weekly forever and every run looked like success.

The test also earned its FK: the first version attributed to a bare UUID
and the database refused it. Attribution to a mission that does not exist
is not attribution, so the test now seeds real mission rows.

400 tests, clippy clean.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
Omar Sobh
2026-08-03 11:43:41 -07:00
co-authored by Claude Opus 5
parent 9de2cf34e4
commit ad89ef94cd
3 changed files with 93 additions and 1 deletions
+6 -1
View File
@@ -26,6 +26,11 @@ pub struct RunRequest {
/// library can otherwise pull hundreds of PDFs in one go.
#[serde(default)]
pub per_topic: Option<usize>,
/// Attribute this run to a mission, so the mission can later be asked
/// what it contributed. `corpus_items.mission_id` has existed since the
/// table landed; without this field nothing could ever populate it.
#[serde(default, rename = "missionId")]
pub mission_id: Option<uuid::Uuid>,
}
#[derive(Serialize)]
@@ -80,7 +85,7 @@ pub async fn run(
&work_root,
&topics,
per_topic,
None,
req.mission_id,
)
.await
.map_err(|e| {