feat(gamification): flag cascade-completed parents as auto_completed
complete_subtask_and_check_parent now sets auto_completed = 1 on the parent when it closes via the cascade. The subtask UPDATE itself remains at the default 0, so explicit user taps still count toward the Phase 8 daily total. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -451,7 +451,13 @@ pub async fn complete_subtask_and_check_parent(pool: &SqlitePool, subtask_id: &s
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
if pending == 0 {
|
if pending == 0 {
|
||||||
sqlx::query("UPDATE tasks SET done = 1, done_at = datetime('now') WHERE id = ?")
|
// Phase 8: flag the cascade so the daily-count query can exclude
|
||||||
|
// it. The subtask UPDATE (above) stays at auto_completed = 0 — the
|
||||||
|
// user explicitly ticked it, so it counts.
|
||||||
|
sqlx::query(
|
||||||
|
"UPDATE tasks SET done = 1, done_at = datetime('now'), auto_completed = 1 \
|
||||||
|
WHERE id = ?",
|
||||||
|
)
|
||||||
.bind(&pid)
|
.bind(&pid)
|
||||||
.execute(&mut *tx)
|
.execute(&mut *tx)
|
||||||
.await
|
.await
|
||||||
@@ -2016,4 +2022,59 @@ mod tests {
|
|||||||
let missing = get_setting(&pool, "nonexistent").await.unwrap();
|
let missing = get_setting(&pool, "nonexistent").await.unwrap();
|
||||||
assert!(missing.is_none());
|
assert!(missing.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn cascade_sets_auto_completed_on_parent_only() {
|
||||||
|
let pool = test_pool().await;
|
||||||
|
|
||||||
|
// Parent + two subtasks.
|
||||||
|
insert_task(
|
||||||
|
&pool,
|
||||||
|
"parent",
|
||||||
|
"Parent task",
|
||||||
|
"inbox",
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
insert_subtask(&pool, "s1", "Step 1", "parent")
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
insert_subtask(&pool, "s2", "Step 2", "parent")
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
complete_subtask_and_check_parent(&pool, "s1")
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
complete_subtask_and_check_parent(&pool, "s2")
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Parent auto-closed.
|
||||||
|
let parent_auto: i64 =
|
||||||
|
sqlx::query_scalar("SELECT auto_completed FROM tasks WHERE id = 'parent'")
|
||||||
|
.fetch_one(&pool)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
parent_auto, 1,
|
||||||
|
"parent closed by cascade must be auto_completed = 1"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Subtasks themselves are manual.
|
||||||
|
let s1_auto: i64 = sqlx::query_scalar("SELECT auto_completed FROM tasks WHERE id = 's1'")
|
||||||
|
.fetch_one(&pool)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let s2_auto: i64 = sqlx::query_scalar("SELECT auto_completed FROM tasks WHERE id = 's2'")
|
||||||
|
.fetch_one(&pool)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(s1_auto, 0, "subtask completion is manual");
|
||||||
|
assert_eq!(s2_auto, 0, "subtask completion is manual");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user