fix(web): stop adopting tied rectification candidates after method coverage
Coverage complete only unlocks discrimination. A 34/33/33 window plus an occupation note must ask a D9/D10 contrast probe instead of offering a stale winner card. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -56,6 +56,9 @@ export type ConfirmationGate = Readonly<{
|
||||
|
||||
export type SessionOutcomeKind =
|
||||
| "collect_evidence"
|
||||
| "discriminate_candidates"
|
||||
| "validate_holdout"
|
||||
| "provisional_range"
|
||||
| "adopt_representative"
|
||||
| "awaiting_confirmation";
|
||||
|
||||
@@ -77,6 +80,24 @@ export function sessionOutcomeView(kind: SessionOutcomeKind): SessionOutcome {
|
||||
user_meaning: `这次校正的收口是采用代表性时间作当前排盘。${UNIQUE_MINUTE_CLOSED_COPY}。`,
|
||||
};
|
||||
}
|
||||
if (kind === "discriminate_candidates") {
|
||||
return {
|
||||
kind,
|
||||
user_meaning: "方法资料已齐,但候选还没拉开。下一步按候选盘面差异反问前事,不要采用时间卡。",
|
||||
};
|
||||
}
|
||||
if (kind === "validate_holdout") {
|
||||
return {
|
||||
kind,
|
||||
user_meaning: "领先候选还要用尚未计分的前事做独立核对,不能直接采用。",
|
||||
};
|
||||
}
|
||||
if (kind === "provisional_range") {
|
||||
return {
|
||||
kind,
|
||||
user_meaning: "当前几个候选基本并列。给出的是可信区间的代表点,不是已经分出的赢家。",
|
||||
};
|
||||
}
|
||||
return {
|
||||
kind: "collect_evidence",
|
||||
user_meaning: "还需要能评分的带日期事件,才能给出可采用的代表性时间。",
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
* After the first dated event, remaining dasha conflict probes
|
||||
* (year/activation differences) are asked before more method rotation
|
||||
* and they block offering time cards so the window can be filtered.
|
||||
* Once blocking methods are covered and propose_allowed, offer a
|
||||
* representative time even if probes or horary remain.
|
||||
* Once blocking methods are covered, move into candidate discrimination.
|
||||
* Coverage complete never means adopt. Horary does not block cards.
|
||||
* A/B/C/D choice frames attach only when candidates already diverge
|
||||
* (event probes, precision stage, varga observation, nakshatra, or holdout).
|
||||
*/
|
||||
@@ -40,7 +40,17 @@ import {
|
||||
type RectificationChoiceCard,
|
||||
type RectificationChoiceFrame,
|
||||
} from "./choice-card.ts";
|
||||
import { sessionOutcomeFromGate, type SessionOutcomeKind } from "./confirmation-gate.ts";
|
||||
import {
|
||||
decideNextAction,
|
||||
sessionKindFromNextAction,
|
||||
type HoldoutValidationStatus,
|
||||
} from "../core/decide-next-action.ts";
|
||||
import {
|
||||
selectDiscriminatorProbe,
|
||||
type CandidateContrastPacket,
|
||||
type CandidateDiscriminatorProbe,
|
||||
} from "../core/candidate-contrast-packet.ts";
|
||||
import type { SessionOutcomeKind } from "./confirmation-gate.ts";
|
||||
import type {
|
||||
DiscriminatingEventProbe,
|
||||
NakshatraBoundary,
|
||||
@@ -308,6 +318,9 @@ export type NextUserActionId =
|
||||
| "score_now"
|
||||
| "record_stated_events"
|
||||
| "ask_method_followup"
|
||||
| "ask_candidate_discriminator"
|
||||
| "ask_holdout_validation"
|
||||
| "offer_provisional_range"
|
||||
| "explain_current_window"
|
||||
| "verify_adopted_time"
|
||||
| "start_consultation";
|
||||
@@ -316,7 +329,7 @@ export type NextUserAction = Readonly<{
|
||||
id: NextUserActionId;
|
||||
user_meaning: string;
|
||||
on_user_stop: {
|
||||
id: Exclude<NextUserActionId, "ask_method_followup">;
|
||||
id: Exclude<NextUserActionId, "ask_method_followup" | "ask_candidate_discriminator" | "ask_holdout_validation">;
|
||||
user_meaning: string;
|
||||
};
|
||||
}>;
|
||||
@@ -346,19 +359,53 @@ export function latestUserStoppedCollecting(
|
||||
export function isOfferBlockingFollowup(
|
||||
followup: MethodFollowup | null,
|
||||
methods?: readonly MethodCoverage[],
|
||||
options?: { separated?: boolean },
|
||||
): boolean {
|
||||
if (methods?.some((item) => BLOCKING_COVERAGE_IDS.has(item.method_id) && item.status === "uncovered")) {
|
||||
return true;
|
||||
}
|
||||
if (!followup) return false;
|
||||
const separated = options?.separated === true;
|
||||
if (followup.source === "event_probe") {
|
||||
if (methods == null) return true;
|
||||
return (followup.information_gain ?? 0) >= 0.08;
|
||||
if (separated) return (followup.information_gain ?? 0) >= 0.08;
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
followup.source === "varga_observation"
|
||||
|| followup.source === "precision_stage"
|
||||
|| followup.intent === "distinguish_candidates"
|
||||
) {
|
||||
return !separated;
|
||||
}
|
||||
if (followup.source !== "method_coverage") return false;
|
||||
return BLOCKING_COVERAGE_IDS.has(followup.method_id as MethodFollowupId);
|
||||
}
|
||||
|
||||
function discriminatorFromFollowup(followup: MethodFollowup | null): CandidateDiscriminatorProbe | null {
|
||||
if (!followup) return null;
|
||||
const discriminator = followup.source === "event_probe"
|
||||
|| followup.source === "varga_observation"
|
||||
|| followup.source === "precision_stage"
|
||||
|| followup.intent === "distinguish_candidates";
|
||||
if (!discriminator) return null;
|
||||
const split = followup.candidate_split_hash ?? followup.semantic_key ?? followup.method_id;
|
||||
return {
|
||||
probeId: split,
|
||||
candidateSetVersion: split,
|
||||
question: followup.user_prompt_hint,
|
||||
expectedOutcomes: [
|
||||
{ outcomeId: "yes", supportsCandidateIds: ["left"], conflictsCandidateIds: ["right"] },
|
||||
{ outcomeId: "no", supportsCandidateIds: ["right"], conflictsCandidateIds: ["left"] },
|
||||
],
|
||||
candidateSplitHash: split,
|
||||
informationGain: followup.information_gain ?? 0,
|
||||
sourceFeatures: [{ technique: followup.source, calculationResultId: null }],
|
||||
domain: followup.domain,
|
||||
year: followup.probe_year ?? null,
|
||||
semanticKey: followup.semantic_key ?? followup.method_id,
|
||||
};
|
||||
}
|
||||
|
||||
export function conversationalSessionOutcome(input: {
|
||||
selectionAllowed: boolean;
|
||||
proposeAllowed: boolean;
|
||||
@@ -366,14 +413,27 @@ export function conversationalSessionOutcome(input: {
|
||||
nextFollowup: MethodFollowup | null;
|
||||
methods?: readonly MethodCoverage[];
|
||||
userStopped?: boolean;
|
||||
candidateScores?: readonly Readonly<{ time: string; score: number }>[];
|
||||
discriminatorProbe?: CandidateDiscriminatorProbe | null;
|
||||
holdoutValidation?: HoldoutValidationStatus;
|
||||
snapshotCurrent?: boolean;
|
||||
}): SessionOutcomeKind {
|
||||
return sessionOutcomeFromGate({
|
||||
selectionAllowed: input.selectionAllowed,
|
||||
if (input.confirmationAllowed) return "awaiting_confirmation";
|
||||
const coverageOpen = Boolean(
|
||||
input.methods?.some((item) => BLOCKING_COVERAGE_IDS.has(item.method_id) && item.status === "uncovered"),
|
||||
);
|
||||
const decided = decideNextAction({
|
||||
methodCoverageAll: !coverageOpen,
|
||||
proposeAllowed: input.proposeAllowed,
|
||||
confirmationAllowed: input.confirmationAllowed,
|
||||
interviewOpen: isOfferBlockingFollowup(input.nextFollowup, input.methods),
|
||||
confirmationAllowed: false,
|
||||
userStopped: input.userStopped,
|
||||
}).kind;
|
||||
selectionAllowed: input.selectionAllowed,
|
||||
snapshotCurrent: input.snapshotCurrent,
|
||||
candidateScores: input.candidateScores ?? [],
|
||||
discriminatorProbe: input.discriminatorProbe ?? discriminatorFromFollowup(input.nextFollowup),
|
||||
holdoutValidation: input.holdoutValidation,
|
||||
});
|
||||
return sessionKindFromNextAction(decided.type);
|
||||
}
|
||||
|
||||
export function buildNextUserAction(input: {
|
||||
@@ -407,14 +467,39 @@ export function buildNextUserAction(input: {
|
||||
"adopt_representative",
|
||||
"本轮已有代表性候选时间。说明本会话以代表性时间收口,不确认唯一分钟,请用户采用下方时间卡片;采用后才用该时间看盘。不要只说记下了以后再说。",
|
||||
);
|
||||
const provisional = action(
|
||||
"offer_provisional_range",
|
||||
"当前几个候选基本并列。说明这是可信区间,代表分钟只是计算用的代表点,不要称某分钟为当前推荐;不要继续假装已经收敛。",
|
||||
);
|
||||
if (input.sessionOutcome === "awaiting_confirmation") {
|
||||
return { id: adopt.id, user_meaning: adopt.user_meaning, on_user_stop: adopt };
|
||||
}
|
||||
if (
|
||||
input.sessionOutcome === "adopt_representative"
|
||||
) {
|
||||
if (input.sessionOutcome === "adopt_representative") {
|
||||
return { id: adopt.id, user_meaning: adopt.user_meaning, on_user_stop: adopt };
|
||||
}
|
||||
if (input.sessionOutcome === "provisional_range") {
|
||||
return { id: provisional.id, user_meaning: provisional.user_meaning, on_user_stop: provisional };
|
||||
}
|
||||
if (input.sessionOutcome === "validate_holdout" && input.nextFollowup) {
|
||||
return {
|
||||
id: "ask_holdout_validation",
|
||||
user_meaning: input.nextFollowup.user_prompt_hint,
|
||||
on_user_stop: input.selectionAllowed ? provisional : action(
|
||||
"explain_current_window",
|
||||
`${working}。独立核对还没做完。用户说没有更多时,说明这是并列区间,不要采用一张赢家卡。`,
|
||||
),
|
||||
};
|
||||
}
|
||||
if (input.sessionOutcome === "discriminate_candidates" && input.nextFollowup) {
|
||||
return {
|
||||
id: "ask_candidate_discriminator",
|
||||
user_meaning: input.nextFollowup.user_prompt_hint,
|
||||
on_user_stop: input.selectionAllowed ? provisional : action(
|
||||
"explain_current_window",
|
||||
`${working}。候选还没拉开。用户说没有更多时,给出并列可信区间,不要宣布某分钟胜出。`,
|
||||
),
|
||||
};
|
||||
}
|
||||
const scoreNow = action(
|
||||
"score_now",
|
||||
"已有可评分事件但还没有候选结果。本轮必须比较候选,不要只口头确认事件。",
|
||||
@@ -456,6 +541,9 @@ export function buildMethodFollowupPlan(input: {
|
||||
askedProbeKeys?: readonly string[];
|
||||
birthDate?: string | null;
|
||||
accepted?: boolean;
|
||||
candidatesSeparated?: boolean;
|
||||
contrastPacket?: CandidateContrastPacket | null;
|
||||
holdoutValidation?: HoldoutValidationStatus;
|
||||
}): MethodFollowupPlan {
|
||||
const makeFollowup = (
|
||||
item: Omit<MethodFollowup, "must_not_label" | "choice_frame">,
|
||||
@@ -506,6 +594,8 @@ export function buildMethodFollowupPlan(input: {
|
||||
];
|
||||
|
||||
const sessionOutcome = input.sessionOutcome ?? "collect_evidence";
|
||||
const candidatesSeparated = input.candidatesSeparated === true;
|
||||
const contrastProbe = selectDiscriminatorProbe(input.contrastPacket ?? null);
|
||||
const focus = input.activeFocus ?? null;
|
||||
const keepAcceptedFocus = Boolean(
|
||||
focus && (focus.intent === "reverse_verify" || focus.intent === "out_of_sample_check"),
|
||||
@@ -525,7 +615,7 @@ export function buildMethodFollowupPlan(input: {
|
||||
if (
|
||||
focus
|
||||
&& !staleCollectFocus
|
||||
&& (sessionOutcome !== "adopt_representative" || keepAcceptedFocus)
|
||||
&& (sessionOutcome !== "adopt_representative" && sessionOutcome !== "provisional_range" || keepAcceptedFocus)
|
||||
&& (!input.accepted || keepAcceptedFocus)
|
||||
) {
|
||||
const existingChoice = parseAgentChoiceCopy(focus.expectedAnswerSchema ?? null);
|
||||
@@ -603,7 +693,7 @@ export function buildMethodFollowupPlan(input: {
|
||||
),
|
||||
source: "method_coverage",
|
||||
});
|
||||
} else if (conflictProbe && (!coverageComplete || (conflictProbe.information_gain ?? 0) >= 0.08)) {
|
||||
} else if (conflictProbe && (!coverageComplete || !candidatesSeparated || (conflictProbe.information_gain ?? 0) >= 0.08)) {
|
||||
next = makeFollowup({
|
||||
method_id: PROBE_METHOD_ID[conflictProbe.domain],
|
||||
intent: "distinguish_candidates",
|
||||
@@ -676,20 +766,25 @@ export function buildMethodFollowupPlan(input: {
|
||||
),
|
||||
source: "method_coverage",
|
||||
});
|
||||
} else if (horaryStatus === "uncovered") {
|
||||
} else if (contrastProbe && !candidatesSeparated) {
|
||||
const domain = contrastProbe.domain === "relationship" ? "relationship" : "career";
|
||||
next = makeFollowup({
|
||||
method_id: "horary",
|
||||
intent: "collect_method_evidence",
|
||||
ask_theme: "horary",
|
||||
domain: "horary",
|
||||
kind_hint: "horary_query",
|
||||
user_prompt_hint: collectHint(
|
||||
"有没有第一次认真问起这件事的时间?",
|
||||
"占问观察盘",
|
||||
"有的话可以按那个时间观察;没有也不挡给出时间卡。状态是 observation_only。",
|
||||
method_id: domain === "relationship" ? "d9_relationship" : "d10_career",
|
||||
intent: "distinguish_candidates",
|
||||
ask_theme: domain === "relationship" ? "relationship_style" : "career_style",
|
||||
domain,
|
||||
kind_hint: domain === "relationship" ? "relationship_change" : "career_change",
|
||||
user_prompt_hint: agentHint(
|
||||
contrastProbe.question,
|
||||
domain === "relationship" ? "D9" : "D10",
|
||||
"按候选盘面差异核对前事,不要问两套盘哪个更像。",
|
||||
),
|
||||
source: "method_coverage",
|
||||
});
|
||||
source: "event_probe",
|
||||
information_gain: contrastProbe.informationGain,
|
||||
semantic_key: contrastProbe.semanticKey,
|
||||
candidate_split_hash: contrastProbe.candidateSplitHash,
|
||||
probe_year: contrastProbe.year ?? undefined,
|
||||
}, true, true);
|
||||
} else if (stage === "lagna_frame") {
|
||||
next = makeFollowup({
|
||||
method_id: "dasha_events",
|
||||
@@ -870,10 +965,35 @@ export function buildMethodFollowupPlan(input: {
|
||||
?? "升点靠近两段日常节奏的交界。哪一组更像你近年的处事方式?这只用来偏置时间窗,不能确认唯一分钟。",
|
||||
source: "nakshatra_boundary",
|
||||
});
|
||||
} else if (input.holdoutValidation === "not_started" && (input.oosBlindPrompts?.length ?? 0) > 0) {
|
||||
const prompt = input.oosBlindPrompts![0]!;
|
||||
next = makeFollowup({
|
||||
method_id: "oos_blind",
|
||||
intent: "out_of_sample_check",
|
||||
ask_theme: "oos_blind",
|
||||
domain: prompt.domain,
|
||||
kind_hint: null,
|
||||
user_prompt_hint: prompt.user_meaning,
|
||||
source: "oos_blind",
|
||||
}, false, true);
|
||||
} else if (horaryStatus === "uncovered") {
|
||||
next = makeFollowup({
|
||||
method_id: "horary",
|
||||
intent: "collect_method_evidence",
|
||||
ask_theme: "horary",
|
||||
domain: "horary",
|
||||
kind_hint: "horary_query",
|
||||
user_prompt_hint: collectHint(
|
||||
"有没有第一次认真问起这件事的时间?",
|
||||
"占问观察盘",
|
||||
"有的话可以按那个时间观察;没有也不挡给出时间卡。状态是 observation_only。",
|
||||
),
|
||||
source: "method_coverage",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const deferAdoption = sessionOutcome === "adopt_representative";
|
||||
const deferAdoption = sessionOutcome === "adopt_representative" || sessionOutcome === "provisional_range";
|
||||
return {
|
||||
methods,
|
||||
next_followup: deferAdoption ? null : next,
|
||||
@@ -890,6 +1010,7 @@ export function projectRectificationChoiceCard(
|
||||
selectionAllowed?: boolean;
|
||||
proposeAllowed?: boolean;
|
||||
userStopped?: boolean;
|
||||
candidateScores?: readonly Readonly<{ time: string; score: number }>[];
|
||||
},
|
||||
): RectificationChoiceCard | null {
|
||||
const plan = buildMethodFollowupPlan(input);
|
||||
@@ -900,10 +1021,13 @@ export function projectRectificationChoiceCard(
|
||||
nextFollowup: plan.next_followup,
|
||||
methods: plan.methods,
|
||||
userStopped: input.userStopped,
|
||||
candidateScores: input.candidateScores,
|
||||
discriminatorProbe: selectDiscriminatorProbe(input.contrastPacket ?? null),
|
||||
holdoutValidation: input.holdoutValidation,
|
||||
});
|
||||
if (
|
||||
!input.accepted
|
||||
&& (sessionOutcome === "adopt_representative" || sessionOutcome === "awaiting_confirmation")
|
||||
&& (sessionOutcome === "adopt_representative" || sessionOutcome === "awaiting_confirmation" || sessionOutcome === "provisional_range")
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
import type { EventDashaLedgerRow } from "./refinement-packet";
|
||||
import type { WindowScan } from "./varga-observations";
|
||||
import type { CandidateSeparation } from "../core/candidate-separation";
|
||||
|
||||
const D9_TYPE_TABLE: Readonly<Record<string, { trait: string; spouse: string; marriage: string }>> = {
|
||||
白羊座: { trait: "主动、热情、冲动", spouse: "独立、有活力", marriage: "早期婚姻、激情型" },
|
||||
@@ -73,7 +74,14 @@ export type SkillVerificationReportInput = Readonly<{
|
||||
unique_minute_claim: false;
|
||||
}> | null;
|
||||
dashaAgreement?: Readonly<{ status: string; user_meaning: string }> | null;
|
||||
techniqueAuditTable?: readonly Readonly<{ technique?: string; status?: string; note?: string }>[];
|
||||
techniqueAuditTable?: readonly Readonly<{
|
||||
technique?: string;
|
||||
status?: string;
|
||||
note?: string;
|
||||
calculation_result_id?: string;
|
||||
}>[];
|
||||
separation?: CandidateSeparation;
|
||||
engineResultId?: string | null;
|
||||
}>;
|
||||
|
||||
export function buildSkillVerificationReport(input: SkillVerificationReportInput): string {
|
||||
@@ -84,6 +92,7 @@ export function buildSkillVerificationReport(input: SkillVerificationReportInput
|
||||
const ledger = input.eventDashaLedger ?? [];
|
||||
const d9Signs = input.windowScan?.d9_sign_names ?? [];
|
||||
const d10Signs = input.windowScan?.d10_sign_names ?? [];
|
||||
const tied = input.separation?.status === "not_separated";
|
||||
const candidateLines = input.candidates.slice(0, 5).map((row) => (
|
||||
`| ${row.rank} | ${row.time} | ${row.relativeSupport} |`
|
||||
));
|
||||
@@ -98,12 +107,19 @@ export function buildSkillVerificationReport(input: SkillVerificationReportInput
|
||||
: ["当前窗还没有可对照的 D10 上升名,类型表待候选换升后填写。"];
|
||||
const audit = (input.techniqueAuditTable ?? []).slice(0, 16);
|
||||
const auditRows = audit.length > 0
|
||||
? audit.map((row) => `| ${row.technique ?? "技法"} | ${row.status ?? "blocked"} | ${row.note ?? ""} |`)
|
||||
? audit.map((row) => {
|
||||
const executed = row.status === "executed" && Boolean(row.calculation_result_id);
|
||||
const status = executed ? "executed" : (row.status === "executed" ? "input_covered" : (row.status ?? "blocked"));
|
||||
const note = executed
|
||||
? (row.note ?? "")
|
||||
: (row.note || "该方法所需资料已覆盖,没有可追溯的 calculationResultId,不能写成已执行。");
|
||||
return `| ${row.technique ?? "技法"} | ${status} | ${note} |`;
|
||||
})
|
||||
: [
|
||||
"| Vimshottari + 受控行运 | executed | 权重口径 40;事件吻合率不是唯一分钟 |",
|
||||
"| D9/D10 分盘 | executed | 权重口径 35;类型表是校时方法 |",
|
||||
"| 宫位 / 六亲六步 | executed | 权重口径 15;后三步方法论层 |",
|
||||
"| Nakshatra Pada | observation_only | 权重口径 10;不确认唯一分钟 |",
|
||||
"| Vimshottari + 受控行运 | input_covered | 没有 calculationResultId 时不能写成已执行 |",
|
||||
"| D9/D10 分盘 | input_covered | 类型表是校时方法;差异要进入区分探针 |",
|
||||
"| 宫位 / 六亲六步 | input_covered | 后三步方法论层 |",
|
||||
"| Nakshatra Pada | observation_only | 不确认唯一分钟 |",
|
||||
"| KP / D60 / Gulika | observation_only | 不进提出门或确认门计分 |",
|
||||
"| 占问 | observation_only | AI 暂不支持独立占问;有问起时间则观察 |",
|
||||
];
|
||||
@@ -113,11 +129,17 @@ export function buildSkillVerificationReport(input: SkillVerificationReportInput
|
||||
"这是当前窗的相对拟合,标签是 `candidate_range_not_birth_time_truth`。采用把代表性时间写入当前排盘;本会话以代表性时间收口,不是已确认唯一出生分钟。",
|
||||
"",
|
||||
"### 筛选",
|
||||
`- 当前代表分钟:${time}`,
|
||||
tied
|
||||
? `- 当前候选基本并列:${(input.separation?.credibleRange ?? []).join("、") || "尚未拉开"}。${time} 只是后续计算的代表点,不是赢家。`
|
||||
: `- 当前代表分钟:${time}`,
|
||||
`- 不可分宽度:${width}`,
|
||||
`- 本命上升(该分钟):${lagna}`,
|
||||
input.windowScan?.d9_candidates_differ ? "- D9 仍会换升,关系类型对照只用来分开候选。" : "- D9 上升在当前窗较稳。",
|
||||
input.windowScan?.d10_candidates_differ ? "- D10 仍会换升,事业类型对照只用来分开候选。" : "- D10 上升在当前窗较稳。",
|
||||
input.windowScan?.d9_candidates_differ
|
||||
? "- D9 仍会换升。这是候选结构差异,应生成区分探针,不能直接宣布不可分。"
|
||||
: "- D9 上升在当前窗较稳。",
|
||||
input.windowScan?.d10_candidates_differ
|
||||
? "- D10 仍会换升。这是候选结构差异,应生成区分探针,不能直接宣布不可分。"
|
||||
: "- D10 上升在当前窗较稳。",
|
||||
"",
|
||||
"### 候选窗(正文复述;卡片仍作采用控件)",
|
||||
"| 排名 | 时间 | 相对支持 |",
|
||||
@@ -126,8 +148,8 @@ export function buildSkillVerificationReport(input: SkillVerificationReportInput
|
||||
"",
|
||||
"### 方法1:Dasha + Gochara",
|
||||
fit
|
||||
? `${fit.user_meaning} ${fit.label}。`
|
||||
: "还没有事件吻合率。有已确认事件后,80%/60% 只描述事件吻合率,不得写成已确认唯一出生分钟。",
|
||||
? `${fit.user_meaning} ${fit.label}。这是事件拟合程度,不是候选区分程度。`
|
||||
: "还没有事件吻合率。有已确认事件后,80%/60% 只描述事件吻合率,不得写成已确认唯一出生分钟,也不得写成候选已经分开。",
|
||||
"",
|
||||
"| 事件 | 吻合 | Dasha / Gochara |",
|
||||
"|---|---|---|",
|
||||
@@ -153,7 +175,7 @@ export function buildSkillVerificationReport(input: SkillVerificationReportInput
|
||||
"状态:`not_used` / `observation_only`。产品可观察一次问起时间,不挡出牌。",
|
||||
"",
|
||||
"### Technique Audit Table",
|
||||
"权重口径:Dasha 40 / 分盘 35 / 宫位 15 / Pada 10。KP、D60、Gulika 观察或 blocked。",
|
||||
"权重口径:Dasha 40 / 分盘 35 / 宫位 15 / Pada 10。KP、D60、Gulika 观察或 blocked。只有带 calculationResultId 的行才能写 executed。",
|
||||
"| 技法 | 状态 | 说明 |",
|
||||
"|---|---|---|",
|
||||
...auditRows,
|
||||
|
||||
Reference in New Issue
Block a user