fix/mrr-base
needs attentionviewing older commite807453 · incrementalpre-PRreviewed 2026-08-11 19:07 UTC0H · 2M · 3L · 8I- Purpose
- Fix gaps in the PostHog annotation pipeline (MRR credit model + deploy trigger gate)
- Goal
- Ensure deploy annotations fire for ALL behavioral prod promotions (CDK/DB/Tinybird-only, not just Vercel), with self-describing DEPLOY_LANES metadata; fix MRR credit model under-reporting base-fee orgs
- Sub-goals
- SG-1: Broaden posthog-annotate trigger from vercel-only to any behavioral lane
- SG-2: Add DEPLOY_LANES env to make each marker self-describing (partial vs full promote)
- SG-3: Explicitly exclude posthog-apply as annotation trigger (analytics config ≠ deploy)
- SG-4: Fix MRR credit model base_price drop (earlier commit, last reviewed)
- What
- This incremental: workflow `posthog-annotate` job condition broadened from `vercel-promote == success` to `(vercel-promote OR cdk-deploy OR db-migrate OR tinybird-prod) == success`; DEPLOY_LANES env added; annotation script renders lanes in content; rule SSOT updated to match
- Why
- A CDK-only or Tinybird-only prod promotion previously produced no annotation marker, making those deploys invisible on PostHog charts — the gap that motivated this fix
- Areas
- .claude/rules/posthog-annotations.md+16−6.github/workflows/release-promote.yml+15−2scripts/posthog-annotate.mjs+8−0
- Blast
- 3 files, +39/−8 total on branch; scripts and CI only — no domain logic, no DB, no API surface
Findings · 11
correctness4
DEPLOY_LANES space-concatenation relies on script normalization to be safe
.github/workflows/release-promote.yml
Lanes are joined with trailing spaces ('cdk ', 'db ', etc.) in the >- block scalar, then the script does `.trim().replace(/\s+/g, ', ')` to normalize. This works today but the correctness contract is split across two files — if a future lane is added without the trailing space, or the script's normalization changes, the output silently breaks. Low runtime risk right now (trim/replace handles all whitespace permutations), but the design is fragile.
posthog-apply exclusion is implicit via `needs` list absence
.github/workflows/release-promote.yml
posthog-apply is correctly excluded because it's absent from posthog-annotate's `needs` array (so its result is never reachable in the if-condition). This is correct, but if someone later adds posthog-apply to `needs` for ordering (e.g., a future sequencing requirement), its result would silently become available without being in the condition. The rule documents this exclusion clearly, which mitigates the risk.
!cancelled() guard correctly allows annotation after partial-cancellation
.github/workflows/release-promote.yml
Without !cancelled(), the job would skip if the workflow was cancelled after a lane already succeeded. The guard correctly allows the annotation to fire in partial-cancellation scenarios — intentional per the 'marker fires even if post-flight health was red' design.
>- block scalar correctly produces space-separated lane tokens
.github/workflows/release-promote.yml
The folded-strip scalar folds newlines into spaces and strips trailing newlines. Each ${{ }} expression on the same logical line is concatenated. Result is a single whitespace-separated string like 'cdk db vercel tinybird' or any subset. The script's normalize handles it correctly.
security2
DEPLOY_LANES contains only hardcoded workflow literals — zero injection surface
.github/workflows/release-promote.yml
DEPLOY_LANES is assembled from GitHub Actions ternary expressions over job result strings (GitHub-controlled enum values). The four token values ('cdk ', 'db ', 'vercel ', 'tinybird') are string literals in the workflow YAML — no user input, PR title, branch name, or external data flows in.
Job permissions are minimal (contents: read only)
.github/workflows/release-promote.yml
posthog-annotate job declares only contents: read. No id-token, no packages, no PR write. The override correctly scopes down from the workflow-level id-token: write.
conventions1
Rule SSOT updated in sync with code — correct pattern
.claude/rules/posthog-annotations.md
The rule, script, and workflow were updated together in the same commit. DEPLOY_LANES env var name is consistent between workflow (`DEPLOY_LANES:`) and script (`process.env.DEPLOY_LANES`). posthog-apply is absent from the if-condition. continue-on-error: true is preserved. All non-negotiables intact.
tests1
No unit tests for DEPLOY_LANES — consistent with project conventions for scripts/
scripts/posthog-annotate.mjs
The new DEPLOY_LANES transform is two trivial lines. No test files exist for any posthog-*.mjs script, consistent with project norms for this layer. Workflow condition changes are not unit-testable. No coverage gap.
improvement3
Adding a new lane requires updating two places: if-condition AND DEPLOY_LANES
.github/workflows/release-promote.yml
The job's `if` condition and the `DEPLOY_LANES` env var both enumerate the same four lanes (cdk-deploy, db-migrate, vercel-promote, tinybird-prod). When a new behavioral lane is added, a developer must update both without structural enforcement. A set-lanes step that emits `has_deployments` + `lanes` outputs would make both consumers derive from one source. Current approach is DRY-violating at the workflow level.
Whitespace normalization contract between workflow and script is undocumented
scripts/posthog-annotate.mjs
The script's `.replace(/\s+/g, ', ')` silently corrects the workflow's space-separated token format. A comment (`// DEPLOY_LANES is space-separated from CI; normalize to comma-separated`) would make this coupling explicit and prevent a future caller from being surprised that the normalization happens here rather than at the source.
No DEPLOY_LANES allowlist — unexpected values appear verbatim in annotation
scripts/posthog-annotate.mjs
The script trusts DEPLOY_LANES verbatim after whitespace normalization. A simple allowlist check (known values: cdk, db, vercel, tinybird) with warn-and-continue would make annotation content more reliable without adding failure risk. Low priority since the workflow only ever sets hardcoded string literals.