Repository navigation
fix(release): publish validated candidates after field repairs - #542
Conversation
taco3064
left a comment
There was a problem hiding this comment.
CHANGES_REQUIRED
只看程式與 #521 發布契約,不看 CI。
這個 PR 本身解掉了「版本 commit 之後不准再有產品修復」這個未來 release cycle 的規則問題,但它 沒有解掉目前 4.1.0 的實際發布問題。而且照現在的 exact-SHA 契約,merge #542 之後反而一定要再做一次 final field convergence。
關鍵不是 release-changeset-gate.mjs 的內容,而是 哪個 commit 會執行這份新 gate。
目前:
已完成完整 field 的候選:
90d2a27c913ca95a29b498e94b90831534a06c92
但 #542 的新 release gate 在:
ae81ad7a487d1ba9632c3e409289e5e83331bd3c
→ merge 後會是另一個新的 main SHA
而 .github/workflows/release.yml 仍是 tag push 後直接 checkout tag target 本身,沒有從 default branch 載入新版 release script。
所以兩條路目前都走不通:
1. tag 仍指向 90d2a27
Release workflow checkout 90d2a27,執行的仍是 90d2 當時舊版:
scripts/release-changeset-gate.mjs
也就是仍會因 version commit 後的 src/ 修復而失敗。
#542 merge 到 main 不會改變 90d2 tag checkout 裡的 script。
2. tag 改指向 #542 merge 後的新 SHA
這時新版 Changesets gate 會生效,但 release-field-gate.mjs 仍要求:
blueprint/field-convergence = success
candidateSha === exact tag SHA
而目前完整 field authority 是 90d2,不是新的 merge SHA。
這個 PR 自己新增的文件甚至明確寫了:
a later commit cannot inherit an earlier candidate's field status, including a commit that changes only release tooling.
因此 merge #542 後若要 tag 新 SHA,依這個 PR 自己的契約就必須:
new main SHA
→ new CI candidate
→ complete field matrix
→ field-convergence success
→ tag
也就是又回到我們正想避免的完整 field 重跑。
為什麼新增的 test 沒抓到這件事
release-changeset-gate.repairs.test.mjs 測的是:
「如果新版 gate 已經存在於 repaired SHA」
→ Changesets gate 可以接受
→ field gate 要求 repaired SHA 自己的 evidence
這個單元模型本身沒錯,但它沒有測到 目前 4.1 的 transition problem:
已驗證 candidate = 90d2
新版 release gate = 後來才出現於另一個 SHA
所以「actual gate invocation succeeds on existing 90d2 history」只是拿 新版 script 去讀 90d2 的 Git history;它不等於 tag 90d2 時 GitHub Actions 會執行新版 script。
要先決定這張 PR 的目標
如果 #542 的目標只是:
修正未來 4.1.x / 4.2 的 release policy,允許 version preparation 後修 product,再對最後 candidate 做 full field
那目前方向基本成立,但它不能拿來解現在 4.1.0 不重跑 field 的發布問題。
發布已經完成 full field 的 90d2 原始候選,不再重跑 16 組
那這個 implementation 還缺一條真正能從新版 main 執行、但只允許發布 90d2 exact artifact 的 recovery path,或另一個同等安全、明確處理「validated SHA 與 release-tool SHA 不同」的機制。
不能用「merge 新 gate → tag 新 SHA」偷偷繞過 exact-SHA field authority,也不能期待 tag 90d2 自動吃到 main 上的新 script。
目前這是 blocker。除此之外,單就「取消 version commit 後 product repair 禁令、改由 exact final field candidate 作 freeze point」這個長期 policy,我沒有看到第二個程式層級問題。
taco3064
left a comment
There was a problem hiding this comment.
CHANGES_REQUIRED
只看程式與 #521 發布契約,不看 CI。
上一輪真正的 blocker 已經解掉:這版新增了可以從新版 main 執行、但只發布舊的 exact validated candidate 的 recovery path,而且沒有把 90d2 的 field status 搬到 tooling SHA。
程式上的 recovery 邊界目前是對的:
workflow_dispatch只允許從refs/heads/main執行;- candidate 必須是成功的 main CI run,且 artifact 唯一、未過期;
- manifest / tarball digest / package identity 都重新驗證;
- candidate 必須是 recovery tooling SHA 的 ancestor;
- 用新版 Changesets / field gate 對 detached 90d2 checkout 驗證;
- existing tag 若存在必須仍解析到 candidate;不存在才在 publish 階段建立;
- publish 使用原始 tgz,不 rebuild、不 repack;
- publish 前再次 reverify;
- exact-SHA field authority 仍留在 90d2,不會繼承到 #542 merge SHA。
我目前沒有再看到上一輪「validated SHA 與 release-tool SHA 不同」的程式層級 blocker。
但現在有一個 decision-fidelity blocker:#521 本身還沒改。
#521 現在仍明寫:
Stage 5:
push tag v4.1.0
→ Release (tag)
Do not manually dispatch this workflow.
The tag push is the trigger and the release workflow is the publisher.
而 #542 現在實作的是:
workflow_dispatch on main
→ publish=false verification
→ owner-authorized publish=true recovery
→ create v4.1.0 at the old converged SHA
→ publish original CI tarball
這兩個契約是直接衝突的。
同時 #521 的 Stage 5 還要求 Changesets gate 驗證:
no disallowed publishable input changed after the release SHA
但 #542 正在刪掉這條 gate,改成「version preparation 只建立版本來源,final field candidate 才是 freeze point」。
所以目前不是 code 還缺什麼,而是 release SSOT 還停在舊規則。
請先把 #521 的發布契約同步到這個 recovery model,至少更新:
- Stage 5 增加 manual recovery publication 例外;
- 移除「Do not manually dispatch this workflow」作為絕對規則;
- Changesets gate 的責任改成 version origin / consumed changesets / changelog / no pending changesets;
- 明確保留 exact candidate field authority,不允許 tooling SHA 繼承;
- Action summary / Publication acceptance criteria 同步 recovery flow;
- 針對這次 4.1 明確寫出:
candidate=90d2a27c...、run=35738770473、先publish=false,review 後才允許publish=true。
等 #521 同步後,我目前從這版程式看不到第二個 blocker。
也就是說,這次不是要再改 recovery code,而是要把已經決定的新發布規則寫回 #521。
taco3064
left a comment
There was a problem hiding this comment.
APPROVED
重新依最新 head c6cc4beb5d4985a2edeb40a5e8b7fef4befacada 與已同步後的 #521 發布契約做 decision-fidelity review。
上一輪 blocker 已收掉。
這版現在把兩個身份切開得正確:
product candidate = 90d2a27c913ca95a29b498e94b90831534a06c92
publisher tooling = #542 merge 後的新 main SHA
而且 recovery path 沒有偷渡 field authority:
- 不把 90d2 的
blueprint/field-convergence複製到 tooling SHA; - 不把 tag 移到 tooling SHA;
- candidate 必須來自成功的 main CI run;
- unique artifact / manifest / package identity / digest 都重新驗證;
- candidate 必須是 tooling SHA 的 ancestor;
- newer Changesets / field gates 對 clean detached candidate checkout 執行;
- existing tag 若存在必須解析回 candidate;
- publish 使用原 CI tgz,不 rebuild、不 repack;
- publish 前再次 reverify;
- recovery provenance 明確區分 candidate/run/artifact 與實際 publisher tooling/workflow run;
- verification-only 與真正 publish 分成
publish=false/ owner-authorizedpublish=true兩階段。
#521 也已同步 recovery publication 例外、Changesets gate 新責任,以及本次 4.1 的 exact recovery identity:
candidate_sha = 90d2a27c913ca95a29b498e94b90831534a06c92
candidate_run_id = 35738770473
tag = v4.1.0
artifact SHA-256 = 9b8a1b84a499d57775883c4b261391a7d60d565a97cd7c8965b2e0604fc64023
另外我把 #521 Stage 2 殘留的「main 一變,舊 candidate 一律失效」修成只針對 product/source/package input change;release-tooling-only commit 現在和 recovery model 一致,不再自相矛盾。
只看程式與發布契約,不看 CI。目前沒有剩餘 blocker。
下一個正確流程是:
merge #542
→ main 上跑 recovery publish=false
→ review verification run
→ owner 明確授權
→ 用相同 candidate/run/tag inputs 跑 publish=true
→ 驗 npm + GitHub Release
不需要因為 #542 的 tooling SHA 變更而重跑 16 組 field。
Problem and resulting behavior
Field repairs necessarily happen after version preparation. The old Changesets gate rejected those repairs even after the final exact candidate passed CI and full field convergence. Removing that restriction fixes future release cycles, but tagging the already validated 90d2 candidate would still execute its old gate.
This PR fixes both boundaries. Changesets validation retains version origin, consumed changesets, matching release notes, and no pending changesets, while the exact-candidate field gate remains authoritative for readiness. The existing release.yml also gains a main-only workflow_dispatch recovery job so newer release tooling can verify and publish an older validated candidate. No second workflow is added.
Recovery behavior
For #521, after this PR is merged and reviewed, use release.yml from main with candidate_sha=90d2a27c913ca95a29b498e94b90831534a06c92, candidate_run_id=35738770473, tag=v4.1.0, publish=false. Review that verification run before an owner-authorized publish=true invocation. The candidate remains 90d2, not this PR's merge SHA, so no field evidence is inherited by the tooling commit.
Verification and boundaries
Part of #521. Supersedes its earlier post-version product freeze and tag-only execution restriction under the owner's revised process decision. The failed v4.1.0 tag has been removed; this PR does not recreate it, merge itself, publish, or close #521.