## 0.62.1（2026-11-04，待发布）

> 本版主题：全项目复查补漏——星座/生命数字的日期尺与全插件统一、非法 action 不再静默落默认、次级入口的 null 守卫。

- **星座 / 生命数字日期尺统一到 1600–2400**（`engine/star.js`、`engine/numerology.js`）：两套各自卡 1900–2100，同一份生日在八字/紫微/黄历可排，到星座/生命数字却被拒；现与 `parseDateTime` / `assertCivil` 同一把尺（越界由日期解析层报 `E_RANGE`），并补 1600 / 2400 / 1599 / 2401 边界断言。
- **非法 action 不再静默落默认分支**（`engine/index.js`、`engine/fengshui.js`、`engine/name.js`）：`fengshui action:'nope'` 以前照样按 natal 排、`name action:'nope'` 照样按 assess 评名；现在直接 `E_INPUT` 并列出合法值（不传仍按默认）。
- **次级入口 null 守卫**（`engine/trend.js`、`engine/mbti.js`、`engine/qimen.js`）：`buildTrend(null)` / `buildMbti(null)` / `buildQimen(null)` / `buildSnapshot(null)` 不再抛裸 TypeError，统一 `E_INPUT`。
- **回归锁**：`test/guard-inputs.test.mjs` ⑲–㉑ 新增 14 条；`test/chunks.test.mjs` 的起名参数从旧别名 `evaluate` 改为 schema 支持的 `assess`。
- 基线：**154 文件 / 7894 条断言**（7880 → 7894，全为新增）。

## 0.62.0（2026-11-04，已发布）

> 已发布：npm `dsh-metaphysics@0.62.0`，shasum `b9563b742dd7ef0f394e8f19b0a69934f6910f01`，101 个文件；tag `v0.62.0` 与 GitHub release 已建。

- **复查报告 50 项：排盘口径、输入守卫与提示层**（`engine/*`、`index.js`、`src/panel-kit.js`、`test/*`）：
  - P0 · 紫微晚子时（`engine/index.js`、`engine/ziwei.js`）：`lateZi` 与紫微历史参数名 `lateZishi` 不互通，revise 回执「已应用」但盘仍按 current-day 排；现统一映射（`lateZi:false` → `current-day`），回执与盘面同源。`hourUnknown` 的过去盘也改为按正午占位，与主盘落在同一张盘上。
  - P1 · 档案两个开关（`src/panel-kit.js`、`index.js`）：`profClean` 白名单漏掉 `trueSolar / lateZi`，存卡时被剥掉、载入时又按默认「都开」；现无条件落盘，旧档案缺字段仍按默认处理。
  - P1 · 紫微合盘丢主星（`engine/ziwei-hepan.js`）：星型标签是中文字面量 `主星`，旧过滤拿 `main` 比对，主星永远进不了合盘；现按 `主星 / 吉星 / 煞星` 取。
  - P1 · 奇门健康用神（`engine/qimen-interpret.js`）：天芮在中宫寄坤后被统一改名「禽芮」，按原名定位不到；驿马只存在 `r.ma.gong` 而不在 `palaces[].star`；主用神缺位时又被次级候选掩盖。现加星名别名、驿马单列、主用神缺位写入 `unresolved`，不再只剩一句「若以死门为用神」。
  - P1 · 梅花时间起卦（`engine/meihua.js`、新增 `engine/datetime.js`）：原先自带一份宽松解析器，`1990-02-30`、13 月、25:00 都能过；现与八字/紫微共用 `parseDateTime`（1600–2400、逐日校验），数字起卦的动爻 `changing` 只收 1–6 整数，非法直接 `E_INPUT`。
  - P1 · 大六壬三传（`engine/daliuren.js`）：遥克改为先全盘找蒿矢、没有再找弹射（不再逐课先到先得）；昴星按阳日虎视取地盘酉上神、阴日冬蛇取天盘酉下神，中末传按阴阳日分别取支上/干上；八专按阳顺阴逆数三神；伏吟初传自刑时中传换另一上神、仍自刑取冲。三传不再整盘套通用递推。
  - P1 · 生时校正 10 年窗口（`engine/bazi.js`、`engine/index.js`、`engine/rectify.js`）：流年窗口新增 `liunianTo`，几十年前的事件可以逐年对账；候选按「日柱+时柱」合并（真太阳时会把相邻整点并进同一时辰），结果里报告合并掉了几个输入整点；虚岁改按公历年算，与趋势页同口径。
  - P1 · 工具层参数（`index.js`）：`hour / date` 只给 `chenggu / xiaoliuren`，别的体系传了直接报错（原先收了不看，用户以为改了时刻）；`partner2` 也做地址长度校验；带句柄再换地址时丢掉上一轮派生的 `longitude / geo`，新地址真正重新解析；三方盘也按出生地解析经度；`system` 缺失时才在 `run()` 报错，schema 仍不写 `required`（只给 handle 的追问是主推用法）。
  - P2 · 三奇入墓（`engine/qimen.js`）：按《玄机赋》阴干逆行取墓改为 乙→戌/乾六、丙→戌/乾六、丁→丑/艮八；原表把乙放未/坤二、丁放戌/乾六。
  - P2 · 奇门时旬空（`engine/qimen.js`）：空亡改按**时柱所在旬**取（如甲子旬空戌亥），不再拿日旬顶替；补注释说明五鼠遁晚子时口径。
  - P2 · 紫微亮度「闲」（`engine/ziwei-words.js`）：五档亮度表含「闲」，词库缺这一档会被当成庙旺；补 `闲地 / neutral / 可用的力不多`，测试锁定该档。
  - P2 · 紫微魁钺流派（`engine/ziwei.js`、`engine/diff.js`、`index.js`）：删除与 qs1 同表的「network」选项，schema / 差异标签 / 测试同步，避免选了「网络派」实际按另一派排。
  - P2 · 塔罗张数（`engine/tarot.js`）：`count` 只收 1 / 3 / 5，`2 / 4 / 0 / 7 / 3.5` 直接 `E_INPUT`；原先静默折成 3 张，牌阵与用户要求不符。
  - P2 · 六爻爻值（`engine/liuyao.js`）：`lines` 必须正好 6 个、每个 6/7/8/9；空参数、缺爻、非法值统一 `E_INPUT`，不再在深处抛裸 TypeError。
  - P2 · 输入标量（`engine/index.js`、`engine/fengshui.js`、`engine/trend.js`）：`verifyPast` 必须是 1–10 整数（6.5 / "6" 不再静默当没传、11 不再截成 10）；`fortuneYear` 必须是整数年份；`toAge` 必须是 10–100 整数；经度只收 number 与十进制数字串（`true / [] / " "` 不再按 1°/0° 静默算真太阳时）；`mode` 按体系分组校验，跨组直接报错；`asOf` 按同一日期尺归一，只给日期 / 带空格 / ISO 三种写法出同一张盘。
  - P2 · 地支关系取句（`engine/bazi-words.js`）：半合/拱合、半会/拱会各自成句，不再落进泛泛的「合」；自刑仍优先于刑。
  - P2 · 风水阴阳遁（`engine/fengshui.js`）：飞星补上 `forward` 方向，阴遁逆飞不再按顺飞排；`fortuneYear` 非整数报错而不是当没给。
  - P2 · 称骨晚子时（`engine/chenggu.js`）：23:00–23:59 与八字/六壬/奇门同口径按次日取农历日与日柱，并在 `input` 里标 `lunarDateShifted`。
  - P2 · 公农历范围（`engine/convert.js`）：与 `assertCivil` 统一到 1600–2400，非法日期与超范围年份改 `E_INPUT`，不再抛裸 Error 或把 1600 年说成 1900。
  - P2 · 追问兜底（`engine/followup.js`）：12 个不产 `interpret.sections` 的体系，改为按 `summary` / 神煞分组回答，不再一律回「没有可追问的分节」。
  - P2 · ΔT 低年段（`engine/calendar.js`）：1600–1900 改用 Meeus 多项式（1600 年约 120s）；原先整段取 1900 常数，1600 年误差 123s，与函数注释自相矛盾。
  - P3 · 地址解析（`engine/geo.js`）：同名区县（中山区→大连、朝阳区按省份/默认北京）不再被同名城市抢走；「中山路」这类全国路名缺城市线索时返回未匹配并提示补城市；「河北区」不再按河北省会算。
  - P3 · 联网 UA（`engine/geo.js`）：`User-Agent` 去掉版本号，只保留应用名与仓库地址，避免发版漏改造成失联（OSM 政策只要求可识别）。
  - P3 · 产物与死代码（`engine/lunar.js`、`dst.js`、`yingqi.js`、`tiaohou.js`）：删掉未使用的 `cursorStart / monthStartJd / withDstNote / monthTone / monthSameBranches`，`YINGQI_RULE_IDS` 直接指向 `RULE_ORDER`；合并句柄增量时用无原型对象承接 `__proto__`，派生 `geo` 不进影子盘指纹；调候表重复的 `热` 键清理。
  - P3 · 共用日期尺（`engine/datetime.js`、`engine/zeri.js`、`engine/index.js`）：日期校验收成一套 `parseYmd / parseDateTime`，择日与小六壬不再各写一份正则；空参数统一 `E_INPUT`（星座/生命数字/姓名/择日/小六壬/风水等）。
  - P3 · 文案与文档：八字缺时柱的说明改为「旺衰、格局、用神、调候暂以正午时柱估算」，不再声称时柱不参与任何判定；日期 tab 默认今天确认为有意行为，不改代码。
  - 回归锁：`test/tarot.test.mjs`、`test/tool-geo.test.mjs`、`test/qimen-rules.test.mjs`、`test/guard-inputs.test.mjs`、`test/verify.test.mjs`、`test/ziwei-words.test.mjs`、`test/ziwei-schools.test.mjs` 同步到新口径；地址同名/路名 8 条、奇门时旬空 6 条、fortuneYear 与引擎入参守卫 12 条为新增断言。
- **复查收尾时又查出的「修了但没生效」四处**（`engine/index.js`、`engine/tarot.js`、`index.js`、`test/*`）：
  - `lateZi` 只改到了八字 / 大六壬 / 紫微，`compute()` 往称骨、小六壬、梅花传参时仍把它漏在门外——引擎各自支持、工具层却收不到，用户关掉晚子时，这三套仍按换日排。三处分支补齐透传，并加断言锁「同一时刻开 / 关晚子时得到不同结果」。
  - `verifyPast` 的数字串整形写在 `computeRaw()`，而「摊开过去流年」的代码在它上游的 `compute()` 里先跑了：`verifyPast:'6'` 先被当成没传、整形再也没机会执行。整形前移到 `compute()` 调用点之前，`'6'` 与 `6` 等价，非法值统一 `E_INPUT`。
  - 塔罗全盘解读遇到缺 `position` 的牌会拼出「（undefined·正位）」；改为按牌在阵中的序位回退（`第 N 张`）。
  - 三方合盘的第三方地址此前只做长度校验、没有走联网解析，出生地填了但真太阳时仍按 0° 算；第三方与主方 / 对方同一条解析路径。
- **构建链补齐 `datetime` 与 `ziwei-words`**（`tools/build-client.mjs`）：`parseDateTime` 抽到 `engine/datetime.js` 后没进 `ORDER`，浏览器产物里会报 `parseDateTime is not a function`；`ziwei.js` 引用 `ziwei-words` 的 `SHA_STAR` 时，模块顺序又排在 `ziwei` 之后。两处都补进 `ORDER` / `COMMON`，18 个分块与单包重新生成，`layout / security / chunks / client-bundle / standalone` 恢复全绿。
- **第二轮复测 16 项：本轮修复自己引入的回归，与上一轮没修到底的边角**（`engine/*`、`index.js`、`README.md`、`test/*`）：
  - P2 · 调候「热且湿」被翻档（`engine/tiaohou.js`）：`judgeClimate` 里 `hot` 先短路，`hot && damp >= 0.8` 那条湿滞分支从未命中；上一轮为了接通它把热+湿并进「湿滞」，3.4% 的盘由「温热 / 需壬水」变成「湿滞 / 需丙火」——闷蒸之局判成「加火来蒸」，等于往蒸笼底下添柴，还顺手把 `favor` 首位换掉。现单列 `湿热` 一档（取水 / 壬 / 忌火），`KIND_NAME`、`DAY_FEEL` 五株日主同步；不热之湿（湿滞取丙火）一字未动。同一处旁白不再按「档名含不含寒」猜忌神（`湿滞` 会念成「要的不是更多的火，而是丙火」），改取 `NEED[kind].avoid`。回归锁：`test/tiaohou.test.mjs` 锁档位与取用、报告点名的两张盘（1935-06-06 / 1995-06-12）喜用仍含水、火没被顶到首位、水没被删成忌神、旁白忌神与 `avoidElement` 逐档对拍、档表三处不许留空。
  - P2 · 奇门「最终倾向」7/7 方向恒不判决策（`engine/qimen-interpret.js`）：`用神有 N 个候选` 也算未决项，而 YONG_SHEN 每个方向本就是「主用神 + 一两个辅用神」、辅用神必然落宫 ⇒ `unresolved` 恒非空，上一轮加的倾向分支一次也没跑过；主用神缺位时又被死门这类次级候选撑住，「用神未上盘」永不触发。现只看主用神是否上盘（缺位写 `主用神X未上盘`），`primary` 优先取主用神行，辅用神同盘不再算未决、候选清单仍在 ④ 逐条列出。回归锁：`test/qimen.test.mjs` 锁七个方向都出倾向、未决项为空、措辞仍是条件式；把开门从盘上摘掉，career 仍须退回未决并点名缺哪个。
  - P2 · `hour` 守卫把 `name` 自己宣传的生辰路径封死（`index.js`）：0.61.2 把 `hour` 限给 `chenggu / xiaoliuren`，而 name 的 schema 明写「年/月/日 + 时/分」，`{ system:"name", year, month, day, hour }` 被宿主当场拦下。白名单补 `name`，`minute` 单列只给 name；其它体系传 `hour / minute / date` 仍报错（收了不看会静默排出另一张盘）。回归锁：`test/args.test.mjs`。
  - P2 · 句柄里的 `hour / date / mode` 让「带 handle 换 system」直接报错（`engine/handle.js`、`index.js`）：文档主推 `{ handle, system:"ziwei" }`，而称骨与小六壬的句柄必带 `hour`、convert / 梅花 / 小六壬必带 `mode`；并回参数后宿主按「用户本轮误传」拦下——上一张盘的输入挡住了这一张盘。新增 `SYSTEM_KEYS` 与 `pruneForeignKeys(merged, owned)`：换体系时剔掉新体系不读、本轮又没显式重给的键（`hour / minute / date / mode / action`），显式重给的照旧拦。顺带把联网解析的 `geo` 详情排除出句柄（`display_name` 换个语种就换一把句柄），只留 `longitude`。回归锁：`test/handle.test.mjs` 锁换体系后的新句柄不带上一张盘的 `hour`、一句话改参换体系同一条尺，`test/shadow.test.mjs` 锁 geo 文案不同而经度相同仍是同一张影子盘。
  - P2 · schema 漏 `upper`，梅花数字起卦在工具面不可表达（`index.js`）：引擎读 `args.upper`，schema 只有 `lower / changing`，模型照 schema 组参永远起不出数字卦，而 `mode` 的说明还在教「数字起卦需 upper/lower」。补 `upper` 并写明与 `lower` 成对；同处加一条清单断言——从 `engine/index.js` 逐个扫 `args.*`，凡用户参数都必须在 schema 里声明（`geo / shadowVersion / schools` 三个宿主内部键单列），并给扫描设条数下限，防止「扫不到键」反而空过。回归锁：`test/guard-inputs.test.mjs` ⑭ 与「按 schema 组参能起出数字卦」「数字卦与引擎直连同卦」。
  - P3 · geo 为挡「中山区」把 `县` 一起拉黑（`engine/geo.js`）：`长沙县 / 乌鲁木齐县 / 承德县` 整条解析失败，真太阳时被静默取消，摘要还写「未提供出生地或经度」。`NOT_CITY_AFTER` 去掉 `县`（县名多与辖它的市同名、县城就在城区边上，按本市经度估算比判「未匹配」准得多），`区` 与 `镇 / 乡 / 路` 仍挡（重庆开州区真有一个长沙镇）；命中县档时 `level` 写「区县」、`note` 说明借用城区经度。回归锁：`test/tool-geo.test.mjs` ⑦ 四条县名 + note 文案 + 工具层「长沙县」拿到 112.94 并进摘要、不再说「没查到」。
  - P2 · `parseYmd` 没有年份闸（`engine/datetime.js`、`engine/validate.js`、`engine/zeri.js`）：`parseDateTime` 早就有 1600–2400，`parseYmd` 只查月/日，于是小六壬 `date:'0000-01-01' / '1500-01-01' / '2500-06-01' / '9999-12-31'` 静默出盘；择日越界虽然报错，文案却甩锅「黄历 的 year 超出支持范围」（`2400-12-30` 起算 +3 天也这样）。`parseYmd` 复用同一对 `MIN_YEAR / MAX_YEAR`，择日改用自己的 `who` 与字段名。回归锁：`test/guard-inputs.test.mjs` ⑮ 逐值 `E_RANGE`、两端点仍可排、闸的边界等于 `validate` 的常量、择日文案点名 `startDate` 且不再提黄历。
  - P2 · 晚子时换日越过 1600–2400 边界（`engine/meihua.js`、`engine/xiaoliuren.js`、`engine/chenggu.js`、新增 `assertShifted`）：`2400-12-31T23:30` 通过入参校验后被整体搬到 2401 出盘，而直接填 `2401-01-01T00:30` 会被 `E_RANGE` 拒——同一张盘「换日就通、直填就拒」。三处换日统一走 `assertShifted`，报错点名是换日所致。回归锁：`test/guard-inputs.test.mjs` ⑮ 逐体系 `E_RANGE` 且文案含「晚子时按次日归后」。
  - P2 · 三奇入墓换表后知识库与 README 仍教旧表（`engine/interpret-knowledge.js`、`README.md`）：盘面说「乙阴木墓于戌，戌在乾六宫」，同一页知识库说「乙木墓未（坤二）」，而且已经打进分块与单文件页、用户直接可见。词条改成辛/戌（乾六）、丁/丑（艮八）并写明「阴干取墓」口径，README 两处同步。回归锁：`test/interpret-knowledge.test.mjs` 的期望值由 `LIUYI_RU_MU` / `ruMuOf` 现推，改表不改文案立刻挂。
  - P3 · 次级入口仍抛裸 TypeError、六爻 `lines` 非数组仍静默随机（`engine/liuyao.js`、`engine/tarot.js`、`engine/name.js`、`engine/convert.js`）：上一轮只修了 7 个 `build*` 主入口。`yongshenOf(r, null)` 一路走到读 `opts.direction`，`hexBody(null)`、name / convert 的空参数同样炸；更坏的是 `lines` 传字符串或对象时被当成「没给」，悄悄换成随机摇卦——用户以为排的是自己那六爻。八处次入口统一 `assertObject` / 显式报错，爻值这一族的码统一 `E_LINES`（长度不对不再改随机）。回归锁：`test/guard-inputs.test.mjs` ⑯ 11 组坏形状逐个 `E_INPUT`、文案既说「收到什么」也说「该传什么」、四条正常路径照旧出盘、留空 `lines` 仍走随机摇卦；`test/args.test.mjs` 从工具面走四个坏形状，两侧码一致（同一个错换个入口进来不能换码）。
  - P3 · 影子盘 `asOf` 归一不彻底（`engine/index.js`、`engine/ziwei.js`）：`asOf:'2030-01-01'`（补 12:00）与 `'2030-01-01T12:00'` 出的盘逐字段相同、`baseId` 与句柄却各一套；首尾空格仍 `E_ASOF`（`datetime` 是 trim 的）；`shadowParams` 仍吞自有 `__proto__` 键（`canonicalJson` 已避过这个坑）。新增 `normalizeAsOf`（trim → `asOfParts` → 只给日期补 12:00），排盘、句柄、影子盘指纹与 `checkAsOf` 共用这一把尺；`asOfParts` 与 datetime 一样 trim；没给 `asOf` 时一个键都不加（`null` 整段进句柄等于给所有旧深链换身份）；`shadowParams` 一律 `defineProperty` 写键。回归锁：`test/shadow.test.mjs` ⑨ 三种写法同句柄同 `baseId`、整张盘 JSON 全等，反向锁 `00:00 / 12:30 / 次日 / 不钉 asOf` 各得不同身份，句柄回放同盘、纯空格按「没钉」处理、`__proto__` 不再撞指纹。深链那一侧不需要新断言：`test/bridge.test.mjs` 的「句柄原样进链接」与「参数往返一致」就是这条的探针——归一化最初写错位置（放进 `computeRaw` 而影子盘尾巴在 `compute`）时，就是这里先变红的。
  - P3 · 六壬伏吟自刑兜底没换到「另一个」（`engine/daliuren.js`）：有克伏吟的初传常常就是第 1 课上神，兜底再取干上神 ⇒ 218 盘自刑伏吟里 74 盘（34%）中传 == 初传（`2026-01-01T01:30` → 辰/辰/戌）。兜底改为在干上 / 支上两个候选里取与初传不同的那个，仍无解才回退。回归锁：`test/daliuren.test.mjs` 锁点名盘不再辰/辰/戌、末传取冲，并扫 400 天 × 12 时辰（4800 盘）自刑伏吟零撞车。
  - P3 · 生时校正两条（`engine/rectify.js`）：`[{year:1601},{year:2399}]` 是合法输入却跑 1267ms——窗口按事件年份逐年排盘，每个候选排 799 年流年（30 年跨度只要 9ms）。加 `MAX_SPAN = 120` 上限，报错里写清实算区间；另一条是出生前的事件此前照样进窗口并计分（`age` 为负），出生 1990 报 1985 会污染排名，现早于出生年直接 `E_INPUT`。回归锁：`test/guard-inputs.test.mjs` ④ 锁两条报错、120 年整窗仍放行、合法调用不再跑到秒级、窗口文案与实算区间同源。
  - P3 · 数字串形式的显式经度被联网解析顶掉（`index.js`、`engine/index.js`）：`{ address, geocode:'online', longitude:'87.6' }` 解析成 121.5，改成 number 才正常——上一轮「保留用户 longitude」只保护了 number 类型，而解析前的判定读的是 `typeof === 'number'`。宿主在地址解析之前先调 `normalizeLongitudes`（`'87.6'` → 87.6；非十进制或超范围当场 `E_RANGE`，且不发网络请求）。回归锁：`test/tool-geo.test.mjs` ⑧ 锁数字串与数字两条路同盘、显式经度在场时零次联网、没给经度时联网解析照旧生效。
  - 体积：这两轮的守卫与 geo 新增的 23 个地级市坐标（286 → 309）随 `COMMON` 进每一块，`bazi / hepan / ziwei` 由 223.9 / 223.1 / 219.8KB 涨到 228.5 / 227.4 / 223.9KB（gzip）⇒ `test/chunks.test.mjs` 的分块线 228 → 232KB，注释里写明抬的是守卫与坐标表、不是新库，下一次再往这三块塞引擎就得拆块；CI 侧 `check-bundle.mjs` 的 260KB 单块硬墙与 2.75MB 总量墙不变。
- **回归锁与基线**（`test/*`、`test/assertion-baseline.json`）：塔罗测试从「非法张数静默折 3」改为「非法张数逐值报 `E_INPUT`」，那 4 组行为断言是有意替换、不是删除；两轮修复落地后基线更新为 **154 个文件 / 7880 条断言**（7718 → 7865 → 7880，全是新增的行为断言，没有删除或注释掉的旧断言）。

- **发版前复查又抓到两处边界**（`engine/bazi.js`、`engine/daliuren.js`、`engine/qimen.js`、`engine/ziwei.js`、`engine/convert.js`、`test/guard-inputs.test.mjs`、`test/fuzz.test.mjs`）：
  - 晚子时换日跨出 1600–2400：`2400-12-31T23:30` 在八字 / 大六壬 / 奇门（`lateZiHourMode:'next-day'`）/ 紫微（`lateZishi:'next-day'`）会被整体搬到 2401 继续出盘，而直填 `2401-01-01` 早被 `E_RANGE` 拒——同一张盘两套资格。四处统一走 `assertShifted`，报错点名「晚子时按次日归后落到 2401-01-01」；`22:30`、显式 `lateZi:false`、奇门 same-day、紫微 current-day 照旧可排。
  - 农历 2400 年末（腊月 1–29 日）换算到公历 2401 时，原先一路走到 `buildAlmanac` 才抛「黄历 的 year 超出支持范围」（`E_INPUT`），把目标越界说成黄历的错；现 `convert` 在换算后先校验目标公历，报 `E_RANGE` 并点名「农历 2400 年腊月29日换算得到的公历日期 2401-02-12 超出可计算范围（1600–2400）」。
  - 回归锁：`test/guard-inputs.test.mjs` ⑰⑱ 共 15 条（四体系越界文案、三套不换日照旧、convert 越界与边界内）；`test/fuzz.test.mjs` 边界日期改用 22:59，越界行为由 guard 测试单独钉住。

## 0.61.2（2026-11-03，已发布）

> 本版主题：输入与状态 bug 批——跨盘残留、历史漏参、生时校正跟错盘、K 线出生地失效等 13 处，全部有真机回归锁；排盘引擎与历算口径一字未动。

> 已发布：npm `dsh-metaphysics@0.61.2`，shasum `cd9281c6a9f9fbb9c3879b075877a3486f8c2257`，100 个文件；tag `v0.61.2` 已推，GitHub release 已建，tarball 已下载核对。

- **0.61.1 之后又查出的一批输入与状态 bug**（`src/app.js`、`src/web-ui.js`、`src/panel-kit.js`、`test/date-input.test.mjs`、`test/features.test.mjs`、`tools/e2e-dom.mjs`、`tools/e2e-panel.mjs`）：
  - 现象一（面板 · 日期被截断）：0.61.1 把日期框改成受控输入后，打字过程中一解析出合法日期就 `props.onChange`，父组件回写 `value` 把草稿冲掉——敲 `1990-05-12`，中途 `1990-05-1` 被补成 `1990-05-01`，再敲 `2` 丢位，最终**静默排成 1 日**。`page.fill` 一次写整串测不出来，真实键盘逐字输入必现。
  - 现象二（独立页 · 藏起来的字段还在拦人）：塔罗、人格两个体系把日期框隐藏了，但 `run()` 仍拿 `usesTimeInput()` 校验日期——日期框一旦为空，点「抽牌」就被「请填写公历日期」挡住，且无从下手。
  - 现象三（独立页 · 跨盘残留）：验前事的自评、贴合度与生时校正的候选时辰是模块级变量，换一张盘只重绘不清空，旧候选时辰会贴在另一张盘下面。
  - 现象四（面板 · 历史记成上一张盘）：切体系 / 看示例 / 载入档案都是「同一个 handler 里先 `setState` 再 `run`」，历史条目读的却是渲染闭包里的旧 `date/time/gender/address`；「时辰未知」的三柱盘重放后被当成正午出生；`localStorage` 里旧版本或半截写入的坏条目会让 `x.date.slice` 抛错，整块面板白屏。
  - 现象五（面板 · 生时校正跟错盘）：反推候选时辰时用的是表单此刻的日期/性别/出生地，而不是屏幕上这张盘的值；档案没存出生地时会沿用上一个地址。
  - 现象六（独立页 · 小六壬）：时刻框被清空时 `Number('') === 0`，悄悄按子时起课，而不是退回正午。
  - 现象七（面板 · 合盘重放排成另一个人）：合盘历史只记主方生日，没记对方（及第三方）的生日、性别、出生地；点旧条目时 `run()` 读的是表单里此刻的对方资料，排出来的已不是当初那张盘。更隐蔽的是两条「主方相同、对方不同」的合盘会被 `sameEntry` 当成重复条目，短的一条被直接顶掉。
  - 现象八（独立页 · 生时校正跟错盘）：排完盘后只改表单的性别 / 出生地 / 真太阳时 / 晚子时（不重新排盘），再点「计算候选时辰」，`doRectify()` 读的是表单此刻的值，候选时辰会按另一套输入反推，与屏幕上这张盘对不上。
  - 现象九（独立页 · 档案把上一个地址带进来）：档案允许不填出生地，但「载入」与「改名读回」只在字段非空时才写回输入框；上一张盘的地址留在框里，这张档案随即按别人的地方算真太阳时。点「改名」再「更新」还会把那个错地址存进档案，从此固定下来。
  - 现象十（面板 · 历史漏记两个开关）：真太阳时与晚子时都会改变时柱，历史条目却只记生日 / 时刻 / 性别 / 出生地。排完盘再拨动开关、点回旧条目，重放会跟着表单此刻的勾选重算；两条只差开关的盘还会被 `sameEntry` 当成重复条目顶掉。
  - 现象十一（人生K线 · 出生地不起作用）：K 线页是出生盘，表单给着性别、出生地、真太阳时与晚子时，但 `run()` 只对八字 / 紫微 / 合盘传地址，K 线拿不到经度——出生地填了等于没填，真太阳时开关也跟着失效；同一份输入在八字页与 K 线页可能算出不同的时柱。
  - 现象十二（档案 · 两个开关没入档）：命盘档案只存了生日 / 时刻 / 性别 / 出生地，真太阳时与晚子时没存。存卡时关着这两个开关，过几天载入，重排却跟着表单此刻的勾选走；档案层 `profFromForm` 也没把开关带出来（面板、独立页两端同时缺）。旧档案因此永远按「都开」的默认处理，而不是表单此刻的状态。
  - 现象十三（面板 · 历史漏记各体系自己的输入）：历史条目只记了各体系共用的生日 / 时刻 / 性别 / 出生地，奇门流派与晚子时、择日事项 / 天数 / 属相 / 候选日、小六壬起课方式与三个数、K 线算到几岁、风水看什么 / 坐向 / 运、起名方式 / 姓 / 名 / 候选数、公农历转换方向 / 农历日 / 闰月，全都没进条目。点回旧条目时按表单此刻的值重算，看到的已不是当初那张；`sameEntry` 也没比这些参数与六爻方向 / 张数、梅花动爻，两条输入不同的盘会被当成重复条目顶掉。
  - 改法：面板日期框打字只写草稿，提交只发生在失焦 / 回车（并补真机逐字输入断言）；独立页的日期显隐与校验共用 `usesTimeInput()` 一处判断；每次新盘成功落盘前清空 `pastMarks / pastFit / rectOut`；历史条目改记本次实际生效的输入（覆盖值 `dt/genderV/addressV`），新增 `hourUnknown` 字段并纳入去重与重放，读入时过滤非对象条目，渲染对缺失字段做兜底；生时校正改用 `result.at / result.gender / result.address / trueSolar / lateZi` 快照（面板与独立页各一套，独立页把这几项一并存进 `last`）；档案载入与改名读回都把 `date / time / gender / address` 无条件写回输入框（空出生地按空字符串覆盖，面板此前已经是这个口径）；小六壬按 `HH:` 正则取小时，取不到退回 12；历史条目补记 `trueSolar / lateZi` 并在 `sameEntry` 里按「缺字段＝默认开」比对，`replay` 时一并还原（旧条目缺字段则保持表单现状）；人生K线并入出生盘分支，与八字共用同一段「性别 + 出生地 → 经纬度 → 真太阳时」透传（面板与独立页各一处，`cross` 仍只给八字 / 紫微）；合盘历史把 `hpChart / partnerDate / partnerTime / partnerGender / partnerAddress / thirdOn / p2Date / p2Time / p2Gender / p2Address` 一并存下，`sameEntry` 比对它们，`replay` 逐项还原（旧条目缺字段时不动当前值）；档案层 `profFromForm` 落 `trueSolar / lateZi`，面板存卡、载入（含 `run` 覆盖参数）与独立页载入 / 存卡都带上这两个开关，旧档案缺字段按默认「都开」；各体系自己的输入（奇门流派 / 晚子时、择日事项 / 天数 / 属相 / 候选日、小六壬方式与三个数、K 线岁数、风水模式 / 运 / 坐向、起名模式 / 姓 / 名 / 候选数、转换方向 / 农历日 / 闰月）一并存入历史并进 `sameEntry`，`replay` 按条目类型逐项还原（旧条目缺字段则不动表单）；六爻 `direction / count` 与梅花 `changing` 也进去重比对。
  - 回归锁：`test/date-input.test.mjs` 新增 19 条口径断言（打字不提交、显隐与校验同源、清空模块状态、历史参数、坏条目过滤、独立页校正按 `last` 快照、档案空地址清残留、K 线并入出生盘分支等）；`test/features.test.mjs` 新增 14 条历史与档案断言（合盘条目带对方信息、去重比对对方信息、重放逐项还原、两个开关入历史 / 入去重 / 入重放、各体系参数入条目 / 入去重 / 入重放、档案层与两端都存两个开关）；`e2e-dom` 新增 15 项真机断言（逐字输入、日期空着抽塔罗、换盘清候选、改出生地不重排时候选不跟着换、无地址档案载入/改名不被上一张盘的地址带偏、K 线换地址结果随之变化）；`e2e-panel` 新增 19 项（含「看示例」历史条目必须是示例盘自己的参数；合盘换对方后两条历史并存，点回旧条目对方生日与时刻复原；两个开关重放复原；K 线的出生地生效；择日「开业 / 嫁娶」各占一条历史，点回旧条目事项与候选日复原）。把任一修复回退，对应断言都会转红——已逐条验过。
  - 随 0.61.2 发布；引擎与排盘口径未动，同一份输入出的盘与 0.61.1 逐字节相同。

- **自动发布还有一处同类漏口**（`tools/autopublish.mjs`、`test/autopublish.test.mjs`）：
  - 现象：0.61.1 的发布回写只改 CHANGELOG 与文档，源码指纹没变；主流程在「指纹与上次一致」处直接 return，连「本地是否领先远端」都没查——那一类假成功刚修完，更早的一处仍在积压永不推送的提交。
  - 改法：把领先数抽成 `aheadCount()`（`origin/main..HEAD` 全仓库只有这一处实现），指纹未变时也先查它：为 0 才报「无改动，跳过」，不为 0 就记「指纹未变（…），但本地领先远端 N 个提交，继续推送」并走同一条推送路径；`--dry-run` 的 reason 同步区分「源码/配置有改动」与「本地领先远端，只推送已提交的 commit」，日志不再把未变的指纹说成「检测到改动」。
  - 回归锁：新增 4 条源码级断言（指纹分支查领先、只有不领先才 return、领先时继续推、日志两种说法都在）＋1 条「`origin/main..HEAD` 只许有一份实现」的结构锁；把指纹分支回退成直接 return，前两条立刻转红。
  - 只动工具链，不进 npm 包（发版清单里没有它），排盘与页面产物一字未改。

## 0.61.1（2026-11-03，已发布）

> 已发布：npm `dsh-metaphysics@0.61.1`，shasum `0254c8a0d40ea443d9abe006c141a470234f6c04`，100 个文件；tag `v0.61.1` 指向发版提交 `3799db4` 并已推，GitHub release 已建，tarball 已下载核对。

> 本版主题：输入层与自证层——出生日期不再跟着浏览器区域翻顺序，产物自己说得出「这一版之后又改了什么」，顺带修掉自动发布的假成功。

- **排盘日期框固定成「年-月-日」**（`src/app.js`、`src/web-ui.js`、`tools/build-html.mjs`、新增 `test/date-input.test.mjs`）：
  - 现象：出生日一直用原生 `<input type="date">`，显示顺序由**浏览器区域**决定——中文环境给 `年/月/日`，一旦被切成 en-US 就变成 `月/日/年`，独立页与面板都跟着翻。用户按习惯填「5 月 12 日」，引擎收到的是 5 月 12 日还是 12 月 5 日，取决于宿主区域设置，排错盘还很难归因。
  - 改法：删掉原生 date 控件，改成文本输入 + 自制掩码（`maskDateText` / `normalizeDateText` / `isoDateOk` 三件套，面板与独立页各一份、口径逐字对齐）。输入时只留数字并自动补连字符（`19900512` → `1990-05-12`），同时认 `1990/5/12`、`1990年5月12日` 这类粘贴写法；失焦或回车才补零成 `YYYY-MM-DD` 并往引擎提交，非法值不提交。
  - 为什么中间态不补零：刚敲下 `1990-05-1` 就补成 `-01`，下一个 `2` 会拼成 `012` 被截掉，看起来「吞键」。掩码只放行 `^\d{0,4}(-\d{0,2}){0,2}$` 这种半成品，把补零推迟到失焦——这是真机逐字敲出来的 bug，不是假想。
  - 非法兜底：输入过程中非法就 `aria-invalid` 转红（模板加了对应 CSS），失焦时非法值**退回最近一次有效值**而不是留一个引擎不认的串；独立页点「排盘」时日期不合法直接给出「按年-月-日填写，例如 1990-05-12」并中止，面板则把同样的话写进提示区。合盘/三方/紫微飞星的四字段时间输入一并改。
  - 验证：`test/date-input.test.mjs` 用 `new Function` 把两处辅助函数从源码里取出来独立求值，13 条用例 × 2 入口 + 7 条「面板与独立页结果一致」+ 6 条模板守卫（`type="text"`、占位符写明顺序、全页不得再出现 `type="date"`）。断言基线 7524 → 7565（152 → 153 个文件）。Playwright 在真 Edge 里跑过逐字输入、带连字符输入、非法月日回退三条路径；`e2e-dom` 137 项通过。
  - 引擎、历算、口径一律未动：这是纯输入层修复，同一份 `YYYY-MM-DD` 进去，出的盘与改动前逐字节相同。桌面版 exe 里的 HTML 已随这次一并重建。

- **不发版本号，也要能自证改了什么**（新增 `tools/unreleased.mjs`、`test/unreleased.test.mjs`；接线 `tools/build-html.mjs`、`tools/build-client.mjs`、`src/app.js`）：
  - 起因就是上一条：日期输入的修复不动版本号，npm 仍是 0.61.0。于是用户手上的单文件页与桌面 exe——带没带这个修复——左上角都写着 `v0.61.0`，谁也没法回答「我这版到底新不新」。
  - 改法：把 CHANGELOG 的「未发布」段做成唯一数据源，构建时读出顶层粗体条目标题（遇到下一个 `##` 即止，嵌套子条目不算一条），三处消费：① 版本徽标旁加一枚小牌「另含 N 项未发版改动」，悬停 `title` 逐条列出；②「方法与验证」新增一段「本版之后又改了什么（版本号未变）」，逐条列出并指回 CHANGELOG；③ 面板错误边界的环境行在版本号后追加「未发版改动 N 项」，报错截图自带新旧判断。
  - 刻意不留第二份手写清单：清单为空时小牌与整段都不渲染（不会出现「另含 0 项」这种话）；窄屏 ≤640px 藏掉小牌，方法段的完整清单仍在，横向溢出 0px。
  - 顺手修掉一个够不到 AA 的新增文本：小牌是 11px 字，压在 `--panel2` 上，用 `--dim` 浅色档只有 4.41:1；改 `--ink2` 后浅 10.19:1 / 深 10.60:1，两条对比度断言一并进闸。
  - 验证：34 条断言（解析口径 7 条含 CRLF / null / 段末收口，渲染 11 条含转义与空清单，真 CHANGELOG 4 条，产物接线与对比度若干）。把小牌与方法段从 `build-html` 里摘掉，4 条立刻转红。
  - 引擎与排盘口径未动；`client.js` 285KB / gzip 87KB（+1KB，多的是那份 JSON 清单）。

- **自动发布修掉「假成功」**（`tools/autopublish.mjs`、`test/autopublish.test.mjs`）：
  - 现象：发版提交只落在本地时，autopublish 看到「允许清单内没有改动」就直接返回，主流程却照样打印「完成：已推送 main」。远端整整落后一个版本，日志仍是绿的。
  - 改法：无改动时先查 `git rev-list --count origin/main..HEAD`——本地领先就继续走 push，不领先才报「本轮不推送」；`commitAndPush` 返回布尔，主流程按实际结果分别记录「已推送」与「无改动可推送」。
  - 回归锁：新增 6 条源码级断言（领先检查、继续推送、`return false`、`return true`、分别报告、不再无条件打印）；把修复回退回事故版本，前五条都会红。
  - 只动工具链，不进 npm 包（发版清单里没有它），只随本版一并记录。

## 0.61.0（2026-11-03，已发布）

> 已发布：npm `dsh-metaphysics@0.61.0`，shasum `5498dde08a729076a69b77c3e33eb62262cf0950`，100 个文件；tag `v0.61.0` 已推（指向发版提交 `8644f6b`，其后为自动发布修复与文档回写），tarball 已下载核对。

> 本版主题（续）：择日不再只数建除宜忌——按《协纪辨方书》卷十一「用事」的逐条神煞计分，再按卷十「宜忌」的六等与德神制化定轻重，起法逐条可回溯。随 0.61.0 发布。

- **择日神煞宜忌层**（新增 `engine/zeri-shensha.js`，约 15KB）：
  - 数据分两层：卷十一「用事」16 条事项的宜／忌神煞名单逐字照录；起法分散在卷四（建除十二神、月建、月厌、厌对、阴阳不将）、卷五（天德、月德、天德合、月德合、月空、天恩、天赦、天愿、母仓、月恩、四相、时德、王官守相民日、四击、九空、五墓、四耗、四废、四忌四穷、九坎九焦、五虚、八风触水龙、宝义制专伐日、八专、无禄、重日五合五离、解神、复日、鸣吠、鸣吠对）、卷六（三合、临日、驿马、劫煞、灾煞、月煞、月刑、月害、大时、游祸、天吏、六合、兵吉、五富、天仓、天贼、要安、玉宇、金堂、敬安、普护、福生、圣心、益后、续世、阳德、阴德、天马、兵禁、地囊、土符、大煞、归忌、往亡、月忌日）与卷九「立成」。
  - 27 个择日事项全部映射到卷十一的 16 条事项；无对应条的走建除简表，映射依据写在 `ZERI_SHENSHA_BASIS`。
  - 没有可靠起法的条目（土王用事后、血忌、伏社日、八风、气往亡、专日、伐日、四离、四绝、上朔）逐日 `shensha.unsupported` 列出，不猜、不计分。
  - 条件神煞按原文条件：天狗只作「申月戌日」；阴阳不将按十二月逐支表；归忌按孟仲季月；三合按局；解神按冲月建（与紫微按月安的解神区分）。
- **打分口径**（`engine/zeri.js`）：
  - 建除宜 +2、建除忌 −2；神煞宜每颗 +2（单类封顶 +4）；神煞忌、日忌、农历日忌各每颗 −2（各封顶 −4）；当事人属相逢冲 −2 并径直排除。
  - 结果逐日新增 `shensha`（月支、建除神、当日神煞名单、宜／忌分组、未实现条目），顶层新增 `shenshaRef`（底本、卷次、未实现清单）。
  - `meta.scope` 与 `disclaimer` 明写：六等判词与德神制化取自卷十，吉／凶权重与比值阈值是本仓校准（不是古籍常数），等第表未逐格数字化。
- **接线（全链路）**：`engine/index.js` 摘要加「神煞依据／起法／未实现起法」一行；`src/panel-kit.js` 择日面板同步显示；`index.js` 工具描述改写为「宜忌依卷十一逐条」。
- **闸门**（新增 `test/zeri-shensha.test.mjs` 11 条 + `test/fixtures/zeri-sources.json`）：
  - 原文锁：夹具里的卷十一原文按最长优先词典切词，逐条等于 `SHENSHA_LISTS` 的宜／忌数组——表被「顺手补齐」即红；夹具条数与库的条目数必须一致。
  - 27 事项映射完整性；2026-10-29（戌月丙子，满／民日／灾煞）、12-01（亥月己酉，开／灾煞）、12-15（子月癸亥，闭／四穷）、12-22（子月庚午，破／月破／大耗、冲鼠）四组逐日落星；天狗只申月戌日；土王用事后只进未实现清单。
  - 打分锁见下条「卷十」；`compare.best` 落在 12-01。
  - **审查修掉一个展示 bug**：余忌命中时 `verdictOf` 把对象数组直接 `join`，逐日断语渲染成「…的余忌之列（[object Object]）」；改为取神煞名，并补两条回归断言（点名「灾煞」、全文无 `[object Object]`）。
  - 断言基线 7496 → 7518（151 → 152 个文件；新增 22 条卷十测试）。
- **卷十「宜忌」六等与德神制化**（继续 `engine/zeri-shensha.js`）：
  - 六等判词逐字取卷十 4853 行：上（吉足胜凶）、上次（吉足抵凶，遇德从宜、不遇从宜亦从忌）、中（吉不抵凶，遇德则吉胜，不遇从忌）、中次（凶胜于吉，遇德始相抵）、下（凶又逢凶，遇德从忌、不遇诸事皆忌）、下下（凶叠大凶，遇德仍诸事皆忌），另立「平」（吉凶相抵）。原文「参」在底本误作「防」，`GRADE_TEXT` 按文义还字，夹具注明。
  - 德神制化按卷十各条按语分三类：`keJie` 德神可解（月建、满日、闭日、劫煞、灾煞、月煞、月刑、月害、月厌、大时、天吏、厌对、复日）、`buJie` 德神犹忌（月破、天狗、游祸、四忌、四穷、往亡）、`wuShe` 与德义不相属（九坎、九焦、土符、地囊、归忌、血忌）。「止忌……」的余忌按事项落回 `residualEntries`（灾煞等止忌求医疗病、月厌止忌婚嫁出行等、月建止忌兴造破土）。
  - 月日条件按原文：满日值守日／相日、闭日值王日／官日、劫煞／灾煞／大时／天吏按孟仲季月值某建除、月刑「巳月值平日」、月害「卯酉月值除日守日、丑未月值执日大时」、月厌「寅申月值成日、丑未月值开日」。德神名单不满足条件或不在名单内，仍按不遇德处理。
  - 月厌叠月破或灾煞时直接判下下·诸事皆忌，遇德也不解。
  - 输出：逐日新增 `grade`（等第、判词、宜忌方向、德神、吉／凶合分、比值、可解／仍忌／犹忌清单、是否叠凶），顶层 `shenshaRef` 新增 `juan10`；`meta.scope` 与 `disclaimer` 明写权重／阈值是本仓校准、等第表未逐格数字化。
  - 接线：`engine/index.js` 摘要逐日附「卷十等第·宜忌方向」并新增一行卷十依据；`src/panel-kit.js` 候选表新增「卷十等第」列与依据脚注；`test/fixtures/zeri-juan10.json` 存判词与 25 条德神制化关键词。
  - 评分锁随六等改写：10-29 开业 +4 推荐·上、12-01 +3 推荐·上、12-08 0 平平·平、12-15 −5 回避·下·诸事皆忌、12-22 排除；灾煞遇德对开业可解，对求医仍落余忌。

> 本版主题：紫微的杂曜不再只有 49 颗简盘——十二颗缺的星按安星诀逐颗落地，诀文一并交给使用者和别家模型。随 0.61.0 发布。

- **杂曜安星库**（新增 `engine/ziwei-zuoyao.js`，11KB）：
  - 补上通行简盘长期缺的十二颗：解神、天巫、天月、阴煞（按生月）；天官、天福、天厨（按生年干）；蜚廉（按生年支）；天德、年解（按生年支起宫顺／逆）；天才（命宫＋生年支）、天寿（身宫＋生年支）。八颗走十干／十二月明表，四颗走起宫顺逆公式；分类为吉星 7、煞星 3、杂曜 2。
  - 三条硬口径：**至少两处独立站点同表才收**（37 条链接去重后 9 个来源，每颗都有 ≥2 个不同站点）；**诀文照录不改写**，转抄例子与自家诀文相抵时以诀文为准（天才一例三源同诀、转抄却写「巳宫安天才」，判为笔误）；**同名异星绝不合并**——蜚廉（年支）≠ 博士十二神的飞廉、按年安的天德 ≠ 岁前十二神的天德、年解 ≠ 按月安的解神（月解），三组在盘上各处其位。
  - 龙德、月德刻意不入表，`ZUOYAO_SKIPPED` 逐颗写明 20 字以上理由（与岁前十二神同名同宫、并入即重复安星），面板与复制提问都看得到这份「没收清单」。
- **新开关 `zuoyaoSchool`（默认 `minimal`，盘面一字不变）**（`engine/ziwei.js`、`engine/index.js`、`index.js`、`engine/diff.js`）：
  - `minimal` 仍是通行简盘 49 颗；`full` 按上面的诀补入十二颗，共 61 颗。默认不排的理由写在开关表注释里：星数一变，旧盘的宫位句柄与已存命盘会静默变盘。
  - 结果新增 `zuoyao` 层：`mode / starTotal / placed[]`（星名、地支、宫名、定宫依据、基本义、入庙标记）`/ verses`（一行一颗的诀文块）`/ skipped`；`rules.schools` 并列入杂曜口径，`rules.zuoyao` 两档各给一句该怎么打开。
  - 口径并排（紫微 12 → 13 组）新增「杂曜：49 颗简盘 / 61 颗全表」；`【流派】` 行只在显式改动时出现。
- **修掉一个真 bug**：`zuoyaoBranch` 的公式曜原先只挡命宫／身宫，缺生年支时 `fix(NaN)` 照样返回「一个宫」，天德、年解会带着 NaN 落宫被塞进盘里（面板宫名渲染成空）。现在四颗公式曜都先验生年支，并对非有限值兜底返回 null——缺依据就整颗不排，绝不安到默认宫。
- **接线（全链路）**：`engine/followup.js` 复制提问在全表盘后附「紫微杂曜安星诀」段（本盘落宫 + 诀文 + 未另立清单，并明写属通行说、不是《全书》原文），简盘不塞这段；`src/panel-kit.js` 宫位与详情两处加「庙」标，盘下方新增可折叠的诀文块，默认档另给一句白话说明怎么开全表；独立页 `命理排盘.html` 同源带出。
- **口径落成知识卡**（`engine/interpret-knowledge.js` 新增 `ziwei-zaoyao`）：挂 `overall / work / health`——`overall` 已被三方四正、破格、四化三张占满（每维最多 3 张），而天官、天福、天厨主贵显与俸禄（事业／公职），天月、解神、阴煞主病符与消灾（疾厄），落宫实质就落在这两维。`engine/citations.js` 记为 `general`（通行说）：维基文库本《紫微斗数全书》卷一是赋文与格局、卷二是安身命例，未见这套安星诀，故不署《全书》原文。
- **体积**：杂曜库随紫微引擎进 `ziwei / bazi / hepan` 三块（+11KB 源码 / +6.5KB gzip），三块原本就贴着 220KB 的 gzip 分块线（最紧一块 213KB），加完变 219.6 / 223.7 / 222.9KB → `test/chunks.test.mjs` 的上限抬到 228KB，并把「再加库就该拆块」写进注释；入口 `client.js` 不受影响。18 块合计 gzip 2.38MB。
- **闸门**（新增 `test/ziwei-zuoyao.test.mjs` 96 条）：
  - 期望值全部由诀文里的地支字重导（`byBranch`），不复制引擎表内数字——表被人「顺手补齐」就红；解神另用第二式（月建对冲）逐月独立互核；新库反过来反查旧表（破碎／华盖／咸池三组三合位）。
  - 面板不靠源码 grep 交差：用 `vm` 把真 `src/panel-kit.js` 载进沙箱、拿真 `compute` 渲两档盘，逐条数「已排 12 颗／12 个 chip／入庙标记／诀文折叠且写明属通行说／11 行诀文／龙德月德未另立／简盘无诀文块／全页无 `undefined`·`NaN`」；撤掉模板里的 `${zyHTML}` 即 4 条红。
  - `placeZuoyao` 缺依据整颗跳过（12／8／9／11／0 五档）、入庙标记只在庙地名单内出现、诀文块一行一颗；开关默认与两档盘面（49 vs 61、简盘星名必为全表子集、盘上落宫 = 库复算落宫）、三组同名异星并存不合并。
  - **新增「接线漏检锁」**（`test/ziwei-schools.test.mjs`）：每个流派开关都必须同时出现在工具 schema、`compute` 平铺透传与口径并排三处——本轮先只加了引擎侧，正是这条能拦住「AI 传了参数但服务端不认」；开关计数由「10」改为键名清单，规则行由「列全九项」改为十一类逐条。
  - 连带更新：`citations.test.mjs` 通行说计数 7 → 8（有意设的锁），并按 `npm run build:citations` 重建 `docs/citations.html`。断言基线 7350 → 7496（150 → 151 个文件）。

> 本版主题（续）：起名字库从「够用」扩到「常见姓名基本不缺字」。随 0.61.0 发布。

- **字库扩容：391 → 1062 字**（`engine/name-extra.js`、`engine/name.js`、`engine/name-data.js`）：
  - 新增 671 个常用名用字，按五行分组：木 210、火 89、土 89、金 143、水 140；原 391 字一字未删，`CHAR_LIB` 与 `READING` 用展开合并，原有调用方与数据形状不变。
  - 补上此前大面积缺字的真实姓名常用字：伟、杰、军、强、丽、娜、秀、英、敏、娟、凯、豪、虎、兵、仪、喆、靖、翊、芯等；`李伟杰`、`王丽娜`、`王秀英`、`张建国` 这类名字不再出现「未收录」。
  - 读音与康熙笔画由 Unihan `kRSUnicode` + 康熙部首笔画 + `kTraditionalVariant` 复算，不是手敲；繁体映射会串义的字按人名通行取法覆盖：千 3、才 3、发 12（發）、钟 17（鍾）、苏 22（蘇）、采 8、万 15、镌 18；长/兴/种按人名读法取 chang2/xing1/zhong4。
  - 未收录字仍不猜五行；扩库只增加「可判断」的字，不改变任何五行归类口径。

- **候选排序加「常用字优先」**（`engine/name.js`）：
  - 字库变大后，笔画讨巧的生僻字可能挤进候选；排序在「合喜用 → 两字异行」之后新增常用字档（两字都常用 > 一字常用 > 都不常用），再看五格与性别倾向。`suggestFor` 给未收录字的替换建议同样先挑常用字。
  - 常用字集合只用于加权排序，不参与五行判定；`notes` 里的排序说明同步改写。

- **闸门**（`test/names.test.mjs`、`test/name-wuge.test.mjs`）：
  - 字库规模改为 1000–1200 字双边界；新增 50 个真实姓名样本的覆盖率门槛（逐字查，缺字率 ≤5%，当前 123/123）。
  - 新增扩充字笔画锚点（千/才/发/钟/苏/采/万/镌/伟/丽/杰/凯/娟）与长/兴/种的读音锚点，防生成脚本回退。

> 本版主题（续）：六爻与梅花不再只有白话大意，盘面直接给出《周易》经文原文。

- **《周易》经文原文库**（`engine/yijing-text.js`）：64 卦辞 + 384 爻辞 + 乾用九 / 坤用六，共 386 条爻辞。
  - 原文照录，不改写、不意译；〔一作…〕标出 20 处古籍异文，只在原句后加括注，不动正文。
  - 三份公开底本互校生成（npm `@freizl/yijing`、npm `iching-shifa`、GitHub `liujuntao123/yijing`），逐条折叠简繁异体后投票：三源一致直采，两源一致取多数，三源互异与已知讹字逐条裁定，裁定只用《周易》本书互证（《彖》《小象》《系辞》引文）与通行注疏本，不引外书。
  - 投票确实抓到底本自身的错：`@freizl/yijing` 姤九五整句重复一次、大有九二误置同人六二「同人于宗，吝」；`iching-shifa` 把大有九二的爻题标成「六二」。爻题因此不抄底本，一律由卦画推出。
  - 取辞按京房体系：动爻取该爻爻辞，六爻皆变且为乾坤时补用九 / 用六，无动爻只给卦辞并写明「六爻皆静」。
- **六爻 / 梅花结果新增「经文原文」节**（`engine/liuyao.js`、`engine/meihua.js`、`engine/interpret.js`）：本卦卦辞 → 动爻爻辞 → 互卦卦辞（梅花）→ 变卦卦辞，排在白话大意之后、「落到生活里」之前；面板逐行转义渲染，无需新增样式，CLI 摘要（`interpretText`）自动带上。
- **复制提问把原文一起带走**（`engine/followup.js`）：交给别家模型的那段话里，盘面摘要之后新增「《周易》经文原文」段——只读结果里已算好的 `jing`，ASK 栈不多背这 12KB；非卦象体系不多塞一段。
- **体积**：这张表只进 `client.liuyao.js` 一块（gzip +12KB，该块 178KB），不进解释栈；其余 17 块体积不变，分块合计 2.33MB。
- **闸门**（`test/yijing-text.test.mjs` 64 条、`tools/check-bundle.mjs`）：
  - 结构自证：384 爻的爻题「九 / 六」逐位比对引擎卦画，爻题写法（初/上位在前、二三四五题在前）全部合京房例；386 条爻辞正文与 64 条卦辞两两不同——大车型错置永远回不来。
  - 接线：跑构建产物 `client.liuyao.js` 的 factory 出盘，锁住「漏配 `tools/build-client.mjs` 时分块静默没有经文」这一类；再加体积锁（表 ≤40KB、不得混进无关分块）。
  - 新闸门「模块顺序」：打包按 `ORDER` 顺序执行 IIFE，被依赖的模块必须排在前，否则取到 `undefined` 且不报错——本次踩到两次，现在由 `check-bundle` 拦。断言基线 7146 → 7213。

> 本版主题（续）：姓氏库从 129 姓扩到 998 姓 + 82 复姓，生僻姓的五格不再整块「算不了」。

- **姓氏库扩容**（新增 `engine/surname-data.js`，`engine/name-data.js` 改为从它摊开）：
  - 单姓 129 → **998**，复姓 13 → **82**；每行是「字 + 康熙笔画 + 拼音 + 声调」，`SURNAME_STROKES / SURNAME_READING / DOUBLE_SURNAMES` 三个旧出口的形状与调用方一字未改，`engine/name.js` 与面板不需要跟着改。
  - 笔画不是手敲：三份独立资料互证（康熙笔画表 / 起名用字表 / 姓氏词典），都缺时用 Unihan 的康熙部首结构值（部首本字画数 + 剩余画数）复算，两条独立路径对上才收；三份资料与旧表四票不一致时逐字人工裁定，理由写进模块头部注释（温 13、万 15（繁体萬）、赖 16（貝部九画，旧表作 20 是错的）、钟 17、迟 19、沈 8、岳 8、板 8、御 11 等 25 字）。瓮（瓮／甕差 10 画）取不定，宁缺不猜。
  - 71 个姓只给得出笔画、给不出唯一读法（乐 Lè/Yuè、查 Zhā/Chá、区 Ōu/Qū 这类多音），拼音一律留空——音韵检查照旧落空并点名缺哪个字，不拿一个可能错的读音去判「顺口」。覃/蔚/隗/柏/乐/能/查/石/尉九个姓另存又读，主读照算，盘面与摘要并列显示「姓又读 覃tan2」。
  - 复姓读音同样由姓氏词典连写（万俟 mòqí、单于 chányú、尉迟 yùchí、澹台 tántái、乐正 yuèzhēng），笔画按逐字康熙值：旧表 诸葛[15,15]、令狐[5,8]、慕容[14,10] 三处按资料改为 [16,15] / [5,9] / [15,10]。
  - **修掉一个真 bug**：`phonetics(fullName)` 原先只把全名第一个字当姓，复姓的第二字（诸葛的「葛」、尉迟的「迟」）走起名用字库，字库没有就整体报「没有读音数据」。现在 `phonetics(fullName, surnameLen)` 由调用方给出姓的字数，复姓逐字都能从姓氏表取读。
- **接线**：`engine/index.js` 摘要的【音韵】行带出又读；面板名字卡音韵行同样并列（`src/panel-kit.js`）；`tools/build-client.mjs` 把 `surname-data` 排在 `name-data` 之前、只挂进 `name` 一块（该块 gzip 143KB，其余 17 块体积不变）。
- **闸门**（新增 `test/name-surname-lib.test.mjs` 48 条）：
  - **常见姓覆盖 100%**：把三份姓氏资料并集里的 521 个常见姓**冻结成测试内的锚点串**（不拿本轮抓取结果当标准答案），逐个要求入表；扩容失败或日后删表都会红。
  - 形状与取值：4 列、笔画 1–40、拼音只含小写字母、**拼音为空 ⇔ 声调为 0**、无重复字；又读必须与主读不同且该姓已有主读。
  - 康熙笔画与读音锚点各一组（含被推翻的旧值 赖 20），复姓逐字笔画齐全、`万俟=moqi`、`单于=chanyu` 锚点。
  - 症状回归锁：撒/蹇/冼/戏/蒉/訾/昝/厍 这些原先五格「算不了」的姓现在都排得出天格 = 姓画 + 1；`compute` 端到端（生僻姓出五格、摘要带又读、候选按五格排序）。断言基线 7213 → 7261。

> 本版主题（续）：塔罗从「78 个名字 + 几个关键词」补成一套有底本、有出处、敢留空的牌义库。

- **78 张牌义库**（新增 `engine/tarot-cards.js`，16KB）：
  - 底本声明为 Rider-Waite-Smith（1909）系，牌义按黄金黎明一脉（Liber 777 公开对应表）取，三处独立资料互核；三源一致才入库，不一致的逐条裁定并把理由写进模块头注释。不同体系的牌义（托特／马赛）不并进同一句话。
  - 每张牌七个字段：英文名、牌面图像（中文白描 15–60 字，78 张全）、核心寓意（小阿卡纳 56 张各写一句，不复用通用句式）、元素、行星、星座、生命树源质。大阿卡纳 22 张全部给行星＋星座，小牌 2–10 共 36 张按三分相定星座（权杖＝白羊/狮子/射手，圣杯＝巨蟹/天蝎/双鱼，宝剑＝天秤/水瓶/双子，星币＝摩羯/金牛/处女）：2-4、5-7、8-10 依次落进这三个星座，同组三张各占该星座的第一／二／三旬，旬主星按迦勒底连续序（白羊一旬起火星）落定（例：权杖二＝火星在白羊第一旬，权杖四＝金星在白羊第三旬，圣杯九＝木星在双鱼第二旬）。
  - **三处明写的「不给」**：四张首牌只归源质不配单一星座；16 张宫廷牌不给占星对应——公开资料里两套映射（国王＝本位宫一派 vs 黄金黎明四元素层级一派）在多数花色上把国王与王后对调，本插件不合并两派，只给元素与角色定位（学徒与消息 / 推进与风格 / 滋养与吸引 / 掌控与承担）；22 条希伯来字母路径层整体不录入，因为它与牌义无关却最容易被抄错。
  - 占星对应全部由规则表算出（`SUIT_SIGNS` / `DECAN_PLANETS` / `SEPHIROTH` / `DECAN_CN`），不逐张手敲；手写的只有中文图像与核心寓意。生成脚本收进 `tools/gen-tarot-cards.mjs`，`node tools/gen-tarot-cards.mjs` 一条命令重生成，Temp 目录不再是这份数据的一部分底稿。
- **接线（全链路）**：`engine/tarot.js` 牌库与抽牌结果逐张带出新字段；`engine/index.js` 摘要每张牌补 `[英文名]` 与「牌面：…」一行；`engine/plain-summary.js` 顶部人话总结带出牌面图像与占星对应（宫廷牌改说「它在盘上顶的是「…」那个角色」）；`engine/event-prompt.js` 与 `engine/followup.js` 复制提问把核心义、占星对应／牌位角色、牌面图像一并带走；`src/panel-kit.js` 面板卡新增英文名牌与牌面白描段（配套两条样式）；`engine/interpret.js` 逐牌解读改写为「牌面上…，它对应的占星位置是…／它在这里顶的是「…」那个角色」。
- **口径落成知识卡**（`engine/interpret-knowledge.js` 新增 `tarot-correspondence`，`engine/citations.js` 同步收录）：塔罗解析文末「这套规则有多稳」会点名本盘涉及的旬位取法与「宫廷牌两派冲突故留空」，状态标签「文本·各家有异说」；`engine/tarot.js` 的 `systemNote` 同步说明，`engine/followup.js` 的追问骨架改为「逐牌（正逆/牌面/元素对应）」。
- **体积**：逐张牌库只挂在 `client.tarot.js` 一块（该块 gzip 176KB，未触 260KB 上限），不进公共解释栈——其余体系不背这 16KB。18 块合计 gzip 2.36MB。
- **闸门**（新增 `test/tarot-cards.test.mjs` 86 条）：
  - 数据自证：78 行形状、英文名纯 ASCII、图像 15–60 字、小牌核心 8–30 字且 **56 句互不相同**（防止回退成套话）、花色与元素逐张对 `SUITS` 一致。
  - 规则闸门：36 张小牌的星座／旬主星逐个按 `SUIT_SIGNS × DECAN_PLANETS` 反算比对，**旬位标注另用一张手抄的迦勒底旬主星表（12 星座 × 3 旬）独立反查**——牌上的行星在该星座实际主第几旬，标注就必须是第几旬；首牌与宫廷牌的「留空」本身是断言（配了星座就红）；22 张大牌的行星与星座逐张过庙旺规则（守护星落在本命宫）。另有 30 条冻结锚点（权杖四＝金星在白羊第三旬、圣杯九＝木星在双鱼第二旬等）与 5 条英文名、3 条源质锚点——换底本或改表都会红。
  - **修掉一个自相矛盾的标注**：旬位原先按「二三四→第一旬、五六七→第二旬、八十→第三旬」分组算，于是权杖三（太阳）与权杖二（火星）同标「白羊座第一旬」——而白羊第一旬的旬主是火星。实际口径是同组三张分居该星座的一／二／三旬，改为按组内序号取模；三源互核的是行星与星座，这一层错的只是标注文案。
  - 端到端：`compute` 摘要两行格式、`brief.sections`、逐牌解读文案、`buildEventPrompt`、面板 HTML（`vm` 里跑）五处都验；`systemNote` 必须提到宫廷牌。
  - 连带更新：`citations.test.mjs` 的通行说计数 6 → 7（这条计数是有意设的锁，新增卡片要显式改），并按 `npm run build:citations` 重建 `docs/citations.html`。断言基线 7261 → 7350。

## 0.60.0（2026-11-02，已发布）

> 已发布：npm `dsh-metaphysics@0.60.0`，shasum `6e126e8d84348f10945faa5e5759b454858d8f59`，94 个文件；tag `v0.60.0` 已推（指向发版提交 `3c92da1`，其后仅文档回写），GitHub release 已建。

> 本版主题：从「算得对」推进到「用得顺」。新增**我的命盘**（本机档案）与**复制提问**两条日常路径，并把历算、输入守卫、异步竞态、发布闸门里查出来的问题逐条修掉。新增能力不改变既有排盘口径；同一输入、同一 asOf 仍产出同一张盘。

- **我的命盘：一次录入，下次点卡出盘**（`src/panel-kit.js`、`src/app.js`、`src/web-ui.js`）：
  - 面板与离线单页共用一套实现与同一个存储键 `dsh-metaphysics/profiles-v1`：存的是出生日期、时刻、性别、出生地这些**输入**，不是结果；只落本机，不上传。
  - 卡片照市面排盘 App 的命盘列表：一张卡一个人，点卡直接出盘；改名、置顶、删除收在卡片右上角，悬停或键盘聚焦才出现，触屏常驻。置顶在前，其余按最近排过排序；最多 24 张，超出时淘汰最久没排的那张。
  - 档案来自 localStorage，按外部输入对待：逐字段验一遍，日期要真过日历，坏条目整条丢弃，不把 `undefined` 渲染进卡片；同 id 只留第一条。
  - 删除点两次才算；改名会把原称呼读回输入框，改完点「更新这张档案」覆盖原档，创建时间、使用次数与置顶状态不变。
  - 写入失败不再假装成功：`profilesPut` 报失败，删除／置顶／记次数也回滚到存储里的真实状态；浏览器完全没有 localStorage 时同样按失败回报——否则卡片从界面消失、下次进来又复活。
  - 旧版本或手改存储留下的「有日期没时刻」卡不再拿表单里现成的时刻顶上（那会排成另一个人），而是提示先补时刻；这种卡也不算「排过一次」。
  - 称呼框是裸 DOM：面板重绘与单页重绘都先把已输入的字存起来，翻置顶、切视图不会把称呼抹掉。

- **复制提问：把盘面和问题整理成一段话，交给任意 AI**（`engine/followup.js`、`engine/bridge.js`、`src/app.js`、`src/web-ui.js`）：
  - 追问框优先于「所问之事」：只读主问题时，命盘类没有这个输入框，复制出去的「所问」会永远是默认开场句。
  - 包里带上面板已算好的开场结论（直答／说人话），别的模型开场沿用同一口径；盘面摘要与回答骨架一并带上。
  - 打包失败时按钮给出「暂无可复制内容」并自动复原，不再毫无反应；切方向 / 重绘结果时追问框里已经输入的字保留。

- **输入守卫：坏参数不再静默变成另一张盘**（`engine/index.js`、`index.js`、`engine/handle.js`）：
  - 经度统一整形并校验：数字串转数字；非有限值或超出 −180…180 报 `E_RANGE`，不再走到真太阳时里炸成裸异常，也不再静默少一次修正。
  - 地址、问题、revise、ask、姓名等自由文本设长度上限——这些串会整段进句柄，不设限等于允许一次调用把结果撑到几百 KB。
  - `datetime` 的秒位真正校验；`asOf` 的小时与分钟必须在范围内，非法值不再被折回另一天。
  - 句柄增量拒绝 `__proto__` / `constructor` / `prototype` 键，避免改掉结果对象的原型。
  - 联网解析失败不写缓存：不会连着六小时把「解析失败」当成答案；风水不再请求出生地解析（经度对盘面没有影响，发给第三方是纯外泄）。
  - `detail` 只接受 `full` / `lean`，写了别的值不再被当成缺省静默放过。

- **历算修正**（`engine/calendar.js`、`engine/lunar.js`、`engine/dst.js`、`engine/ziwei.js`、`engine/trend.js`、`engine/random.js`、`engine/rectify.js`、`engine/zeri.js`）：
  - `jdToParts` 的分钟进位会让 23:59:45 塌回「当日 00:00」，日柱退一天；改为先归到整秒再向下取整分，拆出的那一天永远就是这一刻所在的那一天。
  - 农历的节气时刻被移了两次时（净偏移约 −12 分），节气落在午夜前后十几分钟内会少算一天，置闰整月错位；修正后 1917 年由「闰三」回到真历表「闰二」、1922 年由「闰六」回到「闰五」。
  - 夏令时换表日给出明确说明：起算日 02:00–03:00 的钟面读数在当年不存在，终止日 01:00–02:00 同一读数对应两个真实时刻——按哪种读法折算写进提示。
  - 紫微流年改用调用方的 `asOf` 作基准年，同一句柄跨年不再排出不同的流年表；人生 K 线按交运年份切段，与虚岁轴对齐，不再整条线提前一年。
  - 随机种子把高位与小数位折进状态：相差 2^32 的种子（如隔 49.7 天的毫秒时间戳）不再摇出同一卦。
  - 生时校正的事件限 200 条、年份限 1600–2400、候选时辰去重后最多 24 个；择日事项错误统一带 `E_INPUT`，`days` 的数字串会被规范化，越界或非数字一律报错，不再静默改成 30 天。

- **输出档位与上下文**（`engine/index.js`、`index.js`、`engine/handle.js`）：
  - 新增 `detail: "lean"`：只给结论、所问方向那一条与三张表，长论述与「规则·出处」折成一行指针（省约一半文本）；盘面、句柄与解析对象不变，影子盘与口径对照也不会把档位当成盘面差异。
  - 工具 schema 把梅花与小六壬的 `mode` 合并进同一个字段并写明三组取值，避免同名字段被后定义覆盖。

- **客户端稳定性**（`src/engine-lazy.js`、`src/app.js`）：
  - 分块在途请求去重：并发打开两个体系共享同一次下载；失败也清掉在途记录，一次网络抖动不会把分块永久钉在「正在加载」。
  - 面板连续排盘 / 连点 tab 时用序号丢弃过期结果：旧请求不再覆盖新盘，也不再在 await 之后把 tab 拨回去。

- **闸门与发布**（`tools/`）：
  - `check-html-sinks` 重写：逐插值判定，补上四类旧版漏检（裸变量赋值、一个 `esc(` 救全条、`insertAdjacentHTML` 的第二个实参、`dangerouslySetInnerHTML`），并带可自证的漏检用例。
  - 发布脚本不再 `git add -A`：按目录白名单与扩展名逐路径暂存，点开头的运行痕迹不收，重命名记录正确跳过来源路径。
  - 新增凭据扫描、对拍报告新鲜度校验、分块体积预算（单块 gzip ≤260KB、18 块合计 ≤2.75MB）。
  - `npm test` 现有 147 个测试文件 / 7139 条断言；新测试覆盖档案存储、分块预算、客户端竞态、细节档位、DST 歧义、输入守卫、HTML 注入面、凭据闸。新增断言均通过「把旧实现改回去必须变红」的反向验证。

- **真机回归**：`e2e-dom` 137 项、`e2e-panel` 89 项全过，覆盖档案存入/回填/改名/置顶/两次删除/缺时刻拦截、复制提问的所问与开场结论、切方向后追问框保留、深色与窄屏布局、全程无 JS 报错。

## 0.59.1（2026-11-02，已发布）

> 已发布：npm `dsh-metaphysics@0.59.1`，shasum `43817f74d114121bbbe947c91abc10a825a287b9`，94 个文件。

> 本版主题：把「先说结论」从八字／紫微推到全部九个体系，并且堵住三个会让第一屏**说错话**的坑。不新增断法，不改算法；改的是「第一屏能不能读、说的是不是真的」。

- **九个体系都有第一屏了**（`engine/plain-summary.js`、`engine/index.js`、`src/panel-kit.js`）：
  - 之前只有八字与紫微在盘面上方给一段人话；六爻、梅花、六壬、奇门、塔罗、合盘、走势七个体系点开就是一整屏术语。
  - 现在每个体系一个 `xxxSummary`，统一返回 `{title,chips,lead,sections,advice,caveat,footer}`；`plainSummary()` 分派，`compute()` 统一挂在 `r.brief` 上（生成失败只记 `briefError`，绝不拖垮排盘）。面板侧收成一个 `pp.briefHTML(r)`，九个盘面都只写一行前缀，不再各自判一次、也不会漏一个。
  - 各体系讲各自的结构：六爻讲世应／用神／月日／卦体，梅花讲体用，六壬讲三传（起手—转折—落点），奇门讲日干宫与时干宫的门星神，塔罗逐张给位置义，合盘讲日主关系／夫妻宫／五行互补，走势讲「这一步的基调、最亮最闷、怎么用」。
  - 证据：`test/plain-summary.test.mjs` 从 63 条扩到 149 条。新增一组「七体系×五项」：给得出、字段里不许漏 `undefined`、每段有实质、至少一条可做的事、结尾写明不是断语、问事的要回显用户那句话。渲染侧另测九个盘面：方框在最前、只渲染一次、带免责尾句、结果无 `undefined`。

- **六爻停在「综合」：没有用神也给第一屏，并说清为什么**（`engine/plain-summary.js`）：
  - 问题：用神由「询问方向」定，而方向默认是「综合」。默认状态下卡片一片空白——恰好是大多数第一次点开六爻的人看到的样子。
  - 改法：走「世应版」——只讲与问题无关的世爻、应爻、卦体（六冲／六合／伏吟／反吟）与动爻，并在补充说明里写明「不是算不出来，是取用神要先知道问什么」，第一条建议就是让用户补选方向。选定方向后自动切回用神版，两种版本不会同时出现。
  - 顺带修一句措辞：动爻原来写「4、5、6 爻动」，会被读成「六个爻都在动」；改成「第 4、5、6 爻动」，标签里的「3 爻动」是数量。

- **修：选「财运／学业」时，建议那一段是空的**（`engine/plain-summary.js`）：命盘的「询问方向」是 wealth/career/love/health/study/travel/general 七档，问事提示的六类是 career/love/business/action/day/other，两套键只有两个重合。不转这一道，「财运」取不到现实核对清单。新增 `DIR2KIND` 映射（财运→生意、学业→工作、健康→其他、出行→推进）。

- **修：合盘标签渲染成 `undefinedundefined × undefinedundefined`**（`engine/plain-summary.js`）：合盘结果里 `dayMaster` 是「丁火」这样一整串，不是 `{stem,element}` 对象——两种写法现在都接住。

- **修：紫微同一段里既说「成」又说「破」**（`engine/plain-summary.js`）：被判冲破的格局原先同时出现在「结构上成的是…」与「被冲破的格局有…」两句里，读的人只会觉得自相矛盾。被冲破的一律不计入「成」，措辞也从「被判为被冲破」改成「冲不等于毁，说的是它不如完好时那么顶用」。

- **修：奇门宫位写「6宫」**（`engine/plain-summary.js`）：读奇门的人认的是乾宫、巽宫，不是阿拉伯数字。宫名从 `PALACE_FIELD` 释义里取，并补上方位（乾宫（西北））；中宫仍按寄宫说明。

- **修：塔罗的「关节牌」取得随机**（`engine/plain-summary.js`）：原来取「第一张逆位」，同一副牌换个抽牌顺序结论就换位置。改成取「现在／现况／核心／建议」那一张，没有就取中间一张；标签里也去掉重复的「3 张」。

- **走势不再读挂钟**（`engine/trend.js`、`engine/index.js`、`engine/plain-summary.js`、`src/core.js`、`src/app.js`、`src/web-ui.js`）：
  - 原来 `trendSummary` 用 `new Date().getFullYear()` 找「你现在在哪一步」，过了元旦同一条线会自己改口，也过不了 `check-patterns` 的时间约定。
  - 改成：`buildTrend` 接受 `nowYear`，`compute` 从 `asOf` 取年，写进 `meta.nowYear`；引擎侧一律不读挂钟。界面（面板与离线页）用 `Core.todayStamp()` 传当天，内嵌在八字页里的 K 线也带上。没给 `asOf` 时不假装知道现在，改说「没给当前日期，所以不标现在在第几步」。
  - 顺带多给一句有用的：「走到这一步的第 N 年，再过 M 年换下一步」。

- **修（最严重的一条）：新增模块漏进分块构建，八个体系的产物里静默变成 `briefError`**（`tools/build-client.mjs`）：
  - `plain-summary` 只挂在八字／紫微的栈上。另外八个分块（六爻、奇门、六壬、塔罗、黄历、择日、称骨、起名…）里 `plainSummary` 是 `undefined`，`compute` 一调就抛，被 try/catch 收进 `briefError`——源码测试全绿，打包后第一屏直接消失。这正是 0.59.0 记过的同一个坑（`limits` 那次）。
  - 改法：抽出 `BRIEF` 组，所有会调 `compute` 的分块都带上。`chunks.test.mjs` 的 19 体系逐字节比对当场抓到（报压缩名 `Fe is not a function`）。

- **修：八字页会同时出现两个「先说结论」**（`src/panel-kit.js`、`src/app.js`、`src/web-ui.js`）：K 线随八字页渲染时也带上了自己的人话方框，两个方框抢第一屏。`trendHTML(r, { brief:false })` 用于内嵌，单独看走势时仍然保留。

- **口径对照不把「人话总结」当盘面差异**（`engine/diff.js`）：`brief` 是从盘面派生的叙述，换一档口径必然改写；不剔掉的话，奇门晚子时那一项会从「1 处差异」变成 3 处。

- **时辰未知：八字三柱模式，紫微/合盘阻断，趋势降级**（`engine/bazi.js`、`engine/index.js`、`src/app.js`、`src/web-ui.js`、`tools/build-html.mjs`）：
  - 问题：没填时刻就按页面默认时刻排盘，时柱、紫微命宫、起运日照常出现——**看起来像算过，实际是拿占位值算的**。这比算错更糟：错得看不出来。
  - 做法：`buildBazi` 接受 `hourUnknown`，内部仍按「正午」跑完整条管线（大运、旺衰要有个基准），但对外把不该被当成已知的东西全部收回——`pillars.hour = null`、命宫/身宫置空（依赖生时支）、输入回显不带钟点、`civilText`/`trueSolarText` 只留日期、大运与交运去掉时刻并标 `precision: 'day'`、五行不含时柱重算、只落在时柱上的神煞整条去掉。**全文不出现 `12:00`**，内部只用语义标记 `provisionalHour: 'noon'`。
  - 下游分三类处理：紫微（命宫由生月+生时支定，时支未知整盘不成立）与合盘（夫妻宫、大运依赖时支）→ `HOUR_UNKNOWN` 阻断并给一句可执行引导；趋势 → 降级，顶层带 `hourPrecision: 'day'` 且首行写明「起运按日估算」。
  - 摘要第一行固定句：「时柱按正午暂算，涉及时柱的结论仅供参考」——用户先看到「这不是一张完整盘」，才不会被下面的时柱/命宫误导。
  - 界面：八字与人生 K 线的时间框旁多一个「时辰未知」勾选（勾上即收起时刻框），面板与独立页同一套行为；紫微/合盘不提供这个勾选，因为给了等于诱导出一个假盘。
  - 证据：`test/hour-unknown.test.mjs` 47 条。三条硬断言——全文（JSON + 渲染文本 + 摘要）不得出现 `12:00`；时柱及依赖项必须为空且不得写成已知；提示必须是摘要第一行（无出生地、远期 ΔT 精度提示都不得把它挤到第二行）；工具 schema 必须暴露 `hourUnknown`；面板 `pp-warn` 必须逐字含固定句。另有五条守下游：紫微/合盘必须抛 `HOUR_UNKNOWN`、趋势必须带按日标记、默认路径逐字节不变。

- **修：无地址时固定提示被挤到第二行**（`engine/index.js`、`test/hour-unknown.test.mjs`）：地警告与 ΔT 精度提示也在往摘要最前插——固定句先插、后警告再插，「时柱按正午暂算…」就被压到第二行（命中精度提示时第三行）。改为最后再插固定句，并补「无出生地」「2150 远期盘」两条断言：现在无论有没有地址、精度如何，首行都是它。

- **补：工具 schema 也支持 `hourUnknown`**（`index.js`、`test/hour-unknown.test.mjs`）：原先只有面板与离线页能勾三柱，`metaphysics_chart` 的 schema 里没这个参数，Agent 要不到。补上布尔参数与说明（八字三柱、趋势按日、紫微/合盘阻断），并加断言防回退。

- **面板三柱提示改用固定句**（`src/panel-kit.js`）：`pp-warn` 文案统一为「时柱暂缺：只排年/月/日三柱，起运与交运按日估算。时柱按正午暂算，涉及时柱的结论仅供参考。」，与摘要首行逐字一致（有断言）。
- **证据与门禁**：`test:ci` 138 文件全过，断言基线 6737 条（0.59.0 为 6620）；真机回归 `e2e-dom` 103 项、`e2e-panel` 43 项（含「方框只渲染一次」）；`stress` 200 盘 14 项（p95 2ms、堆增长 +0.46MB）。

## 0.59.0（2026-11-01，已发布）


> 已发布：npm `dsh-metaphysics@0.59.0`，shasum `4712088541c06b112792c9249fe64d0dbe0dd38d`，93 个文件。

> 本版主题：把「算得更准」这条路主动停下，改走「不骗人」。三件事——知识标签不再冒充「已验证」、分歧按「本盘涉及」分组、新增「本插件不回答什么」清单。都不碰算法：0.58.0 的应期回测已经说明，51.7% 对 29.6% 的随机基线，靠调规则优先级补不上来；能补上来的是「别让用户以为它比实际更可靠」。

- **知识标签不再冒充「已验证」**（`engine/interpret-knowledge.js`、`engine/interpret.js`、`src/panel-kit.js`）：
  - 问题：三个标签原写作「诸家一致 / 各家有异说 / 待核实」。前两个在用户眼里约等于「可靠」，而实际含义只是「各书都这么写」。「文本里一致」和「世界里成立」共用一个词，是产品在无意中骗人。
  - 改法：标签写全为「文本·诸家一致 / 文本·各家有异说 / 文本·未录入」，前两个强制带前缀；知识区块末尾加一句统一声明——「以上标签只说明典籍文本的一致程度，不表示该技法经过验证；本插件不对任何技法的预测效度作保证」，全报告只出现一次（挂在最后一个带知识卡的维度下，逐维重复反而会被跳过不看）。
  - 证据：`test/interpret-knowledge.test.mjs` 新增 4 条，其中一条是**防止被改回去**的——任何标签不以「文本·」开头即失败；另三条盯声明本身（存在、点明「不表示经过验证」、点明「不作保证」）。

- **分歧按「本盘涉及」分组**（`engine/interpret.js`）：
  - 问题：文末「这套规则有多稳」把本盘踩到的分歧和「这派别来就吵的」混成一锅，八字一张盘能列十几条，用户看不出哪几条跟自己有关。
  - 改法：按 `seen` 分成两组——先列「本盘涉及 N 处」（只留条目名，正文里已展开过），再列「本体系另有 M 处通行分歧（本盘未涉及，附原注备查）」；两者都没有时写明「本盘未踩到，结论是按一派一路算下来的」。开头与结尾各一句把这层定性钉死：这是**文本层**的分歧，不是谁对谁错的判定，插件不替它们裁决。
  - 证据：`test/interpret-knowledge.test.mjs` 新增 2 条——分组标记必须存在；「本盘涉及」里列出的条目必须真在这张盘的知识卡里出现过（防虚标）。

- **新增「本插件不回答什么」清单**（`engine/limits.js`、`engine/interpret.js`、`engine/index.js`、`src/panel-kit.js`）：
  - 为什么不做成免责声明：「可能不准」这种句子没有信息量，用户看完还是不知道该信哪部分。有用的写法是——这条为什么做不到、做到哪一步就停了、依据是什么。
  - 通用三条：技法效度未经检验（能复核的只有形式层）、同盘不同命（模型硬缺陷，不是样本不够）、不给医疗法律投资建议。按体系各 1–3 条：六爻不给公历日期且用神两现不代选、八字不预测具体年份事件且旺衰是分档不是评分、紫微飞星层只报路径不判吉凶、梅花不取外应、大六壬应期未做、奇门八门九星入墓未做、塔罗只给通行牌义。
  - 走公共收尾 `withReportMeta` 注入，所以奇门那条不经过正文组装的支路也带得上。面板在报告最末折叠显示（与免责声明分工不同：免责声明是「别全当真」，这里是「具体哪几件不答、为什么」）；对话侧全量输出给调用方，不截成标题——模型知道「为什么不答」，才不会自己补一个答案。
  - 证据：`test/limits.test.mjs` 27 条（字段完整 / id 不重复 / 文案 ≥40 字且有实质 / 无绝对化用词 / 七个体系都有专属条目 / 通用三条覆盖三个死穴 / 八字不带六爻条目 / 奇门支路也带上）。其中最关键一条是**清单不能和实现矛盾**：既然写着「应期不给公历日期」，六爻解析全文就不得匹配出 `YYYY年M月D日`；哪天有人在应期里加了日期，这条会先挂。

- **修：新增引擎模块漏进构建清单，打包后静默变成 `undefined`**（`tools/build-client.mjs`）：`limits` 初版只加了 `import`，没进 `ORDER` 与 `INTERPRET` 栈，源码跑得通、打出来的分块里 `limitsFor is not a function`。表现是 `chunks.test.mjs` 七个体系逐字节比对失败（报 `Qn is not a function` 这类压缩名）、`security.test.mjs` 直接抛错。已把 `limits` 插到 `interpret-knowledge` 之后、并列入 `INTERPRET` 组。**教训写在这里：engine 下新增文件，除了 import 还要进 `ORDER` 和它所属的模块组，否则源码测试全绿、产物静默坏掉。**

- **B1 六爻应期收尾：规则顺序纠错 + 补统计显著性**（`engine/yingqi.js`、`tools/backtest-yingqi.mjs`、`test/yingqi.test.mjs`）：
  - **发现一个实质错误**：代码里规则的排列几乎是把原文倒过来排的，而注释声称「状态互斥优先级照应期总注的排列：空 → 破 → 动 → 墓 → 太旺 → 衰绝 → 静」。把《各門類應期總注章第又二十六》19 条逐条对下来，真实次序是「静 → 动 → 太旺 → 衰绝 → 入墓 → 六合 → 月破 → 旬空 → 大象吉受克 → 大象凶受克 → 元神总纲 → 化进 → 化退 → 独发独静 → 变爻动爻 → 远近当分 → 再占 → 世空元动 → 世衰元静」。**那句「空 → 破 → … → 静」原文里没有，是编的。**
  - 改法：新增 `RULE_ORDER` 照原文罗列次序，`primary` 重新定义为「按原文次序第一条生效的规则」，不再是「最可能应验的那条」。同时把 `yingqiState` 上那句「状态互斥优先级」的错注释删掉——那里没有选择逻辑，各项独立计算。
  - **对拍补了二项单尾检验，把「百分比」变成「结论」**（`tools/backtest-yingqi.mjs`）：并集 15/29＝51.7%，随机基线 29.6%，**p=0.0102（显著）**；主规则 8/29＝27.6%，按主规则自身支数算基线 17.0%，**p=0.1047（不显著）**。两者一正一反说明：规则集合确实覆盖了原文所记的应验支，但条文之间没有可用的优先次序——这正是面板继续不出日期的依据。
  - **逐规则统计**（新增）：`liuhe-xiang-ji`（六合宜相击）7 例中 6，85.7%，p≈1.3×10⁻⁴，过 12 条规则的 Bonferroni 校正（α=0.0042），是本批数据里唯一站得住的单项；`rumu-chong-kai`（入墓喜冲开）6 例 0 中、`jing-zhi-chong`（静而逢值逢冲）7 例 1 中，都低于自身基线。**但这只是报告，不据此调规则**——按这些数字重排就是拿对拍集调参，命中率会变成自己喂出来的。脚本头部与测试注释都写死了这条边界。
  - 新增能力边界 `liuyao-liuyue`：不推演流月推进后的二次变化。依据是一条实占反例（用神伏藏、本可靠日辰冲开，进入下月建后一冲解掉原月建对制它之爻的合，制者复起，出伏失败），这类跨月推演还没做，所以应期只能作「该留意哪几支」。
  - 证据：`test/yingqi.test.mjs` 28 条（+3）。新增两条是防回归的关键——「规则顺序照原文罗列」把 15 个 id 的顺序钉死，改排序必须给原文依据；「同时命中按原文次序取主规则」用「入墓 5 < 月破 7」的用例验证排序真的生效。另修正两个旧用例的日辰（原来取辰，正好是水墓，会把「入墓」拉进来抢主位，测的就不是月破/旬空了）。

- **真机回归：用本机浏览器把 19 个 tab 逐个点一遍**（`tools/e2e-dom.mjs`、`package.json`）：
  - 补的是最后一层：冒烟测试跑在 node 里，测得到引擎与渲染函数，测不到事件绑定、表单显隐、勾选后的重渲染、深链落地。这一层用 Chrome 真开页面点。
  - 19 个 tab 各查：切得到、有主按钮、能出结果、结果无脏串、**全程无 JS 报错**（监听 `pageerror` 与 `console.error`）。共 103 项断言。
  - 另测三条只有真浏览器能测的：① 八字勾「时辰未知」后，结果里必须出现「时柱暂缺」且不含 `12:00`；② 深链 `#mp=…` 直接打开能自动落地出结果；③ 深色主题下扫描全页文字对比度（含渐变背景取平均色）、390px 窄屏无横向溢出且能出结果。
  - 用 `playwright-core` + 本机已装的 Chrome/Edge，**不下载浏览器**；找不到浏览器时打印跳过并返回 0，不会把 CI 弄红。
  - 过程中修掉两处**误报**（不是产品问题，但值得记）：渐变背景只读 `backgroundColor` 会拿到透明、把「浅底深字」判成同色；父容器（`button.tool`）的文字都在子节点里，拿父容器的 `color` 算对比度必然误判——改成只看「直接含文字节点的元素」且渐变取平均色。

- **全体系稳定性复查：新增冒烟 + 修掉 K 线 id 不稳定**（`test/smoke-all.test.mjs`、`tools/smoke-all.mjs`、`src/panel-kit.js`）：
  - 为什么加：单测各自盯一块，但整页能出结果的路径有几十条，一条崩就是白屏——上次「时辰未知」崩在 `p.stemTenGod`，引擎 6253 条断言全绿、页面全崩。这次把 19 个 tab 的 36 个用例逐个跑「排盘 → 渲染 → 文本 → 解析」四条链，共 300 条断言。
  - 每项查五件事：不抛异常；成品里不留 `undefined / NaN / null / [object Object]`；**同一张盘渲染两次必须字节一致**；关键结构词在（四柱/命宫/值符/世爻/宜忌…）；无 `<script>` 与事件属性。
  - 另外覆盖：边界日期（1900/1929 时区切换、2024-02-29、2100）、立春前后年柱必须换、晚子时开关必须改日柱、三柱盘与完整盘的年月日柱必须一致、10 条参数错误路径必须给「带错误码的中文提示」、句柄往返、八字×紫微交叉、40 个随机日期采样、以及**交付物自身**——把单页里的 4 段内联脚本各过一遍编译器（产物语法坏了，跑源码的单测永远发现不了）。
  - **修掉一个真 bug**：人生 K 线的 `clipPath` id 原来用全局自增（`klineSeq`），导致同一张盘两次渲染出不同 id——截图对拍、快照测试永远对不上。改成盘面内容的短哈希（FNV-1a）：不同盘不同 id，同盘永远同 id。
  - 用法：`npm run smoke`（也进 `test:ci`，断言数进基线）。

- **盘面顶部「先说结论」：一段人话总结**（`engine/plain-summary.js`、`engine/index.js`、`src/panel-kit.js`）：
  - 起因：排完盘先给的是四柱表和一堆术语，普通人第一屏读不动——就算下面写了解析，也读不到第二屏。要的是「先给一段能看懂的话，再给依据」。
  - 内容：一个方框，四件事——总纲（日主+生月+冷暖+最需要什么）、你的底色（十神权重前两位翻成人话）、感情这件事（配偶星落在哪、配偶宫坐什么、有没有破冲合）、最容易卡住的地方；末尾给 2–4 条可以立刻做的事，再加一句补充说明与「不是断语」的尾句。
  - 硬规矩：**只做「结构 → 人话」的翻译，不下吉凶断语**。「官杀混」可以说成「你容易遇到两种类型的人」，不能说成「你婚姻不好」。同一张盘每次生成的文字逐字相同（有断言钉死确定性）。
  - 八字与紫微都有：紫微那版讲命宫主星、身宫落宫、夫妻宫与格局（格局只描述形状，不作吉凶判词）。
  - 位置：方框在盘面之前、每份结果只渲染一次；对话侧 `renderText` 也把这段放在最前（`【先说结论】`），模型照它复述就不会一开口是术语表。
  - 证据：`test/plain-summary.test.mjs` 38 条。含确定性（两次生成 JSON 全等）、不越界（不许出现「一定会/必然/注定/肯定会」）、时辰未知时必须在补充说明里讲清「只有六个字、约七成信息」、男命取财星不套女命说法、渲染顺序（方框 index < 盘面 index）。

- **面板一键「复制问事提示」**（`src/panel-kit.js`、`src/web-ui.js`、`src/app.js`、`src/core.js`、`engine/index.js`、`tools/build-client.mjs`）：
  - 六爻 / 梅花 / 大六壬 / 奇门 / 塔罗五个体系的结果页，问题行下方出现「复制问事提示」按钮：点一下，当前盘面 + 所问之事打包成一段完整提示，粘到任何对话里都能用。`core.js` 加 `kindOfDirection` 把命盘的七向（财运/事业/感情…）映射到问事的六类（business/career/love…）。
  - 命盘类（八字 / 紫微 / 合盘 / 趋势 / 起名 / 风水 / 称骨 / 星座 / 数字 / 人格）不渲染这个按钮——它们回答的是「这个人是什么结构」，不是「这件事成不成」，给了按钮就是诱导误用。小六壬结果是单行落宫、没有解析报告，按钮也不在它那边，提示走命令行。
  - 引擎侧 `engine/index.js` 导出 `buildEventPrompt` / `ASK_KINDS`；`build-client` 给五个问事分块加 `EVENT_PROMPT` 栈（`qimen-prompt` + `event-prompt`），命盘分块不带，避免无谓体积。本仓 esbuild 不接受 `export {} from`，改为先 `import` 再 `export`。
  - 证据：`test/ask-copy.test.mjs` 14 条——五个问事体系都渲染且只渲染一次、两个命盘类不渲染、引擎确实导出构建器。

- **问事解读提示：把「先问清事 → 取用神 → 回到现实」推广到全部问事体系**（`engine/event-prompt.js`、`engine/qimen-prompt.js`、`tools/event-prompt.mjs`、`docs/问事解读提示.md`）：
  - 起因：奇门那套要求（先答他所问、不堆术语、每个符号说得出为什么、结论回到现实核对）不该只对奇门成立。六爻、梅花、六壬、塔罗、小六壬一样会被读成「符号念一遍」——世爻旺相所以好、用生体所以吉、这张是死神所以完蛋。
  - 做法：骨架共用（时间确认 → 问事分类 → 取用神给理由 → 读状态 → 三追问自检 → 现实核对 → 表达要求 → 禁止 → 输出格式），**取用神各体系自己给**：六爻世应 + 六亲按事类取（工作官鬼、财妻财、感情男财女官、文书父母）、梅花体用、六壬日干日支 + 三传、塔罗牌位决定含义、小六壬明确说明「没有独立的我，别硬补」。奇门委派给 `qimen-prompt.js`，两套提示内容逐字一致（有断言钉住）。
  - 时间不明一律拦住：问事体系靠起课那一刻定盘，没时刻就没有盘。`timeKnown:false` 时返回「先别起课」的拦截文本，且**不得出现任何盘面符号**（有断言：全文不许匹配世爻/应爻/四柱/值符）。
  - 把「说不清」写进提示，而不是糊过去：六爻用神两现必须标「两现未定」；小六壬必须说明它给不了「我 vs 对方」；梅花体用标了「大吉」也要提醒「吉是条件好，不是结果已经发生」。
  - 用法：`npm run prompt:event -- --system liuyao --kind career --question "…" --lines 9,7,8,8,7,6`，输出一段填好盘面的完整提示；`--no-time` 只出「先问时间」。长文档见 `docs/问事解读提示.md`。
  - 证据：`test/event-prompt.test.mjs` 61 条。含**空话检测**（现实核对里不许出现「结合现实 / 具体情况具体分析 / 视情况而定」）、**自洽检测**（禁止清单里写的，提示自己不能犯）、问题超 200 字截断。

- **报告内置「数 / 象 / 辞」三层导读**（`engine/guide.js`、`engine/interpret.js`、`src/panel-kit.js`）：
  - 为什么做进插件而不是只放文档：读不懂命盘的人不会去翻 README，他只在结果页划两下就关了。所以导读必须「一进来就看见、但不挡路」——折叠，默认收起，排在「一页读懂」之前。
  - 内容只讲一件事：这份报告里哪部分是算出来的（可复核）、哪部分是命名（可商量）、哪部分是判断（要自己拿主意）。三层各带一句「这一层在本报告里长什么样」，再接三问检验法（坐标 / 关系 / 唯一读法），最后点明纳甲、十神、宫位都是中间件。
  - 数据与渲染分开：`guide.js` 只存文案（纯数据，vm 可测），`panel-kit` 负责画。两套 UI 共用 `resultWithInterpret`，所以面板与离线页同时生效，不用改两处。
  - 证据：`test/guide.test.mjs` 25 条。最要紧的三条是**内容自洽**：三层与三问必须齐（少一层就退化成鸡汤）、问句必须以问号结尾（是提问不是结论）、**全文不得出现效度承诺词**（这段本身就是「效度未验证」的说明，出现「一定」「精准」即自相矛盾）。另有渲染契约：只渲染一次、排在结论之前、默认收起、转义无注入面。
  - 这一版把 `docs/象与数-要义导读.md`（长文）里的核心判准压缩成 90 秒版放进报告，长文留作延伸阅读。

- **修：深色主题下选中高亮块的字看不见**（`src/app.js`、`src/core.js`）：
  - 症状：深色模式下打开侧栏面板，被点中的那个体系（tab / 分组里的工具项 / 视图开关 / 主按钮 / 分段控件）文字是白的，压在同样浅的品牌色块上，对比度约 1.2:1 —— 等于没有字。
  - 根因不是「颜色没调好」，是**写死了白色**：选中态一律 `background:var(--dsw-alias-brand-primary);color:#fff`，八处都是这么写的。而品牌色在深色主题里通常反而变浅（深色底上才看得见），白字落上去必然糊掉。同一个 `#fff` 在浅色主题下是对的，在深色下是错的，说明它本来就不该被写死。
  - 改法：不再猜一个颜色，改成**运行时量一次宿主真实的品牌色**——往 body 插一个透明探针，`getComputedStyle` 取回解析后的 `backgroundColor`，按 WCAG 相对亮度算出白字与近黑字各自的对比度，挑高的那一侧写进 `:root` 的 `--mp-on-brand`，CSS 只读 `var(--mp-on-brand,#fff)`。系统主题切换（`prefers-color-scheme`）与宿主换 `class` / `data-theme` 时各重算一次；量不到就回落到 `#fff`，不会比改动前更差。
  - 为什么不用媒体查询硬编码两套色：宿主的深色品牌色是什么值，插件无从得知（它可能仍是深蓝，也可能是浅青），猜错一次就是同一个 bug 换个方向复发。
  - 证据：`test/core.test.mjs` 新增 12 条，其中一条走遍 RGB 步长 51 的全色域（216 个底色），断言「挑出来的那侧对比度永远不低于另一侧」，并给出最差值 4.19:1 —— 满足大字号 AA(3:1)；中灰如 `#7f7f7f` 两侧都到不了 4.5，这是色彩本身的极限，不是选错。`test/theme.test.mjs` 新增 8 条静态守卫：**品牌色块后到规则结束为止不得再出现写死的白字**，谁改回去谁先挂。

- **滴天髓·下篇六亲论录入：家庭这一块从「通行说」升到「可核原文」**（`engine/citations.js`、`engine/interpret-knowledge.js`、`test/fixtures/citation-sources.json`）：
  - 起因是「能不能用八字对家庭生活给方向」这个问题。查下来发现，六亲这块在库里只有一条 `smt-liuqin`（三命通会条列名目），夫妻、子女、父母三处的原文一句没录——用户看到的「家庭」解释，实际上没有底本支撑。
  - 补法：从底本（`diancang.xyz/.../ditiansui/153092.html`，下篇六亲论）逐字录入 5 条——夫妻「夫妻因缘宿世来，喜神有意傍天财」、子女「子女根枝一世传，喜神看与杀相连」、父母「父母或降与或替，岁月所关果非细」、女命章、何知章（富/贵/贫/贱四条判据）。原文进 fixture，CI 离线可复验，`test/citations.test.mjs` 的「每条引文的来源正文都在 fixture 里」逐条比对。
  - 关联：`bazi-liuqin` 由 1 条引文扩到 4 条（夫妻/子女/父母各有落点），`bazi-geju-chengbai` 加何知章（成破格 → 富贵贫贱有了原文判据），引文总数 94 → 99。
  - **意外收获，也是本版最硬的一条**：女命章原文「三奇二德虚好语，咸池驿马半推详」——三奇、二德是空口说好话，咸池（桃花）、驿马顶多参考一半。**「神煞不主吉凶」不是今人的现代意见，是《滴天髓》自己说的。** 以前 `bazi-shensha` 只引三命通会（条列名目）+ 子平真诠（主张不主吉凶），只引前者会让人以为插件在给神煞背书；现在两书合看，立场有原文兜底。
  - 边界：六亲论这一篇是韵语提纲，各家注解发挥分歧很大，所以只录原文、不把某家注解当原文引（`dt-liuqin-fuqi` 的 note 写明了这一点）。

- 门槛：131 个测试文件 / 6104 条断言全过（较 0.58.0 增 33 条）；client.js 256KB / gzip 78KB；产物自检 18 个分块 / 逐模块编译 58 个；性能 29 项在限内。

> 下列两条是 0.58.0 之后、本版之前的工作，随本版一并发布。再往下的 C3 对话桥替代 / §5.8 自动发布加固 / push-tag 三条的详细记录属 0.58.0，保留于此备查。

## 0.58.0（2026-11-01，已发布）

> 本版主题：把「盘送不进对话」这条路补成三条不依赖宿主的通道（C3），顺手让自动发布可观测、可自愈，再把引文里两句长期误署的话改回原书。
>
> 包含：C3 对话桥替代（深链 / 复制 / 结构化参数）、§5.8 自动发布加固、B6 通行说复核、B6 通根透干复核（误署纠正）、B6 第五批（大六壬 3 条）、C4-a 三方合盘、C4-b 择日候选日比较、C4-c 同盘多口径并排、D1+ 首屏耗时回显、A1+ 推导链出处、D4 发布回滚、自检修复（见下）。

### 0.58.0 明细（原「未发布」草稿，随该版发布）

- **凭据扫描进约定闸：token 形态的字符串提交不进去**（`tools/check-patterns.mjs`）：
  - 起因：npm / GitHub 的发布凭据存在 `<用户目录>/.dsh/metaphysics-autopublish.json`，只从环境变量喂给 `tools/release.mjs`；它一旦被贴进对话、写进文档或提交到仓库，撤回版本也撤不回已推送的历史。
  - 新增第 8 条规则：全仓（跳过 `node_modules` / `.git` / `.workbuddy`）扫 `npm_xxx`、`gh[pousr]_xxx`、`github_pat_xxx`、PEM 私钥头。**命中只打印「文件:行」与原因，绝不回显匹配到的内容**——检查本身不能变成泄露通道。
  - 自检：往仓库根放一个 `npm_` + 40 位的假串，闸门退出码 1 并指出 `_leak-probe.js:1`；删掉后恢复通过。当前 299 个文件无命中。

- **面板（宿主侧栏）真机回归：补上最后一层没测过的 UI，并抓到一个三柱盘必崩的 bug**（`tools/e2e-panel.mjs`、`src/app.js`、`package.json`）：
  - 缺口在哪：单页 E2E 跑的是 `src/web-ui.js`，面板跑的是 `src/app.js`——两条渲染链只有 `panel-kit` 共用。面板自己的状态（勾选联动、本地历史、深链落地、首屏卡片）此前只有静态字符串断言，等于没跑过。
  - 怎么测：真 Chrome + **真 React 18**，配一个最小宿主——假 `slots` 注册表（`register` / `inject` / `spec`）、假 `ctx.effect`、`assemble()` 打出的全量 client（含引擎），本机 http 起服务（`file://` 下 localStorage 会抛 SecurityError）。把 `PanelIcon` 画进侧栏、主面板画进 `#main`，然后照用户顺序点：切体系 → 排盘 → 勾「时辰未知」→ 起卦 → 切深色 → 缩到 520px → 带 `#mp=` 深链重开。43 项断言。
  - **抓到的真 bug**：`HISTORY_LABEL` 对 `pillars` 逐项取 `.ganzhi`，时柱为 `null` 时抛 `Cannot read properties of null`——表现是「三柱盘一点排盘就报错」，而引擎 6620 条断言全绿（那段代码在面板里，不在引擎里）。已修：过滤空柱，并在文案末尾写「（时柱暂缺）」，别让历史条目看起来像四柱。
  - 顺带验了面板独有的几处：勾选后时刻框被禁用、排过的盘进 `localStorage` 并出现在「最近用过」、连点 10 次不崩也不膨胀、深色下选中卡片对比度 8.13:1、520px 容器无横向溢出、深链把面板切到对应体系并带回问题。
  - `test/hour-unknown.test.mjs` 补 6 条把 `HISTORY_LABEL` 的逻辑本身钉住（从 `app.js` 取出函数独立求值，不依赖浏览器），免得下次又只有真机才暴露。
  - 用法：`npm run e2e:panel`（没有 Chrome/Edge 时打印跳过并返回 0）；`npm run e2e` 现在同时跑单页与面板两层。

- **连续 200 次压测：不崩、不漂、不涨、不串**（`test/stress.test.mjs`、`package.json`）：
  - 冒烟测「每条路能走通」，压测测「一直走会不会变形」。200 份**不同日期**的输入（八字/紫微/六爻/奇门轮转，逼缓存真的淘汰），预热 20 次后再跑。
  - 四条断言：① 200 次零抛错、结果里没有 NaN/undefined/[object Object]；② 同一份输入在压测前后**逐字节一致**（抓隐藏计数器、缓存污染）；③ 日历三个 LRU 都不超上限，且确实踩到过上限（`termInstant 899/4096`、`termYear 32/32`、`termWindow 8/8`——踩不到说明压测没打中热点）；④ 后 50 次不比前 50 次慢（0.5ms vs 0.8ms），p95 ≤40ms。
  - 内存单独起一个 `--expose-gc` 子进程量：强制 GC 后堆增长 **+0.44MB**（9.55 → 10.00MB）。同进程量只会量到未回收的垃圾，是噪声不是泄漏。
  - 实测：200 次共 127ms，平均 0.61ms/次。用法 `npm run stress`。

- **B1 六爻应期：样本不再等用户，改从《增删卜易》里取；规则层落地，命中率公开且不好看**（`engine/yingqi.js`、`tools/gen-zengshan-cases.mjs`、`tools/backtest-yingqi.mjs`、`test/fixtures/zengshan-cases.json`、`test/yingqi.test.mjs`）：
  - 为什么不等用户给卦例。应期对拍要「月建日辰 + 完整六爻 + 断语 + 应期口径 + 实际应验」五样齐，这类样本在《增删卜易》里本来就是成批的（野鹤老人自己拿实占卦例成书）。本地已缓存全书 12.4 万字，170 处「X月Y日占」起式，够用，且不必麻烦用户现编。
  - 收录标准四条全过才收：起式能定位月建日辰；六爻能按行解析；**解析出的六亲/地支/五行与引擎纳甲逐爻一致**（这一条同时充当解析正确性校验——纳甲+六亲由卦宫五行唯一决定，六爻全对基本等于卦没错）；断语点名用神（「寅木官星持世」「未土父母動化進神」「財爻持世」「世爻寅木」「X为用神」五种句式）；应验句里有可解析的年月日。结果 **29 条收录 / 141 条排除**，每条排除都写了理由（`excluded`），不静默丢弃。变卦名按「原文缩写还原成候选，候选唯一才核」处理（写「之兌」即兑为泽、写「之夬」即泽天夬，「大」这种可指大过/大壮的当未能核验），避免拿缩写误判。
  - 规则层照《各門類應期總注章第又二十六》19 条落成 15 条可判规则；落不到「某支」上的 4 条（独发独静、远近换尺、再占、元神总纲）列进 `NOT_IMPLEMENTED`，不假装做了。取支一律只给地支、不换算公历日期——与既有 `yingqiWindow` 的契约一致。
  - **对拍结果（公开，不好看）**：并集命中 15/29＝**51.7%**，平均 3.55 支、随机基线 29.6%；主规则命中 8/29＝**27.6%**，与基线持平。结论：按条文取支集合比瞎猜强约 22 个百分点，但目前的规则优先级排序**没有预测力**；逐条看还能看到「化进神」「化退神」各 1 例全落空。因此面板**仍不出日期**，`test/yingqi.test.mjs` 25 条一律用构造盘断言（不拿对拍集调参，否则命中率是自己喂出来的）。
  - 复现：`npm run gen:zengshan` → `npm run backtest:yingqi`。
- **F 真化改为「判例对齐」**（方案文档同步）：公开古籍没有「已验证人生」的化气格命例，做真化命中率等于在没有答案的地方造分；改为取古籍明确判「化气格成」的四柱，只比对条件清单口径，不做命中率宣称。

- **发版最后一步补成工具：`tools/push-tag.mjs`**（`package.json` 增 `push:tag` 脚本，`release.mjs` 的提示改指它）：
  - 起因：0.58.0 发完 npm，脚本提示 `git tag v0.58.0 && git push origin v0.58.0`，而这台机器 GitHub 443 整段不通（`Connection reset` / 连不上），tag 只能落在本地，远端 release 页面上永远缺一个。
  - 做法：默认取 `package.json` 版本；缺 tag 就建 annotated tag；推送连续三次失败且错误像「连不上」时，自动临时 ed25519 → 注册 deploy key → 走 `ssh.github.com:443` 推 `refs/tags/…` → 无论成败都删 key 与私钥。`--dry-run` 只报告不动手，`--no-create` 只推不建。与自动发布用同一个配置文件，不额外落盘凭据。
  - 证据：`test/push-tag.test.mjs` 22 条（dry-run 不建 tag 也不碰远端、默认 tag 跟版本号、tag 名不合法直接拒绝、SSH 兜底接线与删 key、凭据只从配置文件读）。实测 v0.58.0 走 SSH 兜底推成功，临时 deploy key 168375084 已删。

- **C3 对话桥替代**（`engine/bridge.js`、`src/app.js`、`src/web-ui.js`）：会话槽位 `conversation.input.right` 不稳，桥一断就没路把盘送进对话；这一版给出三条不依赖宿主的通道。
  - 深链：`#mp=<句柄>&q=<问题>`，参数走 C1 句柄编码，截断或改字报 `E_HANDLE` 而不是静默排成另一张盘。面板首屏先读链接再排盘（表单状态下一帧才生效，同一批值经 `run` 的 over 直传，不会先闪一张旧盘）；独立页在 `setTab` 之后填表单再排，并在结果顶部写「已按链接还原：体系｜问题」，没填回表单的参数（如合盘对方）如实列出，不悄悄丢。
  - 复制：完整提问（与桥发出去的是同一份）、一句话精简（体系 + 句柄 + 问题，≤200 字）、结构化参数（`{"tool":"metaphysics","args":{handle,…}}`，助手可直接照 args 调 compute）。
  - 面板在追问框下加一排芯片「复制提问 / 复制精简 / 复制参数 / 复制深链」，桥可用时保留、桥缺席时就是主通道；独立页在追问区加「复制提问」、导出栏加「复制深链」。
  - 证据：`test/bridge.test.mjs` 88 条（深链往返与四柱复现、四种写法可解析、六类坏链接不抛异常且带 code、表单还原与未还原提示、三档文本与 JSON、无句柄不编链接、不改盘面对象、面板与独立页接线、bridge 进公共栈）；无头 Chrome 实测 `命理排盘.html#mp=…` 打开后四柱与问题一致、坏句柄回落到默认盘。

- **§5.8 自动发布加固**（`tools/autopublish.mjs`、计划任务）：把「定时跑但出了问题看不出来」补成可观测、可自愈。
  - 每天 23:00 与 23:30 双跑：第二跑在指纹未变时只写一行日志，等于给第一跑的一次兜底重试。
  - 每次运行开头写 `运行开始（auto/dry-run/init/force，pid …）`；**无改动也写一行**（原来是完全静默，事后查不出任务跑没跑）；日志超过 512KB 自动裁到最近 800 行。
  - 失败写 `tools/.autopublish-error`（内容含失败原因与时间），成功一次自动删掉；未捕获异常也留痕。该文件进 `.gitignore`。
  - GitHub HTTPS 连续失败且报错像「连不上」（443 / timeout / SSL / RPC failed）时，自动生成临时 ed25519 → 调 API 注册 deploy key → 走 `ssh://git@ssh.github.com:443/...` 推一次 → 无论成败删 key、删本地私钥；「推被拒」不触发兜底。
  - 证据：`test/autopublish.test.mjs` 28 条（未知参数仍立即拒绝且不碰状态文件、加固项接线、dry-run 写运行开始、配置缺失时退出码 1 且写错误文件、失败后不留锁也不改状态）。

- **B6 通行说复核（8 张逐张过一遍底本）**（`engine/citations.js`、`engine/interpret-knowledge.js`）：
  - `liuyao-jintui-yong` 由通行说改为 refs：《增删卜易》卷二·進神退神章第二十九「進神退神者，爻之動而化也，化進化退，吉凶禍福有喜忌之分，所喜者宜於化進，所忌者宜化退神。」底本已经把喜忌落在进退上；把「喜／忌」具体落到用神／忌神两档仍标为本插件引申（写进知识卡 note）。
  - 其余七张维持通行说，但把「查过什么」写进理由：紫微飞星三张——`《紫微斗數全書》`卷一、卷三全文检索「宮干／飛星／三方同飛／忌轉忌」均无命中，底本只有生年四化；奇门干宫生克——统宗已抓四卷只有「星相克／仪相克／门相克」与「时干克日干」；十干克应——检索到的「十干克應歌訣」署诸葛亮、释意者为近人，属现代韵语，不能当原文；通根透干——当时没定位到，留待联网复核（下一轮已改判，见「B6 通根透干复核」）；塔罗逆位——韦特《Pictorial Key to the Tarot》1911 已入公有领域，但原书对逆位态度含混，未给「逆位＝受阻／内化」这套固定读法。
  - 53 张卡：45 张已定位原文（+1）、7 张通行说（−1）、1 张待补。`docs/citations.html` 同步重建。
  - 证据：`test/citations.test.mjs` 59 条（新增 3 条：用神化进退落到進神退神章、source 为 verified、通行说剩七张且待补一张）。

- **B6 通根透干复核：通行说是误署，改引《滴天髓·干支总论》**（`engine/citations.js`、`engine/interpret-knowledge.js`）：
  - 说法查证。常被引作《滴天髓》的「地支所藏之干，本静以待用，透出干头，则显其用矣。故干以通根为美，支以透出为贵」，在**滴天髓底本全文**里检索「本静以待用／干以通根为美／透出干头」零命中；在**《子平真诠》沈孝瞻原文**（论十干十二支，中华典藏本 984 字）里同样零命中。它实际出现在《子平真诠》**评注本**卷一·论十干十二支的注文（附支藏人元图、十二月令人元司令分野表之后的按语）。也就是说：网络通行写法「《滴天髓》云：地支所藏之干……」把注文署给了原书。
  - 改判依据。该注文自身引的才是《滴天髓》：「天全一气，不可使地德莫之载；地全三物，不可使天道莫之容」——这句在本地所收滴天髓底本「干支总论」里逐字可对上，语义正好是「天干要地支承载（通根）、地支藏干要透出天干（透出）」。故本卡只引这句可核的原文，注文那两句写进 `note` 作说明，不冒充原文。
  - 结果：`bazi-tonggen-tougan` 由通行说改为 refs（新增引文 `dt-yiqi-tonggen`，《滴天髓·干支总论》）；引文库 93→94 条；**46 张已定位 / 6 张通行说 / 1 张待补**。`docs/citations.html` 现在也会把 `note` 显示在已定位条目下，误引纠正看得见。
  - 证据：`test/citations.test.mjs` 62 条（新增 3 条：改引干支总论、引文确为原句、note 写明误署；通行说计数 7→6）。

- **D4 发布回滚**（`tools/release.mjs` + `tools/release-rollback.mjs`）：发版失败、或发布后附件核对没通过时，打印一套可照抄的回滚步骤，不自动动 registry。
  - `rollbackPlan()` 按原因出步骤：`publish-failed` 先查「版本条目有没有建出来」；两种情况都给出「`npm dist-tag add …@上一版 latest` → `npm deprecate` 问题版本 → 网页 2FA 删包（automation token 会被 403 拒）→ `npm version patch --no-git-tag-version` → CHANGELOG 改回未发布段」；打过 tag 时再加本地删 tag 与远端删 tag 两步。
  - `release.mjs` 在发布前记住 registry 上的 `dist-tags.latest`，作为回退目标；`npm publish` 失败与 `verifyPublish` 失败都自动打印这套步骤，并给出单独跑的等价命令。
  - 新增 `node tools/release-rollback.mjs`（`npm run rollback:plan`）：默认只打印；`--apply dist-tag` 需要 `NPM_TOKEN`，只代为把 latest 指回上一版；`unpublish` / `deprecate` / 删远程 tag 一律只打印，由人确认后执行。
  - 证据：`test/release-rollback.test.mjs` 40 条（两种原因的步骤与命令、无上一版时不猜号、tagged 两步、未知 reason 回落、排版与不打印 token、CLI 退出码与 `--apply` 限制、release.mjs 接线与 verify-only 不把问题版本当上一版）。

- **自检修复**（`engine/index.js`、`src/web-ui.js`）：两处只在真实浏览器/连续操作下才暴露的一致性问题。
  - `partner2: null` 在排盘前归一化为未传：原先 compute 当它没给，句柄却把 `partner2:null` 编进去，同一对盘会拿到两个句柄。
  - 独立页耗时行改存 `last.perf`，由 `paint()` 末尾补回：切询问方向等重绘会换掉整段结果区，原先那一行随之消失；现在重绘后仍在且只有一行。
  - 证据：`test/hepan-triple.test.mjs` 新增 2 条（null 不出三方、与省略同句柄）；`test/perf-instrumentation.test.mjs` 增至 41 条（耗时行入状态、paint 末尾补回）；headless Chromium 实测切方向后 `.mp-perf` 仍为 1 行。

- **B6 第五批：大六壬原文录入**（`engine/citations.js`）：《大六壬大全》维基文库四库全书本，新增 3 条，`daliuren-sike` 由通行说改为 refs。
  - 卷一·起例「十干寄宫」：`甲课寅兮乙课辰，丙戊课巳不须论。丁己课未庚申上，辛戌壬亥是其真。癸课原来丑宫坐，分明不用四正神。`——四课起手。
  - 卷一·起例「贼克法」：`取课先从下贼呼，如无下贼上克初。初传之上名中次，中上加临是末居。三传既定天盘将，此是入式法第一。`——九宗门取初传。
  - 卷二·神将释「月将」：`逆布者谓之月将，其实即十二神也。`——月将定义；加时布盘仍标通行口诀、不标卷次。
  - 引文库合计 **93 条**（八字经典 41 + 引文索引 52），53 张卡里 44 张已定位原文、8 张通行说、1 张待补；`test/fixtures/citation-sources.json` 增至 58 个章页，`docs/citations.html` 同步重建。
  - 证据：`test/citations.test.mjs` 新增 6 条（书目登记、四课三传带 refs、三章定位、无省略号），共 56 条；`test/trace-sources.test.mjs` 同步把大六壬三层的出处改为已核验卷次。

- **A1+ 推导链出处**（`engine/trace.js`）：16 层的 `source` 统一成「出处；实现：engine/…」，能对上已录入篇名的才写书名卷次。
  - 六爻：六亲对读《增删卜易》卷一·用神章第八；伏神引卷二·飛伏神章第二十八；旺衰引卷一·月將章第十六、日辰章第十七。纳甲、世应明写「规则表 / 通行动诀，本仓未录入古籍章页」。
  - 八字：格局引《子平真诠》八、论用神（专求月令），调候参《穷通宝鉴》五行总论；旺衰**明写本仓量化规则、非古籍定数**；四宫标 Tyme 1.5.4 口径与 704 组对拍、未照录古籍章页。
  - 紫微：格局引《紫微斗数全书》卷三·论人命入格、谈星要论（与引文索引同源）。
  - 奇门：盘面事实引《奇门遁甲统宗》卷一·奇门秘诀总赋；旺衰引卷三；宫位引卷二与卷十一·玄机赋（中）；用神表与十干克应明写「本仓表，非古籍原文」。
  - 大六壬：本环境没有可稳定核验的公有领域章页，三层只标「通行口诀，未标卷次」，不拿别书条文冒充。
  - 证据：`test/trace-sources.test.mjs` 35 条（16 层都有实现位置、书名只能在已登记的五本里、所引篇名能在引文库找到、各体系「有据 / 无据」的措辞、Markdown 导出原样保留）；`test/trace.test.mjs` 同步文本断言。

- **D1+ 首屏耗时回显**（`src/engine-lazy.js`、`src/app.js`、`src/web-ui.js`、`src/panel-kit.js`）：
  - `__mpEnsureEngine` 记录每次取块耗时与是否命中缓存（`window.__MP_LAST_LOAD`），不埋点上报、不发网络请求。
  - 面板从点击到两帧后记「首屏」，并拆出引擎取块与排盘两段；连续点两次时旧回调按 `perfSeq` 丢弃，不会把上一次的数字盖到新结果上。
  - 独立页记「排盘」与「渲染（组 HTML + 写 DOM 的同步时间）」，明确不把浏览器真正绘制的那一帧算进来。
  - 结果顶部缝一行灰色小字：`首屏 42ms｜引擎 18ms（首次加载）· 排盘 9ms`，悬停说明「本机实测，不含网络与服务端」。缺哪段省略哪段，不编数字、不出 NaN。
  - 证据：`test/perf-instrumentation.test.mjs` 39 条（三种组合的排版、缓存标注与缺省、NaN/负数、懒加载两次调用与缓存、面板/独立页计时接线、无上报调用）。

- **C4-a 三方合盘**（`engine/hepan.js · tripleOf` + `engine/index.js`）：`hepan` 新增可选 `partner2`（字段同 `partner`），结果多一个 `triple`——
  - `pairs`：三对（你×对方 / 你×第三方 / 对方×第三方）各给 `total`、`level` 与三维度分数，顺序固定；`a-b` 与顶层 `score` 完全一致，另两对与「单独拿这两人排合盘」逐分相同，翻过来排也一样。
  - `best` / `hardest` / `spread` / `focus`：最顺、最需磨合、最高最低分差、三对之间分歧最大的那一维。**分差不足 3 分时不点名**，摘要改说「三对分数接近，不排名」，避免假精确。
  - **不合成「三人总分」**：三方只把三对两两关系并列——和不同的人相处是不同的事，合成一个数会把差异抹平。
  - 八字与紫微两种合盘都支持；`partner2: null` 视同未传，非对象或缺 `datetime` 报 `E_PARTNER` 并点名 `partner2`。
  - 第三人进排盘句柄与影子盘指纹（换第三人＝另一组盘，`baseId` 随之改变），下一轮只传 `handle` 即可复现同一组三方。
  - 面板与独立页：合盘 tab 勾「三方合盘（加入第三人）」后展开第三方日期/时刻/性别/出生地；结果区在三维度后加三对并列小表（分数 + 三维度），只在该勾选时出现。
  - 证据：`test/hepan-triple.test.mjs` 54 条（结构、与单独合盘/颠倒顺序一致、最顺与最需磨合、分歧维度、null 与坏输入、文本、紫微、句柄与影子盘、面板表与转义、面板/独立页/模板/宿主 schema 接线）。

- **C4-b 择日候选日比较**（`engine/zeri.js` + 面板/独立页）：`zeri` 新增可选 `candidates`（2–12 个真实公历日期）。
  - 给了就只比这几天（去重、保持输入顺序），不再按 `startDate` 扫区间；逐日分数与区间模式同一套公式，同一批日子逐分一致。
  - 结果多一个 `compare`：`best`（这一组最高分与结论、同分者）、`spread`（最高与最低分差）、`note`（「胜出只表示更合所问事项，不代表好多少」）。全部因冲属相被排除时 `best` 为 `null`，摘要如实写「都因冲属相被排除」，不硬推一个。
  - 入参守卫：不是数组、少于 2 个、超过 12 个、去重后不足 2 天、`2026-02-30` 这类不存在的日期，一律 `E_INPUT` 并说清改法；区间模式仍必须给 `startDate`。
  - 面板与独立页：择日表单新增「候选日（可空，只比这几天）」，逗号/顿号/空格分隔；结果区在候选模式下画逐日表（日期+农历 / 干支+建除 / 分数 / 结论 / 理由），最优行标「最优」，下方并列推荐、可用、回避与比较口径；区间模式仍用原文案，不铺 60 行表。
  - 候选日进句柄，下一轮只传 `handle` 即可复现同一组比较。
  - 证据：`test/zeri-candidates.test.mjs` 48 条（与区间模式同分、去重、冲煞排除、全排除、五类坏输入、文本、句柄、面板表与转义、四处接线）。

- **C4-c 同盘多口径并排**（`engine/diff.js · CALIBER_VIEWS`）：口径对照的每一行多回 `views`——只挑会影响结论的几项做两列并排，不改盘、不重算、不判优劣。
  - 八字：日柱 / 时柱 / 旺衰 / 格局（`frame.primaryName`）/ 喜用 / 起运；紫微：命宫 / 身宫支 / 五行局 / 身主 / 起大限；奇门：日柱 / 局数 / 值符 / 值使。字段取两张盘里已有的值，缺省写 `—`，不把对象硬串成 JSON。
  - 摘要里每行多一句「并排：日柱 丙辰 → 乙卯；…」，只列变化项；面板与独立页在根因后加 `mp-cview` 表（列名用档位名，例如「换日 / 不换日」），同样只列变化项。
  - 紫微身宫取 `body.branch`；原先写的 `body.ganzhi` 不存在，会一直显示 `—`。
  - 证据：`test/caliber-diff.test.mjs` 新增 21 条（视图键与行数、单元格格式、子年身主 火星 → 铃星、午年无变化项、奇门晚子时落日柱、文本并排、面板表与转义）。

## 0.57.0（2026-11-01，已发布）

> 本版主题：排盘句柄与一句话改参、推导链 Markdown 导出、喜忌中性档、引文索引三批补录、性能门槛。

- **B6 第二/三/四批原文录入**（`engine/citations.js`）：知识卡的「已定位原文」由 17 张增至 **43 张**，通行说由 35 张降至 **9 张**，待补仍 1 张。
  - 第二批 7 条，均取自中华典藏网公有领域底本、逐字核验后照录：《三命通会》卷二「论五行旺相休囚死并寄」（旺相休囚死）、卷三「总论诸神煞」（神煞取用）、卷三「论空亡」（空亡）、卷二「论大运」（起运）、卷七「论六亲」（六亲）、卷二「论三刑」（刑冲），以及《穷通宝鉴》「五行总论」（调候）。《穷通宝鉴》该本页首未标卷次，条目只写篇名、不替它补卷号。`bazi-tonggen-tougan` 仍留通行说——《滴天髓》只有「壬水通根透癸」的单条，没有泛论通根透干的段落，不拿个案冒充通则。
  - 第三批 6 条：《奇门遁甲统宗》卷一「奇门秘诀总赋」（阴阳遁与超神接气）、卷十一「玄机赋（中）」（六仪击刑、三奇入墓）、卷三（旺相休囚）、卷二（八门迫制与有气无气），以及《梅花易数》卷二「体用生克」。奇门章节只标页面实有的卷次与篇题，`qimen-gan-shengke`（干与落宫生克）留通行说——底本只有「奇仪对日干」的十神条，未见单列干宫生克条，不拿十神条文冒充。
  - 第四批 13 条：《增删卜易》（维基文库本，**繁体照录**）——卷一用神、月将、日辰、动变生克冲合、六神、六合、六冲、反伏、各门类应期总注，卷二飞伏神与进神退神；覆盖 `liuyao-yongshen`、`liuyao-fushen`、`liuyao-wangshuai`、`liuyao-yongshen-shuai`、`liuyao-quanggu-shuai`、`liuyao-dongbian`、`liuyao-liushen`、`liuyao-liuhe`、`liuyao-liuchong`、`liuyao-fanyin`、`liuyao-fuyin`、`liuyao-jintui`、`liuyao-yingqi` 十三张卡。`liuyao-jintui-yong` 仍留通行说：底本把进退落在「動而化」的吉凶喜忌与应期上，未见单列「用神化進／化退」条，按用神与忌神分档是本插件引申。
  - 引文库合计 **90 条**（八字经典 41 + 引文索引 49：紫微 23、三命通会 6、增删卜易 13、奇门 5、穷通宝鉴 1、梅花 1）。`test/fixtures/citation-sources.json` 同步到 56 个章页快照，`test/citations.test.mjs` 累计 50 条断言（书目登记、卡片带 refs、各条取书与章名、无省略号）。大六壬仍标通行说：本环境无可稳定核验的公有领域章页（ctext 明示禁止抓取、中华典藏网未收）。
- **D3 性能门槛**（`tools/check-perf.mjs`）：`tools/bench.mjs` 拆出 `runBench()` 与 `CASES` 供复用（CLI 行为不变，`--json` 仍可用），新增门槛脚本对八体系样本逐项判超限——首次 150ms、p50 10ms、p95 25ms、带解析 250ms、1000 盘 4000ms、RSS 800MB。阈值按文档目标（bazi p50 < 1.5ms、1000 盘 < 400ms）留 5–10 倍余量，拦的是数量级回退而非毫秒级抖动；`DSH_PERF_SCALE=3` 可按倍数为慢机放大上限，不改代码。`npm run bench` 只测不判，`npm run check:perf` 判超限，`test:ci`、GitHub Actions 与 `tools/autopublish.mjs` 的发布闸门都串上。证据：`test/perf.test.mjs` 29 条（八体系基准形状、真实样本判定、超限样本必红、阈值余量与放大、npm/CI/自动发布/README/方案接线）；本机实测 bazi 首次约 20ms、p50 0.78ms、1000 盘约 355ms、RSS 约 80MB、带解析 <8ms。
- **自动发布参数校验**（`tools/autopublish.mjs`）：只认 `--dry-run` / `--init` / `--force`，其余参数（例如误写 `--dry`）立即以退出码 1 拒绝并列出可用参数，不再静默忽略后照常提交推送；未知参数不触碰状态文件。证据：`test/autopublish.test.mjs` 8 条。
- **C2 一句话改参**（`engine/revise.js`）：把「换成紫微看 2030 年事业」「女命」「晚子时算次日」「出生在成都」「不用真太阳时」「详细解读一下」这类原话翻成参数补丁再排盘，可配合 `handle` 使用——上一轮的出生信息不必重报。**只认明确句式**：换体系必须有切换词（换成 / 改成 / 看 / 用 / 按…），单提一句「紫微里怎么说」不换盘；出生年份与时辰一句话给不出分秒，不猜，改为在 `ignored` 里明说改不了、请直传 `datetime`。识别不到时盘面一字不动，`applied` 为空。结果 `revision` 回传 `text` / `applied`（`key`、`label`、`value`、`display`、`from`、`fromDisplay`、`ignored`），旧值翻成中文（`system: bazi → 八字`、布尔 → 开 / 关、`asOf` → 年份），没设过的记「（未设）」而不是编默认值。改参先生效、后跑地址解析与日期补全，换体系会连带改走另一套默认值；句柄记的是改后参数、不含 `revise` 原文，所以同一张盘换个说法得到同一句柄。摘要末尾给「【改参】原话 + 逐条 旧 → 新 + 未处理」，面板与独立页给改参卡（先改动、后句柄）。`revision` 属请求回显，影子盘指纹与口径对照均忽略。
- **C1 排盘句柄**（`engine/handle.js`）：每次排盘在结果里回一个自包含短句柄 `mc1.<base64url>.<8 位校验>`，下一次只传 `handle` + 增量参数（`asOf`、`direction`、`question`、换 `system` 看同一时刻另一套盘）即可，不必重报出生信息。句柄把参数本身编码进去而不是存在内存里——宿主一次工具调用可能落在不同进程，内存句柄拿不到下一轮。只收影响盘面的参数：`trace` / `shadow` / `withInterpret` / `cross` / `ask` / `caliber` / `geocode` 这些输出开关不进句柄，所以要不要解析、要不要推导链都不改变句柄；`seed` / `asOf` / 各流派开关必须留下，否则复现不出同一张盘。键序固定（键名排序），参数写法不同也得到同一句柄；校验位用 FNV-1a，截断、改字、错前缀都报 `E_HANDLE` 并给修复提示，不会静默排成另一张盘。base64url 与 UTF-8 均为自带实现（不依赖 Buffer / btoa / TextEncoder），引擎在 Node、浏览器与 vm 沙箱里都能跑。`compute` 入口先 `resolveHandle` 再排盘，显式 `undefined` 不覆盖句柄字段；宿主工具新增 `handle` 参数，并在地址解析、日期补全之前先并回参数，避免追问时漏掉出生地导致真太阳时不同。结果摘要末尾附「【排盘句柄】+ 用法」；面板与独立页给句柄卡与「复制句柄」按钮，并写明「是编码不是加密，含出生时间与出生地，别公开贴出」。影子盘指纹与口径对照忽略 `handle`（它反映的是另一次请求，不是盘面差异）。随机抽牌 / 起卦：句柄复现参数、不复现牌面，要复现须带 `seed`。
- **F 喜忌中性档**（`engine/geju.js`）：忌神里全局分量不足 0.5 的另列 `neutral`（含 `element` / `role` / `verb` / `weight`），摘要、解析层、白话层与面板 chip（`中性偏忌 X 0.3 分`）都写明「近零，不作实忌」。**只是展示分档，`avoid` 不变**——局中没有不等于运里不来，大运/流年遇之仍按忌计，评分与调候结论一律不动。
- **A5 推导链导出**（`engine/trace.js`）：`trace: true` 时结果同时给 `traceText`——同一份层的 Markdown（标题 + 每层结果/规则/输入表/出处），可直接贴进对话或文档；表格单元格转义 `|` 与换行。面板推导链抽屉加「复制 Markdown」按钮（内容取自隐藏 textarea，与引擎同源，不在前端重排）。五个体系（六爻 / 八字 / 紫微 / 奇门 / 大六壬）共用同一份导出逻辑。
- **测试**：新增 `test/handle.test.mjs`（70 条：往返、增量、换体系、键序、输出开关不进句柄、截断/改字/错前缀、中文与表情、影子盘不受影响、宿主 schema 与执行、面板与独立页接线）、`test/revise.test.mjs`（68 条：九条改参规则的命中与不命中、改参后盘面真变化、未设原值回显、忽略项提示、句柄配合、宿主执行、改参卡转义与接线）、`test/trace-export.test.mjs`（60 条）、`test/yongshen-neutral.test.mjs`（29 条）、`test/citations.test.mjs`（50 条，含 B6 第二/三/四批 23 条）、`test/perf.test.mjs`（29 条）、`test/autopublish.test.mjs`（8 条：未知参数直接拒绝、白名单固定）。当前 **122 个测试文件 / 5653 条断言**，七道闸 + 性能门槛全绿。

## 0.56.0（2026-11-01，已发布）

- **邮件反馈 2026-10-31（三条）**：输入区错位、八字旺衰与喜忌、紫微子年身主。逐条处理记录见 `docs/用户反馈记录.md`。
- **面板输入区对齐**（`src/app.js`）：① `.mp-input` / `.mp-textarea` 补 `box-sizing:border-box`——Chrome 下 select 默认 border-box、input 默认 content-box，同为 36px 时 input 实高 50px，底对齐后「性别」下拉比日期框低 14px；② 「晚子时换日」改成与「真太阳时」「联网精确到区县」同构的普通勾选，去掉误加的 `mp-field mp-checks`（继承 `margin-top:13px` 后比同行低 7px），并补 title 说明；③ 降列由视口 `@media` 改为 `.mp-wrap` 容器查询（860px 两列、480px 一列）——侧栏宽度不等于窗口宽度，面板拖到约 600px 而窗口仍是 1200px 时原来照排四列、输入框被压到 117px；「八字 × 紫微 交叉验证」勾选独占一行。无头 Chrome 以面板实际 CSS 在 600/940px 两档复测：同行输入框顶底一致、三项勾选中线一致。独立页本有全局 `*{box-sizing:border-box}`，不受影响。
- **八字旺衰 · 合会折根与虚透减半**（`engine/bazi.js`）：地支通根前先看会合——三会成方时同类支不折、印局按 6 成、他局按 1 成；三合成局同类不折、印局 6 成、他局 2 成；六合同类不折、印 8 成、他 5 成，且只折局外那一支（已入会/合局的支归该局）；半合/半会不折。天干比劫/印透出而折根后同类藏干不足 0.3 的作**虚透**，帮扶按半计。`strength.parts` 新增 `structure`（折根说明）与 `virtualHelpers`，`detail` 追加「合会折根：…」「虚透X帮扶减半」，`method` 改为「…（三会/三合/六合折根）+ 天干帮扶（虚透减半）…属简化算法，非唯一流派」；推导链旺衰层同步新增「合会折根」「虚透」两行。亥月戊土、年子时丑、日坐寅这一型，旧算法把丑中己土与寅中戊土当足根、天干己土当实帮，判「偏强」并忌土；现判偏弱/身弱、喜火土、忌金水木。416 张盘的五档分布由 52/82/56/114/112（偏弱/中和/身弱/偏强/身强）变为 68/87/69/96/96，偏强与身强各降约 15%。
- **紫微身主两派**（`engine/ziwei.js`）：新增第十个流派开关 `shenzhuSchool`——`common`（默认，子午皆火星，与 iztro 及通行排盘一致）/ `verse`（安身主诀「子午安身铃火宿」逐字：子铃星、午火星；维基文库本《紫微斗数全书》卷一、卷三未见此诀，故不标作《全书》原文）。**默认行为变化：子年身主由铃星改为火星**；午年两派都是火星，其余十支不变。子午年盘带 `bodyMasterSchool` 与 `bodyMasterNote`，文本 `【身主】火星（子午皆火星）`、面板 `＊` 悬停说明出处；`rules.schools` 列入身主口径。工具 schema、`engine/index.js` 平铺透传、口径对照（紫微 11 → 12 组）同步；`bodyMasterSchool` / `bodyMasterNote` 属口径回显，不计盘面差异。
- **测试**：新增 `test/bazi-strength-structure.test.mjs`（32 条：同型盘偏弱与喜火土、三会/三合/六合/局内支不重复折、同类局与印局、无合会盘不受影响、推导链两行、五档分布不塌缩）、`test/ziwei-shenzhu.test.mjs`（29 条）、`test/panel-form-align.test.mjs`（11 条）；`test/caliber-diff.test.mjs` 补子年身主能检出、午年无差异与 12 行渲染；`test/ziwei-schools.test.mjs` 开关数 9 → 10；`test/trace.test.mjs` 的争议样本换成 1962-03-22。当前 **116 个测试文件 / 5366 条断言**，七道闸全绿。
- **自动发布改为只推送**（`tools/autopublish.mjs`）：定时任务只跑七道闸、重建产物、提交并推送 `main`，不再自动升版本号、打 tag 或发 npm；push 失败重试 3 次（15s / 30s 退避）。发版仍走 `tools/release.mjs`。
- **B5 玄空替卦与年月日时飞星**（`engine/fengshui.js`）：`action:'xuankong'` 新增兼向替卦与年月日时紫白。兼向按「坐山偏离本山中心超过 4.5°」判定，接受 `sittingOffset` / `sittingDegree` / `facingOffset` / `facingDegree`（坐向都给须一致）；替星取《沈氏玄空学》坤壬乙诀 24 山全表（1/2/6/7/9 五星），山星/向星改以替星入中，顺逆仍按替星本宫同元龙；同卦兼/出卦兼、原运星与「用替而未替」都在结果里标明，替卦不再套正向旺山旺向表。年月日时紫白按公式派：年逐年退一位；月按年支三组起 8/5/2、逐月退一位；日按冬至–夏至三段起 1/7/4 与 9/3/6，阳遁顺飞、阴遁逆飞；时按日支三组子时起 1/7/4 与 9/3/6，阳遁顺行顺飞、阴遁逆行逆飞；月取节气月、日按公历日且 23:00 后归次日。新增 `fortuneDate` / `fortuneTime` 入参；只给年份时只排年星并提示补日期。摘要、面板九宫卡、独立页表单（兼向度数/飞星日期/时刻）同步；口径异说写进 note，不与「日星一律顺飞」「月按农历月」等派别合并。
- **测试**：新增 `test/fengshui-tigua-zibai.test.mjs`（102 条）——替星表 24 山、4.5° 阈值、同卦兼/出卦兼、8 运子午替星改盘、5 运用替而未替、度数输入与边界、年月日时六个分段锚点、时家冬夏×日支三组、晚子时、中宫文案、摘要/面板/compute 接线；`test/fengshui-ui.test.mjs` +5 条替卦卡与飞星事实；原玄空测试的 scope 与来源条数同步。当前 **113 个测试文件 / 5286 条断言**，七道闸全绿。
- **信息层次与 AI 解读可读性**（`engine/followup.js`）：给 8 个体系登记「阅读层次」（八字：基本信息 → 四柱 → 旺衰/格局/用神 → 合冲/神煞 → 大运流年 → 古籍依据；紫微、六爻、梅花、大六壬、奇门、塔罗、风水各有顺序，未知体系走通用兜底）。`askPrompt` 先列层次、再给摘要；回答要求由 4 条改为 5 条：结论 → **骨架事实**（按层次 2–4 行，不掺倾向）→ 最多两条判断（盘面/白话/倾向/边界）→ 只记一件事 → 边界与禁语，并写明「上一层没交代清楚，不要跳到下一层」。层次顺序参考 ziwei.pub/bazi 的分区，只借层次、不复制文案；固定骨架由约 520 字增至约 700 字，仍受 `test/ask-prompt.test.mjs` 的 900 字上限约束。
- **参考资料登记**（`docs/参考资料与对拍来源.md`）：记录 ziwei.pub/bazi 的访问日期、采用的命宫/身宫/胎元/胎息口径与信息层次、704 组日期对拍证据，以及未采用的文案/视觉/AI 内容；另列 tyme4ts 与历法、卦例、紫微、八字、奇门对拍入口。约定「先登记再改代码、采用范围必须能指向测试或对拍证据」。
- **测试**：`test/ask-prompt.test.mjs` 由 67 条扩到 81 条——层次顺序、不跳层、骨架段、5 条编号、8 体系非空不重复、未知体系兜底；当前 **112 个测试文件 / 5179 条断言**，七道闸全绿。
- **B4 奇门十干克应 + 六仪入墓**（`engine/qimen-ganying.js`）：新增通行 100 组「天盘干加地盘干」表（格名 + 断语 + 底本链接），每宫与中宫随盘带 `ganYing`。底本取 daoisms 通行表，《奇门遁甲元灵经》卷二只存甲、乙、丙三组且措辞不同，作为异文并列、不合并；底本个别讹字按文义校正（么→私、病病→病、得→行、磋砣→蹉跎）。新增六仪入墓（戊墓戌乾六、己庚墓丑艮八、辛壬墓辰巽四、癸墓未坤二），与三奇入墓并列进 `conditions.liuYiRuMu`。摘要、解读层「十干克应」段、面板九宫格与事实行、推导链关系层、知识卡 `qimen-ganying` 与引用索引同步；克应只作取象与读盘线索，与门宫/干宫生克并列，不自动折吉凶。
- **测试**：新增 `test/qimen-ganying.test.mjs`（46 条）——100 组完整无重、抽样条目、六仪入墓映射、60 个时辰 × 480 宫逐宫有克应、全链路显示；`test/trace.test.mjs` 宫位条件断言补十干克应与六仪入墓。当前 **112 个测试文件 / 5165 条断言**，七道闸全绿。
- **B6 引文索引补齐**：知识卡 53 张（新增 `qimen-ganying`），已定位原文 17 张、通行说 35 张、待补 1 张；`docs/citations.html` 重新生成。
- **A1+ 奇门四层推导链**（`engine/trace.js`）：新增 `facts → yongshen → states → relations`，依次摊开盘面事实（四柱、节气局数、旬首、值符值使、空亡驿马）、按询问方向取的用神落宫、门/星/天盘干按月令的五态、门迫/宫制门/干宫生克与击刑入墓空亡。用神表由 `engine/qimen-interpret.js` 的 `qimenYongshen()` 单源导出，解读与推导链不再各写一份。
- **A1+ 大六壬三层推导链**（`engine/trace.js`）：新增 `tiandipan → sike → sanchuan`，给出月将加时后的十二支天地盘与天将、四课上下神与生克、三传的干支/六亲/天将/旬空与课体。只读结果，不改盘面。
- **接线**：面板与独立页对奇门 / 大六壬默认请求 `trace`；奇门把「询问方向」传入 compute，改方向时只重建用神落宫层，不重新起局。
- **D1+ 拆分 chart 块**（`tools/build-client.mjs`）：原 `chart` 拆成 `bazi` / `ziwei` / `hepan` / `trend` 四块，分块总数 15 → 18。八字块内含人生 K 线索与紫微交叉验证，紫微块带八字交叉验证，合盘块同时带两套引擎与紫微合盘模板，人生 K 线块不再背紫微。各块 gzip：bazi 178KB、ziwei 174KB、hepan 177KB、trend 154KB（原 chart 183KB）；入口仍为 71KB。分块之间不共享代码，代价是重复的公共栈，换来每个 tab 只取自己需要的块。
- **测试**：`test/chunks.test.mjs` 由 102 条扩到 121 条——18 块注册/自包含/体积、八字与紫微在各自块内开交叉验证、紫微合盘在 hepan 块内复算、切块后缓存不重复拉取；统计 **107 个测试文件 / 4978 条断言**，七道闸全绿。
- **B2 紫微破格**（`engine/ziwei.js`）：34 条格局逐条给 `status`（`formed` / `broken` / `n/a`）、`breaks`（哪颗星落在哪一宫）与 `breakRule`。吉格与武贪、双禄交流、火贪铃贪再判破格：三方四正见羊陀火铃、空劫或化忌即破；石中隐玉另判「三方无科禄」、火贪铃贪按「三方有凶杀」、武贪按「武贪化忌」、机月同梁/昌曲/魁钺夹命各按本条原文判。忌格与命无正曜、杀破狼不判破格，明确标 `n/a`。摘要、文本、解读层与面板 chip 同步显示破格数与理由；`test/ziwei-poge.test.mjs`（25 条）扫 312 张盘复核。
- **B6 引文索引**（`engine/citations.js` + `docs/citations.html`）：新增《紫微斗数全书》23 条原文（维基文库，卷一/卷三，含卷章与链接），与既有 41 条八字原文合成 64 条引文库；53 张知识卡逐张登记出处（B4 新增 `qimen-ganying`），17 张已定位到可核验原文，其余标「通行说」或「待补」并写清理由，不冒充原文。`test/citations.test.mjs`（27 条）核验「原文子串确实出现在来源正文里」，重建索引页并与磁盘逐字比对；`docs/citations.html` 由 `npm run build:citations` 生成。
- **测试**：新增 2 个测试文件（52 条），当前 **109 个测试文件 / 5030 条断言**，七道闸全绿。
- **B3 四宫口径修正**（`engine/bazi.js`）：新增**胎息**（日干五合、日支六合），并把命宫/身宫由「命宫对宫」改为 ziwei.pub 同款 Tyme 1.5.4 口径——命宫＝27 减生月与生时支、取模后加二，身宫＝11 加两支、取模后加二，干支并入六十甲子。旧口径在 1990-05-12 14:30 得丙戌/庚辰，与紫微派页面（辛巳/己丑）不符；修正后四宫为壬申/壬子/辛巳/己丑。已用 tyme4ts 1.5.4 对 1950–2020 的 **704 组日期逐组对齐，0 处不符**。摘要、解读层「胎命身」、面板 chip、独立页与八字推导链第 3 层（`palaces`）同步；`test/bazi-palaces.test.mjs`（57 条）锁 6 组日期与「胎息＝五合六合」「命宫+身宫支序＝6」两条结构不变量。
- **B3 专旺成格 / 真从假从**（`engine/geju.js`）：专旺补 `status`（成格/待定/破格）与 `breaks`——月令助旺且不见官杀/财星为成格，月令不助为待定，官杀 >1.2 逆势或财 >1.8 耗旺为破格；三合局全另记 `ju`。从格补 `rootWeight`（地支藏干同类/印 + 天干透出）与真假：完全无根、无比劫印绶透出为**真从**，有中气/余气微根或虚透为**假从**；见一个本气根（≥1 分）就不作从格。摘要、解读层「格局依据」、面板 chip（破格虚线、假从/待定警示色）与原文取条同步；破格不再挤占专旺单章，化气与假从同盘时化气优先。`test/bazi-special.test.mjs`（28 条）锁成/待/破与真/假从各档及全链路显示。
- **测试**：新增 2 个测试文件（85 条），当前 **111 个测试文件 / 5119 条断言**，七道闸全绿。

## 0.55.0（2026-10-31，已发布）

补齐口径对照里的紫微九派，并把邮件反馈里的两处显示口径收紧：五合不再直接写「合化」，自化与生年/大限/流年四化分三层显示。

- **口径对照补全**（`engine/diff.js`）：紫微由闰月、真太阳时两组扩到 11 组，新增亮度表、庚干四化、天马、天空、截空旬空、魁钺、天伤天使、长生、晚子时九类流派开关。默认档与另一档都取自引擎枚举，平铺参数与 `schools` 嵌套都能读；非法值回落默认。切换后 `schools` / `rules.schools` 只是口径回显，不再计入盘面差异。
- **同一张表**：面板折叠卡、独立页、`tools/caliber-diff.mjs` 与工具 `diff: true` 仍共用 `CALIBER_SWITCHES`；紫微卡一次列 11 行，summary 先给「几组影响此盘」。`shadow` / `trace` 属于派生展示，不再参与对照，避免面板里每组开关都被影子盘回显误报成「有变化」。
- **五合措辞**（`engine/bazi.js`）：干支关系只标「有合」，摘要与面板写「戊癸合（化火待定）」；是否真化仍由化气格条件另判，不把「合」直接说成「化」。
- **四化分层**（`src/panel-kit.js`）：生年四化实心、大限/流年四化空心、自化改为彩色字 + 虚下划线，图例补「虚下划线=自化」，宫位详情同步；自化块带读屏说明。
- **公开对拍补奇门**（`tools/verification.mjs`）：接入 `test/fixtures/qimen-20.json` 的 20 个时辰 × 9 宫 = 180 个宫位，逐宫核四柱、局数、值符、值使、星门神与天盘干；报告从 457 行增到 **477 行**，新增「奇门」筛选与卡片。徽章改为披露「128 例 · 5 剔除 · 312 紫微 · 20 奇门 · 12 交运」。
- **CI 同源加固**：构建产物与对拍报告的 `git diff` 前先 `git add -N`，新增的 `client.*.js`、报告页或徽章不再因 untracked 而漏检；`release` 走同一套判据。自动发布指纹补入报告生成器与两份对拍 fixture。
- **工具输出克隆**（`engine/index.js`）：`jsonSafe` 不再 `JSON.parse(JSON.stringify())`，改为等价递归深拷贝（NaN→null、-0→0、Date→ISO、数组空位→null、对象内 undefined/函数丢键、循环引用抛错），省掉每次 `compute` 建一遍几百 KB 中间字符串。21 个体系 21 组样本改动前后输出逐字节相同、影子盘 ID 不变。
- **三合表单源**（`engine/shensha.js` / `engine/almanac.js`）：将星/驿马/桃花的 `trioKey` 与黄历「三合吉配」「煞方」原本各自维护的三合成员表，改为从 `engine/sanhe.js` 的 `SANHE_GROUPS` 派生，全仓只剩一份三合成员表。
- **测试**：`test/caliber-diff.test.mjs` 由 129 条扩到 205 条——11 组开关、默认档/另一档枚举、嵌套读取、回显忽略、九派逐项能改盘、shadow/trace 不参与对照、11 行渲染；`test/relations.test.mjs` 补五合「待定」与五组干合；`test/layout.test.mjs` 补自化分层与图例；`test/verification.test.mjs` 补奇门 20 例与改坏值符的检出。统计 **107 个测试文件 / 4925 条断言**，七道闸全绿。
- **文档**：README 口径对照、精度与口径、公开对拍三处同步；独立页「方法与验证」补奇门 20 例。
- **版本说明**：0.51.0–0.54.0 未单独发布，能力均并入 0.55.0。已于 2026-10-31 发布：npm latest 从 **0.50.5** 跳到 **0.55.0**（80 个文件，shasum `a8640df32d5451078bd15bf94d7b95da0547f698`），tag 与 GitHub release 同为 `v0.55.0`。

## 0.54.0（2026-10-31）

把「验了什么、差在哪」做成公开页：新增 `docs/verification.html` 与 README 顶部徽章，报告数字与 CI 共用 `tools/verification.mjs` 一个数据源。

- **128 条卦例**：《卜筮正宗》成对 93 条 + 静卦 35 条，逐条核本变卦、动爻数、卦宫、缺爻、旬空；源 138 条中被剔除的 5 条连同原书理由逐条列出（动爻标记冲突、缺爻冲突、卦宫冲突、静卦核对失败）。
- **312 张紫微盘 × 34 条格局 = 10,608 条判定**：沿用 `test/ziwei-patterns.test.mjs` 的扫描盘（1950–2025、月日时错开）与独立谓词——只读星位与四化，不调用引擎格局函数；34 条每条至少命中一次，命中分布列在报告折叠区。
- **12 个交运案例**：覆盖阳年男女顺逆、闰日 02-29、真太阳时、立春/晚子时边界、长间隔与 ΔT 近似区间；独立复算取节、三日折一年比例、`jiao/startAge` 同源、闰日十年后退位与口径标注。
- **报告页**：`docs/verification.html` 自包含，无外链脚本 / 样式；可按「一致 / 剔除 + 理由 / 不一致」与体系（六爻 / 紫微 / 交运）筛选，附搜索与 34 格局命中分布；窄屏表格横向滚动，深色跟随系统。README 顶部徽章 `docs/assets/verification-badge.svg` 由同一生成器写出，0 处不符时为绿色。
- **CI 同源**：新增 `test/verification.test.mjs`（23 条）直接 import 生成器，断言 128 / 312 / 12 / 0 不符、剔除项带理由、报告与徽章和生成结果逐字节一致；并故意改坏一条卦宫判定，要求校验器立刻标「不一致」。CI 增加「重建报告 + `git diff`」步骤，`release` 也会重建并校验报告；任何判定变化或忘记重建，CI 都会红。
- **测试**：统计 **107 个测试文件 / 4836 条断言**，七道闸全绿。报告页 390×844 深色无横向溢出，筛选按钮与表格可读。

## 0.53.0（2026-10-31）

把 `client.js` 按 tab 拆开：入口只留界面与懒加载器，引擎落到 15 个自包含分块，首屏 gzip 从 0.52 的 334KB 降到 71KB（目标 < 100KB）。

- **拆包协议**：DSH 客户端模块支持 `require.async("./client.<name>.js")`，分块用 `__ModuleLoader__.load({ id, chunk, factory })` 注册。入口 `client.js` 不再内联 `engine/*.js`，只保留 panel-kit / app / core；新增 `src/engine-lazy.js`，按当前 tab 取分块，并把该块统一入口的导出合并到同一个 `Engine` 对象。分块自包含，宿主与入口都缓存已加载的块。
- **分组**：chart（八字 / 紫微 / 合盘 / 人生 K 线）、name、fengshui、liuyao（六爻 / 梅花）、qimen、daliuren、tarot、almanac、convert、zeri、chenggu、xiaoliuren、star、numerology、mbti，共 15 块，覆盖全部 19 个 tab。互相依赖的体系（如合盘双方、八字交叉紫微）落在同一块，避免运行时同步 require 另一个分块。
- **安全降级**：`buildModule` 的 import 解构改为 `(__mods.x || {})`，统一入口对未随块加载的体系引用能安全落空，只有实际被调用的体系需要在场。入口在 `require.async` 缺失时给出明确的宿主版本提示，不静默白屏。
- **界面**：`run()` 与切到人格 tab 前先 `await ensureEngine(k)`，加载期间显示「正在加载本页需要的引擎…」；MBTI 题面不再在未加载时缓存空问卷；独立页与旧宿主没有分块加载器时回退到现成的完整 `Engine`，离线页行为不变。
- **构建与自检**：`tools/build-client.mjs` 生成入口 + `client.<name>.js`，并清理已下线分块的旧文件；`tools/check-bundle.mjs` 现在同时校验入口与每个分块的编译、注册名、返回 `Engine`、与源码逐字节一致，并守住入口 gzip < 100KB；`release` 的产物 diff 与 tarball 关键文件加入分块。构建日志按 UTF-8 字节数报告，不再用字符串长度低估中文体积。
- **体积**：入口 `client.js` 239KB（UTF-8）/ gzip 71KB；最大分块 chart 179KB gzip，六爻 128KB、奇门 123KB、塔罗 122KB、六壬 118KB、起名 98KB，速查类 46–68KB、人格 55KB。首次打开只下载入口，排盘时才取当前 tab 的块。
- **测试**：新增 `test/chunks.test.mjs`（102 条）：19 个 tab 全映射、15 个分块的注册名 / 自包含 / 体积、入口体积与懒加载、19 个体系的分块引擎与源码逐字节一致、切回 chart 仍能排紫微、分块缓存不重复拉取、无 interpret 的分块不抹掉 DIRECTIONS。统计 **106 个测试文件 / 4813 条断言**，七道闸全绿。
- **界面验证**：CDP 真机视口 390×844 深色：`innerWidth = scrollWidth = 390`、结果区 366px、`prefers-color-scheme: dark = true`、正文底色 `rgb(18,17,13)`、推导链入口在；无横向溢出。940×900 浅色 `scrollWidth = 940`、结果区 888px。

## 0.52.0（2026-10-31）

把「结论怎么来的」摊开：新增 A1 推导链 `trace: true`，六爻 / 八字 / 紫微逐层返回 `{field, rule, inputs, result, source}`，面板用右侧抽屉逐级展开。

- **六爻五层**：纳甲（本卦上下卦 → 六爻干支）→ 六亲（卦宫五行 → 逐爻六亲）→ 世应（八宫世位 → 世 / 应爻）→ 伏神（用神不上卦时取本宫首卦同位，附飞伏生克与出伏判定）→ 旺衰（月建 / 日辰 → 用神五态与全卦逐爻状态）。未选询问方向时明确写「未选询问方向（综合），未取用神」，不再误写成「未指定所问之事」。
- **八字两层**：旺衰分值（日主 / 月令权重 / 通根 / 天干帮扶耗泄 → 分值、档位与 detail）与格局取用（月令格与取格依据、十神分量、调候 → 主格 / 兼格、喜忌、有争议五行）。
- **紫微一层**：格局命中条件（命宫、五行局、命主身主、命中数 → 逐条命中的格局与 evidence；未命中时写明只是不在已收录清单内）。
- **只读与可复现**：`buildTrace` 只读 `compute` 结果，不重算、不读时间与随机，`trace` 开关前后盘面逐字节一致、影子盘 ID 不变；生成失败只挂 `traceError`，不影响主结果。`renderText` 追加【推导链】段，宿主 `metaphysics_chart` 同步暴露 `trace` 布尔参数。
- **界面**：结果顶部新增「推导链」入口（显示层级链与层数），点开为右侧抽屉；每层用 `<details>` 逐级展开，先给规则与结构化输入，再给结果与出处。关闭按钮 44px、遮罩与 Esc 可关、关闭后焦点回入口；窄屏抽屉占满 100vw，深色只换变量，打印隐藏。六爻的询问方向一开始就参与 compute（否则用神会退成综合），改方向时只按新方向重算用神 / 旺衰 / 伏神三层，不重摇一卦。独立页 `#out` 的入场动画从「位移 + 淡入」改为纯淡入——`transform` 动画会为 fixed 子元素建立 containing block，曾把抽屉关在结果卡片里。
- **测试**：新增 `test/trace.test.mjs`（61 条）：五层 / 两层 / 一层的字段与顺序、每层 rule / inputs / result / source、伏神在爻上与不上卦两种分支、未选方向说明、改方向 refresh 不重摇也不改原结果、trace 不改盘与不改影子盘 ID、文本层、面板抽屉与转义、面板 / 独立页接线、宿主 schema 与执行。统计 **105 个测试文件 / 4711 条断言**，七道闸全绿。
- **界面验证**：390×844 深色下抽屉贴视口右侧（`rect = 0,0,390,844`）、5 层、首层展开、关闭按钮 44px、无横向溢出；关闭后 `aria-hidden=true`。900px 浅色与既有结果卡均无溢出。

## 0.51.0（2026-10-31）

给每张盘一个可复制的「影子盘」ID，并把 `client.js` 真正压缩（路线图 A4 + D1）。

- **A4 影子盘（引擎）**：新增 `engine/fingerprint.js`（规范化 JSON + 35 位短哈希，纯函数）。`compute({ shadow: true })` 在结果上挂 `shadow: { id, baseId, version, system, payload, reproducible, asOfPinned }`。`id` 含版本，`baseId` 不含版本；同一组归一化参数（键序无关、默认值等价、地址与等值经度等价）在任何机器上得到同一 ID，版本升级只改 `id`、不改 `baseId`。
- **版本 diff**：`shadowDiff(previous, current)` 只在 `baseId` 相同时比对，复用 `engine/diff.js` 的标签 / 根因 / 分类，返回「几处变化、根因字段旧值→新值、连带分类」；`compute({ shadow: true })` 的结果可直接比，也可以比 `shadowSnapshot()` 存下的轻量快照。面板与独立页把快照写进本地存储（最多 24 张盘），同盘重排时自动与上次比对，升级后展开就能看到字段级差异。
- **随机起卦不撞 ID**：塔罗 / 六爻未给 `seed` 时，实际抽到的牌面 / 六爻值会算进指纹，两次不同抽牌得到不同 ID，并标「不可复算」；给定 `seed` 或六爻值时同参数同 ID。八字 / 紫微未固定 `asOf` 时提示「流年随此刻变化」。
- **界面**：结果上方新增影子盘卡（ID 等宽、一键复制、版本与基础指纹），有跨版本 / 跨次变化时展开「与上次同盘比对」；共享调色板，深色只换变量，窄屏复制按钮 44px、无横向溢出，打印时强制展开并隐藏复制按钮。面板与独立页同一渲染路径。
- **工具**：宿主 `metaphysics_chart` 新增 `shadow` 布尔参数，版本从 `package.json` 注入；`renderText` 追加【影子盘】行。独立页由 `build-html` 注入 `window.__MP_VER`，不再落到 `dev`。
- **D1 压缩**：`tools/build-client.mjs` 用 esbuild（`minify + target es2020 + charset utf8`）压缩，未安装时退回保守去注释；`client.js` 从 **983KB → 640KB**，gzip **329KB**。`check-bundle` 改为在未压缩源码上逐模块定位、对真实文件做整文件与宿主形态执行，并与压缩重建结果逐字节比对；CI 增加 `npm ci`；`client-bundle` 新增体积断言（低于源码 80%、gzip < 360KB），并改走统一断言工具（失败会真正退出非零）。路线图原定 gzip < 100KB，不做内容拆分与懒加载无法达到，这里按实际体积设闸并写明。
- **界面验证**：390×844 深色下 `scrollWidth = 390`、卡片宽 366、复制按钮 44px、卡片底色 `rgb(33,31,24)`；900px 浅色下卡片 848、复制按钮 40px；模拟旧版本存档后自动 diff 正确显示「版本变化 + 1 处字段」。
- **测试**：新增 `test/shadow.test.mjs`（55 条）：ID 确定性 / 键序 / 默认值 / 参数敏感性 / 体系 / asOf、地址与经度等价、版本只改 id、随机牌面不撞 ID、diff 根因与分类、文本层、面板转义与复制按钮、localStorage 自动对盘、宿主 schema 与版本注入。统计 **104 个测试文件 / 4650 条断言**，七道闸全绿。

## 0.50.5（已发布 2026-10-31）

修 GitHub issue #1：「身弱喜火土，给分析成忌火土了」——顺带修掉同源的「同一五行同时出现在喜用与忌神」。

- **问题在哪**：`engine/geju.js` 的 `yongshenOf` 先按扶抑定喜忌，再让调候在「调候优先」时把 `climate.avoidElement` 插进 `avoid`；如果这个五行本来就在扶抑的 `favor` 里（例：偏弱己土燥盘，火为印、喜火，调候又忌火），两份列表就会重叠。摘要行仍写「喜水火土……忌金木」，但面板、解读、喜忌筛选各取一份，用户看到的就是「一会儿喜火、一会儿忌火」。身强寒湿盘的水同理。
- **修法**：调候所忌若已在 `favor`，不再插入 `avoid`，改记入 `disputed`（元素、扶抑角色、调候气候），喜用保留该行；调候所需要素仍按原逻辑从 `avoid` 移除。新增 `disputedTenGods`；`detail`、摘要「用神」「寒暖」行、解读「用神」「寒暖」节、白话、面板用神行与寒暖卡都标「有争议」，并说明「保留在喜用，不列入忌」。没有冲突的盘不出现该标记。
- **口径**：这是「两派并存」的显式标注，不改旺衰、不改调候判断、不替用户选边；扶抑与调候仍然各自成立，只是不允许同一行同时被判喜与忌。
- **界面验证**：390px 宽度下，争议行在 366px 内折 2 行，喜忌行与寒暖卡（338/338）均无横向溢出；浅色正文对比度 4.77:1、深色 7.73:1。
- **测试**：新增 `test/yongshen-disputed.test.mjs`（23 条）：两张真实争议盘（1962-03-22 偏弱燥火、2000-01-01 偏强寒湿水）的 favor/avoid/disputed/disputedTenGods、无冲突盘不误报、216 盘扫描喜忌无交集、文本 / 解读 / 白话 / 面板四处可见、白话与解读内嵌一致。统计 **103 个测试文件 / 4593 条断言**，七道闸全绿。
- **讨论群二维码**：GitHub README 的外部图片会被改写成 `camo.githubusercontent.com`，部分网络下断链；改挂 GitHub Release 附件直链（不经 camo / raw），并保留微信邀请链接兜底。Chrome 内实测 1161×1623 正常加载，README-only，不改运行时与断言数。

## 0.50.4（已并入 0.50.5）

把「口径对照」从命令行搬到结果下面：同一个盘只换一个开关（晚子时 / 真太阳时 / 闰月归月 / 奇门取局 / 晚子时归日），差在哪几个字，现在展开就能看见。

- **缺口在哪**：`engine/diff.js` 与 `tools/caliber-diff.mjs` 0.24 起就有，但只停在 CLI；面板与独立页切口径后只给新盘，用户不知道变的是日柱、命宫还是起运。紫微与奇门的差异还落成 `soul.ganzhi`、`siZhu.day` 这种原始路径，读不出来。
- **引擎**（`engine/index.js`）：新增 `caliberCompare(args)`，按 `CALIBER_SWITCHES` 把**当前口径**与**另一档**各排一次，返回 `{currentLabel, altLabel, total, summary, roots, categories}`；对照前剔掉 `cross / verifyPast / question / direction` 等只影响解析与附加模块的参数。`renderText` 在 `result.caliber` 存在时追加【口径对照】段。
- **标签与根因**（`engine/diff.js`）：补紫微（命宫 / 身宫 / 宫位 / 星曜 / 大限 / 飞星 / 格局）与奇门（四柱 / 局数 / 阴阳遁）的标签；`soul.ganzhi`、`siZhu.day`、`ju`、`dayun.jiao.at` 等进入根因表。口径回显字段（`juMethod / juMethodNote / lateZiHourMode / leapPolicy`）不再算差异——此前奇门两张完全相同的盘会被报成「2 处」，非闰月紫微也会凭空多 1 处。
- **界面**（`src/panel-kit.js` / `src/app.js` / `src/web-ui.js`）：结果下新增折叠的「口径对照」卡；summary 先用一句话说「几组开关中几组影响此盘」，展开后逐行给「当前 · A → 换成 · B」、根因旧值→新值、连带分类计数。只对八字 / 紫微 / 奇门出现；对照失败时不影响主结果。卡内走共享调色板，深色只换变量；窄屏隐藏「展开」提示、summary 保持 44px 触摸目标；打印时强制展开。
- **工具与 CLI**：根 `index.js` 新增 `diff: true`（默认关，每次多排 2–3 张盘）；`tools/caliber-diff.mjs` 改用同一个 `caliberCompare`，开关表只维护一份；`tools/build-client.mjs` 把 `diff` 模块打进 `client.js`。
- **口径**：只列同一组输入下的逐字段差异与根因，不判哪套口径更准，不改盘、不折吉凶；没有根因时如实写「无单一根因」（例如真太阳时只改起运时刻、不改柱）。`total` 是变化字段数，不是分数。
- **验证**：390×844 同源 iframe 实测（1996-01-19 23:40 · 安徽池州）：`scrollWidth 375 < innerWidth 390`，对照卡 351px，展开后无横向溢出；强制展开深色媒体块后卡底 `#211f18`、正文与注 6.74:1、标题 6.49:1。
- **测试**：`test/caliber-diff.test.mjs` 由 19 条扩到 129 条——开关表、标签 / 根因、口径回显忽略、八字 / 紫微 / 奇门真实盘独立复算（当前→另一档方向、`total / summary / roots` 与 `diffObjects` 对拍）、无变化与无根因边界、XSS 转义、面板 / 独立页 / 工具接线。统计 **102 个测试文件 / 4570 条断言**，七道闸全绿。
- **文档**：讨论群二维码换新图（`docs/assets/dsh-metaphysics-group.jpg`，11 月 6 日前有效），README 有效期同步；旧 PNG 删除、改用新文件名，避免旧图缓存继续命中。不涉及运行时与断言数。

## 0.50.3（已并入 0.50.5）

给「岁运提示」补上最后一段干支关系：大运与本命四柱的伏吟 / 反吟。以前只比「大运 × 流年」和「流年 × 本命柱」，大运压到本命柱上的那一步一直空着，知识卡的 note 也明写着「未逐年标注」。

- **引擎**（`engine/bazi.js`）：逐年 `suiyun.signals` 新增 `大运伏吟`（当值大运与本命某柱干支相同）与 `大运反吟`（天克地冲），对年 / 月 / 日 / 时四柱逐柱比对；target 写成「第N步大运·某柱」，detail 写明具体干支。整步大运都在，随每年重复列出，note 与解析层都写明「不当成逐年加重」。原四类信号与顺序不变，`岁运并临` 仍优先于同一组大运的 `运年反吟`。
- **接线**：摘要、解析层、面板沿用旧路径；摘要与面板 chip 对「大运」类信号也带柱位（`大运反吟(第8步大运·日柱)`），面板 chip 悬停仍给完整依据。`suiyunClassicOf` 口径不变：任一类信号出现就附《三命通会·卷二·总论岁运》原文。
- **口径**：仍只标干支重复与对冲，不折分数、不判吉凶；大运伏吟/反吟是整步十年的背景，不是逐年加码。选这一条而不是六爻应期具体日期，是因为后者在清单里明确要先建 20 条以上《卜筮正宗》应验日期对拍集，缺语料时输出日期等于拍脑袋。
- **文档与知识卡**：`bazi-suiyun` 由「四类」改「六类」，note 改为交代「连续多年出现、不逐年加重」；README「岁运提示」、清单 §3 与 0.50.3 说明块同步。
- **测试**：`test/suiyun.test.mjs` 的独立参照补上两类（六类信号逐条复算），新增 1950 盘钉住「大运伏吟整步重复 2026–2028」、同年 type+target 不重复、摘要与面板柱位、知识卡六类与 note；`test/sanming.test.mjs` 的无信号样例改用 1996-02-18（1984-10-18 在新口径下已有大运信号）。统计 **102 个测试文件 / 4460 条断言**，七道闸全绿。

## 0.50.2（已并入 0.50.5）

给 0.49.0 的「人元司权」补上原文出处：录入《三命通会》卷二·论人元司事（典藏网 7529），并如实并列该本与本插件不同的日数分法。

- **缺口在哪**：0.49.0 起每张八字盘都会算「生在本月第几日、哪一干当权」，知识卡却只写「之说见《渊海子平》」，没有卷次、没有链接，解释层也没有一句原文——这是全插件少数「有算法、无出处」的地方。
- **原文**（`engine/classics.js`）：新增 `smt-renyuan`，照录「故支吕所藏者主命，谓之人元……寅中有艮土用事五日，丙火长生五日，甲木二十日；二月建卯，卯中有甲木用事七日，乙木二十三日」，81 字逐字核验通过；来源本写作「支吕」，按「异文不改字」原样保留，不替它改字或圆场。
- **口径分歧**：该本寅月作 5/5/20、卯月作 7/23，本插件通行 30 日表作 7/7/16、10/20；`plain` 与解析层都写明「不是同一套分法、不改取格」，两表并列。新增 scene「人元」，与「岁运」一样不进五条取条表：`compute` 在有 `renyuan` 时挂 `r.renyuanClassic`，摘要人元行加「原文见《三命通会·卷二·论人元司事》」、解析层人元节附原文与白话、面板经通用 section 渲染自动出现；`RENYUAN_TABLE`、旺衰与取格一行未改。
- **知识卡**：`bazi-yueling-siquan` 的 detail/source/note 补上 7529 与 5/5/20，状态仍为 `variant`。
- **文档**：README「古籍原文」「人元司权」「致谢」三处、清单 §二.1 / §三表 / §四.1 与 0.50.2 说明块同步。
- **测试**：`test/classic-quotes.test.mjs` +4（scene 枚举加「人元」、原文/出处/plain、不进五条），`test/sanming.test.mjs` 由 17 条改为 18 条并 +11（结果层/摘要/解析层/面板/知识卡），`test/renyuan.test.mjs` +11（用 `RENYUAN_TABLE` 独立对照原文日数、结果层接线、5/5/20 可见）。统计 **102 个测试文件 / 4432 条断言**，七道闸全绿。

## 0.50.1（已发布 2026-10-30）

宿主侧栏面板的首屏与独立页并轨：三组卡片、最近用过、分组↔平铺、窄屏收纳，全部从同一份数据生成，不再「页面一套、侧栏一套」。

- **缺口在哪**：0.39.0 给独立页做了分组首屏（问一件事 / 看一个人 / 查日子、最近用过、分组↔平铺），面板一直是 19 个 tab 平铺加自己那套 `.mp-tabs`——既没有最近用过，也没有「每组先露 4 项」的收纳；窄侧栏里 tab 条先吃掉大半屏，卡片与表单被推到下面。
- **唯一数据源**（新增 `src/groups.mjs`）：三组标题、白话提示与 19 个入口（含「人生K」铺满整行）只写一份。`tools/build-html.mjs` 用它在构建时生成页面分组 HTML；`tools/build-client.mjs` 用 `JSON.stringify` 注入 `window.__MPGroups` 给面板。页面产物与面板不再各抄一份，`test/panel-first-screen.test.mjs` 逐项对拍页面生成的入口与数据源。
- **面板首屏**（`src/app.js`）：React 版分组卡片（`.mp-tgroup` / `.mp-tool`）、最近用过（`mp.recent.tabs`，最多 3 条，先过 TABS 白名单）、分组↔平铺开关（`mp.first.view`，默认分组）、窄屏折叠（「还有 N 个」/「收起」，带 `aria-expanded`）。两套入口共用 `activate` → `recordRecent` + `switchTo`，排盘参数与结果路径不变。
- **平铺 tab 重构**：19 个 tab 从「分段控件」改为圆角胶囊网格（与独立页同形），窄屏单行横滑、44px 触摸目标；分组视图下 tab 条整体隐藏（`.mp-tabs.hide`）。
- **收纳用容器查询**：侧栏宽度不等于窗口宽度，`@container (max-width:560px)` 让 420px 侧栏与 390px 手机都按「每组 4 项 + 还有 N 个」收，不再用窗口媒体查询猜。
- **口径**：分组只是另一套入口——19 个 tab 原样保留，不改变任何默认值、排盘参数与结果；存储不可用（隐私模式）只少记「最近用过」，面板照常可用。
- **测试**：新增 `test/panel-first-screen.test.mjs` 40 条——分组数据、唯一数据源、页面产物对拍、面板接线、折叠与降级。统计 **102 个测试文件 / 4406 条断言**，七道闸全绿。

## 0.50.0（已并入 0.50.1）

知识卡 `liuyao-yingqi` 一直写着「应期只作时间窗口的提示」，引擎却一行都没给：用神旺衰算了、伏神出伏算了，轮到「什么时候见分晓」只剩「未做」。这一版把诚实的那一半补上——列出该留意的地支与快慢方向，仍不给具体日期。

- **引擎**（`engine/liuyao.js`）：新增 `yingqiWindow(result, useGod, { monthBranch })`。用神在卦上取用神、不上卦取伏神，每支列出逢值（本支）、逢冲（对支）、逢合（六合支）三支；用神旬空时本支追加「出空填实」、对支追加「冲空」。快慢按月建五态：旺 / 相 → 偏速，休 / 囚 / 死 → 偏缓，月破或旬空 → 待解，缺月建 → 未定；用神两现时逐支归并去重，快慢不一致记未定。结果挂在 `r.yingqi`。
- **四处可见**：摘要加「应期线索：偏缓 · 逢值/逢冲辰 · …（只列地支，不出日期）」；解析层新增「应期线索」一节，逐条写月态与触发支；白话加一句「应期上大体偏远……不换算成具体哪天」；面板在伏神与进退之间加一排 chip（偏速绿、待解琥珀）。
- **口径**：只做「该留意哪一支」与快慢方向——不换算日期、不排先后、不判忌神受制、不叠动变连环；近事以日计、远事以月计，用哪把尺由事情远近决定，不代选。知识卡 `liuyao-yingqi` 仍为 `variant`，`liuyao-yingqi-exact` 仍为 `todo`（具体日期未做）。
- **口径变更连带**：解析层「未纳入」原写「应期仍未做」，现改为「应期的具体日期未做」；`test/liuyao-chufu.test.mjs` 第 212 行同步改断言（从锁旧句改为锁新句），不涉及伏神判定本身。
- **文档**：README「六爻」「精度与口径」两条、清单 §3.1 / §4.3 与 0.50.0 说明块同步；package description 补「应期线索」。
- **测试**：新增 `test/liuyao-yingqi.test.mjs` 73 条——12 支冲合独立复算、64 卦 × 13 组月建（12 支 + 缺月建）× 4 方向 3328 盘逐条复算（月态 / 月破 / 旬空 / 快慢 / 归并去重）、旬空 / 月破 / 用神两现 / 伏神 / 缺月建 / 两现快慢不一六条边界、四处可见与不出现日期、旧结果兼容、确定性。统计 **101 个测试文件 / 4366 条断言**，七道闸全绿。

## 0.49.3（已并入 0.50.1）

离线页（`命理排盘.html`）的「农历」tab 一直是坏的：转换方向那条分段控件从来没显示出来，农历日期怎么填都被判格式错；同一次真机检查还量出深色主题下「选中态实心底上的白字」只有约 3:1。这一版把断链接通，把强调面文字换成变量（两套配色各自过 WCAG），并顺手收掉窄屏闰月勾选框被拉高的毛病。

- **断链**（`src/web-ui.js`）：① `setTab` 的速查子表单显隐漏了 `#qk-convert`，只有「公历 → 农历」的默认分支能跑，切到「农历 → 公历」的入口根本看不到；② 农历日期正则写成 `/^(d{4})-(d{1,2})-(d{1,2})$/`（少反斜杠），`d` 被当字面量，任何输入都匹配失败；③ 日期标签用硬编码名单判「起卦」，convert 漏在名单外被标成「起卦日期（公历）」。现改为与面板同一套正则，标签跟随 `TIME_KIND` 的 date 类写成「日期（公历）」。
- **深色强调面**（`tools/build-html.mjs`）：深色块里的 `.tab.on,.seg button.on,.go{color:#14130f}` 写在基础规则之前，同优先级被后面的 `color:#fff` 盖掉——深色下实际是白字压浅珊瑚底，约 3:1。改为 `--accent-bg / --accent-bg2 / --on-accent / --on-accent-soft` 四个变量，7 处实心强调面（印章、选中 tab、分组卡片、评分格、主按钮、分段按钮、追问/chip）统一走变量。浅色仍是白字压 `#a72c23 → #7d1f18`（6.9 / 9.8:1），深色改为深字压 `#f0a38e → #e2755f`（9.1 / 6.1:1），渐变两端都 ≥4.5:1；页面样式里不再出现 `color:#fff`。
- **口径**：这是一次设计口径变更，先把 `test/theme.test.mjs` 第三节改成锁变量与逐端对比度（含副文字按 alpha 叠色后复算），再改实现；`test/first-screen.test.mjs` 里锁旧元素规则的一条同步换成 `--on-accent` 规则。
- **窄屏（≤640px）**：`#qk-convert` 独占整行，方向分段按钮不再折行；闰月改用 `.field.check`，勾选框保持 18px，触摸区由外层 label 撑到 44px（此前继承输入框的 `min-height:44px`，变成 18×44 长条）。
- **验证**：真 390×844（CDP 设备模拟）浅/深各跑一遍——无横向溢出（scrollW=390）、`农历2026年九月十七 ⇄ 2026-10-26` 正常出结果、日期标签为「日期（公历）」、勾选框 18×18、tab 与主按钮触摸目标 44/48px。
- **测试**：新增 `test/convert-ui.test.mjs` 31 条（两个入口同一套正则、2026-9-17 与闰六月前后边界、每个 `#qk-*` 都有显隐接线、闰月与 datetime 透传、格式错误文案走 textContent）；`test/theme.test.mjs` 现为 65 条。统计 **100 个测试文件 / 4293 条断言**，七道闸全绿。

## 0.49.2（已并入 0.50.1）

黄历卡片里的二十八宿，把「壁水貐」写成了「壁水獝」、「胃土雉」写成了「胃土彘」——两个字都只是动物名，不影响排盘、宜忌与宿值日，但它是用户每天在摘要和面板上能看到的原文。这一版按通行二十八宿名逐字改正，并把整张表在测试里独立重录一遍，逐字对拍。

- **数据**（`engine/almanac.js`）：`MANSIONS` 的壁宿动物 `獝` → `貐`、胃宿动物 `彘` → `雉`；宿名仍按「宿·五行·动物」写法，其余 26 宿未动。四宫、吉凶、五行、值日轮转规则一行未改。
- **口径**：值日宿仍按「日支 + 星期」定，28 日一循环；壁宿落周三（水）、胃宿落周六（土），与七曜一致。本次只改动物名，不改任何日期落到哪一宿。
- **文案**：`engine/almanac.js` 顶部「诚实边界」注释同步——二十八宿、胎神、值日神、吉神方位已收录，未收录的只剩逐日全量吉凶神煞与彭祖百忌（旧注释把已收录项也写成了「未收录」，与返回值的 `scope` 打架）。
- **测试**：新增 `test/almanac-xiu.test.mjs` 60 条——通行表在测试里独立录 28 行逐字对拍（含壁水貐、胃土雉）、四宫各七、动物不重、12 支 × 7 日的七曜顺序、13 段 56 天的 28 日循环与 28 日不重不漏、2026 全年不再出现「獝」「彘」、壁/胃的星期锚点、结果层/文本摘要/面板三处可见、同日两次逐字段一致、400 天宿五行与星期七曜一致。统计 **99 个测试文件 / 4262 条断言**，七道闸全绿。

## 0.49.1（已并入 0.50.1）

「岁运提示」是引擎里唯一一节没有原文支撑的能力：逐年标出岁运并临 / 运年反吟 / 流年伏吟反吟，读法却是自己写的；知识卡 `bazi-suiyun` 的出处只写「见《三命通会》《渊海子平》」，没有卷次也没有链接。这一版补上《三命通会》卷二「总论岁运」原文，并顺手记下一处口径分歧。

- **原文**（`engine/classics.js`）：新增 `smt-suiyun`（卷二·总论岁运，典藏网 7539），照录「行运以生月为运元，最怕行运与太岁冲克，若岁运冲月必祸；若岁运与日相对，谓之返吟，岁运压日，谓之伏吟，二者不利六亲，非横破财，不为吉兆。」——用 `verify-quotes.pl` 对章页逐字核验通过（67 字，连续子串），白话自撰。
- **口径分歧写进 plain**：原文的「返吟」指岁运与日柱相对、「伏吟」指岁运压日；本插件按通行用法取「干支相同为伏吟、天克地冲为反吟」，两者并列、不合并。末句「不利六亲、破财」是旧说的重话，只作变动提示。新增 `scene: '岁运'`，不挂格局 tag。
- **不进五条上限**（`suiyunClassicOf`）：`classicsFor` 仍是「格局两条 + 气候两条 + 总纲一条」；岁运原文只在 `liunian` 真有信号时随该节出现——原文讲的正是冲克，没冲没克时挂出来只会误导。结果挂 `r.suiyunClassic`。
- **三处可见**：摘要「岁运提示」行末加「古籍见《三命通会·卷二·总论岁运》」；解析层「岁运提示」节补原文与白话；面板岁运 chip 下加一行原文（悬停看白话，样式只走 `--muted`），无信号时三处都不出现。
- **知识卡**（`engine/interpret-knowledge.js`）：`bazi-suiyun` 的 source 换成带链接的《三命通会》卷二·总论岁运，detail 写明返吟/伏吟的定义分歧；状态仍 `variant`。
- **口径**：只补出处与定义对照，四类信号的判定、分档与「不判吉凶」的边界一行不动。
- **文档**：README「古籍原文」「岁运提示」与致谢、清单 §二·7 与文末注同步；三命通会条目 16 → 17。
- **测试**：`test/sanming.test.mjs` +14 条（原文抽检、章名/链接、scene 与 tag、不进五条表、有/无信号两向的结果层/摘要/解析层/面板表现、知识卡出处），条目计数 16 → 17；`test/classic-quotes.test.mjs` +4 条（原文、出处、plain 口径）并把 scene 枚举加入「岁运」。统计 **98 个测试文件 / 4202 条断言**，七道闸全绿。

## 0.49.0（已并入 0.50.1）

「月令是什么」此前只答到月支本气：知识卡 `bazi-yueling-siquan` 写着「月内分日轮值」，引擎却一个字段都没给，面板与摘要里也看不到「生在本月第几日、哪一干当权」。这一版把《渊海子平》的人元司权分日落进引擎与解释层，补上清单 §3.3 里挂得最久的争议项。

- **引擎**（`engine/bazi.js`）：新增 `RENYUAN_TABLE` 与 `renyuanOf(monthBranch, birthJdn, termJd)`——固定通行 30 日表（余气 → 中气 → 本气，合计 30 日，如寅月戊7丙7甲16），从「节」的当日算第 1 日，日差取本盘所用时刻（含真太阳时）所在日；第 31 日以后不硬分摊，按本气算并标 `beyond`。返回当权干与五行、所在日段、下一段距今天数、是否在本柱藏干表内。结果挂在 `bazi.renyuan`，并带 `term`（起算的节与时刻）。
- **摘要**（`engine/index.js`）：节气行后加一行「人元：X月第N日，干+五行司权（各段日数）」，超出 30 日表时注明。
- **解析层**（`engine/interpret.js`）：新增「人元司权」一节，说明从哪个节起算、这一日谁当权、下一段几日起交；同时写明分日只作解释层细节，**不改取格**；司权表比本柱藏干表宽的地方（子月壬、卯月甲、午月丙、酉月庚、亥月戊只出现在司权表）两表各照原样。
- **知识卡**（`engine/interpret-knowledge.js`）：`bazi-yueling-siquan` 的 detail 与 note 补齐实现口径，状态仍为 `variant`——7/7/16、9/3/18 等分法未并列实现，轮值不参与旺衰与取格。
- **口径**：只认「节」不认「气」；节当日为第 1 日；30 日表固定，不按流派切换；第 31 日起按本气；司权与取格、旺衰解耦，删掉该字段后 `primary` / `favor` 逐字不变。
- **文档**：README「人元司权」一条；清单 §3.3 与 §4.1 同步，并补实现说明块。
- **测试**：新增 `test/renyuan.test.mjs` 361 条——逐支核表（合计 30、连续、五行、末段为本气、2–3 段）、纯边界（首日/末日/下一段/第 31 日/第 0 日夹取）、12 张真实盘独立复算日差、已知盘 1990-05-12（巳月第 7 日庚）与 1990-11-08（亥月第 1 日戊，不在藏干表）、2023-06-05（第 31 日按本气）、立春前后 30 分钟切换、删字段不改格、确定性、摘要/解析层/知识卡口径，并禁绝「一定/必然/注定/百分百」。统计 **98 个测试文件 / 4185 条断言**，七道闸全绿。

## 0.48.0（已并入 0.50.1）

在 390×844 的真视口（无头 Edge + DevTools 协议，浅色与系统深色各跑一遍）里把「交叉验证」和三张表量了一遍：大运表六列排到 748px，屏幕只露出左半边，右边界既没有渐隐也没有「还能滑」的提示；交叉验证是五段「八字——…；紫微——…；判断：…」的长句连读；表头 11px 的 `--label` 对 `--band` 只有 3.51:1；目录链接 22px、证据摘要 33px、名词解释 22px，都够不着 44px 的触摸目标。这一版按测量结果改样式与结构，`test/theme.test.mjs` 锁的深色/打印/窄屏规则一条没动，七道闸全绿。

- **交叉验证改对照卡**（`engine/crosscheck.js`、`src/panel-kit.js`）：新增 `crossSection(cross)`，把文本和 `items` 一起交给面板——同一份数据两个去处，面板不用再拆文本。每个方面一张卡：标题行带「同向 / 有张力 / 互补」语气标签（绿 / 琥珀 / 蓝），八字、紫微各占一栏，注释放最后一行；≤640px 改单列，标签跟正文走。Markdown 与工具输出仍是原来的五行文本，口径不变。
- **三张表不再横着截断**：渲染时给每个 `td` 打 `data-label`、表头加 `scope="col"`；≤640px 隐藏表头，一行一张卡、每格用列名当行标，首列抬成卡头。390px 下大运表从 748px 横滑变成 342px 宽的可读卡片，触发事件表同理（418px → 342px）；宽屏与打印仍是原表格。
- **对比度**：表头从 `--label` 改 `--ink2`（浅色 3.51 → 10.53:1，深色 9.98:1）；卡内标签与备注用 `--muted`（5.29 / 6.74:1）。三档标签、目录链接、正文在两套变量下逐对算 WCAG 亮度比，全部 ≥4.5:1。
- **触摸目标**：窄屏目录改单行横滑胶囊（隐藏滚动条、首尾留 11px），链接与证据摘要、名词解释摘要统一 `min-height:44px`；390px 实测全部 44px，折叠标题 ≥46px。正文宽度不变，页面横向溢出为 0。
- **入口统一**：独立页与面板都改用 `Engine.crossSection`，不再各自拼 `crossText`。
- **侧栏也生效**：dsh 侧栏是「窗口宽、报告窄」，`@media` 不触发；`.mp-it` 声明为查询容器，同一批窄屏规则另挂一份 `@container (max-width:640px)`。实测把报告放进 420px 容器（窗口 1280px）：表格 1092px → 396px 且不再横滑、目录链接 44px、对照卡单列，与 390px 视口下的结果一致。
- **测试**：新增 `test/narrow-report.test.mjs` 52 条——结构（五张卡、十个分栏、`data-label` 数量、转义）、窄屏样式规则（含容器查询版）、触摸目标、两套调色板逐对对比度，并反向锁住「表头若改回 label 会掉到 3.51:1」。统计 **97 个测试文件 / 3824 条断言**，七道闸全绿。

## 0.47.1（已并入 0.50.1）

交叉验证是 README 里挂了很久的能力，但测试只在外围点了六下（条目数、三档词、文本出现），五项判定的阈值、性别分支与节奏真值表一条没锁；顺手查出两处「说得比数据多」的文案。

- **测试补真**（新增 `test/crosscheck.test.mjs`，71 条）：把交叉验证当纯函数测——事业「官杀 + 食伤 ≥ 2」、财富「财 ≥ 2」、感情按性别取「妻星（财）/ 夫星（官杀）」的 1.9 / 2.0 边界；节奏用 5 档 × 煞星轻重共 10 组真值表逐格核判断与说明；再用 10 张真实盘 × 男女共 20 组，从原始 `godStats` / 宫位星曜 / 大运档位独立复算五项判断与文案；另锁条目恰好五项、次序固定、只带六个字段（没有合并分数）、输入不被改写、两次调用同结果、八字入口与紫微入口的对照逐字节一致、`crossText` 五行结构。用「事业阈值 2 改成 3」做过变异检查：2 条立即变红，恢复后 71 条全绿。
- **文案与实现对齐**（`engine/crosscheck.js`）：① 节奏一项原先只有一句「一边顺、一边压」，但八字大运为「平」时也会套用——1980-03-05、2005-01-13 等盘就是「平 + 紫微煞星 2 颗」。现在按实情分三句：八字顺而紫微煞星多、八字偏紧而紫微平静、八字为平而紫微煞星多，各写各的处理方式。② 大限没取到时，紫微侧原来写成「大限未取到；无煞星」，把缺数据说成了没有问题；现在只写「大限未取到」。③ 任一侧当前阶段缺失（八字未起运、紫微大限不在范围）时，判断由「同向 / 有张力」改为「互补」，说明里点名缺的是哪边，并写明「不下两边对照的结论」——不再拿「没取到」冒充「没问题」。
- **口径**：五项仍只并列、不合并成总分；三档仍是同向 / 有张力 / 互补，「互补」现在也明确承担「只有一边有信号」这一情形。健康项固定「互补」不变。
- **文档**：README「精度与口径」补一条，写明缺一侧时的标法与节奏说明的分档。
- **测试**：96 个测试文件 / 3772 条断言，七道闸全绿。

## 0.47.0（已并入 0.50.1）

四墓月（辰戌丑未）此前只取月令本气，藏干透了也用不上、三合会成了局也看不见；同一段代码还把戊辰、戊戌、己丑、己未当成建禄，把透干/会支取到的劫财写成「劫财格」。这一版把《子平真诠》十六「论杂气如何取用」落进引擎与原文库。

- **取格三级**（`engine/geju.js`）：杂气月按「透干 → 三合会支 → 本气」取格。藏干透到年/月/时干仍优先；没有透干时，若其余三支与月支凑齐同一三合局，取局中五行对应的那一藏干（甲生辰月、年支申日支子 → 取水印）；三合不齐才回本气。依据里写明走的是哪一条（透于某干 / 某某会成某局 / 以月令本气取格），会支只认三合、不认三会方。
- **两处误标**：`base.god === '比肩'` 原先一律给建禄格，戊辰、戊戌、己丑、己未这类「本气比肩但不在禄位」的杂气月因此冒称建禄——现加禄位校验，改判比肩格并在依据里点明「禄在巳、不在辰」；杂气月由透干或会支取到劫财时，按原文「透乙则用月劫」改判月劫格，不再落到「劫财格」。
- **原文与知识卡**（`engine/classics.js`、`engine/interpret-knowledge.js`）：新增 `zp-zaji`（十六、论杂气如何取用，典藏网 53636），原文照录「何谓透干……透而又会，则透与会并用」、白话自撰。用神总纲位由三选一改为四选一：化气 > 四墓杂气 > 组合 > 通用总纲，杂气与组合同现时取杂气；位次不增，整节仍以 5 条为限。知识卡 `bazi-zaji-quyong` 补一条，标「各家有异说」。
- **口径**：原文「兼透则兼用」只给原则，落到单一格名必须择一，本插件取最先透出的那一干；会支只认三合、不认三会方；不判原文所说的「有情 / 无情」。这几点写进 README 与清单，不替分歧圆场。
- **测试**：新增 `test/zaji.test.mjs` 52 条，用 9 张真实盘正反两向钉住——透干压会支（1996-01-19）、会支取用（1985-02-03 / 2005-01-13 / 2002-10-13）、三合不齐回本气（1992-04-05）、非杂气月不启用会支（1979-11-13 / 1985-09-15）、建禄不误标（1989-03-05 / 1983-08-20 / 1990-04-13）、月劫三路（1985-04-05 / 1996-08-05 / 1990-10-28），并核总纲位次序、上限、确定性、摘要/解释层/面板与知识卡。`test/classic-quotes.test.mjs` +5 条，把总纲位改判为四选一并加原文抽检。统计 **95 个测试文件 / 3701 条断言**，七道闸全绿。

## 0.46.5（已发布 2026-10-30）

「问进对话」只把盘面摘要和问题送进对话，模型得自己再推一遍结论——同一张盘，面板里读到的「说人话」和对话开场可能不是一套口径。这一版把面板已算好的白话结论一并交给模型。

- **缺口在哪**（`engine/followup.js`）：`askPrompt` 只读 `r.summary`，而 `interpret(r, ask)` 产出的 `answer`（直答）与 `plain`（说人话）只存在于面板结果对象 `it` 里。用户点「问进对话」后，模型看到的是原始盘面，开场结论全靠现场发挥；问法或流派稍有出入，就会与面板上的结论打架。
- **改动**：`askPrompt(r, { interpret })` 新增可选解析对象；有 `interpret` 时，在「所问」与「盘面摘要」之间插入「开场结论」小节，原样带上 `answer`（直答）与 `plain`（说人话），并把回答要求第 1 条改成「先沿用上面的开场结论，再用一句不用术语的话说清主线」。调用方没传时回退读 `r.interpret`（`compute({ withInterpret: true })` 的结果）；两者都没有就完全不加这一节，固定骨架保持原样。
- **接线**（`src/app.js`）：面板两处调用都带 `interpret: result.it`；`LAST` 增加 `it` 字段，输入框右侧的「命理·问」也能拿到同一份白话底稿，而不是只带摘要。
- **账面**：1996 盘（所问「今年考运」）提问文本 2353 → 2669 字，底稿只多 316 字（直答 106 + 说人话 144 + 小节标题），没有把提问撑成小作文；未传解析时逐字不变。
- **口径**：底稿只做「同一口径」的搬运，不改写、不摘要；模型仍被要求压成一句无术语的话，避免直接复读盘面术语。
- **测试**：`test/ask-prompt.test.mjs` +13 条——底稿小节存在且排在摘要之前、直答/说人话原样带入、回答要求指向底稿、未传解析时不加小节、`r.interpret` 自动回退、空解析对象不加空小节、无问题时底稿不说「先答所问」、带底稿仍逐字确定；`test/client-bundle.test.mjs` +2 条锁住面板两处调用都带 `interpret`、桥的 `LAST` 保留解析对象。统计 **94 个测试文件 / 3643 条断言**，七道闸全绿。

## 0.46.4（已并入 0.46.5）

0.46.3 有三处「写进了文案、没落进代码」：文末分歧清单只列前 4 条、面板仍显示「问题：（未填写）／先答所问」、归属稳定性测试并不存在。这一版把三处补齐，并把它们钉进断言。

- **分歧清单不再截断**（`engine/interpret.js`）：`caveats.slice(0, 4)` 让 1996 盘的 13 条分歧只显示 4 条，另有 9 条不在任何段落、其中 7 条原注整份报告都读不到——与 0.46.3 写的「信息不丢」相反。现在按状态拆开：「待核实」仍归「尚未实现（不猜）」并附原注；其余分歧逐条列出（已展开的只留条目名，未展开的附原注），同一句原注不会出现两遍。
- **没问事就别喊「答所问」**（`src/panel-kit.js`、`engine/index.js`）：奇门只选方向时，面板回显原来是「问题：（未填写）｜询问方向：财运」，直答标题也固定写「先答所问」。现在没填问题只回显方向，标题改为「先看结论」；填了问题仍用「先答所问」。奇门的直答也从泛泛的「五个维度」改为「排盘事实、用神、宫位条件几节」，并点明所选方向。
- **测试补真**（`test/interpret-dedupe.test.mjs`，28 条）：归属稳定性按 7 个方向 × 有事/无事 逐一对拍「卡片→维度」签名；分歧清单断言行数等于条目数、未展开条目的原注必须在、已展开的不重复贴；`knowledgeCount` 同时与「唯一卡片数」「逐维挂载总数」独立核对；面板侧用源码锁住旧「（未填写）」串已删除。0.46.3 里那句没有测试支撑的说法，至此才有对应断言。
- **口径**：信息完整优先于尾部紧凑——文末清单从 4 行回到 13 行，1996 盘解析文本 9099 → 9965 字（无问题）/ 10051 字（有问题），`knowledgeCount` 仍为 10，正文五维没有新增复读。
- **测试**：新增 94 个文件 / 3628 条断言，七道闸全绿。

## 0.46.3（已并入 0.46.5）

同一段「规则注解」在报告里复读了两三遍：1996 示例盘的 29 条注解里，只有 16 张是不同的卡。这次把注解改成「一张卡全报告只挂一次、每维最多 3 条」，没填问题时也不再假称「你问的这件事」。

- **缺口在哪**（`engine/interpret.js` 的 `enrichPlain`）：知识卡按维度静态挂载，而 `knowledgeFor(system, dimKey)` 对「整体运势 / 事业发展 / 健康」会返回同一批通用条目，于是「月令不是一个月」「大运管十年基调」「同一个格，子平真诠怎么用、三命通会怎么取」这类解释在正文里出现 2–3 次，把五段判断冲散。实测 1996 盘：整体 14 条、事业 10 条（9 条重复）、感情 3 条（2 条重复）、健康 2 条（两条全重复）——29 条里 16 张不同，段落被复读切成碎片。
- **改动**：先按固定维度次序（整体 → 工作 → 事业 → 感情 → 健康）分派，已出现过的 id 跳过，每维再截到 3 条。次序用固定表而不是显示顺序，是因为「所问之事」会把某一维提前——按显示顺序先到先得的话，同一张盘换个问法，注解归属就整体搬家（归属稳定性测试在 0.46.4 补上）。文末「这套规则有多稳」对已展开的条目只留一句索引，不再贴一遍全文；被截掉的分歧条目也应进文末清单（0.46.4 修正：此处当时实际只列了前 4 条，另有 9 条及其 7 条原注被漏掉）。
- **顺手**（`engine/interpret-plain.js`、`engine/interpret.js`）：没填问题时抬头不再写「问题：（未填写）」，正文也不再假称「具体到你问的这件事」——改成「没指定问题，就按……的顺序往下看」。这是「读者视角」的最后一点漏：没问问题却硬答「你问的这件事」，最容易被当成模板腔（面板侧的回显与「先答所问」标题在 0.46.4 一并修正）。
- **账面**：1996 盘解析文本 11862 → 9099 字（−23%），`knowledgeCount` 29 → 10，五维正文之间不再有整块复读。
- **测试**：`test/interpret-knowledge.test.mjs` +5 条——同卡不重复、每维 ≤3、`knowledgeCount` 与实际挂载一致、无问题时抬头不写「未填写」、正文不假称「你问的这件事」。统计 **93 个测试文件 / 3600 条断言**，七道闸全绿。

## 0.46.2（已并入 0.46.5）

离线页的「验前事 / 生时校正」原来是原生控件：年份框 21px、按钮 31px 灰底；窄屏下三档判断按钮 22px，追问框 37px、导出按钮 39px，「点任一宫位看详情」只有 2.25:1。

- **缺口在哪**：这两块由 `web-ui.js` 输出 `.mp-btn` / `.mp-input`，但基础样式只写在 DSH 宿主的 `src/app.js` 里（且用的是 `--dsw-*` 变量），离线页从没定义过——于是年份与类型退回 21px 原生输入框，「算贴合度 / 计算候选时辰」退回 31px 灰按钮，和整页的米色卡片明显不是一套。
- **实测口径**：用无头 Chrome 通过 CDP 在 390px 视口、浅色/深色两套配色下逐个点开 19 个 tab，量 `#out` 内溢出、可点区域尺寸与文字对比度。修复前：验前事三档按钮 32×22、年份框 21px、按钮 31px；全页每个 tab 的追问框 37px、导出按钮 39px；紫微提示条 2.25:1。
- **改动**（只碰页面层与结果区模板）：`tools/build-html.mjs` 给页面补一套同变量的 `.mp-verify/.mp-rect` 按钮与输入框样式（含聚焦环），窄屏把三档按钮排成等分三列、标签独占一行，`.mp-chip` / 验前事按钮 / 年份与类型框 / 追问框 / 导出按钮统一抬到 44px，追问输入改 16px 避免 iOS 聚焦缩放；`src/panel-kit.js` 的 `.pp-soon` 由 `--faint` 改 `--muted`（浅色 4.77:1、深色 7.73:1）；`src/web-ui.js` 删掉两处把按钮压到 12px/31px 的行内样式。
- **口径不变**：颜色全走既有页面变量，深色仍是只换变量；`test/theme.test.mjs` 锁定的打印、深色、窄屏 tab 规则一条未动（50 条断言原样通过）。
- **测试**：新增 `test/ui-controls.test.mjs`（15 条）——页面控件样式、无硬编码色、窄屏 44px、提示条对比度（从变量声明取色独立复算）。修复后复测：19 个 tab × 浅/深 0 处横向溢出、0 个 <44px 控件、0 处对比度 <3:1。统计 **93 个测试文件 / 3595 条断言**（+15），七道闸全绿。

## 0.46.1（已并入 0.46.5）

偏财格不再引《论正财》，七杀格补上三命对照：九个走月令的格，这才真正做到「子平在前、三命在后」各一条。

- **缺口在哪**：三命通会此本正财、偏财分章，引擎却让两格共用 tag「财」——1996 示例盘就是偏财格，古籍节里挂的却是《三命通会·卷六·论正财》。七杀格更只有子平《论偏官》一条，没有三命对照，而 README 已写「同一个格，子平真诠在前讲怎么用，三命通会紧随作对照」。
- **两条原文**（`engine/classics.js`）：`smt-piancai`（卷六·论偏财 7650，「乃众人之财也……切忌有姊妹兄弟分夺」）与 `smt-guansha-liu`（卷五·官煞去留杂论 7599，「天干透者易去，月支所藏者难去」）。均按典藏网章页逐字核验（2/2 通过），照录不加省略号，plain 为白话自撰。
- **七杀为何取「官煞去留杂论」**：该本三命通会没有单列「论偏官」章，硬凑一篇改名就是造出处；取同卷讲官煞混杂去留的这一篇作对照，章名照录，plain 写明「七杀格遇正官混杂，就按这一篇看取舍」。
- **接线**：`GEJU_KEY` 把正财格、偏财格拆成两个 tag，子平《论财》同时标「正财」「偏财」，于是两格都是子平在前、三命本格章在后；七杀格 / 偏官格指向官煞篇。5 条上限、专旺从格先占位、总纲位三选一均未动，其余盘选条逐字节不变。
- **文档与知识卡**：`bazi-sanming-duizhao` 补写「此本正财偏财分章、七杀无专章」；清单四·1 与 README 致谢的「十四篇」改对为十六篇；README 里写死的「90 个测试文件 / 3423 条断言」改为「取自断言基线」，避免每轮过期。
- **测试**：`test/sanming.test.mjs` 的条目分组由「章名是否以论开头」改为显式 id 清单（官煞篇不是「论」字题），新增偏财 / 七杀配对与正反两向（偏财不引正财章、正财不误取偏财章）；`test/classic-quotes.test.mjs` 用 1996 偏财盘钉住对照条；`test/tongguan.test.mjs` 的 1996 选条期望同步为 `smt-piancai`。统计 **92 个测试文件 / 3580 条断言**（+13），七道闸全绿。

## 0.46.0（已并入 0.46.5）

紫微补齐九类流派开关：此前只做了闰月三档，换派只能拿到默认盘；现在每一项都能单独切换，且不传时盘面与旧版完全一致。

- **缺口在哪**：0.42.0 把参考项目的「其余九类流派开关」明确留作后续，引擎里亮度、庚干四化、天马、天空、截空旬空、魁钺、天伤天使、长生起点、晚子时都只有一种写法；工具 schema 也没有对应参数，模型侧无法要求「按全书派排」。
- **改动**（`engine/ziwei.js`）：新增 `ZIWEI_SCHOOL_DEFAULTS` / `ZIWEI_SCHOOL_OPTIONS` / `ziweiSchoolsOf`，九个开关逐个落到安星与起盘——`brightnessSchool` 四套亮度数值表按星逐年转中文（QS/XD1 七档、ZZ/XD2 五档）；`gengYearSihua` 五个庚干四化变体；`tianmaSchool` 年支/生月三合；`tiankongSchool` 不排/年支顺行/加生时；`jiekongSchool` 不排/单星/正副/占验，启用时同时排旬空副旬；`kuiyueSchool` 四派魁钺（生年与流年同表）；`tianshiTianshang` 中州派阴男阳女互换；`changshengSchool` 火土派把土五局长生起点从申改寅；`lateZishi` next-day 时 23:00 后起盘日顺延。
- **接线**：`engine/index.js` 透传九个平铺参数与嵌套 `schools`（八字 × 紫微交叉验证同样生效）；根 `index.js` 的 MCP schema 新增九个字段与枚举；摘要只在改动默认时补一行【流派】，默认盘不多噪音。
- **口径**：不传或传非法值一律回默认，默认仍是 49 星盘面；庚干变体只作用于生年四化，宫干自化与大限/流年四化不随之改变（已写进 `rules.schools`）。
- **测试**：新增 `test/ziwei-schools.test.mjs`（73 条）——默认盘逐字节不变、九项各自独立生效、非法值回退、嵌套参数、compute 透传与摘要。统计 **92 个测试文件 / 3567 条断言**（+73），七道闸全绿。

## 0.45.2（已并入 0.46.5）

玄空的 `period` 非整数不再静默落回九运，而是按入参错误报 `E_INPUT`。

- **缺口在哪**：`engine/index.js` 只把 `Number.isInteger(period)` 传给引擎，`2.5` 或字符串 `"9"` 会被直接丢掉，`buildXuankong` 随后走缺省分支排九运——调用方拿到的是一张看似正常的盘，而不是「运写错了」。
- **改动**：`buildXuankong` 先校验「显式给了 period 就必须是整数」（`null` / `undefined` 仍算未给），不符合与越界共用同一条 `E_INPUT` 文案；`index.js` 不再预先过滤 period，原样交给引擎判定。
- **口径不变**：合法 1–9 的整数仍优先于 `fortuneYear`；未给 period 时仍按 `fortuneYear` 定运，再缺省九运并注明。
- **测试**：`test/fengshui-xuankong.test.mjs` 补 4 条（非整数/字符串报错、错误码、`null` 仍缺省），`test/tool-fengshui.test.mjs` 补 2 条（两种非整数在工具层都显示 `[E_INPUT]`）。统计 **91 个测试文件 / 3494 条断言**（+6），七道闸全绿。

## 0.45.1（已并入 0.46.5）

风水引擎的入参校验改走统一错误工厂，工具层不再把「坐向写错」这类调用错误标成内部异常。

- **缺口在哪**：`engine/fengshui.js` 的坐向、性别、生日、运越界都裸抛 `new Error`，到 `index.js` 的工具 catch 里没有 `code`，一律落到 `[E_INTERNAL]`；模型侧据此会把「参数该改」误判成「插件坏了」。
- **改动**：六处入参校验改用 `fail('E_INPUT', …)`——非 24 山、命卦缺性别、命卦缺完整生日、缺坐向、坐向不对宫、运越界。`mingGua` 落中宫的「命卦计算异常：落中宫」是内部一致性守卫，不是入参错误，仍保持无码 → `E_INTERNAL`。
- **口径不变**：文案、判定条件与结果字段均未改，只补错误码；工具层现有 `code || E_INTERNAL` 的透传逻辑不用动。
- **测试**：`test/tool-fengshui.test.mjs` 补 7 条（+7）——运越界与坐向不对宫各加一条码断言，另表驱动五组入参错误，要求文案匹配且前缀恒为 `[E_INPUT]`。统计 **91 个测试文件 / 3488 条断言**（+7），七道闸全绿。

## 0.45.0（已并入 0.46.5）

把「通关」从一句取象变成可复核的结构判定：用神与忌神相战时，指出五行里唯一能接上的那一行，并如实报它在局中的分量。

- **缺口在哪**：`engine/geju.js` 的文案一直写「身中和，先取调候与通关」，但引擎从未算过通关；`classics.js` 也只录了寒暖/燥湿等滴天髓条目，没有通神论「通关」原文。
- **判定口径**（`engine/geju.js` 的 `tongguanOf`）：只在「用神与克它的忌神两行在局中各 ≥1.5 分」时成立相战；通关行由五行生克唯一确定（克方所生、又生用神，金克木以水为关），按分量分「可通 / 关弱 / 为忌 / 未通」四档，`usable` 仅指「可通」。通关行若在本盘属忌神，只标「为忌」、不当桥用；只写进用神 detail、摘要与解释层，不折分数、不断吉凶，也不判通关之力够不够用。
- **原文与选条**（`engine/classics.js`）：新增 `dt-tongguan`（通神论·通关，典藏网 153091，原句照录「关内有织女，关外有牛郎，此关若通也，相邀入洞房」）。只在 `usable` 时占一位，并让泛论「用神配气候」让位；寒暖/燥湿的具体条目照留，整节仍以 5 条为限。未通的盘（如 1996 盘）经典选条保持原样。
- **知识卡**（`engine/interpret-knowledge.js`）：新增 `bazi-tongguan`，标 `variant` 并写明分歧——各家对「两神相战」取哪两神不一（日主与官杀 / 用神与忌神 / 局中最旺两行），本插件固定取用神与克它的忌神。知识库 50 条（15 / 34 / 1）。
- **已知边界**：调候与扶抑可能给出同一行同时在喜在忌（扫射中约四分之一盘）；本插件不改写喜忌表，通关判定按现表计算，并在清单里写明。
- **测试**：新增 `test/tongguan.test.mjs`（58 条）——五组相克各给唯一通关行、1.4/1.5 阈值与四档分类、喜忌顺序与空结果、24 年逐月真实盘独立重算与确定性、可通/未通两盘的经典选条、摘要/解释层/面板可见性与知识卡。统计 **91 个测试文件 / 3481 条断言**（+58），七道闸全绿。

## 0.44.2（已并入 0.46.5）

补齐模型侧调用玄空的最后一环：工具 schema 声明 `action:'xuankong'` 与 `period`，并让「今年」只补进命卦。

- **缺口在哪**：玄空下卦在引擎与两个界面都能用，但模型工具 `metaphysics_chart` 的 `action` 枚举只有 natal / advise / assess / generate，没有 `xuankong`，也没有 `period` 参数——对话里让模型排玄空，schema 层面就过不去。
- **另一个隐患**：`run()` 原先把「没给 fortuneYear 就补今年」的规则写成「fengshui 且不是 advise」，玄空一旦可调用，缺省会得到 fortuneYear=今年，九运缺省提示永远不出现，按年定运与默认九运两种口径悄悄混在一起。现在只对 natal（含未写 action 的缺省）补年份，玄空严格走 `period` → `fortuneYear` → 九运并注明。
- **改动**（`index.js`）：`action` 枚举加 `xuankong`；新增 `period`（1–9，优先于 fortuneYear）；`sitting` / `facing` / `fortuneYear` 与 `system` 的说明同步覆盖玄空；年份补全条件收窄到 natal。
- **口径不变**：显式 `period` 优先；给了 `fortuneYear` 按该年定运并回运程起止；两者都没有才缺省九运（2024–2043）并写明提示。
- **测试**：新增 `test/tool-fengshui.test.mjs`（19 条）——枚举与 period 声明、显式运不注入年份、按年定运的起止、缺省九运且不被今年顶替、命卦仍默认今年、非法运与坐向不自洽在工具层报错。统计 **90 个测试文件 / 3423 条断言**（+19），七道闸全绿。

## 0.44.1（已并入 0.46.5）

风水结果在 DSH 侧栏与独立页同步换了展示：从一段摘要文本变成方位网格，侧栏主按钮文案也按 tab 归位。

- **为什么**：上一轮把玄空下卦算出来了，但结果只是 `renderText` 的文本墙——九宫运/山/向挤在方括号里，旺山旺向与表法只能逐字读。侧栏面板里这个问题更明显（没有等宽排版）。
- **共用一份渲染**（`src/panel-kit.js` 的 `pp.fengshuiHTML`）：侧栏（`src/app.js`）与独立页（`src/web-ui.js`）都挂到同一个函数，改一处两边同步。
  - **玄空**：按后天八卦三行九宫（巽离坤 / 震中兑 / 艮坎乾），每宫依次列运/山/向三数；与当运相同的数高亮（中宫运数本身即当运，故 9 运、8 运各 3 处高亮）；卡头写山盘/向盘的入中星与顺逆，以及「盘面」「表法」两个独立 chip；下方事实行写当运落宫、合十、表法说明。
  - **八宅命卦**：八向格（中宫留空）标星名与吉/凶，四吉四凶各四；给了流年时加一行年紫白（入中星 + 八宫星名）。
  - **门主灶**：同一张八向格 + 门/灶/床/厕四行 + 命宅配（给了生辰才有）。
  - 所有文本走 `esc()`，布局文案或宅卦名里塞 `<img>` / `<script>` 不会变成标签。
- **侧栏动作按钮**：速查类 tab（黄历/农历/择日/称骨/小六壬/星座/生命数字/人生K/风水/起名）由「起卦」改为「看结果」，奇门为「起局」，空状态提示同步改成「填好参数，点『看结果』」。
- **没改什么**：引擎与输出字段未动，仍是展示层改动；`meta.scope` 与免责声明原文照旧。
- **测试**：新增 `test/fengshui-ui.test.mjs`（43 条）——九宫顺序与 27 个数、当运高亮、9 运无局与 8 运乾巽到山到向两套盘、八宅四吉四凶与年紫白、门主灶四行与命宅配、转义、侧栏/独立页接线与按钮文案。统计 **89 个测试文件 / 3404 条断言**（+43），七道闸全绿。

## 0.44.0（已并入 0.46.5）

风水补上一直挂着的玄空飞星：不是只加一张表，而是把「运盘 → 山盘 → 向盘」的挨星规则真正跑通，并让盘面与通行旺山旺向表逐运对得上。

- **缺口在哪**：README 的风水段一直明写「不含玄空各运盘」。八宅命卦、大游年、年紫白都是单星飞布，缺的正是玄空最核心的**下卦三盘**：当运星入中排运盘，再取坐宫/向宫的运星入中排山盘、向盘，最后看当运山星是否到坐、当运向星是否到向。
- **关键口径（这一轮最容易踩错的地方）**：山盘/向盘的顺逆**不是**按坐山本身的阴阳，而是按「入中运星的本宫（本位卦）同元龙之山」的阴阳；五黄入中时按本山阴阳。按本山阴阳会把旺山旺向算成每运固定的六局，与通行二十四山旺山旺向表（一运、九运无局）对不上；改按本宫同元龙后，九运旺山旺向表与盘面逐运吻合。
- **新增能力**（`engine/fengshui.js`）：`periodOfYear`（1864 起一运、每运 20 年、九运 180 年一轮）、`MOUNTAIN_META`（24 山三元龙与阴阳）、`xuankongChart` 与 `action:'xuankong'`。输出九宫逐宫的 `运/山/向`、山盘与向盘的入中星与顺逆依据、当运星落宫、山星/向星合十宫位，以及**表法**旺山旺向（通行表）与**盘面**旺山旺向（当运星是否落坐/向）两套结论并列；两者口径不同，不合并、不互相覆盖，文案里写明差在哪。缺省运为九运（2024–2043）并给出提示，也可传 `period`（1–9）或 `fortuneYear`。
- **没做什么**：替卦 / 兼向、年月日时飞星、形峦与现场勘舆、具体应期。`meta.scope` 与免责声明逐条写明。
- **界面**：面板与独立页的风水速查加第三个模式「玄空」，坐山/朝向沿用 24 山输入，另加「运（1–9）」输入；结果仍走摘要文本，九宫按「巽离坤 / 震中兑 / 艮坎乾」三行排出。
- **测试**：新增 `test/fengshui-xuankong.test.mjs`（119 条）——三元九运边界、24 山三元龙阴阳逐条、七张公开盘面数字（含双星会向、五黄入中）、每运 12 局三盘均为 1–9 排列、**盘面旺山旺向与通行表逐运一致**（两套独立数据互证）、坐向互通、216 局确定性、运的来源与输入边界、`compute` 接线与摘要。统计 **88 个测试文件 / 3361 条断言**（+119），七道闸全绿。

## 0.43.1（已并入 0.46.5）

专旺格与从格终于有原文可读：三命通会里其实有七篇专章，此前清单写的「三书没有可整段照录的专章」是错的。

- **缺口在哪**：`docs/知识扩展与待核实清单.md` 四·1 一直写着「专旺格与从格暂无对应的单章原文条目（三书里没有可整段照录的专章），暂不硬凑」。核对典藏网目录后发现三命通会卷六有曲直、炎上、从革、润下、稼穑五篇，卷五有弃命从煞、卷六有弃命从财——正好对着引擎里已有的专旺五格与从财格、从杀格。于是这一轮不是「补口径」，是补上本可以早就有的原文。
- **七条原文**（`engine/classics.js`）：`smt-quzhi`（卷六·曲直 7630）、`smt-yanshang`（卷六·炎上 7631）、`smt-congge`（卷六·从革 7632）、`smt-runxia`（卷六·润下 7633）、`smt-jiasi`（卷六·稼穑 7634）、`smt-congsha`（卷五·弃命从煞 7598）、`smt-congcai`（卷六·弃命从财 7652）。原文取连续段落照录、不加省略号也不改写；白话自撰。原文里「多主眼疾」「破家不仁之人」这类旧说重话照录，但明确只记原文、不拿来断人。
- **接线**（`classicsFor`）：命中的专旺格 / 从财格 / 从杀格先取单章原文，排在月令格之前——专旺或从格是这张盘的定义性结构，先占位才不会被后面两条气候与总纲挤掉；整节仍以 5 条为上限，不额外放宽。从儿格（食伤）、从强格（印 / 比劫）三书里没有可整段照录的专章，`SPECIAL_CLASSIC` 不登记、不硬凑，测试里用两张真实盘反向核过「不误配」。
- **知识库 49 条**：新增 `bazi-zhuanwang-yuanwen`（专旺五格的成格条件比「身强」细）与 `bazi-congge-yuanwen`（弃命相从、见根气即破格），均标 `variant`——专旺是否必须成方局、从格是否允许微根，各家宽严不一；只列结构与原文，不断贵贱，也不补专旺的破格条件。顺手把清单表格里漏登的三条历史条目（紫微三方四正复合飞化、六爻用神旺衰、六爻全卦逐爻旺衰）补齐，表格从 44 行对到 49 条。
- **口径修正**：清单四·1 与 README 致谢里「三书没有专章 / 只取七条」的说法一并改对，写明「十四篇：论十神七篇 + 专旺五格与弃命从煞、从财七篇」，并注明从儿、从强仍未录。
- **测试**：`test/classic-quotes.test.mjs` 新增七张真实盘（曲直 / 炎上 / 从革 / 润下 / 稼穑 / 从财 / 从杀）逐格核「命中的单章排第一、why 点名、仍守 5 条上限」，另加从儿 / 从强两条反向用例、limit 截断、摘要与解释层可见；`test/sanming.test.mjs` 条目数由 7 改为 14（并拆出「7 论十神 + 7 格局篇」两个计数），逐条核原文、章名、典藏网链接、链接互不重复、tag 不与月令十神混用，并钉住两张新知识卡。统计 **87 个测试文件 / 3242 条断言**（+57），七道闸全绿。

## 0.43.0（已并入 0.46.5）

解读从「五维度 + 若干节」升级成可读的报告：紫微补逐宫与分层格局，八字补命局框架、画像、流年叙述与专业建议；措辞收进两份独立词库，引擎与说法彻底分开。

- **缺口在哪**：此前的解读只有五个维度和几张表——维度说得对，但不成篇。用户拿到紫微盘，看不到「这十二个宫各自是什么味道」；拿到八字盘，看不到「这个人的框架、长什么样、哪一年顺」，只能自己去拼盘面。对照市面上的成篇解读，差的是**结构与措辞**这两层，不是数据。
- **紫微新增四块**（`engine/interpret.js`）：① **命身底色**——命宫主星 + 亮度 + 双星组合 + 身宫落点一句话说清；② **逐宫分析**——十二宫各一条 `【宫·支】主星（亮度）｜吉星｜煞星｜四化`，下接「读法」；③ **三层格局**——有利格局 / 结构提示 / 忌格提醒，每条写 `名称 · 人话 · 依据（盘面事实） · 做法`，按 tone 着色；④ **行动建议**四条。只把六煞（擎羊/陀罗/火星/铃星/地空/地劫）写进五个维度，其余杂曜留在逐宫，避免一眼看去全是星名。
- **八字新增四节**：**命局框架**（日主/用神/格局三行，末尾一句命局基调）、**正面画像**（外在取象 / 性格底色 / 事业与家庭）、**流年时间轴**（近三年逐条给档位与理由，用「可能性」措辞并声明档位不是断语）、**专业建议**（喜用落地 / 忌神自觉 / 地支关系 / 调候四件可做的事）。
- **两份词库**（新增 `engine/ziwei-words.js`、`engine/bazi-words.js`）：紫微侧 12 宫取象、14 主星（别称/关键词/得地与失地两种语气/长处/要留意的点）、24 组双星、14 煞星、18 吉星、四化落宫、七档亮度、34 条格局读法；八字侧 10 天干取象、10 颗十神 + 5 组（十神权重底层给的是组名，组与单颗各有一套话）、旺衰 × 用神方向的六种命局基调、地支冲合刑害破的手感。**词库不含判断条件**——要不要说、说哪一条由引擎决定，换个排盘引擎结论也不会被说反。
- **命局基调按权重取**：`frameToneOf(level, favorRoles)` 只看角色不动分数；调用方先把 `favorRoles` 按十神权重排好再传入，于是「身强喜食伤财官杀」取到的是分量最重那一支（泄），而不是固定顺序的第一条。强档没有对应基调时回落「泄」、弱档回落「生」，都写明理由。
- **面板**：分节支持 tone（左框线 + 标题色：有利绿、提示橙、忌格红）与 `**加粗**`、换行分段（此前整节挤成一坨）；逐宫、三层格局各有独立锚点，目录可跳。
- **术语表**（`engine/interpret-plain.js`）：补 庙旺 / 三方四正 / 命主 / 身主 / 五行局 / 自化 / 飞星 / 正曜 / 借对宫 / 双星 / 墓库 / 伏吟 / 反吟 十三条，仍按「正文里真的出现过」才展示，并按体系取不同释义。
- **顺手改掉两处重复**：紫微「说人话」不再复述直答里的命宫与身宫，改说「你与环境怎么互动」与重心；八字性格底色的单颗十神只补「落在哪个角色上」，不再把组的那句抄一遍。
- **测试**：新增 `test/ziwei-words.test.mjs`（55 条）与 `test/bazi-words.test.mjs`（46 条）——词库条目数与引擎表一一对应（34 条格局名与 `PATTERN_TONE` 双向零差集）、双星 key 必须能拆成两颗真实主星、亮度三档齐全、煞星不写成判决、基调优先序与回落、地支关系去重与「自刑优先于刑」、四节存在且引用本盘真实字段、面板把 `**` 与换行渲染成 `<b>` 与段落、全文无 undefined/NaN。**87 个测试文件 / 3185 条断言**，七道闸全绿。
- **边界**：词库只给倾向与做法，不下断语；格局读法覆盖现有 34 条，新增格局未入词库时按 tone 回落成通用句而不是现编；逐宫只写星曜与四化，不叠大限流年的三层算力；健康维度只用煞星星情，不给脏腑诊断。

## 0.42.0（已并入 0.46.5）

紫微的闰月从两档补到三档，默认换成主流排盘的「按日切分」；顺手修掉流年斗君二次换月。

- **缺口在哪**：此前只有「闰月按本月」与 `leapAsNext`（整月归次月）两档，默认按本月。闰月后半月出生的人，主流排盘按次月起盘，我们却按本月，命宫、身宫、五行局、十四主星位置、大限起运、流月斗君整条链都差一个月——盘看起来完整，宫位却系统性偏移。
- **三档口径**（`engine/ziwei.js` 新增 `LEAP_POLICIES` / `leapPolicyOf` / `effectiveLunarMonth`）：`split`（默认，1–15 归本月、16 起归次月，按日切分）、`next`（整月归次月）、`prev`（整月归本月）；`leapAsNext: true` 保留为 `next` 的旧写法，`leapMonth` 优先于它。不认识的取值回落到默认，不抛错。工具参数同步成枚举，`rules.leapMonth` 写明三档与默认。
- **为何改默认**：参考开源项目 [ziwei-doushu](https://github.com/Renhuai123/ziwei-doushu)（MIT）的流派配置与其 150 组金标准盘对照结论——主流排盘默认「月中分界」。我们不引入其引擎，只采纳这一条排盘口径，并把它做成可切回的开关；不想换的人传 `leapMonth: 'prev'` 即回到旧口径。
- **盘里能看见**：`lunar` 保留 `monthRaw`（原始闰月）与换算后的 `month`、`leapPolicy`，闰月另给一句说明（「闰4月按日切分……本盘闰月21日按5月」）；摘要的农历行写成「2020年闰4月21日（按5月起盘）」，不再把 21 日写成「闰5月21日」；面板宫盘抬头同样处理。
- **修掉一个旧 bug**：`flowOf` 里的流年斗君此前用 `chart.lunar.month`（已是换算后的月）再按 `leapAsNext` 加一次月，闰月 + `leapAsNext` 会多推一个月。现在起盘时只换一次，流月/流日/流时全部直接读换算结果。
- **边界**：闰十二月十六起回绕到正月只换月序、不老一岁（闰腊月极罕见，明写不猜）；1–15/16–30 的分界按通行「月中」，不提供逐日自由配置；不引入参考项目的其余九类流派开关（庚年四化变体、亮度流派、安天马/天空/截空等），留作后续。
- **测试**：新增 `test/ziwei-leap.test.mjs`（44 条）——2020 闰四月的初十/十五/十六/廿一四个边界、三档口径函数与默认/别名/未知值回落、起盘月与命宫紫微斗君逐项对照、前半月 split 与 prev 同盘、`leapAsNext` 与 `next` 等价、斗君只换一次月、非闰月三档排出同一张盘、compute 透传与摘要/面板文案。**85 个测试文件 / 3084 条断言**，七道闸全绿。

## 0.41.0（已并入 0.46.5）

起名补上一直被写在「不做」里的两层：**五格剖象**（天格/人格/地格/外格/总格 + 81 数理 + 三才）与**音韵检查**。此前 README 明写「不做五格（需康熙字典笔画）与音韵」，等于把最常被问的两件事推给用户；这一轮把笔画与读音数据补全，再按通行算法落地。

- **数据层**（新增 `engine/name-data.js`）：391 个用字逐字补**拼音、声调、康熙笔画**（按繁体字形与偏旁本字计：华→華14、马→馬10、静→静16、涛→濤18、灵→靈24、兰→蘭23、丰→豐18、书→書10、画→畫12、云→雲12、风→風9、阳→陽17；氵→水4、艹→艸6、辶→辵7、阝左→阜8、阝右→邑7）；单姓笔画表约 120 个（王4/李7/张11/刘15/陈16/罗20/郑19），复姓 13 个逐字存（欧阳 15/17、司马 5/10、夏侯 10/9…）；81 数理取通行本，分吉/半吉/凶三档。数据与字库由测试逐条对齐——391 条一一对应，多一个字少一个字都会红。
- **五格**（`engine/name.js` 新增 `wuge`）：单姓双名 天格=姓+1、人格=姓末+名首、地格=名两字和、外格=总−人+1、总格=全部；单姓单名 地格=名+1、**外格固定 2**（没有「外侧」，通行本记 2，不是 1）；复姓 天格=两字和、外格=总−人+1（等价于复姓单名的「姓首字+1」）。数理超 81 按 −80 回绕（104→24），三才取天/人/地个位对五行，再按生克给一句「一路相生 / 相连相克 / 吉凶各派看法不一」，不折算分数。
- **缺笔画不半算**：任一字查不到康熙笔画，整体返回 `available:false` 并点名是哪个字，提示用 `strokeOverrides`（逐字）或 `surnameStrokes`（按姓）补；补进来的字在结果与面板里都标「用户指定」。姓超两字、姓不在表、只给名不给姓，都走同一条「算不了」的路，不拿简体笔画或猜测顶上。
- **音韵**（新增 `phonetics`）：只报可数的事实——全名同调、相邻同声母、相邻同韵母、相邻同音（叠字），再按条数判「顺口 / 略拗 / 拗口」。声母先切 zh/ch/sh，y/w 按拼写当声母。**不做语义谐音**（需要词库），摘要与注释都写明「谐音、方言读法还得自己读三遍」。
- **排序而非判定**：生成候选名把五格格数当第三顺位（合喜用 → 两字异行 → 五格 → 性别倾向 → 字库序），注释写清「是排序不是吉名判定」；姓的笔画不在表里时这一轮不按五格排序，也不伪造。
- **四处可见**：摘要各加一行【五格】【音韵】；面板新增五格格阵（5 列，吉/半吉/凶各配色）、笔画行（用户指定标「（指定）」）、三才行与音韵行（拼音+调、声调序列、水平徽标、逐条问题），算不了时显示原因而不是空白；生成候选的每个名字带「五格 N/5 吉」与音韵水平 chip。
- **顺手修掉一处静默丢参**：页面上「评名字」虽然显示出生日期，`src/web-ui.js` 与 `src/app.js` 却在提交前 `delete args.datetime`，于是填了生辰也永远得到「给出生年月日才能判断」；现在生辰填了就传、空着才删，评估能按喜用判，面板里的八字行也随之出现。
- **测试**：新增 `test/name-wuge.test.mjs`（103 条）——数据完整性（读音表与字库双向零差集、声调 1–4、笔画 1–40、拼音正则、81 条数理档位）、康熙锚点（静16/涛18/灵24/兰23/丰18/书10/画12/云12/风9/阳17 等 16 字与 7 个姓）、81 回绕、四类姓氏结构的五格数与吉凶、三才、缺笔画/超长姓/无名的落点、笔画覆盖与来源标注、音韵四类问题与顺口反例（王沐宸）、compute 接线与面板渲染，以及两处入口不再丢生辰。**84 个测试文件 / 3040 条断言**，七道闸全绿。
- **边界**：81 数理各派对少数数取法有出入，按通行本取一套；五格只是传统数理游戏，不参与喜用判定，也不改结论。

## 0.40.0（已并入 0.46.5）

六爻的伏神补上「出伏条件」：飞伏生克与月建日辰并列摆出，归成四档，只判条件、不出应期。

- **缺口在哪**：知识卡 `liuyao-fushen` 一直写着伏神看「日月生扶」，引擎却只算飞伏生克（飞生伏 / 伏生飞 / 飞克伏 / 伏克飞 / 比和）——月建、日辰从未落到伏神那一爻上。卡上是口径、盘上没有实现，这一轮把这一层补上。
- **四档判定**（`engine/liuyao.js` 新增 `fushenAccess`，挂 `result.fushenAccess`）：先并列两栏——助（飞生伏、伏克飞、日辰生、日辰比和、月建旺、月建相）与压（飞克伏、日辰克、月破）；有助无压为「可出」、有助有压为「有助有压」、有压无助为「受压难出」、两者都无为「未得助」；没有飞伏关系时记「飞伏未知」，不猜。
- **四处可见**：摘要单列「伏神出伏：第2爻可出」；解析在飞伏段后逐条写该爻的月建（五行、五态、是否月破）、日辰（五行、五关系）与助压明细；白话按档位补一句（「出得来」是条件、不等于马上应验）；面板在旺衰 chip 下单列一排（可出绿，有助有压 / 受压难出赭）。
- **口径与边界**：四档只并列条件，不排「飞伏与日月谁先谁后」的各家优先级；月破算压、伏神旬空只标出而不并入档位，都是明写的取法，不假装是共识。**应期仍未做**——这一层只回答「现在出不出得来」，不给具体日期；`docs/知识扩展与待核实清单.md` 的四·3 与文末注同步写明「条件是条件、应期另算」。
- **测试**：新增 `test/liuyao-chufu.test.mjs`（53 条）——用独立的五行生克与相冲表复算 64 卦 × 4 个询问方向 × 12 个月 × 12 日 = 6,048 组，要求逐组零不符、四档都出现、四种真实飞伏关系都覆盖；四条从真实盘里挑的边界（地雷复·学业 寅卯「可出」、亥卯「有助有压」、地火明夷·财 子子「受压难出」、地山谦·财 午辰「未得助」）；缺月建只看日辰、飞伏关系未知、伏神旬空只标不改档、传 null 不抛四条兜底；摘要/解析/白话/面板四层可见、旧结果兼容、断言输出里没有应期字段。统计 **83 个测试文件 / 2937 条断言**，七道闸全绿。

## 0.39.0（已并入 0.46.5）

首屏从「19 个 tab 平铺」改成按目的分三组，并保留一键切回平铺。此前第一次来的人得先猜「梅花」「称骨」是什么；现在按「问一件事 / 看一个人 / 查日子」分组，每项带一句白话。同一轮还改了「问进对话」的提问模板：原来它只约束证据与口气，模型答出来是一串带引用的术语流，读的人不知道这张盘在说什么。

- **三组入口**（`tools/build-html.mjs`）：问一件事（六爻/梅花/塔罗/奇门/六壬/小六壬）、看一个人（八字/紫微/合盘/人格/称骨/数字/人生K）、查日子（黄历/择日/农历/星座/风水/起名）——19 项一个不落，顺序按用途重排，不按引擎模块排。
- **每项一句白话**：「摇六次，问一件事」「四柱看一生格局」「挑个办事的好日子」，不用先懂术语再点。
- **最近用过**（`src/web-ui.js`）：只记入口名与时间，最多 3 条，存 `mp.recent.tabs`；点入口、点起卦/排盘、人格问卷提交时记录，首屏默认 tab 不记；`localStorage` 读写都包 try/catch，隐私模式下只是不记，不影响使用；读回的值先过「当前页面真实入口」白名单，不直接拼进选择器。
- **平铺回退**：19 个 tab 原样保留在页面上，右上角「分组 / 平铺」一键切换并记住选择（`mp.first.view`），旧用户的肌肉记忆不受影响。
- **手机端**：每组先露 4 项，其余折在「还有 N 个」后面（`nth-child(n+5)` + `.open`），三组铺完不再把表单推到第二屏以下；桌面三列、中屏一列。
- **样式**：卡片沿用纸色 + 朱红（选中项实心），深色下文字反色；打印时首屏分组、视图开关与 tab 条一律不打印，纸面仍是「抬头 + 盘面 + 解读」。
- **追问读不懂**（`engine/followup.js`、`test/ask-prompt.test.mjs`）：此前「回答要求」只有三条——引到具体柱/宫/爻、没依据就说看不出来、别给绝对断言。这三条只管**证据**与**口气**，不管**可读性**，于是照它答出来的东西是一串带引用的术语流：知道「甲有问题、乙有问题」，却不知道这张盘到底在说什么。现在模板先交代一句「读者不懂命理」，再给一套骨架：**开头一句不用术语的结论**（只读这句也该有收获）→ 判断**最多两条、按重要性排序**，每条分 `盘面｜白话｜倾向｜边界` 四行（盘面只引字段不掺解释；白话把上一行的术语当场翻掉，一个词只翻一次、不连续堆三个以上；倾向用「更可能……」讲清现实含义；边界写清何时不成立，盘面没给的直接写「这盘里看不出来」）→ 收尾一句「**如果只记一件事**」，给可核对、可动手的观察点并点明它出自哪条依据。`调候 / 化气 / 通关 / 空亡 / 争合` 单独点名要求落地；「格局很好」「运程不顺」这类没有信息的空话禁掉。
- **默认问法也改口**：空问题时原来问「请先总览这张盘」，而「总览」本身就在邀请逐字段复述——模型当然照着摘要念一遍。改成「先用一句白话讲清这张盘的主线，再指出最值得注意的一两处，并说明每处的具体依据」。
- **固定骨架有长度上限**：抬头 + 回答要求约 520 字，不随 `maxChars` 变；测试里那条「固定骨架本身不超过 900 字」专门盯它别长成小作文。顺带修掉一条会误报的旧断言——原来写「整段提问 < 800 字」，骨架一长就红，现在拆成「摘要正文真的截到 maxChars」与「骨架另有上限」两条，各盯各的。
- **测试**：新增 `test/first-screen.test.mjs`（44 条）——三组名称与顺序、19 项与平铺集合逐一对齐、每项都有白话、记录时机（入口/主按钮/问卷）、存储上限与去重、读写失败降级、手机折叠与 aria、两套入口共用 `activate`、深色反色与打印隐藏。其中 `.recent[hidden]` 一条专盯「`display:flex` 盖掉 `[hidden]`」——首版就踩了，没记录时页头挂着一个空的「最近用过」。`test/ask-prompt.test.mjs` 由 46 条增至 54 条（骨架四行齐全、无术语结论、难词点名、收尾句、空话黑名单、默认问法改口）。统计 **83 个测试文件 / 2937 条断言**，七道闸全绿。

## 0.38.2（已发布 2026-10-29）

紫微格局修掉三处「写得像实现了、其实永远不成立」的判定：夹局的方向、羊陀夹忌、刑囚夹印；顺手把 34 条目录从 README 的 31 条补全，并用独立谓词逐条钉死。

- **夹局不分左右**（`engine/ziwei.js` 的 `jia`）：旧写法只认「A 在命宫前一宫、B 在后一宫」这一种顺序，但「夹」只要求两星分居命宫前后。实测 69,120 张盘：**昌曲夹命 0/8、羊陀夹命 0/1,474 从未命中**，日月夹命（237:231）、左右夹命（470:457）、魁钺夹命（283:292）各漏约一半。改为两向都认；`test/ziwei-patterns.test.mjs` 用镜像方向的真实盘（1955-01-02、1955-06-22、1956-02-14 等）钉住。
- **羊陀夹忌**：擎羊恒在禄存 +1、陀罗恒在禄存 −1，两星只能夹**禄存**那一宫；旧判据要求「化忌两侧是羊陀」，几何上不可能（1,553 张符合的盘一次都没报）。改为「化忌与禄存同宫」，证据文本写明化忌落在哪一支。
- **刑囚夹印**：廉贞与天相永远隔偶数宫，字面上的「廉贞、擎羊夹天相」同样不成立（17,568 张盘两向皆零）。按通行说法改为「廉贞天相同**守命宫**于子午、擎羊同宫」——源文说的是「守命」，所以判的是命宫那一宫，廉相羊同宫在别的宫位不报；evidence 写明三颗星同守哪一宫；命宫卯酉、廉贞天相对照遇擎羊的变体未纳入，写进 README 口径。三条来源：知乎「刑囚夹印」、sohu 格局文、ziwei-yun「天相不可能被廉贞和擎羊二星所夹」。
- **34 条目录补齐**：README 原列 31 条，且把 武贪同行、火贪铃贪 归在吉格（引擎一直是中性）、`双禄交流 / 命无正曜 / 杀破狼` 完全没写。现按引擎口径分三组列出（吉 20 / 中性 5 / 忌 9），`PATTERN_TONE` 改为导出供测试比对；README 与目录的一致性由测试直接解析 README 断言。
- **结构统计补中性**：`patternSummary` 增 `neutral`，摘要行改成「吉格 N、中性 K、忌格 M」——此前中性格计入 count 却不出现在统计里，count 会大于两档之和。
- **不新增能力、不动知识库**：知识库仍 47 条（本轮是判定口径修正，不是新规则）；格局仍只描述结构、不折吉凶分数。
- **测试**：新增 `test/ziwei-patterns.test.mjs`（79 条）——34 条目录与 README 三组逐名对齐；312 张盘 × 34 条用独立谓词（只读星位与四化，不调引擎判定）复算，要求每条「零不符且至少命中一次」，专门防死规则；夹局镜像方向、羊陀夹命 ⇔ 禄存守命、羊陀夹忌 ⇔ 化忌同禄存、刑囚夹印守命（含「非命宫同宫不报」反向盘）、摘要计数与确定性各自钉住。故意把 `jia` 改回有序写法时该文件 11 条变红。统计 **81 个测试文件 / 2832 条断言**，七道闸全绿。

## 0.38.1（已并入 0.38.2）

古籍库补上《子平真诠》论格局成败的两章，并把「用神总纲」一位改成按盘取；顺手修掉 why 里拼出「论论财」的旧文案。

- **两条原文**（`engine/classics.js`）：`zp-chengbai`（九、论用神成败救应，「成中有败，必是带忌；败中有成，全凭救应」）与 `zp-bianhua`（十、论用神变化，「藏庚透壬，则化为财。凡此之类皆用神之变化也」），均照录中华典藏网 53629 / 53630，白话自撰。
- **为什么是这两章**：0.37.0 起古籍节覆盖了「月令格 × 两书对照」与「调候」，但化气格只剩气候与总纲，组合（官印相生、伤官见官等）没有任何原文可读——这两章正是判「化气成不成」「成格有没有带忌」的出处。
- **总纲位三选一，不另加位次**：`classicsFor` 的第五条仍是「用神总纲」位——有化气格取「论用神变化」，见组合取「论用神成败救应」，其余取「论用神」通用总纲。上限没有从 5 放宽，也没有让泛论挤掉针对这张盘的话；同盘同时有化气与组合时取「变化」，why 写明取舍。
- **文案 bug**：此前 why 用 `${书名}论${章名}` 拼，而章名本身已带「论」，实际输出成「子平真诠论论财」「三命通会论论正财」。改为「书名「章名」一条 / 另取」，章节标题去掉序号与开头的「论」；测试加「why 不出现论论」的断言。
- **知识库 47 条**：新增 `bazi-geju-chengbai`（成中带忌、败中有救）与 `bazi-huagi-bianhua`（月令藏干与合局改变取用），均标 `variant`——成格条件、化气成立条件各家宽严不一，只并列原文与方向，不逐盘判成破。`docs/知识扩展与待核实清单.md` 的条数、统计与注记同步；顺手把上一轮注记里写错的版本号 0.37.2 改回 0.38.0。
- **口径边界**：专旺格、从格仍没有对应的单章原文（三书里没有可整段照录的专章），不硬凑；古籍节仍只负责「书上怎么说」，不把原文折算成吉凶分数。
- **测试**：`test/classic-quotes.test.mjs` 新增 13 条（两章原文抽检与典藏网出处、why 无双「论」、三选一互斥、1996 盘取「变化」、化气/组合/无特格三种落点）；`test/sanming.test.mjs` 新增 7 条（总纲换条后仍保住两书对照、两张知识卡的出处与「不当断语」口径）。统计 **80 个测试文件 / 2753 条断言**，七道闸全绿。

## 0.38.0（已并入 0.38.2）

补上知识卡里已经写了、引擎却一直没做的一层：**岁运并临与伏吟反吟的逐年提示**。此前 `bazi-suiyun` 卡说「只作变动提示」，但盘面里没有任何地方标出是哪一年，等于只有口径、没有实现。

- **四类信号**（`engine/bazi.js` 给每条流年加 `suiyun`）：**岁运并临**（当值大运与流年干支相同）、**运年反吟**（大运与流年天克地冲）、**流年伏吟**（流年与年/月/日/时柱干支相同）、**流年反吟**（流年与某柱天克地冲）。每条信号带 `type` / `target` / `detail`，另给 `note` 写明口径。
- **当值大运怎么取**：流年按立春起算，取与「该年立春到次年立春」区间相交的大运；交运落在这一年里时，前后两步都在本年当过值，两条并列。没有用虚岁近似，也不把交运日抹平。
- **天克地冲的判据**：天干相克 **且** 地支相冲，缺一不算。例如丙子年对丙午年柱是同干相冲，不标反吟；这条单独在测试里构造验证。
- **口径与边界**：只标干支重复与对冲，不折分数、不判吉凶——「岁运并临主大凶」一说不采，摘要与解析都写明「只标变动，仍看该年是否动到用神」。大运与原局之间的伏吟反吟未逐年标，四柱十神的引化也未叠入；起运前只有流年这一侧能成立。
- **四处可见**：摘要加一行「岁运提示（只标干支变动，不判吉凶）：2030庚戌 岁运并临；…」；解析新增「岁运提示」节，逐年写清当值大运与每条的出处；白话只在最近一个命中处补一句「变化感强一点，不是好消息也不是坏消息」；面板在流年 chip 下方单列一排提示，chip 悬停给逐条依据。旧结果（没有 `suiyun` 字段）照常渲染，解析退回「近十年没有」的保守说法。
- **账面口径修正**（`docs/知识扩展与待核实清单.md`）：知识库实际已是 45 条（诸家一致 15 / 各家有异说 29 / 待核实 1），清单头部还写着 42 条、统计还停在 15/27/1，一并改对；「岁运并临吉凶」一行补上「已落引擎与界面」。
- **测试**：新增 `test/suiyun.test.mjs`（102 条）——不复用引擎判定，按「月柱干支顺逆推八步」与「立春区间相交」两套独立写法复算 10 张盘 × 10 年；扫描全部样本核四类信号与事实一致（并临必然同干支、反吟必然天克地冲、伏吟必然同柱）；构造同干相冲（丙子 vs 丙午）不算反吟、起运前无大运、年内交运两步并列三条边界；钉住确定性、摘要/解析/白话/面板四处可见、旧结果兼容与知识卡口径。统计 **80 个测试文件 / 2733 条断言**，七道闸全绿。

## 0.37.1（已并入 0.38.2）

界面深修一轮，重点在窄屏：19 个 tab 不再吃掉首屏，两列表单不再被按钮挤成 134px；六爻的化进/化退补上力重。

- **桌面抬头改竖排**（`tools/build-html.mjs`）：品牌一行、tab 条一行。tab 从右对齐的 flex 换行改为 `repeat(auto-fit,minmax(74px,1fr))` 等宽网格，每格同宽、末行左对齐，不再出现「起名 人格」两项孤零零挂在右边、与上一行错开半个身位。
- **窄屏 tab 改单行横滑**：3 列网格是为六个 tab 写的，tab 涨到 19 个后要占七行（约 340px），首屏只剩输入框。改回单行横滑，44px 触摸目标、`scrollbar-width:none` + `::-webkit-scrollbar{display:none}` 藏掉滚动条、首尾各留 12px 呼吸位；切到靠后的 tab 时 `scrollTabIntoView()` 把当前项滚到可视区中间（`prefers-reduced-motion` 下用瞬时跳转），避免「页面变了、高亮停在屏幕外」。
- **窄屏表单两列修好**：根因是 `.go{grid-column:4}`、`.go.ghost{grid-column:3}` 写死给桌面四列，窄屏两列时这两条会生成第 3、4 列隐式 auto 轨道，把两个正文列挤到 134px，性别与按钮全被压扁。窄屏改为「看示例/排盘」分别落在第 1、2 列，性别与出生地各占整行，三个勾选项两两成对，收尾不再留空格。
- **人格页重做**（`src/panel-kit.js`）：结果卡原本是「四行细条 + 段落堆叠」，字小、无层级；现在按「类型抬头（大字类型码 + 名称/关键词 + 已答题数）→ 四维瓦片（双极字母 + 取值条 + 一句取向）→ 一句 → 优势/留意（绿/赭左线两张卡）→ 认知功能链（主导高亮）→ 工作/关系/学习/课题分节」分层。问卷态改成两列编号清单，桌面一眼扫完 24 题。同时把卡片抬头从 `<header>` 改成 `<div>`：页面级 `header{flex-direction:column}` 会把卡片抬头也压成竖排。
- **顶层卡片没拿到调色板**（根因）：变量块只挂在 `.pp,.mp-it` 上，而人格、黄历、称骨、人生 K 线、起名、速查这些卡片是直接插进 `#out` 的兄弟节点，`var(--band)`/`var(--card)` 全部失效 → 卡片退化成没底色、没边框的一堆字，这正是人格页看着丑的主因。变量块扩到 `.mp-al/.mp-cg/.mp-kline/.mp-mb/.mp-nm/.mp-quick` 等全部顶层卡片，`test/theme.test.mjs` 的断言同步改为「各顶层卡共享同一份变量」。
- **人格问卷改分页问答**（`src/web-ui.js`、`src/app.js`、`tools/build-html.mjs`、`src/panel-kit.js`）：原来是一个「24 题分数」文本框——让用户自己数 24 个数字，像在填表格。现在照常见在线测评的做法：**4 题一页、共 6 页**，每题 1–5 五格单选（完全不像 / 不太像 / 说不准 / 有点像 / 很像我），顶部有进度条与「第 n / 6 页 · 已答 x / 24」，底部是上一页 / 下一页 / 看结果 / 清空。答满 12 题就能先出结果（与引擎的 `E_INPUT` 门槛一致），不够时按钮禁用并写明还差几题；最后一页收起「下一页」，「看结果」与原主按钮二选一，不再重复两个入口。题目与 1–5 的说法都从引擎的问卷态取（`compute({system:'mbti'})`），前端不抄一份；答案按题序存成数组，末尾连着没答的去掉再交给 `answers`，中途未答的按引擎口径算「跳过」。独立页与 DSH 面板共用同一套分页交互（面板是 `MbtiQuiz` 组件）；结果不进「最近排过」——答案没存进历史，重放还原不了问卷。
- **人格页输入区**：问卷与日期无关，起卦日期/时刻在人格 tab 下隐藏（面板与独立页同步）；问卷整行独占，窄屏下 5 格缩字体与内边距、按钮整行、44px 触摸目标；深色下选中格文字随强调色反色（与 tab / 主按钮同一口径）。
- **桌面副本可同步**：新增 `--desktop` 与 `npm run build:desktop`，一次把同一份页面写到仓库根和 `~/Desktop/命理排盘.html`。桌面那份是手工拷的产物，源码一改就旧；现在构建就能刷新，页面左上角的版本徽标用来核对。README 三处说明同步更新。
- **变量补全与观感**：共享变量块补齐 `--ink3/--fx/--sans/--kai`（此前多条形同虚设的字体、次级色规则因此失效）与 `--shadow`，深色另给一套；盘面卡片统一 12px 圆角与外阴影，古籍引文块改为左侧朱线 + 楷体悬挂缩进，`:focus-visible` 统一描边，结果入场只做一次轻微上浮并尊重 `prefers-reduced-motion`。
- **六爻 · 化进/化退力重**（`engine/liuyao.js` 新增 `jinTuiPower`，挂 `result.jinTuiPower`）：此前只标方向，现在把每条进退放回月建五态落档——旺相 → 后劲足（退则退得缓）、休囚 → 后劲有限（退则退得实）、死 → 进得虚、逢月破 → 月破失据、缺月建 → 只报趋势；旬空只标出、不改结论。摘要单列「进退力重」一行；解析在「卦体关系」里逐条写清月建、日辰与档位，「未纳入」删去该项（保留用神两现权重与伏神出伏应期）；白话加一句；面板单列一排 chip（后劲足/退得缓绿、其余赭）。只给档位、不折加权分数，吉凶仍落在用神/忌神那一层判。
- **测试**：`test/theme.test.mjs` 第五节改为「单行横滑 + 藏滚动条 + 首尾呼吸位 + 44px 触摸目标 + 切 tab 自动滚入视野 + 两列内按钮不生成额外轨道」，共 50 条断言；`test/mbti.test.mjs` 新增分页问卷一节（25 条）——离线页容器/样式、web-ui 的每页 4 题与 12 题门槛、事件委托、面板 `MbtiQuiz` 单跑校验（一页 4 题、刻度来自引擎、进度文案、按钮禁用与末页无「下一页」）、题面不复制到页面/面板；`test/liuyao-jintui.test.mjs` 新增第六节（27 条）——五态两行档位逐档复算、月破与缺月建两条边界、旬空只标不改结论、摘要/解析/白话/面板四处可见、旧结果不出该排。统计 **79 个测试文件 / 2631 条断言**，七道闸全绿。

## 0.37.0（已并入 0.38.2）

古籍库从两本扩到三本：接入《三命通会》卷五、卷六论十神七条，与《子平真诠》同一格局并列对照。

- **三命通会 7 条**（`engine/classics.js` 登记 `sanming` 书目）：论正官、论正财、论印绶、论食神、论伤官、论阳刃、论建禄各一条，原文照录通行本、逐条给典藏网章节链接，白话释义自撰。选条标准只有一条——与「格局取用」直接相关；神煞、女命、六亲等卷暂不录入。
- **同格两书并列**：同一个「月令格」，先取《子平真诠》那一条（讲怎么用：顺逆、成败、救应），再取《三命通会》同格一条作对照（讲怎么取、怕什么）。例如正官格：子平真诠讲「刑冲破害为忌、生之护之为喜」，三命通会讲「六格之首，止许一位，多则不宜」。两条各给一句 why，不合并、不调和成一句断语。
- **条数上限 5**：格局两条 + 气候两条 + 用神总纲一条，正好把默认位占满；未匹配到两书同格时只出一条，不硬凑。
- **面板书名修正**（`src/panel-kit.js`）：此前面板把非子平真诠的条目一律标成「滴天髓」，接入第三本后会串成「滴天髓·卷六·论正财」；改为按书目映射书名，`test/sanming.test.mjs` 钉住这一点。
- **知识库**：新增 `bazi-sanming-duizhao`（两书分工：一重「用」、一重「取」与「忌」，并列而不合并），全库 **45 条**。
- **口径**：只录与格局取用直接相关的七条，不声称覆盖全书；两书成书年代与流派不同，用语有出入，照录通行本、不做校勘改字，也不替两家调和。
- **测试**：新增 `test/sanming.test.mjs`（40 条）——书目与七条完整性、原文逐字抽检、七格「子平在前、三命在后」的对照选取、why 文案、上限与去重、确定性与 limit、摘要/解释层/面板三处可见、知识卡。`test/classic-quotes.test.mjs` 同步改为三书、条目 ≥26、单盘取 2–5 条。统计 **79 个测试文件 / 2571 条断言**，七道闸全绿。

## 0.36.0（已并入 0.38.2）

把 `docs/知识扩展与待核实清单.md` 里登记的两处缺口补上：紫微的「三方四正一起飞」、六爻的「全卦逐爻旺衰」。0.35.x 的面板修复随这一版一起发。

- **紫微 · 三方四正复合飞化**（`engine/ziwei.js` 新增 `flyComposite`，挂 `chart.flyComposite`）：单宫飞化只回答「这一宫自己去找谁」，这一层把本宫、对宫与两个三合宫共四宫的宫干四化一起摊开——四宫各化禄权科忌，共 16 条，按落宫归堆，落到同一宫就是会照。四类会聚单独成型：**双忌会**（同宫收到 ≥2 个忌）、**禄忌同宫**（禄随忌走）、**三化以上会宫**、**自化**（宫干化出去又落回本宫）。摘要加【三方四正飞化】行（会聚标签 + 四化去向按宫去重）；解析新增「三方四正飞化」节，写清哪几股力会到哪一宫；白话加一句「N 股力最后挤在 X 这件事上」；面板并排 chip，悬停给飞入清单。
- **紫微 · 口径**：会聚判定只看「落在同一宫」这一条结构事实，不折分数、不断吉凶，也未叠大限流年四化；星未上盘时只记星、不记落宫（`to: null`）。三方四正四宫由命宫 +4/+8/+6 推得，与格局识别用的那一套同源。
- **六爻 · 全卦逐爻旺衰**（`engine/liuyao.js` 新增 `hexagramStrength`，挂 `result.hexStrength`）：与用神旺衰同一套判定（月令五态、日辰五关系、月破/暗动/冲空），区别只在不挑用神——六爻每一爻都给一次，世应、动爻、旬空另标，并给出五态分布 `counts`、最旺/最弱爻与世应各自的状态。
- **六爻 · 不依赖用神**：此前旺衰只在取到用神时才算，没指定所问之事就一片空白；现在 `hexStrength` 在 `buildLiuyao` 之后独立计算，没给 `direction` 也能看整张卦的气。
- **六爻 · 口径**：只报状态、不折分数；「未纳入」删去「全卦逐爻的月建旺衰」，保留化进化退的实际力重、用神两现取舍、伏神出伏应期三项。
- **知识库**：新增 `ziwei-sanfang-fei`（复合飞化的会照取法与各家分歧）与 `liuyao-quanggu-shuai`（全卦旺衰与「用神只是一处落点」），并把 `ziwei-feixing` 的 note 从「未做完整飞星串连」更正为「串连与复合飞化已做、未叠大限流年」。全库 **44 条**。
- **自我介绍与讨论群（只在仓库页）**：README 文末新增「关于：一个人做的插件，欢迎来聊」——写明这是个人作品、能力有限，欢迎就断法口径、神煞取法、解析措辞进群讨论，报 bug 请带输入与结果；`docs/assets/dsh-metaphysics-group*.png` 放群二维码。**不进插件运行时**：面板与离线页不加这条提示，市场条目与 `locale` 描述也只说能力、不说作者（提醒只出现一次，在仓库 README）。市场条目与 `locale` 另补齐了 0.35–0.36 两项新能力。
- **测试**：新增 `test/ziwei-fly-triad.test.mjs`（44 条）与 `test/liuyao-hex-shuai.test.mjs`（53 条）——四化表与五态五关系都用另一套写法逐格复算（16 条飞化、12 卦 × 3 月 × 6 爻）、归堆与会聚独立过滤比对、60 张盘结构自洽且会聚非死规则、四种冲法构造验证、摘要/解析/白话/面板四处可见、旧结果兼容、确定性。统计 **78 个测试文件 / 2531 条断言**，七道闸全绿。

## 0.35.1（已并入 0.38.2）

修一个会让整个命理面板白屏的崩溃，并让它以后能自己把错误说出来。

- **崩溃根因**（`src/app.js`）：为了给「问进对话」记住上一张盘，加了一个 `useEffect` 去写 `LAST`，但它落在 `const [result, setResult] = useState(null)` **之前**；React 首渲时读依赖数组撞上 TDZ，抛 `ReferenceError: Cannot access 'result' before initialization`，整个面板渲染失败——桌面端看到的就是「侧栏有『命理』、点开一片空白」。已把该 effect 移到 `result` 声明之后。
- **渲染兜底**（新增 `PanelGuard`，`React.Component` 的错误边界）：面板里任何一层组件抛错时，把错误原文与前 14 行栈直接铺在面板上，并附「__PP / Engine / React / 版本」环境行——不再白屏，也不用开 devtools 才能报错。
- **版本可见**：构建时把 `package.json` 的版本注入 `window.__MP_VER`，侧栏标题显示为「命理 v0.35.1」；`__ModuleLoader__.load` 的模块描述里也带 `version`。以后一眼能确认应用加载的是哪份构建。
- 测试与闸门不变：**76 个测试文件 / 2434 条断言**，七道闸全绿。

## 0.35.0（已并入 0.38.2）

面板可以直接把提问送进对话窗了：排完盘点「问进对话」，这张盘的摘要和你的问题会变成一条正常的用户消息，由对话里的模型接着答。

- **提问模板**（`engine/followup.js` 新增 `askPrompt`）：四段——一句说明（不用重排盘）、`体系 / 所问` 两行、`——盘面摘要——`（取 `compute` 的 `summary`，超 3000 字截断并标「摘要已截断」）、`——回答要求——`（引到具体柱/宫/爻、没依据就说「这盘里看不出来」、不给绝对化断言）。只做文本组装，不调模型、不改盘，返回 `{text, question, system, label, chars, truncated}`。
- **对话桥**（`src/app.js`）：往会话作用域槽位 `conversation.input.right` 注册一个不画界面的组件，从 slot props 取 `inputActions`；点按钮时 `setDraft(text)` 写草稿再 `submit()`，走输入框正常的回车路径——有回合在跑时排队，不打断当前回答。桥没挂上（插件刚装、还没重启，或 Harness 改了槽位名）时退回复制剪贴板并提示，不报错。
- **按钮位置**：结果卡下方的追问行，「追问」（本地按盘面字段直接答）旁边多一个「问进对话」，两者共用同一个问题输入框。
- **离线页不动**：`命理排盘.html` 没有 Harness 对话窗，所以只有「追问」，不出现这个按钮。
- 测试：新增 `test/ask-prompt.test.mjs`（46 条：字段结构、体系名翻译、问题原样带入、摘要截断与占位、六套体系各跑一遍、无绝对化表述、传 null 不抛、确定性）；`test/client-bundle.test.mjs` 增加对话桥注册与「提问 → setDraft → submit」源码通路的断言（现在注册三个槽）。
- 统计：**76 个测试文件 / 2431 条断言**（当时），七道闸全绿。

# 更新记录

版本按「一组可感知的改动」发，README 与市场条目描述随能力同步。

0.23.0–0.33.0 都只提交在本地、没有单独发到 npm；这些内容随 **0.34.0** 一并发布。npm 上的 latest 从 0.22.0 直接跳到 0.34.0，`npm i dsh-metaphysics` 装到的就是这一版。

0.35.0–0.38.1 同样只提交在本地；这些内容随 **0.38.2** 一并发布（2026-10-29），npm 上的 latest 从 0.34.0 直接跳到 0.38.2。

0.39.0–0.46.4 同样只提交在本地；这些内容随 **0.46.5** 一并发布（2026-10-30），npm 上的 latest 从 0.38.2 直接跳到 0.46.5。

0.47.0–0.50.0 同样只提交在本地；这些内容随 **0.50.1** 一并发布（2026-10-30），npm 上的 latest 从 0.46.5 跳到 0.50.1。

## 0.34.0（已发布）

六爻补上**用神旺衰**：月建给这一段时令的气，日辰给当天的扶克。此前用神只算到「落在哪一爻、与卦体怎么对」，旺不旺一律写「仍要月建日辰」，等于把最关键的一半留白。

- **月令五态**：爻五行与月支五行同气为旺、受月令生为相、生月令为休、克月令为囚、被月令克为死（`monthStateOf`）。
- **日辰五关系**：站在爻这一边说——日辰生我为「日生」、克我为「日克」、同气为「比和」，反过来是我泄日辰（「泄」）或我耗日辰（「耗」）（`dayRelationOf`）。
- **三种冲法分开命名**：月建冲爻为**月破**，日辰冲静爻为**暗动**，日辰冲旬空之爻为**冲空**，日辰冲动爻为**逢日辰冲**；不再混成一句「被冲」。
- **月建从哪来**：给了 `datetime`（或 `asOf`）就按节气换月、与八字同源（复用奇门的 `buildSnapshot`）取月支；没给时间就不编月建，只报日辰那一半，摘要里也看不出凭空多出的月份。
- **四处可见**：摘要加「用神旺衰：月建 午（火）　用神月建相 · 用神与日辰比和」；解析「用神落位与卦体」节加「时令对用神」段（逐爻写月建态与日辰关系、冲法）；面板加一排旺衰 chip（旺/相/得日辰生用 ok 色，死/囚/月破/受日辰克/泄/耗用 warn 色）；白话加一句「眼下这阵子对这件事是帮着的/不太帮忙/有帮有压」。
- **口径**：这一层只报状态标签，不折成分数、不断成败；全卦逐爻的旺衰仍未做（现在只算到用神那几爻），化进化退叠上月建日辰后的实际力重也仍未做。
- **知识库**：新增 `liuyao-yongshen-shuai`（variant）讲五态、五关系与三种冲法，note 写明各家对月破/暗动/冲空取法不完全一致。全库 **42 条**。
- **发版工具**：新增 `tools/verify-publish.mjs` 与 `--verify-only` 模式——核对以「tarball 能下载、字节与 registry 记的 shasum 一致、关键文件在包里」为准，因为 npm 会先让版本条目可见、附件晚几分钟才落盘（0.34.0 发布时就撞上过这段空窗，`npm publish` 的成功字样并不作数）。
- **测试**：新增 `test/liuyao-shuai.test.mjs`（52 条）——地支五行 12 支、月令五态与日辰关系各 144 格逐格用另一套写法复算、12 张静卦 × 3 个月建逐爻复算、月破/暗动/冲空/逢日辰冲四种冲法各自构造验证、标签次序、缺月建与缺用神的退化路径、摘要/解析/面板/白话四处可见、旧结果（无 `useGodStrength`）不炸、确定性。统计 **75 个测试文件 / 2379 条断言**（含发布核对工具的 35 条自测）。

## 0.33.0

奇门补上**天盘干的两层**：干对月令的旺衰，以及干与所落宫的生克。此前旺衰只算门与星，干只出现在击刑/入墓这类硬条件里，落宫关系（干与宫谁克谁）完全没说。

- **干宫生克**：新增 `stemPalaceRelation(stem, palace)`（`engine/qimen.js`），只吃「天干五行 + 洛书宫五行」，输出 干克宫 / 宫克干 / 干生宫 / 宫生干 / 比和 五种，附五行与一句说明；与门宫关系（门迫、宫制门）并列，**各说各的、不折成一个分数**，两者同时成立时分别列出。
- **干旺衰**：`STEM_ELEMENT`（甲乙木、丙丁火、戊己土、庚辛金、壬癸水）并入同一套旺相休囚死判定；每宫多 `stemElement` / `stemRelation` / `stemState` 三个字段，中五宫同样有（无门但干与星照算），汇总到 `states.stem`。
- **三处可见**：摘要【旺衰】行改为「门 … 星 … 干 …」；解读「月令旺衰」段加入天盘干一行与「干宫的落宫关系另算：宫克干 9宫辛、2宫癸；干生宫 7宫己…」；面板事实表新增**「干旺衰」「干宫生克」两行**，九宫格每格底部补干宫关系与干旺衰小字。
- **口径**：天盘干只认三奇六仪（甲隐于六仪、盘面不出现），所以干旺衰实际覆盖 9 个符号；干宫生克是「天盘干对地盘宫」，不是天盘干对地盘干的**十干克应**——后者 100 组仍未做（各家措辞不一，需先定底本）。
- **知识库**：`qimen-wangshuai` 扩写为「门、星与天盘干」；新增 `qimen-gan-shengke`（variant）讲干宫五态与「不折分数」，note 写明各家取象宽窄不一、十干克应未做。全库 **41 条**（诸家一致 15 / 各家有异说 25 / 待核实 1）。
- **测试**：新增 `test/qimen-gan.test.mjs`（53 条）——用天干五行与宫五行重推 10 干 × 9 宫 = 90 组全部复算；合成盘验五侧与缺参；扫 60 个真实盘逐宫核 `stemElement` / `stemRelation` / `stemState`（含中五宫），要求 9 个天盘干、五种干宫关系、五种状态都出现（防死表）；`states.stem` 与逐宫一致；三处可见 + 转义；旧结果（无 stemState/stemRelation）不炸；确定性。统计 **73 个测试文件 / 2292 条断言**。

## 0.32.0

八字大运补上**交运时刻（日 / 时辰级）**——此前只有「几岁几月起运」，交运年份在边界处可能差一年内；清单里的 `bazi-dayun-jiaoqi` 从「待核实」转成「各家有异说」。

- **口径**：三日折一年。交运时刻 = 出生时刻 + 「出生 → 起运那一侧节令」的真实天数 × 365.2422/3（≈121.7474）。这一条比例同时兑现古法三条换算——3 日折 1 年、1 日折 4 个月（≈121.75 天）、1 时辰折 10 日（≈10.15 天）；顺排数到下一节、逆排数到上一节。
- **每步大运**：在「同月同日同时刻」换，公历闰日（2 月 29 日交运）十年后退到 2 月 28 日；每步带 `fromDate` / `toDate`，八步首尾相接。
- **结果字段**：`dayun.jiao = { at, jd, scaleDaysPerDay, yearDays, spanDays, from:{name,time}, frame, offsetMinutes, note }`，旧的 `dayun.startAge` 与 `toNextJieDays` 原样保留（向后兼容）；交运时刻与四柱同口径（真太阳时盘上就是真太阳时，`frame` 写明）。
- **三处可见**：摘要「大运：… 起运；交运 1998-08-08 02:51（平太阳时，距芒种 24.7197 天，三日折一年）」；解读「时间窗」节首行给交运时刻与换算说明，大运表新增**「交运」列**；面板运势曲线头部与页脚写交运时刻，大运 chip 的悬停标题带该步交运日期。
- **知识库**：`bazi-dayun-jiaoqi` 由 todo 改写为 variant——讲清放大口径、同月同日同时刻换、闰日退位，并注明各家对「一年折几日」取法不一（本插件固定 365.2422 日，与按 360 日折算的流派会差一两天）。全库仍 40 条（诸家一致 15 / 各家有异说 24 / 待核实 1）。
- **测试**：新增 `test/bazi-jiaoyun.test.mjs`（58 条）——比例与三条换算、用 `partsToJd` 独立复算偏移、顺逆取节令、八步相接与每步 10 年、闰日退位（1987-10-10 盘交运 1988-02-29 → 1998-02-28）、22 个盘的全日期合法性扫描、真太阳时口径、四处可见、旧结果兼容、确定性。`test/report.test.mjs` 的大运表断言改为按表头取列号（加列不再让它失败）。统计 **72 个测试文件 / 2239 条断言**。

## 0.31.0

新增第十九套体系：**十六型人格（mbti）**——一份 MBTI **风格**的 24 题问卷。这不是命理，是用户点名要的「isfp / infp 这种问答判断」；口径上单独写清它**不是官方 MBTI 量表**（题目、计分、常模都是自建的，不与任何商业量表对齐），结果只作自我参照。

- 新模块 `engine/mbti.js`（纯 ESM、零依赖、确定性计算）：`DIMENSIONS`（EI/SN/TF/JP 四维，各带两侧白话与平手侧 I/N/F/P）、`QUESTIONS`（24 题，四维各 6 题，左右交错）、`FUNCTION_STACKS`（16 型 → 四功能码）、`FUNCTIONS`（八种认知功能各一句）、`TYPES`（16 型文案：称号、关键词、一句话、3 条优势、2 条留意、工作/关系/学习/课题）、`mbtiPaper()`（发卷）、`buildMbti({ answers })`（计分）。
- **计分**：每题净分 =（分数 − 3）× 侧向（题目的 `side` 是该题「像我」时的加分侧），维度净分大于 0 取左字母、小于 0 取右字母、= 0 按平手侧取并标「临界」；强度按「净分 / (答数 × 2)」分四档（临界 ≤12%、轻微 ≤30%、明显 ≤60%、很强）。跳过某题传 `null`（也接受 `''`）不计入分母，**至少答 12 题**才出口径；非数组或超过 24 个报 `E_INPUT`，分值不是 1–5 整数报 `E_RANGE`。
- **三处可见**：`compute({ system:'mbti' })` 不给 `answers` 时先返回 24 道题与量表说明；给了就返回类型 + 四维强度 + 认知功能栈 + 工作/关系/学习/课题；摘要分节写【十六型人格】【四维】【优势】【留意】【课题】【认知功能】【工作】【关系】【学习】与末行口径声明。
- **面板与独立页**：侧栏新增「人格」tab（`src/app.js`），独立页新增 `data-tab="mbti"` 与 `#for-mbti` 输入块（`tools/build-html.mjs`），两处都是「24 个分数（1–5，空格或逗号分隔；留空先发问卷）」一个输入框；结果由 `pp.mbtiHTML` 渲染成四维强度条 + 双栏优势/留意 + 认知功能 chips + 四段白话，问卷态则列 24 题清单。tab 从 18 个变 19 个，`test/standalone.test.mjs` 的 tab 清单断言同步。
- **工具 schema**：`system` enum 与描述加入 `mbti`，新增 `answers` 参数（24 个 1–5 整数，可含 `null`）；`locale/en.json` 与 `zh.json` 的体系数从十八/十套速查改为十九/十一套，并点名十六型人格。
- **不进知识库**：十六型人格不属命理体系、也没接解读层（`interpret()` 不处理它），所以 `engine/interpret-knowledge.js` 仍是 40 条；它的口径声明写在结果自身的 `note` 与 README「精度与口径」里。
- 测试 `test/mbti.test.mjs` 63 条：问卷结构（24 题、四维各 6 题、左右两侧题数相同、题号唯一、平手侧齐全）；试卷模式；**四组样例 × 四维独立复算**（另写「左分 − 右分」实现核净分、取值与类型）；强度四档边界；全左=ESTJ、全右=INFP、全 3 分按平手取 INFP；16 型全覆盖且每型文案齐全（3 优势 / 2 留意 / 四场景）、功能栈 4 个合法码；入参校验 8 类；跳题按维度扣减答数、整维跳过标「未作答」；摘要与面板三处可见、转义、旧结果不炸；确定性与「同维同侧换题序不改分」。统计 **71 个测试文件 / 2181 条断言**。

## 0.30.0（待发布）

六爻的**用神落位与卦体联动**：以前解释层只有一句「问工作看官鬼」，并没有真的把用神取出来，所以「用神持世」「用神化退」「用神在六冲卦」这些话都无从对上。现在用神会真的落到某一爻上，再与卦体、动变、旬空串起来看。

- `engine/liuyao.js` 新增 `YONGSHEN_RULES`（七档取用）、`yongshenOf(result, { direction, gender, liuqin })`、`PURE_BY_PALACE`（宫 → 首卦，供伏神取用）、飞伏生克表 `WUXING_SAY`/`RELATION_LABEL`。
- **取用口径**：求财与男命妻缘看妻财、工作职位考核看官鬼、文书合同学历看父母、健康以官鬼为病（子孙为医药）、出行以世爻为用、感情男看妻财女看官鬼；未指明所问之事则不取用神，只给提示，不硬凑。
- **用神不上卦就取伏神**：回到本宫首卦（八纯卦）找同六亲的爻位，列出伏神与飞神，并按五行标出「飞生伏 / 伏生飞 / 飞克伏 / 伏克飞 / 比和」；首卦同一六亲两现时标「伏神两现」，两句都列出来、**不代选**，也不出出伏日期。
- **与卦体联动**：六冲卦（主散）、六合卦（主成）、变六冲、变六合、内外卦伏吟、内外卦反吟（并注明来源是地支全冲还是八卦正对）、用神化进 / 化退、用神旬空、用神持世 / 临应 / 发动。标签始终挂「用神」二字，避免把全卦的动势误当成用神的处境。
- **四处可见**：摘要新增 `用神：官鬼（工作、职位、考核）→ 2爻甲寅木（内卦）` 与 `用神联动：…`；解析在「卦体关系」之后新增「用神落位与卦体」节；面板在卦体 chips 之后加用神 chip 行；白话直答与整段白话各带一句「你问的这件事，在卦里对应第 2 爻」。
- 知识库按实现重写 `liuyao-yongshen`（七档取用，settled）与 `liuyao-fushen`（伏神取法与两现不代选，variant+note），全库 **40 条**（15 诸家一致 / 23 异说 / 2 待核实）。
- 测试 `test/liuyao-yongshen.test.mjs` 54 条：七档取用与感情分男女、出行用世；64 卦 × 5 档取用位置逐一核；伏神用 classics.json 里 **56 条带「缺爻」标注的卦例**对拍（伏神位必须等于本宫首卦同位，且与典籍原录的缺爻一致，100 处命中）；飞伏生克方向独立按五行复算；卦体联动标签两侧都验；旬空两侧都验；摘要/解析/面板/白话四处可见；旧结果（无 `useGod`）不炸。统计 **70 个测试文件 / 2118 条断言**（当时）。

## 0.29.0（待发布）

紫微的**四化飞星串连**：宫干定四化、四化定落宫，再顺着这条化从落宫接着飞下去——把「命宫化忌进父母宫，父母宫又化忌进福德宫」这种逐宫传递，一路跟到它绕回来为止。

- `engine/ziwei.js` 新增 `FLY_TYPES`、`flyStarOf(stem, type)`、`flyStars(chart)`、`flyChain(chart, { from, type, maxSteps })`、`flyChains(chart, { from })`；`buildZiwei()` 结果新增 `fly`（12 宫 × 四化 = 48 条飞化）与 `flyChains`（命宫出发的四支链）。
- **两条口径**：①飞化只认宫干四化表（中州派表，庚干作太阳禄、武曲权、太阴科、天同忌），星落在哪一宫就写哪一宫，落回本宫记**自化**；②串连只跟**同一支化**逐宫跳，最多 12 步，回到走过的宫即记「成环」。因为「一个宫 → 一个宫」是函数映射，完整盘上每条链必然成环——实测链长为 1、3、4、5、6 步。
- **三处可见**：摘要新增 `【命宫飞星】禄：命宫→官禄→父母→命宫（成环）…`；解析在「四化」之后新增「四化飞星」节，逐跳写 `命宫（丙）化忌廉贞→父母`、点出成环与自化，并声明「这一层只描方向与牵引，不断吉凶」；面板在四化 chips 之后加四支飞化 chip（`飞忌 命→父母→福德→财帛→交友→父母↺`，title 给逐跳依据）。白话直答也带一句「这几件事是连着转的」。
- 知识库新增 2 条：`ziwei-feixing`（飞星派 vs 三合派、庚干异说，标 `variant`）、`ziwei-jichuanji`（串连走几跳、借对宫飞化各派不一，本插件走满 12 宫或成环即停，标 `variant`）。
- 测试 `test/ziwei-fly.test.mjs` 42 条：测试内**独立录入**十天干四化表核 40 条；固定盘 48 条飞化的落宫/地支/自化与盘面 `selfHua` 两处互证；四支链逐步核「宫干 → 化星 → 落宫」与首尾相接；换一张盘核 12 宫出发全成环；固定盘回归快照（禄/权/科/忌四条路径逐字）；摘要/解读/白话/面板三处可见；旧结果（缺 `fly`）不炸。统计 **69 个测试文件 / 2064 条断言**。

## 0.28.0（待发布）

离线单文件页 `命理排盘.html` 改为**随 npm 包分发**：之前它只是本地产物（默认写到包目录之外），订阅者装完插件手里并没有这份页面；现在它就在包里。

- `tools/build-html.mjs` 的默认输出从 `path.resolve(root, '..', '命理排盘.html')` 改为 `path.resolve(root, '命理排盘.html')`——写进包根，`--out <路径>` 仍可另存（例如同步桌面那份手边的拷贝）。
- `package.json` 的 `files` 增加 `命理排盘.html`，`exports` 增加 `"./命理排盘.html"`：既会被 npm 发出去，也能用 `require.resolve('dsh-metaphysics/命理排盘.html')` 拿到绝对路径。
- 重新生成一份进包：`node tools/build-html.mjs` → 689907 字符 / 887419 字节（UTF-8），单文件零依赖，十八个 tab 齐全。外部 URL 只有三类：仓库链接、典籍出处链接（点开才联网）、可选的地理编码在线查询。
- **介绍同步**：`README.md` 特性表加「离线单文件页（随包分发）」并新增小节，写明包内路径、`require.resolve` 用法、与面板同源同版本、以及只在这两处会联网；`SUBMIT.md` 与市场条目 `submit/xuanfu-web__dsh-metaphysics.yml` 的 en/zh 描述都补上这一句。
- 测试 `test/standalone.test.mjs` 新增 4 条：`files` 里带离线页、`exports` 能解析、**仓库根那份与 `page()` 逐字相同**（防止改了源码忘了重建、把旧页面发给订阅者）、构建默认目标在包根而不是包外。统计 **68 个测试文件 / 2022 条断言**。

## 0.27.0（待发布）

六爻的「化进神 / 化退神」：动爻变出的地支与本爻同五行、且在顺次上往前一步，这一爻就有后劲；倒着退一步则渐消。

- `engine/liuyao.js` 新增 `jinTuiOf(from, to)`、常量 `JIN_TUI_PAIRS` 与 `JIN_OF`/`TUI_OF` 两张单向表；`bodyRelations()` 返回值新增 `jinTui: [{ position, from, to, type: '进'|'退' }]`。
- **判定口径**：八对顺次——木 寅→卯、火 巳→午、金 申→酉、水 亥→子，土四支成环 丑→辰→未→戌→丑。同五行但不相邻（如寅→辰）不算；同支不变不算；跨五行不算。
- `bodyLabels()` 在爻伏吟 / 爻反吟之后追加「化进神 5、6」「化退神 4」（进在前），面板 / 摘要 / 解读 / 白话读同一份标签。
- **三处可见**：摘要「卦体：」行带化进 / 化退；「解读」的「卦体关系」节逐爻写清本支→变支并声明「同一爻化进，也得看用神旺不旺」；面板 chip 化进用 ok 色、化退用 warn 色。
- 知识库新增 2 条：`liuyao-jintui`（settled，机制与八对表）、`liuyao-jintui-yong`（variant，讲用神化进为得力 / 忌神化进为患加剧，并注明土之进退次序各家不完全一致）。
- 测试新增 `test/liuyao-jintui.test.mjs` 49 条：五行分组独立生成八对进神再与 12×12 全枚举重算比对、12 条语料卦例逐字对拍、静卦与跨五行不硬凑、摘要 / 面板 chip / 旧结果兼容。`test/liuyao-body.test.mjs` 的 23 条对拍改为只核卦体标签（化进 / 化退另由新测试负责）。统计 **68 个测试文件 / 2018 条断言**。

## 0.26.0（当时）

奇门的「月令旺衰」：八门与九星各自对月支五行分旺、相、休、囚、死，回答「这个符号当下有多少气」。

- `engine/qimen.js` 新增 `monthState(element, monthElement)`、`monthElementOf(branch)`、`groupByState(items, monthElement)` 与只读表 `QIMEN_STATE_TABLES`（门/星/月支三张五行表）。
- **判定口径**：与月令同气为旺、月令所生为相、生月令为休、克月令为囚、被月令克为死。以月支五行为尺（寅卯木、巳午火、申酉金、亥子水、辰戌丑未土），八门与九星各用自己的五行去对；月令取四柱月支，与节气月同一口径。
- 排盘结果新增 `month: { branch, element }` 与 `states: { gate: {旺,相,休,囚,死}, star: … }`；每个宫多 `gateState` / `starState`（中五宫只有星的）。
- **三处可见**：摘要多一行「【旺衰】月令 午（火）　门 旺 景门　相 死门/生门 …」；「解读」新增「月令旺衰」节，列出五态归属、五态定义，并声明这一层只说明力量强弱、不折吉凶（门旺而宫克门仍受制）；面板奇门盘下方键值表加「月令」「门旺衰」「星旺衰」三行。
- 知识库新增 2 条（`qimen-wangshuai` 为 settled，`qimen-wangshuai-yong` 标 variant 并写明「按时令/落宫论」的流派差异）。
- 测试新增 `test/qimen-wangshuai.test.mjs` 36 条：三张表与传世说法对拍、五行对月令的组合全部用测试内独立生克表重算、归堆不重不漏、60 个真实盘逐宫核对门/星状态与月令来源、五态在真实盘里都能出现、摘要/解读/面板三处接线、旧结果缺字段不炸。统计 **67 个测试文件 / 1969 条断言**。

## 0.25.0（当时）

奇门的「宫位条件」补齐两块：六仪击刑、三奇入墓——和门迫一样，都是天盘干落到某个宫就成立的硬条件，只作条件、不打分。

- `engine/qimen.js` 新增 `jiXingOf()` / `ruMuOf()` 与只读表 `QIMEN_CONDITION_TABLES`，排盘结果多一个 `conditions: { jiXing, ruMu }`（每项 `{palace, stem, zhi, basis}`）。
- **判定口径**：
  - 击刑按地支相刑定宫：甲子戊震三（子刑卯）、甲戌己坤二（戌刑未）、甲申庚艮八（申刑寅）、甲午辛离九（午自刑）、甲辰壬巽四（辰自刑）、甲寅癸巽四（寅刑巳）。只判天盘六仪，地盘不计。
  - 入墓按五行墓库定宫：乙木墓未（坤二）、丙丁火墓戌（乾六）。只判天盘三奇；六仪、八门、九星的入墓说法不统一，留白。
- **三处可见**：摘要多一行「【宫位条件】击刑 … 入墓 …」；「解读」的「宫位条件」段把门迫/宫制门/击刑/入墓并列，每条带依据（如「甲午辛，午自刑」），并声明不自动等同于用神受制；面板奇门盘下方键值表加「击刑」「入墓」两行。
- 知识库新增 2 条（`qimen-jixing` / `qimen-rumu`，均标 variant 并写明流派差异）。
- 测试新增 `test/qimen-rules.test.mjs` 49 条：表与「地支相刑 → 该支所在宫」的独立推导逐条对拍、合成宫位验成立/不成立两侧、60 个真实盘扫查（六仪与三奇都能触发，防表变死数据；所标之宫与盘中天盘干一致）、摘要/解读/面板三处接线、旧结果缺 `conditions` 不炸。统计 **66 个测试文件 / 1930 条断言**。

## 0.24.0（当时）

六爻多了「卦体」这一层：六冲卦、六合卦、卦伏吟、卦反吟、爻伏吟、爻反吟，全部由纳甲地支实配推导，并用《增删卜易》体例的 23 条带断语卦例逐条对拍。

- `engine/liuyao.js` 新增 `hexBody()` / `bodyRelations()` / `bodyLabels()`：结果里多一个 `body` 字段（`ben` / `bian` 的六冲六合、`fuYin`、`fanYin.by: ['chong'|'pair']`、`yaoFuYin`、`yaoFanYin`），并挂 `body.labels` 供面板与文本共用同一份措辞。
- **判定口径（可复核）**：
  - 六冲卦 = 六爻地支正好配成子午、寅申、辰戌三组对冲。按纳甲实排共 **10 支**：八纯卦 + 天雷无妄 + 雷天大壮（传统只认八纯，故知识条目按 variant 写并注明分歧）。
  - 六合卦 = 配成子丑、寅亥、卯戌、辰酉、巳申、午未三组相合，正好 **8 支**，与传世名单完全吻合；六冲与六合无交集，重支之卦（如雷水解）不判。
  - 卦伏吟 = 变卦某宫三支与本卦对应宫逐位相同，且**卦确实变了**；纳甲上只有乾震共用子寅辰/午申戌，所以只会出在乾↔震互换。
  - 卦反吟 = 地支三爻全冲，或本卦之宫与变卦之宫在后天八卦上正对（乾巽/坎离/艮坤/震兑）；爻伏吟、爻反吟按动爻本支与变支同支/相冲判。
- **三处可见**：摘要末尾「卦体：」一行；「解析与详解」新增「卦体关系」一节（讲聚散、原地、反复，并声明「标签只说明动势，吉凶仍归用神」），整体维度「依据」加一行卦体；面板六爻卡在爻线下方加 chip 行。
- 白话层（直答 / 说人话）各补一句卦体的话；知识库新增 4 条（`liuyao-liuchong` / `liuyao-liuhe` / `liuyao-fanyin` / `liuyao-fuyin`）。
- 测试新增 `test/liuyao-body.test.mjs` 63 条：六合 8 支与传世表对拍、六冲 10 支（含「只认八纯」的差异说明）、伏吟「卦未变不算伏吟」回归、反吟两路分判、23 条卦例逐字对拍；统计 **65 个测试文件 / 1881 条断言**（当时）。

## 0.23.0（未单独发布，并入 0.34.0）

八字结果里多了「古籍原文」：格局、十神喜忌、调候三条线，各引原书一句，并附白话释义与出处。

- 新增 `engine/classics.js`：**19 条**原文摘句——`子平真诠` 10 章（论用神、论用神配气候得失、论正官、论财、论印绶、论食神、论偏官、论伤官、论阳刃、论建禄月劫）+ `滴天髓` 通神论 9 条（寒暖、燥湿、衰旺、中和、官杀、伤官、月令、体用、精神），照录中华典藏网通行本，逐条带章名与 url。
- **匹配规则明确**：先按月令格局取对应十神章（如偏财格 → 论财），再按气候取《滴天髓》寒暖 / 燥湿，再补《论用神配气候得失》，最后以《论用神》兜底；去重后限 4 条，每条写明「为什么取这条」。
- **三处可见**：八字摘要末尾【古籍】四行；「解析与详解」新增「古籍原文」一节；面板八字卡在寒暖/穷通之后新增古籍块（书名·章、原句、白话释义）。
- 口径：原文照录通行本（各本有异文），释义为白话自撰；不把原句改写成结论，也不合并不同流派的说法。
- 测试新增 `test/classic-quotes.test.mjs` 34 条（19 条完整性、10 处原文定值抽检、匹配规则、解释层/摘要/面板接线）；统计 **64 个测试文件 / 1818 条断言**。

## 0.22.0（已发布）

起名不再只是「未收录」三个字：逐字给出五行、判定与可换字。

- 字库 190 → **391 字**（常用名用字为主，按木/火/土/金/水五行分段）：丰（火）、秋（金，秋收成熟）、林（木）这类常见字不再掉「未收录」。
- **逐字判定**：`assessName` 每个字返回五行、释义、性别倾向、来源（`lib` 自建字库 / `user` 你传入的 `charElements` / `none` 未收录）、是否合喜用；未收录的字不猜五行，但会给出**同喜用五行的可换字**（如「秋」不合喜用 → 可换坤（土）、垚（土））。
- **不替用户下判断**：没给生辰时 `favorable` 返回 `null`（不判合不合），结论分「无生辰 / 全未收录 / 全合 / 部分合 / 全不合」五档，并把统计（几个字、几个已知、几个合喜用、字库共几字）写出来。
- **候选去同质化**：`generateNames` 三轮选名（新字 + 新五行组合 → 新字 → 放开）× 字库顺序打散 × 两字异行优先，避免「清一色梓桐」。同一盘 8 个候选示例：李炎梓（火木）、李坤桐（土木）、李楠灿（木火）、李楷垚（木土）、李培炫（土火）、李炜城（火土）、李柏松（木木）、李煜烨（火火）。
- **面板**新增起名卡（`pp.nameHTML`）：逐字大字 + 五行 chip + 来源徽标 + 合/不合喜用 + 可换字、八字与喜用一行、结论；生成卡按「名 + 五行 chips + 释义」逐行排，不再是纯文本块。
- 工具参数新增 `charElements`（`{字: 木|火|土|金|水}`，自定义字五行，未收录字也能参与判定）；`name` 的出生信息允许省 `datetime` 用 `year/month/day`。
- 测试新增 `test/names.test.mjs` 39 条（字库规模与去重、丰秋林逐字判定、未收录字 + 可换字、charElements 生效与非法忽略、无生辰不判、候选全合喜用、面板结构与接线）；统计 **63 个测试文件 / 1784 条断言**。

## 0.21.0（已发布）

《穷通宝鉴》120 格逐条入库：同一「日主 + 月令」该取什么，书上怎么写的，全都摆出来。

- 新增 `engine/qiongtong.js`：十天干 × 十二月令共 120 格，每格含用神顺序（首取在前）、原文摘句、出处章号；
  - 用神顺序据通行整理表（knowyourbazi 整理表，首格为首选），原文摘句照录 [luckclub.cn](https://www.luckclub.cn/bazi/004/)《穷通宝鉴》每章首段（去掉「徐乐吾曰」评注）；
  - 数据里的 `quoteStems` 是「原文首段依次提到的天干」，与整理表首取不同处可对照阅读（如正月庚金：表首取戊，原文先举丙）；
  - 原文全章未见某用神字时（丁酉缺「丙」、癸未缺「壬」）直接写 note「按整理表录入，待以善本核对」，不替它圆场。
- **取用**：调候优先时，寒暖判定定「这一盘缺什么」，穷通宝鉴定「这一格书上取什么」；两者不同向时以调候为先，界面与解释层把两套并列写出，不悄悄合并。
- **评分**：流年天干正落在该格首取时 +0.3，次取 +0.15，理由写明「天干丙正是丑月乙日的首取（穷通宝鉴）」；该干属忌神时不给这笔分。
- **解释层**新增「穷通宝鉴」一节：格（「乙日生于十二月」）+ 用神与首取 + 原文摘句 + 章号；「未纳入」一栏同步改成「已录 120 格，整理表口径、异文处已标 note」。
- **面板**寒暖卡下新增穷通宝鉴块：用神 chips（首取高亮）、原文引句、章号；文本摘要「寒暖：」一行后追加「穷通：十二月乙取丙（首取丙）」。
- 新增 `tools/qiongtong-scrape.mjs`（抓 113 章原文，缓存不入库）与 `tools/qiongtong-build.mjs`（生成 `engine/qiongtong.js`），数据可复现。
- 测试 `test/qiongtong.test.mjs` 31 条：120 格齐全、用神字合法、原文摘句非空、月令月名一致、定值（乙丑取丙、庚寅首取戊/原文先举丙、丁酉与癸未的 note、未知输入返回 null）、1996 寒湿盘接入（detail/评分/解释/面板）。
- 统计：62 个测试文件 / 1745 条断言；client.js 44 模块。

## 0.20.0（已发布）

调候（寒暖燥湿）不再是脚注：从「扶抑为主 + 一句提示」改成「调候优先 + 扶抑校验」的判定层。

- 新增 `engine/tiaohou.js`：按月令基础温度、全局火水比例、湿土燥土给出 **寒 / 寒湿 / 寒燥 / 湿滞 / 平 / 燥 / 燥热 / 温热** 八档气候，附温度与燥湿量化值和依据（如「季冬丑月、火0、水1.8、湿土2处」）；由此定调候所取（寒湿取丙火、燥热取壬水）与所忌。偏寒偏燥明显时判「调候优先」，否则「扶抑为主」。
- **用神仲裁**：调候所需与扶抑喜忌冲突时显式裁决并说明理由（「寒暖失衡时再补强弱也难受」），不冲突时写「两套取法同向，不必取舍」；`method` 字段改成「调候优先 + 扶抑校验」/「扶抑为主 + 调候校验」，读得出来用了哪套。
- **评分接入调候**：流年/大运评分里，调候优先时天干地支合调候所需加权，合所忌扣权，寒局再逢水再扣（「地支子水加重寒湿」）。以 1996-01-19 盘为例：2020 庚子由「平 0.5」改为「忌 −0.8」并写明水助寒湿；2026 丙午「大吉 4.0」写明「寒湿之局得丙火，解冻」。
- **解释层**新增「寒暖燥湿」一节：气候判定 + 体感白话（按日主五行各写一句）+ 调候取忌 + 仲裁；八字文本摘要加「寒暖：」一行。
- **面板**在「用神」下新增寒暖卡：气候标签、调候优先徽标、寒—平—热标尺、调候取/忌/依据、白话叙述；独立页与面板共用。
- 口径：调候由月令与全局寒暖燥湿判定，未逐条录入《穷通宝鉴》120 条；调候与扶抑的优先级各家有争论，界面与文档都写明采用的是「调候优先、扶抑校验」。
- 测试新增 `test/tiaohou.test.mjs`（32 条：寒/热两盘、仲裁同向与冲突、评分方向与上下限、解释节、摘要行、面板卡）；统计 61 个测试文件 / 1714 条断言。

## 0.19.0（已发布）

黄历、择日、公农历互转三处按「吉历」的用法补齐（只吸收合适的那部分，不搬它的小工具）：

- **黄历增强**：值日十二神（黄道/黑道）、十二时辰吉凶（五鼠遁定干支 + 时家十二神，逐时标吉凶）、二十八宿（吉凶/七政/禽/宫）、胎神、财神/喜神/福神/阳贵/阴贵方位、日柱纳音、六合三合吉配生肖；值日神/二十八宿/胎神/吉神方位与 lunar-javascript 逐日对拍（60 天仅交节当日 1 处日界差异，已注明口径）。
- **择日扩充**：事项从 13 类扩到 27 类（领证/提亲/收送聘金/满月酒/交易/投资/签订合同/搬家入宅/装修建造/试车买车/旅行/赴任/访亲友/入学…），面板与独立页按「常用 / 婚嫁 / 生活 / 建造 / 工商」五组下拉归类；打分与冲属相排除口径不变。
- **公农历互转 `convert`**：新增体系。公历 → 农历（农历年月日、闰月、干支四柱、生肖）与农历 → 公历（闰月须显式指定，小月无三十报错），往返自洽；只知道农历生日时可先转公历再排盘。工具层与面板、独立页都已接入。
- 面板与独立页 tab 由 17 个扩到 **18 个**；黄历 tab 有专属卡片（值日徽标、宜忌、四格、吉神方位、十二时辰吉凶网格）。
- 测试新增 `test/tools3.test.mjs`（14 条：黄历新增字段定值、五鼠遁、十二时辰吉凶、公农历往返/闰月/报错、择日分组与冲属相排除、渲染与接线）。

## 0.18.4（已发布）

称骨补上**称骨歌原文**与白话释义（此前只有自撰的分档批语）：

- 新增通行本《称骨歌》52 首（二两一钱 … 七两二钱），`CHENGGU_SONG` 按骨重（钱）索引，原文照录；
  各版本有异文，断句标点统一为「，；，。」
- `buildChenggu` 新增 `song` 字段：`{ text, plain, title, source }`；`plain` 是白话释义（自撰，明确不是原文），
  超出 21–72 钱时给出「未见通行本歌诀」而不是编一首
- 文本摘要把「歌诀」与「释义」分两段；口径里写明歌诀为通行本、释义为白话自撰
- 新增 `PP.chengguHTML`：四项骨重表格 + 合计与分档徽标 + 歌诀（两行竖排大字）+ 释义 + 口径；
  面板与独立页的称骨 tab 改用它（原先落到通用文本块）
- 新增 `test/chenggu.test.mjs`（18 条）：52 档齐全且都是四句、关键档位不串行、白话不是原文、
  summary 两段、渲染器四项与口径、两处界面接线
- 统计：59 个测试文件 / 1668 条断言

## 0.18.3（已发布）

K 线的第二轮打磨（0.18.2 之后的可读性修正）：

- 大运段名从图顶挪到图下的条纹带里，不再和「最高/最低岁」标记抢位置；段名居中，条带随大运交替着色
- 5 年 / 10 年均线在右缘标出末端数值，两条贴太近时自动上下错开
- 纵轴补 0/25/50/75/100 刻度，横轴补「年龄（岁）」与「每岁一分 · 满分 100」；影线用 `clipPath`
  夹在绘图区内，贴边的影线不再溢出
- 新增统计条：全段均值、最好大运、最差大运、波动幅度。旺衰落在换档阈值附近时只给均值与波动，不给
  「最好/最差大运」的顺位
- 图高由 300 提到 322，给刻度与段名条留位
- `test/kline.test.mjs` 增到 29 条（段名条、均线末端值、纵轴刻度、统计条、最好/最差大运）
- 统计：58 个测试文件 / 1650 条断言

## 0.18.2（已发布）

人生 K 线从「等宽文本 + ASCII」升级成真正的蜡烛图，并嵌进八字结果：

- 新增 `PP.trendChart` / `PP.trendHTML`：实体＝该岁相对上一岁的涨跌、影线＝±4 分；叠 5 年 / 10 年均线、
  大运交替底色与分界虚线（段名标顶部）、0–100 固定量程网格、年龄刻度、最高/最低岁标记；悬停看逐年
  「多少岁 / 哪一年 / 什么干支 / 多少分 / 落在哪步大运」。颜色全走 CSS 变量，深浅色与打印跟随
- 「人生K线」tab 不再输出纯文本摘要，直接给图 + 大运分段 chips + 高低年份；数据不足或空值时安全退回文本
- **八字结果底部直接嵌同一张 K 线**（面板与独立页在排八字时顺带算一次 `trend`），与原有的
  「人生运势曲线」（大运阶梯 + 流年折线）并存：曲线看趋势形态，K 线看逐年涨跌
- 新增 `test/kline.test.mjs`（23 条）：结构、坐标不越界、无 NaN、空/单点安全、旺衰边界不出高低结论、
  两处嵌入点都在源码里
- 统计：58 个测试文件 / 1644 条断言

## 0.18.1（已发布）

元数据与检索入口同步，**无运行时行为变化**：

- 把「玄学 / 算命 / 占卜 / 运势」加进 `package.json` 关键词与描述、`locale/*.json`、市场条目描述、README 与工具描述——之前只写「命理排盘」，用户搜「玄学」搜不到；现在搜「玄学」应能命中
- 工具描述补一条触发条件：用户只搜「玄学」或问「有什么玄学工具」时也应介绍本插件
- 排盘逻辑、输出与测试断言不变；仅 UA 随版本号更新（`dsh-metaphysics/0.18.1`）

## 0.18.0（已发布）

吸收同生态另一款命理插件「玄机阁」（dsh-xuanji，MIT）的能力：**按行为规格独立实现，不 vendor 源码、
不引入 iztro / lunar-javascript 依赖**，引擎仍为零外部依赖的纯 ESM。

### 九套速查体系（新增）

每套都有 `engine/*.js` + 工具分支 + 面板/独立页入口 + 测试，口径固定、同日同结果：

- **黄历 almanac**：农历、四柱干支（年柱按立春、月柱按节）、建除十二神、宜忌简表、冲煞与财喜神方位、
  上一/下一节气、每日一卦。与 lunar-javascript 对拍四组日期（日柱/月柱/年柱/农历/建除全一致）；
  唯一差异是交节当日「上一节气」的日界口径（我们按正午判已交节），已记入 `meta.scope`
- **择日 zeri**：13 类事项 × 建除适配打分，逐日分「推荐 / 可用 / 回避」，当事人属相冲煞日直接排除，
  每条回避都带理由；明确是「排序引导」，不是吉凶断语
- **称骨 chenggu**：年/月/日/时四项骨重求和与分档批语。年表按 `(农历年-4)%60` 查 60 甲子，
  月日时各一张表；对拍公开黄历页修正了初版错表（1990-08-15 巳时应为**五两六钱**，不是五两五钱）
- **小六壬 xiaoliuren**：时间起课（农历月/日/时三掐）与报数起课（三个 1–99），六宫吉凶与白话断语
- **星座 star**：太阳星座档案 + 当日四维基调；基调由日期哈希确定性生成，同一天同一星座永远一致，
  明写「不是随机数，也不是模型编的」
- **生命数字 numerology**：生命路径数 / 生日数 / 态度数，11/22/33 主数保留，逐数给数义与课题；
  与八字是两套口径，混问时会说明不可互相印证
- **人生 K 线 trend**：复用八字的旺衰、大运、流年十神，按固定计分表给 1–100 岁逐年分与 K 线形态、
  分大运 ASCII 走势、最佳/最差年份。旺衰恰好落在换档阈值（±0.3）时只给提示、不给顺位结论
- **风水 fengshui**：八宅命卦（1900s/2000s 男女公式、立春界）、大游年四吉四凶、流年九宫飞星
  （2026 一白入中为锚）、24 山门主灶布局倾向、命宅配调停文案；`scope` 明写不含玄空各运盘与现场勘舆
- **起名 name**：评估现有名字或生成候选名；按八字喜用五行（偏强喜克泄耗、偏弱喜生扶）匹配 241 字
  自建字库，未收录的字如实标「未收录」。**不做五格剖象**（需康熙字典笔画）与音韵判断

### 1986–1991 夏令时自动校正

`engine/dst.js`：中国 1986–1991 年夏季行夏令时，钟面时间比标准时快 1 小时。八字/紫微/合盘/验前事/
生时校正/人生 K 线/风水在排盘前统一校正，跨日时回退到前一天 23:xx 并给出 `dst.note`；
`dst: false` 可显式关闭（出生证已是真实太阳口径时用）。修正了「夏令时出生按钟面时间排盘差一个时辰」的口径错误。

### 合婚明细层（hepan 增强）

原有总分与三维度**不动**，新增 `detail`：属相六合/三合/六冲/相害/相刑、天干五合、双向十神、
跨盘地支关系、年命纳音生克、吉凶象计数分档（上 / 中上 / 中 / 需磨合）。冲刑害一律中性叙述，不断「必分」。

### 界面

- 面板与独立页 tab 由 8 个扩到 **17 个**：九套速查体系各有自己的最小输入；速查结果走通用 `pp.quickHTML`
  （等宽文本 + 标题），不套命盘模板
- 八字面板补传 `verifyPast`，验前事区块终于会在面板里出现（此前只有独立页有）
- 独立页「方法页」同步体系清单与已知边界

### 视觉升级三项（沿用本次工作树）

视觉升级三项，均不改计算口径、不新增判断：

- **色板拉开层级**：`--bg` 压深作「桌面」（`#fffdf8 → #f6f1e6`），`--card` 提到近白（`#fffefb → #fffdf8`），
  band / tri / soul / sel / link 一并拉开。`--hair` 随底色同步加深（`#efe9dc → #e9e2d3`），否则比背景还亮、
  发丝线会变成高光。深色块用同一套逻辑（底更沉、卡片更亮）。
  改动前 `--bg` 与 `--card` 只差 1/255，卡片与底色几乎同色，一切「卡片」都浮不起来。
  前景色（ink / muted / red / lu / 十神组）一个未动，对比度、打印样式、可访问性不受影响
- **人生运势曲线**：新增 `pp.curveHTML()`（渲染在八字盘「大运」节内）——大运作阶梯、流年作折线，
  叠在同一坐标系；背景五条档位色带（绿＝吉 / 灰＝平 / 红＝忌），标出全程最高运与最低运，
  今年流年点加粗描边，悬停看逐年「年份（年龄）干支　档位 分值」。
  纯内联 SVG、零依赖，颜色走 CSS 变量，深浅色自动跟随
  - 纵轴固定量程 −2.2 ~ 3.2（引擎实测 score ∈ [−2, 3.2]）：固定而非自适应，不同盘之间才可比
  - 数据不足两步大运则不画（不画半张图）；缺 `luck` 字段、传 null / 空对象均不崩
  - 新增 `test/curve.test.mjs` 36 条：几何不越界、色带无缝、阶梯形态、点与引擎数据对齐、
    刻度不重叠、安全与无障碍、边界不崩
- **三套内联 SVG 符号**（零依赖、零外部请求，一律 `currentColor` 跟随主题）：
  - **爻线**：原先 span + 背景色拼接、靠 `flex gap:18%` 留阴爻间隙，字号一变间隙就飘；
    改为 104×12 内联 SVG，间隙按画布坐标固定（两段各 43 + 间隙 18 = 104）。三种尺寸共用一份几何
  - **动爻标记**：沿用传统老阳 ○ / 老阴 ×，非动爻留同宽空位，六列对齐不抖；爻线列由 112px 放宽到 128px
  - **五行符号**：12×12 描边图标，形状取各元素最易辨识的意象（木＝树 / 火＝焰 / 土＝「土」字骨 /
    金＝菱形 / 水＝波纹），接入五行分类 chip 与用神喜忌行
  - **八卦小象**：14×10 三爻 SVG，接在梅花上下卦标题前；爻位由 `TRI_BITS` 自下而上翻转后渲染
  - 新增 `test/symbols.test.mjs` 79 条：三种尺寸几何、阴爻两段+间隙恰为满宽、八个卦逐爻位校验、
    五条元素路径互不相同、整合到六爻/梅花/八字盘、既有结构回归护栏、无脏值无注入面
  - 全量 57 文件 / 1621 条 PASS（原 1362），`test:ci` 七道闸全绿
  - 新增 `test/tools.test.mjs` 65 条 + `test/tools2.test.mjs` 68 条：黄历对拍、择日排除冲属相、
    称骨四项和、小六壬递推、星座边界、生命数字主数、DST 开关、人生 K 线边界、风水坐向、起名未收录字

## 0.17.1（已发布）

同步更新，**无运行时行为变化**：

- README 与仓库现状对齐：补齐奇门 / 合盘（八套体系）、0.16–0.17 的报告化与可核验能力、安装示例版本
- CI 自检加固：新增 `tools/check-bundle.mjs` 产物自检闸（逐模块编译 client.js、核对与源码一致），`test:ci`
  先构建再检查；`ask.test` 不再读取仓库外的生成物
- 仅 UA 字符串随版本号更新（`dsh-metaphysics/0.17.1`），排盘逻辑与输出不变

## 0.17.0（已发布）

对应「晚子时开关 / 验前事 / 生时校正」三条用户反馈：

- **晚子时开关**：面板与独立页新增「晚子时换日」（八字/紫微/合盘）与奇门「归当日/归次日」；
  之前引擎已支持 `lateZi` / `lateZiHourMode`，但 UI 没有暴露，用户无法自己调
- **验前事**：工具参数 `verifyPast`（年数）+ 面板/独立页「验前事」区块——列出过去若干年的
  流年信号（冲/合/刑、档位、十神），用户自评「准/不准/不确定」，用 `verifyFit` 算贴合度并给建议；
  **只读，不重排、不改盘**；贴合度低时先提示核对出生时间/时区/晚子时
- **生时校正**：`engine/rectify.js` + 工具参数 `rectify`/`events`——对候选时辰逐一排盘，
  按固定规则（事件类别 × 当年十神/关系/档位）打分，返回候选排序与并列说明；
  规则显式可复核，明确「只缩小范围、不替代出生记录」
- 测试：新增 `test/verify.test.mjs` 25 条；全量 53 个文件 / 1362 条 PASS

## 0.16.0（已发布）

报告化改版，对应与 Seeself 对比后的 R1–R8：

- **R1 报告骨架**：解析顶部新增「一页读懂」五条摘要（整体 / 事业 / 财富 / 感情 / 节奏）；
  目录锚点跳转；新增三张表——八字「大运表 / 流年表 / 触发事件表」、紫微「大限表 / 流年表 / 触发事件表」，
  全部由已有引擎字段摊平，不新增判断；打印加 `break-inside:avoid` 与表格换行规则
- **R2 证据卡**：每个维度的「依据」从一行灰字升级为可展开的 `<details>` 证据卡
  （盘面事实 + 技法标签），并给每个维度打「置信度 强/中/弱」（只按证据条数分档，不引新算法）；
  文本输出同步：依据行尾附 `置信度：…`
- **R3 追问模式**：新增 `engine/followup.js` 与工具参数 `ask`——围绕已算好的盘回答
  「某一年 / 某方面」的问题（如「2027 年事业怎么样」），只取盘面已有字段，不重排、不猜测；
  找不到年份/未识别方面时明确说找不到并给出可问范围。面板与独立页都加了追问输入框
- **R4 示例报告**：面板与独立页各加「看示例」，固定示例盘（1990-05-12 14:30 男 石家庄）
  走与真实排盘完全相同的渲染路径，无示例专用分支
- **R5 交叉验证层**：新增 `engine/crosscheck.js` 与工具参数 `cross`——八字 × 紫微对
  事业/财富/感情/身体/节奏五项并列对照，标注「同向 / 有张力 / 互补」；只作对照，不合并数值
- **R6 量化表达**：八字/紫微各加「量化口径」分节——明确量化只到档位（十神权重、宫位计数），
  不换算金额、不给疾病诊断；新增 `test/report-extra.test.mjs` 断言不出现金额区间
- **R7 方法与验证页**：独立页内置静态「方法与验证」（体系、对拍 128 条、测试与闸门、口径、已知边界），
  离线可开
- **R8 导出与分享**：面板与独立页加「导出 .md」（盘面 + 解析 + 交叉验证 + 追问），
  独立页保留打印/存 PDF
- 测试：新增 `test/report.test.mjs` 36 条、`test/report-extra.test.mjs` 31 条；
  全量 52 个文件 / 1335 条 PASS

## 0.15.0（已发布）

- **性能**：节气按需计算、牛顿初值用回归年、容差放宽；八字单盘 2.70ms → 1.60ms
- **口径差异对照**：`engine/diff.js` + `tools/caliber-diff.mjs`，区分根因字段与连带变化
- **白话四层**：直答 / 说人话 / 每维一句话 / 追问建议；术语按体系区分
- **规则知识库**：28 条（出处 + 可信度 + 尚未实现清单）
- **卦例对拍扩容**：《卜筮正宗》从 19 条扩到 **128 条**（93 成对 + 35 静卦），
  新增核对动爻个数、缺爻（伏神）、旬空；排除的 5 条连同理由留在
  `tools/data-boshizhengzong.mjs` 的 `excluded`
- **引擎入参守卫（P0）**：新增 `engine/validate.js` 的 `assertCivil()`，`buildBazi / buildZiwei /
  buildDaliuren / buildQimen / buildHepan / buildZiweiHepan / buildSnapshot` 入口统一校验；
  坏入参从裸 `TypeError` 改为 `E_INPUT`，文案写清「该传什么」（15 类坏输入有契约测试）
  - 统一错误工厂 `engine/fail.js`；梅花的 datetime / 数字起卦错误也改为 `E_INPUT`
- **缓存层统一（P0）**：新增 `engine/lru.js`（上限 + TTL + 命中率），节气瞬时/单年/三年窗口/
  地址四处缓存改为同一工厂；`DSH_METRICS=1` 时 `renderText` 打印各缓存命中率
  （实测紫微盘 `termInstant` 命中 75%）
- **规则表单一真源（P0 收尾）**：`engine/nayin.js`（六十甲子纳音，bazi/ziwei 共用）、
  `engine/sanhe.js`（三合四局 + 单支归属，bazi/hepan/daliuren 共用）；纳甲本就在 `liuyao.js` 一份
  - `test/tables.test.mjs`：纳音 60 项与八字导出逐项一致、三合同局判定与五行等价、
    乾为天纳甲起例，并用静态检查防止有人再把表复制回各模块

## 0.14.3（已发布）

- **经典通例对拍**：新增 `test/fixtures/classics.json` 与 `test/classics.test.mjs`，把典籍里的规则表当作期望值来验实现——
  - 六爻：京房八宫卦序的宫属与世应（八纯上爻、一至五世依次、游魂四爻、归魂三爻），64 卦全表
  - 六壬：日干寄宫（甲寅乙辰丙戊巳丁己未庚申辛戌壬亥癸丑）、中气换将（雨水登明亥将起，12 个中气抽样）
  - 紫微：纳音定五行局、紫微天府以寅申为轴相照
  - 出处与录入方式写在 fixture 的 `meta.sources`，由 `tools/gen-classics-fixture.mjs` 生成，不从引擎输出反推
  - 说明：录入的是**通例表**（规则级），不是某本书的例课原文；例课需要可引用的原文，见 README「对拍」
- **卦象/牌阵类也给出「依据」**：六爻列本卦/变卦、世应爻位与六亲六神、动爻、日辰、卦宫；梅花列本卦/互卦/变卦、体用与生克、动爻；六壬列课体、三传、月将、旬空与青龙/朱雀/六合/天后/白虎/子孙是否出现；塔罗列牌阵与牌位、主轴牌、正逆位计数与元素分布
  - 至此六个有维度的体系（八字/紫微/六爻/梅花/六壬/塔罗）都能核对依据；奇门走分节形态，事实本就写在 section 正文里
- **《增删卜易》卦例对拍**：从 PDF 电子本（有文字层）录入 9 条原文卦例——「月建 + 日干支 + 本卦 → 变卦」，出处精确到章（元神忌神衰旺章第十、月将章第十六、日辰章第十七、独发章第三十一、星煞章第三十三、用神元神忌神仇神章第九）。引擎须按 64 卦表还原这一对（名字、翻爻、变卦生成）
  - 《卜筮正宗》（复城道长精校）此前是**扫描版 PDF、无文字层**；这次拿到同一版本的 **docx**（有文字层），从中提取 138 条带「占事」的卦例，99 条卦名可唯一解析，收 19 条进 `boshizhengzong`
    - 每条核对：本卦 → 变卦、卦宫（宫 + 五行，与八宫表互证）、有日期的样本还核旬空
    - 书中「空亡」与通用旬空不一致的例子（丙辰日作戌亥，应为子丑）只记卦名卦宫、不断言空亡；1 条卦宫与八宫表冲突（表格串行）不收，原因写在 fixture 的 `meta.sources`
  - 原文用字保留异体（遯/遁、干/乾），动爻**不录**——原书卦象图在 PDF 里被压成一行，位置不可靠，硬录等于造数据
- **六爻补旬空**：`buildLiuyao` 现在输出 `xunShou`（旬首）与 `xunKong`（旬空两位），文本摘要多一行「旬首：甲午　旬空：辰巳」；六旬表与「丙辰日空子丑」都有断言
- **双 UI 收口（第一步）**：新增 `src/core.js`，把「爻值解析」「问事体系」「数字输入」三条规则收成单一来源，`app.js` 与 `web-ui.js` 都改为调用 `window.__MPCore`；构建脚本把 core 一并打进 `client.js` 与独立 HTML
  - 单测 `test/core.test.mjs`（21 条）直接加载浏览器文件验证；`ask.test.mjs` 改为检查「单一来源 + 两端委托」
  - 表单编排（参数拼装）仍各留一份，下一步再收
- **修合盘面板**：合盘的主方性别/出生地被漏在 `bazi|ziwei` 分支之外——0.14.1 起引擎把性别改为必填，面板点「合盘」会直接报 `你（主方）的gender 必须是 male 或 female`，看起来像"合盘不对"。现在三体系共用同一分支，合盘四柱与单盘一致（实测 庚午 辛巳 丁丑 丁未 对 庚午 辛巳 丁丑 丁未）
- **奇门进面板**：新增「奇门」tab，起局时刻 + **换局规则**（fieldset + legend + `role="radiogroup"` 的原生 radio：拆补 / 超神接气 / 置闰，附 `details` 说明），`juMethod` 透传给引擎；盘面下新增 `qimenFactsHTML`，用 `dl > div > dt/dd` 列出局数、节气、四柱、值符、值使、旬首、空亡、驿马、换局规则、晚子时——事实与解读区的结论分开，全部走 `esc()`
  - 尚未做（下一步）：三栏 Grid 布局、`<template>` 渲染、显式状态机（idle/missing_input/…）、960/1200 断点的布局断言
- **独立页补齐合盘 / 奇门**：`命理排盘.html` 由六个 tab 变八个
  - 合盘：对方出生日期/时刻/性别/出生地 + 「合盘方式」八字/紫微切换；主方同样带性别与真太阳时，四柱与单盘一致
  - 奇门：换局规则用 `fieldset + legend + role="radiogroup"` 的原生 radio（拆补/超神接气/置闰，附 `details`），加「询问方向（定用神）」；结果 = 九宫盘 + `dl` 事实表 + 分节解读；换规则重起局、换方向只重出解读
  - `build-html` 导出 `page()` 且直接运行时才写盘，`test/standalone.test.mjs` 直接对生成源码做结构断言（24 条）
- **解析深化：把"怎么推出来的"也写出来**
  - 八字 / 紫微新增四段：**看盘顺序**（月令→旺衰→用神→格局→大运→流年/命宫→三方→四化→大限，逐步引用实际值）、**时间窗**（当前与后续大运 + 近五年流年，带档位与理由）、**交叉校验**（喜忌分量对比、大运与流年同向/反向、调候与扶抑是否一致）、**未纳入**（没算什么、哪些流派差异会改变轻重）
  - 六爻 / 六壬补**看卦/看课顺序**（卦宫→世应→动爻→用神→日辰→变卦；月将→四课→三传→课体→神将）与**未纳入**
  - 这些段落全部由盘面数据推出，不新增断语；`test/deep.test.mjs` 41 条断言校验结构、关键步骤与"无占位值"
- 测试：44 个文件 / 1147 条 PASS

## 0.14.2 —— 口径、复现与性能（已发布）

- **1929 年前的节气改用当时的地方时**：`termInstantJd` 与农历共用同一套换算（1929-01-01 前为北京地方平时 UTC+7.7611，之后东八区），并顺手修正切点常量的半天偏移。此前农历切换、节气一律 +8，1929 年前出生者在交节前后约 14 分钟内可能月柱整柱错位
- **晚子时口径统一**：`lateZi`（八字/六壬）与 `lateZiHourMode`（奇门）互为别名，一个概念不再有两个参数名；四套体系的摘要都会写明实际采用的口径（换日 / 不换日）。默认值保持原样（八字/六壬换日、奇门不换日），不偷偷改盘
- **无经度必须告警**：没给出生地/经度时，八字与紫微摘要首行出现 ⚠（此前只在一行括号里提一句，海外出生很容易被忽略）
- **可复现**：塔罗/六爻新增 `seed`（同 seed 同结果，可回放、可对拍）；塔罗 `castAt` 由 `asOf` 决定；八字流年可用 `asOf` 钉死基准年（此前锚在"当前年份"，隔年重算结论就变了）；六爻的日辰（六神起法）也可用 `asOf` 固定，不再随本机日期漂移
- **默认离线**：工具新增 `geocode: 'offline' | 'online'`，默认 `offline`——内置坐标表已到地级市，足够真太阳时；只有显式开启才会把出生地原文发给 Nominatim。地址解析加 6 小时缓存，UA 补上版本与仓库地址
- **性能**：`termInstantJd` / `termWindow` 按年缓存（农历换算一次要问几百次中气，而 VSOP87 是全引擎最贵的一段）
  - 紫微盘 10.9ms → **0.5ms**，奇门 8.1ms → **0.07ms**，八字 2.4ms → **0.4ms**
  - 全量回归 15.8s → **3.3s**
- **无障碍**：结果区补 `role="region"` + `aria-live="polite"`，错误提示 `role="alert"`，通知 `role="status"`
- **工具层**：`geocode` / `seed` 进 schema，`asOf` 说明覆盖紫微/八字/塔罗三个体系；非法 `geocode` 值报 `E_INPUT`
- **CI**：新增 `tools/check-html-sinks.mjs`（innerHTML 拼接必须经过白名单转义函数）与 `tools/check-patterns.mjs`（engine 纯净性、日志、`var`、`debugger`、`new Date()`/`Math.random` 白名单），正/负向都验证过
- **稳定性扫射**：`test/fuzz.test.mjs` —— 用固定种子随机 12 组生日跑遍八个体系，覆盖参数矩阵、边界日期（1600/2400/闰年/1929 切换点）、解析层与"同参数两次结果字节一致"
- **自刑补齐**：辰午酉亥两柱同见判「自刑」，大运/流年支与原局同支也按自刑处理。此前 `buildRelations` 遇到同支直接跳过，四柱里 3 个辰也不会报刑
- **权重口径显式化**：五行占比（1/0.5/0.3）与日主通根（1.2/0.6/0.3）各自命名并注明用途——数值未变，只是不再像"同一件事写了两份"
- **解析加「依据」**：八字与紫微的五个维度各附一行盘面事实（日主旺衰、月令、喜忌、大运流年、宫位主星、煞星），面板渲染 `mp-it-dev`、文本渲染「　依据：…」；卦象类的依据行在 0.14.3 补齐
- **解析失败不再变空壳**：builder 抛错时面板显示「⚠ 解析生成失败」并把原因转义后带出，文本摘要同样标出；此前只返回一个空 dimensions 的对象，用户看到的是"没有解析"
- **结构不变量**：`test/invariants.test.mjs` —— 不依赖外部样盘，用"盘面自身必须成立"的性质守算法：紫微 12 宫支互异/大限连续覆盖、奇门八门八神各一次、六十四卦一一对应、四柱纳音与世应合法。金标准只能覆盖少量样盘，不变量对每张盘都成立
- 测试：39 个文件 / 1011 条 PASS（新增 historical-tz、repro、caliber、tool-geo、fuzz、relations、evidence、invariants 八组）

## 0.14.1 —— 先让「通过」可信

这一版不加新体系，只补三件会静默出错的地基：测试的失败信号、渲染层的转义、入参的拒绝。

- **测试不再假绿**：`test/_harness.mjs` 统一断言，任何一条 FAIL 都让进程非零退出。此前 bazi / calendar / liuyao / lunar / shensha / tarot / ziwei / e2e / layout 九个文件只 `console.log`，断言写错也 exit 0，`npm test` 恒报 27/27
  - `tools/check-assertions.mjs`：每个文件的 PASS 条数锁进 `test/assertion-baseline.json`，删断言即失败（`npm run test:baseline` 显式重建）
  - `tools/verify-tests-can-fail.mjs`：故意写错一条断言，必须变红——保护「测试本身」
- **两处 XSS**：塔罗面板的「所问」与解读段落回显（`src/panel-kit.js`）、独立页错误提示（`src/web-ui.js`）此前把用户原文拼进 `innerHTML`；现改为 `esc()` 与 `textContent`，并加 `test/security.test.mjs` 回归
- **入参校验与错误码**：`compute()` 新增 `E_INPUT / E_RANGE / E_LINES / E_COUNT / E_ASOF / E_PARTNER / E_SYSTEM`
  - 日期按月份天数与闰年校验（`1990-02-30`、`2026-04-31` 不再静默滚到下个月）
  - `bazi / ziwei / hepan` 的 gender 改为必填（缺省按男命排会让大运/大限方向整个反掉）
  - 六爻爻数 ≠ 6 时报错（不再悄悄换成随机卦）；塔罗张数非 1/3/5 时报错；`asOf` 非法时报错（不再静默用「此刻」）
  - 工具层 `execute()` 统一包上 `[错误码]` 前缀，内部异常不再以堆栈式文案直出
- **合盘口径与单盘对齐**：合盘现在把 `address / longitude / trueSolar / lateZi` 分别透传给双方（工具层也会为 `partner.address` 解析经度）。此前合盘完全忽略地址，同一次出生在单盘是 丁丑 日、在合盘里却是 戊寅 日
  - 新增 `test/hepan.test.mjs`：断言「合盘里的你 == 单盘的你」，八字与紫微两条链路都覆盖
- **解析文案修复**：`命局身身强`（level 已含「身」）、`调候上还初夏`（硬拼连接词）、同一段两次「调候上…」、大运与流年档位并成一句导致建议前后矛盾
  - 新增 `test/interpret-copy.test.mjs`：对 8 个体系的实际输出做病句/重复/未定义值扫描
- 测试新增 `test/args.test.mjs`（40 条）、`test/security.test.mjs`（10 条）、`test/hepan.test.mjs`（7 条）、`test/interpret-copy.test.mjs`（63 条），全量 31 个文件 893 条 PASS
- CI 增加「断言数不低于基线」与「测试自检」两步

## 0.14.0 —— 奇门、合盘与节气精度（此前只存在于工作树，本版一并落库）

- 新增**奇门遁甲**（时家转盘：拆补 / 超神接气 / 置闰三派取局、值符值使、九宫、空亡驿马）与对应解读
- 新增**合盘**：八字合盘（日主关系 / 夫妻宫 / 五行互补）与紫微合盘（命宫、夫妻宫、五行局）
- 节气计算改用 **VSOP87B 截断级数 + 岁差 + 章动 + 光行差**，与 NAOJ 历要项对拍偏差降到 1 分钟内
- `parseDateTime` 对 ΔT 覆盖范围（1900–2100）之外的年份给出精度提示，摘要顶部标 ⚠
- `geocodeAddress` 支持地址更细时联网（Nominatim）兜底，失败退回内置坐标表
- 六壬补神煞与格局文案；紫微补流月/流日/流时并接入盘面与解读
- `tools/qimen-divergence.mjs`：枚举三派取局的分裂样本，供排盘差异核对

## 0.13.6

- 修 `npm run release` 的发布后核对：npm 的发布是异步的（PUT 返回 202，registry 生效实测要 1–4 分钟），脚本原来 30 秒就判定失败
  - 改为对 tarball 轮询 HEAD，最多等 6 分钟；超时只提示「已提交，稍后自查」而不报错
  - 顺手核对 `dist-tags`，`latest` 不指向新版本时给出 `npm dist-tag add` 的建议

## 0.13.5

- 新增 `npm run release`（`tools/release.mjs`）：一条命令走完「测试 → 构建 → 校验产物 → 发 npm」，token 只从环境变量 `NPM_TOKEN` 读，临时 `.npmrc` 用后即删
  - 发布前会拦下三种情况：git 工作区不干净、`client.js` 与源码不同步、registry 上已有同版本
  - `-- --dry-run` 只跑到校验；本机没装 npm CLI 时用 `NPM_CLI=/path/to/npm-cli.js` 指定

## 0.13.4

- 新增 `npm run build` / `npm run build:html` / `npm test`：`tools/test-all.mjs` 顺序跑完 20 个测试文件并汇总退出码，省掉手敲一长串 `node test/*.mjs`
- `daliuren` / `meihua` 两处旧测试统一成 `PASS/FAIL` 计数风格（此前只打印 `all pass`，CI 里数不出断言数）
- 补 `CHANGELOG.md`；`engines.node` 声明 `>=18`；SUBMIT 文档补提交状态与阻塞说明
- 新增 GitHub Actions（`.github/workflows/test.yml`）：先构建并校验 `client.js` 与源码一致，再跑全部回归

## 0.13.3

- **工具层打通「解析与详解」**：`compute()` 把 `question` / `direction` 透传给 `interpret()`；工具 schema 新增 `withInterpret`、`direction`（综合/财运/事业/感情/健康/学业/出行）与 `asOf`（流月流日流时的基准时刻）；`renderText()` 在带解析时附上解析正文与免责声明
- 修 `layout` 测试沿用旧类名 `.pn`（0.13.2 已改 `.ft-pn`）导致的假失败
- 未知体系报错改为列出六种体系（原文案仍写着「紫微斗数尚未接入」）
- `package.json` 补 `author` / `repository` / `homepage` / `bugs`；中英文案重写
- 市场条目描述同步到当前能力（主星庙旺、流月流日流时、解析）
- README 注明真太阳时只按经度修正、未含历史时区与夏令时

## 0.13.2

- 叶子类名按语义补前缀（`bz-` / `dt-` / `flow-` / `ft-` / `ct-` / `hb-` / `ss-` / `ask-` 等 192 处），消除泛词类名复用隐患

## 0.13.1

- 修三个潜伏的结构性缺陷：孤立「身」角标残骸、解析详解块调色板失效、320px 下六爻盘横向溢出
- 打印时折叠的详解自动展开；宫格补 `aria-expanded` 同步

## 0.13.0

- 八字四柱表按专业排盘版式重排（四列并排、无竖线、干支大字、十神分组着色、藏干逐行）
- 末行新增五行旺相休囚死；修 `td.big` 选择器长期失效

## 0.12.0

- 紫微补流月 / 流日 / 流时（斗君逐级下推），接入盘面与解读

## 0.11.0

- 深色主题（盘面颜色全变量化）、存为 PDF / 打印、修 390px 下塔罗 tab 被裁

## 0.10.0

- 紫微宫位可点击展开详情、三方四正联动；修「身宫整格消失」的类名撞车

## 0.9.0

- 紫微十四主星加庙旺得利平不陷亮度标注；塔罗面板可选 1/3/5 张牌阵

## 0.8.x

- 0.8.0 起卦 tab 新增「所问之事 + 询问方向」，解读按问题展开；解析区可折叠
- 0.8.1 紫微解读补化科、流年四化不再截断
- 0.8.2 手机竖屏紫微盘恢复 4×4 宫盘
- 0.8.3 竖屏布局改用容器查询，修窄侧栏下盘面挤成一团

## 0.7.0

- 新增「解析与详解」模块：五维度解析、卦象卦辞爻辞动爻、塔罗连贯解读，带免责提示

## 0.6.0

- 六爻 / 梅花 / 六壬面板重绘（真爻线、体用标注、天地盘方盘）；输入区区分出生时间与起卦时刻

## 0.5.0

- 八字 42 神煞（七类、双查法）+ 格局 / 用神 / 大运流年评分
- 紫微 34 格局、大限一览、流年四化
- 塔罗模块重写：78 张牌、牌阵位义、6–8 段解读、体系声明
- 首个进入插件市场投稿流程的版本（awesome-dsh-plugin PR）
