Skip to content

feat(cost-insights): Introduce Cost Insights feature#4253

Open
jeanduplessis wants to merge 23 commits into
mainfrom
jdp/cost-insights
Open

feat(cost-insights): Introduce Cost Insights feature#4253
jeanduplessis wants to merge 23 commits into
mainfrom
jdp/cost-insights

Conversation

@jeanduplessis

@jeanduplessis jeanduplessis commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds owner-scoped Cost Insights for personal users and organizations so authorized users can inspect Credit spend, configure Spend Alerts, review alert episodes, and act on Cost Suggestions.

  • Adds Cost Insights dashboard, activity, Ask Kilo, and settings routes with responsive personal and organization UI.
  • Adds normalized hourly spend rollups, coverage tracking, repair/backfill jobs, and atomic updates across Credit-spend paths.
  • Adds anomaly and rolling 24-hour threshold evaluation, active episode state, notification delivery, retention cleanup, and cron entry points.
  • Adds Coding Plan and Kilo Pass Cost Suggestions based on observed spend, with dismissal history and independent enablement.
  • Adds owner-scoped authorization, current-recipient revalidation, server-side activity pagination, captured contributor evidence, and numeric sidebar review badges.
  • Adds generated database migrations, seed data, Storybook coverage, and regression tests for rollups, evaluation, presentation, routing, and billing integrations.

Verification

  • Not manually verified in browser in this session.

Visual Changes

N/A - screenshots were not captured as part of this update.

Reviewer Notes

  • Review spend-writer transaction boundaries carefully: Credit spend and its hourly rollup must commit atomically.
  • Review anomaly coverage and repair behavior around incomplete historical windows and current partial hours.
  • Review organization authorization and notification recipient revalidation for owners and billing managers.
  • Cost Suggestions remain advisory and independent from Spend Alert enablement; they do not alter billing or spend behavior.
  • Activity history uses server-side filtering and pagination, while alert events resolve current actor labels from captured driver IDs.

Run this branch locally

Prerequisites: Docker Desktop must be running, tmux must be installed, and .env.local must contain a local POSTGRES_URL. Use Node from .nvmrc and pnpm from package.json.

  1. Fetch and check out the branch. For a first checkout, use the tracking command; if the branch already exists locally, use git switch jdp/cost-insights && git pull --ff-only instead.
git fetch origin jdp/cost-insights
git switch --track origin/jdp/cost-insights
nvm install
nvm use
corepack enable
pnpm install
  1. Configure local environment variables if this clone is not already configured. Team members with Vercel access can use the first path; otherwise use the interactive local setup.
# Team-member/Vercel path
vercel link --project kilocode-app
vercel env pull

# Or local-only setup
pnpm dev:setup-env

# Generate service-specific local env files after either path
pnpm dev:env
  1. Start PostgreSQL and apply this branch's migrations. Re-run migration after every pull that adds migration files.
docker compose -f dev/docker-compose.yml up -d --wait postgres
pnpm drizzle migrate
  1. Seed the Cost Insights fixture before opening the UI.
pnpm dev:seed cost-insights:spend-evidence
  1. Start the app.
pnpm dev:start

Default web URL is http://localhost:3000. If another Kilo dev stack is running, generate env and start this worktree with a stable automatic offset, then read the actual Next.js port from status output:

KILO_PORT_OFFSET=auto pnpm dev:env
KILO_PORT_OFFSET=auto pnpm dev:start
KILO_PORT_OFFSET=auto pnpm dev:status --json

What the seed creates

pnpm dev:seed cost-insights:spend-evidence creates a deterministic, owner-scoped fixture containing:

  • 90 days of personal and organization Variable Credit spend.
  • Monthly KiloClaw Scheduled Credit spend.
  • Current-hour anomaly spikes and rolling 24-hour threshold crossings.
  • Active Spend Alert banners, Coding Plan and Kilo Pass Cost Suggestions, notification rows, and activity history.
  • An organization named [seed:cost-insights] Northstar Labs with owner, billing manager, and member-attributed spend drivers.
  • Matching hourly rollups and complete coverage metadata, so all 24h, 7d, 30d, and 90d views are populated.

The command prints personalLoginPath, organizationLoginPath, owner IDs, organization ID, record counts, and the database target. Prefix a printed login path with http://localhost:<nextjs-port>.

