release-skill 0.9.32 → 0.9.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codebuddy-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +2 -2
  4. package/.cursor-plugin/plugin.json +1 -1
  5. package/.kimi-plugin/plugin.json +1 -1
  6. package/.qoder-plugin/plugin.json +1 -1
  7. package/CHANGELOG.md +54 -0
  8. package/INSTALL.md +2 -2
  9. package/INSTALL.zh-CN.md +2 -2
  10. package/README.md +31 -13
  11. package/README.zh-CN.md +17 -13
  12. package/adapters/claude/.claude-plugin/plugin.json +1 -1
  13. package/adapters/claude/bin/release-skill.bundle.mjs +5855 -4045
  14. package/adapters/claude/schemas/.render-manifest.json +8 -4
  15. package/adapters/claude/schemas/release-plan.schema.json +85 -0
  16. package/adapters/claude/schemas/release-project.schema.json +18 -0
  17. package/adapters/claude/schemas/test-intake.schema.json +217 -0
  18. package/adapters/claude/skills/release-assess/SKILL.md +11 -0
  19. package/adapters/claude/skills/release-config/SKILL.md +6 -0
  20. package/adapters/claude/skills/release-help/SKILL.md +20 -4
  21. package/adapters/claude/skills/release-prepare/SKILL.md +11 -2
  22. package/adapters/claude/skills/release-setup/SKILL.md +15 -2
  23. package/adapters/claude/skills/release-verify/SKILL.md +2 -0
  24. package/adapters/codex/.codex-plugin/plugin.json +2 -2
  25. package/adapters/codex/bin/release-skill.bundle.mjs +5855 -4045
  26. package/adapters/codex/schemas/.render-manifest.json +8 -4
  27. package/adapters/codex/schemas/release-plan.schema.json +85 -0
  28. package/adapters/codex/schemas/release-project.schema.json +18 -0
  29. package/adapters/codex/schemas/test-intake.schema.json +217 -0
  30. package/adapters/codex/skills/release-assess/SKILL.md +11 -0
  31. package/adapters/codex/skills/release-config/SKILL.md +6 -0
  32. package/adapters/codex/skills/release-help/SKILL.md +20 -4
  33. package/adapters/codex/skills/release-prepare/SKILL.md +11 -2
  34. package/adapters/codex/skills/release-setup/SKILL.md +15 -2
  35. package/adapters/codex/skills/release-verify/SKILL.md +2 -0
  36. package/adapters/cursor/.cursor-plugin/plugin.json +1 -1
  37. package/adapters/cursor/bin/release-skill.bundle.mjs +5855 -4045
  38. package/adapters/cursor/schemas/.render-manifest.json +8 -4
  39. package/adapters/cursor/schemas/release-plan.schema.json +85 -0
  40. package/adapters/cursor/schemas/release-project.schema.json +18 -0
  41. package/adapters/cursor/schemas/test-intake.schema.json +217 -0
  42. package/adapters/cursor/skills/release-assess/SKILL.md +11 -0
  43. package/adapters/cursor/skills/release-config/SKILL.md +6 -0
  44. package/adapters/cursor/skills/release-help/SKILL.md +20 -4
  45. package/adapters/cursor/skills/release-prepare/SKILL.md +11 -2
  46. package/adapters/cursor/skills/release-setup/SKILL.md +15 -2
  47. package/adapters/cursor/skills/release-verify/SKILL.md +2 -0
  48. package/adapters/kimi/.kimi-plugin/plugin.json +1 -1
  49. package/adapters/kimi/bin/release-skill.bundle.mjs +5855 -4045
  50. package/adapters/kimi/schemas/.render-manifest.json +8 -4
  51. package/adapters/kimi/schemas/release-plan.schema.json +85 -0
  52. package/adapters/kimi/schemas/release-project.schema.json +18 -0
  53. package/adapters/kimi/schemas/test-intake.schema.json +217 -0
  54. package/adapters/kimi/skills/release-assess/SKILL.md +11 -0
  55. package/adapters/kimi/skills/release-config/SKILL.md +6 -0
  56. package/adapters/kimi/skills/release-help/SKILL.md +20 -4
  57. package/adapters/kimi/skills/release-prepare/SKILL.md +11 -2
  58. package/adapters/kimi/skills/release-setup/SKILL.md +15 -2
  59. package/adapters/kimi/skills/release-verify/SKILL.md +2 -0
  60. package/adapters/qoder/.qoder-plugin/plugin.json +1 -1
  61. package/adapters/qoder/bin/release-skill.bundle.mjs +5855 -4045
  62. package/adapters/qoder/schemas/.render-manifest.json +8 -4
  63. package/adapters/qoder/schemas/release-plan.schema.json +85 -0
  64. package/adapters/qoder/schemas/release-project.schema.json +18 -0
  65. package/adapters/qoder/schemas/test-intake.schema.json +217 -0
  66. package/adapters/qoder/skills/release-assess/SKILL.md +11 -0
  67. package/adapters/qoder/skills/release-config/SKILL.md +6 -0
  68. package/adapters/qoder/skills/release-help/SKILL.md +20 -4
  69. package/adapters/qoder/skills/release-prepare/SKILL.md +11 -2
  70. package/adapters/qoder/skills/release-setup/SKILL.md +15 -2
  71. package/adapters/qoder/skills/release-verify/SKILL.md +2 -0
  72. package/adapters/workbuddy/.codebuddy-plugin/plugin.json +1 -1
  73. package/adapters/workbuddy/bin/release-skill.bundle.mjs +5855 -4045
  74. package/adapters/workbuddy/schemas/.render-manifest.json +8 -4
  75. package/adapters/workbuddy/schemas/release-plan.schema.json +85 -0
  76. package/adapters/workbuddy/schemas/release-project.schema.json +18 -0
  77. package/adapters/workbuddy/schemas/test-intake.schema.json +217 -0
  78. package/adapters/workbuddy/skills/release-assess/SKILL.md +11 -0
  79. package/adapters/workbuddy/skills/release-config/SKILL.md +6 -0
  80. package/adapters/workbuddy/skills/release-help/SKILL.md +20 -4
  81. package/adapters/workbuddy/skills/release-prepare/SKILL.md +11 -2
  82. package/adapters/workbuddy/skills/release-setup/SKILL.md +15 -2
  83. package/adapters/workbuddy/skills/release-verify/SKILL.md +2 -0
  84. package/bin/release-skill-cli.mjs +37 -2
  85. package/bin/release-skill.bundle.mjs +5855 -4045
  86. package/package.json +1 -1
  87. package/platform-manifest.json +4 -4
  88. package/references/.render-manifest.json +6 -6
  89. package/references/01-state-machine.md +12 -1
  90. package/references/02-project-config.md +20 -0
  91. package/references/05-evidence-and-errors.md +30 -0
  92. package/schemas/.render-manifest.json +8 -4
  93. package/schemas/release-plan.schema.json +85 -0
  94. package/schemas/release-project.schema.json +18 -0
  95. package/schemas/test-intake.schema.json +217 -0
  96. package/skills/release-assess/SKILL.md +11 -0
  97. package/skills/release-config/SKILL.md +6 -0
  98. package/skills/release-help/SKILL.md +20 -4
  99. package/skills/release-prepare/SKILL.md +11 -2
  100. package/skills/release-setup/SKILL.md +15 -2
  101. package/skills/release-verify/SKILL.md +2 -0
  102. package/skills-src/release-assess/SKILL.md +11 -0
  103. package/skills-src/release-config/SKILL.md +6 -0
  104. package/skills-src/release-help/SKILL.md +20 -4
  105. package/skills-src/release-prepare/SKILL.md +11 -2
  106. package/skills-src/release-setup/SKILL.md +15 -2
  107. package/skills-src/release-verify/SKILL.md +2 -0
  108. package/src/commands/approve.mjs +13 -0
  109. package/src/commands/prepare.mjs +501 -5
  110. package/src/commands/publish.mjs +2 -0
  111. package/src/commands/reconcile.mjs +2 -0
  112. package/src/commands/route.mjs +32 -7
  113. package/src/commands/setup.mjs +13 -6
  114. package/src/commands/ship.mjs +168 -5
  115. package/src/core/config.mjs +5 -0
  116. package/src/core/plan.mjs +3 -1
  117. package/src/core/test-candidate.mjs +649 -0
  118. package/src/core/test-intake.mjs +645 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "release-skill",
3
- "version": "0.9.32",
3
+ "version": "0.9.34",
4
4
  "description": "Safe preparation and frozen GitHub/npm production publishing with full happy end verification",
5
5
  "author": {
6
6
  "name": "广州市风荷科技有限公司"
@@ -2,11 +2,11 @@
2
2
  "schemaVersion": "1.0.0",
3
3
  "platformId": "release-skill",
4
4
  "platformName": "release-skill Plugin Platform",
5
- "version": "0.9.32",
5
+ "version": "0.9.34",
6
6
  "logicalRoot": "skills-src/",
7
- "logicalRootDigest": "a1e30e490fe705ec8c4b1a60597cc30e2d85b136d74100fec0202327333d14d0",
8
- "projectionDigest": "38de97ff9a7e11c1e1b3b50b9ab392dfef5312b05271abc7503a482aeefb210c",
9
- "projectionId": "release-skill:platform:0.9.32",
7
+ "logicalRootDigest": "14d6ec1067ce115107d04fa9165d774d8bea711549e2b3f652601d83f6cdd2ae",
8
+ "projectionDigest": "fce9e9871760b1a6ea47469a463ff1c40502a16197bc24c5fda18c2a9a300e21",
9
+ "projectionId": "release-skill:platform:0.9.34",
10
10
  "manifestRequired": true,
11
11
  "projectionSources": {
12
12
  "skills-src-root": {
@@ -6,12 +6,12 @@
6
6
  "bytes": 6335
7
7
  },
8
8
  "01-state-machine.md": {
9
- "digest": "85e20f4ba60a833325516b9ced9351f9e324cd7b386460d3fb108b79b8875265",
10
- "bytes": 14857
9
+ "digest": "75a34b3e8bcf196e6ccde20717b8f2aba9eb848a2a6a67aa914e5444f82d6b29",
10
+ "bytes": 16742
11
11
  },
12
12
  "02-project-config.md": {
13
- "digest": "50f9b775a4864270642b752d040546f6c365f0b49bf1bfe8a3aacefe88eae702",
14
- "bytes": 26033
13
+ "digest": "f0df7c1c22b8e853fc7cefecc8ee963958b2984ecb94416934674c1b95fdf419",
14
+ "bytes": 33622
15
15
  },
16
16
  "03-readme-quality.md": {
17
17
  "digest": "d74e41052592443ebbd450d0ace5f9b9b19c7a94db50f952b17c1c5a4c5dc230",
@@ -22,8 +22,8 @@
22
22
  "bytes": 4682
23
23
  },
24
24
  "05-evidence-and-errors.md": {
25
- "digest": "f1352256e3b9e2c96c1aa6689fa921a909ab41f80832c5a3356a10590b640929",
26
- "bytes": 12014
25
+ "digest": "90a3e7de1cc3edc6cfb55f03b060158db819fe211c0c7a4af41977466fe7f27b",
26
+ "bytes": 20537
27
27
  },
28
28
  "06-adapter-contract.md": {
29
29
  "digest": "fd58e8a438aaa9a7a4a939ac190dbdd5d11c3fcaca08feaced4a612a6d6dcf3f",
@@ -102,6 +102,14 @@ postPublish hooks 分两个阶段,各自对应独立的 distribute run:
102
102
  外部写入开始后不得缩小范围。任一检查点成功后出现失败,仍进入 PARTIAL,并由
103
103
  `reconcile` 在原冻结计划内向前恢复;延期单元需要另行 prepare、审阅和批准。
104
104
 
105
+ ### 2.4 显式测试接入的同候选续接
106
+
107
+ 声明 `testIntake` 的生产 prepare 不新增状态。首次准备在冻结适用快照和 tarball 后保存一份非正式候选,命令返回 `NEEDS_INPUT`(`GATE_FAILED`,退出码 13)。这一步不写正式计划,不进入 `PREPARED`,也不写 `FROZEN`。
108
+
109
+ 同一候选通过 `prepare --candidate <path>` 续接。适用的预冻结要求核验通过后,才写入正式计划并进入 `PREPARED`。续接使用新的运行目录,不覆盖旧证据,也不再生成第二份候选。对象、配置或权威要求等实质输入变化时拒绝续接,原候选保持不变;只补齐仍绑定该对象的结果不算漂移。
110
+
111
+ 候选不是计划。它不能进入批准或发布,也不能把 `PARTIAL`、`PUBLISHED`、`VERIFIED` 或任何已成功的外部检查点改成完成。`ship` 在接受前保持持久状态 `NEW`,并带上同一个 `testCandidate`。未声明 `testIntake` 的项目仍按原转换进入 `PREPARED`。
112
+
105
113
  ---
106
114
 
107
115
  ## 3. 禁止转换
@@ -141,6 +149,7 @@ postPublish hooks 分两个阶段,各自对应独立的 distribute run:
141
149
  - 系统必须明确列出缺失的输入项、影响范围和可选方案。
142
150
  - NEEDS_INPUT 不能被静默转换为 VERIFIED。
143
151
  - 用户提供输入后,系统从 DISCOVERED 或 ASSESSED 重新开始。
152
+ - 显式测试接入的 `NEEDS_INPUT` 只补齐同一候选的结果。`ship` 保持 `NEW` 与原 `testCandidate`,不重建候选,也不读取正式 `planPath`。结果满足后,同一次续接才进入 `PREPARED`。
144
153
 
145
154
  ### 4.2 BLOCKED 处理
146
155
 
@@ -160,7 +169,7 @@ postPublish hooks 分两个阶段,各自对应独立的 distribute run:
160
169
 
161
170
  批准记录绑定到发布计划 hash。以下任何变化均导致批准自动失效:
162
171
 
163
- - 发布计划绑定层内容变化(plan digest 不匹配)。planVersion 2 的 digest 只绑定信任边界:冻结产物身份(git commit/tree、manifestDigest、npm tarball 摘要)、外部动作列表(不含运行时 status)、目标版本、配置摘要、校验门。
172
+ - 发布计划绑定层内容变化(plan digest 不匹配)。planVersion 2 的 digest 只绑定信任边界:冻结产物身份(git commit/tree、manifestDigest、npm tarball 摘要)、外部动作列表(不含运行时 status)、目标版本、配置摘要、校验门。当前计划版本上的可选 `testAcceptance` 属于绑定层,记录层剥离不移除它。替换结果、准则、范围或允许的限制会改变 plan digest,原批准不再适用。不改变这些原件的注释不会使批准失效。没有 `testAcceptance` 的计划保持原绑定范围。planVersion 1 与未声明该字段的 planVersion 2 摘要含义不变。
164
173
  - 目标版本变化。
165
174
  - 已批准的 action 列表变化。
166
175
 
@@ -170,6 +179,8 @@ postPublish hooks 分两个阶段,各自对应独立的 distribute run:
170
179
 
171
180
  失效后系统回退到 PREPARED 状态,要求重新批准。
172
181
 
182
+ approve、publish 和 reconcile 在任何外部动作前复核 `testAcceptance` 指向的要求文件和结果原件。原件缺失或摘要不符时失败关闭,不重新批准,也不重放已经成功的外部检查点。未带 `testAcceptance` 的计划跳过这项复核。
183
+
173
184
  ### 4.5 路由诊断与当前恢复
174
185
 
175
186
  `route` 负责选择 workflow 和展示 diagnostics,不承担发布授权。传入
@@ -31,6 +31,10 @@ releaseFinish: # 可选;仅控制本地发布收尾
31
31
  sourceBranchCheck: remind # remind(缺省)或 skip
32
32
  setupSkill: <plugin:skill> # 可选;已加载目标插件提供的 setup 入口
33
33
 
34
+ testIntake: # 可选;生产 prepare 才接受。未声明则保持原路径
35
+ requirementsFile: intake/requirements.json
36
+ resultFile: intake/result.json
37
+
34
38
  publicSourceAuthorityReceipt: # 可选;把源码坐标与多个 npm tarball 绑定为公开 Release asset
35
39
  coordinatorUnitId: <release-unit-id>
36
40
  subjectUnitIds: [<release-unit-id>]
@@ -118,6 +122,22 @@ policy: # 可选,安全策略
118
122
 
119
123
  `distributions: []` 表示该发布单元不生成 npm 或插件市场动作,不表示跳过公开发布。
120
124
 
125
+ ### 2.0 显式测试接入
126
+
127
+ `testIntake` 可选。只含两个项目相对普通文件路径:`requirementsFile` 与 `resultFile`。两者归一化后必须不同;`a/./b` 与 `a/b` 视为同一路径。未知字段、绝对路径、`..` 和结尾斜杠在配置加载时拒绝。
128
+
129
+ 未声明 `testIntake` 的项目保持原有 hook、完整门、缓存和发布路径,不因此增加 TEST、Graph 或 Registry 依赖。`--test-selection incremental` 仍在冻结时拒绝。
130
+
131
+ 声明之后只允许生产 `prepare`。非生产 prepare 返回 `CONFIG_INVALID`,原因 `TEST_INTAKE_NON_PRODUCTION`。assess 等其他命令仍可加载这份配置。docs、config、marketplace 轻量工作流、`selectedUnits` 和无需发布的配置分支都不免除项目级要求:未选中单元的单元级要求可以不进入本轮,项目级要求始终适用。
132
+
133
+ 要求文件与结果文件的字段以 `schemas/test-intake.schema.json` 为准。release 只核收原件:预冻结项必须有一条可核验结果,处置为 `executed`、`reused`,或由 owner 确认的 `not-applicable`;结论为 `passed`;`acceptedBy` 与声明的 acceptor 一致,`not-applicable` 时与 owner 一致;引用文件可读且摘要一致;结果里的 `subjectDigest` 与 `requirementsSha256` 绑定当前对象。退出码 0、全局 PASS、空证据、`failed` / `incomplete` / `uncovered`、未知字段,或把后续阶段项提前标成完成,都不能通过。未知失败原因保持 `unknown`。安装、加载和业务证据继续分开保存,不合并成一个类别。
134
+
135
+ 首次生产 prepare 生成适用快照和 tarball 后,只保存一份非正式候选 `.release-skill/runs/<run>/test-candidate.json`,返回 `NEEDS_INPUT`(`GATE_FAILED`,退出码 13),并给出 `candidatePath`、`candidateSha256`、`subjectDigest`。此时不写正式计划,也不进入 `PREPARED` 或 `FROZEN`。之后用 `prepare --candidate <path>` 续接:新的运行目录,不覆盖旧运行目录、旧证据或旧候选。结果补齐并核验通过后才写正式计划。对象、配置、权威要求或其他实质输入变化时返回 `TEST_CANDIDATE_REPREPARE`,原候选字节保持不变。只往结果文件补入仍绑定该对象的有效内容,不算输入漂移。
136
+
137
+ 候选不能传给 approve 或 publish,也不能把 `PARTIAL`、`PUBLISHED`、`VERIFIED` 或任何已成功的外部检查点改成完成。`ship` 在接受前保持持久状态 `NEW` 与 `testCandidate`,不重建候选。没有 `testCandidate` 的 `NEW` 记录仍走原来的准备路径。
138
+
139
+ 正式计划上的可选 `testAcceptance` 进入当前计划版本的绑定摘要,记录层剥离不移除它。替换结果、准则、范围或允许的限制会改变 plan digest,原批准不再适用。不改变这些原件的注释不会使批准失效。没有 `testAcceptance` 的计划保持原摘要路径。approve、publish 和 reconcile 在动作前复核绑定原件;原件缺失或被改写时失败关闭,不重新批准,也不重放已经成功的外部检查点。
140
+
121
141
  ### 2.1 本地发布收尾
122
142
 
123
143
  `releaseFinish` 只控制 `release-finish` 的本地收尾,不改写冻结计划、发布状态或宿主范围。
@@ -34,6 +34,34 @@
34
34
  | `DIRTY_SOURCE_INPUT` | 源码输入闭包存在未提交变化 | `publicFiles.from` 或 `version.source` 有 staged、unstaged、untracked 变化 | 提交或撤销这些具体输入的变化后重新 prepare;无关 dirty 不受影响 |
35
35
  | `BUNDLE_STALE` | bundle 与其源码输入失步(fail-closed 前置门禁) | `bin/release-skill.bundle.mjs` 内嵌的源码摘要与当前 `src/` 摘要不一致,或 bundle/内嵌摘要缺失;在 prepare 加载 config 后的早期阶段检测,任何 workflow 均不可豁免 | 按错误提示在 release-skill 包根运行 `node scripts/build-bundle.mjs`(或 `pnpm build`)重建 bundle 后重新 prepare |
36
36
 
37
+ 显式测试接入不新增顶层错误码。配置和结构问题仍是 `CONFIG_INVALID`(退出码 10),覆盖和续接问题仍是 `GATE_FAILED`(退出码 13)。稳定原因写在 `details.reason`,未知失败保持 `unknown`,不另造原因。
38
+
39
+ | `details.reason` | 错误码 | 含义 |
40
+ |---|---|---|
41
+ | `TEST_INTAKE_NON_PRODUCTION` | `CONFIG_INVALID` | 非生产 prepare 声明了 `testIntake` |
42
+ | `TEST_INTAKE_PATH` | `CONFIG_INVALID` | 接入路径不合法,或两个文件归一化后相同 |
43
+ | `TEST_CANDIDATE_WITHOUT_INTAKE` | `CONFIG_INVALID` | 未声明 `testIntake` 却传入候选路径 |
44
+ | `TEST_CANDIDATE_NOT_PLAN` | `GATE_FAILED` | 把候选文件交给 approve 或 publish |
45
+ | `TEST_INTAKE_NEEDS_INPUT` | `GATE_FAILED` | 候选已保存,预冻结结果尚未接受 |
46
+ | `TEST_REQUIREMENT_MISSING` | `GATE_FAILED` | 结果文件或某条适用要求缺失 |
47
+ | `TEST_EVIDENCE_EMPTY` | `GATE_FAILED` | `executed` 或 `reused` 没有可核验证据 |
48
+ | `TEST_ACCEPTOR_MISMATCH` | `GATE_FAILED` | `acceptedBy` 与 acceptor 或 owner 不一致 |
49
+ | `TEST_RESULT_EARLY_PHASE` | `GATE_FAILED` | 后续阶段项在冻结前被标成完成 |
50
+ | `TEST_SUBJECT_MISMATCH` | `GATE_FAILED` | 结果没有绑定当前对象 |
51
+ | `TEST_REQUIREMENTS_DIGEST_MISMATCH` | `GATE_FAILED` | 结果没有绑定当前要求文件 |
52
+ | `TEST_CANDIDATE_REPREPARE` | `GATE_FAILED` | 候选所绑定的实质输入已变化,须重新准备 |
53
+ | `TEST_CANDIDATE_DIGEST_MISMATCH` | `GATE_FAILED` | 候选字节与 ship 记录或证据摘要不一致 |
54
+ | `TEST_CANDIDATE_EVIDENCE_MISSING` | `GATE_FAILED` | 找不到保存候选时的证据摘要 |
55
+ | `TEST_CANDIDATE_CONFIG_CONFLICT` | `GATE_FAILED` | ship 续接时配置摘要已变化 |
56
+ | `TEST_CANDIDATE_UNIT_CONFLICT` | `GATE_FAILED` | ship 续接时单元选择已变化 |
57
+ | `TEST_ACCEPTANCE_MISSING` | `GATE_FAILED` | 计划绑定的原件缺失 |
58
+ | `TEST_ACCEPTANCE_TAMPERED` | `GATE_FAILED` | 计划绑定的原件与摘要不符 |
59
+ | `TEST_ACCEPTANCE_SUBJECT` | `GATE_FAILED` | `testAcceptance.subjectDigest` 与计划对象不一致 |
60
+ | `TEST_ACCEPTANCE_ROOT` | `GATE_FAILED` | 无法从计划路径确定项目根 |
61
+ | `unknown` | `GATE_FAILED` | 失败、未完成或未覆盖,且没有更具体的稳定原因 |
62
+
63
+ 安装证据、加载证据和业务证据继续按原字段分开保存。测试接入不把它们收成一个全局 PASS 或单一证据类别。
64
+
37
65
  **动作状态码** (adapter execute/observe/verify):
38
66
 
39
67
  - `NO_CHANGE`: 幂等时 payload 无差异,不创建 commit/tag/push。
@@ -205,6 +233,8 @@ v2 的顶层结构封闭(`additionalProperties: false`),只接受 Schema
205
233
 
206
234
  冻结计划存放在 `.release-skill/plans/<planDigest>.json`;批准记录存放在 `.release-skill/approvals/<planDigest>/<approvalDigest>.json`,均不在运行目录内。
207
235
 
236
+ 声明 `testIntake` 时,首次生产 prepare 在该次运行目录写入 `test-candidate.json`。它不是正式计划。证据流用 `phase: test-candidate`、`status: saved` 记录这次保存,候选摘要放在 `details.candidateSha256`。续接另开运行目录,不改写这份候选,也不改写当时的证据。正式计划只在接受之后出现。
237
+
208
238
  ### 5.1 文件保留
209
239
 
210
240
  - 不得手工删除运行证据。生产 prepare 保留 `.release-skill/runs/` 中已有的运行目录,包括封口失败的 prepare 和已经结束的谱系。
@@ -26,16 +26,20 @@
26
26
  "bytes": 1744
27
27
  },
28
28
  "release-plan.schema.json": {
29
- "digest": "3d24cb908cdfbfd5d89551b7c6fed5140f6f1448b9920f114264291ca4cf1c52",
30
- "bytes": 55905
29
+ "digest": "a1e748edeb36b00aa59cbcce893141a30b5c96e75d7fbdbc85b932cde9cc413c",
30
+ "bytes": 68944
31
31
  },
32
32
  "release-project.schema.json": {
33
- "digest": "b0ba3c46692622f734a80d3f4e3904180bbfd1096ca2d9b6d6fd957917e96f73",
34
- "bytes": 47688
33
+ "digest": "e996238c58067fbe1228ab012da53e8edde1b9d3c8f135d4d5848349f4392148",
34
+ "bytes": 57111
35
35
  },
36
36
  "release-run.schema.json": {
37
37
  "digest": "4a041b8f6488e7d61b7eb271ebdbc2e043731df41c4437783ef63e77f664c192",
38
38
  "bytes": 19002
39
+ },
40
+ "test-intake.schema.json": {
41
+ "digest": "654e91ce518cb2b8aca84947d0c3bb8c4262ab047d86081e7e93dc07a9c6c739",
42
+ "bytes": 6982
39
43
  }
40
44
  }
41
45
  }
