Commit Graph

2 Commits

Author SHA1 Message Date
claude-code 3f2e45f5dc fix(resource-rule): 上次裝到一半死掉的帳號要能再裝一次(Arcrun#123)
封測者 1.4.45 實撞:
  a namespace with this account ID and title already exists
⇒ 那個帳號從此永遠裝不起來,而錯誤訊息對用戶完全無法行動。

根因:rule.mjs 第 2c 段只問「有沒有已部署的 worker 綁著它」,
不問「這個名字在帳號上是不是已經存在」。註解裡「本來就沒有東西可丟」
漏掉一種狀態——資源已建、worker 還沒部署就中斷(逾時/關掉分頁/斷網)。
拆除 youlin 時親眼看到的 8 顆空殼 KV 是同一個形狀。

修法:2c 在 create 之前先查同名。找到同名資源時:
  · 呼叫端聲明了 createNameIsOurs → 接回那一顆(adopt + reclaimed 標記)
  · 沒聲明 → 停手,訊息帶 RES-NAME-TAKEN 錯誤碼讓用戶回報

createNameIsOurs 是接管的唯一依據,預設 false(fail-closed)。只有名字
推導自使用者自己的身分時才准聲明——安裝器的
arcrun-rag-<slugFromEmail(email)>-kv-<binding> 合格;acr 從 toml 讀到的
裸 binding 名(WEBHOOKS)不合格,因為用戶自己也可能用那個名字。

這不是把 #97 刪掉的「照名字 ensure」搬回來:
  ① #97 找不到就新建一顆頂上去(會弄丟資料);這裡找到才沿用,
     找不到照舊新建,永遠不拿新的空資源頂替既有的
  ② 排在「已部署綁定=事實」之後,名字只在沒有任何綁定可看時才有發言權
  ③ #97 無條件相信名字;這裡要呼叫端先證明名字推導自用戶身分

順手補上假帳號的保真度:FakeCloudflare.createKvNamespace 原本不擋同名,
所以半殘帳號在測試裡看起來只是「多幾顆孤兒」,實際上是裝不起來——
少了那一行,這個 bug 測不出來。fixture-account.mjs 也把
resourcesExist 與 deployed 拆開,才表達得出這個狀態。

驗證(皆為實跑):
  node shared/resource-rule/tests/half-finished-install.mjs  → 全部通過(零依賴)
  cd cli && npm test                                          → 73/73 pass
  sync-resource-rule --check                                  → 三份副本皆與原稿一致

⚠️ 只有規則這一半。安裝器要在 manifestRequirements 聲明 createNameIsOurs
才會生效,那一半在 arcrun-rag(D85)。

Refs: inkstone/Arcrun#123
2026-08-14 08:08:37 +00:00
uncle6me-web bb548b6fdf refactor(shared): 「該用哪些資源」搬出 CLI——一份實作,acr 與安裝器吃同一條規則
leo 2026-08-12:「根本就不應該在 CLI,我要的是一個大家都可以用到的規則。」

「這個實例該用哪些資源」換到安裝器就要重寫一次 ⇒ 依 rules/07-thin-shell.md 的判準
它是**能力**,而它原本住在 cli/src/lib/resource-resolver.ts ⇒ 那本身就是違規。
後果已經真的發生:acr 那條有 Arcrun#97 的修法、安裝器那條沒有,於是安裝器照名字
找、找不到就建一顆空的綁上去 ⇒「我按了更新,工作流和登入全不見了」。

規則搬到 shared/resource-rule/(零依賴 ESM,Node 與 Workers runtime 都直接跑):

  · rule.mjs           規則本體+把 CF 回應讀成事實的 normalizeLive*
  · cf-resource-api.mjs ResourceApi 的 CF REST 實作——**眼睛也共用**:
                        兩條路各自解讀 CF 回應,只要一邊看不到既有綁定就會去新建,
                        #97 不需要規則寫錯就能重演
  · installer-entry.mjs 安裝器唯一該碰的入口 resolveInstanceResources()

不是做成 cypher 端點的理由(自舉):這條規則要在「決定怎麼裝」的當下就用得到,
而那時 cypher 可能還不存在(安裝器的工作正是把它生出來);且輸入是使用者自己帳號的
綁定狀態,不該送去平台換答案。它是純函式,用不著變成服務。

只有一份,機械看守:
  · 安裝器直接 import repo archive 裡的原稿,**不需要副本**
  · acr 因為 npm pack 打不進套件目錄外的檔案,帶一份逐位元組鏡射
    (scripts/sync-resource-rule.mjs 產生;build/test 先跑 --check,差一位元組就紅)
    ——同 cli/harness/ 產生物+世代閘的既有慣例
  · cli/tests/single-implementation.test.ts 掃全 repo:7 支規則函式的實作只有一處

CLI 淨 -496 行(邏輯是搬走,不是複製)。cf-api.ts 的 CfAccountClient 保留公開介面,
ResourceApi 那七個方法全部委派共用 client。

驗證:cli 58/58 綠(含新增的兩條路一致性 fixture + 三種情境),tsc --noEmit 乾淨。
2026-08-12 23:37:01 +08:00