diff --git a/src/lib/oauth/crs-usage-probe.mjs b/src/lib/oauth/crs-usage-probe.mjs index 90961052f..f62c078d8 100644 --- a/src/lib/oauth/crs-usage-probe.mjs +++ b/src/lib/oauth/crs-usage-probe.mjs @@ -135,7 +135,9 @@ export function parseOAuthUsage(data = {}) { export function isCompleteOAuthUsage(data = {}, parsed = null) { const p = parsed || parseOAuthUsage(data) - if (!p.five_hour || !p.seven_day) return false + // Official usage can omit the session window while retaining weekly limits. + // Keep an absent window unknown; a supplied but unreadable window is invalid. + if (!p.seven_day || (!p.five_hour && data.five_hour != null)) return false if (p.usage_has_fable !== null) return true // 2.1.293 GET /api/oauth/usage is a Utilization object: named windows, no limits[] catalog. if ( diff --git a/test/unit/crs-usage-probe.test.mjs b/test/unit/crs-usage-probe.test.mjs index 150c2c50b..f72741cdb 100644 --- a/test/unit/crs-usage-probe.test.mjs +++ b/test/unit/crs-usage-probe.test.mjs @@ -2,6 +2,7 @@ import { test } from 'node:test' import assert from 'node:assert/strict' import { parseOAuthUsage, + isCompleteOAuthUsage, parseFableProbe, isFablePlanDenied, isFableUnavailablePro, @@ -16,6 +17,25 @@ import { probeVmUsage, } from '../../src/lib/oauth/crs-usage-probe.mjs' +test('official weekly-only usage is complete without inventing a session window', () => { + const data = { + five_hour: null, + seven_day: { utilization: 4, resets_at: '2026-11-05T12:00:00Z' }, + limits: [{ kind: 'weekly_all', percent: 4, resets_at: '2026-11-05T12:00:00Z' }], + } + const parsed = parseOAuthUsage(data) + assert.equal(isCompleteOAuthUsage(data, parsed), true) + assert.equal(parsed.five_hour, null) + assert.equal(parsed.seven_day.utilization, 0.04) + const { five_hour, ...omitted } = data + assert.equal(isCompleteOAuthUsage(omitted), true) + assert.equal(isCompleteOAuthUsage({ ...data, five_hour: { utilization: 12 } }), true) + assert.equal(isCompleteOAuthUsage({ ...data, five_hour: {} }), false) + assert.equal(isCompleteOAuthUsage({ ...data, seven_day: null }), false) + assert.equal(isCompleteOAuthUsage({ five_hour: null, seven_day: null, limits: [] }), false) + assert.equal(isCompleteOAuthUsage({}), false) +}) + test('oauth usage parse: official percent scale 1 = 1%', () => { const p = parseOAuthUsage({ five_hour: { utilization: 1, resets_at: '2026-08-18T20:00:00Z' },