Skip to content

feat(admin): require expiration for credit grants unless 'Never expires' is checked#15

Open
kiloconnect[bot] wants to merge 1 commit intomainfrom
session/agent_fb167b27-bee3-4de5-aadd-28c00ea62a2f
Open

feat(admin): require expiration for credit grants unless 'Never expires' is checked#15
kiloconnect[bot] wants to merge 1 commit intomainfrom
session/agent_fb167b27-bee3-4de5-aadd-28c00ea62a2f

Conversation

@kiloconnect
Copy link
Contributor

@kiloconnect kiloconnect bot commented Feb 4, 2026

Summary

This PR updates the admin user detail page to require an expiration date or hours when granting credits, unless the user explicitly checks a "Never expires" checkbox.

Changes

  • Add "Never expires" checkbox option to the credit grant form
  • Make expiration date OR expiration hours required by default
  • When "Never expires" is checked, expiration fields become disabled and cleared
  • Add form validation to enforce the requirement
  • Reset "Never expires" state when changing credit category or after successful submission

Motivation

This prevents accidentally creating credits without expiration dates, which creates unnecessary financial liabilities. Users who genuinely need non-expiring credits can explicitly check the "Never expires" box.

Testing

  • TypeScript type checking passes
  • Lint-staged checks pass

Built for Brendan by Kilo for Slack

…es' is checked

- Add 'Never expires' checkbox option to the credit grant form
- Make expiration date OR expiration hours required by default
- When 'Never expires' is checked, expiration fields become disabled
- Add form validation to enforce the requirement
- Clear expiration fields when 'Never expires' is checked

This prevents accidentally creating credits without expiration dates,
which creates unnecessary financial liabilities. Users who genuinely
need non-expiring credits can explicitly check the 'Never expires' box.
<div>
<Label className="text-sm font-medium" htmlFor="expiry-hours">
Expiry Hours
Expiry Hours{!neverExpires && !expirationDate ? ' (required)' : ''}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

WARNING: Required indicator condition is incorrect for "Expiry Hours"

This shows "(required)" whenever expirationDate is empty, even if the user already entered expiryHours. Consider only showing required when neither expiration field is set.

Suggested change
Expiry Hours{!neverExpires && !expirationDate ? ' (required)' : ''}
Expiry Hours{!neverExpires && !expiryHours && !expirationDate ? ' (required)' : ''}

step="0.01"
id="expiry-hours"
disabled={!selectedCredit}
disabled={!selectedCredit || neverExpires}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

WARNING: Required indicator condition is incorrect for "Expiration Date"

This shows "(required)" whenever expiryHours is empty, even if the user already selected an expirationDate. Consider only showing required when neither expiration field is set.

Suggested change
disabled={!selectedCredit || neverExpires}
Expiration Date{!neverExpires && !expiryHours && !expirationDate ? ' (required)' : ''}

<div>
<Label className="text-sm font-medium" htmlFor="date">
Expiration Date
Expiration Date{!neverExpires && !expiryHours ? ' (required)' : ''}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

SUGGESTION: Date input value fallback likely never triggers + format mismatch

expirationDate is a string state initialized to '', so expirationDate ?? ... will always pick expirationDate (empty string is not nullish) and never fall back to the category default. Also, <input type="date"> expects YYYY-MM-DD, while toISOString() produces a full timestamp (YYYY-MM-DDTHH:mm:ss.sssZ).

Consider using something like expirationDate || (selectedCreditCategory?.credit_expiry_date ? selectedCreditCategory.credit_expiry_date.toISOString().slice(0, 10) : '').

@kiloconnect
Copy link
Contributor Author

kiloconnect bot commented Feb 4, 2026

Code Review Summary

Status: 3 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 1

Fix these issues in Kilo Cloud

Issue Details (click to expand)

WARNING

File Line Issue
src/app/admin/components/UserAdmin/UserAdminCreditGrant.tsx 235 "Expiry Hours (required)" indicator shows even when hours are provided
src/app/admin/components/UserAdmin/UserAdminCreditGrant.tsx 245 "Expiration Date (required)" indicator shows even when a date is selected

SUGGESTION

File Line Issue
src/app/admin/components/UserAdmin/UserAdminCreditGrant.tsx 250 type="date" value fallback uses ?? (never triggers for empty string) + toISOString() format mismatch
Other Observations (not in diff)

Issues found in unchanged code that cannot receive inline comments:

File Line Issue
Files Reviewed (1 files)
  • src/app/admin/components/UserAdmin/UserAdminCreditGrant.tsx - 3 issues

jeanduplessis pushed a commit that referenced this pull request Feb 7, 2026
Comprehensive audit of observability across all 6 workflows (sync,
triage, sandbox, extraction, auto-dismiss, stale cleanup). The feature
has basic Sentry error capture and console.log debug logging, but no
operational observability: no LLM call timing or token usage tracking
(despite emitApiMetrics existing in the codebase), no cron heartbeats,
no GitHub API rate limit monitoring, no correlation IDs across the
multi-tier pipeline, and no metrics for triage/extraction fallback
rates or auto-dismiss volumes.

https://claude.ai/code/session_01RG48f6grwtxGT6Mo3uHRxj
jeanduplessis pushed a commit that referenced this pull request Feb 7, 2026
Addresses Finding #15 (HIGH: No Operational Observability) from the
security agent production readiness review. Lays out a 5-phase plan
covering correlation IDs, structured logging, LLM call timing/token
tracking, cron heartbeats, sync metrics, pipeline instrumentation,
and degradation detection — all using existing codebase infrastructure
(emitApiMetrics, sentryLogger, Sentry spans, BetterStack heartbeats).

https://claude.ai/code/session_01H6HahwjayzdFFZXbpE9Hg7
jeanduplessis pushed a commit that referenced this pull request Feb 7, 2026
…kflows

Implements all 5 phases of the observability plan (Finding #15):

Phase 1 - Correlation ID & Structured Logging:
- Generate correlationId (UUID) at analysis start, thread through all tiers
- Store correlationId in SecurityFindingAnalysis JSONB for queryability
- Replace ~76 console.log/error calls with sentryLogger (dual console+Sentry)
- Wrap startSecurityAnalysis in Sentry withScope for tag propagation

Phase 2 - LLM Call Timing & Token Tracking:
- Wrap triage and extraction LLM calls in Sentry startSpan (op: ai.inference)
- Extract token usage from sendProxiedChatCompletion responses
- Emit metrics via emitApiMetrics with mode security-agent-triage/extraction
- Track input/output tokens as span attributes

Phase 3 - Cron Heartbeats & Sync Metrics:
- Add BetterStack heartbeat support to both cron jobs (env-configurable URLs)
- Send /fail heartbeat on sync errors
- Add per-repository sync timing in syncDependabotAlertsForRepo
- Track GitHub API rate limits via x-ratelimit-remaining headers

Phase 4 - Pipeline Timing & R2 Retry Instrumentation:
- Wrap processAnalysisStream in Sentry span (op: ai.pipeline)
- Track stream duration, R2 retry attempts, and retry wait time
- Log tier transition timing (Tier 1 duration)
- Record stream outcome status on span attributes

Phase 5 - Outcome Distribution & Degradation Detection:
- Add Sentry breadcrumbs for triage/extraction outcomes with isFallback flag
- Track auto-dismiss decisions with correlationId and source
- Add stale analysis anomaly detection (warn when count > threshold)
- Log bulk auto-dismiss summaries

https://claude.ai/code/session_01H6HahwjayzdFFZXbpE9Hg7
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.

0 participants