atagen

malice

public
Star0
Watch0
cf020696433e54fc5fb60de3b67218baef8c4748
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git

Blame: web/src/lib/repair-model.ts

9f996e377406atagen2026-10-25 03:32 UTC1
export type HistoryRepairPolicy =
9f996e377406atagen2026-10-25 03:32 UTC2
  | 'StartRecent'
9f996e377406atagen2026-10-25 03:32 UTC3
  | 'Bridge'
9f996e377406atagen2026-10-25 03:32 UTC4
  | { BridgeShortGaps: { threshold_ms: number } };
9f996e377406atagen2026-10-25 03:32 UTC5
9f996e377406atagen2026-10-25 03:32 UTC6
export interface HistoryRepairBudget {
9f996e377406atagen2026-10-25 03:32 UTC7
  max_pages: number;
9f996e377406atagen2026-10-25 03:32 UTC8
  max_events: number;
9f996e377406atagen2026-10-25 03:32 UTC9
  max_duration_ms: number;
9f996e377406atagen2026-10-25 03:32 UTC10
}
9f996e377406atagen2026-10-25 03:32 UTC11
9f996e377406atagen2026-10-25 03:32 UTC12
export interface HistoryRepairFailure {
9f996e377406atagen2026-10-25 03:32 UTC13
  kind: string;
9f996e377406atagen2026-10-25 03:32 UTC14
  message: string;
9f996e377406atagen2026-10-25 03:32 UTC15
  server?: { status: number; errcode: string; message: string } | null;
9f996e377406atagen2026-10-25 03:32 UTC16
  [key: string]: unknown;
9f996e377406atagen2026-10-25 03:32 UTC17
}
9f996e377406atagen2026-10-25 03:32 UTC18
9f996e377406atagen2026-10-25 03:32 UTC19
export interface HistoryRepairReport {
9f996e377406atagen2026-10-25 03:32 UTC20
  room_id: string;
9f996e377406atagen2026-10-25 03:32 UTC21
  requested_policy: HistoryRepairPolicy;
9f996e377406atagen2026-10-25 03:32 UTC22
  strategy: 'Recent' | 'Overlap' | 'Bridge';
9f996e377406atagen2026-10-25 03:32 UTC23
  coverage_duration_ms: number | null;
9f996e377406atagen2026-10-25 03:32 UTC24
  threshold_evaluated: boolean;
9f996e377406atagen2026-10-25 03:32 UTC25
  pages: number;
9f996e377406atagen2026-10-25 03:32 UTC26
  events: number;
9f996e377406atagen2026-10-25 03:32 UTC27
  phase: 'FetchingRecent' | 'Bridging' | 'Ready' | 'Paused';
9f996e377406atagen2026-10-25 03:32 UTC28
  continuity: 'Unresolved' | 'Verified' | 'AccessibleStart';
9f996e377406atagen2026-10-25 03:32 UTC29
  recent_available: boolean;
9f996e377406atagen2026-10-25 03:32 UTC30
  stop: 'Cancelled' | 'Budget' | 'HistoryUnavailable' | 'NoAnchor' | 'CursorStalled' | null;
9f996e377406atagen2026-10-25 03:32 UTC31
  failure: HistoryRepairFailure | null;
9f996e377406atagen2026-10-25 03:32 UTC32
}
9f996e377406atagen2026-10-25 03:32 UTC33
9f996e377406atagen2026-10-25 03:32 UTC34
export const DEFAULT_HISTORY_REPAIR_BUDGET: HistoryRepairBudget = {
9f996e377406atagen2026-10-25 03:32 UTC35
  max_pages: 10,
9f996e377406atagen2026-10-25 03:32 UTC36
  max_events: 1000,
9f996e377406atagen2026-10-25 03:32 UTC37
  max_duration_ms: 15000
9f996e377406atagen2026-10-25 03:32 UTC38
};
9f996e377406atagen2026-10-25 03:32 UTC39
9f996e377406atagen2026-10-25 03:32 UTC40
function record(value: unknown): Record<string, unknown> | null {
9f996e377406atagen2026-10-25 03:32 UTC41
  return typeof value === 'object' && value !== null && !Array.isArray(value)
9f996e377406atagen2026-10-25 03:32 UTC42
    ? (value as Record<string, unknown>)
9f996e377406atagen2026-10-25 03:32 UTC43
    : null;
9f996e377406atagen2026-10-25 03:32 UTC44
}
9f996e377406atagen2026-10-25 03:32 UTC45
9f996e377406atagen2026-10-25 03:32 UTC46
function safeNonnegativeInteger(value: unknown): value is number {
9f996e377406atagen2026-10-25 03:32 UTC47
  return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;
9f996e377406atagen2026-10-25 03:32 UTC48
}
9f996e377406atagen2026-10-25 03:32 UTC49
9f996e377406atagen2026-10-25 03:32 UTC50
export function parseHistoryRepairPolicy(value: unknown): HistoryRepairPolicy | null {
9f996e377406atagen2026-10-25 03:32 UTC51
  if (value === 'StartRecent' || value === 'Bridge') return value;
9f996e377406atagen2026-10-25 03:32 UTC52
  const outer = record(value);
9f996e377406atagen2026-10-25 03:32 UTC53
  const details = outer && record(outer['BridgeShortGaps']);
9f996e377406atagen2026-10-25 03:32 UTC54
  if (!outer || Object.keys(outer).length !== 1 || !details || Object.keys(details).length !== 1 || !safeNonnegativeInteger(details['threshold_ms'])) return null;
9f996e377406atagen2026-10-25 03:32 UTC55
  return { BridgeShortGaps: { threshold_ms: details['threshold_ms'] } };
9f996e377406atagen2026-10-25 03:32 UTC56
}
9f996e377406atagen2026-10-25 03:32 UTC57
9f996e377406atagen2026-10-25 03:32 UTC58
function isOneOf<T extends string>(value: unknown, values: readonly T[]): value is T {
9f996e377406atagen2026-10-25 03:32 UTC59
  return typeof value === 'string' && (values as readonly string[]).includes(value);
9f996e377406atagen2026-10-25 03:32 UTC60
}
9f996e377406atagen2026-10-25 03:32 UTC61
9f996e377406atagen2026-10-25 03:32 UTC62
export function parseHistoryRepairReport(value: unknown): HistoryRepairReport | null {
9f996e377406atagen2026-10-25 03:32 UTC63
  const data = record(value);
9f996e377406atagen2026-10-25 03:32 UTC64
  if (!data) return null;
9f996e377406atagen2026-10-25 03:32 UTC65
  const policy = parseHistoryRepairPolicy(data['requested_policy']);
9f996e377406atagen2026-10-25 03:32 UTC66
  const failure = data['failure'];
9f996e377406atagen2026-10-25 03:32 UTC67
  const failureData = failure === null ? null : record(failure);
9f996e377406atagen2026-10-25 03:32 UTC68
  if (
9f996e377406atagen2026-10-25 03:32 UTC69
    typeof data['room_id'] !== 'string' || !policy ||
9f996e377406atagen2026-10-25 03:32 UTC70
    !isOneOf(data['strategy'], ['Recent', 'Overlap', 'Bridge']) ||
9f996e377406atagen2026-10-25 03:32 UTC71
    !(data['coverage_duration_ms'] === null || safeNonnegativeInteger(data['coverage_duration_ms'])) ||
9f996e377406atagen2026-10-25 03:32 UTC72
    typeof data['threshold_evaluated'] !== 'boolean' ||
9f996e377406atagen2026-10-25 03:32 UTC73
    !safeNonnegativeInteger(data['pages']) || !safeNonnegativeInteger(data['events']) ||
9f996e377406atagen2026-10-25 03:32 UTC74
    !isOneOf(data['phase'], ['FetchingRecent', 'Bridging', 'Ready', 'Paused']) ||
9f996e377406atagen2026-10-25 03:32 UTC75
    !isOneOf(data['continuity'], ['Unresolved', 'Verified', 'AccessibleStart']) ||
9f996e377406atagen2026-10-25 03:32 UTC76
    typeof data['recent_available'] !== 'boolean' ||
9f996e377406atagen2026-10-25 03:32 UTC77
    !(data['stop'] === null || isOneOf(data['stop'], ['Cancelled', 'Budget', 'HistoryUnavailable', 'NoAnchor', 'CursorStalled'])) ||
9f996e377406atagen2026-10-25 03:32 UTC78
    !(failure === null || (failureData && typeof failureData['kind'] === 'string' && typeof failureData['message'] === 'string'))
9f996e377406atagen2026-10-25 03:32 UTC79
  ) return null;
9f996e377406atagen2026-10-25 03:32 UTC80
  return {
9f996e377406atagen2026-10-25 03:32 UTC81
    room_id: data['room_id'],
9f996e377406atagen2026-10-25 03:32 UTC82
    requested_policy: policy,
9f996e377406atagen2026-10-25 03:32 UTC83
    strategy: data['strategy'],
9f996e377406atagen2026-10-25 03:32 UTC84
    coverage_duration_ms: data['coverage_duration_ms'],
9f996e377406atagen2026-10-25 03:32 UTC85
    threshold_evaluated: data['threshold_evaluated'],
9f996e377406atagen2026-10-25 03:32 UTC86
    pages: data['pages'],
9f996e377406atagen2026-10-25 03:32 UTC87
    events: data['events'],
9f996e377406atagen2026-10-25 03:32 UTC88
    phase: data['phase'],
9f996e377406atagen2026-10-25 03:32 UTC89
    continuity: data['continuity'],
9f996e377406atagen2026-10-25 03:32 UTC90
    recent_available: data['recent_available'],
9f996e377406atagen2026-10-25 03:32 UTC91
    stop: data['stop'],
9f996e377406atagen2026-10-25 03:32 UTC92
    failure: failureData as HistoryRepairFailure | null
9f996e377406atagen2026-10-25 03:32 UTC93
  };
9f996e377406atagen2026-10-25 03:32 UTC94
}