@@ -1170,6 +1170,9 @@
1170
1170
  }
1171
1171
  }
1172
1172
  },
1173
+ "testAcceptance": {
1174
+ "$ref": "#/definitions/testAcceptance"
1175
+ },
1173
1176
  "createdAt": {
1174
1177
  "type": "string",
1175
1178
  "format": "date-time"
@@ -1371,6 +1374,58 @@
1371
1374
  }
1372
1375
  },
1373
1376
  "definitions": {
1377
+ "testFileRef": {
1378
+ "type": "object",
1379
+ "additionalProperties": false,
1380
+ "required": ["path", "sha256"],
1381
+ "properties": {
1382
+ "path": {
1383
+ "type": "string",
1384
+ "minLength": 1,
1385
+ "pattern": "^(?!/)(?!.*\\\\)(?!.*\\u0000)(?!.*(?:^|/)\\.\\.(?:/|$))(?!.*//)(?!.*/$).+$"
1386
+ },
1387
+ "sha256": {
1388
+ "type": "string",
1389
+ "pattern": "^[a-f0-9]{64}$"
1390
+ },
1391
+ "anchor": {
1392
+ "type": "string",
1393
+ "minLength": 1
1394
+ }
1395
+ }
1396
+ },
1397
+ "testAcceptance": {
1398
+ "type": "object",
1399
+ "description": "Binding-layer acceptance of pre-freeze test requirements. Included in the plan digest. Not a record-layer field.",
1400
+ "additionalProperties": false,
1401
+ "required": [
1402
+ "formatVersion",
1403
+ "subjectDigest",
1404
+ "requirements",
1405
+ "result",
1406
+ "acceptedRequirementIds",
1407
+ "deferredRequirementIds"
1408
+ ],
1409
+ "properties": {
1410
+ "formatVersion": { "const": 1 },
1411
+ "subjectDigest": {
1412
+ "type": "string",
1413
+ "pattern": "^[a-f0-9]{64}$"
1414
+ },
1415
+ "requirements": { "$ref": "#/definitions/testFileRef" },
1416
+ "result": { "$ref": "#/definitions/testFileRef" },
1417
+ "acceptedRequirementIds": {
1418
+ "type": "array",
1419
+ "uniqueItems": true,
1420
+ "items": { "type": "string", "minLength": 1 }
1421
+ },
1422
+ "deferredRequirementIds": {
1423
+ "type": "array",
1424
+ "uniqueItems": true,
1425
+ "items": { "type": "string", "minLength": 1 }
1426
+ }
1427
+ }
1428
+ },
1374
1429
  "verificationGate": {
1375
1430
  "type": "object",
1376
1431
  "required": [
@@ -2221,6 +2276,36 @@
2221
2276
  }
2222
2277
  }
2223
2278
  }
2279
+ },
2280
+ {
2281
+ "if": {
2282
+ "properties": {
2283
+ "production": {
2284
+ "required": ["mode"]
2285
+ }
2286
+ },
2287
+ "required": ["production"]
2288
+ },
2289
+ "then": {
2290
+ "properties": {
2291
+ "units": {
2292
+ "items": {
2293
+ "properties": {
2294
+ "frozenSnapshot": {
2295
+ "required": [
2296
+ "gitObjectDir",
2297
+ "branch",
2298
+ "branchStrategy",
2299
+ "commit",
2300
+ "tree",
2301
+ "commitTimestamp"
2302
+ ]
2303
+ }
2304
+ }
2305
+ }
2306
+ }
2307
+ }
2308
+ }
2224
2309
  }
2225
2310
  ]
2226
2311
  }
@@ -62,6 +62,24 @@
62
62
  }
63
63
  }
64
64
  },
65
+ "testIntake": {
66
+ "type": "object",
67
+ "description": "Optional explicit test intake. When present, both files are required project-relative ordinary paths. Production prepare only. Undeclared projects keep the existing release path.",
68
+ "additionalProperties": false,
69
+ "required": ["requirementsFile", "resultFile"],
70
+ "properties": {
71
+ "requirementsFile": {
72
+ "type": "string",
73
+ "minLength": 1,
74
+ "pattern": "^(?!/)(?!.*\\\\)(?!.*\\u0000)(?!.*(?:^|/)\\.\\.(?:/|$))(?!.*//)(?!.*/$).+$"
75
+ },
76
+ "resultFile": {
77
+ "type": "string",
78
+ "minLength": 1,
79
+ "pattern": "^(?!/)(?!.*\\\\)(?!.*\\u0000)(?!.*(?:^|/)\\.\\.(?:/|$))(?!.*//)(?!.*/$).+$"
80
+ }
81
+ }
82
+ },
65
83
  "publicSourceAuthorityReceipt": {
66
84
  "type": "object",
67
85
  "description": "Optional public source-authority receipt uploaded to one coordinator GitHub Release after all subject npm tarballs are frozen.",
@@ -0,0 +1,217 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://release-skill.dev/schemas/test-intake/v1",
4
+ "title": "Release test intake documents",
5
+ "description": "Requirements, results, candidate, and testAcceptance documents for an explicit testIntake release. Unknown fields are rejected.",
6
+ "$ref": "#/definitions/candidate",
7
+ "definitions": {
8
+ "fileRef": {
9
+ "type": "object",
10
+ "additionalProperties": false,
11
+ "required": ["path", "sha256"],
12
+ "properties": {
13
+ "path": {
14
+ "type": "string",
15
+ "minLength": 1,
16
+ "pattern": "^(?!/)(?!.*\\\\)(?!.*\\u0000)(?!.*(?:^|/)\\.\\.(?:/|$))(?!.*//)(?!.*/$).+$"
17
+ },
18
+ "sha256": {
19
+ "type": "string",
20
+ "pattern": "^[a-f0-9]{64}$"
21
+ },
22
+ "anchor": {
23
+ "type": "string",
24
+ "minLength": 1
25
+ }
26
+ }
27
+ },
28
+ "requirement": {
29
+ "type": "object",
30
+ "additionalProperties": false,
31
+ "required": ["id", "source", "criterion", "owner", "scope", "phase", "acceptor"],
32
+ "properties": {
33
+ "id": { "type": "string", "minLength": 1 },
34
+ "source": { "$ref": "#/definitions/fileRef" },
35
+ "criterion": { "$ref": "#/definitions/fileRef" },
36
+ "owner": { "type": "string", "minLength": 1 },
37
+ "scope": {
38
+ "oneOf": [
39
+ {
40
+ "type": "object",
41
+ "additionalProperties": false,
42
+ "required": ["kind"],
43
+ "properties": { "kind": { "const": "project" } }
44
+ },
45
+ {
46
+ "type": "object",
47
+ "additionalProperties": false,
48
+ "required": ["kind", "unitId"],
49
+ "properties": {
50
+ "kind": { "const": "unit" },
51
+ "unitId": { "type": "string", "minLength": 1 }
52
+ }
53
+ }
54
+ ]
55
+ },
56
+ "phase": {
57
+ "type": "string",
58
+ "enum": ["pre-freeze", "consumer-verify", "postverify", "finish"]
59
+ },
60
+ "acceptor": { "type": "string", "minLength": 1 },
61
+ "handoff": { "$ref": "#/definitions/handoff" }
62
+ },
63
+ "allOf": [
64
+ {
65
+ "if": {
66
+ "properties": { "phase": { "const": "pre-freeze" } },
67
+ "required": ["phase"]
68
+ },
69
+ "then": { "not": { "required": ["handoff"] } }
70
+ },
71
+ {
72
+ "if": {
73
+ "properties": { "phase": { "enum": ["consumer-verify", "postverify", "finish"] } },
74
+ "required": ["phase"]
75
+ },
76
+ "then": { "required": ["handoff"] }
77
+ }
78
+ ]
79
+ },
80
+ "handoff": {
81
+ "type": "object",
82
+ "additionalProperties": false,
83
+ "required": ["kind", "id"],
84
+ "properties": {
85
+ "kind": { "type": "string", "enum": ["gate", "hook", "finish"] },
86
+ "id": { "type": "string", "minLength": 1 }
87
+ }
88
+ },
89
+ "requirementsDocument": {
90
+ "type": "object",
91
+ "additionalProperties": false,
92
+ "required": ["formatVersion", "requirements"],
93
+ "properties": {
94
+ "formatVersion": { "const": 1 },
95
+ "requirements": {
96
+ "type": "array",
97
+ "minItems": 1,
98
+ "items": { "$ref": "#/definitions/requirement" }
99
+ }
100
+ }
101
+ },
102
+ "resultItem": {
103
+ "type": "object",
104
+ "additionalProperties": false,
105
+ "required": [
106
+ "requirementId",
107
+ "disposition",
108
+ "verdict",
109
+ "acceptedBy",
110
+ "decision",
111
+ "evidence",
112
+ "applicability",
113
+ "limitations"
114
+ ],
115
+ "properties": {
116
+ "requirementId": { "type": "string", "minLength": 1 },
117
+ "disposition": {
118
+ "type": "string",
119
+ "enum": ["executed", "reused", "not-applicable", "failed", "incomplete", "uncovered"]
120
+ },
121
+ "verdict": {
122
+ "type": "string",
123
+ "enum": ["passed", "failed", "not-evaluated"]
124
+ },
125
+ "acceptedBy": { "type": "string", "minLength": 1 },
126
+ "decision": { "$ref": "#/definitions/fileRef" },
127
+ "evidence": {
128
+ "type": "array",
129
+ "items": { "$ref": "#/definitions/fileRef" }
130
+ },
131
+ "applicability": { "$ref": "#/definitions/fileRef" },
132
+ "limitations": {
133
+ "type": "array",
134
+ "items": { "$ref": "#/definitions/fileRef" }
135
+ }
136
+ }
137
+ },
138
+ "resultDocument": {
139
+ "type": "object",
140
+ "additionalProperties": false,
141
+ "required": ["formatVersion", "subjectDigest", "requirementsSha256", "results"],
142
+ "properties": {
143
+ "formatVersion": { "const": 1 },
144
+ "subjectDigest": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
145
+ "requirementsSha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
146
+ "results": {
147
+ "type": "array",
148
+ "items": { "$ref": "#/definitions/resultItem" }
149
+ }
150
+ }
151
+ },
152
+ "testAcceptance": {
153
+ "type": "object",
154
+ "additionalProperties": false,
155
+ "required": [
156
+ "formatVersion",
157
+ "subjectDigest",
158
+ "requirements",
159
+ "result",
160
+ "acceptedRequirementIds",
161
+ "deferredRequirementIds"
162
+ ],
163
+ "properties": {
164
+ "formatVersion": { "const": 1 },
165
+ "subjectDigest": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
166
+ "requirements": { "$ref": "#/definitions/fileRef" },
167
+ "result": { "$ref": "#/definitions/fileRef" },
168
+ "acceptedRequirementIds": {
169
+ "type": "array",
170
+ "uniqueItems": true,
171
+ "items": { "type": "string", "minLength": 1 }
172
+ },
173
+ "deferredRequirementIds": {
174
+ "type": "array",
175
+ "uniqueItems": true,
176
+ "items": { "type": "string", "minLength": 1 }
177
+ }
178
+ }
179
+ },
180
+ "candidate": {
181
+ "type": "object",
182
+ "additionalProperties": false,
183
+ "required": ["candidateVersion", "writerVersion", "prepareOptions", "requirements", "prepared"],
184
+ "properties": {
185
+ "candidateVersion": { "const": 1 },
186
+ "writerVersion": { "type": "string", "minLength": 1 },
187
+ "prepareOptions": {
188
+ "type": "object",
189
+ "additionalProperties": false,
190
+ "required": ["workflow", "offline", "production", "unitIds", "unitVersions"],
191
+ "properties": {
192
+ "workflow": { "type": "string", "enum": ["full", "docs", "config", "marketplace"] },
193
+ "offline": { "type": "boolean" },
194
+ "production": { "const": true },
195
+ "unitIds": {
196
+ "type": "array",
197
+ "items": { "type": "string", "minLength": 1 }
198
+ },
199
+ "unitVersions": {
200
+ "type": "object",
201
+ "additionalProperties": { "type": "string", "minLength": 1 }
202
+ }
203
+ }
204
+ },
205
+ "requirements": { "$ref": "#/definitions/fileRef" },
206
+ "prepared": {
207
+ "type": "object",
208
+ "properties": {
209
+ "status": false,
210
+ "digest": false,
211
+ "testAcceptance": false
212
+ }
213
+ }
214
+ }
215
+ }
216
+ }
217
+ }
@@ -19,6 +19,17 @@ description: "Read-only release governance diagnosis: adoption, project readines
19
19
 