Seed identities:

Cost Insights v1 is admin-only during initial rollout. The owner and billing-manager fixture users below are seeded with is_admin = true, so they can open Cost Insights and exercise the owner/billing-manager management paths. The contributor fixture is not an admin and is not authorized to open organization Cost Insights.

Purpose Email
Personal Spend owner and organization owner, Kilo admin cost-insights-owner@example.com
Organization billing manager, Kilo admin cost-insights-billing-manager@example.com
Organization spend contributor fixture, non-admin cost-insights-member@example.com

Organization ID: 4f2fc143-4b30-4c8a-878b-df89c89c6790.

With the default port, use these direct fake-login URLs:

Personal dashboard:
http://localhost:3000/users/sign_in?fakeUser=cost-insights-owner%40example.com&callbackPath=%2Fcost-insights

Organization dashboard as owner:
http://localhost:3000/users/sign_in?fakeUser=cost-insights-owner%40example.com&callbackPath=%2Forganizations%2F4f2fc143-4b30-4c8a-878b-df89c89c6790%2Fcost-insights

Organization dashboard as billing manager:
http://localhost:3000/users/sign_in?fakeUser=cost-insights-billing-manager%40example.com&callbackPath=%2Forganizations%2F4f2fc143-4b30-4c8a-878b-df89c89c6790%2Fcost-insights

Non-admin contributor access check:
http://localhost:3000/users/sign_in?fakeUser=cost-insights-member%40example.com&callbackPath=%2Forganizations%2F4f2fc143-4b30-4c8a-878b-df89c89c6790%2Fcost-insights

Wait for fake-login account creation to finish before evaluating the page. The admin owner and admin billing manager can change settings and review items. The non-admin contributor exists to exercise contributor attribution and should be blocked from organization Cost Insights.

Suggested local checks

  • Confirm personal and organization dashboards show anomaly and threshold banners, suggestions, spend metrics, and top drivers.
  • Switch spend evidence among 24h, 7d, 30d, and 90d; zero-spend buckets should have zero-height bars.
  • Open Activity, switch each filter, and paginate through retained events.
  • Use Manage threshold from a threshold banner to open the matching settings section; adjust or disable the threshold there and confirm the banner clears, settings update, and activity records the change.
  • Dismiss a suggestion and acknowledge alerts; confirm sidebar review count decreases.
  • Open organization settings as the admin owner and admin billing manager, then repeat as the non-admin contributor to confirm organization Cost Insights is blocked.

Seed safety and reset behavior

  • The seed refuses USE_PRODUCTION_DB=true and rejects any POSTGRES_URL whose host is not loopback (localhost, 127.0.0.1, or ::1).
  • Rerunning the seed is the normal reset path. It replaces only this fixture's stable users, organization, spend evidence, rollups, events, suggestions, and notification rows.
  • Seeded users use placeholder Stripe customer IDs. Use fake login for Cost Insights pages; do not open Stripe-backed billing pages with these users.
  • To restore mutated Cost Insights state after testing, rerun pnpm dev:seed cost-insights:spend-evidence.
  • For a completely fresh local database, stop the app and run the destructive reset below. This removes all local app data, not only Cost Insights fixtures.
pnpm dev:stop
pnpm dev:db:reset
pnpm drizzle migrate
pnpm dev:seed cost-insights:spend-evidence
pnpm dev:start

Comment thread apps/web/src/lib/cost-insights/repository.ts
Comment thread apps/web/src/lib/cost-insights/notifications.ts Outdated
Comment thread apps/web/src/lib/cost-insights/evaluation.ts Outdated
Comment thread apps/web/src/routers/cost-insights-router.ts Outdated
Comment thread apps/web/src/components/cost-insights/ask-kilo/CostInsightsAskKiloView.tsx Outdated
Comment thread apps/web/src/lib/cost-insights/repository.ts Outdated
Comment thread apps/web/src/lib/cost-insights/repository.ts Outdated
Comment thread apps/web/src/components/cost-insights/overview/SpendEvidenceCard.tsx Outdated
Comment thread apps/web/src/lib/cost-insights/jobs.ts Outdated
Comment thread apps/web/src/scripts/db/exa-usage-log-indexes.ts Outdated
Comment thread dev/seed/cost-insights/spend-evidence.ts Outdated
Comment thread dev/seed/cost-insights/spend-evidence.ts Outdated
Comment thread apps/web/src/lib/cost-insights/presenter.ts
Comment thread apps/web/src/app/api/cron/cost-insights-hourly/route.ts Outdated

@pandemicsyn pandemicsyn 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.

Found additional correctness issues and non-blocking performance warnings after excluding feedback already present on the PR. Database performance warnings are advisory and do not individually block merging.

Comment thread apps/web/src/routers/cost-insights-router.ts
Comment thread apps/web/src/lib/exa-usage.ts
Comment thread apps/web/src/lib/cost-insights/presenter.ts Outdated
Comment thread apps/web/src/lib/cost-insights/presenter.ts Outdated
Comment thread apps/web/src/lib/cost-insights/repository.ts Outdated
Comment thread apps/web/src/lib/cost-insights/jobs.ts Outdated
Comment thread apps/web/src/lib/cost-insights/canonical-sources.ts
Comment thread apps/web/src/lib/cost-insights/canonical-sources.ts
Comment thread apps/web/src/lib/cost-insights/evaluation.ts
Comment thread packages/db/src/cost-insights-rollups.ts Outdated
@jeanduplessis jeanduplessis marked this pull request as ready for review July 3, 2026 12:36
@jeanduplessis jeanduplessis requested a review from pandemicsyn July 3, 2026 12:37
Comment thread packages/db/src/migrations/0176_opposite_tiger_shark.sql Outdated
Comment thread packages/db/src/migrations/0176_opposite_tiger_shark.sql Outdated
Comment thread apps/web/src/lib/cost-insights/evaluation.ts Outdated
Comment thread apps/web/src/components/cost-insights/shell/CostInsightsAlertBar.tsx Outdated
@kilo-code-bot

kilo-code-bot Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: 1 Issue Found | Recommendation: Address before merge

Executive Summary

The incremental change (fix(db): honor sslmode require in postgres urls) adds a new fallback that disables TLS certificate verification (rejectUnauthorized: false) for sslmode=require connections lacking a configured CA.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/db/src/database-url.ts 42 New sslmode=require fallback sets rejectUnauthorized: false, disabling server certificate verification and losing MITM protection when DATABASE_CA is not configured
Files Reviewed (2 files)
  • packages/db/src/database-url.ts - 1 issue (new sslmode=require TLS fallback branch)
  • packages/db/src/database-url.test.ts - 0 issues (new regression tests for both TLS branches)

Fix these issues in Kilo Cloud

Previous Review Summaries (4 snapshots, latest commit f30206d)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit f30206d)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental change replaces the two previously-flagged non-concurrent CREATE INDEX statements on coding_plan_terms and microdollar_usage with a dedicated CREATE INDEX CONCURRENTLY operator script, matching the existing exa-usage-log-indexes.ts pattern; no new issues found in this pass.

Files Reviewed (6 files)
  • apps/web/src/scripts/db/cost-insights-source-indexes.ts - 0 issues (new concurrent-index operator script)
  • apps/web/src/lib/cost-insights-source-indexes-script.test.ts - 0 issues
  • packages/db/src/migrations/0178_useful_wallop.sql (renamed from 0178_gorgeous_cassandra_nova.sql) - both previously-flagged non-concurrent CREATE INDEX statements removed; both prior findings confirmed resolved
  • packages/db/src/migrations/meta/0178_snapshot.json (generated, not reviewed in detail)
  • packages/db/src/migrations/meta/_journal.json (generated, not reviewed in detail)
  • packages/db/src/schema.ts - indexes for coding_plan_terms.credit_transaction_id and microdollar_usage(organization_id, created_at) removed from Drizzle schema, consistent with moving provisioning to the new concurrent-index script

Previous review (commit fc50d0f)

Status: 2 Issues Found | Recommendation: Address before merge

Executive Summary

The regenerated migration adds two non-concurrent CREATE INDEX statements on pre-existing, populated tables (coding_plan_terms, and the ~800M-row actively-written microdollar_usage), reintroducing the same table-locking risk this PR already fixed for credit_transactions/exa_usage_log via dedicated CONCURRENTLY operator scripts.

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/db/src/migrations/0178_gorgeous_cassandra_nova.sql 312 Non-concurrent CREATE INDEX on existing, populated coding_plan_terms table
packages/db/src/migrations/0178_gorgeous_cassandra_nova.sql 313 Non-concurrent CREATE INDEX on the 800M-row, actively-written microdollar_usage table
Files Reviewed (13 files)

Note: The branch was rebased since the last review (previous review commit 3d90cd2bf960c400b33f1921e495e6b9cbe2f7e4 is no longer an ancestor of HEAD), so this pass re-scoped to the true content delta versus the equivalent pre-rebase review point and re-verified all prior "Fixed in ..." claims against current code. All prior findings on this PR (retention-delete of active episodes, notification claim recovery, evaluation hour-boundary drift, settings-commit ordering, Ask Kilo static data, alert/suggestion transactional writes, viewer time-zone formatting, hourly-sweep missed-hour recovery, invalid-CONCURRENTLY-index detection, seed fixture coverage mutation, seed default rollup mode, dismissal pending-state UI, presenter memberLimitsHref, cron partial-failure reporting, alert acknowledgment identity, Exa usage validation, coalesced rollup-to-zero presentation, timestamp serialization, suggestion-badge scope, threshold sub-option visibility, threshold validation, stable enum list, chart keyboard accessibility, JSONB snapshot validation, invalidation await, sidebar badge a11y label, evaluation coalescing performance, hourly cron batching, canonical-source composite indexes, evaluation lock/query performance, rollup lock coordination, dead disableThreshold mutations, unreachable non-admin branches, and non-constant-time cron auth) remain fixed at current HEAD.

  • apps/web/src/app/api/cron/cost-insights-hourly/route.test.ts
  • apps/web/src/app/api/cron/cost-insights-hourly/route.ts
  • apps/web/src/app/api/cron/cost-insights-retention/route.test.ts
  • apps/web/src/app/api/cron/cost-insights-retention/route.ts
  • apps/web/src/lib/cron-auth.test.ts
  • apps/web/src/lib/cron-auth.ts
  • apps/web/src/routers/cost-insights-router.test.ts
  • apps/web/src/routers/cost-insights-router.ts
  • apps/web/src/routers/organizations/organization-cost-insights-router.test.ts
  • apps/web/src/routers/organizations/organization-cost-insights-router.ts - 0 new issues (previously flagged unreachable branches confirmed removed)
  • packages/db/src/migrations/0178_gorgeous_cassandra_nova.sql - 2 issues
  • packages/db/src/migrations/meta/_journal.json
  • packages/db/src/migrations/meta/0178_snapshot.json (generated, not reviewed in detail)

Fix these issues in Kilo Cloud

Previous review (commit 3d90cd2)

Status: No Issues Found | Recommendation: Merge

Executive Summary

This incremental review covers the 17 files changed since the last review; all 4 previously flagged findings (non-concurrent index creation on credit_transactions/exa_usage_log in the migration, the anomaly-dedup timestamp comparison bug, and the hardcoded placeholder org slug) are fixed in this update, and no new issues were introduced.

Files Reviewed (17 files)
  • apps/storybook/stories/cost-insights/CostInsightsAlertBar.stories.tsx
  • apps/web/src/components/cost-insights/CostInsightsOverviewClient.tsx
  • apps/web/src/components/cost-insights/overview/CostInsightsDashboardView.tsx
  • apps/web/src/components/cost-insights/overview/DashboardNotices.tsx
  • apps/web/src/components/cost-insights/overview/SpendEvidenceCard.tsx
  • apps/web/src/components/cost-insights/settings/CostInsightsSettingsView.tsx
  • apps/web/src/components/cost-insights/shell/CostInsightsAlertBar.tsx
  • apps/web/src/components/cost-insights/useCostInsightsTracking.ts
  • apps/web/src/lib/cost-insights/evaluation.ts
  • apps/web/src/lib/cost-insights/presenter.test.ts
  • apps/web/src/lib/cost-insights/presenter.ts
  • apps/web/src/lib/credit-transaction-indexes-script.test.ts
  • apps/web/src/scripts/db/credit-transaction-indexes.ts
  • packages/db/src/migrations/0176_cynical_norrin_radd.sql
  • packages/db/src/migrations/meta/0176_snapshot.json
  • packages/db/src/migrations/meta/_journal.json
  • packages/db/src/schema.ts

Previous review (commit 5f4ddc4)

Status: 4 Issues Found | Recommendation: Address before merge

Executive Summary

The generated migration applies non-concurrent CREATE INDEX statements to the populated, actively-written credit_transactions and partitioned exa_usage_log tables, risking write locks on core billing paths during deploy.

Overview

Severity Count
CRITICAL 0
WARNING 4
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/db/src/migrations/0176_opposite_tiger_shark.sql 313 Non-concurrent CREATE INDEX on populated credit_transactions table blocks writes during build
packages/db/src/migrations/0176_opposite_tiger_shark.sql 315 Non-concurrent CREATE INDEX on partitioned exa_usage_log recurses into every partition with locking builds, bypassing this PR's own safe per-partition CONCURRENTLY script
apps/web/src/lib/cost-insights/evaluation.ts 184 Anomaly-episode dedup short-circuit compares canonical ISO hourStart to raw, unnormalized Postgres timestamp text, so it never matches and the intended re-evaluation short-circuit never fires
apps/web/src/components/cost-insights/shell/CostInsightsAlertBar.tsx 14 Hardcoded placeholder org slug (acme-cost-insights) in the organization review link; currently unreachable from any route but broken by construction if ever wired up
Verification of prior review feedback

This PR previously received 66 inline review comments from human and bot reviewers. All findings with a currently-resolvable line mapping were re-verified against the current HEAD (5f4ddc459e) and confirmed fixed, including: independent active-alert snapshots surviving event retention, transactional event/state writes, stale-episode acknowledgment guarding via episode-ID match, added indexes for previously-flagged missing-index performance issues, hourly-rollup-based rolling-window evidence queries, roving-focus chart accessibility, sidebar badge accessibility, settings mutation invalidation awaiting, and upstream Exa response runtime validation. No duplicates of those findings are included above.

Files Reviewed (125 files)

Full PR diff (base 0e8b4d1e → head 5f4ddc459) across Cost Insights dashboard/activity/settings/Ask Kilo UI, presenter/formatting/tracking, evaluation/jobs/notifications, repository/spend-repository/canonical-sources, routers and API routes (cron, Exa), database schema/migrations/rollups, seed fixtures, and Storybook stories.

Fix these issues in Kilo Cloud


Reviewed by claude-sonnet-5 · Input: 44 · Output: 8.7K · Cached: 1.1M

Review guidance: REVIEW.md from base branch main

@jeanduplessis jeanduplessis requested a review from St0rmz1 July 6, 2026 09:45
Comment thread apps/web/src/routers/cost-insights-router.ts Outdated
Comment thread apps/web/src/routers/organizations/organization-cost-insights-router.ts Outdated
Comment thread apps/web/src/app/api/cron/cost-insights-hourly/route.ts Outdated
@St0rmz1

St0rmz1 commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Low, Documentation: The "Run this branch locally" instructions say the seeded owner (cost-insights-owner@example.com) and billing manager (cost-insights-billing-manager@example.com) can view and manage organization Cost Insights, and that the Kilo admin is a read-only inspector. Per the spec (Authorization rules 1 to 3) and the actual code, v1 is Kilo-admin-only: personal routes use adminProcedure (requires is_admin), and the organization layout does if (!isGlobalAdmin) notFound(). The seeded owner and billing-manager emails are not @admin.example.com, so those non-admin logins will hit notFound / FORBIDDEN rather than a manageable dashboard. The read-only admin login is actually the working path, which is the reverse of what the instructions imply.

A reviewer following these steps will conclude the feature is broken when it is behaving to spec. Suggestion: update the local-run narrative so the owner and billing-manager fixtures only gain access when they are also Kilo admins, and make the primary working path a Kilo admin who also holds an owner or billing-manager role in the seeded org.

@jeanduplessis

Copy link
Copy Markdown
Contributor Author

Updated the PR description for the local-run documentation note. It now states that Cost Insights v1 is admin-only during initial rollout, clarifies that the seeded owner and billing-manager fixtures are Kilo admins, replaces the stale read-only-admin URL with a non-admin contributor access check, and updates the suggested local checks to use Manage threshold via settings.

Comment thread packages/db/src/migrations/0178_gorgeous_cassandra_nova.sql Outdated
Comment thread packages/db/src/migrations/0178_gorgeous_cassandra_nova.sql Outdated
Comment thread packages/db/src/database-url.ts Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants