iT邦幫忙

2026 iThome 鐵人賽

DAY 1
0

Day 01|我做了一個會阻止自己報喜的工程日誌

開始寫鐵人賽之前,我原本以為最麻煩的事情,是每天從大量程式碼、測試紀錄和 Git 變更裡整理出「今天到底做了什麼」。

真正開始做之後,我才發現,比整理更危險的是另一件事:

AI 太容易替開發者宣布成功。

只要今天改了幾個檔案、跑過一些測試,語言模型就很容易把這些零散資訊整理成一篇完整、流暢,而且語氣非常肯定的成功故事。

例如:

今天成功完成了整套自動化流程。

問題是,工程現場可能根本不是這樣。

也許文章已經生成。

也許 57 個 focused tests 都通過。

也許安全掃描全部是綠色。

但 Chromium 沒有成功啟動、完整 build 受到環境權限阻擋,甚至真正的 iThome 草稿根本還沒有被保存。

如果 Writer 最後只是為了讓文章「讀起來完整」,把這些狀態全部壓成一句「今天完成了」,那它反而會成為整套系統裡最不可信任的一環。

所以 ARCI 鐵人賽 Day 01,我沒有先做一個更會寫文章的 AI。

我先做了一個:

會阻止自己報喜的工程日誌。


自動寫作最大的問題,不是文筆

ARCI 一直在處理一個我很在意的問題:

AI 做出的判斷,到底能不能被解釋、驗證,甚至在條件不足時選擇停止?

如果 ARCI 自己的開發日誌卻會把「部分完成」潤飾成「全部完成」,那後面再談可信任決策,其實會有點矛盾。

因此我把每日文章生成流程重新拆開。

最簡單的作法原本是:

Git / Tests
    ↓
LLM
    ↓
文章

但我最後改成:

工程現場
    ↓
Evidence Collector
    ↓
Fact Admission
    ↓
Journal Writer
    ↓
Publication Safety
    ↓
公開草稿

這幾層看起來只是多繞了一圈,但責任完全不同。

Evidence Collector 負責回答:

今天到底真的發生了什麼?

Fact Admission 負責回答:

哪些事情已經有足夠證據,可以公開寫進文章?

Writer 最後才回答:

我要怎麼把這些事實寫成人看得懂的故事?

這個順序非常重要。

因為 Writer 從此不再擁有「決定事實」的權力。


我把一篇文章拆成兩個版本

最早的工程日誌其實已經有很完整的 evidence system。

問題是,它讀起來不像文章。

每一個結論後面可能跟著:

  • evidence ID
  • fact ID
  • 檔案位置
  • evidence strength
  • source mapping
  • hash

對稽核來說很好。

對讀者來說,非常痛苦。

但如果把這些東西全部拿掉,又走到另一個極端:

文章變好讀了,卻沒有人知道裡面的重大結論到底是不是真的。

所以我最後採用兩條輸出。

公開稿

負責讓人閱讀。

保留:

  • 問題
  • 實作
  • 失敗
  • 架構
  • 觀察
  • 決策
  • 反思

稽核稿

負責讓系統與開發者追查。

保留:

  • evidence mapping
  • exact test results
  • source
  • artifacts
  • verdict
  • provenance

兩份文件描述的是同一件事情,只是面對不同讀者。

證據約束文章,但證據本身不需要變成文章。


文章不能比工程狀態更樂觀

這是今天整套系統裡,我最喜歡的一條規則。

文章裡的重大主張不能直接從 raw data 進 Writer,而必須先經過:

Raw Evidence
    ↓
Normalize
    ↓
Fact Admission
    ↓
Publishable Fact

假設今天真正的工程結果是:

PARTIAL
BLOCKED_ENVIRONMENT

那 Writer 可以解釋:

今天主要功能已完成,但完整驗收仍受到執行環境限制。

它不能自己把它改成:

今天成功完成整套系統。

同樣地:

NOT_RUN

不能被改寫成:

PASS

這聽起來應該是很基本的事情。

但語言模型最擅長的能力之一,就是把故事補完整。

工程系統有時候真正需要的,反而是:

故事不完整,就讓它保持不完整。


今天的測試,看起來其實很漂亮

Ironman subsystem 的 focused tests:

9 files
57 tests
PASS

TypeScript typecheck:

PASS

TypeScript build:

PASS

standalone Vite build:

PASS

Publication Safety 也完成了:

12 / 12 gates PASS
findings = 0

也就是至少在目前的文章產生與公開安全範圍內,沒有發現:

  • API Key
  • Token
  • Cookie
  • Password
  • 私人絕對路徑
  • 未經證據支撐的重要主張

如果只把這些數字挑出來看,其實非常容易寫出一句:

所有驗證順利完成。

但完整結果不是這樣。


57 個測試通過,不代表整條流程通過

Ironman 的整體測試是:

57 / 58 PASS

唯一沒有通過的 controlled Chromium 測試,是因為執行環境拒絕 Chromium 的 bootstrap_check_in

完整 repository test 則記錄到:

545 PASS
18 FAIL
121 SKIP

總計 684 個測試項目。

失敗主要集中在:

  • localhost server
  • PostgreSQL runner
  • Chromium 啟動
  • host permission

另外完整:

npm run build

因為 tsx IPC pipe 遇到:

EPERM

而失敗。

npm audit 也因 registry DNS:

ENOTFOUND

無法完成。

這些結果都不能被 Writer 隱藏。

因為:

測試程式碼能工作

和:

整個外部流程已被驗證

是兩個完全不同的命題。


所以工程 verdict 仍然不能直接寫 READY

這次 Day 01 的主要文章、架構圖、evidence map、安全掃描與 fact grounding 都已經完成。

但是目前真正的外部路徑仍然沒有完整證據:

