atagen

malice

public
Star0
Watch0
132eeceeb3625aabae038739d20d7954e510dc25
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git
web/src/lib/repair-model.tsTypescript94 lines3.7 KB
1
export type HistoryRepairPolicy =
2
  | 'StartRecent'
3
  | 'Bridge'
4
  | { BridgeShortGaps: { threshold_ms: number } };
5
6
export interface HistoryRepairBudget {
7
  max_pages: number;
8
  max_events: number;
9
  max_duration_ms: number;
10
}
11
12
export interface HistoryRepairFailure {
13
  kind: string;
14
  message: string;
15
  server?: { status: number; errcode: string; message: string } | null;
16
  [key: string]: unknown;
17
}
18
19
export interface HistoryRepairReport {
20
  room_id: string;
21
  requested_policy: HistoryRepairPolicy;
22
  strategy: 'Recent' | 'Overlap' | 'Bridge';
23
  coverage_duration_ms: number | null;
24
  threshold_evaluated: boolean;
25
  pages: number;
26
  events: number;
27
  phase: 'FetchingRecent' | 'Bridging' | 'Ready' | 'Paused';
28
  continuity: 'Unresolved' | 'Verified' | 'AccessibleStart';
29
  recent_available: boolean;
30
  stop: 'Cancelled' | 'Budget' | 'HistoryUnavailable' | 'NoAnchor' | 'CursorStalled' | null;
31
  failure: HistoryRepairFailure | null;
32
}
33
34
export const DEFAULT_HISTORY_REPAIR_BUDGET: HistoryRepairBudget = {
35
  max_pages: 10,
36
  max_events: 1000,
37
  max_duration_ms: 15000
38
};
39
40
function record(value: unknown): Record<string, unknown> | null {
41
  return typeof value === 'object' && value !== null && !Array.isArray(value)
42
    ? (value as Record<string, unknown>)
43
    : null;
44
}
45
46
function safeNonnegativeInteger(value: unknown): value is number {
47
  return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;
48
}
49
50
export function parseHistoryRepairPolicy(value: unknown): HistoryRepairPolicy | null {
51
  if (value === 'StartRecent' || value === 'Bridge') return value;
52
  const outer = record(value);
53
  const details = outer && record(outer['BridgeShortGaps']);
54
  if (!outer || Object.keys(outer).length !== 1 || !details || Object.keys(details).length !== 1 || !safeNonnegativeInteger(details['threshold_ms'])) return null;
55
  return { BridgeShortGaps: { threshold_ms: details['threshold_ms'] } };
56
}
57
58
function isOneOf<T extends string>(value: unknown, values: readonly T[]): value is T {
59
  return typeof value === 'string' && (values as readonly string[]).includes(value);
60
}
61
62
export function parseHistoryRepairReport(value: unknown): HistoryRepairReport | null {
63
  const data = record(value);
64
  if (!data) return null;
65
  const policy = parseHistoryRepairPolicy(data['requested_policy']);
66
  const failure = data['failure'];
67
  const failureData = failure === null ? null : record(failure);
68
  if (
69
    typeof data['room_id'] !== 'string' || !policy ||
70
    !isOneOf(data['strategy'], ['Recent', 'Overlap', 'Bridge']) ||
71
    !(data['coverage_duration_ms'] === null || safeNonnegativeInteger(data['coverage_duration_ms'])) ||
72
    typeof data['threshold_evaluated'] !== 'boolean' ||
73
    !safeNonnegativeInteger(data['pages']) || !safeNonnegativeInteger(data['events']) ||
74
    !isOneOf(data['phase'], ['FetchingRecent', 'Bridging', 'Ready', 'Paused']) ||
75
    !isOneOf(data['continuity'], ['Unresolved', 'Verified', 'AccessibleStart']) ||
76
    typeof data['recent_available'] !== 'boolean' ||
77
    !(data['stop'] === null || isOneOf(data['stop'], ['Cancelled', 'Budget', 'HistoryUnavailable', 'NoAnchor', 'CursorStalled'])) ||
78
    !(failure === null || (failureData && typeof failureData['kind'] === 'string' && typeof failureData['message'] === 'string'))
79
  ) return null;
80
  return {
81
    room_id: data['room_id'],
82
    requested_policy: policy,
83
    strategy: data['strategy'],
84
    coverage_duration_ms: data['coverage_duration_ms'],
85
    threshold_evaluated: data['threshold_evaluated'],
86
    pages: data['pages'],
87
    events: data['events'],
88
    phase: data['phase'],
89
    continuity: data['continuity'],
90
    recent_available: data['recent_available'],
91
    stop: data['stop'],
92
    failure: failureData as HistoryRepairFailure | null
93
  };
94
}