Skip to content

feat(cohorts): add version and sweep tables to cohort_membership - #89795

Merged
trunk-io[bot] merged 4 commits into
posthog-self-driving/chorecohorts-settle-membership-origin-6314b9from
matheus-vb/cohort-membership-sweep-schema
Aug 28, 2026
Merged

trunk-io[bot] merged 4 commits into
posthog-self-driving/chorecohorts-settle-membership-origin-6314b9from
matheus-vb/cohort-membership-sweep-schema

Conversation

@matheus-vb

@matheus-vb matheus-vb commented Aug 27, 2026 •

Copy link
Copy Markdown
Member

Problem

Someone who stops matching an edited cohort keeps an in_cohort = true row forever, so feature flags still treat them as a member.

Deleting those rows needs a way to tell a stale row from a current one, and cohort_membership has no version column.

This PR adds only the schema. The consumer and sweeper that use it are the next PR in the stack.

Part of #88014.

Changes

  • version holds the producer's monotonic stamp, the same value ClickHouse already orders this data on.
  • The column is nullable with no default, so the statement does not rewrite the table. A lock_timeout bounds how long the DDL can park readers behind its lock.
  • A NULL version reads as older than anything the pipeline stamped, which is what rows written before this feature are.
  • cohort_membership_sweeps records which reconcile run has certified a cohort, including when it turned ready and which pod holds its sweep claim.
  • cohort_membership_consumer_progress records how far the consumer applied each partition, keyed by broker cluster so offsets survive a topic moving clusters without lying.
  • An index on (team_id, cohort_id, version) lets the sweep page through one cohort and stop early. It builds CONCURRENTLY in its own no-transaction migration file, so the build never blocks the consumer's writes.
  • Nothing reads or writes these yet, so no behavior changes.

Ships ahead of the code so the schema is live before the sweep flag ever flips. The next PR gates all new writes behind that flag.

How did you test this code?

Applied all three migrations against a local test_behavioral_cohorts database with rust/bin/migrate-entry behavioral-cohorts, then inspected the resulting schema.

No tests here. The next PR in the stack exercises these tables.

👉 Stay up-to-date with PostHog coding conventions for a smoother review.

Automatic notifications

  • Publish to changelog?

Docs update

None.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Authored with Claude Code (Opus) from a design document for issue #88014. Review fixes applied with Claude Code (Fable).

Skills invoked: /implement-plan, /writing-pr-descriptions.

Split out of a single branch so the migrations land on their own. ci-migrations-service-separation-check rejects a PR that touches rust/behavioral_cohorts_migrations/*.sql together with nodejs/**, and the deploy order wants the schema first regardless.

@matheus-vb
matheus-vb requested a review from a team August 27, 2026 00:42
@posthog-project-board-bot posthog-project-board-bot Bot moved this to In Review in Feature Flags Aug 27, 2026
@pr-assigner-resolver-posthog
pr-assigner-resolver-posthog Bot requested a review from a team August 27, 2026 00:42
@matheus-vb
matheus-vb removed the request for review from a team August 27, 2026 00:43
@github-actions

Copy link
Copy Markdown
Contributor

🤖 CI report

✅ Trunk lane — non-backend lane

This PR is assigned to the non-backend lane. It does not run backend Python tests and may merge in parallel with PRs in other lanes.

@trunk-io

trunk-io Bot commented Aug 27, 2026 •

Copy link
Copy Markdown

Static Badge   Static Badge   Static Badge

View Full Report ↗︎ ⋅ Docs

@matheus-vb
matheus-vb requested a review from a team as a code owner August 27, 2026 13:43
@matheus-vb
matheus-vb force-pushed the matheus-vb/cohort-membership-sweep-schema branch from 9e80916 to cf830c4 Compare August 27, 2026 13:44

@haacked haacked left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, the lock_timeout and CONCURRENTLY handling are right. A few schema suggestions inline, mostly things that get expensive once these tables have rows.

@github-project-automation github-project-automation Bot moved this from In Review to Approved in Feature Flags Aug 27, 2026
@matheus-vb
matheus-vb force-pushed the matheus-vb/cohort-membership-sweep-schema branch from cf830c4 to 9db4b4b Compare August 27, 2026 17:35
@matheus-vb
matheus-vb force-pushed the matheus-vb/cohort-membership-sweep-schema branch from 7421354 to 99ae613 Compare August 27, 2026 19:56
The consumer only upserts, so a person who stops matching an edited
cohort keeps in_cohort = true forever. Sweeping those rows needs a
version column and per-run sweep bookkeeping tables.

`version` is nullable with no default: the DDL is catalog-only and NULL
reads as older than anything stamped. Must land before the consumer
that writes it.
@matheus-vb
matheus-vb force-pushed the matheus-vb/cohort-membership-sweep-schema branch from 1560d7e to 7be5ca9 Compare August 28, 2026 13:21
@trunk-io
trunk-io Bot merged commit e046be5 into master Aug 28, 2026
209 checks passed
@github-project-automation github-project-automation Bot moved this from Approved to Done in Feature Flags Aug 28, 2026
@trunk-io
trunk-io Bot deleted the matheus-vb/cohort-membership-sweep-schema branch August 28, 2026 14:53
@trunk-io

trunk-io Bot commented Aug 28, 2026

Copy link
Copy Markdown

This pull request was merged into master as part of stacked PR 89797.

@deployment-status-posthog

deployment-status-posthog Bot commented Aug 28, 2026 •

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-08-28 15:21 UTC Run
prod-us ✅ Deployed 2026-08-28 15:43 UTC Run
prod-eu ✅ Deployed 2026-08-28 15:40 UTC Run

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

Labels

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

2 participants