import { mkdirSync, readFileSync, writeFileSync } from 'node:fs' import { dirname, join } from 'node:path' import type { DesktopAccountInfo } from '@geo/shared-types' import { app } from 'electron/main' import type { PublishAccountIdentity } from './account-binder' import type { AccountAuthReason, AccountAuthState, AccountHealthProfile, AccountHealthSnapshot, AccountProbeState, AuthProbeResult, } from './auth-types' import { getPlatformAdapter, type PlatformAdapter, type PlatformFailureInput, } from './platform-auth-adapters' import { emitRuntimeInvalidated } from './runtime-events' import { getPersistedPartition, getSessionHandle } from './session-registry' const PROBE_TICK_MS = 1_000 const STALE_AFTER_MS = 45 * 60_000 const INITIAL_PROBE_MIN_MS = 1_000 const INITIAL_PROBE_MAX_MS = 10_000 const REGULAR_PROBE_MIN_MS = 30 * 60_000 const REGULAR_PROBE_MAX_MS = STALE_AFTER_MS const CONFIRM_BACKOFF_STEPS_MS = [30_000, 120_000] as const const NETWORK_RETRY_MS = 2 * 60_000 const PREFLIGHT_MAX_AGE_MS = 15 * 60_000 const MAX_CONCURRENT_ACCOUNT_PROBES = 2 const MANUAL_PROBE_CACHE_TTL_MS = 5 * 60_000 const MANUAL_PROBE_MIN_INTERVAL_MS = 15_000 const ACCOUNT_PROBE_RETRY_BACKOFF_MS = [1_000, 3_000, 10_000] as const const CHALLENGE_RECHECK_ATTEMPTS = 1 type ProbeTrigger = 'scheduled' | 'manual' | 'preflight' | 'confirm' interface PersistedAccountHealthRecord { accountId: string platform: string lastVerifiedAt: number | null lastAuthFailureAt: number | null profile: AccountHealthProfile | null sessionFingerprint: string | null } interface AccountHealthRecord { accountId: string platform: string authRevision: number authState: AccountAuthState probeState: AccountProbeState authReason: AccountAuthReason lastVerifiedAt: number | null lastProbeAt: number | null nextProbeAt: number | null lastAuthFailureAt: number | null profile: AccountHealthProfile | null sessionFingerprint: string | null suspectedExpiredAt: number | null confirmFailureCount: number } interface AccountProbeJob { account: PublishAccountIdentity trigger: ProbeTrigger allowSilentRefresh: boolean force: boolean status: 'queued' | 'running' attempt: number maxAttempts: number resolve: (snapshot: AccountHealthSnapshot) => void reject: (error: unknown) => void promise: Promise } const trackedAccounts = new Map() const records = new Map() const accountLocks = new Map>() const probeJobs = new Map() const probeQueue: string[] = [] let initialized = false let probeTimer: ReturnType | null = null let activeProbeCount = 0 function randomInt(min: number, max: number): number { if (max <= min) { return min } return min + Math.floor(Math.random() * (max - min)) } function persistedHealthPath(): string { return join(app.getPath('userData'), 'desktop-account-health.json') } function resolvePartition(accountId: string): string { return ( getSessionHandle(accountId)?.partition ?? getPersistedPartition(accountId) ?? `persist:acc-${accountId}` ) } function resolveKnownPartition(accountId: string): string | null { return getSessionHandle(accountId)?.partition ?? getPersistedPartition(accountId) ?? null } function nextInitialProbeAt(now = Date.now()): number { return now + randomInt(INITIAL_PROBE_MIN_MS, INITIAL_PROBE_MAX_MS) } function nextRegularProbeAt(now = Date.now()): number { return now + randomInt(REGULAR_PROBE_MIN_MS, REGULAR_PROBE_MAX_MS) } function normalizePersisted(record: PersistedAccountHealthRecord): AccountHealthRecord { return { accountId: record.accountId, platform: record.platform, authRevision: 0, authState: record.lastVerifiedAt ? 'active' : 'unknown', probeState: 'idle', authReason: record.lastVerifiedAt ? 'probe_success' : null, lastVerifiedAt: record.lastVerifiedAt ?? null, lastProbeAt: null, nextProbeAt: nextInitialProbeAt(), lastAuthFailureAt: record.lastAuthFailureAt ?? null, profile: record.profile ?? null, sessionFingerprint: record.sessionFingerprint ?? null, suspectedExpiredAt: null, confirmFailureCount: 0, } } function loadPersistedRecords(): void { try { const raw = JSON.parse( readFileSync(persistedHealthPath(), 'utf8'), ) as PersistedAccountHealthRecord[] for (const item of raw) { if (!item?.accountId || !item?.platform) { continue } records.set(item.accountId, normalizePersisted(item)) } } catch { records.clear() } } function persistRecords(): void { const payload: PersistedAccountHealthRecord[] = [...records.values()].map((record) => ({ accountId: record.accountId, platform: record.platform, lastVerifiedAt: record.lastVerifiedAt, lastAuthFailureAt: record.lastAuthFailureAt, profile: record.profile, sessionFingerprint: record.sessionFingerprint, })) const target = persistedHealthPath() mkdirSync(dirname(target), { recursive: true }) writeFileSync(target, JSON.stringify(payload, null, 2), 'utf8') } function ensureInitialized(): void { if (initialized) { return } initialized = true loadPersistedRecords() } function ensureProbeTimer(): void { ensureInitialized() if (probeTimer) { return } probeTimer = setInterval(() => { void runDueProbes() }, PROBE_TICK_MS) } function coerceDerivedAuthState(record: AccountHealthRecord): AccountAuthState { return record.authState } function toPublicSnapshot(record: AccountHealthRecord): AccountHealthSnapshot { return { accountId: record.accountId, platform: record.platform, partition: resolvePartition(record.accountId), authState: coerceDerivedAuthState(record), probeState: record.probeState, authReason: record.authReason, lastVerifiedAt: record.lastVerifiedAt, lastProbeAt: record.lastProbeAt, nextProbeAt: record.nextProbeAt, lastAuthFailureAt: record.lastAuthFailureAt, profile: record.profile, sessionFingerprint: record.sessionFingerprint, } } function snapshotSignature(record: AccountHealthRecord): string { return JSON.stringify(toPublicSnapshot(record)) } function commitRecord( record: AccountHealthRecord, previousSignature: string | null, ): AccountHealthSnapshot { records.set(record.accountId, record) persistRecords() const nextSignature = snapshotSignature(record) if (previousSignature !== nextSignature) { emitRuntimeInvalidated('account-health', { accountId: record.accountId }) } return toPublicSnapshot(record) } function ensureRecord(account: PublishAccountIdentity): AccountHealthRecord { ensureInitialized() const existing = records.get(account.id) if (existing) { existing.platform = account.platform return existing } const created: AccountHealthRecord = { accountId: account.id, platform: account.platform, authRevision: 0, authState: 'unknown', probeState: 'idle', authReason: null, lastVerifiedAt: null, lastProbeAt: null, nextProbeAt: nextInitialProbeAt(), lastAuthFailureAt: null, profile: null, sessionFingerprint: null, suspectedExpiredAt: null, confirmFailureCount: 0, } records.set(account.id, created) persistRecords() return created } async function withAccountLock(accountId: string, work: () => Promise): Promise { const previous = accountLocks.get(accountId) ?? Promise.resolve() let release!: () => void const current = new Promise((resolve) => { release = resolve }) accountLocks.set(accountId, current) await previous.catch(() => undefined) try { return await work() } finally { release() if (accountLocks.get(accountId) === current) { accountLocks.delete(accountId) } } } function confirmBackoffMs(failureCount: number): number { const index = Math.min(Math.max(failureCount - 1, 0), CONFIRM_BACKOFF_STEPS_MS.length - 1) return ( CONFIRM_BACKOFF_STEPS_MS[index] ?? CONFIRM_BACKOFF_STEPS_MS[CONFIRM_BACKOFF_STEPS_MS.length - 1] ) } function applyActiveResult( record: AccountHealthRecord, result: AuthProbeResult, now: number, ): AccountHealthSnapshot { const previousSignature = snapshotSignature(record) record.authState = 'active' record.probeState = 'idle' record.authReason = result.reason ?? 'probe_success' record.lastVerifiedAt = now record.lastProbeAt = now record.nextProbeAt = nextRegularProbeAt(now) record.lastAuthFailureAt = null record.profile = result.profile ?? record.profile record.sessionFingerprint = result.sessionFingerprint ?? record.sessionFingerprint record.suspectedExpiredAt = null record.confirmFailureCount = 0 return commitRecord(record, previousSignature) } function applyExpiredResult( record: AccountHealthRecord, result: AuthProbeResult, now: number, ): AccountHealthSnapshot { const previousSignature = snapshotSignature(record) record.authState = 'expired' record.probeState = 'idle' record.authReason = result.reason ?? 'login_redirect' record.lastProbeAt = now record.nextProbeAt = null record.lastAuthFailureAt = now record.suspectedExpiredAt = null record.confirmFailureCount = 0 return commitRecord(record, previousSignature) } function applyChallengeResult( record: AccountHealthRecord, result: AuthProbeResult, now: number, ): AccountHealthSnapshot { const previousSignature = snapshotSignature(record) record.authState = 'challenge_required' record.probeState = 'idle' record.authReason = result.reason ?? 'captcha_gate' record.lastProbeAt = now record.nextProbeAt = nextRegularProbeAt(now) record.lastAuthFailureAt = now record.suspectedExpiredAt = null record.confirmFailureCount = 0 return commitRecord(record, previousSignature) } function applyNetworkResult( record: AccountHealthRecord, result: AuthProbeResult, now: number, trigger: 'scheduled' | 'manual' | 'preflight' | 'confirm', ): AccountHealthSnapshot { const previousSignature = snapshotSignature(record) const hadSuspicion = Boolean(record.suspectedExpiredAt) record.probeState = 'network_error' record.authReason = result.reason ?? 'network_error' record.lastProbeAt = now if (hadSuspicion && trigger === 'confirm') { record.confirmFailureCount += 1 record.authState = record.authState === 'unknown' ? 'unknown' : 'expiring_soon' record.nextProbeAt = now + confirmBackoffMs(record.confirmFailureCount) } else { record.nextProbeAt = now + NETWORK_RETRY_MS if (record.authState === 'active') { record.authState = 'expiring_soon' } } return commitRecord(record, previousSignature) } function networkProbeResult(): AuthProbeResult { return { verdict: 'network_error', reason: 'network_error', profile: null, sessionFingerprint: null, } } async function probeAdapter( adapter: PlatformAdapter, account: PublishAccountIdentity, partition: string, ): Promise { return await adapter.probe(account, partition).catch(() => networkProbeResult()) } async function recheckChallengeResult( adapter: PlatformAdapter, account: PublishAccountIdentity, partition: string, result: AuthProbeResult, ): Promise { if (result.verdict !== 'challenge_required') { return result } let confirmed = result for (let attempt = 0; attempt < CHALLENGE_RECHECK_ATTEMPTS; attempt += 1) { confirmed = await probeAdapter(adapter, account, partition) if (confirmed.verdict !== 'challenge_required') { return confirmed } } return confirmed } function applyProbeResult( record: AccountHealthRecord, result: AuthProbeResult, now: number, trigger: ProbeTrigger, ): AccountHealthSnapshot { switch (result.verdict) { case 'active': return applyActiveResult(record, result, now) case 'expired': return applyExpiredResult(record, result, now) case 'challenge_required': return applyChallengeResult(record, result, now) default: return applyNetworkResult(record, result, now, trigger) } } async function performProbeLocked( account: PublishAccountIdentity, options: { trigger: ProbeTrigger allowSilentRefresh: boolean }, ): Promise { const record = ensureRecord(account) const adapter = getPlatformAdapter(account.platform) const probeAuthRevision = record.authRevision const previousSignature = snapshotSignature(record) record.probeState = 'probing' commitRecord(record, previousSignature) const partition = resolveKnownPartition(account.id) if (!partition) { return applyExpiredResult( record, { verdict: 'expired', reason: 'missing_partition', profile: null, sessionFingerprint: null, }, Date.now(), ) } if (options.allowSilentRefresh) { const refreshed = await adapter.silentRefresh(account, partition).catch(() => false) if (record.authRevision !== probeAuthRevision) { return toPublicSnapshot(record) } if (!refreshed) { const currentSignature = snapshotSignature(record) record.authReason = 'silent_refresh_failed' commitRecord(record, currentSignature) } } const result = await probeAdapter(adapter, account, partition) if (record.authRevision !== probeAuthRevision) { return toPublicSnapshot(record) } const confirmedResult = await recheckChallengeResult(adapter, account, partition, result) if (record.authRevision !== probeAuthRevision) { return toPublicSnapshot(record) } return applyProbeResult(record, confirmedResult, Date.now(), options.trigger) } function canUseCachedProbe( record: AccountHealthRecord, options: { trigger: ProbeTrigger; force: boolean }, now = Date.now(), ): boolean { if (options.force) { return false } if ( options.trigger === 'manual' && record.lastProbeAt && now - record.lastProbeAt < MANUAL_PROBE_MIN_INTERVAL_MS ) { return true } if ( (options.trigger === 'manual' || options.trigger === 'scheduled') && record.authState === 'active' && record.lastVerifiedAt && now - record.lastVerifiedAt < MANUAL_PROBE_CACHE_TTL_MS && record.probeState !== 'network_error' ) { return true } return false } function markProbeQueued(record: AccountHealthRecord): AccountHealthSnapshot { const previousSignature = snapshotSignature(record) record.probeState = 'queued' return commitRecord(record, previousSignature) } function isProbeInFlight(record: AccountHealthRecord): boolean { return record.probeState === 'queued' || record.probeState === 'probing' } function isStaleActiveRecord(record: AccountHealthRecord, now = Date.now()): boolean { return ( record.authState === 'active' && Boolean(record.lastVerifiedAt) && now - (record.lastVerifiedAt ?? 0) >= STALE_AFTER_MS ) } function maxAttemptsForTrigger(trigger: ProbeTrigger): number { return trigger === 'preflight' ? 1 : ACCOUNT_PROBE_RETRY_BACKOFF_MS.length + 1 } function enqueueProbeJob(job: AccountProbeJob): void { if (!probeQueue.includes(job.account.id)) { probeQueue.push(job.account.id) } drainProbeQueue() } function removeQueuedProbeJob(accountId: string): void { const job = probeJobs.get(accountId) if (!job || job.status !== 'queued') { return } probeJobs.delete(accountId) for (let index = probeQueue.length - 1; index >= 0; index -= 1) { if (probeQueue[index] === accountId) { probeQueue.splice(index, 1) } } } function scheduleProbeRetry(job: AccountProbeJob): void { const retryIndex = Math.min( Math.max(job.attempt - 2, 0), ACCOUNT_PROBE_RETRY_BACKOFF_MS.length - 1, ) const backoff = ACCOUNT_PROBE_RETRY_BACKOFF_MS[retryIndex] ?? ACCOUNT_PROBE_RETRY_BACKOFF_MS[ACCOUNT_PROBE_RETRY_BACKOFF_MS.length - 1] job.status = 'queued' setTimeout(() => enqueueProbeJob(job), backoff) } function drainProbeQueue(): void { while (activeProbeCount < MAX_CONCURRENT_ACCOUNT_PROBES && probeQueue.length > 0) { const accountId = probeQueue.shift() if (!accountId) { continue } const job = probeJobs.get(accountId) if (!job || job.status !== 'queued') { continue } job.status = 'running' activeProbeCount += 1 void runProbeJob(job) } } async function runProbeJob(job: AccountProbeJob): Promise { try { const snapshot = await withAccountLock(job.account.id, async () => { const record = ensureRecord(job.account) if (canUseCachedProbe(record, job)) { return toPublicSnapshot(record) } return await performProbeLocked(job.account, { trigger: job.trigger, allowSilentRefresh: job.allowSilentRefresh, }) }) if (snapshot.probeState === 'network_error' && job.attempt < job.maxAttempts) { job.attempt += 1 scheduleProbeRetry(job) return } probeJobs.delete(job.account.id) job.resolve(snapshot) } catch (error) { probeJobs.delete(job.account.id) job.reject(error) } finally { activeProbeCount = Math.max(0, activeProbeCount - 1) drainProbeQueue() } } function enqueueAccountProbe( account: PublishAccountIdentity, options: { trigger?: ProbeTrigger allowSilentRefresh?: boolean force?: boolean } = {}, ): Promise { syncTrackedAccountsInternal([account], false) const trigger = options.trigger ?? 'manual' const force = Boolean(options.force) const record = ensureRecord(account) if (canUseCachedProbe(record, { trigger, force })) { return Promise.resolve(toPublicSnapshot(record)) } const existing = probeJobs.get(account.id) if (existing) { if (force) { existing.force = true } existing.allowSilentRefresh = existing.allowSilentRefresh || Boolean(options.allowSilentRefresh) if (trigger === 'manual') { existing.trigger = 'manual' } return existing.promise } markProbeQueued(record) let resolve!: (snapshot: AccountHealthSnapshot) => void let reject!: (error: unknown) => void const promise = new Promise((resolvePromise, rejectPromise) => { resolve = resolvePromise reject = rejectPromise }) const job: AccountProbeJob = { account, trigger, allowSilentRefresh: Boolean(options.allowSilentRefresh), force, status: 'queued', attempt: 1, maxAttempts: maxAttemptsForTrigger(trigger), resolve, reject, promise, } probeJobs.set(account.id, job) enqueueProbeJob(job) return promise } async function runDueProbes(): Promise { const now = Date.now() const dueAccounts = [...trackedAccounts.values()].filter((account) => { const record = records.get(account.id) if (!record || isProbeInFlight(record)) { return false } return Boolean( (record.nextProbeAt && record.nextProbeAt <= now) || isStaleActiveRecord(record, now), ) }) for (const account of dueAccounts) { const record = records.get(account.id) if (!record) { continue } const trigger = record.suspectedExpiredAt ? 'confirm' : 'scheduled' void enqueueAccountProbe(account, { trigger, allowSilentRefresh: true, }).catch((error) => { console.warn('[desktop-account-health] scheduled probe failed', { accountId: account.id, platform: account.platform, message: error instanceof Error ? error.message : String(error), }) }) } } function parseVerifiedAt(value: string | null | undefined): number | null { if (!value) { return null } const timestamp = Date.parse(value) return Number.isNaN(timestamp) ? null : timestamp } function fallbackAuthState( health: DesktopAccountInfo['health'] | null | undefined, ): AccountAuthState { switch (health) { case 'live': return 'unknown' case 'captcha': return 'challenge_required' case 'expired': return 'expired' default: return 'unknown' } } export function initAccountHealth(): void { ensureInitialized() ensureProbeTimer() } export function syncTrackedAccounts(accounts: PublishAccountIdentity[]): void { syncTrackedAccountsInternal(accounts, true) } function syncTrackedAccountsInternal( accounts: PublishAccountIdentity[], pruneMissing: boolean, ): void { initAccountHealth() let removed = false if (pruneMissing) { const nextIds = new Set(accounts.map((account) => account.id)) for (const [accountId] of trackedAccounts.entries()) { if (!nextIds.has(accountId)) { trackedAccounts.delete(accountId) records.delete(accountId) removed = true emitRuntimeInvalidated('account-health', { accountId }) } } } for (const account of accounts) { trackedAccounts.set(account.id, account) ensureRecord(account) } persistRecords() if (removed) { emitRuntimeInvalidated('account-health') } if (pruneMissing) { queueMicrotask(() => { void runDueProbes() }) } } export function forgetTrackedAccountHealth(accountId: string): void { trackedAccounts.delete(accountId) if (records.delete(accountId)) { persistRecords() emitRuntimeInvalidated('account-health', { accountId }) } } export function markTrackedAccountBound( account: PublishAccountIdentity, profile: AccountHealthProfile | null = null, ): AccountHealthSnapshot { const record = ensureRecord(account) const previousSignature = snapshotSignature(record) const now = Date.now() const resolvedProfile: AccountHealthProfile = { displayName: profile?.displayName ?? account.displayName ?? null, avatarUrl: profile?.avatarUrl ?? null, subjectUid: profile?.subjectUid ?? account.platformUid ?? null, } trackedAccounts.set(account.id, account) record.authRevision += 1 record.platform = account.platform record.authState = 'active' record.probeState = 'idle' record.authReason = 'bind_success' record.lastVerifiedAt = now record.lastProbeAt = now record.nextProbeAt = nextRegularProbeAt(now) record.lastAuthFailureAt = null record.profile = resolvedProfile record.sessionFingerprint = resolvedProfile.subjectUid ?? record.sessionFingerprint record.suspectedExpiredAt = null record.confirmFailureCount = 0 const snapshot = commitRecord(record, previousSignature) const queuedJob = probeJobs.get(account.id) if (queuedJob?.status === 'queued') { removeQueuedProbeJob(account.id) queuedJob.resolve(snapshot) } return snapshot } export function markTrackedAccountMissingPartition( account: PublishAccountIdentity, ): AccountHealthSnapshot { const record = ensureRecord(account) const previousSignature = snapshotSignature(record) const now = Date.now() trackedAccounts.delete(account.id) record.authRevision += 1 record.platform = account.platform record.authState = 'expired' record.probeState = 'idle' record.authReason = 'missing_partition' record.lastProbeAt = now record.nextProbeAt = null record.lastAuthFailureAt = now record.profile = null record.sessionFingerprint = null record.suspectedExpiredAt = null record.confirmFailureCount = 0 const snapshot = commitRecord(record, previousSignature) const queuedJob = probeJobs.get(account.id) if (queuedJob?.status === 'queued') { removeQueuedProbeJob(account.id) queuedJob.resolve(snapshot) } return snapshot } export function getAccountHealthSnapshot(accountId: string): AccountHealthSnapshot | null { ensureInitialized() const record = records.get(accountId) return record ? toPublicSnapshot(record) : null } export function getProjectedAccountHealth(input: { accountId: string platform: string health?: DesktopAccountInfo['health'] verifiedAt?: string | null }) { const snapshot = getAccountHealthSnapshot(input.accountId) if (!snapshot) { return { health: input.health ?? 'risk', authState: fallbackAuthState(input.health), probeState: 'idle' as AccountProbeState, authReason: null as AccountAuthReason, lastVerifiedAt: parseVerifiedAt(input.verifiedAt), lastProbeAt: null, nextProbeAt: null, lastAuthFailureAt: null, profile: null, sessionFingerprint: null, partition: resolvePartition(input.accountId), } } const health = snapshot.authState === 'active' ? ('live' as const) : snapshot.authState === 'challenge_required' ? ('captcha' as const) : snapshot.authState === 'expired' || snapshot.authState === 'revoked' ? ('expired' as const) : ('risk' as const) return { ...snapshot, health, } } export async function probeTrackedAccount( account: PublishAccountIdentity, options: { trigger?: ProbeTrigger allowSilentRefresh?: boolean force?: boolean } = {}, ): Promise { return await enqueueAccountProbe(account, { trigger: options.trigger ?? 'manual', allowSilentRefresh: Boolean(options.allowSilentRefresh), force: Boolean(options.force), }) } export async function ensureAccountReady( account: PublishAccountIdentity, ): Promise { syncTrackedAccountsInternal([account], false) const snapshot = getAccountHealthSnapshot(account.id) const isFresh = snapshot?.lastVerifiedAt ? Date.now() - snapshot.lastVerifiedAt < PREFLIGHT_MAX_AGE_MS : false if ( snapshot && snapshot.authState === 'active' && snapshot.probeState !== 'network_error' && isFresh ) { return snapshot } if ( snapshot && ['expired', 'challenge_required', 'revoked'].includes(snapshot.authState) && !(account.platform === 'baijiahao' && snapshot.authState === 'challenge_required') ) { return snapshot } return await withAccountLock(account.id, async () => { const lockedSnapshot = getAccountHealthSnapshot(account.id) const lockedFresh = lockedSnapshot?.lastVerifiedAt ? Date.now() - lockedSnapshot.lastVerifiedAt < PREFLIGHT_MAX_AGE_MS : false if ( lockedSnapshot && lockedSnapshot.authState === 'active' && lockedSnapshot.probeState !== 'network_error' && lockedFresh ) { return lockedSnapshot } return await performProbeLocked(account, { trigger: 'preflight', allowSilentRefresh: true, }) }) } export async function reportAccountFailure( account: PublishAccountIdentity, input: PlatformFailureInput, ): Promise { syncTrackedAccountsInternal([account], false) const adapter = getPlatformAdapter(account.platform) const classification = adapter.classifyFailure(input) if (classification === 'ok') { return getAccountHealthSnapshot(account.id) } return await withAccountLock(account.id, async () => { const record = ensureRecord(account) const previousSignature = snapshotSignature(record) const now = Date.now() if (classification === 'challenge' || classification === 'risk_control') { record.probeState = 'probing' commitRecord(record, previousSignature) const partition = resolveKnownPartition(account.id) const result = partition ? await recheckChallengeResult(adapter, account, partition, { verdict: 'challenge_required', reason: classification === 'risk_control' ? 'risk_control' : 'captcha_gate', profile: null, sessionFingerprint: null, }) : { verdict: 'expired' as const, reason: 'missing_partition' as const, profile: null, sessionFingerprint: null, } return applyProbeResult(record, result, Date.now(), 'confirm') } if (classification === 'network') { record.probeState = 'network_error' record.authReason = 'network_error' record.lastProbeAt = now record.nextProbeAt = now + NETWORK_RETRY_MS return commitRecord(record, previousSignature) } record.lastAuthFailureAt = now record.suspectedExpiredAt = record.suspectedExpiredAt ?? now if (record.authState === 'active') { record.authState = 'expiring_soon' } record.nextProbeAt = now commitRecord(record, previousSignature) return await performProbeLocked(account, { trigger: 'confirm', allowSilentRefresh: true, }) }) }