Repository navigation
Expand file tree
/
Copy pathprepare.ts
More file actions
71 lines (66 loc) · 2.58 KB
/
Copy pathprepare.ts
File metadata and controls
71 lines (66 loc) · 2.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import { toSituationAnswer, type EvalCase, type EvalQuestion } from "./eval-question.ts";
import { EvalQuestions } from "./questions/index.ts";
import { buildTimeline, type BuiltTimeline } from "./timeline.ts";
export interface PreparedCase {
evalCase: EvalCase;
timeline: BuiltTimeline;
ruleAnswer: string;
/** Situations only: "yes" whenever any built-in signal fired. */
signalPresentAnswer: string | null;
}
export interface PreparedQuestion {
question: EvalQuestion;
cases: PreparedCase[];
}
export function selectQuestions(questionIds: readonly string[]): readonly EvalQuestion[] {
if (questionIds.length === 0) return EvalQuestions;
return questionIds.map((questionId) => {
const question = EvalQuestions.find((candidate) => candidate.id === questionId);
if (!question) {
const known = EvalQuestions.map((candidate) => candidate.id).join(", ");
throw new Error(`Unknown question ${questionId}. Known: ${known}.`);
}
return question;
});
}
export function prepareQuestions(questions: readonly EvalQuestion[]): PreparedQuestion[] {
return questions.map((question) => ({
question,
cases: question.cases.map((evalCase) => {
const timeline = buildTimeline(evalCase.timeline, evalCase.askedAt);
const ruleInput = {
state: evalCase.state,
events: timeline.events,
signalNames: timeline.signalNames,
};
return {
evalCase,
timeline,
ruleAnswer: question.answerByRule(ruleInput),
signalPresentAnswer:
question.kind === "situation" ? toSituationAnswer(timeline.signalNames.length > 0) : null,
};
}),
}));
}
/** A pair whose members fire different signals could be told apart by a signal rule, which defeats its purpose. */
export function failOnUnmatchedPairs(questions: readonly PreparedQuestion[]): void {
const problems: string[] = [];
for (const { question, cases } of questions) {
const signalsByPair = new Map<string, Set<string>>();
for (const { evalCase, timeline } of cases) {
if (evalCase.pair === null) continue;
const signature = [...timeline.signalNames].sort().join(",") || "(none)";
const signatures = signalsByPair.get(evalCase.pair) ?? new Set<string>();
signalsByPair.set(evalCase.pair, signatures.add(signature));
}
for (const [pair, signatures] of signalsByPair) {
if (signatures.size > 1) {
problems.push(`${question.id} / ${pair}: ${[...signatures].join(" vs ")}`);
}
}
}
if (problems.length > 0) {
throw new Error(`These pairs aren't signal-matched:\n ${problems.join("\n ")}`);
}
}