{"record":{"id":"3eec1581705b010d","repo":"tursodatabase/turso","slug":"ranked-row-count-mismatch","errorCode":null,"errorMessage":"ranked row count mismatch","messagePattern":"ranked row count mismatch","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"perf/fts/src/main.rs","lineNumber":333,"sourceCode":"}\n\nfn validate_result(\n    case: QueryCase,\n    documents: usize,\n    queries: usize,\n    rows: usize,\n    sum: i64,\n) -> Result<()> {\n    let ids = (0..documents).filter(|id| match case {\n        QueryCase::Rare => id % 100 == 0,\n        QueryCase::Common => true,\n        QueryCase::And => id % 6 == 0,\n        QueryCase::Or | QueryCase::Ranked => id % 2 == 0 || id % 3 == 0,\n        QueryCase::Phrase => id % 200 == 0,\n    });\n    let expected_rows = ids.clone().count();\n    if matches!(case, QueryCase::Ranked) {\n        ensure!(\n            rows == expected_rows.min(10) * queries,\n            \"ranked row count mismatch\"\n        );\n    } else {\n        ensure!(\n            rows == expected_rows * queries,\n            \"row count mismatch for {case:?}\"\n        );\n        ensure!(\n            sum == ids.map(|id| id as i64).sum::<i64>() * queries as i64,\n            \"ID sum mismatch for {case:?}\"\n        );\n    }\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {","sourceCodeStart":315,"sourceCodeEnd":351,"githubUrl":"https://github.com/tursodatabase/turso/blob/8d4a589f8d13ac184700d2a8f724f27e1995be3b/perf/fts/src/main.rs#L315-L351","documentation":"validate_result compares the rows returned by the benchmark query against a count recomputed from the seeded data predicate. For QueryCase::Ranked, expected rows are capped by the LIMIT 10 of the ranked query and multiplied by the number of query executions; ensure! at perf/fts/src/main.rs:333 fails when the observed row count differs, meaning the engine returned a different result set than the model predicts.","triggerScenarios":"Calling validate_result with case == Ranked where rows != expected_rows.min(10) * queries — i.e. the FTS engine returned more or fewer matching rows than the capped expectation, typically indicating a query engine, ranking/LIMIT, or MVCC visibility discrepancy.","commonSituations":"Running the validation under WAL/MVCC where visibility differs; a Turso FTS bug returning duplicate or missing rows; changing the LIMIT or query text without updating validate_result; concurrency races writing rows between seed and validation.","solutions":["Re-run with a single query (--queries 1) to isolate whether the mismatch is per-query or aggregate","Diff the actual returned rows against ids.filter(predicate).take(10) to see what is missing/extra","Check for concurrent writers or MVCC snapshot differences between seeding and validation","Update validate_result if the query's LIMIT or predicate legitimately changed"],"exampleFix":"// before (assumes no cap)\nassert_eq!(rows, expected_rows * queries);\n// after (ranked queries are LIMIT 10)\nassert_eq!(rows, expected_rows.min(10) * queries);","handlingStrategy":"try-catch","validationCode":"// compute expectation locally before validating\nlet expected: usize = (0..n).filter(|&id| id % 2 == 0 || id % 3 == 0).count().min(10) * queries;","typeGuard":null,"tryCatchPattern":"match validate_result(...) {\n    Err(e) if e.to_string().contains(\"ranked row count mismatch\") => {\n        // dump actual vs expected rows for diagnosis\n        eprintln!(\"ranked mismatch: got {rows}, want {expected}\");\n    }\n    other => other?,\n}","preventionTips":["Ensure seeding completes and is visible before validation queries run","Keep validate_result's predicate in sync with the emitted query LIMIT","Avoid concurrent writers during validation runs","Reproduce mismatches with --queries 1 first"],"tags":["validation","fts","result-mismatch","benchmark"],"backgroundTag":"unexpected-response-shape","analyzedSha":"8d4a589f8d13ac184700d2a8f724f27e1995be3b","analyzedAt":"2026-09-20T13:18:14.658Z","contentChangedAt":"2026-09-20T13:18:14.658Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}