From a2c17a8b0da6171578fa20c06d5da8f53a92080d Mon Sep 17 00:00:00 2001 From: altair823 Date: Tue, 5 May 2026 01:29:11 +0900 Subject: [PATCH] =?UTF-8?q?refactor(v026):=20#5=20AiFailedReason=20union?= =?UTF-8?q?=20=EB=8B=A8=EC=9D=BC=20export=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 기존 'unreachable' | 'schema' | 'timeout' | 'other' literal 이 3곳에 분산: - telemetryEvents.ts (zod enum AiFailedReason) - TelemetryService.ts (EmitInput 안 inline literal) - AiWorker.ts (classifyReason 반환 + AiTelemetryEmitter inline literal) zod enum z.infer 통해 type 파생, 단일 export AiFailedReason 으로 통합. - AiFailedReasonSchema (zod enum) + AiFailedReason (type) 둘 다 export - TelemetryService EmitInput / AiWorker classifyReason / AiTelemetryEmitter 모두 import type AiFailedReason 사용 Co-Authored-By: Claude Opus 4.7 (1M context) --- src/main/ai/AiWorker.ts | 5 +++-- src/main/services/TelemetryService.ts | 3 ++- src/main/services/telemetryEvents.ts | 5 +++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/ai/AiWorker.ts b/src/main/ai/AiWorker.ts index 9850f27..f7469ad 100644 --- a/src/main/ai/AiWorker.ts +++ b/src/main/ai/AiWorker.ts @@ -1,11 +1,12 @@ import type { NoteRepository } from '../repository/NoteRepository.js'; import type { Note } from '@shared/types'; +import type { AiFailedReason } from '../services/telemetryEvents.js'; import { ProviderHolder } from './ProviderHolder.js'; import { parseAllCandidates } from '../services/dueDateParser.js'; import { ZodError } from 'zod'; import { kstTodayAsDate, kstTodayIso } from '../../shared/util/kstDate.js'; -function classifyReason(err: unknown): 'unreachable' | 'schema' | 'timeout' | 'other' { +function classifyReason(err: unknown): AiFailedReason { if (err instanceof ZodError) return 'schema'; const msg = err instanceof Error ? err.message.toLowerCase() : String(err).toLowerCase(); if (msg.includes('econnrefused') || msg.includes('enotfound') || msg.includes('fetch failed') || msg.includes('econnreset') || msg.includes('unreachable')) { @@ -20,7 +21,7 @@ function classifyReason(err: unknown): 'unreachable' | 'schema' | 'timeout' | 'o export interface AiTelemetryEmitter { emit(input: | { kind: 'ai_succeeded'; payload: { noteId: string; durationMs: number; attempts: number } } - | { kind: 'ai_failed'; payload: { noteId: string; reason: 'unreachable' | 'schema' | 'timeout' | 'other'; attempts: number } } + | { kind: 'ai_failed'; payload: { noteId: string; reason: AiFailedReason; attempts: number } } | { kind: 'tag_vocab_hit'; payload: { tagId: number; vocabSize: number } } | { kind: 'tag_vocab_miss'; payload: { vocabSize: number } } ): Promise; diff --git a/src/main/services/TelemetryService.ts b/src/main/services/TelemetryService.ts index 3d5e8fc..ecd147b 100644 --- a/src/main/services/TelemetryService.ts +++ b/src/main/services/TelemetryService.ts @@ -1,6 +1,7 @@ import { mkdir, appendFile, readFile, readdir, unlink, writeFile } from 'node:fs/promises'; import { join } from 'node:path'; import { validateEvent, TelemetryEvent } from './telemetryEvents.js'; +import type { AiFailedReason } from './telemetryEvents.js'; import { aggregateStats } from './telemetryStats.js'; import { kstTodayIso, DAY_MS } from '../../shared/util/kstDate.js'; @@ -11,7 +12,7 @@ export interface TelemetryServiceOptions { export type EmitInput = | { kind: 'capture'; payload: { noteId: string; rawTextLength: number; hasMedia: boolean } } | { kind: 'ai_succeeded'; payload: { noteId: string; durationMs: number; attempts: number } } - | { kind: 'ai_failed'; payload: { noteId: string; reason: 'unreachable' | 'schema' | 'timeout' | 'other'; attempts: number } } + | { kind: 'ai_failed'; payload: { noteId: string; reason: AiFailedReason; attempts: number } } | { kind: 'trash'; payload: { noteId: string } } | { kind: 'restore'; payload: { noteId: string } } | { kind: 'permanent_delete'; payload: { noteId: string } } diff --git a/src/main/services/telemetryEvents.ts b/src/main/services/telemetryEvents.ts index 67d194f..6704c87 100644 --- a/src/main/services/telemetryEvents.ts +++ b/src/main/services/telemetryEvents.ts @@ -12,11 +12,12 @@ const AiSucceededPayload = z.object({ attempts: z.number().int().nonnegative() }).strict(); -const AiFailedReason = z.enum(['unreachable', 'schema', 'timeout', 'other']); +export const AiFailedReasonSchema = z.enum(['unreachable', 'schema', 'timeout', 'other']); +export type AiFailedReason = z.infer; const AiFailedPayload = z.object({ noteId: z.string().min(1), - reason: AiFailedReason, + reason: AiFailedReasonSchema, attempts: z.number().int().nonnegative() }).strict();