block/buzz · error

count, gate on

Error message

count, gate on

What it means

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.

Source

Thrown at crates/buzz-db/src/runtime/tests.rs:1635

        let mut q = EventQuery::for_community(cid);
        q.channel_id = Some(channel);
        q.until = chrono::DateTime::from_timestamp((base + 60) as i64, 0);
        q
    };

    // Budget unset ⇒ bounded arm disabled ⇒ writer.
    let n = db
        .count_events_routed("test_count", &q)
        .await
        .expect("count, gate off");
    assert_eq!(n, 2, "budget unset must count on the writer");

    // Budget set + fresh entry ⇒ bounded arm ⇒ replica.
    db.set_replica_read_max_age_for_tests(Some(std::time::Duration::from_secs(5)));
    let n = db
        .count_events_routed("test_count", &q)
        .await
        .expect("count, gate on");
    assert_eq!(n, 1, "budget set must count on the replica (bounded)");

    // Entry older than the budget ⇒ bounded fails ⇒ writer. Covered
    // would still hold here (upper <= wall) — proving count never
    // consults it.
    db.fence().close();
    db.fence().force_open_for_tests_at(
        chrono::Utc::now(),
        std::time::Instant::now() - std::time::Duration::from_secs(10),
    );
    let n = db
        .count_events_routed("test_count", &q)
        .await
        .expect("count, entry too old");
    assert_eq!(
        n, 2,
        "an over-budget entry must fail the count closed to the writer, \
             even when the covered arm would admit the shape"

View on GitHub (pinned to dad5a33865)

Solutions

  1. Verify the replica scratch DB (`cnt_r`) still exists and has the events schema/migrations.
  2. Call `db.fence().force_open_for_tests(chrono::Utc::now())` before setting the budget so a fresh proved entry exists.
  3. Print the inner sqlx error instead of panicking with just the label to see the root cause.
  4. Restart Postgres and re-run; drop leftover scratch DBs from prior runs.
  5. Confirm `set_replica_read_max_age_for_tests(Some(Duration::from_secs(5)))` precedes this call.

Example fix

// before
let n = db.count_events_routed("test_count", &q).await.expect("count, gate on");
// after
let n = db.count_events_routed("test_count", &q).await
    .unwrap_or_else(|e| panic!("count (gate on / replica bounded) failed: {e}"));
Defensive patterns

Strategy: validation

Validate before calling

// Confirm replica readiness and a fresh fence entry before the bounded arm
sqlx::query("SELECT 1").execute(db.replica()).await.expect("replica unreachable");
db.fence().force_open_for_tests(chrono::Utc::now());
db.set_replica_read_max_age_for_tests(Some(std::time::Duration::from_secs(5)));

Type guard

fn budget_enabled(db: &Db) -> bool { db.replica_read_max_age().is_some() }

Try / catch

let n = db.count_events_routed("test_count", &q).await
    .unwrap_or_else(|e| panic!("bounded count failed (replica arm): {e}"));

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of block/buzz@dad5a33865 (2026-08-30). Data as JSON: /api/errors/7656e8c0ecd43a3f. Report an issue: GitHub.