@@ -6,9 +6,10 @@
* fate promises.
*/
import type { EventDashaLedgerRow } from "./refinement-packet" ;
import type { DashaAgreement , EventDashaLedgerRow , WindowScanTransition } from "./refinement-packet" ;
import type { WindowScan } from "./varga-observations" ;
import type { CandidateSeparation } from "../core/candidate-separation" ;
import { signFromTransitions } from "./divergence-panel" ;
import { D9_TYPE_TABLE , D10_TYPE_TABLE , signKey } from "./varga-type-tables" ;
function typeRow ( sign : string , table : "d9" | "d10" ) : string {
@@ -23,6 +24,18 @@ function typeRow(sign: string, table: "d9" | "d10"): string {
return ` | ${ key } | ${ row . trait } | ${ row . occupation } | ${ row . style } | ` ;
}
export type CandidateVargaSigns = Readonly < {
d9 : string | null ;
d10 : string | null ;
} > ;
export type SkillVerificationReport = Readonly < {
width_minutes : number | null ;
dasha_agreement : DashaAgreement | null ;
sign_by_candidate : Readonly < Record < string , CandidateVargaSigns > > ;
markdown : string ;
} > ;
export type SkillVerificationReportInput = Readonly < {
representativeTime : string | null ;
widthMinutes : number | null ;
@@ -38,7 +51,8 @@ export type SkillVerificationReportInput = Readonly<{
user_meaning : string ;
unique_minute_claim : false ;
} > | null ;
dashaAgreement? : Readonly < { status : string ; user_meaning : string } > | null ;
dashaAgreement? : DashaAgreement | null ;
signByCandidate? : Readonly < Record < string , CandidateVargaSigns > > ;
techniqueAuditTable? : readonly Readonly < {
technique? : string ;
status? : string ;
@@ -49,26 +63,71 @@ export type SkillVerificationReportInput = Readonly<{
engineResultId? : string | null ;
} > ;
export function signByCandidateFromTransitions (
times : readonly string [ ] ,
transitions : readonly WindowScanTransition [ ] ,
) : Readonly < Record < string , CandidateVargaSigns > > {
const out : Record < string , CandidateVargaSigns > = { } ;
for ( const time of times ) {
out [ time ] = {
d9 : signFromTransitions ( transitions , "d9" , time ) ,
d10 : signFromTransitions ( transitions , "d10" , time ) ,
} ;
}
return out ;
}
function uniqueSigns ( signs : readonly ( string | null | undefined ) [ ] ) : string [ ] {
const seen = new Set < string > ( ) ;
const out : string [ ] = [ ] ;
for ( const sign of signs ) {
const keyed = sign ? signKey ( sign ) : "" ;
if ( ! keyed || seen . has ( keyed ) ) continue ;
seen . add ( keyed ) ;
out . push ( keyed ) ;
}
return out ;
}
export function buildSkillVerificationReport ( input : SkillVerificationReportInput ) : string {
return buildSkillVerificationPacket ( input ) . markdown ;
}
export function buildSkillVerificationPacket ( input : SkillVerificationReportInput ) : SkillVerificationReport {
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 signByCandidate = input . signByCandidate
? ? signByCandidateFromTransitions (
input . candidates . map ( ( row ) = > row . time ) ,
input . windowScan ? . transitions ? ? [ ] ,
) ;
const d9Signs = uniqueSigns ( Object . values ( signByCandidate ) . map ( ( row ) = > row . d9 ) ) ;
const d10Signs = uniqueSigns ( Object . values ( signByCandidate ) . map ( ( row ) = > row . d10 ) ) ;
const d9TableSigns = d9Signs . length > 0 ? d9Signs : uniqueSigns ( input . windowScan ? . d9_sign_names ? ? [ ] ) ;
const d10TableSigns = d10Signs . length > 0 ? d10Signs : uniqueSigns ( input . windowScan ? . d10_sign_names ? ? [ ] ) ;
const d9Differs = d9Signs . length >= 2
|| ( d9Signs . length === 0 && input . windowScan ? . d9_candidates_differ === true ) ;
const d10Differs = d10Signs . length >= 2
|| ( d10Signs . length === 0 && input . windowScan ? . d10_candidates_differ === true ) ;
const tied = input . separation ? . status === "not_separated" ;
const candidateLines = input . candidates . slice ( 0 , 5 ) . map ( ( row ) = > (
` | ${ row . rank } | ${ row . time } | ${ row . relativeSupport } | `
) ) ;
const signRows = input . candidates . map ( ( row ) = > {
const signs = signByCandidate [ row . time ] ;
return ` | ${ row . time } | ${ signs ? . d9 ? ? "—" } | ${ signs ? . d10 ? ? "—" } | ` ;
} ) ;
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" ) ) ]
const d9Table = d9TableSigns . length > 0
? [ "| D9上升 | 感情特质 | 配偶类型 | 婚姻特点 |" , "|---|---|---|---|" , . . . d9TableSigns . map ( ( sign ) = > typeRow ( sign , "d9" ) ) ]
: [ "当前窗还没有可对照的 D9 上升名,类型表待候选换升后填写。" ] ;
const d10Table = d10Signs . length > 0
? [ "| D10上升 | 事业特质 | 职业类型 | 工作风格 |" , "|---|---|---|---|" , . . . d10Signs . map ( ( sign ) = > typeRow ( sign , "d10" ) ) ]
const d10Table = d10TableSigns . length > 0
? [ "| D10上升 | 事业特质 | 职业类型 | 工作风格 |" , "|---|---|---|---|" , . . . d10TableSigns . map ( ( sign ) = > typeRow ( sign , "d10" ) ) ]
: [ "当前窗还没有可对照的 D10 上升名,类型表待候选换升后填写。" ] ;
const audit = ( input . techniqueAuditTable ? ? [ ] ) . slice ( 0 , 16 ) ;
const auditRows = audit . length > 0
@@ -89,9 +148,9 @@ export function buildSkillVerificationReport(input: SkillVerificationReportInput
"| 占问 | observation_only | AI 暂不支持独立占问;有问起时间则观察 |" ,
] ;
return [
const markdown = [
"## 生时纠正验证报告(skill 八法)" ,
"这是当前窗的相对拟合,标签是 `candidate_range_not_birth_time_truth`。采用只会把代表性时间写入当前排盘,不等于 确认唯一出生分钟。" ,
"这是当前窗的相对拟合,标签是 `candidate_range_not_birth_time_truth`。采用只会把代表性时间写入当前排盘,不是已 确认的 唯一出生分钟。" ,
"" ,
"### 筛选" ,
tied
@@ -99,10 +158,10 @@ export function buildSkillVerificationReport(input: SkillVerificationReportInput
: ` - 当前代表分钟: ${ time } ` ,
` - 不可分宽度: ${ width } ` ,
` - 本命上升(该分钟): ${ lagna } ` ,
input . windowScan ? . d9_candidates_differ
d9Differs
? "- D9 仍会换升。这是候选结构差异,应生成区分探针,不能直接宣布不可分。"
: "- D9 上升在当前窗较稳。" ,
input . windowScan ? . d10_candidates_differ
d10Differs
? "- D10 仍会换升。这是候选结构差异,应生成区分探针,不能直接宣布不可分。"
: "- D10 上升在当前窗较稳。" ,
"" ,
@@ -111,6 +170,11 @@ export function buildSkillVerificationReport(input: SkillVerificationReportInput
"|---|---|---|" ,
. . . ( candidateLines . length > 0 ? candidateLines : [ "| — | — | 还没有可出示的候选 |" ] ) ,
"" ,
"### 各候选分盘上升(只抄本表)" ,
"| 时间 | D9 | D10 |" ,
"|---|---|---|" ,
. . . ( signRows . length > 0 ? signRows : [ "| — | — | 还没有可出示的候选 |" ] ) ,
"" ,
"### 方法1: Dasha + Gochara" ,
fit
? ` ${ fit . user_meaning } ${ fit . label } 。这是事件拟合程度,不是候选区分程度。 `
@@ -122,7 +186,7 @@ export function buildSkillVerificationReport(input: SkillVerificationReportInput
input . dashaAgreement ? ` 双轨: ${ input . dashaAgreement . user_meaning } ` : "Narayana 对照未交付时只保留 Vimshottari。" ,
"" ,
"### 方法2– 3: D9 / D10 类型表" ,
"写的是「该分钟下分盘升 X,与用户所述特质的对应/冲突」。这是校时方法,不是咨询命运承诺。" ,
"写的是「该分钟下分盘升 X,与用户所述特质的对应/冲突」。这是校时方法,不是咨询命运承诺。分盘上升只抄本报告 `sign_by_candidate`,不得自行按换升时刻推算。 " ,
. . . d9Table ,
"" ,
. . . d10Table ,
@@ -147,4 +211,11 @@ export function buildSkillVerificationReport(input: SkillVerificationReportInput
"" ,
"不得把 VedAstro/holdout 或高吻合写成已校到唯一分钟。" ,
] . join ( "\n" ) ;
return {
width_minutes : input.widthMinutes ,
dasha_agreement : input.dashaAgreement ? ? null ,
sign_by_candidate : signByCandidate ,
markdown ,
} ;
}