refactor(v026): #5 AiFailedReason union 단일 export 통합
기존 '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) <noreply@anthropic.com>
This commit is contained in:
@@ -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<void>;
|
||||
|
||||
@@ -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 } }
|
||||
|
||||
@@ -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<typeof AiFailedReasonSchema>;
|
||||
|
||||
const AiFailedPayload = z.object({
|
||||
noteId: z.string().min(1),
|
||||
reason: AiFailedReason,
|
||||
reason: AiFailedReasonSchema,
|
||||
attempts: z.number().int().nonnegative()
|
||||
}).strict();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user