mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-07 07:55:13 +02:00
feat: add historic sql bucket helpers
This commit is contained in:
parent
55140d1e6c
commit
6a291a1875
3 changed files with 109 additions and 0 deletions
|
|
@ -0,0 +1,59 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import {
|
||||
bucketDistinctUsers,
|
||||
bucketErrorRate,
|
||||
bucketExecutions,
|
||||
bucketFrequency,
|
||||
bucketP95Runtime,
|
||||
bucketRecency,
|
||||
} from './buckets.js';
|
||||
|
||||
describe('historic-sql bucket helpers', () => {
|
||||
it('uses stable execution buckets', () => {
|
||||
expect([0, 9, 10, 99, 100, 999, 1000, 4999, 5000, 49999, 50000].map(bucketExecutions)).toEqual([
|
||||
'<10',
|
||||
'<10',
|
||||
'10-100',
|
||||
'10-100',
|
||||
'100-1k',
|
||||
'100-1k',
|
||||
'1k-5k',
|
||||
'1k-5k',
|
||||
'5k-50k',
|
||||
'5k-50k',
|
||||
'>50k',
|
||||
]);
|
||||
});
|
||||
|
||||
it('uses stable distinct-user, error-rate, runtime, and recency buckets', () => {
|
||||
expect([0, 1, 2, 5, 6, 10, 11].map(bucketDistinctUsers)).toEqual([
|
||||
'0',
|
||||
'1',
|
||||
'2-5',
|
||||
'2-5',
|
||||
'5-10',
|
||||
'5-10',
|
||||
'>10',
|
||||
]);
|
||||
expect([0, 0.01, 0.05, 0.2].map(bucketErrorRate)).toEqual(['none', 'low', 'low', 'high']);
|
||||
expect([null, 99, 100, 999, 1000, 9999, 10000].map(bucketP95Runtime)).toEqual([
|
||||
'unknown',
|
||||
'<100ms',
|
||||
'100ms-1s',
|
||||
'100ms-1s',
|
||||
'1s-10s',
|
||||
'1s-10s',
|
||||
'>10s',
|
||||
]);
|
||||
expect(bucketRecency('2026-05-11T00:00:00.000Z', new Date('2026-05-11T12:00:00.000Z'))).toBe('current');
|
||||
expect(bucketRecency('2026-04-20T00:00:00.000Z', new Date('2026-05-11T12:00:00.000Z'))).toBe('recent');
|
||||
expect(bucketRecency('2026-01-01T00:00:00.000Z', new Date('2026-05-11T12:00:00.000Z'))).toBe('stale');
|
||||
});
|
||||
|
||||
it('maps frequency counts to high, mid, and low labels', () => {
|
||||
expect(bucketFrequency(80, 100)).toBe('high');
|
||||
expect(bucketFrequency(20, 100)).toBe('mid');
|
||||
expect(bucketFrequency(1, 100)).toBe('low');
|
||||
expect(bucketFrequency(0, 0)).toBe('low');
|
||||
});
|
||||
});
|
||||
49
packages/context/src/ingest/adapters/historic-sql/buckets.ts
Normal file
49
packages/context/src/ingest/adapters/historic-sql/buckets.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
export function bucketExecutions(value: number): string {
|
||||
if (value < 10) return '<10';
|
||||
if (value < 100) return '10-100';
|
||||
if (value < 1000) return '100-1k';
|
||||
if (value < 5000) return '1k-5k';
|
||||
if (value < 50000) return '5k-50k';
|
||||
return '>50k';
|
||||
}
|
||||
|
||||
export function bucketDistinctUsers(value: number): string {
|
||||
if (value <= 0) return '0';
|
||||
if (value === 1) return '1';
|
||||
if (value <= 5) return '2-5';
|
||||
if (value <= 10) return '5-10';
|
||||
return '>10';
|
||||
}
|
||||
|
||||
export function bucketErrorRate(value: number): string {
|
||||
if (value <= 0) return 'none';
|
||||
if (value < 0.1) return 'low';
|
||||
return 'high';
|
||||
}
|
||||
|
||||
export function bucketP95Runtime(value: number | null): string {
|
||||
if (value === null) return 'unknown';
|
||||
if (value < 100) return '<100ms';
|
||||
if (value < 1000) return '100ms-1s';
|
||||
if (value < 10000) return '1s-10s';
|
||||
return '>10s';
|
||||
}
|
||||
|
||||
export function bucketRecency(lastSeen: string, now: Date): string {
|
||||
const parsed = new Date(lastSeen);
|
||||
if (Number.isNaN(parsed.getTime())) {
|
||||
return 'unknown';
|
||||
}
|
||||
const ageDays = (now.getTime() - parsed.getTime()) / (24 * 60 * 60 * 1000);
|
||||
if (ageDays <= 7) return 'current';
|
||||
if (ageDays <= 45) return 'recent';
|
||||
return 'stale';
|
||||
}
|
||||
|
||||
export function bucketFrequency(count: number, total: number): 'high' | 'mid' | 'low' {
|
||||
if (total <= 0 || count <= 0) return 'low';
|
||||
const ratio = count / total;
|
||||
if (ratio >= 0.5) return 'high';
|
||||
if (ratio >= 0.1) return 'mid';
|
||||
return 'low';
|
||||
}
|
||||
|
|
@ -317,6 +317,7 @@ export type {
|
|||
export { NOTION_ORG_KNOWLEDGE_WARNING } from './adapters/notion/chunk.js';
|
||||
export { NotionSourceAdapter, type NotionSourceAdapterDeps } from './adapters/notion/notion.adapter.js';
|
||||
export { NotionClient, type NotionApi, type NotionBotInfo } from './adapters/notion/notion-client.js';
|
||||
export { bucketDistinctUsers, bucketErrorRate, bucketExecutions, bucketP95Runtime, bucketRecency } from './adapters/historic-sql/buckets.js';
|
||||
export { chunkHistoricSqlStagedDir, describeHistoricSqlScope } from './adapters/historic-sql/chunk.js';
|
||||
export { detectHistoricSqlStagedDir } from './adapters/historic-sql/detect.js';
|
||||
export {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue