Skip to main content
← Back to list
01Issue
BugShippedagentPublic
Assigneeskeeb

Relationships

⊘ blocked by #927↔ sibling #925

#929 Incremental activity projector + swamp.events username bloom index (spun off #925, stages 5+7)

Opened by keeb · 7/2/2026· Shipped 8/15/2026

Spun out of #925's approved plan — the shadow-critical slice, kept separate so its parity gate gets undivided attention. Prerequisite: #927 (single-runner gate for the projector; both prod replicas currently run it and can double-grant same-day chunks — that race would poison this issue's parity validation).

Projector: full rescan → touched-set incremental (was #925 stage 5)

Every 60s tick, activity-asof-projector.sql (a) groups the entire all-history cli_daily rollup, (b) does FROM swamp.score_grants FINAL over every post-cutover grant (grant_type not pruned by the ORDER BY), (c) runs window CTEs over every user's full history. Cost grows linearly forever; will eventually blow the tick's 10-min timeout.

Plan:

  • CH migration: add last_seen SimpleAggregateFunction(max, DateTime) to swamp.cli_daily, populated by cli_daily_mv with max(now())ingest time, deliberately NOT max(created_at): the projector supports late-arriving events for old days ("late arrivals mint one more chunk"), and an event-time watermark would put a late arrival before the watermark and skip its chunk forever. Add a projector test for exactly this case. Ships via the clickhouse-migrations Job in giga-swamp (content-hash ConfigMap, Lab #859); infrastructure/clickhouse/init/02-score-grants.sql kept in lockstep.
  • activity-asof-projector.sql: add a touched CTE (distinct_ids with last_seen >= {WATERMARK}); scope the cli CTE to distinct_id IN touched (full backward history only for touched users — required for correct as-of streak/rolling windows) and the granted CTE the same way. Keep FINAL but scopeddistinct_id is the first ORDER BY column of score_grants, so this prunes by primary key. Do NOT build the SummingMergeTree granted-units table floated in #925: score_grants is a ReplacingMergeTree precisely so re-inserted deterministic grant_ids dedup; an insert-fed SummingMergeTree would double-count re-inserts and corrupt units_before.
  • activity-projector.ts: {WATERMARK} substitution with the same strict-validation pattern as {CUTOVER}; per-process watermark = previous tick start time; epoch on first tick (full pass, idempotent by design — a restart just does one expensive tick).
  • Parity gate before merge: as-of harness (mirror :8123 vs run DB :8133) — full-history pass and incremental pass must produce identical ledgers (same grant count, equal sums, matching grant_ids). Post-deploy: watch the prod shadow comparison board for drift.

swamp.events username bloom index (was #925 stage 7)

clickhouse-active-days-repository.ts filters swamp.events by username, but the only bloom filter is on distinct_id → full-table scan per user; backfill-score-grants.ts multiplies that by N operatives per pass.

Plan: ALTER TABLE swamp.events ADD INDEX on username (bloom_filter, same granularity as the distinct_id index) + MATERIALIZE INDEX over history, riding the same clickhouse-migrations batch as the projector change (a skip index is result-neutral, so it cannot muddy the parity gate). Leave the admin shadow board's three FINAL-over-ledger queries as-is (low frequency, admin-only); pre-aggregated owner-totals MV is the escape hatch if the board slows.

Full staging rationale, DDD analysis, and adversarial-review trail live in the #925 lifecycle.

02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED+ 1 MOREASSIGNED+ 2 MOREREVIEW+ 4 MOREPR_MERGED

Shipped

8/15/2026, 12:53:37 AM

No activity in this phase yet.

03Sludge Pulse
keeb assigned keeb8/14/2026, 10:04:57 PM
keeb linked related to #9257/2/2026, 9:57:19 PM
keeb linked blocked by #9277/2/2026, 9:57:23 PM
keeb marked as blocked7/2/2026, 9:57:23 PM
keeb unblocked automatically7/17/2026, 7:01:57 PM

Sign in to post a ripple.