{"record":{"id":"7656e8c0ecd43a3f","repo":"block/buzz","slug":"count-gate-on","errorCode":null,"errorMessage":"count, gate on","messagePattern":"count, gate on","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/buzz-db/src/runtime/tests.rs","lineNumber":1635,"sourceCode":"        let mut q = EventQuery::for_community(cid);\n        q.channel_id = Some(channel);\n        q.until = chrono::DateTime::from_timestamp((base + 60) as i64, 0);\n        q\n    };\n\n    // Budget unset ⇒ bounded arm disabled ⇒ writer.\n    let n = db\n        .count_events_routed(\"test_count\", &q)\n        .await\n        .expect(\"count, gate off\");\n    assert_eq!(n, 2, \"budget unset must count on the writer\");\n\n    // Budget set + fresh entry ⇒ bounded arm ⇒ replica.\n    db.set_replica_read_max_age_for_tests(Some(std::time::Duration::from_secs(5)));\n    let n = db\n        .count_events_routed(\"test_count\", &q)\n        .await\n        .expect(\"count, gate on\");\n    assert_eq!(n, 1, \"budget set must count on the replica (bounded)\");\n\n    // Entry older than the budget ⇒ bounded fails ⇒ writer. Covered\n    // would still hold here (upper <= wall) — proving count never\n    // consults it.\n    db.fence().close();\n    db.fence().force_open_for_tests_at(\n        chrono::Utc::now(),\n        std::time::Instant::now() - std::time::Duration::from_secs(10),\n    );\n    let n = db\n        .count_events_routed(\"test_count\", &q)\n        .await\n        .expect(\"count, entry too old\");\n    assert_eq!(\n        n, 2,\n        \"an over-budget entry must fail the count closed to the writer, \\\n             even when the covered arm would admit the shape\"","sourceCodeStart":1617,"sourceCodeEnd":1653,"githubUrl":"https://github.com/block/buzz/blob/dad5a33865fc81a2e55b3b60746632f615ec1e3a/crates/buzz-db/src/runtime/tests.rs#L1617-L1653","documentation":"This is `.expect(\"count, gate on\")` on `count_events_routed` after `set_replica_read_max_age_for_tests(Some(5s))` enables the bounded arm, so the count must be served from the replica pool. The expect panics if the replica-served COUNT fails — typically a replica connectivity or schema problem. Its distinct label lets you tell which routing arm was active when the query failed.","triggerScenarios":"Calling `count_events_routed` on the bounded/replica arm in `count_events_routed_is_bounded_only` when the replica scratch DB is down, unmigrated, or its connection pool has been closed or timed out; also if the fenced entry is missing so routing errors instead of falling back.","commonSituations":"Replica scratch DB dropped by a prior failed test run; `fence().force_open_for_tests` not called before enabling the budget; stale connection after long-running seeds; Postgres restart between arms of the test.","solutions":["Verify the replica scratch DB (`cnt_r`) still exists and has the events schema/migrations.","Call `db.fence().force_open_for_tests(chrono::Utc::now())` before setting the budget so a fresh proved entry exists.","Print the inner sqlx error instead of panicking with just the label to see the root cause.","Restart Postgres and re-run; drop leftover scratch DBs from prior runs.","Confirm `set_replica_read_max_age_for_tests(Some(Duration::from_secs(5)))` precedes this call."],"exampleFix":"// before\nlet n = db.count_events_routed(\"test_count\", &q).await.expect(\"count, gate on\");\n// after\nlet n = db.count_events_routed(\"test_count\", &q).await\n    .unwrap_or_else(|e| panic!(\"count (gate on / replica bounded) failed: {e}\"));","handlingStrategy":"validation","validationCode":"// Confirm replica readiness and a fresh fence entry before the bounded arm\nsqlx::query(\"SELECT 1\").execute(db.replica()).await.expect(\"replica unreachable\");\ndb.fence().force_open_for_tests(chrono::Utc::now());\ndb.set_replica_read_max_age_for_tests(Some(std::time::Duration::from_secs(5)));","typeGuard":"fn budget_enabled(db: &Db) -> bool { db.replica_read_max_age().is_some() }","tryCatchPattern":"let n = db.count_events_routed(\"test_count\", &q).await\n    .unwrap_or_else(|e| panic!(\"bounded count failed (replica arm): {e}\"));","preventionTips":["Open the fence and force a fresh entry before enabling the budget","Check the replica scratch DB exists and is migrated","Avoid long seed phases that let pools idle-timeout","Drop stale scratch DBs from previous runs"],"tags":["postgres","database","test-panic","replica-routing"],"backgroundTag":"postgres-query-failed","analyzedSha":"dad5a33865fc81a2e55b3b60746632f615ec1e3a","analyzedAt":"2026-08-30T13:49:18.474Z","contentChangedAt":"2026-08-30T13:49:18.474Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}