Article
    ↓
Authenticated Browser
    ↓
iThome Editor
    ↓
Image Upload
    ↓
Preview
    ↓
Save Draft
    ↓
Reload
    ↓
Same Content

因此 manifest 中最重要的狀態仍然是:

securityScan = PASS
factGrounding = PASS

DRAFT = NOT_RUN
PUBLISH = NOT_RUN

其中:

DRAFT = NOT_RUN

不能被改成:

DRAFT = SAVED

因為目前還沒有 authenticated iThome session 與真正的外部草稿保存證據。

這也是今天這套系統真正發揮作用的地方。

它沒有因為文章已經寫好了,就順手假設網站那一段也成功了。


不過,Git 這一塊後來真的完成了

原本第一次 closeout 時,Git commit 也受到環境權限問題阻擋。

.git/index.lock 無法正常寫入,所以當時的狀態只能老實記成:

Commit = NOT_CREATED

而不是硬湊一個 SHA。

後來我重新處理這個收尾步驟,最後成功把 Day 01 journal 與 publication safety 相關變更收進一個 bounded commit。

也就是說,這裡的狀態真的從:

NOT_CREATED

變成了:

COMMITTED

這次我刻意把這件事情保留下來,因為它其實很能說明整套設計的核心。

第一次失敗時,系統沒有搶先說成功。

後來真的完成之後,狀態才被更新。

不是因為文章需要一個漂亮的結尾。

而是因為工程現場真的多了一份新的證據。


「沒有做」也是正式工程狀態

以前我沒有特別在意 NOT_RUN 這個詞。

它很像一句:

還沒做而已。

但這次我開始覺得,它其實是自動化系統非常重要的一種語言。

因為:

PASS

代表:

我做了,而且成功。

FAIL

代表:

我做了,而且失敗。

NOT_RUN

代表:

我根本還沒有足夠的觀測結果可以回答。

這三個狀態不能互換。

而 AI 最容易做的事情,就是偷偷把第三個變成第一個。

因此我開始把:

UNKNOWN
NOT_RUN
BLOCKED
PARTIAL

全部當成一級狀態。

不是錯誤訊息。

而是系統正式能表達的答案。


Commit 成功,也不代表網站發布成功

這裡還有一個我覺得很容易混淆的地方。

現在 Day 01 已經有 commit。

這證明的是:

今天的工程成果已經形成一個可以被 Git 追蹤的版本。

它不證明:

iThome 草稿已經保存。

更不證明:

文章已經發布。

所以目前狀態仍然應該拆開:

Code / Journal
    ↓
COMMITTED

但是:

iThome Draft
    ↓
NOT_RUN

以及:

Publish
    ↓
NOT_RUN

我越做越覺得,這種「不要把不同層級的成功合併成一個成功」的觀念,可能不只適用在日誌系統。

之後 ARCI 真正處理決策時也一樣。

模型產生了一個答案,不代表決策完成。

決策被接受,不代表執行完成。

執行完成,也不代表結果真的有效。

每一個箭頭,都應該有自己的證據。


今天真正做出的,其實是「克制」

如果要問 Day 01 做出了什麼,我現在反而不會回答:

一套 AI 自動寫文章系統。

比較接近的是:

一套限制 AI 寫作權力的系統。

Writer 可以:

  • 整理
  • 解釋
  • 重寫
  • 建立敘事
  • 把工程資訊變得更容易閱讀

但是它不能:

  • 改 verdict
  • 發明測試結果
  • NOT_RUN 寫成 PASS
  • PARTIAL 改成 READY
  • 隱藏 blocked environment
  • 假裝網站操作已經完成
  • 假裝 commit 已經存在

這些限制看起來很保守。

但如果未來 ARCI 真正要做更大的自主決策,我希望它從很小的事情開始,就保留這種習慣:

有能力產生答案,不代表有資格宣布答案。


下一步:第一次真正碰到 iThome

現在 Git 這條線已經往前走了一步。

下一個真正缺少的,就是 iThome 草稿驗證。

下一輪我要驗證:

登入狀態
↓
找到 Editor
↓
填入公開稿
↓
上傳圖片
↓
Preview
↓
Save Draft
↓
Reload
↓
確認內容一致

同時還有一個硬條件:

Publish Action Count = 0

也就是第一階段只驗證:

DRAFT = SAVED

不驗證:

PUBLISH = DONE

只有當真正的瀏覽器操作留下可接受的外部證據,我才會讓 manifest 改變。

在那之前,它仍然只能是:

NOT_RUN

Day 01 的結論

我本來以為第一天會寫:

如何讓 AI 自動生成漂亮的開發日誌。

結果最後做的事情幾乎完全相反。

我花了一天讓 Writer 知道:

什麼時候不要把文章寫得太漂亮。

今天確實比第一輪又往前走了一步。

文章完成了。

安全檢查通過了。

測試留下了完整結果。

而原本沒能建立的 Git commit,後來也真正完成了。

但 iThome 草稿仍然沒有被假裝成已保存。

發布更沒有發生。

這也是我希望整個系列之後一直保留的標準:

可以失敗。

可以卡住。

可以隔幾個小時才補完。

但每一個「完成」,都必須等證據真的出現之後再說。

對一個想做可信任決策系統的高中生開發者來說,我覺得這個習慣,比第一天就做出一個全自動發文機器更重要。

至少今天,當系統有機會提前報喜時,它沒有這麼做。

等事情真的完成之後,它才改口。

我覺得這是一個不錯的 Day 01。


下一篇
# Day 02|從 ACCEPTED 到 VERIFIED:一則訊息還差多少證據
系列文
《30 天打造自主決策 AI:從事件感知到自我驗證的 ARCI 系統工程》6
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言