架構決策 (ADR)
固定 Flutter SDK 版本於 CI 與本機 toolchain(停用 stable channel 浮動)
Context
既有設計
本 monorepo 含 Flutter mobile(mobile/)。CI 透過 subosito/flutter-action@v2
取得 Flutter SDK,原本所有 step 僅指定 channel: stable、未指定版本:
- uses: subosito/flutter-action@v2
with:
channel: stable本機開發則由 asdf 透過 .tool-versions 管理(與 bun、terraform 同一機制)。
觸發
channel: stable 不指定版本時,CI 每次執行會抓取當下最新的 stable 版本。
這造成兩個問題:
- 不可重現:不同時間點的 CI run 可能跑在不同 Flutter 版本上;上游發佈新
stable 後,原本綠燈的
main可能在下一次 run 無預警變紅,且無 code 變更可對應。 - 本機與 CI 不一致:
.tool-versions釘住的版本與 CI 浮動版本可能不同, 開發者本機通過、CI 失敗(或反之),難以除錯。
CI 是 merge gate,浮動版本等於把「工具鏈版本」這個變因留在不受控狀態。
Decision
結論:Flutter SDK 版本在 CI 與本機 toolchain 兩側都顯式釘住單一版本, 升級改為經 review 的刻意變更,而非隱性浮動。
實作分兩個 PR(見文末 Links):
- PR #546(釘版):
- CI:保留
channel: stable,並在所有subosito/flutter-action@v2step 加上flutter-version釘住3.44.0——共 5 處:.github/workflows/ci.yml(2)、.github/workflows/cd-mobile.yml(2)、.github/workflows/flutter-e2e.yml(1)。 - 本機:
.tool-versions釘flutter 3.44.0-stable(asdf)。 - 文件:
ONBOARDING.md的 Flutter SDK 版本同步標註為釘住版本。
- CI:保留
- PR #547(後續防護):#546 merge 後由 mob review(Claude + Codex + Gemini)共識補上:
.tool-versions變更觸發 Flutter CI——原本 Flutter CI 的 paths-filter 只認mobile/**,純.tool-versions的 SDK bump 不會觸發任何 Flutter check, 釘版形同虛設;#547 將.tool-versions納入觸發路徑。- 版本值加單引號(
flutter-version: '3.44.0'),避免 YAML 將其解讀為 float 等型別歧義。
channel: stable 與 flutter-version 並存:action 會在 stable channel 內解析到
指定的精確版本,因此 channel 欄位保留不影響釘版效果。
升級流程:bump 版本時,必須同時更新 CI 5 處 + .tool-versions +
ONBOARDING.md;因 #547 已將 .tool-versions 納入 Flutter CI 觸發路徑,SDK bump
本身即會觸發 Flutter check(含 mobile P0 critical path),須綠燈後才合併。
Alternatives Considered
- 方案 A:維持
channel: stable浮動(不指定版本) — 考慮過,因為不可重現 + 本機/CI 版本漂移,且上游新 stable 會無預警打斷main而拒絕。 - 方案 B:只釘
.tool-versions,CI 不釘 — 考慮過,因為CI 仍浮動、 且 CI 才是 merge gate,本機釘版無法阻止 CI 因版本漂移失敗,故不足。 - 方案 C:導入 FVM(Flutter Version Management) — 考慮過,因為
會多一層 版本管理工具,而 asdf + .tool-versions 已是本 repo 既有 toolchain 標準 (bun/terraform 同機制),為維持單一機制而不採用。
Consequences
好:
- CI build 可重現;同一 Flutter 版本貫穿所有 run 與本機。
- 消除「上游發佈新 stable → 無 code 變更卻打斷 main」的浮動風險。
- 本機與 CI 版本對齊(
.tool-versions↔ workflows)。
壞 / 代償:
- 升級需在多處手動 bump(CI 5 處 +
.tool-versions+ONBOARDING.md), 存在「只改部分、版本不一致」的風險,須在同一 PR 內全部對齊。 - 不再自動取得最新 stable 的修復/安全更新,需靠刻意 bump 才會跟進。
- 需要一個升級紀律:bump 時同步全部位置並跑 mobile P0 測試。
中性:
channel: stable保留,與flutter-version並存(action 於 stable channel 內 解析精確版本)。3.44.0為目前釘住的 baseline;後續版本演進以 git tag / PR 追蹤。
Links
- PR #546 —
chore(ci): pin Flutter SDK to 3.44.0 across CI and .tool-versions(釘版,已 merged 2026-06-18) - PR #547 —
ci: validate Flutter SDK on .tool-versions changes + quote versions(後續防護:.tool-versions變更觸發 Flutter CI + 版本值加引號,已 merged 2026-06-18)