跳轉到

2026-W36 週報:容量不再是一個數字的那一週

第六份週報,本週 5 張卡,5 個工作日,量與節奏都達標。而且這一週跨了兩件事:電力鏈在 9/2 走完最後一張(dc-16),9/3 冷卻鏈開工。

但真正該記的不是里程碑,是模型在這五天裡被連續改了五次,而且每一次都比前一次更根本

「容量」變成什麼 前一天的 code 還能不能用
dc-14 rack PDU 四維取 min,而 binding 會跑 能,這是 W35 #1 的兌現
dc-15 電錶 實測維度帶誤差帶,要用保守端;失聯要降級 能,加一個 method
dc-16 雙電源 多一個離散維度 scenario(3 值) 能,但既有數字會變壞
dc-17 冷卻水塔 limit: floatlimit(env);第二種資源(水) 不能binding() 簽章換了
dc-18 冰機 沿樹求值變成解聯立(固定點迭代) 不能,報表要多帶 converged

一週之內,「還剩多少」從查表變成解方程。而最後一張卡做了這條軌跡從來沒發生過的事:dc-18dc-17 自己的模型推翻了 dc-17 的結論。

本週卡片

標題 這張卡最關鍵的一個事實
dc-14 機櫃電源 rack PDU 線間負載的電流不能相加:10 A + 10 A 的共用相是 17.32 A(向量和),但 wye 接法就是直接相加——兩種算法都對,錯的是不知道自己在哪一種。而同一顆 CS8365C 插頭依內部斷路器數量有 35 A 與 40 A 兩個正確答案
dc-15 電力監測儀表與電錶 精度與取樣率正交:輪詢從 5 分鐘改 5 秒只是更頻繁地拿到同一個 ±1% 的錯值。而精度沿感測鏈累加(PMD 0.2 + CT 0.5 → 0.7%),在 2 MW 上是 14 kW——比兩個機櫃還多
dc-16 設備端雙電源與單電源 樹在最後一跳變成 DAG。而「每側 ≤ 50%」是推論不是規定:真正的約束是「單側扛得住全櫃」。10 kW 櫃日常 58.4% 全綠,failover 是 116.8%——斷路器跳,冗餘設計反而全損
dc-17 冷卻水塔 濕球升 2 °C,容量掉一半,一格設備都沒壞。 出水溫是「濕球 + approach」,濕球是天氣給的不是你設的。同時它是第一個同時掛在電力樹與冷卻樹上的設備
dc-18 冰水主機 跳機的是壓力不是容量。 WB 30 °C/2 格那格,水塔「排得掉」1 877 kW、容量報表不算超載,但平衡點解出 35.8 °C 超過冷凝器進水上限 → 高壓跳脫。容量報表全綠、機器照跳

串起來

一、五天,五次「容量」的定義被改寫

W35 的結論是「還剩多少有三種回傳型別」。本週把它一路推到底:

dc-14  capacity = min over 四個維度            ← 純量比大小
         ↓ binding 會跑(30A 機是進線,50A 機是斷路器)
dc-15  capacity = min over 維度,但實測維度是「區間」  ← 值變成 Bound
         ↓ 而且失聯時該維度是 stale 不是 0
dc-16  capacity = min over 維度 × scenario     ← 多一個離散軸(3 值)
         ↓ 第一次讓既有數字「變壞」:58.4% 綠 → 116.8% 紅
dc-17  capacity = min over 維度 × scenario,limit 是 env 的函數  ← 軸變成連續
         ↓ 而且要 per-resource(kW 不能跟 L/min 比大小)
dc-18  capacity = 解聯立的結果                   ← 不再是求值,是求解

每一步都不是加欄位,是換數學。 而且五步之間沒有任何一步是可逆的——dc-18 之後你不可能再退回「查一下表就知道還剩多少」。

值得單獨記一句:dc-16 是第一張讓既有數字變難看的卡。 前十五張卡都在增加模型的解析度,dc-16 第一次讓一個「本來是綠燈」的機櫃變成紅燈——而它並沒有新增任何量測,只是多算了一個情境。這是模型成熟的訊號,也是最容易被拒絕的那種改進。

二、本週最大的一件事:後一張卡推翻了前一張卡

dc-17 算出「濕球 30 °C 時 4 格水塔只剩 1 300 kW、用率 142%、紅燈」。dc-18 把水塔模型和冰機模型接起來解聯立,得到完全不同的答案:

Q_tower(T_cw) = 650 × 4 × (T_cw − WB)          ← dc-17 的水塔
P_comp(T_cw)  = 455 × 0.55 × (1 + 0.036 × (T_cw − 32))   ← dc-18 的冰機
Q_reject      = 1600 + P_comp

令兩邊相等,WB = 30 °C:
  640.99 · T_cw = 21061.96
  T_cw = 32.86 °C   ← 系統不會停,它停在這裡
驗證:approach 2.86 K → 水塔排 1859 kW;kW/ton 0.567 → 壓縮機 258 kW → 需排 1858 kW ✔

濕球 30 °C 時系統不會掛,它停在冷卻水 32.9 °C,代價是冰機多吃 8 kW。142% 是錯的。

錯在哪很重要:不是算術錯,是前提錯。 dc-17 假設冷卻水恆定 32 °C,然後問「這個溫度下水塔排得掉多少」。但真實系統的水溫會往上浮直到排得掉為止;水溫一浮,冰機更耗電、排更多熱——正回饋,只能解不能算

而真正的紅燈條件也換了位置:

情境 平衡冷卻水溫 判定
WB 28 °C、4 格 30.8 °C 綠燈
WB 30 °C、4 格 32.9 °C 綠燈(dc-17 說紅燈)
WB 28 °C、2 格 33.7 °C 黃燈
WB 30 °C、2 格 35.8 °C 紅燈——但不是容量不足,是超過 max_condenser_entering_c = 35

反推臨界濕球:4 格 32.1 °C/3 格 31.1 °C/2 格 29.2 °C。台北極端濕球就在 2 格那個數字附近——所以「兩格水塔同時不可用」在夏天真的會掉機房,四格全開則再熱都撐得住。 這三個數字是這座機房冷卻鏈的風險地圖,而且是算出來的,不是誰的經驗。

