feat: save job_id on syntheses for provenance lookup

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
master
oabrivard 3 months ago
parent eba721266f
commit 0e2c69edf7

@ -20,7 +20,7 @@ pub async fn list_for_user(
) -> Result<Vec<Synthesis>, AppError> {
let rows = sqlx::query_as::<_, Synthesis>(
r#"
SELECT id, user_id, week, sections, status, created_at
SELECT id, user_id, week, sections, status, created_at, job_id
FROM syntheses
WHERE user_id = $1
ORDER BY created_at DESC
@ -42,7 +42,7 @@ pub async fn list_for_user(
pub async fn get_by_id(pool: &PgPool, id: Uuid) -> Result<Option<Synthesis>, AppError> {
let row = sqlx::query_as::<_, Synthesis>(
r#"
SELECT id, user_id, week, sections, status, created_at
SELECT id, user_id, week, sections, status, created_at, job_id
FROM syntheses
WHERE id = $1
"#,
@ -64,7 +64,7 @@ pub async fn get_by_id_for_user(
) -> Result<Option<Synthesis>, AppError> {
let row = sqlx::query_as::<_, Synthesis>(
r#"
SELECT id, user_id, week, sections, status, created_at
SELECT id, user_id, week, sections, status, created_at, job_id
FROM syntheses
WHERE id = $1 AND user_id = $2
"#,
@ -86,17 +86,19 @@ pub async fn create(
user_id: Uuid,
week: &str,
sections_json: &serde_json::Value,
job_id: Uuid,
) -> Result<Synthesis, AppError> {
let row = sqlx::query_as::<_, Synthesis>(
r#"
INSERT INTO syntheses (user_id, week, sections, status)
VALUES ($1, $2, $3, 'completed')
RETURNING id, user_id, week, sections, status, created_at
INSERT INTO syntheses (user_id, week, sections, status, job_id)
VALUES ($1, $2, $3, 'completed', $4)
RETURNING id, user_id, week, sections, status, created_at, job_id
"#,
)
.bind(user_id)
.bind(week)
.bind(sections_json)
.bind(job_id)
.fetch_one(pool)
.await?;

@ -32,6 +32,7 @@ pub struct Synthesis {
pub sections: serde_json::Value,
pub status: String,
pub created_at: DateTime<Utc>,
pub job_id: Option<Uuid>,
}
/// Response shape for `GET /api/v1/syntheses/:id`.
@ -254,6 +255,7 @@ mod tests {
sections,
status: "completed".into(),
created_at: Utc::now(),
job_id: None,
};
let list_item = SynthesisListItem::try_from(synthesis).unwrap();
@ -270,6 +272,7 @@ mod tests {
sections: serde_json::json!([]),
status: "completed".into(),
created_at: Utc::now(),
job_id: None,
};
let list_item = SynthesisListItem::try_from(synthesis).unwrap();
@ -295,6 +298,7 @@ mod tests {
sections,
status: "completed".into(),
created_at: Utc::now(),
job_id: None,
};
let response = SynthesisResponse::try_from(synthesis).unwrap();
@ -312,6 +316,7 @@ mod tests {
sections: serde_json::json!("not an array"),
status: "completed".into(),
created_at: Utc::now(),
job_id: None,
};
assert!(SynthesisResponse::try_from(synthesis).is_err());
@ -326,6 +331,7 @@ mod tests {
sections: serde_json::Value::Null,
status: "completed".into(),
created_at: Utc::now(),
job_id: None,
};
let response = SynthesisResponse::try_from(synthesis).unwrap();

@ -250,7 +250,7 @@ pub async fn run_generation(
/// Inner implementation of the generation pipeline, returning a Result.
async fn run_generation_inner(
_job_id: Uuid,
job_id: Uuid,
state: &AppState,
user_id: Uuid,
tx: &watch::Sender<ProgressEvent>,
@ -808,7 +808,7 @@ async fn run_generation_inner(
let sections_json = sanitize_json_null_bytes(sections_json);
let synthesis =
db::syntheses::create(&state.pool, user_id, &week, &sections_json).await?;
db::syntheses::create(&state.pool, user_id, &week, &sections_json, job_id).await?;
// Record article URLs in history for cross-synthesis dedup
if settings.article_history_days > 0 {

Loading…
Cancel
Save