feat/mrr-pivot
needs attentionviewing older commit8df489e · incrementalpre-PRreviewed 2026-08-07 23:21 UTC2H · 1M · 3L- Purpose
- Establish a durable, repo-native pattern for PostHog insights that cannot be codified in Terraform due to HogQL SQL variables (interactive dropdowns unsupported by the posthog/posthog provider).
- Goal
- Add the MRR master-pivot insight (interactive recurring/one-time MRR table with group-by and filter dropdowns) and document the escape-hatch pattern so future maintainers know when and how to use it.
- Sub-goals
- SG-1: Implement `scripts/posthog-mrr-pivot.mjs` — idempotent creator for the MRR pivot insight (previous commit, already reviewed)
- SG-2: Codify the non-Terraform escape-hatch pattern in `.claude/rules/posthog-api-insights.md` with a registry of API-sourced insights
- What
- Added `.claude/rules/posthog-api-insights.md` documenting when/how to create PostHog insights via API script rather than Terraform, including a pseudocode template and a registry table. The actual MRR pivot script (`scripts/posthog-mrr-pivot.mjs`, 194 lines) was added in the previous commit on this branch.
- Why
- The PostHog Terraform provider lacks `insight_variable` resource support, so insights with interactive HogQL SQL variable dropdowns cannot be declared in `infra/posthog/`. Without a documented pattern they become orphaned UI clicks; this rule makes the escape hatch explicit, bounded, and findable.
- Areas
- .claude/rules/posthog-api-insights.md+91−0scripts/posthog-mrr-pivot.mjs+194−0
- Blast
- 2 files, +285 lines. Documentation rule + a standalone out-of-band script. Zero impact on application code, database, or CI pipeline.
Findings · 6
correctness3
Pseudocode keys by `spec.key` — field does not exist on VAR_SPECS
.claude/rules/posthog-api-insights.md:43
The pseudocode writes `codeNames[spec.key] = v.code_name`, implying each spec has a `key` property. The actual script keys its output map by `spec.name` (`out[spec.name]`). A developer following the pseudocode literally will get `undefined` as the map key for every variable, silently breaking the SQL interpolation step. Fix: change `spec.key` → `spec.name`.
Pseudocode omits pagination, `.json()` call, and `encodeURIComponent` on search
.claude/rules/posthog-api-insights.md:39
Three gaps versus the actual script: (1) Variable list call should be `/insight_variables/?page=1` + explicit `.json()` — without pagination the call silently truncates if the project has many variables; (2) Insight search uses `/insights/?search=${name}` with bare interpolation — the actual script uses `encodeURIComponent`, `&basic=true`, `&limit=100`; without encoding, an insight name with non-ASCII characters (·, ×, accents as in the MRR pivot) produces a malformed URL. These omissions are correctness traps for the next implementer.
Registry insight name truncated — does not match `INSIGHT_NAME` in script
.claude/rules/posthog-api-insights.md:74
Registry shows `MRR · pivote maestro` but the script's `INSIGHT_NAME` constant is `MRR · pivote maestro (producto × org × plan)`. The idempotency guarantee is keyed on this exact name — a truncated entry in the registry will mislead operators searching PostHog or grep-ing the codebase. Use the exact full string.
conventions2
Registry table will rot without enforcement
.claude/rules/posthog-api-insights.md:67
The registry is a manually maintained list parallel to what `ls scripts/posthog-*.mjs` already shows. There is no CI check to keep it current. If the 'Document it here' non-negotiable isn't caught in review, new scripts will be added without a registry entry. Either add a convention for how to verify it, or point readers to `ls scripts/posthog-*.mjs` as the derivable source of truth.
Auto-load glob omits workflow file (cf. sibling posthog-annotations.md)
.claude/rules/posthog-api-insights.md:7
`posthog-annotations.md` lists `.github/workflows/release-promote.yml` as a third auto-load trigger. This rule omits it. If a promote-job step ever calls one of these scripts, the rule won't auto-load for the workflow editor. Minor inconsistency with the established pattern.
improvement1
Delete instructions ambiguous: `PATCH { deleted: true }` vs `DELETE`
.claude/rules/posthog-api-insights.md:48
The doc shows both options without stating which to prefer. PostHog soft-deletes via PATCH; hard DELETE may behave differently. The actual script doesn't implement delete at all, so there's no reference to reconcile against. A brief note on the preferred approach (PATCH for soft-delete, consistent with the upsert's `!i.deleted` filter) would prevent guessing.