Merge branch 'codex/birth-time-journey'
# Conflicts: # frontend/src/app/globals.css
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import {
|
||||
assistantIntentCopy,
|
||||
birthTimePersistenceValues,
|
||||
describeBirthTimeDraft,
|
||||
isBirthTimeDraftReady,
|
||||
type BirthTimeDraft,
|
||||
} from "../src/lib/birth-time-intake-model.ts";
|
||||
|
||||
const emptyDraft: BirthTimeDraft = {
|
||||
date: "1993-04-17",
|
||||
time: "",
|
||||
reportedTime: "",
|
||||
birthTimeSource: "",
|
||||
birthTimePeriod: "",
|
||||
birthTimeClue: "",
|
||||
uncertaintyBeforeMinutes: null,
|
||||
uncertaintyAfterMinutes: null,
|
||||
birthTimeStatus: "",
|
||||
};
|
||||
|
||||
test("birth time intake requires only the fields selected by the source", () => {
|
||||
const hospital = {
|
||||
...emptyDraft,
|
||||
birthTimeSource: "hospital_record",
|
||||
reportedTime: "08:16",
|
||||
} satisfies BirthTimeDraft;
|
||||
const period = {
|
||||
...emptyDraft,
|
||||
birthTimeSource: "period_only",
|
||||
birthTimePeriod: "evening",
|
||||
} satisfies BirthTimeDraft;
|
||||
const incompleteApproximate = {
|
||||
...emptyDraft,
|
||||
birthTimeSource: "approximate",
|
||||
reportedTime: "14:30",
|
||||
} satisfies BirthTimeDraft;
|
||||
|
||||
assert.equal(isBirthTimeDraftReady(hospital), true);
|
||||
assert.equal(isBirthTimeDraftReady(period), true);
|
||||
assert.equal(isBirthTimeDraftReady(incompleteApproximate), false);
|
||||
assert.equal(isBirthTimeDraftReady({ ...emptyDraft, birthTimeSource: "unknown" }), true);
|
||||
});
|
||||
|
||||
test("birth time declaration payload cannot write deterministic application fields", () => {
|
||||
const draft = {
|
||||
...emptyDraft,
|
||||
time: "14:24",
|
||||
reportedTime: "14:30",
|
||||
birthTimeSource: "approximate",
|
||||
uncertaintyBeforeMinutes: 30,
|
||||
uncertaintyAfterMinutes: 30,
|
||||
birthTimeStatus: "confirmed",
|
||||
} satisfies BirthTimeDraft;
|
||||
|
||||
assert.deepEqual(birthTimePersistenceValues(draft), {
|
||||
reported_birth_time: "14:30",
|
||||
birth_time_source: "approximate",
|
||||
birth_time_period: null,
|
||||
birth_time_clue: null,
|
||||
uncertainty_before_minutes: 30,
|
||||
uncertainty_after_minutes: 30,
|
||||
});
|
||||
});
|
||||
|
||||
test("birth time intake describes uncertainty without claiming false precision", () => {
|
||||
const approximate = {
|
||||
...emptyDraft,
|
||||
birthTimeSource: "approximate",
|
||||
reportedTime: "14:30",
|
||||
uncertaintyBeforeMinutes: 30,
|
||||
uncertaintyAfterMinutes: 30,
|
||||
} satisfies BirthTimeDraft;
|
||||
|
||||
assert.equal(describeBirthTimeDraft(approximate), "1993年4月17日,约 14:30(前后 30 分钟)");
|
||||
assert.equal(
|
||||
assistantIntentCopy("present_saved_candidate_range"),
|
||||
"目前只能保存候选范围,还没有足够证据应用到具体分钟。",
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,108 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import {
|
||||
parseBirthTimeProfile,
|
||||
parseRectificationQuestionnaire,
|
||||
parseRectificationScoring,
|
||||
} from "../src/lib/birth-time-journey-adapters.ts";
|
||||
|
||||
const coordinates = {
|
||||
latitude: 31.2304,
|
||||
longitude: 121.4737,
|
||||
timezone_offset: 8,
|
||||
} as const;
|
||||
|
||||
test("birth time profile adapter parses an exact hospital declaration", () => {
|
||||
const assessment = parseBirthTimeProfile({
|
||||
birth_date: "1993-04-17",
|
||||
reported_birth_time: "08:16:00",
|
||||
birth_time_source: "hospital_record",
|
||||
uncertainty_before_minutes: 2,
|
||||
uncertainty_after_minutes: 2,
|
||||
...coordinates,
|
||||
});
|
||||
|
||||
assert.equal(assessment.source, "hospital_record");
|
||||
if (assessment.source === "hospital_record") {
|
||||
assert.equal(assessment.reportedTime, "08:16");
|
||||
assert.equal(assessment.location.lon, 121.4737);
|
||||
}
|
||||
});
|
||||
|
||||
test("birth time profile adapter parses a period without inventing a time", () => {
|
||||
const assessment = parseBirthTimeProfile({
|
||||
birth_date: "1993-04-17",
|
||||
reported_birth_time: null,
|
||||
birth_time_source: "period_only",
|
||||
birth_time_period: "evening",
|
||||
...coordinates,
|
||||
});
|
||||
|
||||
assert.equal(assessment.source, "period_only");
|
||||
assert.equal("reportedTime" in assessment, false);
|
||||
});
|
||||
|
||||
test("birth time profile adapter rejects missing location coordinates", () => {
|
||||
assert.throws(() => parseBirthTimeProfile({
|
||||
birth_date: "1993-04-17",
|
||||
reported_birth_time: "08:16:00",
|
||||
birth_time_source: "hospital_record",
|
||||
uncertainty_before_minutes: 2,
|
||||
uncertainty_after_minutes: 2,
|
||||
}));
|
||||
});
|
||||
|
||||
test("rectification adapter normalizes Python questionnaire samples and options", () => {
|
||||
const questionnaire = parseRectificationQuestionnaire({
|
||||
questions: [{
|
||||
id: "education_environment_shift",
|
||||
prompt: "是否有明显学业变化?",
|
||||
options: [
|
||||
{ key: "A", label: "明确有" },
|
||||
{ key: "D", label: "不记得" },
|
||||
],
|
||||
}],
|
||||
candidate_scan: {
|
||||
samples: [{
|
||||
ascendant: { sign: "Cancer" },
|
||||
varga_lagna: {
|
||||
D9: { sign: "Leo" },
|
||||
D10: { sign: "Virgo" },
|
||||
},
|
||||
}],
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepEqual(questionnaire.questions[0]?.options, [
|
||||
{ key: "A", label: "明确有" },
|
||||
{ key: "D", label: "不记得" },
|
||||
]);
|
||||
assert.deepEqual(questionnaire.samples[0], {
|
||||
ascendantSign: "Cancer",
|
||||
d9Sign: "Leo",
|
||||
d10Sign: "Virgo",
|
||||
});
|
||||
});
|
||||
|
||||
test("rectification adapter rejects a malformed Python questionnaire", () => {
|
||||
assert.throws(() => parseRectificationQuestionnaire({
|
||||
questions: [{ id: "missing_prompt" }],
|
||||
candidate_scan: { samples: [] },
|
||||
}));
|
||||
});
|
||||
|
||||
test("rectification adapter normalizes scoring without elevating confidence", () => {
|
||||
const scoring = parseRectificationScoring({
|
||||
answered_count: 3,
|
||||
candidate_cluster_rankings: [
|
||||
{ cluster: "middle_candidate_cluster", score: 5 },
|
||||
],
|
||||
next_round: 2,
|
||||
});
|
||||
|
||||
assert.equal(scoring.answeredCount, 3);
|
||||
assert.deepEqual(scoring.candidateClusterRankings, [
|
||||
{ cluster: "middle_candidate_cluster", score: 5 },
|
||||
]);
|
||||
assert.equal(scoring.raw.next_round, 2);
|
||||
});
|
||||
@@ -0,0 +1,43 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import { parseJourneyResponse } from "../src/lib/birth-time-journey-client.ts";
|
||||
|
||||
const snapshot = {
|
||||
state: "rectifying",
|
||||
assistantIntent: "start_standard_rectification",
|
||||
input: "rectification_questions",
|
||||
route: "rectification",
|
||||
confidence: null,
|
||||
canApply: false,
|
||||
activeTime: null,
|
||||
reportedRange: { label: "14:00—15:00", startTime: "14:00", endTime: "15:00" },
|
||||
} as const;
|
||||
|
||||
test("journey client parses the sanitized API response", () => {
|
||||
const parsed = parseJourneyResponse({
|
||||
caseId: "7299894c-10a8-4b45-91d1-339007282c50",
|
||||
snapshot,
|
||||
questionnaire: {
|
||||
questions: [{
|
||||
id: "education_environment_shift",
|
||||
prompt: "是否有明显学业变化?",
|
||||
options: [{ key: "A", label: "明确有" }],
|
||||
}],
|
||||
samples: [],
|
||||
raw: {},
|
||||
},
|
||||
scoring: null,
|
||||
});
|
||||
|
||||
assert.equal(parsed.snapshot.route, "rectification");
|
||||
assert.equal(parsed.questionnaire?.questions[0]?.id, "education_environment_shift");
|
||||
});
|
||||
|
||||
test("journey client rejects an API response that tries to apply a rectification result", () => {
|
||||
assert.throws(() => parseJourneyResponse({
|
||||
caseId: "7299894c-10a8-4b45-91d1-339007282c50",
|
||||
snapshot: { ...snapshot, canApply: true, activeTime: "14:24" },
|
||||
questionnaire: null,
|
||||
scoring: null,
|
||||
}));
|
||||
});
|
||||
@@ -0,0 +1,216 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import { birthTimeAssessmentSchema } from "../src/lib/birth-time-journey.ts";
|
||||
import {
|
||||
createBirthTimeJourneyService,
|
||||
type BirthTimeJourneyEngine,
|
||||
type BirthTimeJourneyStore,
|
||||
type PersistedJourneyAssessment,
|
||||
type StoredRectificationCase,
|
||||
} from "../src/lib/birth-time-journey-service.ts";
|
||||
|
||||
const hospitalAssessment = birthTimeAssessmentSchema.parse({
|
||||
date: "1993-04-17",
|
||||
source: "hospital_record",
|
||||
reportedTime: "08:16",
|
||||
uncertaintyBeforeMinutes: 2,
|
||||
uncertaintyAfterMinutes: 2,
|
||||
location: { lat: 31.2304, lon: 121.4737, tz: 8 },
|
||||
});
|
||||
|
||||
function scanWithSigns(signs: readonly string[]) {
|
||||
const samples = signs.map((sign) => ({
|
||||
ascendantSign: sign,
|
||||
d9Sign: sign,
|
||||
d10Sign: sign,
|
||||
}));
|
||||
return {
|
||||
questionnaire: {
|
||||
questions: [{ id: "education_environment_shift", prompt: "是否有明显学业变化?" }],
|
||||
samples,
|
||||
raw: { candidate_scan: { samples } },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function memoryStore(initialCase?: StoredRectificationCase) {
|
||||
let savedAssessment: PersistedJourneyAssessment | null = null;
|
||||
let savedCase = initialCase ?? null;
|
||||
const store: BirthTimeJourneyStore = {
|
||||
async saveAssessment(value) {
|
||||
savedAssessment = value;
|
||||
return "case-1";
|
||||
},
|
||||
async loadCase() {
|
||||
return savedCase;
|
||||
},
|
||||
async saveScoring(value) {
|
||||
savedCase = value;
|
||||
},
|
||||
};
|
||||
return {
|
||||
store,
|
||||
savedAssessment: () => savedAssessment,
|
||||
savedCase: () => savedCase,
|
||||
};
|
||||
}
|
||||
|
||||
test("journey service activates a stable hospital record and persists its scan", async () => {
|
||||
const memory = memoryStore();
|
||||
let receivedUncertainty = 0;
|
||||
const engine: BirthTimeJourneyEngine = {
|
||||
async scan(input) {
|
||||
receivedUncertainty = input.uncertaintyMinutes;
|
||||
return scanWithSigns(["Cancer", "Cancer", "Cancer"]);
|
||||
},
|
||||
async score() {
|
||||
throw new Error("not used");
|
||||
},
|
||||
};
|
||||
const service = createBirthTimeJourneyService({ store: memory.store, engine });
|
||||
|
||||
const result = await service.assess("user-1", hospitalAssessment);
|
||||
|
||||
assert.equal(receivedUncertainty, 2);
|
||||
assert.equal(result.snapshot.route, "direct_chart");
|
||||
assert.equal(result.snapshot.activeTime, "08:16");
|
||||
assert.equal(result.caseId, "case-1");
|
||||
assert.deepEqual(memory.savedAssessment()?.candidateScan, result.questionnaire);
|
||||
});
|
||||
|
||||
test("journey service fails a scanner error closed without activating the time", async () => {
|
||||
const memory = memoryStore();
|
||||
const engine: BirthTimeJourneyEngine = {
|
||||
async scan() {
|
||||
throw new TypeError("scanner offline");
|
||||
},
|
||||
async score() {
|
||||
throw new Error("not used");
|
||||
},
|
||||
};
|
||||
const service = createBirthTimeJourneyService({ store: memory.store, engine });
|
||||
|
||||
const result = await service.assess("user-1", hospitalAssessment);
|
||||
|
||||
assert.equal(result.snapshot.route, "rectification");
|
||||
assert.equal(result.snapshot.canApply, false);
|
||||
assert.equal(result.questionnaire, null);
|
||||
assert.equal(memory.savedAssessment()?.snapshot.activeTime, null);
|
||||
});
|
||||
|
||||
test("journey service accumulates answers while preserving the application gate", async () => {
|
||||
const approximate = birthTimeAssessmentSchema.parse({
|
||||
date: "1993-04-17",
|
||||
source: "approximate",
|
||||
reportedTime: "14:30",
|
||||
uncertaintyBeforeMinutes: 30,
|
||||
uncertaintyAfterMinutes: 30,
|
||||
location: { lat: 31.2304, lon: 121.4737, tz: 8 },
|
||||
});
|
||||
const questionnaire = scanWithSigns(["Cancer", "Leo", "Leo"]).questionnaire;
|
||||
const initialSnapshot = createBirthTimeJourneyService({
|
||||
store: memoryStore().store,
|
||||
engine: {
|
||||
async scan() { return { questionnaire }; },
|
||||
async score() { throw new Error("not used"); },
|
||||
},
|
||||
});
|
||||
const assessed = await initialSnapshot.assess("user-1", approximate);
|
||||
const storedCase: StoredRectificationCase = {
|
||||
id: "case-1",
|
||||
userId: "user-1",
|
||||
snapshot: assessed.snapshot,
|
||||
questionnaire,
|
||||
answers: { education_environment_shift: "A" },
|
||||
};
|
||||
const memory = memoryStore(storedCase);
|
||||
let scoredAnswers: Readonly<Record<string, "A" | "B" | "C" | "D">> = {};
|
||||
const engine: BirthTimeJourneyEngine = {
|
||||
async scan() {
|
||||
return { questionnaire };
|
||||
},
|
||||
async score(input) {
|
||||
scoredAnswers = input.answers;
|
||||
return {
|
||||
answeredCount: 3,
|
||||
candidateClusterRankings: [{ cluster: "middle_candidate_cluster", score: 5 }],
|
||||
raw: { next_round: 2 },
|
||||
};
|
||||
},
|
||||
};
|
||||
const service = createBirthTimeJourneyService({ store: memory.store, engine });
|
||||
|
||||
const result = await service.answerQuestion("user-1", "case-1", "career_responsibility_pressure", "B");
|
||||
|
||||
assert.deepEqual(scoredAnswers, {
|
||||
education_environment_shift: "A",
|
||||
career_responsibility_pressure: "B",
|
||||
});
|
||||
assert.equal(result.snapshot.state, "candidate");
|
||||
assert.equal(result.snapshot.canApply, false);
|
||||
assert.deepEqual(memory.savedCase()?.answers, scoredAnswers);
|
||||
});
|
||||
|
||||
test("journey service resumes an owner-scoped unfinished case", async () => {
|
||||
const questionnaire = scanWithSigns(["Cancer", "Leo"]).questionnaire;
|
||||
const storedCase: StoredRectificationCase = {
|
||||
id: "case-1",
|
||||
userId: "user-1",
|
||||
snapshot: {
|
||||
state: "rectifying",
|
||||
assistantIntent: "continue_rectification_questions",
|
||||
input: "rectification_questions",
|
||||
route: "rectification",
|
||||
confidence: null,
|
||||
canApply: false,
|
||||
activeTime: null,
|
||||
reportedRange: { label: "14:00—15:00", startTime: "14:00", endTime: "15:00" },
|
||||
},
|
||||
questionnaire,
|
||||
answers: { education_environment_shift: "A" },
|
||||
};
|
||||
const service = createBirthTimeJourneyService({
|
||||
store: memoryStore(storedCase).store,
|
||||
engine: {
|
||||
async scan() { throw new Error("not used"); },
|
||||
async score() { throw new Error("not used"); },
|
||||
},
|
||||
});
|
||||
|
||||
const result = await service.resume("user-1", "case-1");
|
||||
|
||||
assert.equal(result.caseId, "case-1");
|
||||
assert.deepEqual(result.answers, { education_environment_shift: "A" });
|
||||
assert.equal(result.snapshot.canApply, false);
|
||||
});
|
||||
|
||||
test("journey service resumes a fail-closed case without a questionnaire", async () => {
|
||||
const storedCase: StoredRectificationCase = {
|
||||
id: "case-2",
|
||||
userId: "user-1",
|
||||
snapshot: {
|
||||
state: "rectifying",
|
||||
assistantIntent: "explain_assessment_unavailable",
|
||||
input: "rectification_questions",
|
||||
route: "rectification",
|
||||
confidence: null,
|
||||
canApply: false,
|
||||
activeTime: null,
|
||||
reportedRange: { label: "08:14—08:18", startTime: "08:14", endTime: "08:18" },
|
||||
},
|
||||
questionnaire: null,
|
||||
answers: {},
|
||||
};
|
||||
const service = createBirthTimeJourneyService({
|
||||
store: memoryStore(storedCase).store,
|
||||
engine: {
|
||||
async scan() { throw new Error("not used"); },
|
||||
async score() { throw new Error("not used"); },
|
||||
},
|
||||
});
|
||||
|
||||
const result = await service.resume("user-1", "case-2");
|
||||
|
||||
assert.equal(result.questionnaire, null);
|
||||
assert.equal(result.snapshot.canApply, false);
|
||||
});
|
||||
@@ -0,0 +1,155 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import {
|
||||
assessBirthTime,
|
||||
birthTimeAssessmentSchema,
|
||||
journeySnapshotSchema,
|
||||
withRectificationScoring,
|
||||
} from "../src/lib/birth-time-journey.ts";
|
||||
|
||||
const location = { lat: 31.2304, lon: 121.4737, tz: 8 } as const;
|
||||
|
||||
test("birth time journey sends a stable hospital record directly to charting", () => {
|
||||
const assessment = birthTimeAssessmentSchema.parse({
|
||||
date: "1993-04-17",
|
||||
source: "hospital_record",
|
||||
reportedTime: "08:16",
|
||||
uncertaintyBeforeMinutes: 2,
|
||||
uncertaintyAfterMinutes: 2,
|
||||
location,
|
||||
});
|
||||
|
||||
const snapshot = assessBirthTime(assessment, { kind: "stable" });
|
||||
|
||||
assert.equal(snapshot.state, "ready");
|
||||
assert.equal(snapshot.route, "direct_chart");
|
||||
assert.equal(snapshot.canApply, true);
|
||||
assert.equal(snapshot.activeTime, "08:16");
|
||||
assert.equal(snapshot.assistantIntent, "confirm_stable_record");
|
||||
assert.equal(journeySnapshotSchema.safeParse(snapshot).success, true);
|
||||
});
|
||||
|
||||
test("birth time journey fails a sensitive hospital record closed into rectification", () => {
|
||||
const assessment = birthTimeAssessmentSchema.parse({
|
||||
date: "1993-04-17",
|
||||
source: "hospital_record",
|
||||
reportedTime: "08:16",
|
||||
uncertaintyBeforeMinutes: 2,
|
||||
uncertaintyAfterMinutes: 2,
|
||||
location,
|
||||
});
|
||||
|
||||
const snapshot = assessBirthTime(assessment, { kind: "sensitive" });
|
||||
|
||||
assert.equal(snapshot.state, "rectifying");
|
||||
assert.equal(snapshot.route, "rectification");
|
||||
assert.equal(snapshot.canApply, false);
|
||||
assert.equal(snapshot.activeTime, null);
|
||||
assert.equal(snapshot.assistantIntent, "explain_sensitive_boundary");
|
||||
});
|
||||
|
||||
test("birth time journey fails a scanner outage closed into rectification", () => {
|
||||
const assessment = birthTimeAssessmentSchema.parse({
|
||||
date: "1993-04-17",
|
||||
source: "hospital_record",
|
||||
reportedTime: "08:16",
|
||||
uncertaintyBeforeMinutes: 2,
|
||||
uncertaintyAfterMinutes: 2,
|
||||
location,
|
||||
});
|
||||
|
||||
const snapshot = assessBirthTime(assessment, { kind: "unavailable" });
|
||||
|
||||
assert.equal(snapshot.route, "rectification");
|
||||
assert.equal(snapshot.canApply, false);
|
||||
assert.equal(snapshot.assistantIntent, "explain_assessment_unavailable");
|
||||
});
|
||||
|
||||
test("birth time journey routes family and approximate declarations to rectification", () => {
|
||||
const family = birthTimeAssessmentSchema.parse({
|
||||
date: "1993-04-17",
|
||||
source: "family_exact",
|
||||
reportedTime: "14:30",
|
||||
uncertaintyBeforeMinutes: 10,
|
||||
uncertaintyAfterMinutes: 10,
|
||||
location,
|
||||
});
|
||||
const approximate = birthTimeAssessmentSchema.parse({
|
||||
date: "1993-04-17",
|
||||
source: "approximate",
|
||||
reportedTime: "14:30",
|
||||
uncertaintyBeforeMinutes: 30,
|
||||
uncertaintyAfterMinutes: 30,
|
||||
location,
|
||||
});
|
||||
|
||||
assert.equal(assessBirthTime(family, { kind: "sensitive" }).assistantIntent, "start_light_rectification");
|
||||
assert.equal(assessBirthTime(approximate, { kind: "sensitive" }).assistantIntent, "start_standard_rectification");
|
||||
});
|
||||
|
||||
test("birth time journey accepts period-only and unknown declarations without inventing a clock time", () => {
|
||||
const period = birthTimeAssessmentSchema.parse({
|
||||
date: "1993-04-17",
|
||||
source: "period_only",
|
||||
period: "evening",
|
||||
location,
|
||||
});
|
||||
const unknown = birthTimeAssessmentSchema.parse({
|
||||
date: "1993-04-17",
|
||||
source: "unknown",
|
||||
clue: "家人只记得天黑以后",
|
||||
location,
|
||||
});
|
||||
|
||||
const periodSnapshot = assessBirthTime(period, { kind: "not_required" });
|
||||
const unknownSnapshot = assessBirthTime(unknown, { kind: "not_required" });
|
||||
|
||||
assert.equal(periodSnapshot.reportedRange.label, "18:00—22:59");
|
||||
assert.equal(periodSnapshot.activeTime, null);
|
||||
assert.equal(periodSnapshot.assistantIntent, "start_period_rectification");
|
||||
assert.equal(unknownSnapshot.reportedRange.label, "全天待确认");
|
||||
assert.equal(unknownSnapshot.assistantIntent, "collect_time_clues");
|
||||
});
|
||||
|
||||
test("birth time assessment rejects source-specific missing or invalid fields", () => {
|
||||
const missingTime = birthTimeAssessmentSchema.safeParse({
|
||||
date: "1993-04-17",
|
||||
source: "hospital_record",
|
||||
uncertaintyBeforeMinutes: 2,
|
||||
uncertaintyAfterMinutes: 2,
|
||||
location,
|
||||
});
|
||||
const invalidFamilyRange = birthTimeAssessmentSchema.safeParse({
|
||||
date: "1993-04-17",
|
||||
source: "family_exact",
|
||||
reportedTime: "14:30",
|
||||
uncertaintyBeforeMinutes: 30,
|
||||
uncertaintyAfterMinutes: 30,
|
||||
location,
|
||||
});
|
||||
|
||||
assert.equal(missingTime.success, false);
|
||||
assert.equal(invalidFamilyRange.success, false);
|
||||
});
|
||||
|
||||
test("rectification scoring can save a candidate but never apply an exact minute", () => {
|
||||
const assessment = birthTimeAssessmentSchema.parse({
|
||||
date: "1993-04-17",
|
||||
source: "approximate",
|
||||
reportedTime: "14:30",
|
||||
uncertaintyBeforeMinutes: 30,
|
||||
uncertaintyAfterMinutes: 30,
|
||||
location,
|
||||
});
|
||||
const initial = assessBirthTime(assessment, { kind: "sensitive" });
|
||||
|
||||
const scored = withRectificationScoring(initial, {
|
||||
answeredCount: 3,
|
||||
candidateClusterRankings: [{ cluster: "middle_candidate_cluster", score: 5 }],
|
||||
});
|
||||
|
||||
assert.equal(scored.state, "candidate");
|
||||
assert.equal(scored.canApply, false);
|
||||
assert.equal(scored.activeTime, null);
|
||||
assert.equal(scored.assistantIntent, "present_saved_candidate_range");
|
||||
});
|
||||
Reference in New Issue
Block a user