feat(expiry): telemetry 2 events — expired_banner_shown / expired_batch_trash (#5 v0.2.3)

This commit is contained in:
altair823
2026-05-02 00:08:44 +09:00
parent fec80361dd
commit f76ca06d9e
6 changed files with 105 additions and 9 deletions

View File

@@ -18,6 +18,8 @@ interface DailyRow {
restore: number;
permanent_delete: number;
empty_trash: number;
expired_banner_shown: number;
expired_batch_trash: number;
}
export interface StatsResult {
@@ -34,11 +36,18 @@ export function aggregateStats(events: TelemetryEvent[], generatedAt: Date): Sta
let durationN = 0;
let trashCount = 0;
let restoreCount = 0;
let expiredBannerShownCandidatesSum = 0;
let expiredBatchTrashCountSum = 0;
for (const ev of events) {
const day = kstDate(ev.ts);
let row = byDay.get(day);
if (!row) {
row = { date: day, capture: 0, ai_succeeded: 0, ai_failed: 0, trash: 0, restore: 0, permanent_delete: 0, empty_trash: 0 };
row = {
date: day,
capture: 0, ai_succeeded: 0, ai_failed: 0,
trash: 0, restore: 0, permanent_delete: 0, empty_trash: 0,
expired_banner_shown: 0, expired_batch_trash: 0
};
byDay.set(day, row);
}
if (ev.kind === 'capture') row.capture += 1;
@@ -60,6 +69,12 @@ export function aggregateStats(events: TelemetryEvent[], generatedAt: Date): Sta
row.permanent_delete += 1;
} else if (ev.kind === 'empty_trash') {
row.empty_trash += 1;
} else if (ev.kind === 'expired_banner_shown') {
row.expired_banner_shown += 1;
expiredBannerShownCandidatesSum += ev.payload.candidateCount;
} else if (ev.kind === 'expired_batch_trash') {
row.expired_batch_trash += 1;
expiredBatchTrashCountSum += ev.payload.count;
}
}
const days = Array.from(byDay.values()).sort((a, b) => a.date.localeCompare(b.date));
@@ -69,6 +84,9 @@ export function aggregateStats(events: TelemetryEvent[], generatedAt: Date): Sta
const trashRecoveryRate = trashCount === 0
? 'N/A'
: `${(restoreCount / trashCount * 100).toFixed(1)}% (${restoreCount}/${trashCount})`;
const expiredTrashRatio = expiredBannerShownCandidatesSum === 0
? 'N/A'
: `${(expiredBatchTrashCountSum / expiredBannerShownCandidatesSum * 100).toFixed(1)}% (${expiredBatchTrashCountSum}/${expiredBannerShownCandidatesSum})`;
const lines: string[] = [];
lines.push('# Inkling Telemetry Stats');
lines.push('');
@@ -77,10 +95,10 @@ export function aggregateStats(events: TelemetryEvent[], generatedAt: Date): Sta
lines.push('');
lines.push('## 일자별 카운트');
lines.push('');
lines.push('| 일자 | capture | ai_succeeded | ai_failed | trash | restore | permanent_delete | empty_trash |');
lines.push('|------|---------|--------------|-----------|-------|---------|------------------|-------------|');
lines.push('| 일자 | capture | ai_succeeded | ai_failed | trash | restore | permanent_delete | empty_trash | expired_banner_shown | expired_batch_trash |');
lines.push('|------|---------|--------------|-----------|-------|---------|------------------|-------------|----------------------|---------------------|');
for (const row of days) {
lines.push(`| ${row.date} | ${row.capture} | ${row.ai_succeeded} | ${row.ai_failed} | ${row.trash} | ${row.restore} | ${row.permanent_delete} | ${row.empty_trash} |`);
lines.push(`| ${row.date} | ${row.capture} | ${row.ai_succeeded} | ${row.ai_failed} | ${row.trash} | ${row.restore} | ${row.permanent_delete} | ${row.empty_trash} | ${row.expired_banner_shown} | ${row.expired_batch_trash} |`);
}
lines.push('');
lines.push('## 핵심 ratio');
@@ -88,6 +106,7 @@ export function aggregateStats(events: TelemetryEvent[], generatedAt: Date): Sta
lines.push(`- AI 성공률: ${successRate}`);
lines.push(`- 평균 ai_succeeded durationMs: ${avgDuration}`);
lines.push(`- 휴지통 회수율: ${trashRecoveryRate}`);
lines.push(`- 만료 trash ratio: ${expiredTrashRatio}`);
lines.push('');
return { md: lines.join('\n'), eventCount };
}