fix(rectification): treat a yes discriminator as covering that domain's collect
A choice-card yes/weak_yes already told us the domain happened, so skip the same-domain "which year" collect without writing the ledger. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
# 印度占星 Skill 更新日志
|
||||
|
||||
## 2026-09-05 — 区分卡答发生了之后不再问同一领域哪年
|
||||
|
||||
生时校正里,如果刚在选择卡上确认某类经历发生过,不会紧接着再问「还记得哪年…」同一领域的采集题。点选仍不记入证据账本。那年没有或记不清时,仍可以问别的年份。Skill 版本仍是 10.0.14。
|
||||
|
||||
## 2026-09-05 — 报告页可下载全量数据附录
|
||||
|
||||
主报告仍是五章叙事。ready 之后可以另下一份 Markdown 全量数据附录(三年年度、KP 月度、功能吉凶、校时敏感度等)。附录失败只显示暂不可用,不会把主报告打回失败,也不退款。Skill 版本未变。
|
||||
|
||||
@@ -8470,3 +8470,19 @@
|
||||
- 复发自:无
|
||||
- 修复版本:`52a4570c`
|
||||
|
||||
## BUG-549 | 区分卡答「发生了」后仍问同一领域哪年采集
|
||||
|
||||
- 状态:resolved
|
||||
- 首次发现:2026-09-05
|
||||
- 最近更新:2026-09-05
|
||||
- 影响面:`buildMethodFollowupPlan`、`datedCollectDomainBlocked`、`rectificationFollowupCatalog`
|
||||
- 用户现象:刚在事业区分卡上点选「发生了」,下一问又是「工作上呢,还记得哪年入职、换工作…」。
|
||||
- 触发条件:账本没有该领域带年份证据;区分卡答案只进推断层;本轮已无剩余区分卡,计划层按账本判断领域未覆盖。
|
||||
- 根因:点选答案不写证据账本(BUG-389–393 分层,本单不推翻)。计划层 `careerCovered` / `datedCollectDomainBlocked` 只看账本。BUG-547 之后区分卡问完才进采集链,刚答过的领域会被再问一次。
|
||||
- 修复:`yes` / `weak_yes` 的领域视为采集已覆盖(用 `eventProbes` 按 `semantic_key` / `probe_id` 回查 domain,回查不到则忽略)。不写账本,不改 `meetsAcceptanceEventQuality`,不改确认门。`no` / `unsure` 不算覆盖。
|
||||
- 验证:`frontend/tests/rectification-collect-direction-20260904.test.ts`:账本无事业证据、事业探针答 yes 后下一问不是事业采集;答 no 仍问。BUG-546/547 既有用例仍过。
|
||||
- 防复发:不得把点选答案写入证据账本来「修」重复采集。不得用 `semantic_key` 前缀硬拆领域。不得加「除了刚才那次以外」这类补丁文案。
|
||||
- 相关记录:BUG-389、BUG-546、BUG-547
|
||||
- 复发自:无
|
||||
- 修复版本:待发布
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# PROGRESS · 区分卡答「发生了」视为该领域采集已覆盖(2026-09-05)
|
||||
|
||||
工作树:`.worktrees/rectification-probe-answer-covers-domain-20260905`
|
||||
分支:`codex/rectification-probe-answer-covers-domain-20260905`
|
||||
基线:`origin/staging` @ `2dc61946`(任务书)。未改 `.gitea/workflows/**`、未动迁移、未升级依赖、未 bump Skill(仍 10.0.14)、未改 `page.tsx`。
|
||||
|
||||
| 任务 | 状态 | BUG |
|
||||
| --- | --- | --- |
|
||||
| 点选 A/B 覆盖该领域采集,不写账本、不动门 | 完成 | BUG-549 |
|
||||
|
||||
## 编号
|
||||
|
||||
开工时最大号 BUG-548。本单 **BUG-549**。未占用预留的 BUG-542。
|
||||
|
||||
## 产品取舍
|
||||
|
||||
任务书决策 2 允许否决「答 C/D 后仍可马上问同领域采集」。本单**保留原文**:C/D 不算覆盖。区分卡谈的是那一个年份窗口;采集问的是别的年份。隔一轮只是把同一问推迟,会把调度混进覆盖判定,也不减少信息差。未加「除了刚才那次以外」文案。
|
||||
|
||||
`decideFromDossier` 里只用来算 `methodCoverageAll` / `datedMethodCollectOpen` 的轻量 `buildMethodFollowupPlan` 仍只看账本,训练门与确认门输入不变。出题计划通过 `rectificationFollowupCatalog.answeredProbes` 透传。`adopt-narration.ts` 不调用 `buildMethodFollowupPlan`,无需改。
|
||||
|
||||
## 实现要点
|
||||
|
||||
- `domainsAnsweredYes`:用 `eventProbes`(外加同类型的 clarification / collection 探针)按 `semantic_key` / `probe_id` 回查 `domain`;回查不到忽略,不从前缀拆领域。
|
||||
- `relationshipCovered` / `careerCovered` / `familyCovered` 与 `datedCollectDomainBlocked` 叠加 `answeredYes`。
|
||||
- `classified_from: "evidence"` 不算覆盖。
|
||||
|
||||
## 测试
|
||||
|
||||
| 命令 | 结果 |
|
||||
| --- | --- |
|
||||
| collect-direction + choice-card | 52/52 |
|
||||
| `npx tsx --test tests/rectification-*.test.ts tests/agent-voice-copy-contract.test.ts` | 898 项;pass 898;fail 0;cancelled 0;skipped 0 |
|
||||
| `npx tsc --noEmit` | 0 错 |
|
||||
| 改动文件 eslint `--quiet` | 0 error |
|
||||
| `page.tsx` | 未改 |
|
||||
|
||||
未做浏览器真人走查。清单:`docs/testing/rectification-probe-answer-covers-domain-20260905.md`。旧会话在部署前仍会按旧逻辑再问一遍。
|
||||
@@ -54,7 +54,7 @@
|
||||
| — | `PROGRESS-rectification-adopt-card-anchor-20260905.md` | 采用卡钉在历史采集题下,最新旁白没有卡;单分钟交付旁白机器腔 | 已验收通过(浏览器走查欠) | `codex/rectification-quality-probe-dedupe-20260904`(BUG-544~545) |
|
||||
| — | `PROGRESS-rectification-family-collect-continue-20260905.md` | 家人答「没有」后直接给结果,未继续收能区分分钟的经历 | 已由 cd704a92 修正并验收通过 | `codex/rectification-quality-probe-dedupe-20260904`(BUG-546) |
|
||||
| `TASK-rectification-family-collect-continue-fix-20260905.md` | `PROGRESS-rectification-family-collect-continue-20260905.md` | `998406ce` 修复单:家人之后的 dated 补采集无条件抢在现成区分卡之前(choice-card A/B 卡用例回归),另两条顺序断言缺三栏说明 | 已验收通过(浏览器走查欠) | `cd704a92`(BUG-547) |
|
||||
| `TASK-rectification-probe-answer-covers-domain-20260905.md` | — | 区分卡答 A/B 后紧接着又问同领域"哪年…"采集题:点选答案只进推断层不写账本,计划层领域覆盖只看账本;改为 yes/weak_yes 视为该领域采集已覆盖(不写账本、不动门) | 待执行 | `codex/rectification-probe-answer-covers-domain-20260905`(BUG-549 起) |
|
||||
| `TASK-rectification-probe-answer-covers-domain-20260905.md` | `PROGRESS-rectification-probe-answer-covers-domain-20260905.md` | 区分卡答 A/B 后紧接着又问同领域"哪年…"采集题:点选答案只进推断层不写账本,计划层领域覆盖只看账本;改为 yes/weak_yes 视为该领域采集已覆盖(不写账本、不动门) | 待验收 | `codex/rectification-probe-answer-covers-domain-20260905`(BUG-549) |
|
||||
| `TASK-api-not-configured-mislabel-20260904.md` | — | 16 处路由把数据库瞬断(部署切换窗口)兜底翻译成 503「服务尚未配置」;改为仅配置错误用该文案,其余 `service_unavailable`,收敛为共享 helper | 待执行 | `codex/api-not-configured-mislabel-20260904`(BUG-542 起) |
|
||||
| `TASK-rectification-ux-20260902.md` | `PROGRESS-rectification-ux-20260903.md` | 会话面空白假死与交互摩擦 | 已验收 | `d159f08e`(09-03 在新基线重做后合入,BUG-505~509) |
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# Staging 人肉复核 · 区分卡答发生了之后不再问同一领域哪年(2026-09-05)
|
||||
|
||||
给产品负责人。不要把真实案例里的年份、事件或候选分钟写进任何记录。
|
||||
|
||||
对应 BUG-549。测之前先做第 0 条。本单部署前,旧会话仍可能在区分卡答「发生了」后马上问同一领域「哪年…」。
|
||||
|
||||
## 0. 确认测的是新版本
|
||||
|
||||
浏览器打开 `https://staging.jyotisha.chat/api/health`,看 `deployment.gitCommit` 前 8 位是否等于本单合入 staging 后的提交。不一致 = 先别测。
|
||||
|
||||
## 1. 事业区分卡答「发生了」后不要再问哪年入职(P0)
|
||||
|
||||
1. 新建生时校正。
|
||||
2. 先补齐能把对话推到区分卡的带年份经历(不要口述补一条事业入职)。
|
||||
3. 出现事业区分卡:「某年某月前后,有没有入职、换工作或职责加重?」点 A 或 B(发生了 / 比较像发生了)。
|
||||
4. 把其余区分卡答完,直到下一问变成口述采集。
|
||||
|
||||
- ✅ 预期:下一句**不是**「工作上呢,还记得哪年入职、换工作,或职责一下子变重吗?」可以是别的还没问过的领域(钱、搬家、身体、家人、学业)或职业口述。
|
||||
- ❌ 失败:紧接着又问「工作上呢,还记得哪年入职…」。
|
||||
|
||||
## 2. 事业区分卡答「没有」后仍可问哪年(P0)
|
||||
|
||||
同一路径,事业区分卡点 C(那年没发生)或 D(记不清):
|
||||
|
||||
- ✅ 预期:后面仍可以出现事业采集「工作上呢,还记得哪年入职…」。那年没有,别的年份仍可能有。
|
||||
- ❌ 失败:因为点了 C/D,事业采集整条线被关掉。
|
||||
|
||||
## 3. 不要出现补丁口吻(P1)
|
||||
|
||||
- ✅ 预期:采集题仍是原来的「工作上呢,还记得哪年…」,没有「除了刚才那次以外」这类句子。
|
||||
- ❌ 失败:为了回避重复而改写了采集原文。
|
||||
@@ -1048,9 +1048,15 @@ async function persistExhaustionCollect(input: {
|
||||
hostNarration: string;
|
||||
focus?: ConversationFocus | null;
|
||||
}> {
|
||||
const catalog = rectificationFollowupCatalog(
|
||||
input.dossier.latestResult ?? null,
|
||||
input.dossier.evidence,
|
||||
);
|
||||
const followup = exhaustionSpokenCollectFollowup({
|
||||
evidence: input.dossier.evidence,
|
||||
declinedTopics: input.dossier.conversationSummary.declinedSkippedTopics,
|
||||
answeredProbes: catalog.answeredProbes,
|
||||
eventProbes: catalog.eventProbes,
|
||||
});
|
||||
const range = nonConvergingRangeNarration({
|
||||
...input.decision,
|
||||
|
||||
@@ -282,6 +282,7 @@ export function rectificationFollowupCatalog(
|
||||
contrastPacket: contrastPacketFromLatestResult(latest ?? null, evidence),
|
||||
topCandidateTimes,
|
||||
askedProbeKeys: askedKeys,
|
||||
answeredProbes: inference?.answered_probes ?? [],
|
||||
eventProbes: refinement.discriminating_event_probes,
|
||||
eventClarificationProbes: refinement.event_clarification_probes,
|
||||
evidenceCollectionProbes: refinement.evidence_collection_probes,
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
* Known-event quality probes (exam went badly for a year already
|
||||
* in the ledger) are not reverse-inference cards. Dasha existence
|
||||
* probes skip a year already in the ledger, not the whole domain.
|
||||
* A yes/weak_yes discriminator answer covers that domain's spoken
|
||||
* collect without writing the ledger. no/unsure does not.
|
||||
* Contrast-packet ranking must use the same year rule: a dated
|
||||
* unstructured probe stays eligible when the domain already has a
|
||||
* different year. Information gain is recomputed on the current
|
||||
@@ -223,6 +225,47 @@ function hasConfirmedDomain(evidence: readonly MethodFollowupEvidence[], domain:
|
||||
return evidence.some((item) => item.status === "confirmed" && item.domain === domain);
|
||||
}
|
||||
|
||||
export type AnsweredProbeCoverageRow = Readonly<{
|
||||
semantic_key: string;
|
||||
probe_id?: string;
|
||||
answer_class: string;
|
||||
classified_from?: string;
|
||||
}>;
|
||||
|
||||
function domainForAnsweredProbe(
|
||||
answer: AnsweredProbeCoverageRow,
|
||||
eventProbes: readonly DiscriminatingEventProbe[],
|
||||
): string | null {
|
||||
const keys = new Set(
|
||||
[answer.semantic_key, answer.probe_id].filter((key): key is string => Boolean(key?.trim())),
|
||||
);
|
||||
if (keys.size === 0) return null;
|
||||
for (const probe of eventProbes) {
|
||||
const semantic = probe.semantic_key?.trim() ?? "";
|
||||
if (!semantic || !keys.has(semantic)) continue;
|
||||
const domain = probe.domain?.trim();
|
||||
if (domain) return domain;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Domains where a discriminator was answered yes/weak_yes. Lookup is by probe identity, not key prefix. */
|
||||
export function domainsAnsweredYes(
|
||||
answeredProbes: readonly AnsweredProbeCoverageRow[] | undefined,
|
||||
eventProbes: readonly DiscriminatingEventProbe[] | undefined,
|
||||
): Set<string> {
|
||||
const domains = new Set<string>();
|
||||
if (!answeredProbes?.length) return domains;
|
||||
const catalog = eventProbes ?? [];
|
||||
for (const answer of answeredProbes) {
|
||||
if (answer.answer_class !== "yes" && answer.answer_class !== "weak_yes") continue;
|
||||
if (answer.classified_from && answer.classified_from !== "choice") continue;
|
||||
const domain = domainForAnsweredProbe(answer, catalog);
|
||||
if (domain) domains.add(domain);
|
||||
}
|
||||
return domains;
|
||||
}
|
||||
|
||||
function evidenceYear(item: MethodFollowupEvidence): number | null {
|
||||
const raw = item.occurredFrom || item.occurredTo;
|
||||
if (!raw || raw.length < 4 || !/^\d{4}/.test(raw)) return null;
|
||||
@@ -1070,19 +1113,26 @@ function datedCollectDomainBlocked(
|
||||
domain: (typeof DATED_COLLECT_ORDER)[number],
|
||||
evidence: readonly MethodFollowupEvidence[],
|
||||
declined: ReadonlySet<string>,
|
||||
answeredYes: ReadonlySet<string> = new Set(),
|
||||
): boolean {
|
||||
if (domain === "health_pressure") {
|
||||
return declinedHealth(declined) || hasConfirmedHealth(evidence);
|
||||
return declinedHealth(declined)
|
||||
|| hasConfirmedHealth(evidence)
|
||||
|| answeredYes.has("health_pressure")
|
||||
|| answeredYes.has("health");
|
||||
}
|
||||
return declined.has(domain) || hasConfirmedDomain(evidence, domain);
|
||||
return declined.has(domain)
|
||||
|| hasConfirmedDomain(evidence, domain)
|
||||
|| answeredYes.has(domain);
|
||||
}
|
||||
|
||||
export function nextDatedCollectFollowup(
|
||||
evidence: readonly MethodFollowupEvidence[],
|
||||
declined: ReadonlySet<string>,
|
||||
answeredYes: ReadonlySet<string> = new Set(),
|
||||
): MethodFollowup | null {
|
||||
for (const domain of DATED_COLLECT_ORDER) {
|
||||
if (datedCollectDomainBlocked(domain, evidence, declined)) continue;
|
||||
if (datedCollectDomainBlocked(domain, evidence, declined, answeredYes)) continue;
|
||||
const next = datedCollectFollowup(domain, evidence);
|
||||
if (next) return next;
|
||||
}
|
||||
@@ -1125,9 +1175,12 @@ function otherCollectFollowup(evidence: readonly MethodFollowupEvidence[]): Meth
|
||||
export function exhaustionSpokenCollectFollowup(input: {
|
||||
evidence: readonly MethodFollowupEvidence[];
|
||||
declinedTopics?: readonly Readonly<Record<string, unknown>>[];
|
||||
answeredProbes?: readonly AnsweredProbeCoverageRow[];
|
||||
eventProbes?: readonly DiscriminatingEventProbe[];
|
||||
}): MethodFollowup | null {
|
||||
const declined = declinedDomains(input.declinedTopics ?? []);
|
||||
const dated = nextDatedCollectFollowup(input.evidence, declined);
|
||||
const answeredYes = domainsAnsweredYes(input.answeredProbes, input.eventProbes);
|
||||
const dated = nextDatedCollectFollowup(input.evidence, declined, answeredYes);
|
||||
if (dated) return dated;
|
||||
if (
|
||||
!declined.has("occupation")
|
||||
@@ -1506,6 +1559,7 @@ export function buildMethodFollowupPlan(input: {
|
||||
eventClarificationProbes?: readonly DiscriminatingEventProbe[];
|
||||
evidenceCollectionProbes?: readonly DiscriminatingEventProbe[];
|
||||
askedProbeKeys?: readonly string[];
|
||||
answeredProbes?: readonly AnsweredProbeCoverageRow[];
|
||||
closedCollectFocuses?: readonly Readonly<Record<string, unknown>>[];
|
||||
birthDate?: string | null;
|
||||
accepted?: boolean;
|
||||
@@ -1559,10 +1613,18 @@ export function buildMethodFollowupPlan(input: {
|
||||
const ask = (why: string, varga: string, extra = "") =>
|
||||
agentHint(why, varga, extra, input.evidence);
|
||||
const declined = declinedDomains(input.declinedTopics ?? []);
|
||||
const answeredYes = domainsAnsweredYes(input.answeredProbes, [
|
||||
...(input.eventProbes ?? []),
|
||||
...(input.eventClarificationProbes ?? []),
|
||||
...(input.evidenceCollectionProbes ?? []),
|
||||
]);
|
||||
const dashaCovered = input.evidence.some(isConfirmedDated);
|
||||
const relationshipCovered = hasConfirmedDomain(input.evidence, "relationship");
|
||||
const careerCovered = hasConfirmedDomain(input.evidence, "career");
|
||||
const familyCovered = hasConfirmedDomain(input.evidence, "family");
|
||||
const relationshipCovered = hasConfirmedDomain(input.evidence, "relationship")
|
||||
|| answeredYes.has("relationship");
|
||||
const careerCovered = hasConfirmedDomain(input.evidence, "career")
|
||||
|| answeredYes.has("career");
|
||||
const familyCovered = hasConfirmedDomain(input.evidence, "family")
|
||||
|| answeredYes.has("family");
|
||||
const financeCovered = hasConfirmedDomain(input.evidence, "finance");
|
||||
const healthCovered = hasConfirmedHealth(input.evidence);
|
||||
const occupationCovered = hasConfirmedDomain(input.evidence, "occupation")
|
||||
@@ -2120,7 +2182,7 @@ export function buildMethodFollowupPlan(input: {
|
||||
&& precisionCard?.choice_frame
|
||||
) {
|
||||
next = precisionCard;
|
||||
} else if ((datedCollect = nextDatedCollectFollowup(input.evidence, declined))) {
|
||||
} else if ((datedCollect = nextDatedCollectFollowup(input.evidence, declined, answeredYes))) {
|
||||
next = makeFollowup(datedCollect);
|
||||
} else if (!occupationCovered) {
|
||||
if (meetsAcceptanceEventQuality(input.evidence)) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
spokenFollowupForUser,
|
||||
type MethodFollowupEvidence,
|
||||
} from "../src/lib/rectification-agentic/v9/method-followup.ts";
|
||||
import type { DiscriminatingEventProbe } from "../src/lib/rectification-agentic/v9/refinement-packet.ts";
|
||||
import { persistNextInterviewAfterChoice } from "../src/lib/rectification-agentic/v9/answer-choice.ts";
|
||||
import { projectTurnDecision } from "../src/lib/rectification-agentic/v9/turn-decision.ts";
|
||||
import { parseV9CaseDossier } from "../src/lib/rectification-agentic/v9/tool-service.ts";
|
||||
@@ -472,3 +473,99 @@ test("turn decision and GET interview expose collection_progress 2/3/1 or null",
|
||||
);
|
||||
assert.match(tools, /采集题必须写出服务端给你的领域/);
|
||||
});
|
||||
|
||||
const CAREER_EXISTENCE_PROBE: DiscriminatingEventProbe = {
|
||||
year: 2011,
|
||||
year_label: "2011 年前后",
|
||||
domain: "career",
|
||||
event_family: "入职、换工作或职责加重",
|
||||
source: "dasha_activation",
|
||||
tracks: ["vimshottari", "narayana"],
|
||||
tracks_agree: true,
|
||||
unique_minute_claim: false,
|
||||
user_meaning: "年份锁定 2011 年前后。事件家族:入职、换工作或职责加重。",
|
||||
role: "distinguish",
|
||||
information_gain: 0.4,
|
||||
candidate_ids: ["05:00", "05:20"],
|
||||
expected_outcomes: [
|
||||
{ answer_class: "yes", supports: ["05:00"], conflicts: ["05:20"] },
|
||||
{ answer_class: "no", supports: ["05:20"], conflicts: ["05:00"] },
|
||||
],
|
||||
semantic_key: "career.2011",
|
||||
candidate_split_hash: "career.2011:05:00|05:20",
|
||||
choice_kind: "existence",
|
||||
};
|
||||
|
||||
const RELATIONSHIP_AND_FAMILY = [
|
||||
dated("relationship", "2014", { eventKind: "relationship_start" }),
|
||||
dated("family", "2016", { eventKind: "family_event" }),
|
||||
] as const;
|
||||
|
||||
function careerAnswerPlan(answerClass: string, extra: Partial<Parameters<typeof buildMethodFollowupPlan>[0]> = {}) {
|
||||
return buildMethodFollowupPlan({
|
||||
evidence: RELATIONSHIP_AND_FAMILY,
|
||||
eventProbes: [CAREER_EXISTENCE_PROBE],
|
||||
askedProbeKeys: ["career.2011", "probe:career.2011"],
|
||||
answeredProbes: [{
|
||||
semantic_key: "career.2011",
|
||||
probe_id: "probe:career.2011",
|
||||
answer_class: answerClass,
|
||||
classified_from: "choice",
|
||||
}],
|
||||
holdoutValidation: "not_started",
|
||||
...extra,
|
||||
});
|
||||
}
|
||||
|
||||
test("career discriminator yes covers career collect without ledger career evidence", () => {
|
||||
const unanswered = buildMethodFollowupPlan({
|
||||
evidence: RELATIONSHIP_AND_FAMILY,
|
||||
eventProbes: [CAREER_EXISTENCE_PROBE],
|
||||
askedProbeKeys: ["career.2011", "probe:career.2011"],
|
||||
holdoutValidation: "not_started",
|
||||
});
|
||||
assert.equal(unanswered.next_followup?.domain, "career");
|
||||
assert.equal(unanswered.next_followup?.intent, "collect_method_evidence");
|
||||
assert.equal(spokenFollowupForUser(unanswered.next_followup), USER_COLLECT_QUESTION.career);
|
||||
|
||||
const yes = careerAnswerPlan("yes");
|
||||
assert.notEqual(yes.next_followup?.domain, "career");
|
||||
assert.equal(yes.next_followup?.domain, "education");
|
||||
assert.equal(yes.next_followup?.intent, "collect_method_evidence");
|
||||
assert.equal(spokenFollowupForUser(yes.next_followup), USER_COLLECT_QUESTION.education);
|
||||
assert.equal(
|
||||
yes.methods.find((item) => item.method_id === "d10_career")?.status,
|
||||
"covered",
|
||||
);
|
||||
|
||||
const weakYes = careerAnswerPlan("weak_yes");
|
||||
assert.notEqual(weakYes.next_followup?.domain, "career");
|
||||
assert.equal(weakYes.next_followup?.domain, "education");
|
||||
|
||||
const no = careerAnswerPlan("no");
|
||||
assert.equal(no.next_followup?.domain, "career");
|
||||
assert.equal(spokenFollowupForUser(no.next_followup), USER_COLLECT_QUESTION.career);
|
||||
|
||||
const unsure = careerAnswerPlan("unsure");
|
||||
assert.equal(unsure.next_followup?.domain, "career");
|
||||
assert.equal(spokenFollowupForUser(unsure.next_followup), USER_COLLECT_QUESTION.career);
|
||||
});
|
||||
|
||||
test("career discriminator yes does not invent coverage from a semantic_key prefix", () => {
|
||||
const plan = careerAnswerPlan("yes", { eventProbes: [] });
|
||||
assert.equal(plan.next_followup?.domain, "career");
|
||||
assert.equal(spokenFollowupForUser(plan.next_followup), USER_COLLECT_QUESTION.career);
|
||||
});
|
||||
|
||||
test("ledger-classified career probe answers do not cover career collect", () => {
|
||||
const plan = careerAnswerPlan("yes", {
|
||||
answeredProbes: [{
|
||||
semantic_key: "career.2011",
|
||||
probe_id: "probe:career.2011",
|
||||
answer_class: "yes",
|
||||
classified_from: "evidence",
|
||||
}],
|
||||
});
|
||||
assert.equal(plan.next_followup?.domain, "career");
|
||||
assert.equal(spokenFollowupForUser(plan.next_followup), USER_COLLECT_QUESTION.career);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user