更新完就看不到版本號了——CLI 那條路會把版本標籤洗掉 #106

Open
opened 2026-08-12 13:21:50 +00:00 by Leo · 1 comment
Owner

症狀(leo 2026-08-12 實撞)

leo 更新完 leo21c 後打開 Portal 設定頁,「版本」欄位顯示:

無法讀取目前版本(知識庫服務可能正在啟動)

🔴 這踩到 leo 自己立的那條:「版本號是我唯一的驗收介面」——
更新完之後他反而看不出自己跑的是哪一版。

實測對照(同一分鐘)

leo21c   cypher /health → {"ok":true,"auth_store":{...},"mail_relay_configured":...}
                          ↑ 沒有 bundle_version 欄位
geek6688 cypher /health → bundle_version: "1.4.29"

諷刺的是 geek6688 是舊版卻有,leo21c 剛更新反而沒有。

根因

cypher-executor/src/routes/health.ts:22

...(bundleVersion ? { bundle_version: bundleVersion } : {}),

⇒ 欄位來自 ARCRUN_BUNDLE_VERSION(部署時注入的 plain_text var)沒注入就整個欄位消失

而它是誰注入的:

路徑 有沒有注入 ARCRUN_BUNDLE_VERSION
安裝器arcrun-rag installer/oauth-prototype/worker.js:1194
CLI 更新那條cli/src/commands/update.ts 整個 repo 的 cli/src 裡搜不到這個字串

用安裝器裝的實例有版本號;用 CLI 更新過的實例會被洗掉
(重部署 worker 會換掉 bindings,而 CLI 不知道要把這個 var 補回去)。

為什麼 Arcrun#97 的修法沒接住

#97 的「已部署的 worker 綁著什麼就是什麼」確實在 CLI 更新那條路上生效——
它的實際輸出是「沿用你既有的 12 個資源」(KV/D1/Vectorize/service binding)。

🔴 但它只保留「資源類」綁定,沒有保留 plain_text vars。
⇒ 同一個病的另一面:保留了櫃子,沒保留櫃子上的標籤。

影響面比「畫面難看」大

health.ts:8 的註解自己寫著:

daemon cloudVersionStale()/healthbundle_version 判斷是否過舊

欄位消失時 daemon 拿到空字串,會判成 stale ⇒ 可能一直提示使用者「雲端太舊」,
或反覆嘗試更新。這是一個會自我維持的迴圈:更新 → 版本欄消失 → 判 stale → 再提示更新。

要達成什麼

用任何一條路更新完,Portal 都看得到正確版本號,daemon 也判得對。

不指定做法。但有一個明顯的方向值得先評估:
CLI 已經會「讀已部署 worker 的綁定並沿用」,plain_text vars 一併納入沿用範圍
似乎比「叫 CLI 自己算版本號」更貼近 #97 已經在做的事——
這是我這個外部觀察,請自己判斷(我不是這條路的專家)。

怎麼驗才算數

  1. 在一台已安裝的實例上跑 CLI 更新,跑完 curl <cypher>/health 要有 bundle_version
  2. Portal 設定頁實際打開看,版本欄顯示的是正確版號(不是「無法讀取」)——
    curl 不算,那是 leo 唯一的驗收介面
  3. daemon 的 cloudVersionStale() 在更新後不再誤判 stale
  4. 回歸:用安裝器裝的路徑仍然有版本號(不能修了 A 弄壞 B)

紅線

  • 🔴 不准部署到 leo21c(leo 唯一一份知識庫的實例,要他親手解閘)
  • 🔴 不准為了讓版本欄有東西就在前端寫死或猜一個版本——寧可誠實顯示讀不到
  • 🔴 不准推 main

📍 repo:matrix/arcruncli/src/commands/update.tscypher-executor/src/routes/health.ts
products/arcrun-raginstaller/oauth-prototype/worker.js:1194 是目前唯一會注入的地方)
📍 相關:Arcrun#97(保留綁定,只保留資源類)|Arcrun#95(畫面說已是最新但引擎是舊的)

## 症狀(leo 2026-08-12 實撞) leo 更新完 leo21c 後打開 Portal 設定頁,「版本」欄位顯示: > **無法讀取目前版本(知識庫服務可能正在啟動)** 🔴 **這踩到 leo 自己立的那條**:「**版本號是我唯一的驗收介面**」—— 更新完之後他反而看不出自己跑的是哪一版。 ## 實測對照(同一分鐘) ``` leo21c cypher /health → {"ok":true,"auth_store":{...},"mail_relay_configured":...} ↑ 沒有 bundle_version 欄位 geek6688 cypher /health → bundle_version: "1.4.29" ``` **諷刺的是 geek6688 是舊版卻有,leo21c 剛更新反而沒有。** ## 根因 `cypher-executor/src/routes/health.ts:22`: ```ts ...(bundleVersion ? { bundle_version: bundleVersion } : {}), ``` ⇒ 欄位來自 **`ARCRUN_BUNDLE_VERSION`(部署時注入的 plain_text var)**,**沒注入就整個欄位消失**。 而它是誰注入的: | 路徑 | 有沒有注入 `ARCRUN_BUNDLE_VERSION` | |---|---| | **安裝器**(`arcrun-rag` `installer/oauth-prototype/worker.js:1194`) | ✅ 有 | | **CLI 更新那條**(`cli/src/commands/update.ts`) | ❌ **整個 repo 的 cli/src 裡搜不到這個字串** | ⇒ **用安裝器裝的實例有版本號;用 CLI 更新過的實例會被洗掉** (重部署 worker 會換掉 bindings,而 CLI 不知道要把這個 var 補回去)。 ## 為什麼 `Arcrun#97` 的修法沒接住 `#97` 的「已部署的 worker 綁著什麼就是什麼」確實在 CLI 更新那條路上生效—— 它的實際輸出是「**沿用你既有的 12 個資源**」(KV/D1/Vectorize/service binding)。 🔴 **但它只保留「資源類」綁定,沒有保留 `plain_text` vars。** ⇒ 同一個病的另一面:**保留了櫃子,沒保留櫃子上的標籤。** ## 影響面比「畫面難看」大 `health.ts:8` 的註解自己寫著: > daemon `cloudVersionStale()` 讀 `/health` 的 `bundle_version` 判斷是否過舊 ⇒ **欄位消失時 daemon 拿到空字串,會判成 stale** ⇒ 可能一直提示使用者「雲端太舊」, 或反覆嘗試更新。**這是一個會自我維持的迴圈**:更新 → 版本欄消失 → 判 stale → 再提示更新。 ## 要達成什麼 **用任何一條路更新完,Portal 都看得到正確版本號,daemon 也判得對。** 不指定做法。但有一個明顯的方向值得先評估: CLI 已經會「讀已部署 worker 的綁定並沿用」,**把 `plain_text` vars 一併納入沿用範圍** 似乎比「叫 CLI 自己算版本號」更貼近 `#97` 已經在做的事—— 但**這是我這個外部觀察,請自己判斷**(我不是這條路的專家)。 ## 怎麼驗才算數 1. 在一台**已安裝**的實例上跑 CLI 更新,跑完 `curl <cypher>/health` **要有** `bundle_version` 2. **Portal 設定頁實際打開看**,版本欄顯示的是正確版號(不是「無法讀取」)—— curl 不算,那是 leo 唯一的驗收介面 3. daemon 的 `cloudVersionStale()` 在更新後**不再誤判 stale** 4. 回歸:用安裝器裝的路徑仍然有版本號(不能修了 A 弄壞 B) ## 紅線 - 🔴 不准部署到 `leo21c`(leo 唯一一份知識庫的實例,要他親手解閘) - 🔴 不准為了讓版本欄有東西就在前端寫死或猜一個版本——**寧可誠實顯示讀不到** - 🔴 不准推 main 📍 repo:`matrix/arcrun`(`cli/src/commands/update.ts`、`cypher-executor/src/routes/health.ts`) + `products/arcrun-rag`(`installer/oauth-prototype/worker.js:1194` 是目前唯一會注入的地方) 📍 相關:`Arcrun#97`(保留綁定,只保留資源類)|`Arcrun#95`(畫面說已是最新但引擎是舊的)
Author
Owner

修法送出:PR #107(分支 fix/version-label-106)。

判斷:這題有兩種 var,規則相反——
· 設定類 var(PORTAL_MAIL_RELAY_BASE 等)=使用者實例的事實 → 沿用(把 #97「已部署的就是事實」套用到標籤上)
· 版本標籤 = 成品的屬性 → 每趟重烙,不沿用。沿用舊值=永遠停在安裝當天的假標籤,比沒有更糟。
版號取部署當下 install.arcrun.dev/api/latest 的 release(Portal/daemon 就是拿它當最新版比),
另外把真正部署的 commit 一起烙上(/health 多吐 bundle_commit);查不到 release 就誠實退成
YYYY-MM-DD+<commit7>,不掰 semver 假裝已是最新。

驗到哪裡:Portal 版本行用檔案裡那 79 行原始碼實跑五種情境(病灶重現+修好後「目前版本 1.4.41 已是最新版 commit f87d0e9」);
對真實已部署 worker 做唯讀 dry-run(確認 leo21c 現在真的沒有版本標籤,且修好後會寫進哪些 var);
cli 49/49、cypher health 4/4 綠。

還沒驗(所以這張留 open):沒有在真實實例上跑過 acr update,也沒有真實 Portal 截圖——
本機唯一有憑證的帳號是 leo21c(紅線禁碰),youlin 沒有任何憑證,且本 session 的 wrangler 需人工核准。
daemon cloudVersionStale() 住在 arcrun-rag,沒讀過,判斷是推論不是實證。
接手驗收只要三行,寫在 PR 內文最後一段。

修法送出:PR #107(分支 `fix/version-label-106`)。 **判斷**:這題有兩種 var,規則相反—— · 設定類 var(`PORTAL_MAIL_RELAY_BASE` 等)=使用者實例的事實 → **沿用**(把 #97「已部署的就是事實」套用到標籤上) · 版本標籤 = 成品的屬性 → **每趟重烙,不沿用**。沿用舊值=永遠停在安裝當天的假標籤,比沒有更糟。 版號取部署當下 `install.arcrun.dev/api/latest` 的 release(Portal/daemon 就是拿它當最新版比), 另外把真正部署的 commit 一起烙上(`/health` 多吐 `bundle_commit`);查不到 release 就誠實退成 `YYYY-MM-DD+<commit7>`,不掰 semver 假裝已是最新。 **驗到哪裡**:Portal 版本行用檔案裡那 79 行原始碼實跑五種情境(病灶重現+修好後「目前版本 1.4.41 已是最新版 commit f87d0e9」); 對真實已部署 worker 做唯讀 dry-run(確認 leo21c 現在真的沒有版本標籤,且修好後會寫進哪些 var); cli 49/49、cypher health 4/4 綠。 **還沒驗(所以這張留 open)**:沒有在真實實例上跑過 `acr update`,也沒有真實 Portal 截圖—— 本機唯一有憑證的帳號是 leo21c(紅線禁碰),youlin 沒有任何憑證,且本 session 的 wrangler 需人工核准。 daemon `cloudVersionStale()` 住在 arcrun-rag,沒讀過,判斷是推論不是實證。 接手驗收只要三行,寫在 PR 內文最後一段。
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Leo/Arcrun#106