20
20
  检查请求结束于结构化结果、实际检查范围、未覆盖项和下一入口,不自动继续 prepare。
21
21
 
22
+ 已配置项目用本技能做增量诊断,不调用 `setup --write` 覆盖。Foundation 建议不是发布批准,也不能替代 `requiredPublicFiles` 或禁路径检查。
23
+
24
+ ## 工程材料角色
25
+
26
+ 只读诊断按现有字段核对四类材料。字段坐标如下:
27
+
28
+ - 正式可公开资源:`releaseUnits[].publicFiles`。`from` 是仓根相对输入路径,`to` 是冻结快照目标路径。接入评估入口 `setup --assess-adoption` 检查 `from` 是否存在,缺失记为 `PUBLIC_FILE_MISSING`。普通 `assess` 与 `verify-records` 不使用该接入评估码。
29
+ - 必需运行文件:`releaseUnits[].requiredPublicFiles` 是字符串快照目标路径,必须被同一单元 `publicFiles[].to` 精确覆盖。接入评估按 `to` 找到对应 `from`,再检查仓根相对输入是否存在;缺失记为 `REQUIRED_PUBLIC_FILE_MISSING`。该码只属于接入评估。后续 `prepare` 仍使用自身原生错误(例如 `PUBLIC_FILE_MISSING`、`CONFIG_INVALID`),不以接入评估码代替。文档完整性缺口(如 `LICENSE_MISSING`)不能代替该角色。覆盖失败由配置加载以 `CONFIG_INVALID` 失败关闭。
30
+ - 私有正式设计、非正式日志与运行记录:不要写入 `publicFiles`。需要挡住时,用 `policy.forbiddenPaths` / `forbiddenContentPatterns`。`forbiddenPaths` 按快照目标路径配置,不能把源目录名直接当作任意重命名后的禁路径。分类文字本身不会机械识别全部私有内容;未列入映射或禁路径的材料,不因这段说明自动排除。后续 prepare 扫描命中禁路径或禁内容时拒绝。
31
+ - `delivery.include/exclude` 只描述宿主选择,不能当作文件包含或排除。排除策略不得覆盖运行必需资源。
32
+
22
33
  ## 只读边界
23
34
 
24
35
  治理诊断只运行 release-skill 自身的只读检查程序,不运行目标 Skill、业务脚本或构建,不执行目标 hook,也不调用 `prepare`、`verify` 或 `release-finish`。请求中即使出现 `smokeBin`、`invoke-setup` 或生产发布线索,也不能据此启动对应动作;这些属于另一个产品动作场景。
@@ -38,6 +38,12 @@ prepare 的真实输出是 plan 内的 `workflowDecision`。
38
38
  - 场景 B:`publishPath === 'publish-needed'`(公开 surface 变化或不可判定)→ 运行
39
39
  轻链 (approve→publish→verify)
40
40
 
41
+ 存量增量只改本轮目标映射。已有合法字段、历史发行记录与精确授权保持不变,不要重建 `.release-skill/project.yaml`。
42
+
43
+ 正式可公开资源写入 `releaseUnits[].publicFiles`:`from` 为仓根相对输入,`to` 为快照目标。必需运行文件写入 `releaseUnits[].requiredPublicFiles`,该项是快照目标路径,必须被同一单元 `publicFiles[].to` 覆盖。私有正式设计与非正式日志不得进入公开映射;需要挡住时,`policy.forbiddenPaths` 按快照目标路径配置,`forbiddenContentPatterns` 按内容扫描。
44
+
45
+ `delivery.include/exclude` 不是文件包含或排除。排除不得覆盖 `requiredPublicFiles`。互相冲突的配置必须失败关闭。Foundation 建议不能作为发布批准。未经精确批准不产生远端动作。分类文字不会机械识别全部私有内容。接入评估缺失码 `REQUIRED_PUBLIC_FILE_MISSING` 不属于本技能的 prepare 路径;config-only prepare 仍走 `release-prepare` 原生错误。
46
+
41
47
  **授权边界**: 命令调用本身即授权执行配置的 hooks/gates。config-only 工作流的远程写操作受标准 approval 机制约束,不 bypass 安全 gate。
42
48
 
43
49
  **阶段通过规则**: