diff --git a/frontend/src/lib/consultation-evidence-card.ts b/frontend/src/lib/consultation-evidence-card.ts index d0a19633..7772c842 100644 --- a/frontend/src/lib/consultation-evidence-card.ts +++ b/frontend/src/lib/consultation-evidence-card.ts @@ -378,6 +378,19 @@ function copy(value: unknown): Json | undefined { return value !== undefined && isJson(value) ? structuredClone(value) : undefined; } +// For house 7 the engine's event-house lord and opposite-house lord are the +// same planet, so each hit arrives twice ("X(宫主)" and "X(对宫主)") with the +// same layer and PAC. Keep the "(宫主)" row and drop its twin: the card keeps +// engine values only, and the 7th lord is the opposite lord by definition +// (BUG-1185: the corrected aspect count adds 7th-house rows). +function dropOppositeLordTwins(rows: JsonRecord[]): JsonRecord[] { + const normalized = (row: JsonRecord) => JSON.stringify({ + ...row, target: typeof row.target === "string" ? row.target.replaceAll("(对宫主)", "(宫主)") : row.target, + }); + const plain = new Set(rows.filter((row) => !String(row.target ?? "").includes("(对宫主)")).map(normalized)); + return rows.filter((row) => !String(row.target ?? "").includes("(对宫主)") || !plain.has(normalized(row))); +} + function pickKeys(source: unknown, keys: readonly string[]): JsonRecord { const from = record(source); const out: JsonRecord = {}; @@ -857,7 +870,7 @@ function domainSection( const ul = pickKeys(karakas.UL, KARAKA_TARGET_KEYS); section.double_transit = { ...(typeof double.date === "string" ? { date: double.date } : {}), - house_7: conclusions.filter((row) => row.house === 7).map((row) => pickKeys(row, DOUBLE_TRANSIT_ROW_KEYS)), + house_7: dropOppositeLordTwins(conclusions.filter((row) => row.house === 7).map((row) => pickKeys(row, DOUBLE_TRANSIT_ROW_KEYS))), ...(nonEmpty(dk) ? { DK: dk } : {}), ...(nonEmpty(ul) ? { UL: ul } : {}), ...(typeof record(karakas.DK).method === "string" ? { karaka_method: record(karakas.DK).method as string } : {}), diff --git a/frontend/tests/consult-evidence-card-v2-20260927.test.ts b/frontend/tests/consult-evidence-card-v2-20260927.test.ts index 4a52f48d..c9229894 100644 --- a/frontend/tests/consult-evidence-card-v2-20260927.test.ts +++ b/frontend/tests/consult-evidence-card-v2-20260927.test.ts @@ -162,8 +162,15 @@ test("marriage: 5H / 5L, day / night, Punarphoo, Double Transit on 7H / 7L / DK claim_boundary: punarphoo.claim_boundary, }, `${where} Punarphoo`); const double = layers.double_transit as Json; - const seventh = (double.conclusions as Json[]).filter((row) => row.house === 7) + // 原值: 引擎第 7 宫每一行原样上卡 + // 新值: 与某行只差「(对宫主)」/「(宫主)」、其余字段相同的「(对宫主)」行不上卡(保留「(宫主)」那一行) + // 原因: 第 7 宫的事件宫主与对宫主是同一颗星,两行重复;BUG-1185 相位改从 1 数后第 7 宫命中变多, + // 泰勒婚姻轮超出 12,000 字符预算 40 字,按 BUG-1155 先例压缩格式、不改预算断言;卡上仍只放引擎原值 + const rows = (double.conclusions as Json[]).filter((row) => row.house === 7) .map((row) => pick(row, ["layer", "target", "strength", "jupiter_pac", "saturn_pac"])); + const asLord = (row: Json) => JSON.stringify({ ...row, target: String(row.target).replaceAll("(对宫主)", "(宫主)") }); + const plainKeys = new Set(rows.filter((row) => !String(row.target).includes("(对宫主)")).map(asLord)); + const seventh = rows.filter((row) => !String(row.target).includes("(对宫主)") || !plainKeys.has(asLord(row))); assert.deepEqual(dig(section.double_transit, "house_7"), seventh, `${where} 7H / 7L double transit`); for (const key of ["DK", "UL"]) { assert.deepEqual(