Skip to content

docs(changelog,adr): 给已合入 master 的 breaking 删除补发布级别裁决(二次复审 B1 → 1.7.0) - #129

Merged
dommaker merged 2 commits into
masterfrom
feat/ship-20260909-1716
Sep 9, 2026
Merged

dommaker merged 2 commits into
masterfrom
feat/ship-20260909-1716

Conversation

@dommaker

@dommaker dommaker commented Sep 9, 2026

Copy link
Copy Markdown
Owner

🤖 harness-ship

问题不是代码,是裁决缺口:DynamicTask 删除(b2c7b71)已随 PR #128 进
origin/master,但 CHANGELOG [Unreleased] 为空、ADR-0022 删除清单无此项、最新
tag 仍是 v1.6.0 —— 一个 breaking 变更零记录。harness-ship 的发布级别取自人给的
参数、无 breaking 自动判级,且 [Unreleased] 空时走 commit 清单兜底,下一次发版会
把这个从未被裁决的删除静默发上 npm。前例(A1/A2 + ADR-0022 六项)全部走了人类裁决
并写明代价,B1 是同案第三处却没有这份记录。

级别 = 1.7.0(minor,人类裁决),沿用 ADR-0022 决策 4 与 v1.6.0 裁决段同一判据
(唯一消费者 studio、采纳由 ship-chain 阶段 2 显式 bump),不升 2.0.0。代价再记
一次档:breaking 内容落在 ^1.x 可解析范围内,任何按范围解析的新增安装都会拿到它。

- CHANGELOG [Unreleased]:裁决段(blockquote)+ 变更条目(bullet),使发版走迁移
  路径而非兜底清单。用 changelog_release.py 在临时目录演练 1.7.0 迁移:exit 0、
  首版本头 = 1.7.0、四条实质行守恒、未走兜底(v1.6.0 那条裁决就是被旧迁移逻辑丢弃
  后事后补记的,这次先验再发)
- ADR-0022:新增「追记(二次复审 B1)」节——定级纠正的三层证据(v1.6.0 源
  src/index.ts:106 导出、定义在 types/passes-gate.ts:61、已发布产物
  dist/index.d.ts:38 含包根 export type,1.4.0/1.5.0 产物同样在)、归属判定
  (no_delete_without_context 三分支走完 → 真正无用)、发布级别、防复发口径;
  front-matter 影响版本行标出该例外项不在 1.6.0 车上,避免按 1.6.0 口径核对一个
  尚未发布的删除得出错结论
- 自我纠正两处失实:原写「类型面无冻结闸」过头(A2 后已有已删类型负钉 + 两条活
  类型正钉 PassesGateCheckResult/TaskTestResult),洞的确切位置是「删除之前」那句
  断言无闸可跑;原写「一条正钉」经 grep 核为两条。引用 SHA 逐个 git log 验存在

验收:node bin/harness.js check → 铁律全部通过 (1 条) + skip 1 条
(governance_presence);改动纯文档 2 文件,无代码/测试受影响。
收 ADR-0022 追记第 4 条的口子(上一笔 bf56798 只记了档、没落闸)。洞的确切位置不是
「删完没钉住」,而是删除动作**之前**那句定级断言无闸可跑:本仓 breaking 判据长期挂在
「这个符号在不在包根导出面」上(ADR-0010:5/31、ADR-0019:10、ADR-0022 皆以它定级),
而 public-exports.test.ts 的全量冻结只覆盖包根运行时导出面,类型面自 A2 起只有
「已删类型」负钉 + 两条活类型正钉——钉的都是删完之后。A2 与 B1 已在同一处错两次。

三处判断,都不是照抄现有做法:

1. 公开面按 package.json 的 exports 定义,不只看包根。本包发布五个入口点
   (. / ./core / ./presets / ./context / ./gates),`@dommaker/harness/core` 与包根
   同样是对外承诺。入口清单从 exports 派生而非硬编码,新增子路径未登记冻结清单即红。
   这条口径由 B1 直接逼出:DynamicTask 当时同时经 . 与 ./core 可达(v1.6.0 源
   src/core/index.ts 含它,已发布产物 dist/core/index.d.ts 亦含),只冻包根等于把
   同一个洞的另一半留着。
2. 清单不手抄,来源经产物对撞。五个入口的 src 解析结果与各自 tsc 产物
   (exports[*].types 指向的 .d.ts)逐项比对,152/32/1/12/18 逐字一致。这一步不是仪式:
   它先否掉了我手打的一份假清单(中间断裂、含不存在的 DEFAULT_INjection_config_NEVER、
   还混进 checkConstraint 这类值导出——被 diff 当场抓到),又抓到 src/gates/index.ts
   的 3 个 `export { 值, type X }` 混用说明符被「按块分类」漏计(15 → 真实 18),
   于是清单归类改按说明符自身而非块形式。
3. 本闸刻意不 import 任何入口,因此单独立文件。同案的编译期钉在类型面被改动时会让
   整套 suite「failed to run」(实测注入一条 export type { DynamicTask } 得 0 tests),
   拿不到指名到符号的 diff;本闸在那种改动下必须仍然跑得动。

闸的组成:导出写法白名单(export * / export type * / 入口内联 export interface|type|
enum|class 一律红而非跳过——它们会让按名字扫描静默漏算;内联 export function|const 属
值面放行)+ 逐入口类型清单逐字冻结 + 一条防空跑假绿的长度钉。

反向验闸五种破坏各红一次、suite 均跑得动、diff 指名到入口与符号:包根重新导出
DynamicTask、./gates 删活类型 GateResult、包根注入 export *、入口注入内联
export interface、package.json 新增 ./monitoring 子路径。每次注入后按 sha1 还原现场。

记账:CHANGELOG [Unreleased] 补 test(exports) 条目并把「流程洞记档」改为「已落闸」,
定级纠正段补 ./core 同面证据;ADR-0022 追记第 4 条改写为收口记录、第 5 条记剩余边界
——子路径入口的**值面**仍无对等冻结闸(运行时清单只钉包根 Object.keys,./gates 的 5 个
内联 create*Gate 不被任何清单钉住),同类断言在值面仍无闸可跑,另案。
public-exports.test.ts 文件头的「两道闸」口径同步为三道。

验收(都是新鲜输出):npx jest --runInBand → 151 套件 / 2090 passed / 6 skipped、
退出码 0;两份导出面套件 18 项绿;tsc --noEmit 与 eslint src 零错;
node bin/harness.js check 通过 (1 条)。环境记档:本机 3.6G 内存,并行 worker 版
`npm test` 会被 OOM 杀掉退 143,HEAD 基线同样 143,与本改动无关,故取 runInBand 口径。
@dommaker
dommaker enabled auto-merge September 9, 2026 09:37
@dommaker
dommaker merged commit 259aec5 into master Sep 9, 2026
3 checks passed
@dommaker
dommaker deleted the feat/ship-20260909-1716 branch September 20, 2026 07:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant