0b8f7c7299
Diagrams reviewed: docs/architecture/AGENT_DIAGRAM.md, docs/architecture/GATEWAY_SESSIONS_AND_QUEUE.md, docs/api/PROTOCOL.md (no changes required).
196 lines
5.7 KiB
TypeScript
196 lines
5.7 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import type { AuditEvent } from './types.js';
|
|
import { renderPhase0BaselineMarkdown, summarizePhase0Baseline } from './phase0BaselineSummary.js';
|
|
|
|
function makeEvent(
|
|
timestamp: number,
|
|
event_type: AuditEvent['event_type'],
|
|
event: Record<string, unknown>,
|
|
): AuditEvent {
|
|
return {
|
|
timestamp,
|
|
level: 'info',
|
|
event_type,
|
|
event,
|
|
};
|
|
}
|
|
|
|
describe('summarizePhase0Baseline', () => {
|
|
it('summarizes run outcomes, cancel latency, and reaction decisions', () => {
|
|
const events: AuditEvent[] = [
|
|
makeEvent(1000, 'run.state', {
|
|
session_id: 'telegram:s1',
|
|
channel: 'telegram',
|
|
sender: 'u1',
|
|
source: 'channel',
|
|
state: 'start',
|
|
}),
|
|
makeEvent(1200, 'run.state', {
|
|
session_id: 'telegram:s1',
|
|
channel: 'telegram',
|
|
sender: 'u1',
|
|
source: 'channel',
|
|
state: 'complete',
|
|
}),
|
|
makeEvent(2000, 'run.state', {
|
|
session_id: 'discord:s2',
|
|
channel: 'discord',
|
|
sender: 'u2',
|
|
source: 'gateway',
|
|
state: 'start',
|
|
}),
|
|
makeEvent(2400, 'run.state', {
|
|
session_id: 'discord:s2',
|
|
channel: 'discord',
|
|
sender: 'u2',
|
|
source: 'gateway',
|
|
state: 'error',
|
|
}),
|
|
makeEvent(3000, 'run.state', {
|
|
session_id: 'telegram:s3',
|
|
channel: 'telegram',
|
|
sender: 'u3',
|
|
source: 'channel',
|
|
state: 'start',
|
|
}),
|
|
makeEvent(3200, 'run.state', {
|
|
session_id: 'telegram:s3',
|
|
channel: 'telegram',
|
|
sender: 'u3',
|
|
source: 'channel',
|
|
state: 'cancelled',
|
|
}),
|
|
makeEvent(3300, 'run.state', {
|
|
session_id: 'telegram:s3',
|
|
channel: 'telegram',
|
|
sender: 'u3',
|
|
source: 'channel',
|
|
state: 'cancel_requested',
|
|
}),
|
|
makeEvent(3500, 'run.cancel', {
|
|
session_id: 'telegram:s3',
|
|
channel: 'telegram',
|
|
sender: 'u3',
|
|
source: 'channel',
|
|
requested: true,
|
|
acknowledged: true,
|
|
latency_ms: 120,
|
|
}),
|
|
makeEvent(3600, 'run.cancel', {
|
|
session_id: 'discord:s2',
|
|
channel: 'discord',
|
|
sender: 'u2',
|
|
source: 'gateway',
|
|
requested: true,
|
|
acknowledged: false,
|
|
latency_ms: 300,
|
|
}),
|
|
makeEvent(3700, 'reaction.match', {
|
|
session_id: 'telegram:s1',
|
|
channel: 'telegram',
|
|
sender: 'u1',
|
|
source: 'channel',
|
|
rule_name: 'boss-email',
|
|
}),
|
|
makeEvent(3800, 'reaction.skip', {
|
|
session_id: 'telegram:s1',
|
|
channel: 'telegram',
|
|
sender: 'u1',
|
|
source: 'channel',
|
|
reason: 'no_match',
|
|
candidate_count: 1,
|
|
}),
|
|
makeEvent(3900, 'reaction.skip', {
|
|
session_id: 'discord:s2',
|
|
channel: 'discord',
|
|
sender: 'u2',
|
|
source: 'gateway',
|
|
reason: 'no_rules',
|
|
candidate_count: 0,
|
|
}),
|
|
];
|
|
|
|
const summary = summarizePhase0Baseline(events);
|
|
|
|
expect(summary.event_counts.run_state).toBe(7);
|
|
expect(summary.run_outcomes.overall.total_outcomes).toBe(3);
|
|
expect(summary.run_outcomes.overall.complete).toBe(1);
|
|
expect(summary.run_outcomes.overall.cancelled).toBe(1);
|
|
expect(summary.run_outcomes.overall.error).toBe(1);
|
|
expect(summary.run_outcomes.overall.cancel_requested).toBe(1);
|
|
expect(summary.run_outcomes.overall.start).toBe(3);
|
|
|
|
const telegram = summary.run_outcomes.by_channel.find((row) => row.key === 'telegram');
|
|
expect(telegram?.stats.total_outcomes).toBe(2);
|
|
const discord = summary.run_outcomes.by_channel.find((row) => row.key === 'discord');
|
|
expect(discord?.stats.total_outcomes).toBe(1);
|
|
|
|
const cancelStats = summary.cancel_latency_ms;
|
|
expect(cancelStats?.count).toBe(2);
|
|
expect(cancelStats?.p50_ms).toBe(210);
|
|
expect(cancelStats?.p95_ms).toBe(291);
|
|
|
|
expect(summary.reactions.matched).toBe(1);
|
|
expect(summary.reactions.skipped).toBe(2);
|
|
expect(summary.reactions.match_rate_pct).toBe(33.33);
|
|
|
|
expect(summary.reactions.skip_reasons).toEqual([
|
|
{ reason: 'no_match', count: 1, pct: 50 },
|
|
{ reason: 'no_rules', count: 1, pct: 50 },
|
|
]);
|
|
});
|
|
|
|
it('filters by channel', () => {
|
|
const events: AuditEvent[] = [
|
|
makeEvent(1000, 'run.state', {
|
|
session_id: 'telegram:s1',
|
|
channel: 'telegram',
|
|
sender: 'u1',
|
|
source: 'channel',
|
|
state: 'complete',
|
|
}),
|
|
makeEvent(1100, 'run.state', {
|
|
session_id: 'discord:s2',
|
|
channel: 'discord',
|
|
sender: 'u2',
|
|
source: 'gateway',
|
|
state: 'error',
|
|
}),
|
|
];
|
|
|
|
const summary = summarizePhase0Baseline(events, { channels: ['telegram'] });
|
|
expect(summary.run_outcomes.overall.total_outcomes).toBe(1);
|
|
expect(summary.run_outcomes.by_channel).toHaveLength(1);
|
|
expect(summary.run_outcomes.by_channel[0]?.key).toBe('telegram');
|
|
});
|
|
});
|
|
|
|
describe('renderPhase0BaselineMarkdown', () => {
|
|
it('renders key sections', () => {
|
|
const events: AuditEvent[] = [
|
|
makeEvent(1000, 'run.state', {
|
|
session_id: 'telegram:s1',
|
|
channel: 'telegram',
|
|
sender: 'u1',
|
|
source: 'channel',
|
|
state: 'complete',
|
|
}),
|
|
makeEvent(1200, 'reaction.skip', {
|
|
session_id: 'telegram:s1',
|
|
channel: 'telegram',
|
|
sender: 'u1',
|
|
source: 'channel',
|
|
reason: 'no_match',
|
|
candidate_count: 1,
|
|
}),
|
|
];
|
|
|
|
const summary = summarizePhase0Baseline(events);
|
|
const markdown = renderPhase0BaselineMarkdown(summary);
|
|
expect(markdown).toContain('Phase 0 Baseline Telemetry Summary');
|
|
expect(markdown).toContain('Run Outcomes (Overall)');
|
|
expect(markdown).toContain('Reaction Decisions');
|
|
expect(markdown).toContain('no_match');
|
|
});
|
|
});
|