fix(rectification): unblock next build typecheck for house tables

Docker npm run build failed on Failed to type check. The skill-package-registry Import traces were only file-tracing noise; houseTable used && on string|null, and eight-method tests compared impossible literals that tsconfig still typechecks.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-08-20 12:21:08 +08:00
parent 3c6c86e307
commit 0eebf9713f
3 changed files with 27 additions and 6 deletions
+16
View File
@@ -4826,3 +4826,19 @@
- 相关记录:BUG-291、BUG-319
- 复发自:BUG-291(迁居继续不轮询;财务/健康被一并排除后不再被方法层追问)
- 修复版本:1b93afc5
## BUG-321 | Docker `npm run build` 因宫位表 `&&` 与八方法测试字面量类型检查失败
- 状态:resolved
- 首次发现:2026-08-20
- 最近更新:2026-08-20
- 影响面:`deploy/railway-web.Dockerfile``RUN npm run build``rectification-candidate-result.ts``rectification-eight-method.test.ts`
- 用户现象:staging publish 在 web 镜像构建失败。BuildKit 日志末尾是 `skill-package-registry.ts` 的 Import traces。
- 触发条件:向 `staging` 推送 Skill 10.0.8 后走 publish 镜像构建。push 上的 validate 跳过 `npm run build`
- 根因:日志末尾 Import traces 只是动态文件访问追踪警告,真正失败是 `Failed to type check``selectedTime && houseTablesByTime[selectedTime]``string | null` 下会被推断成 `"" | HouseTable | null``??` 不能消掉空字符串。八方法测试对 `do_not_poll` 传入 `"appearance"`,并对观察层比较永远不存在的 `"d24"` / `"d2"``tsconfig` 包含 `tests/**/*.ts`,因此这些测试错误也会挡住 `next build`
- 修复:宫位表改用三元取值;测试改为断言 `do_not_poll` 恰好是 `horary`,并用完整观察层列表证明 D24/D2 不单独成层。
- 验证:`./node_modules/.bin/tsc --noEmit``npx tsx --test tests/rectification-eight-method.test.ts`
- 防复发:对 `string | null` 做查找不得用 `&&` 当存在性守卫。`readonly ["horary"]``.includes()` 只能传入 `"horary"`。staging push 的 validate 仍不跑 `next build`,类型回归只在 publish Docker 暴露。
- 相关记录:BUG-309、BUG-315、BUG-320
- 复发自:BUG-309validate 跳过 `next build`;日志末尾 Import traces 掩盖类型检查失败)
- 修复版本:待提交
@@ -220,8 +220,8 @@ export function parseRectificationCandidateResult(value: unknown): Rectification
const fallbackHouseTable = parseRectificationHouseTable(snapshot.houseTable)
?? parseRectificationHouseTable(snapshot.house_table)
?? parseRectificationHouseTable(receipt?.house_table);
const houseTable = (selectedTime && houseTablesByTime[selectedTime])
?? (representativeTime && houseTablesByTime[representativeTime])
const houseTable = (selectedTime ? houseTablesByTime[selectedTime] : null)
?? (representativeTime ? houseTablesByTime[representativeTime] : null)
?? fallbackHouseTable;
return {
@@ -221,8 +221,7 @@ test("declined relationship skips to career and still skips horary", () => {
});
assert.equal(plan.next_followup?.method_id, "d10_career");
assert.equal(plan.next_followup?.domain, "career");
assert.equal(plan.do_not_poll.includes("horary"), true);
assert.equal(plan.do_not_poll.includes("appearance"), false);
assert.deepEqual([...plan.do_not_poll], ["horary"]);
});
test("D9 differ becomes an internal ask theme without sign labels", () => {
@@ -305,7 +304,10 @@ test("D24-only window change folds into education follow-up without a second lay
const observations = internalObservationsFromWindowScan(scan);
assert.equal(observations.find((item) => item.layer === "d5")?.candidates_differ, true);
assert.equal(observations.find((item) => item.layer === "d5")?.ask_theme, "education_style");
assert.equal(observations.some((item) => item.layer === "d24"), false);
assert.deepEqual(
observations.map((item) => item.layer),
["d9", "d10", "d4", "d5", "d7", "d12", "d11", "d30"],
);
const plan = buildMethodFollowupPlan({
evidence: [
{ status: "confirmed", domain: "relationship", datePrecision: "year", occurredFrom: "2018-01-01", occurredTo: null },
@@ -353,7 +355,10 @@ test("D11-only window change folds into finance follow-up without delaying adopt
assert.equal(observations.find((item) => item.layer === "d11")?.candidates_differ, true);
assert.equal(observations.find((item) => item.layer === "d11")?.ask_theme, "finance_change");
assert.equal(observations.find((item) => item.layer === "d30")?.ask_theme, "health_pressure");
assert.equal(observations.some((item) => item.layer === "d2"), false);
assert.deepEqual(
observations.map((item) => item.layer),
["d9", "d10", "d4", "d5", "d7", "d12", "d11", "d30"],
);
const plan = buildMethodFollowupPlan({
evidence: [
{ status: "confirmed", domain: "relationship", datePrecision: "year", occurredFrom: "2018-01-01", occurredTo: null },