This directory holds implementation plans for making the cloud (SaaS) plan benefits real, consistent, and tested, plus the Round-2 audit fixes and the Round-3 feature backlog.
Every benefit a plan advertises in
@chm/pricingis (a) rendered identically on the landing pricing page and the in-app billing page, and (b) actually enforced at runtime — or explicitly, visibly marked "not yet enforced" with a tracking test. No advertised benefit is silently unenforced; no surface drifts from the canonical source.
"Fail loud" applies: if a benefit can't be enforced yet, the plan says so and a test asserts the current contract so a future change can't regress it quietly.
Treat this table as the work queue. A plan is available when its row is
⏳ TODO and every plan it depends on is ✅ DONE. Dependency edges and the
per-wave kickoff prompts live in OVERNIGHT-SWARM.md; the
strategy + per-plan specs live in ROADMAP-2026H2.md.
Legend: ✅ DONE merged to main · 🔶 HELD PR open, needs a human
decision (see reason) · ⏳ TODO not started.
| # | Plan | Type | Risk |
|---|---|---|---|
| 01 | allow-private-hosts.md | feature (self-host) | low |
| 02 | plan-benefits-parity.md | correctness + tests | medium |
| 03 | blog-stat-strip.md | copy | trivial |
Security / correctness / perf fixes surfaced by the code audit. Each shipped as its own squash-merged PR (code only; the spec files are archived here).
| # | Plan | Status | PR |
|---|---|---|---|
| 04 | conversation-upsert-idor.md — scope upsert to owner (cross-tenant IDOR) | ✅ DONE | #2203 |
| 05 | health-webhook-auth-gate.md — write-auth on the SSRF proxy | ✅ DONE | #2204 |
| 06 | alert-commit-after-delivery.md — dedup state after delivery | ✅ DONE | #2205 |
| 07 | parallel-connection-chart-queries.md — parallel chart queries | ✅ DONE | #2206 |
| 08 | retention-prune-characterization-tests.md — cron prune tests | ✅ DONE | #2207 |
| 09 | management-ddl-injection.md — escape/validate RBAC DDL | ✅ DONE | #2208 |
| 10 | data-table-body-render-key.md — cheap render key | ✅ DONE | #2209 |
| 11 | clerk-webhook-handler-tests.md — seat-enforcement tests | ✅ DONE | #2210 |
| 12 | ai-agent-doc-tool-sync.md — docs↔tools sync + anti-drift test | ✅ DONE | #2211 |
| 13 | ssrf-guard-ipv6-pinning-tests.md — IPv6 + DNS-pinning tests | ✅ DONE | #2202 |
Supporting infra PRs: #2212 (biome format drift) and #2220 (break the plan-48 baseline import cycle + clear round-3 format drift).
Supporting infra: #2242 bumped
CI's bun-version 1.3.13→1.3.14 for the unit-tests coverage-writer crash
(WriteFailed); #2246 then
fixed the real root cause of the related cloudflare:workers pre-push-hook
failures with a global bun test preload; #2252
bumped remaining stray bun pins. unit-tests is a required merge check (PR
#2527, merged 2026-07-10);
known non-required checks are e2e-test, e2e-test-tsr, and component-test.
Note: a separate long-running autonomous swarm (see ~/.claude memory
chmonitor-swarm-ci-operating-context) also works this backlog concurrently —
some merges above may originate from it rather than an interactive session.
| # | Plan | PR | Why it's held |
|---|---|---|---|
| 25 | Email alert adapter | #2218 | No-op transport. The SMTP path is a stub, and email only fires from the cron sweep when a webhook is also configured. Decide the real transport (Mailgun/SendGrid/SMTP) and the fire path. Owner chose to defer this decision (2026-07-03). |
| 42 | Kafka consumer control | #2259 | Design-level block, not just a decision. Marked HELD by the swarm: broker-admin operations aren't implementable within the current architecture as specced — needs a redesign, not a go/no-go call. |
| 66 | Onboarding sample-cluster preset | #2225 | Not just a failed live-verification — a real credential-exposure risk. The public demo (play.clickhouse.com) denies query_log/parts/merges/etc. so most pages render empty. The obvious-looking fix — point at chmonitor's own duet-ubuntu cloud demo host — was investigated and rejected: that demo's credentials are deliberately server-side-only (CHM_CLOUD_DEMO_HOSTS, proxied), while the onboarding preset (sample-preset.ts) is embedded client-side and shipped in every deployment's public JS bundle forever. Needs either a genuinely publish-safe ClickHouse demo with broad system.* grants, or ship with honest "limited demo" copy instead. |
Plans 26, 28, 29, 30, 32, 33 (the rest of the alerting cluster) were all
implemented in parallel against the same base commit and ALL touch the same
core dispatch function, apps/dashboard/src/lib/health/server-sweep.ts. Only
31 merged cleanly; the other five now cascade into CONFLICTING against each
other as each one lands. Reconciling them requires composing routing +
suppression gates (maintenance windows, ACKs) + rule-evaluation additions
(compound, custom) + dispatch-time formatting (Opsgenie, remediation links)
correctly, in order — not a naive per-PR rebase. This is the current top
priority: land them serially, verify bun test src/lib/health/ --isolate
passes after each (it exercises all six plans' interaction), before starting
new alerting or advisor work on top of this file. There is also a 5-way
migration-number collision (0014_*.sql) across plans 28/29/30/32/52 to
renumber sequentially as each lands.
| # | Plan | PR |
|---|---|---|
| 26 | opsgenie-adapter.md | #2248 — conflicting |
| 28 | maintenance-windows-suppression.md | #2254 — conflicting |
| 29 | alert-ack-manual-resolution.md | #2258 — conflicting |
| 30 | per-rule-alert-routing.md | branch advisor/30-per-rule-alert-routing, PR pending reconciliation |
| 32 | custom-alert-rule-builder.md | #2257 — conflicting |
| 33 | remediation-action-links.md | #2255 — mergeable, will conflict once others land |
Also in flight, not yet merged: 57 custom-dashboard-builder-grid.md (#2265, mergeable, auto-merge armed), 41 clickhouse-cloud-connect-wizard.md (#2240, conflicting, needs a rebase), 39 otel-trace-export (swarm-originated PR #2243, not in the original plan file set).
Each of these needs a product/design decision, depends on a held PR, or is epic-scale (new toolchain / package / enterprise auth) — i.e. not appropriate for blind autonomous execution. Grouped by the blocker:
- Revenue 15–16, 18–20 (5) — 🟢 unblocked as of 2026-07-03 (plan 14 merged,
#2213): 15 upgrade-paywall-modal, 16 billing-usage-dashboard-card, 18 per-host-overage-billing, 19 downgrade-protection, 20 seat-cap-invite-time-gate. (17 checkout-webhook-e2e-tests already merged as a recovery-runbook doc, #2229.) - Enterprise 21, 23–24 (3) — edition-gated enterprise auth; prefer Clerk enterprise connections over a bespoke SAML stack. Product decision required: 21 sso-saml-enterprise, 23 rbac-roles-enterprise, 24 enterprise-multi-org-pooling. (22 audit-log-export already merged, #2232.)
- Alerting 26, 28–34 (8) — depends on held #25 (email transport): 26 opsgenie-adapter, 28 maintenance-windows-suppression, 29 alert-ack-manual-resolution, 30 per-rule-alert-routing, 31 compound-alert-rules, 32 custom-alert-rule-builder, 33 remediation-action-links (ACK-gated, never auto-executes DDL), 34 pagerduty-escalation-oncall (extends 30). (27 alert_events store already merged, #2231 — this cluster records into it.)
- Integrations 37–40, 42–43 (5) — new packages/toolchains (38 Grafana plugin, 40 Terraform provider, 39 OTel, 37 Slack OAuth) + security-adjacent proxies (42/43): 37 slack-app-native-oauth, 38 grafana-datasource-plugin, 39 otel-trace-export, 40 terraform-provider, 42 kafka-consumer-control, 43 mcp-custom-server-registry — 🔷 PR open #2271 (per-user D1 registry, SSRF-pinned transport, template library). (36, 41, 44, 45, 46, 47 already merged — the plumbing/advisor foundation this cluster builds on.)
- Advisor 52 (1) — 52 proactive-weekly-health-report (depends on 25/37 delivery channels). (49 query-cost-estimator already merged, #2233.)
- Dashboards/OSS 57–59 (3) — 🟢 57 unblocked as of 2026-07-03 (plan 56
merged,
#2224): 57 custom-dashboard-builder-grid, 58 declarative-chart-schema, 59 ai-generated-dashboards (needs 57 too). (54 query-config pack registry already merged, #2230.) - Growth 61, 63, 65, 67 (4) — marketing copy must be verified against shipped+enforced features first; 65 depends on held #66: 61 feature-sections-advisor-alerts-refresh, 63 comparison-pages-vs-competitors, 65 live-demo-embedded (needs 66), 67 docs-blog-content-engine. (60, 64, 68, 69, 70 already merged.)
Generated by the improve skill on 2026-07-10 at commit 070f5fe0a (8 parallel
category audits: correctness, security, perf, UI/charts/tables, content/landing,
tests, tech-debt/deps, routing/business-logic; every finding vetted against the
code before planning). Each plan is self-contained for a zero-context executor.
GitHub issue per plan (links below). Execute in numeric order unless the
Depends column says otherwise; 75 (test gate) should land before the test plans
it protects (76–78, 95).
| # | Plan | Category | Priority | Effort | Depends on | Status |
|---|---|---|---|---|---|---|
| 71 | cloud-demo-host-guard-coverage | security | P1 | M | — | ⏳ TODO · #2488 |
| 72 | prefetch-query-key-alignment | bug | P1 | S | — | ✅ DONE · shared chartQueryKey/tableQueryKey in apps/dashboard/src/lib/swr/prefetch.ts · #2489 |
| 73 | table-result-row-cap | perf | P1 | M | — | ✅ DONE · max_result_rows cap in apps/dashboard/src/lib/api/query-executor.ts · #2490 |
| 74 | host-id-validation-unification | bug | P1 | S | — | ⏳ TODO · #2491 |
| 75 | required-unit-tests-check | dx | P1 | S | — | ✅ DONE · PR #2527 merged 2026-07-10 · #2492 |
| 76 | billing-resolution-tests | tests | P1 | M | — | ⏳ TODO · #2493 |
| 77 | deploy-env-projection-tests | tests | P1 | S | — | ⏳ TODO · #2494 |
| 78 | constant-time-auth-dedupe | security | P1 | S | — | ⏳ TODO · #2495 |
| 79 | menu-link-search-params | bug | P2 | S | — | ⏳ TODO · #2496 |
| 80 | background-bar-companions | bug | P2 | S | — | ⏳ TODO · #2497 |
| 81 | tooltip-breakdown-fixes | bug | P2 | S | — | ⏳ TODO · #2498 |
| 82 | data-table-utility-columns-sorting | bug | P2 | S | — | ⏳ TODO · #2499 |
| 83 | fleet-wide-rate-limiting | security | P2 | M | — | ✅ DONE · #2500 (closes #2467) |
| 84 | sanitize-500-error-responses | security | P2 | S | — | ⏳ TODO · #2501 |
| 85 | bug-handler-fail-closed-senders | security | P2 | S | — | ⏳ TODO · #2502 |
| 86 | telemetry-event-insert-bounds | security | P3 | S | — | ✅ DONE · MAX_BODY_BYTES + hex64 validation in apps/telemetry/src/index.ts · #2503 |
| 87 | browser-connection-store-fixes | bug | P2 | M | — | ⏳ TODO · #2504 |
| 88 | optional-table-probe-transient-errors | bug | P2 | S | — | ⏳ TODO · #2505 |
| 89 | lazy-markdown-imports | perf | P2 | S | — | ✅ DONE · lazy react-markdown in apps/dashboard/src/components/data-table/formatters/advanced-formatters.tsx · #2506 |
| 90 | landing-blog-image-optimization | perf | P2 | M | — | ⏳ TODO · #2507 |
| 91 | readme-docs-link-fixes | docs | P1 | S | — | ⏳ TODO · #2508 |
| 92 | blog-og-duplicate-post | docs/SEO | P2 | S | — | ⏳ TODO · #2509 |
| 93 | landing-copy-consistency | docs | P2 | S | — | ⏳ TODO · #2510 |
| 94 | toolchain-version-alignment | dx | P2 | S | — | ⏳ TODO · #2511 |
| 95 | platform-adapter-tests | tests | P2 | S | — | ⏳ TODO · #2512 |
| 96 | opennext-context-replacement-spike | migration | P3 | M | 95 | ⏳ TODO · #2513 |
| 97 | billing-cycle-metering-alignment | business-logic | P2 | M | 76 (soft) | ✅ DONE · #2514 |
| 98 | cloud-mode-runtime-consistency | investigate | P3 | S–M | — | ✅ DONE · build-time contract + detectCloudModeMismatch guard in /api/healthz · #2515 |
| 99 | seat-precheck-pending-invites | business-logic | P3 | S | — | ⏳ TODO · #2516 |
| 100 | ai-usage-reservation-release | investigate | P3 | S | — | ⏳ TODO · #2517 |
| 101 | chart-color-token-hygiene | tech-debt | P3 | M | — | ⏳ TODO · #2518 |
| 102 | render-perf-cleanups | perf | P3 | S | 72 | ⏳ TODO · #2519 |
- 75 (make unit-tests a required check) landed in PR #2527 — unit-tests is now
required alongside
dashboard. - 102 depends on 72 (both touch the chart/table queryKey code).
- 96 depends on 95 (adapter contract tests pin the API the spike must preserve).
- 71 and 84 both touch API route error paths — mergeable independently, but rebase whichever lands second.
- format- helper consolidation* (~12 fragmented
lib/format-*modules): real fragmentation, but M effort for cognitive cleanup only; existing implementations are individually tested. Not worth a plan now. - react-markdown vs streamdown consolidation: split is defensible (streaming vs static); noted as an investigate-follow-up inside plan 89, not its own plan.
query-config/index.ts/menu.tsgod-file concerns: checked — cleanly structured declarative data, not debt.- axios/undici at repo root: transitive security override pins, not duplicate HTTP clients.
- Committed
.env*values: only intentionally-public identifiers (Sentry DSN, PostHog key, Polar product ids); secrets properly gitignored. - Concurrent org host-add overage under-count: latent only while Polar overage billing is unwired; revisit inside plans/18.
/v1/summarydouble-WHERE 500 and insight NaN guards: already tracked as issues #2466 / #2469 — not re-planned.
Generated by the improve skill on 2026-08-26 at commit 34113ac. GitHub issue
per plan (links below). Plan 119 extends plan 78 (constant-time auth dedupe);
plan 120 supersedes plan 84 (sanitize 500 error responses).
Also from the same audit batch (plan 139): outage state carry-forward in
apps/cloud-hooks — ✅ DONE · #3335.
Each plan defines:
- Goal — a single measurable outcome.
- Real test — a test that fails today (or would fail if the behaviour regressed) and passes after the change. Not a tautology.
- Verification — the exact commands to prove it (build + targeted test).
Testing note (CLAUDE.md): use Bun test for unit/logic and Cypress for component/e2e. Jest has known hanging issues — do not add Jest.
