Skip to content

Drop white-box SQL-shape test for retention prune #16

Description

@BumpyClock

Problem

retention_prune_sql_deletes_offset_tail (line 374) asserts internal SQL fragments emitted by retention_prune_sql() (line 209) rather than any observable runtime outcome:

// crates/core/src/storage/history.rs  lines 374–396
#[test]
fn retention_prune_sql_deletes_offset_tail() {
    let sql = HistoryDb::retention_prune_sql();

    assert!(sql.contains("LIMIT -1 OFFSET ?1"),);
    assert!(sql.contains("WHERE id IN ("),);
    assert!(!sql.to_ascii_lowercase().contains("not in"),);
    assert!(sql.contains("ORDER BY created_at DESC, id DESC"),);
}

The test calls retention_prune_sql() directly and string-matches on "LIMIT -1 OFFSET ?1", "WHERE id IN (", "NOT IN", and "ORDER BY created_at DESC, id DESC".
Any semantics-preserving rewrite of the helper (e.g. switching to a NOT IN anti-join, a CTE, or a DELETE … RETURNING-based approach) would break this test even if the three behavior tests below continue to pass.

Behavior already covered by adjacent tests:

Test Lines What it verifies
retention_prunes_to_max_rows_and_keeps_newest 322–371 Row count == cap; oldest survivor is correct
retention_prune_helper_deletes_zero_when_under_cap 399–437 No delete when at- or under-cap
retention_prune_helper_deletes_oldest_tail_over_cap 440–481 Exactly overflow rows deleted; oldest survivor correct

Why it matters

  • Refactor friction. Any SQL simplification (relevant if the COUNT(*) guard at line 225 is replaced) requires updating this test even when behavior is unchanged. The test becomes a false failure gate.
  • No new coverage. The three behavior tests already exercise every correctness property the SQL-shape assertions imply. This test adds zero protection against regressions.
  • Coupled churn risk. The COUNT(*) pre-check at lines 225–230 is a known candidate for removal (see Coupled Issue below). If the prune SQL changes as a result, this test will fail for unrelated reasons, creating noise in review.

Proposed change

  1. Delete retention_prune_sql_deletes_offset_tail (lines 374–396) entirely.
  2. If there is concern about the OFFSET-based strategy being accidentally abandoned: add a single EXPLAIN QUERY PLAN assertion (matching the existing recent_query_uses_index test at line 497) that verifies the prune query walks idx_history_recent rather than doing a full scan — this tests the performance contract, not the SQL shape.
  3. No other test changes required. The three behavior tests remain the source of truth.

Guard: before deleting, confirm retention_prunes_to_max_rows_and_keeps_newest, retention_prune_helper_deletes_zero_when_under_cap, and retention_prune_helper_deletes_oldest_tail_over_cap all pass green.

Recommendation / triage

DO — but coupled with the COUNT(*) issue. If the COUNT(*) pre-check in prune_old_entries (lines 225–230) is simplified or removed, the prune SQL will change anyway, and this test will need updating regardless. Decide the count-query issue first, then drop or rewrite retention_prune_sql_deletes_offset_tail in the same PR to avoid touching this file twice.

Acceptance criteria

  • retention_prune_sql_deletes_offset_tail is removed (or replaced with an EXPLAIN QUERY PLAN-based index-use assertion).
  • retention_prunes_to_max_rows_and_keeps_newest passes — row count equals cap, correct oldest survivor.
  • retention_prune_helper_deletes_zero_when_under_cap passes — zero rows deleted at- and under-cap.
  • retention_prune_helper_deletes_oldest_tail_over_cap passes — exact overflow deleted, correct oldest survivor.
  • recent_query_uses_index passes (no regression on read-path index).
  • No new SQL-shape string assertions are introduced as replacements.

Traceability

clawpatch finding ID: fnd_sig-feat-ui-flow-5955f2836e-370d_b05afa5ba8

Revalidate command:

clawpatch revalidate --finding fnd_sig-feat-ui-flow-5955f2836e-370d_b05afa5ba8 --reasoning-effort high

Coupled issue: This change should be batched with the COUNT(*) pre-check decision in prune_old_entries (line 225). Resolve that issue first; land both changes in the same PR.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    deslopifyFound by clawpatch deslopify reviewtech-debtCode quality / maintainability cleanup

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions