Skip to content

fix(code-reviews): billing error classification#1332

Open
alex-alecu wants to merge 8 commits intomainfrom
feat/billing-pr-comment
Open

fix(code-reviews): billing error classification#1332
alex-alecu wants to merge 8 commits intomainfrom
feat/billing-pr-comment

Conversation

@alex-alecu
Copy link
Contributor

@alex-alecu alex-alecu commented Mar 20, 2026

Summary

Billing errors from code reviews were being misclassified in two ways: v1 billing errors arrived as interrupted and got normalized to cancelled (hiding them from billing analytics), and v2 billing errors had the real error message discarded by the wrapper, storing the generic string session.error instead. This PR adds a terminal_reason column to track failure categories, fixes both classification paths, posts billing notices on PRs/MRs, and backfills ~13k historical rows.

Three layers of fixes:

  • Wrapper (cloud-agent-next): passes the real billing error text from properties.error instead of discarding it and forwarding just the event type string.
  • normalizePayload (status callback handler): detects billing patterns in error messages when no explicit terminalReason is set, reclassifying cancelled billing errors as failed with terminalReason: 'billing'.
  • Orchestrator: catches 402 billing errors from prepareSession/initiateSession/sendMessageV2, tags them with terminalReason: 'billing', and prevents the sendMessage fallback from retrying billing failures.

Also adds billing PR/MR comment notices, admin dashboard improvements for billing vs. non-billing failure separation, and three backfill migrations for historical data.

Verification

  • pnpm jest 'code-review-status.*route\.test' — 17 tests pass (4 new: interrupted billing reclassification, failed billing inference, non-billing interrupted preserved, explicit terminalReason preserved)
  • pnpm typecheck — passes across all workspace packages including cloud-agent-next wrapper
  • Pre-push hooks passed (format, lint, typecheck)

Visual Changes

N/A

Reviewer Notes

  • The v2 backfill migration (0057) uses exact error_message = 'session.error' matching rather than ILIKE patterns to avoid false positives from branch names containing billing keywords.
  • Migration 0056 already backfilled v1 failed billing rows (23,711 rows). Migration 0057 covers the remaining gaps: v1 cancelled billing rows (~12,461) and v2 session.error rows (742).
  • Deployment order matters: deploy the normalizePayload fix (Next.js) first so it's ready to handle callbacks, then apply the backfill migration, then deploy the wrapper fix (cloud-agent-next Worker).
  • The !terminalReason guard in normalizePayload ensures the billing inference only fires when no explicit reason was provided — orchestrator-path billing errors (which already send terminalReason: 'billing') are not double-handled.

…pers

Add functions to create new top-level comments on GitHub PRs and GitLab
MRs, plus deduplication helpers that check for an existing HTML marker
before posting.
When a review fails due to a billing error, post a short comment on the
PR/MR telling the user their account is out of credits with a link to
app.kilo.ai. Skips posting if the notice already exists (deduplication
via HTML marker).
Cover GitHub and GitLab billing notice posting, deduplication (skip if
already posted), non-billing failures (no notice), and link presence.
Consistent with findKiloReviewNote — iterate pages so the billing
notice deduplication check works on MRs with >100 notes.
@kilo-code-bot
Copy link
Contributor

kilo-code-bot bot commented Mar 20, 2026

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (4 files)
  • cloud-agent-next/wrapper/src/connection.ts
  • packages/db/src/schema-types.ts
  • packages/worker-utils/src/cloud-agent-next-client.ts
  • src/lib/integrations/platforms/github/adapter.ts

Reviewed by gpt-5.4-20260305 · 533,327 tokens

The wrapper was discarding real billing error messages, passing the
generic event type string instead. normalizePayload did not detect
billing from error text, so v1 billing errors stayed as 'cancelled'
and v2 ones lacked terminal_reason. Fix all three layers: wrapper
passes the actual error, normalizePayload infers billing from message
patterns, and a backfill migration corrects ~13k historical rows.
@alex-alecu alex-alecu changed the title feat(code-reviews): post billing notice on PR when out of credits fix(code-reviews): billing error classification Mar 20, 2026
if (isTerminalError(eventType, properties)) {
callbacks.onTerminalError(eventType);
const errorText =
typeof properties.error === 'string'
Copy link
Contributor

Choose a reason for hiding this comment

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

WARNING: Structured session.error payloads still lose the real billing message

EventSessionError.properties.error is an object union (APIError, UnknownError, etc.), not just a string. isTerminalError() already stringifies object-shaped errors, so this branch still fires for billing session.error events, but the fallback here stores Insufficient credits: ${eventType} instead of the actual data.message. That recreates the same generic-message problem for the common non-string error shape.

- Paginate hasPRCommentWithMarker using octokit.paginate to match the
  GitLab counterpart and avoid duplicate billing notices on busy PRs
- Preserve structured error objects in wrapper fallback via JSON.stringify
  instead of discarding them
- Improve cross-reference comments between the duplicate terminal reason
  type definitions in worker-utils and db packages
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.

1 participant