
Day 13 把兩個可寫入的任務(mutation-capable task)拆進不同工作樹(worktree),解掉「共用中間狀態」的污染。
但 Agent 不會永遠從乾淨 Repository 開始。
真實工作裡更常見的,是工作目錄本來就有尚未提交的變更(dirty working tree):
git status
→ modified files
→ untracked files
→ 某些變更不是這次任務產生的
我一開始最直覺的安全規則是:
看到有未提交變更的工作目錄(dirty working tree)就停。
這很保守,卻很快遇到另一個問題:只要使用者原本就在工作,Agent 幾乎永遠得停。
問題可以再拆成兩層。
Dirty 是狀態;Collision 才是風險判斷。
真正要判斷的不是 Repository 乾不乾淨,而是既有變更與本次 mutation 之間,是否存在行為衝突、歸屬(ownership)不明或高風險依賴。
這條也寫進了 ap-safe-preflight 的前置檢查(preflight)規則:
Pre-existing user changes are evidence, not defects.
preflight 先讀取:
git status
git diff
git diff --cached
relevant untracked files
再建立起始狀態清冊(start-state ledger),把工作狀態至少拆成:
pre-existing user changes
current-task expected changes
stale tests / expectations
unknown or potentially conflicting changes
如果 Agent 一看到既有 diff 就假設它是錯的,最容易做出的「安全動作」反而可能是 reset、revert 或 clean,直接破壞使用者尚未完成的工作。
預設不再是「先清乾淨」,而是:
先證明哪些變更原本就存在,再判斷它們和這次任務有沒有衝突。
這也是 collision 定義最重要的一次修正。
ap-safe-preflight 明確要求:直接衝突(direct collision)指的是既有變更與本次要求的行為(requested behavior)發生實際衝突,或既有變更本身不清楚、只做了一半;不是只要碰到既有使用者變更(existing user change)就算 collision。
假設這次要修改:
src/auth/router.ts
而這個檔案原本就有使用者尚未 commit 的調整。
只看到 path overlap 還不夠判 STOP。
如果既有修改和本次需求可以同時成立,Agent 應該保留既有意圖(intent),只在必要範圍內繞著它修改。
反過來,如果 existing diff 正在把某個 auth rule 改成 A,而本次需求要求 B,這才是直接 collision。這種情況不能靠模型猜哪個 intent 比較新,應該停在那一段並回報衝突。
我現在會把判斷順序寫成:
Path overlap?
↓
Behavior overlap?
↓
Intent clear?
↓
Risk acceptable?
而不是:
dirty?
↓
stop
這個判斷沒有只停在文字規則。
agent-platform/tools/sync-consumer-skills.ps1 在同步 consumer skill 前,會先取得 consumer 已存在的 Git status paths,再拿它們和準備同步的 target prefixes 比對。
核心邏輯很直接:
pre-existing status path
↓
falls inside target sync path?
↓
YES → throw collision
實作會直接擋下:
pre-existing consumer target modification collision
理由不是「consumer repo 不能 dirty」,而是這次 lifecycle 準備寫入的 target,已經有一份不屬於本次 lifecycle 的既有 mutation。
同步工具沒有足夠授權(authority)決定誰該覆蓋誰,因此採取失敗即阻擋(fail closed)。
這讓一個重要分界變得很具體:
unrelated dirty change
≠
target collision
而 repo 還多做了一步:允許把「預期要保留的 dirty paths」明確寫進 ledger。
new-shared-skill-preflight-evidence.ps1 的 ExpectedConsumerDirtyPaths 預設是空陣列;如果 consumer 本來就有需要保留的修改,就必須明確列出,而不是假裝 worktree 是 clean。
README 甚至直接寫明:
consumer clean
→ omit ExpectedConsumerDirtyPaths
consumer has preserved changes
→ provide a non-empty explicit ledger
這個設計把「容忍 dirty」從一句原則變成可驗證契約。
new-shared-skill-preflight-evidence.ps1 同時記錄 HEAD、實際 changed paths、預期 changed paths 與 targetCollision。如果 Agent 開始工作後,實際 dirty paths 和 ledger 不一致,preflight validation 直接擋下:
changed paths do not match expected evidence
也就是說,允許既有變更存在,不等於允許 working state 任意漂移。
Collision Check 到這裡才從「我看過了,應該沒問題」,變成一個可重跑的問題:
Agent 開始工作前,Repository 到底已經有哪些變更?哪些是預期的?哪些不是?
不是每個 dirty tree 都值得中止。我會先把 mutation 怎麼處理 收斂成三種:
明確 collision / intent unknown
→ STOP
既有變更與本次任務無關
→ AVOID
已知且相容的既有變更
→ PROCEED
這裡有兩條不同的判斷軸:
STOP / AVOID / PROCEED
→ 既有變更要不要碰
FAST / STANDARD / HIGH_RISK
→ 這次需要多深的執行與驗證
AVOID 不等於 escalation。FAST 只有在沒有 target collision、unrelated changed file、unowned change 等阻礙時才成立;條件破壞就記錄原因並提高處理層級,高風險 Evidence 再進入 HIGH_RISK。
例如 working tree 有一個和本次任務無關、但已知是使用者正在做的修改:
mutation strategy
→ AVOID that region
execution / review depth
→ FAST may no longer be eligible
所以「不能走 FAST」不等於「整個任務必須停止」;它只代表自動化信任程度要下降,而既有區域仍應被保留。

適合這些情況:
這些情況下,多問一次比「自動整理乾淨」便宜。
Repository 可以繼續工作,但某些既有區域不屬於這次任務。
例如 working tree 已有:
docs/notes.md modified
assets/cover.png untracked
而本次只修改:
src/auth/router.ts
tests/auth.test.ts
這時可以把 unrelated region 視為 immutable,明確避開,而不是要求使用者先把所有工作 commit 掉。
即使 target 或 adjacent file 已經有修改,只要能確認:
就可以在保留既有變更的前提下繼續。
如果 collision rule 只存在文件裡,我仍然不會太放心。
agent-platform 的負向路徑測試(negative-path tests)有一個 ConsumerCollision scenario。測試會刻意製造 consumer target collision,再執行 lifecycle runner。
預期結果是:
status = BLOCKED
exit = 20
consumer target collision blocked before mutation
而且 canonical 與 consumer fixture snapshot 都必須維持不變。
這個測試證明的不是「Agent 很小心」,而是:
當 target ownership 不清楚時,mutation path 真的會在寫入前被擋下。
到這裡,Collision Check 才從一條建議,變成可驗證的 guardrail。
Collision Check 很適合把客觀資訊固定化:
但有一層不能假裝完全自動化:
這份既有變更到底代表什麼 intent?
File path 可以比對;behavioral ownership 有時仍需要讀 diff、handoff、issue 或最近決策,必要時直接問使用者。
所以 Collision Check 既不是:
if dirty:
stop
也不是:
if no path overlap:
safe
比較接近實際的版本是:
deterministic state collection
+
explicit task scope
+
existing-change ownership
+
semantic overlap decision
前半段盡量固定;後半段只有證據足夠時才繼續。
Day 12|Bounded Scope
→ 被授權改什麼
Day 13|Worktree Isolation
→ 中間 mutation 放在哪裡
Day 14|Collision Check
→ 既有變更哪些可保留、避開,哪些必須停止
三層共同避免兩種誤判:「看得到」不等於「有權改」,dirty 也不等於「不可工作」。
Day 14 最後要回答的是:
既有 mutation 的 intent 是否清楚?本次 mutation 會不會跨過 ownership boundary?
如果 Scope 正確、Worktree 隔離完成、Collision 也已經處理,至少能降低改到不該碰內容的機率。
但這仍然只證明 Agent 在合理邊界裡工作,還沒有證明它做對了。
所以下一階段會把問題從 Authority 換成 Evidence。
Agent 說:
Implemented successfully.
下一個要追問的是:
你實際驗證到哪一層?