對這條學習軌跡本身的意涵:這是第一次「今天的卡證明昨天的卡是錯的」。這件事應該被視為正常而不是失誤——dc-17 在只有水塔知識時給出了那個前提下唯一能給的答案,dc-18 帶來了缺的那一半。真正的教訓是卡片裡的數字必須帶著它的前提一起存dc-17 自己其實有標「這張表是一階近似,不是規格」,做對了);只有數字沒有前提的那些,才是未來會靜默出錯的地方。

三、電力鏈橫向回顧(W35 交代的作業)

第一輪 16 項在 9/2 走完,實際產出 22 張卡(六次拆卡)。回頭看整條鏈:

dc-01 市電  → dc-02 變壓器 → dc-03 MV盤 → dc-04 ATS → dc-05 發電機 → dc-06 油
   → dc-07 LV盤 → dc-08 UPS → dc-09 電池 → dc-10 STS → dc-11 PDU
   → dc-12 RPP → dc-13 busway → dc-14 rack PDU → dc-16 設備
                                      (dc-15 電錶不在鏈上,是掛在鏈上的觀測器)

第一個發現:整條鏈上沒有任何兩段的容量單位可以直接相加。

容量單位 為什麼不能跟上一段相加
dc-02 變壓器 MVA + 阻抗% 阻抗決定下游的 Icw 合法性,不是容量
dc-07 LV 盤 InA / Inc / Ing / RDF 四個額定名字都叫「電流」但語意不同
dc-11 PDU kVA + 極數 極數用完了 kVA 還剩很多(擱置容量)
dc-13 busway A + 位置(前綴和) 同一條 run 上不同位置的剩餘量不同
dc-14 rack PDU 每相 A(向量和 線間負載不能算術相加
dc-16 設備 W × scenario 沒有單一數字,只有一組情境下的數字

第二個發現,也是更有用的一個:六次拆卡全部發生在同一個交界上。

原卡(設備本體) 拆出去的(關係/制度)
dc-03 MV 盤額定 dc-03b LSC 分級與互鎖(制度
dc-05 發電機額定 dc-05b 起動時序、dc-05c NFPA 110 測試制度(時間軸/制度
dc-07 LV 盤額定 dc-07b 短路耐受與保護協調(設備之間的關係
dc-09 電池額定 dc-09b 測試制度、dc-09c 消防合規(時間軸/第二棵樹
dc-10 STS 本體 dc-10b 兩源拓撲關係、dc-10c 相位同步(邊與圖

規律很乾淨:設備本身寫得完,設備之間的關係與圍繞它的制度寫不完。 每一次拆卡都是「六格裝不下」的訊號,而裝不下的東西總是同三類:時間軸、第二棵樹、邊

這對佇列排程有直接建議:冷卻鏈可以預期同樣的拆法dc-18 已經冒出「冰機重啟時序」(時間軸)與「水處理/退伍軍人桿菌合規」(制度)兩條線,兩條都不在六格裡。

四、「真相不在設施側」本週出現三次,而且各寫了一次降級路徑

這是本週最該立刻收斂的一件事(見連貫性檢視 #1):

欄位 真相在哪 過期時
dc-15 錶讀數 錶/BMS,會失聯 Meter.last_seen + ttl → METER_STALE
dc-16 psu_policy iDRAC/Redfish,伺服器管理員會改而不通知設施 fetched_at + ttl → PSU_POLICY_STALE
dc-17 濕球 氣象站/推導自乾球+RH SiteEnvironment.validENV_STALE

三個形狀一模一樣:外部來源 + 取得時間 + 有效期 + 過期時退回保守值並吐一條降級 Finding。三張卡各實作了一次。

dc-16 那條特別值得記,因為它是第一個真相在別的部門手上的欄位:hot spare 開著時 A 側天天貼著 93.5% 跑,設施看到的「嚴重不平衡」完全是設計行為——而這個設定不在設施的任何一張表裡。這不只是技術問題,是組織介面問題。

五、掉一個會連鎖到哪:本週的兩條新連鎖

(a)電力側的故障域會投影成冷卻側的容量損失dc-17 誤解 3):

A 側停電 → 幾格水塔風扇掉電 → in_service=False
        → 有效格數變少 → 平衡冷卻水溫上升(dc-18 解聯立)
          → 冰機 lift 上升、kW/ton 上升
            → 若超過 35 °C 進水上限 → 高壓跳脫 → 機房失冷

兩張表若互不知道,這條連鎖沒有人看得到。 W35 收斂的「兩棵樹橫向邊」在 dc-17 第一次有真實流量,而且是有方向的:電力側的 scenario 要能傳播成熱側的容量損失。

(b)冰機回頭咬發電機dc-18 對資料模型 #5):

停電 → 冰機掉(不在 UPS 上)→ 熱慣量只撐 5.2 分鐘(20 m³ 環路)
     → 發電機起來 → 冰機重啟是 250 kW 的 step load
       → 回頭吃 dc-05b 的發電機暫態性能(頻率下陷)
         → 時序沒排好會連累別的負載

restart_time 本身是回水溫的函數(見來源分歧),回水太熱時重啟會二次跳脫。所以這條連鎖是時間軸上的,穩態的 CapacityReport 表達不了它——dc-18 因此要求一個 TransientScenario這是本軌跡第一次需要模擬而不是計算。

六、本週母題

週次 母題
W31 單一欄位裝不下一個事實(數字要帶著量測條件)
W32 有些事實根本不住在欄位裡(住在序列、存量、多對多裡)
W33 上限是多候選取 min,裸數字丟掉了最有用的資訊
W34 判定不是事實的屬性,是事實 × 判準——而判準是版本化的資料
W35 「還剩多少」有多種型別,而鏈上要跨它們取 min
W36 容量不是屬性,是在一組條件與情境下解出來的值——而條件會被結果改變

五張卡各自撞到它的不同層次:dc-14算法分岔(wiring 決定用哪條公式)、dc-16情境(離散)、dc-17環境(連續)、dc-18迴圈(互為因果)。dc-15 則從側面說了同一件事:連「量到的值」都不是一個數,是一個帶著出身的區間。

自我測驗

Q1(事實回憶). 一台 208 V delta 接法的 rack PDU,L1-L2 掛 12 A、L2-L3 掛 8 A、L3-L1 掛 0 A。三條線的電流各是多少?若同一批負載改接在台灣常見的 380Y/220V 機櫃上呢?

答案

delta:L1 = 12 A、L3 = 8 A、L2 = 17.44 A。

L1 與 L3 各只被一個負載使用,等於該負載本身。L2 被兩個線間負載共用,相位差 120°,走向量和:

I_L2 = √(12² + 8² + 12×8) = √(144 + 64 + 96) = √304 = 17.44 A

注意 L2 比任何一個負載都大,也比它們的算術平均大很多,但小於 20 A。 直覺上「平均一下」與「加起來」都會給錯答案,而且錯的方向相反。

wye(380Y/220V):插座是相對中性的單相 220 V,電流直接相加。 同一批負載掛在同一相上就是 20 A。

這才是重點:兩種算法都對,錯的是不知道自己在哪一種。 所以 RackPdu.wiring 不是裝飾欄位,它是計算的前提——不存的話兩個分支都會給出看起來合理的數字,而且沒有任何遙測會告訴你選錯了(PDU 自己量到的永遠是對的,錯的是你的資料庫)。

Q2(事實回憶). 你把某條饋線的 Modbus 輪詢從 5 分鐘改成 5 秒。資料變準了嗎?如果沒有,什麼情況下這件事仍然值得做?

答案

沒有變準。精度與取樣率正交。

精度由 PMD 等級與 CT 等級決定(Eaton 的比喻:精度是樂手唱得準不準,取樣率是你用 HD 還是舊 VHS 錄他)。±1% 的錶輪詢再密還是 ±1%。這條對軟體工程師特別致命,因為「提高取樣頻率」是我們手上唯一能自己動的旋鈕。

而且精度沿感測鏈累加,不是只看錶:

class 0.2 的 PMD + class 0.5 的 CT
  最壞(線性):0.2 + 0.5 = 0.7%
  RSS:        √(0.2² + 0.5²) ≈ 0.54%
2 MW × 0.7% = 14 kW   ← 比兩個 6 kW 機櫃還多

更陰險的是同一顆錶在不同負載率下不是同一個精度:CT 的等級定義在額定附近,新機房第一年一條 400/5 CT 只跑 60 A = 15% 額定,誤差比銘牌差好幾倍——而新機房頭一年正是最需要準確資料做容量規劃的時候

仍值得提高取樣率的情況:要抓的是短時事件而非穩態值——STS 切換暫態、發電機 起動時的電壓下陷、跨 demand block 邊界的真實尖峰(dc-15 第三節那個 750 vs 1000 kW,差 33%)。這些在 5 分鐘取樣下根本不存在。

一句話:取樣率決定你「看得到什麼事件」,精度決定你「數字有多可信」。 兩者都要,不能互相替代。

Q3(應用). 一個機櫃日常兩側各 58.4%,儀表板全綠。你的容量報表要多做哪一件事才會發現這是紅燈?把數字算出來。

答案

要在 failover 情境下重算,不能只算今天的讀數。

「每側 ≤ 50%」是推論不是規定。唯一的約束是「單側必須扛得住全機櫃」:

P_rack ≤ C_side

dc-14:兩條 208 V delta 30 A rack PDU,derated 24 A, C_side = √3 × 208 × 24 = 8 646 VA

10 kW 機櫃(PF 0.99 → 10 101 VA):

normal :每側 5 050 VA / 8 646 VA = 58.4%   ← 綠燈
lose_b :A 側 10 101 VA / 8 646 VA = 116.8% ← 斷路器跳,整櫃死

⚠️ dc-16 卡片的驗收表把 normal 那格寫成 50.5%,那是錯的。 分母誤用成 10 kVA 而非單側 derated 容量 8 646 VA。自我一致性檢查很簡單:平分政策下 failover 恰好是 normal 的兩倍,116.8 / 2 = 58.4。同卡的 8 kW 那列(46.7% / 93.5%)就是這個關係,只有 10 kW 這列破了。照那張驗收表寫測試會直接紅。 見連貫性檢視 #6。

冗餘設計反而造成全損,而日常儀表板永遠看不到這件事。

還有第二層陷阱:負載不會平均落回去。伺服器 PSU 的兩路輸入未必接在對側 PDU 的同一 bank,轉移後可能單一 bank 瞬間翻倍而其他兩個不變——總量還在 90%,但某一個 bank 已經跳了。所以 redundancy_ok() 不能比對總 kVA,要逐 bank 模擬對側失效後的重分佈

對模型CapacityReport 要多一個 scenario 維度(normal / lose_a / lose_b),binding() 取跨情境的最壞值。這是 dc-10b「枚舉配置取 max」從幾台 STS 推廣到每一個葉節點

Q4(應用). 「容量用率 92%、綠燈」但冰機跳了。怎麼會這樣?順便說明為什麼這個數字不能沿著樹往上查就算出來。

答案

跳的是保護不是容量。

WB 30 °C、水塔只剩 2 格時,解聯立得到平衡冷卻水溫 35.8 °C,超過 max_condenser_entering_c = 35 → 高壓保護動作。熱量「排得掉」(水塔排 1 877 kW,數字上不算超載),但排得掉的那個溫度機器受不了。

為什麼不能沿樹查:冰機的 limit 依賴冷凝器進水溫,那個溫度由水塔決定;而水塔要排的熱包含冰機自己的壓縮機功——互為因果,形成正回饋。沿樹求值假設「下游不影響上游」,這個假設在這裡破了。

Q_tower(T_cw) = 650 × cells × (T_cw − WB)
Q_reject      = 1600 + 455 × 0.55 × (1 + 0.036 × (T_cw − 32))
→ 固定點迭代求 T_cw

對模型的三個後果

  1. CapacityReport 要記 converged / iterations / residual_k——不收斂的報表要能明講自己不收斂,而不是吐一個看起來很正常的數字。
  2. 保護設定值與容量維度要分開存Finding 要有 PROTECTION_TRIP_PREDICTED,與 OVERLOADED 並列而非合併——這兩件事的處置方向完全不同。
  3. 反推臨界濕球(二分搜尋讓 T_cw 剛好 35 °C)得到 4 格 32.1 / 3 格 31.1 / 2 格 29.2 °C。這是可以算出來的風險地圖,不必等事故。

Q5(建模判斷). 本週三張卡各自實作了一次「外部真相過期就降級」:METER_STALEPSU_POLICY_STALEENV_STALE。它們該合併嗎?合併成什麼?不合併會怎樣?

答案

該合併,而且這是本週投報率最高的一項。

三者的形狀完全相同——只差在來源與 TTL:

dc-15 dc-16 PSU 政策 dc-17 濕球
來源 錶/BMS Redfish/iDRAC 氣象站/乾球+RH 推導
誰會改它 沒人,會失聯 伺服器管理員,且不通知設施 天氣
過期判準 last_seen + ttl fetched_at + ttl valid 旗標
過期時 退回 nameplate 法 退回平分假設 退回設計濕球(保守端)
吐什麼 METER_STALE PSU_POLICY_STALE ENV_STALE

收斂建議(可直接貼):

from dataclasses import dataclass
from datetime import datetime, timedelta
from typing import Generic, TypeVar, Literal

T = TypeVar("T")

@dataclass(frozen=True)
class Sourced(Generic[T]):
    value: T
    source: Literal["redfish", "modbus", "bacnet", "weather", "manual", "design"]
    fetched_at: datetime
    ttl: timedelta
    fallback: T | None = None      # 過期時退回的保守值

    def is_stale(self, now: datetime) -> bool:
        return now - self.fetched_at > self.ttl

    def resolve(self, now: datetime) -> tuple[T, "Finding | None"]:
        if not self.is_stale(now):
            return self.value, None
        if self.fallback is None:
            raise ValueError(f"stale {self.source} and no fallback")
        return self.fallback, Finding(
            policy_id="SOURCE_STALE", severity="WARNING",
            entity_ids=[], message=f"{self.source} stale, using fallback")

不合併的三個具體後果:

  1. 降級語意會漂。 三處各寫一次 if stale: ...,遲早有一處忘了設 Dimension.valid=False,於是那一維被當成量到 0——dc-15 已經點名這件事:回報 0 的系統會讓人以為機櫃是空的。
  2. Finding 的 code 會爆炸。 每多一個外部來源就多一個 *_STALE,而它們的處置完全一樣。應該是同一條 policy 帶不同 source,這樣「本站現在有幾個資料來源是過期的」才是一個查得出來的問題。
  3. 最重要的一條:Sourced 逼你為每個外部欄位想清楚 fallback 是什麼。 三張卡的 fallback 都是保守端(設計濕球而不是今天的濕球、nameplate 而不是實測、平分而不是 hot spare 假設),但這件事目前只寫在散文裡。放進型別,它就變成建構時必須回答的問題。

反過來,不該塞進 SourcedSiteEnvironment 本身。濕球是站點級外生變數dc-17 對資料模型 #4),同時被水塔、冰機、free cooling 判斷、CRAH 除濕四個地方消費,掛在某台設備下面會被複製四份且互相不一致。Sourced 包的是欄位的取得方式,不是欄位的歸屬層級——這兩件事本週很容易混起來。

間隔複習

本週抽兩週前(W34)與四週前(W32)各一張。

週次 抽兩週前 抽四週前
W34 W32 ✅ 尚無
W35 W33 的 dc-07b W31 的 dc-03b
W36(本週) W34 的 dc-10 STS W32 的 dc-05b 發電機起動時序
W37 W35 的卡(dc-10b ~ dc-13 W33 的卡(dc-06 ~ dc-09

兩張都不是隨機抽的:本週有兩張卡分別把它們的結論推到了新的規模與新的領域。

抽 W34 的 dc-10 靜態切換開關 STS(2026-08-20,17 天前)

複習題. dc-10 說「有兩個源是宣稱,redundancy_effective() 才是事實」,並要求對 STS 跑 common-ancestor 測試。本週的 dc-16 對這個結論做了什麼?為什麼那是一個量級的差別?另外,dc-16 裡的「ATS」跟 dc-10 裡的 ATS 是同一種東西嗎?

答案

dc-16 把這個測試的對象從「幾台 STS」變成「每一台伺服器」。

dc-10 / dc-10b 的 common-ancestor 測試原本只要對設施級 STS 跑——一座機房大概幾台。dc-16 指出雙電源設備的兩條電源線就是兩個父節點,所以同一個測試要對每一台雙電源伺服器跑:

dc-10  :幾台 STS,每台兩條上游邊          → 樹 + 少數例外
dc-16  :幾千台伺服器,每台兩條上游邊       → 樹在最後一跳整片變成 DAG

量級差別的實質後果:所有沿樹寫的容量演算法都得重寫。dc-13 立的前綴和要參數化成 prefix_sum(edge, scenario)load 不能是純量,PowerEdge 需要 share_normalshare_failover,而後者取決於「哪一側掛了」——所以它不是欄位,是情境函數 load(scenario)

dc-16 的加分題把這件事變成一個可執行的清單:對整個機房跑一次 check_path_independence(),統計有多少台設備的獨立性只到 rack PDU 層。 那個數字就是進 commissioning 前最該修的清單——dc-10b 那三級 verdict(NO_INDEPENDENCE / SHALLOW_LCA / OK)在這裡第一次有了統計意義。

ATS 那半:不是同一種東西,而且差兩個數量級。

設施級 ATS(dc-04 機櫃級「rack ATS」(dc-16
切什麼 市電 vs 發電機(一邊通常是死的) 兩條都活的 A/B 側
機構 接觸器/馬達操作斷路器 固態
轉換時間 100–500 ms(EPC) 典型 8 ms(APC AP4423)

EPC 直言「UPS 下游放(設施級)ATS 餵伺服器,不是保護它們,是重開它們」。兩邊都沒錯——是兩種不同的東西共用一個名字。

對模型的結論很硬device_role == "ats" 推不出轉換時間,transfer_time_ms 必須是實測或型錄值。而且就算是 8 ms 也沒有帳面上那麼寬鬆:ITIC 的 20 ms hold-up 是滿載條件下標的,負載 90% 時可能只剩 12 ms,餘裕從 12 ms 縮到 4 ms——而 failover 發生的時刻正好是負載最高的時刻。這跟 dc-10 演算 1「餘裕從 13.83 ms 掉到 5.50 ms」是同一種陷阱的第二次現身:規格書上的餘裕都是在最好的條件下算的,而故障總是發生在最壞的條件下。

抽 W32 的 dc-05b 發電機起動時序與暫態性能(2026-08-05,32 天前)

複習題. dc-05b 講發電機承接階躍負載時的頻率/電壓下陷(ISO 8528-5)。本週的 dc-18 從冷卻側丟了一個新的階躍負載過來——是什麼?為什麼它比一般負載麻煩?這會讓資料模型長出什麼欄位?

答案

是冰機重啟:一台 455 RT 級的機器約 250 kW,而且它是整條鏈上唯一「掉了不會馬上回來」的設備。

先把時間尺度排一次,這是本軌跡最該記住的一張表:

UPS        毫秒       (dc-08)
STS        4–12 ms   (dc-10)
rack ATS   8 ms      (dc-16)
設施 ATS   100–500 ms(dc-04 / dc-16 的分歧)
發電機     ~10 秒     (dc-05b)
冰機       分鐘      (dc-18)← 慢了兩個數量級

為什麼比一般負載麻煩,三個理由:

  1. 它不在 UPS 上,所以停電時一定掉。 而熱慣量只撐得住 5.2 分鐘(20 m³ 環路、允許回水 12→18 °C、1600 kW 負載)——要撐 15 分鐘需要 57 m³,將近 3 倍,這就是 dc-20 儲冷槽存在的理由。前提是泵在 UPS 上:水不流動時那 20 m³ 送不到機房,有儲量不等於送得到
  2. 重啟本身是一個大階躍,正好落在 dc-05b 講的 ISO 8528-5 暫態性能上。時序沒排好,頻率下陷會連累同一台發電機上的其他負載。
  3. 重啟時間不是常數(來源分歧)。 datacentre.solutions / Climaveneta 說典型 10–15 分鐘、新機種 4–5 分鐘;Cundall(2026-07,附 L4 實測,模型與實測差 0.2 °C 內)說重啟計時器根本不是重點——他們在雪梨看到的是回水溫爬太高,冰機重啟後蒸發器過壓、幾分鐘內二次跳脫

會長出的欄位:

  • PowerLoad.startup_profile(步階大小、允許延遲、可否分批)——這份資料只有機械團隊有,設施電力側拿不到。這是本週第二個「真相在別的部門手上」的欄位(第一個是 dc-16psu_policy 在伺服器團隊手上)。
  • restart_time_s 不能是設備欄位,要是 restart(return_water_temp, attempt_n),而且必須能回傳「重啟會失敗」。這是「常數 vs 條件函數」的又一例,跟 dc-10transfer_time_ms 同構。
  • TransientScenario——ride_throughf(loop_volume, allowed_dt, load, pumps_on_ups, restart_time),橫跨冰機/泵/儲槽/UPS 四類設備,而 restart_time 自己又是回水溫的函數。穩態的 CapacityReport 表達不了它,這是模型第一次需要時間軸模擬。

兩張卡合起來的那句話dc-05b 問「發電機承不承受得住這個階躍」,dc-18 問「這個階躍什麼時候來、來幾次、來的時候還有沒有用」。同一個事件的兩端,中間隔了 32 天和一整條鏈。

本週的 model code 連貫性檢視

先結算舊帳。本週是規律最清楚的一次

來源 項目 狀態
W35 #1 「還剩多少」三種回傳型別 兌現dc-14 定義了統一的 Dimension / CapacityReport(dims: list[Dimension]),而 dc-15 / dc-16 / dc-17 / dc-18 四張卡全部長在同一份上(每張都明寫「不要開新檔案」)
W35 #2 validate() -> list[str] vs audit() -> list[Finding] 兌現dc-14 定義了 Finding 本體(含「不得有 acked」的註解),本週五張卡一致回 list[Finding]
W35 #3 _derated 命名漂了三次 🟡 部分dc-14input_derated_a + derating_basis,形狀對了;但 Rating(nameplate, derated, basis, authority) 這個值物件仍未抽出來
W35 #4 Breaker / Panelboard 各定義兩次 ⚠️ 未動(本週沒碰)
W35 #5 約束的基數有四種 🟡 部分dc-14Outlet.legs: tuple[Leg,...]wiring 決定長度)是第一個把基數當一等公民的例子
W34 #1 dc-09energy_kwh() 改名 🔴 連續第三週掛在第一順位卻沒做。 10 分鐘
W34 #2 Policy 本體 🔴 仍未定義。本週的 Finding.policy_id 已經指向 7 個不存在的 policy
W33 #1 / #2 Assembly 碰撞 / EnergyStore ⚠️ 仍未動(連續第四週)

W34 立的那條規律第三次成立具體到可以直接貼進 code 的建議會被採納,抽象的不會。 W35 的 #1 與 #2 都附了明確的目標 dataclass,兩項都在下一張卡就兌現了;#4 / #5 是描述性的,一項沒動。所以下面五項同樣全部寫成可貼的 code。

本週新增五處。

🔴 1. 三個 *_STALE 是同一件事(=自我測驗 Q5)

不重複展開。結論:抽出 Sourced[T]{value, source, fetched_at, ttl, fallback}resolve()(值, Finding | None)這是本週投報率最高的一項——三處已經各寫了一次,第四處(dc-19 泵的運轉狀態)下週就會來。

🔴 2. binding() 的簽章在本週被改了兩次,而前三張卡的驗收表全部失效

# dc-14 / dc-15 / dc-16 假設的
def binding(self) -> Dimension: ...            # remaining 最小的那一維

# dc-17 要求的
def binding(self) -> dict[Resource, Dimension] # kW 不能跟 L/min 比大小

# dc-18 追加的前置條件
#   converged=False 時 binding() 不得回報綠燈

dc-17 那一改是對的(跨資源比大小確實沒有意義),但它讓 dc-14dc-15dc-16 三張卡驗收表裡的 binding().name == "input_current" 這類斷言全部跑不過

收斂建議(一次改到位,之後不用再動):

@dataclass(frozen=True)
class CapacityReport:
    entity_id: str
    dims: list[Dimension]
    evaluated_at_env: SiteEnvironment | None = None   # dc-17:沒有環境就不可複現
    scenario: Scenario = "normal"                     # dc-16
    converged: bool = True                            # dc-18
    iterations: int = 0
    residual_k: float | None = None

    def binding(self) -> dict[Resource, Dimension]:
        """per-resource 取 remaining 最小者。跨 resource 不比較。"""
        ...

    def worst(self, resource: Resource = "power_kw") -> Dimension:
        """舊行為的相容入口——dc-14~dc-16 的驗收表改呼叫這個。"""
        return self.binding()[resource]

    def status(self) -> Literal["green", "yellow", "red", "unknown"]:
        if not self.converged:
            return "unknown"        # ★ dc-18:不收斂不得回綠
        ...

worst() 這個相容入口只要 3 行,而它讓前三張卡的驗收表繼續有效。 不做的話,下次回頭跑那些測試會以為是自己寫錯了。

🔴 3. Dimension 本週長了六個新欄位,但沒有一張卡回頭改前一張的建構子

逐卡累積:

加了什麼
dc-14 name / remaining / used_pct / method / valid
dc-15 method="measured"valid 第一次真的有用途(stale ≠ 0)
dc-16 scenario
dc-17 resource / unitlimit: floatlimit(env) -> Bound
dc-18 lower_limit(第一個下界維度)

合併後的目標(可直接貼):

@dataclass(frozen=True)
class Dimension:
    name: str                       # "input_current" | "bank" | "thermal" | "makeup_water" ...
    resource: Resource              # ★ dc-17
    unit: str                       # ★ dc-17:"A" | "kW" | "L/min" | "U"
    remaining: Bound | None         # ★ dc-15/17:區間,不是點值;None = 這台沒有這一維
    used_pct: float | None
    method: Method                  # nameplate | measured | pole_count | prefix_sum
                                    # | outlet_count | vector_sum | curve   ← dc-17 新增
    scenario: Scenario = "normal"   # ★ dc-16
    lower_limit: float | None = None    # ★ dc-18:違反時 UNDERLOADED,處置方向相反
    valid: bool = True              # False = stale,不是 0

注意 lower_limit 不能塞進 remaining:上界違反要減少負載,下界違反要減少在線設備——處置方向相反,合併會讓自動化建議做出完全錯的事。

🟡 4. Bound 第三次被要求,而三處語意不同

出處 形狀 語意
W33 提出 → dc-10c 實作 Angle(deg, kind) 同單位、不同 kind 禁止比較
dc-15 band() -> tuple[float, float] 量測誤差帶
dc-17 capacity_kw() -> "Bound" 一階近似的區間

三者都是「一個值加上它的不確定性」,但一個是值物件、一個是裸 tuple、一個只在型別註解裡出現過。

@dataclass(frozen=True)
class Bound:
    lo: float
    hi: float
    unit: str
    basis: str          # "PMD0.2+CT0.5@15%" / "linear approx" / "vendor curve"

    def conservative(self, direction: Literal["min","max"] = "min") -> float:
        return self.lo if direction == "min" else self.hi

    def __lt__(self, other: "Bound") -> bool:
        if self.unit != other.unit:
            raise TypeError(f"cannot compare {self.unit} with {other.unit}")
        ...

basis 那一欄是重點,它跟 derating_basisdc-12)、accuracy chaindc-15)、RatingPointdc-17)是同一個家族:「不能是列舉、要能指向來源」的欄位本週湊到第四個。 該考慮讓它們共用一個 Provenance 型別了。

🟡 5. 「模式欄位改變演算法」本週出現三次,形狀卻各不相同

模式欄位 分岔了什麼
dc-14 wiring ∈ {delta_208, wye_380y220} line_currents():向量和 vs 直接相加
dc-16 psu_policy.hot_spare draw_on():平分 vs 全壓在 primary
dc-17 mode ∈ {mechanical, free_cooling} 排熱需求含不含壓縮機功

三處各寫一組 if。它們的共通點是這個欄位不是資料,是計算的前提——選錯不會報錯,兩個分支都會給出看起來合理的數字,而且沒有任何遙測會告訴你選錯了

建議:不必立刻抽象成 Strategy(那是 W34 說的「抽象的不會被採納」那一類),但至少讓這類欄位在型別上可辨識,並強制它們有一條 validate() 規則:

# 最小可行版本:一個標記 + 一條共用規則
PREMISE_FIELDS = {"wiring", "hot_spare", "mode"}   # 計算前提,不是資料

def check_premises(entity) -> list[Finding]:
    """前提欄位若來自預設值而非實際確認過的來源 → 吐 PREMISE_UNVERIFIED。"""
    ...

理由很實際:dc-14wiring 答錯,整個機房的每相電流全錯dc-16hot_spare 答錯,A/B 平衡報表在報一個不存在的問題。這兩件事都不會有任何告警。

🔴 6. dc-16 的驗收表有一個算錯的數字(本週唯一「已經錯了」而非「待重構」的一項)

前面五項都是「型別該怎麼收斂」,這一項不同——它是一個現在就錯在卡片上的數字

dc-16 驗收表寫:

| 10 kW 同上 | `normal` 50.5% 綠燈,但 binding() 回 116.8% 並吐 OVERLOAD_ON_FAILOVER |
10 kW / PF 0.99 = 10 101 VA
C_side = √3 × 208 × 24 = 8 646 VA
normal 每側 = 5 050 / 8 646 = 58.4%     ← 不是 50.5%
failover    = 10 101 / 8 646 = 116.8%  ✔ 這個是對的

分母被誤用成 10 kVA 而非單側 derated 容量。照這張驗收表寫測試會直接紅,而它剛好落在最不該錯的地方——那一列的教學重點正是「normal 看起來還好」,58.4% 比 50.5% 更能撐住這個論點(它離 50% 更遠卻仍然綠燈)。

收斂建議(5 分鐘):改 dc-16 卡片那一格為 58.4%,並在測試裡加一條不變式而不是逐格核對:

# 平分政策下,failover 恰好是 normal 的兩倍。這條不變式能自動抓出整類分母錯誤。
assert used_pct(dev, "lose_b") == pytest.approx(2 * used_pct(dev, "normal"))

怎麼被抓到的值得記一筆:不是靠重算,是靠同卡內橫向核對——8 kW 那列是 46.7% / 93.5%(恰為兩倍),只有 10 kW 這列破了關係。W35 的自我修正(0.80 被修正兩次)與本週 dc-18 推翻 dc-17,都是下一張卡發現上一張卡;這是第一次由同一張卡內部的一致性抓到錯誤。

建議把「同卡內數字的自我一致性檢查」加進 dc-daily-card SKILL 的收尾:凡是同一張表裡有兩列以上共用同一組公式的,收工前核對它們之間應該成立的比例關係。這比重算便宜,而且抓得到重算抓不到的東西(重算時你會用同一個錯誤的分母)。


優先序

  1. #6 改掉 dc-16 的 50.5% → 58.4% + 加不變式 — 5 分鐘。排第一不是因為它最重要,是因為它是本週唯一一個「已經錯在檔案裡」的東西,其餘五項都只是還沒做的重構。錯誤資訊留著會被後面的卡引用。
  2. #2 binding() 相容入口 — 3 行,讓三張卡的驗收表繼續有效。擋住其他任何改動的驗證。
  3. #1 Sourced[T] — 三處合一,且 dc-19 下週就是第四處。投報率最高。
  4. #3 Dimension 合併 — 機械改寫,但要一次做完,否則 dc-19 會變成第六個版本。
  5. W34 #1 energy_kwh() 改名連續第三週。10 分鐘。它是模型裡唯一會產生錯誤數字的項目,而且是靜默的。 若這週再不做,建議直接降級成「已知缺陷」寫進 topic-01——一項連續三週排在前面卻不做的事,掛在清單上只會讓清單失去可信度。
  6. 4 Bound / #5 前提欄位標記 — 可以等,但 Bound 跟 #3 的 remaining: Bound 綁在一起,實際上會一起做。

本週該問 facility 的問題

五張卡共提出 15 個問題,去重後選 3 個下週真的拿去問人的。挑選標準沿用前五週:「現在問還來得及改,晚問就固化了」。本週三題的固化時點分別是——設計階段/隨時可能被改掉/採購規格

Q1 — 問 機電設計單位 + 冰機/水塔廠商(⚠️ 設計階段,設備下單後就固化)

設計濕球用的是哪個數字、哪一年的氣象資料、哪個百分位(0.4% / 1% / 2%)? 站址有沒有做過熱氣再循環修正? 水塔的廠商性能曲線(cold water temp vs 濕球 vs 水量)拿得到嗎? 冰機的冷凝器進水上限與蒸發器低溫保護設定值是多少?出廠值有沒有被現場改過? 最小負載多少?低負載靠變頻還是熱氣旁通?運轉策略是輪流開一台還是全部並聯?

為什麼是這題,而且為什麼最急dc-18 算出這座機房的臨界濕球是 4 格 32.1 °C/3 格 31.1 °C/2 格 29.2 °C——而台北的極端濕球就在 2 格那個數字附近。這三個數字的正確性完全取決於上面四個輸入:

  • 設計濕球:卡片裡的 28 °C 是佔位符,明確標了「不要直接引用」。這個數字錯 1 °C,臨界濕球整條線跟著移。
  • 性能曲線:拿不到就只能存一個銘牌數字,而那個數字一年裡大概只有幾小時是對的dc-17 的線性近似自己標了「不可以拿去做設計或驗收」)。
  • 35 °C 進水上限dc-18 明寫這是「常見典型值,各機型不同,要跟廠商拿」。而紅燈判定完全建立在這個數字上——它是保護設定值,不是容量。
  • 最小負載與運轉策略dc-18 第 4 節指出三台並聯跑 136 RT 會讓每台只有 18%,低於離心機典型的 25–30% 最小負載 → surge 或熱氣旁通純燒電。這是前 17 張卡第一次出現「加冗餘反而讓事情變糟」,而它跟 N+1 的標準做法直接衝突。

這一題現在問還來得及影響選型與台數,設備進場後就只能接受。

Q2 — 問 伺服器團隊 + facility(要兩邊一起問)(⚠️ 隨時可能被改掉,而且改了不會有人通知)

機櫃內的伺服器 PSU 冗餘政策是什麼?hot spare 開著嗎?primary PSU 是哪一顆? 現場有多少單電源設備?各接在哪裡?有沒有 rack ATS?型號與標稱轉換時間多少? A/B 兩側往上追,最近的共同祖先在哪一層?

為什麼是這題:這是本軌跡第一個真相在別的部門手上的欄位,而且它會被改而設施完全不知情

  • Dell 的 hot spare 啟用時一顆 PSU 進睡眠、幾乎全部負載壓在 active 那顆。同一個 8 kW 機櫃,平分是兩側各 46.7%,hot spare + Primary PSU = 1A 側 93.5%、B 側 ≈0總量一樣,設施側看到的是完全不同的兩張圖。
  • 若整櫃伺服器都用出廠預設 Primary PSU = 1,A 側天天貼著 93.5% 跑——而這個事實不在設施的任何一張表裡,它在 iDRAC。
  • 單電源盤點越早越好:EPC 指出「Tier III 設計為了省錢砍掉 STS,後來才發現三分之一的機櫃是單電源」。而 rack ATS 不是等價替代——它只是把單點從電源路徑搬到 ATS 上,且 PSU 在 90% 負載時 hold-up 可能只剩 12 ms,餘裕縮到 4 ms
  • 第三問是 dc-10b 的老題目,但這次要對每一台伺服器跑(見間隔複習)。若答案是「同一台 UPS」,那機櫃裡所有雙電源設備的第二條線都只是裝飾

這一題的答案有半衰期——問完要排定期輪詢,不是問一次就結案。

Q3 — 問 機電設計單位 + rack PDU 供應商(⚠️ 採購規格階段)

機櫃內是 208 V line-to-line(delta)還是 220 V line-to-neutral(wye)?rack PDU 型錄給我。 rack PDU 的分路斷路器幾個、額定多少?進線導體線規多少? outlet-level 計量是哪一個 class(IEC 62053-21 class 1 還是只是「大概準」)?資料保存多久?

為什麼是這題

  • 第一問答錯,整個機房的每相電流都是錯的,而且錯得看起來很合理(dc-14 誤解 1)。這是本週「前提欄位」問題最貴的一個實例。
  • 第二問決定 binding 在哪,以及同一顆插頭是 35 A 還是 40 A。 同一個 CS8365C,3 個分路斷路器是 35 A、6 個是 40 A——差的是一個從外觀完全看不到的線規,而它值 1.1 kVA。型錄封面上不會有。
  • 第三問延續 W35 Q3:沒有保存期就不能用實測法做容量規劃。順帶注意 dc-14 記的那個坑:rack PDU 宣稱的 class 1(IEC 62053-21)與電錶的 class 0.2(ANSI C12.20)不可互相比較,兩套標準的 class 數字語意不同。

這週沒選上、但別忘記的

  • 「對外報的 PUE 是 category 幾?量測點在哪顆錶上?用 ISO/IEC 30134-2 還是 Green Grid 的定義?」 後者綁量測頻率(Level 3 = 一年 ≥ 35 040 點),前者不綁(可以是 12 點)——對遙測儲存與輪詢設計差一個數量級。
  • 「每顆錶的 CT 變比與精度等級表給我;初期負載下這些 CT 實際跑在額定的百分之幾?」 後半是殺手:CT 照滿載選,你讀它時機房是空的(60/400 = 15% 額定,誤差比銘牌差好幾倍)。
  • 「Demand 用 fixed block 還是 rolling?區間幾分鐘?跟台電帳單對得上嗎?」 同一批原始資料,fixed 15 分鐘報 750 kW、rolling 報 1000 kW,差 33%
  • 「停電後冰機重啟時序是什麼?誰先起、間隔多久?回水太熱時會不會拒絕啟動或二次跳脫,實測過沒有?」 直接決定 dc-20 儲冷槽要多大(5.2 分鐘 → 15 分鐘要 57 m³,近 3 倍)。順帶必問:泵在不在 UPS 上? 不在的話有儲量也送不到機房。
  • 「補水從哪來?斷水時盆內存量撐幾分鐘?排污有沒有排放許可的水量/水質上限?」 這三問決定水這個資源的容量維度長什麼樣。
  • 冷卻水塔清洗與檢驗頻率的地區差異dc-17 分歧二):美規約每 90 天培養檢驗/每月清洗,台灣業界指引是每年至少一次、高風險半年一次、每季或每半年清洗消毒——頻率差一個數量級,不要把美規排程硬編進工單系統。
  • W35 起就掛著、仍未問的:busway 吊裝位置環境溫度與廠商降載曲線、A/B 兩台 RPP 是否同櫃/同吊架、鋰電室樓板承重上限(W33 起)、STS 波形記錄保存期。

節奏

5 張卡 / 5 個工作日(8/31 一 ~ 9/4 五),本週是這條軌跡目前最平順的一週——沒有空窗、沒有補寫、沒有 lock 殘留、沒有重複卡片。W35 那條「拆卡當下必須同時往 backlog 插入新項目」的教訓本週沒有再被觸發(本週沒有拆卡,五張全部一次寫完,且四張落在 9457–9998 字元,貼著上限但都在範圍內)。

但這份週報本身遲到了。 排程的 datacenter-weekly-review(週日 10:00)在 9/6 沒有產出 2026-W36.md;本份是 datacenter-daily-card週日 21:20 執行時,依 SKILL 的「若今天是週日 → 改走週報流程」分支偵測到缺漏後補寫的。

建議(機制性的,跟 W34 的 lock 問題同一類)dc-daily-card 的週日分支目前是唯一的安全網,而它能運作純屬幸運——這條任務的 cron 設為週一至週五,9/6 這次執行是額外觸發的。應該在 dc-weekly-review 加一道自檢:開工先確認上週的週報檔案存在,不存在就先補上週的再寫本週的。 否則週報的斷鏈會安靜累積,而且沒有任何東西會通知你——這正是本週 dc-14 / dc-16 反覆講的那種失敗模式(選錯前提不會報錯、儀表板全綠)。我們自己的基礎設施犯了跟卡片內容一模一樣的錯。

另外值得記一筆:本週五張卡有四張明寫「不要開新檔案,繼續長同一份 code」dc-15 / dc-16 / dc-17 / dc-18)。這是 W35 連貫性檢視 #1、#2 產生的直接效果——一旦有了一份共同的 CapacityReport,後面的卡就會自動往上長。 這比任何抽象建議都有效,值得作為往後寫卡的預設做法。


下週

  • 佇列下一張:dc-19 一次側/二次側冰水泵。 dc-18 已經先欠了它一個問題:「泵在不在 UPS 上」決定 ride-through 是 5.2 分鐘還是 0。而 dc-19 會是 Sourced[T] 的第四個使用者(泵的運轉狀態),所以連貫性檢視 #1 與 #2 請在動筆之前做完——現在是 20 + 3 分鐘,dc-19 寫完再做就是六張卡一起改。
  • energy_kwh() 改名連續第三週掛在第一順位卻沒做。 10 分鐘。它是模型裡唯一會產生錯誤數字的項目,而且是靜默的。若下週再沒做,建議直接從佇列裡撥半天出來清一次技術債,不要再往後推。
  • 冷卻鏈可以預期跟電力鏈一樣的拆法(見「串起來」第三節)。dc-18 已經冒出兩條不在六格裡的線:冰機重啟時序(時間軸,跟 dc-05c 的測試制度同類)與水處理/退伍軍人桿菌合規(制度,跟 dc-09c 的消防合規同類)。建議現在就在 backlog 預留位置,不要等到寫的時候才發現裝不下——這正是 W35 記取的教訓。
  • ⚠️ commissioning 隨時可能開始。 本週為現場驗收單加了兩項:(a)rack PDU 的 wiring 與分路斷路器實地確認dc-14,錯了整個機房每相電流全錯)、(b)冰機停電重啟實測,含回水溫過高時的二次跳脫行為dc-18,Cundall 的實測經驗指出這才是真正的失效模式)。連同 W32 Q3(ATS 五個計時器、NFPA 110 分段時序記錄)、W33 Q2(ZSI 注入電流測試、tie 閉合互鎖、arc flash 標籤)、W34 Q3(STS 演算法、抑制門檻、latched reset 權限)、W35 Q2(兩源實際相位差 + 手動轉換實測)——這六份清單合起來就是現場驗收單。W35 就建議整理成一頁帶去現場,本週再提一次。
  • W37 的間隔複習:抽 W35 的卡(dc-10b ~ dc-13)+ W33 的卡(dc-06 ~ dc-09)。