Leo
|
03a2c3d5f8
|
fix(ship): 解開出貨線的兩個自鎖——閘改成量指紋、戳版順序倒過來(arcrun-rag#88)
出貨線從第 5 站 daemon-source-check 就把自己鎖死,push/deploy/verify/
release-record 四站一次都沒執行過。實查真兇是**兩個**,不是一個,而且同源:
D95 第一輪把 `CHANGELOG.md` 搬進 `collector/`(為了讓 collector/ 自足、
有資格獨立成 repo)之後,**「宣告新版本」這個動作本身就是在改 collector/**。
── 自鎖① 出貨線那道閘:用 git 歷史當代理 ────────────────────────────
舊判法=`git log <宣告那顆>..HEAD -- collector` 非空就擋。
⇒ 一顆**只改宣告、一行程式都沒動**的 commit(dcd0132 就是)也被算成
「宣告之後源碼又動過」⇒ 閘擋自己。
⇒ 反過來也不準:collector/ 底下有些檔案(打包腳本旁的 .mjs 工具、README)
根本不會進到執行檔,動了它們一樣被判「要重打包」。
🔴 兩件事都對,疊起來變成死結:**衝突在範圍重疊,不在任何一方做錯。**
修法不是把 changelog 搬回去(那會推翻 D95 第一輪),也不是加路徑白名單
(那就是被禁的字串比對)。改成問**同一件事實**,而那份事實這個 repo 早就在算:
`daemon-version.py` 每次戳版都把「當下的原始碼指紋」記進
`.version-source.json`(2026-08-06 起就存在)。
**版本 X 的指紋 == 現在算出來的 ⇒ X 的成品確實是照這份源碼打的。**
宣告那一步改到的檔案,在戳版當下就已經算進指紋 ⇒ 結構上不可能擋自己;
而「改了 code 卻沒重打包」照樣指紋不同 ⇒ 原本要擋的一個都沒放過。
指紋怎麼算是 daemon 自己的知識,出貨線**不重寫一份**(兩套並存必然漂移):
新增唯讀的 `daemon-version.py --source-state`,`daemon-freshness.mjs` 只負責問與判。
這就是遷移計畫寫的「daemon-freshness 該**搬家**不是加固」。
── 自鎖② 戳版的順序:帳本記的是「還沒戳版」那一刻的樹 ──────────────
`main()` 原本先 `check_or_record()` 再把宣告寫進 changelog。而 changelog 就住在
指紋涵蓋的樹底下 ⇒ 帳本記下來的那棵樹,從寫完宣告那一刻起就不存在了。
實撞(本輪 A/B 重現,見 daemon-version.test.mjs ⑦):
build-mac.sh 戳版打完 dmg → 同一輪 build-win.sh 走「重打同一版」路徑
→ 現在的指紋(含已戳版的 changelog)≠ 帳本裡那個 → dist/ 已有 dmg
→ 判「版號已對應另一份原始碼」→ **第二個平台永遠打不出來**
而上游 `daemon-sync` 兩個平台都要,缺一不准出貨 ⇒ 出貨線在這裡也走不完。
⇒ 先寫宣告、再記指紋。(這條路是升版,帳本不可能已有該版號 ⇒ 不會中途 die。)
🔴 這個病是 D95 第一輪帶進來的:v0.18.29 打包時 changelog 還在 docs-site/,
不在指紋範圍內,所以當時不會發作。
── 為什麼要多一本逐檔帳(.version-source-files.json)────────────────
總指紋只有 16 個字,對不上時只講得出「不一樣」。而紅線要求
「回報通過時要說得出它實際比對了什麼」⇒ 逐檔雜湊讓閘講得出**哪幾個檔**變了。
只留最新一版(閘只問最上面那一版),與總指紋帳本一樣排除在指紋之外(自我參照)。
── 閘要留痕(InkStoneCo#48)────────────────────────────────────────
`installer/daemon-freshness-gate-log.md`:擋下、放行、明知故犯放行,三種都記。
── 順手收進來的一筆(同一輪的複驗項)───────────────────────────────
cherry-pick 89dd323:`checkDocsLive()` 的假綠。實測線上 stage 文件站——
那一頁是舊的(135KB 逐版列表、沒有 dcd0132 的 meta-refresh),卻因為內文
剛好含一次 releases 網址而被 `body.includes()` 判過 ⇒ fails=0。修後 fails=1。
實測
· daemon 0.18.30:Mac dmg 8.3M + Windows exe 22M **同一輪打出來**(修前不可能)
· 閘判決:status=ok,帳本 ad1106716ae426d2 == 現在 ad1106716ae426d2(涵蓋 228 個檔)
· installer 測試 257 支全綠;collector 版本產生器 9 支全綠(新增 ⑦⑧⑨)
· daemon-freshness 自己的演練 15 支:兩個方向各有案例
(不擋自己/仍擋得住沒重打包/問不出來一律停/留痕)
紅線遵守:只碰 stage;沒推 main、沒併分支、沒碰 prod/GitHub。
Refs: inkstone/arcrun-rag#88
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-18 15:39:52 +08:00 |
|
Leo
|
aeb44c712b
|
fix(88): 撤回「產生端吐裸號」的宣稱——那個 v 是版本線判別器,不能單獨拿掉
總管複驗退回一格(`inkstone/arcrun-rag#88#issuecomment-3082`),退得對。
我照他要的兩條路去查,結論是**選 B,而且原本那個改動本身有 bug**。
## 兩件事要分開講
**① 總管的事實宣稱有一處錯,但他看到的現象是真的**
「這條分支一行都沒動 daemon-version.py」— 不對,上一個 commit 動了 37 行,
含 `version = "v%d.%d.%d"` → `"%d.%d.%d"`。他跑 `daemon-version.py` 得到 `v0.18.29`
也是真的:當時的過渡規則讓「重打已發佈的版本」沿用原本寫法。
⇒ 他跑對了指令、看到真東西,只是把原因歸成「沒改」。
**② 但我的改動確實有 bug,而且比他指出的更嚴重**
`^## v` 這條判斷式有**四份各自為政的拷貝**(daemon-freshness/daemon-in-bundle-gate/
ship.mjs daemon-sync/daemon-version.py),三份只認帶 `v` 的。
產生端一旦戳出 `## 0.18.30(…)`,那三份**不會報錯**,而是往下比對到更舊的
`## v0.18.29(…)` ⇒ **打包出 0.18.30 的執行檔,manifest 卻宣稱是 v0.18.29。**
版本號說謊,靜默,21 站全綠。上一個 commit 就埋著這顆。
## 為什麼不是把三份放寬成 `v?`(我試了,當場被測試擋下)
🔴 **那個 `v` 目前身兼「哪一條版本線」的判別器。**
放寬後 daemon 的閘開始把雲端那條 `## 1.4.47(…)` 當成 daemon 版本撈走
⇒ `daemon-in-bundle-gate.test.mjs` ①⑮⑯ 轉紅,而它們釘的正是 D95 第二輪剛修好的
「出貨線指到錯的 changelog 卻安靜放行」。`daemon-notes.changelogRelFor()` 也用 `/^v/`。
⇒ 「不要 v」要落到產生端,得**先給那些閘一個替代判別器**
(建議拿 `DAEMON_LINE` 比對,例 `^## v?0\.18\.\d+(`,同時擋「錯的檔」與「錯的線」)。
那要動 `topReleasedVersion()` 等對外簽章、跨 installer/ 與 collector/,
**與正在進行的 collector 拆 repo 相衝** ⇒ 不在這條分支做。
## 這個 commit 做了什麼
- 產生端**恢復原行為**(一律吐 `v`):不留「產生端裸號+閘只認 v」那顆靜默炸彈
- 四份拷貝**收成一份**(`daemon-notes.DAEMON_RELEASED_RE`,維持嚴格版)
⇒ **零行為變更**,但哪天要改格式只需改一個地方,而不是記得改四個
- 把「為什麼還不能改裸號」釘成一支會說話的測試(`daemon-version.test.mjs` ⑤⑥)
——不是註解,是紅燈
- 兩處註解寫清楚接手要先做什麼
**上一個 commit 的另外兩格(release 掛成品、內外對應)未受影響,總管已複驗通過。**
測試:installer 252/252、collector 6/6。
|
2026-08-18 15:25:22 +08:00 |
|
Leo
|
2e26528bc9
|
feat(version): 對外號真的不帶 v + release 掛得動成品 + 內外對應由機器產生(arcrun-rag#88)
leo 2026-08-18 當場抓到「剛剛不是說不要 v?」——實查確認不是措辭問題:
規約寫在 wiki,而**產生號碼的那條路照舊帶 v**。這輪修的是產地與載體。
① 對外號從**產生端**就是裸的
`daemon-version.py` 是 daemon 那條線唯一的版本產生器,一路長到
產物檔名(Arcrun-<版本>.dmg)、manifest.daemon.version、/api/latest。
- 新戳的版本一律裸號;`RELEASED_RE` 加 `v?` 讀得懂歷史
- 🔴 重打同一版**沿用 changelog 上原本的寫法**:selfupdate.go 的
newerThanCurrent() 是字串不等於就提示更新 ⇒ 把 v0.18.28 改吐成 0.18.28
會讓每台已安裝的機器收到一個內容相同卻宣稱是新版的**假更新**。
規約會自己過期:頂上那段變裸號之後,重打路徑吐的也是裸號。
- 實測:真實 changelog +一段未發佈 → 產生器吐 `0.18.30`(不是 v0.18.30)
② release 掛得動真的成品(本輪的硬前置)
leo:「assets 都寫 source code,這兩個附檔實際是什麼?是 dmg 還是 go?」
——那是 Gitea/GitHub 自動產生的整包 repo 快照。實測既有 release 的
attachment 數是 **0**,坐實那兩個附檔沒有一個是成品。
- gitea/github-release.mjs 各補 uploadReleaseAsset/listReleaseAssets
(兩邊 API 形狀不同是 API 本身的差別,不硬套成同一種)
- release-lines.mjs 讓**每條版本線各自宣告**自己的成品(assetKeys);
daemon 線明列 mac/win/msix,**排除釘在 0.15.7 的兩筆歷史遺留**
——照「有 file 欄就掛」會把舊檔掛上新版頁面,正是本輪要治的病
- ship.mjs 建完 release 後掛檔,並**回頭查證**附件真的在頁面上;
缺任何一個就擋(不留「點下去沒東西」的版本頁)
③ 內外對應由機器產生,不再是總管手寫
leo:「對應關係記在該次發佈的 release note,不靠號碼本身編碼」
- 新增 internal-version.mjs:`RAG-20260818-001-<commit7>`
- 🔴 `formatInternalVersion` 收到空的 artifacts 直接丟例外
⇒ **算不出一個沒有成品的內部號**(leo:「內部每次就要出貨 bundle 的版本」)。
ops-facts 原本記著「這件事目前靠自律,沒有機械閘」——這就是那道閘
- 序號從**既有 release 的事實**算,不養會漂的帳;tag 與內文都掃
(08-17 那兩筆內部號寫在 tag_name 上,只掃內文當天會從 1 重編、無聲撞號)
紅線遵守:既有 tag/檔名一個都沒回頭改;沒寫 GitHub(②③ 實測都在 Gitea);
沒部署、沒推 main、沒自己併分支。演練建的 release 與 tag 都已刪除複驗。
測試:installer 252 支全綠(原 233 +新 19);collector 產生器新增 6 支全綠。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-18 15:13:00 +08:00 |
|