Files
Jyotisha/frontend/src/lib/rectification-agentic/v9/skill-verification-report.ts
T
Jesse_Chen f3327235ea
Independent Staging Quality Gate / validate (push) Successful in 10m50s
Independent Staging Quality Gate / publish (push) Successful in 13m29s
fix(rectification): remove static interview fallbacks
2026-08-27 16:40:47 +08:00

151 lines
7.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Skill Path-C eight-method verification report for offer/adopt turns.
*
* 80%/60% language is event-fit rate for the current window, never a unique
* birth-minute confirmation. D9/D10 type tables are rectification method, not
* fate promises.
*/
import type { EventDashaLedgerRow } from "./refinement-packet";
import type { WindowScan } from "./varga-observations";
import type { CandidateSeparation } from "../core/candidate-separation";
import { D9_TYPE_TABLE, D10_TYPE_TABLE, signKey } from "./varga-type-tables";
function typeRow(sign: string, table: "d9" | "d10"): string {
const key = signKey(sign);
if (table === "d9") {
const row = D9_TYPE_TABLE[key];
if (!row) return `| ${key} | (当前窗上升,类型表无这一行) |`;
return `| ${key} | ${row.trait} | ${row.spouse} | ${row.marriage} |`;
}
const row = D10_TYPE_TABLE[key];
if (!row) return `| ${key} | (当前窗上升,类型表无这一行) |`;
return `| ${key} | ${row.trait} | ${row.occupation} | ${row.style} |`;
}
export type SkillVerificationReportInput = Readonly<{
representativeTime: string | null;
widthMinutes: number | null;
candidates: readonly Readonly<{ time: string; rank: number; relativeSupport: number }>[];
houseLagna?: string | null;
windowScan?: WindowScan | null;
eventDashaLedger?: readonly EventDashaLedgerRow[];
eventFitRate?: Readonly<{
matched: number;
total: number;
percent: number | null;
label: string;
user_meaning: string;
unique_minute_claim: false;
}> | null;
dashaAgreement?: Readonly<{ status: string; user_meaning: string }> | null;
techniqueAuditTable?: readonly Readonly<{
technique?: string;
status?: string;
note?: string;
calculation_result_id?: string;
}>[];
separation?: CandidateSeparation;
engineResultId?: string | null;
}>;
export function buildSkillVerificationReport(input: SkillVerificationReportInput): string {
const time = input.representativeTime ?? "尚未选定";
const width = input.widthMinutes == null ? "未知" : `${input.widthMinutes} 分钟`;
const lagna = input.houseLagna?.trim() || "未交付";
const fit = input.eventFitRate;
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} |`
));
const dashaRows = ledger.length > 0
? ledger.map((row) => `| ${row.summary} | ${row.match_label} | ${row.user_meaning} |`)
: ["| (本轮还没有已确认事件行) | — | 先收带日期经历再填这张表 |"];
const d9Table = d9Signs.length > 0
? ["| D9上升 | 感情特质 | 配偶类型 | 婚姻特点 |", "|---|---|---|---|", ...d9Signs.map((sign) => typeRow(sign, "d9"))]
: ["当前窗还没有可对照的 D9 上升名,类型表待候选换升后填写。"];
const d10Table = d10Signs.length > 0
? ["| D10上升 | 事业特质 | 职业类型 | 工作风格 |", "|---|---|---|---|", ...d10Signs.map((sign) => typeRow(sign, "d10"))]
: ["当前窗还没有可对照的 D10 上升名,类型表待候选换升后填写。"];
const audit = (input.techniqueAuditTable ?? []).slice(0, 16);
const auditRows = audit.length > 0
? 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 + 受控行运 | input_covered | 没有 calculationResultId 时不能写成已执行 |",
"| D9/D10 分盘 | input_covered | 类型表是校时方法;差异要进入区分探针 |",
"| 宫位 / 六亲六步 | input_covered | 后三步方法论层 |",
"| Nakshatra Pada | observation_only | 不确认唯一分钟 |",
"| KP / D60 / Gulika | observation_only | 不进提出门或确认门计分 |",
"| 占问 | observation_only | AI 暂不支持独立占问;有问起时间则观察 |",
];
return [
"## 生时纠正验证报告(skill 八法)",
"这是当前窗的相对拟合,标签是 `candidate_range_not_birth_time_truth`。采用只会把代表性时间写入当前排盘,不等于确认唯一出生分钟。",
"",
"### 筛选",
tied
? `- 当前候选基本并列:${(input.separation?.credibleRange ?? []).join("、") || "尚未拉开"}${time} 只是后续计算的代表点,不是赢家。`
: `- 当前代表分钟:${time}`,
`- 不可分宽度:${width}`,
`- 本命上升(该分钟):${lagna}`,
input.windowScan?.d9_candidates_differ
? "- D9 仍会换升。这是候选结构差异,应生成区分探针,不能直接宣布不可分。"
: "- D9 上升在当前窗较稳。",
input.windowScan?.d10_candidates_differ
? "- D10 仍会换升。这是候选结构差异,应生成区分探针,不能直接宣布不可分。"
: "- D10 上升在当前窗较稳。",
"",
"### 候选窗(正文复述;卡片仍作采用控件)",
"| 排名 | 时间 | 相对支持 |",
"|---|---|---|",
...(candidateLines.length > 0 ? candidateLines : ["| — | — | 还没有可出示的候选 |"]),
"",
"### 方法1Dasha + Gochara",
fit
? `${fit.user_meaning} ${fit.label}。这是事件拟合程度,不是候选区分程度。`
: "还没有事件吻合率。有已确认事件后,80%/60% 只描述事件吻合率,不得写成已确认唯一出生分钟,也不得写成候选已经分开。",
"",
"| 事件 | 吻合 | Dasha / Gochara |",
"|---|---|---|",
...dashaRows,
input.dashaAgreement ? `双轨:${input.dashaAgreement.user_meaning}` : "Narayana 对照未交付时只保留 Vimshottari。",
"",
"### 方法23D9 / D10 类型表",
"写的是「该分钟下分盘升 X,与用户所述特质的对应/冲突」。这是校时方法,不是咨询命运承诺。",
...d9Table,
"",
...d10Table,
"",
"### 方法4:六亲宫位(Raman 六步)",
"前三步(宫、宫主、自然卡拉卡)可执行;后三步(日月重复、D9、正负多数)标方法论层。家人事件对照 D12 / D7 / D3。",
"",
"### 方法56:外貌 / 疤痕",
"只作体质验证、缩小范围,不升主评分,不定分钟。",
"",
"### 方法7:职业",
"对照 D1 第 10 宫 + D10,允许事业类型表。",
"",
"### 方法8:占问",
"状态:`not_used` / `observation_only`。产品可观察一次问起时间,不挡出牌。",
"",
"### Technique Audit Table",
"权重口径:Dasha 40 / 分盘 35 / 宫位 15 / Pada 10。KP、D60、Gulika 观察或 blocked。只有带 calculationResultId 的行才能写 executed。",
"| 技法 | 状态 | 说明 |",
"|---|---|---|",
...auditRows,
"",
"不得把 VedAstro/holdout 或高吻合写成已校到唯一分钟。",
].join("\n");
}