Files
Jyotisha/frontend/src/lib/birth-time-dynamic-result-validator.ts
T

65 lines
2.2 KiB
TypeScript

import type { DynamicChoiceScoringResult } from "./birth-time-dynamic-choice-internal.ts";
import type { TimeRange } from "./birth-time-dynamic-choice.ts";
import { BirthTimeScoringJobError } from "./birth-time-scoring-job.ts";
function minute(value: string): number {
const [hour, part] = value.split(":").map(Number);
return hour * 60 + part;
}
function rangeMinutes(range: TimeRange): readonly number[] {
const start = minute(range.startTime);
const end = minute(range.endTime);
const values = [start];
let current = start;
while (current !== end) {
current = (current + 1) % 1_440;
values.push(current);
}
return values;
}
function segmentIsCoherent(
result: DynamicChoiceScoringResult,
currentRange: TimeRange,
): boolean {
const segment = result.candidate.winningSegment;
if (segment === null) return true;
const candidates = rangeMinutes(currentRange);
const start = candidates.indexOf(minute(segment.startTime));
const end = candidates.indexOf(minute(segment.endTime));
if (start < 0 || end < start) return false;
const width = end - start + 1;
const representative = candidates[start + Math.floor((width - 1) / 2)];
return segment.widthMinutes === width
&& minute(segment.representativeTime) === representative;
}
export function assertDynamicScoringResult(
result: DynamicChoiceScoringResult,
currentRange: TimeRange,
): void {
const candidate = result.candidate;
const segment = candidate.winningSegment;
const blocked = candidate.reasons.includes("missing_mandatory_layers");
const high = !blocked
&& result.effectiveAnswerCount >= 4
&& result.dimensionCount >= 3
&& segment !== null
&& segment.widthMinutes <= 5
&& candidate.marginPercent >= 20;
const medium = !blocked
&& result.effectiveAnswerCount >= 3
&& result.dimensionCount >= 2
&& segment !== null
&& segment.widthMinutes <= 15
&& candidate.marginPercent >= 10;
const expected = high ? "high" : medium ? "medium" : "low";
if (!segmentIsCoherent(result, currentRange)
|| candidate.confidence !== expected
|| candidate.canApply !== false
|| candidate.evidence.length !== 0) {
throw new BirthTimeScoringJobError("invalid_result");
}
}