Skip to content

feat(health): live daily spend from audit log + limits/breaker surfacing (#83) - #240

Open
blippip69 wants to merge 1 commit into
Bitcoindefi:mainfrom
blippip69:feat/passport-health-endpoint
Open

feat(health): live daily spend from audit log + limits/breaker surfacing (#83)#240
blippip69 wants to merge 1 commit into
Bitcoindefi:mainfrom
blippip69:feat/passport-health-endpoint

Conversation

@blippip69

Copy link
Copy Markdown

feat(health): passport health endpoint with live spend + optional limits (#83)

EN

Completes the health route so every field from the issue schema is real data:

  • dailySpentXlm now derives from the audit log — entries with action
    spend / verified_spend carrying metadata.amountXlm, current UTC day;
    weeklySpentXlm covers the trailing seven days (bonus field).
  • spendLimits and circuitBreakerStatus surface the passport's configured
    values when present in config; null otherwise (optional features, no fake
    zeros).
  • Kept the existing fullLifeExpiryHoursRemaining contract; status logic and
    404-for-unknown-agent unchanged.

Tests: 3 new (health-spend.test.ts) covering UTC-day boundary math, weekly
window, non-spend entries being ignored, and config surfacing. Existing 8
health tests untouched and green.

Test Files 14 passed (14) | Tests 149 passed (149)

ES

El endpoint de health ahora devuelve datos reales en todos los campos del
esquema: gasto diario/semanal derivado del audit log (UTC), limites de gasto y
estado del circuit breaker cuando esten configurados. Tests nuevos para las
fronteras del dia y la semana; suite completa en verde (149 tests).

@sonarqubecloud

Copy link
Copy Markdown

Comment on lines +18 to +23
function spendAmount(entry: AuditEntry): number | null {
const action = entry.action as unknown as string
if (action !== "spend" && action !== "verified_spend") return null
const amount = (entry.metadata as { amountXlm?: unknown } | undefined)?.amountXlm
return typeof amount === "number" && Number.isFinite(amount) ? amount : null
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Bug: Daily/weekly spend always 0 — no producer emits spend entries

spendAmount only counts audit entries whose action is spend or verified_spend, but the AuditAction union (lib/passport/audit.ts:3-11) does not include those values and no code anywhere calls appendAuditEntry with them (grep finds references only in this route and its test, which force action: "spend" as never). Consequently dailySpentXlm and weeklySpentXlm will always be 0 against real data — the tests pass only because they bypass the type system. Add spend/verified_spend to AuditAction and ensure the spend flow actually writes those audit entries (with metadata.amountXlm), otherwise the endpoint reports fabricated zeros.

Was this helpful? React with 👍 / 👎

Comment on lines +82 to +96
const config = passport.config as {
spendLimits?: { dailyMaxXlm?: number; weeklyMaxXlm?: number | null } | null
circuitBreaker?: {
consecutiveFailures?: number
maxConsecutiveFailures?: number
tripped?: boolean
} | null
}
const spendLimits =
config.spendLimits && typeof config.spendLimits.dailyMaxXlm === "number"
? {
dailyMaxXlm: config.spendLimits.dailyMaxXlm,
weeklyMaxXlm: config.spendLimits.weeklyMaxXlm ?? null,
}
: null

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Bug: spendLimits/circuitBreakerStatus can never populate in production

The route casts passport.config to a shape with optional spendLimits/circuitBreaker, but PassportConfig is defined as only { allowTransfer: boolean } (lib/passport/passport.ts:6), so these fields are never present on real records and spendingLimits/circuitBreakerStatus will always be null. The test only exercises this by casting injected config as Partial<PassportRecord>, bypassing the type. Extend PassportConfig to declare spendLimits/circuitBreaker so the values can actually be stored and surfaced.

Was this helpful? React with 👍 / 👎

@gitar-bot

gitar-bot Bot commented Aug 25, 2026

Copy link
Copy Markdown
Code Review ⚠️ Changes requested 0 resolved / 2 findings

Derives live daily and weekly spend from audit logs and surfaces circuit breaker status, but the spend calculation always returns zero because no producer emits the expected action types.

⚠️ Bug: Daily/weekly spend always 0 — no producer emits spend entries

📄 app/api/protocol/passport/[id]/health/route.ts:18-23 📄 app/api/protocol/passport/[id]/health/route.ts:72-79

spendAmount only counts audit entries whose action is spend or verified_spend, but the AuditAction union (lib/passport/audit.ts:3-11) does not include those values and no code anywhere calls appendAuditEntry with them (grep finds references only in this route and its test, which force action: "spend" as never). Consequently dailySpentXlm and weeklySpentXlm will always be 0 against real data — the tests pass only because they bypass the type system. Add spend/verified_spend to AuditAction and ensure the spend flow actually writes those audit entries (with metadata.amountXlm), otherwise the endpoint reports fabricated zeros.

⚠️ Bug: spendLimits/circuitBreakerStatus can never populate in production

📄 app/api/protocol/passport/[id]/health/route.ts:82-96

The route casts passport.config to a shape with optional spendLimits/circuitBreaker, but PassportConfig is defined as only { allowTransfer: boolean } (lib/passport/passport.ts:6), so these fields are never present on real records and spendingLimits/circuitBreakerStatus will always be null. The test only exercises this by casting injected config as Partial<PassportRecord>, bypassing the type. Extend PassportConfig to declare spendLimits/circuitBreaker so the values can actually be stored and surfaced.

🤖 Prompt for agents
Code Review: Derives live daily and weekly spend from audit logs and surfaces circuit breaker status, but the spend calculation always returns zero because no producer emits the expected action types.

1. ⚠️ Bug: Daily/weekly spend always 0 — no producer emits spend entries
   Files: app/api/protocol/passport/[id]/health/route.ts:18-23, app/api/protocol/passport/[id]/health/route.ts:72-79

   `spendAmount` only counts audit entries whose action is `spend` or `verified_spend`, but the `AuditAction` union (lib/passport/audit.ts:3-11) does not include those values and no code anywhere calls `appendAuditEntry` with them (grep finds references only in this route and its test, which force `action: "spend" as never`). Consequently `dailySpentXlm` and `weeklySpentXlm` will always be 0 against real data — the tests pass only because they bypass the type system. Add `spend`/`verified_spend` to `AuditAction` and ensure the spend flow actually writes those audit entries (with `metadata.amountXlm`), otherwise the endpoint reports fabricated zeros.

2. ⚠️ Bug: spendLimits/circuitBreakerStatus can never populate in production
   Files: app/api/protocol/passport/[id]/health/route.ts:82-96

   The route casts `passport.config` to a shape with optional `spendLimits`/`circuitBreaker`, but `PassportConfig` is defined as only `{ allowTransfer: boolean }` (lib/passport/passport.ts:6), so these fields are never present on real records and `spendingLimits`/`circuitBreakerStatus` will always be null. The test only exercises this by casting injected config `as Partial<PassportRecord>`, bypassing the type. Extend `PassportConfig` to declare `spendLimits`/`circuitBreaker` so the values can actually be stored and surfaced.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Important

Your trial ends in 7 days — upgrade now to keep code review, CI analysis, auto-apply, custom automations, and more.

Was this helpful? React with 👍 / 👎 | Gitar

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