<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>契約 on Tarragon</title><link>https://tarrragon.github.io/blog/tags/%E5%A5%91%E7%B4%84/</link><description>Recent content in 契約 on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Thu, 11 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/%E5%A5%91%E7%B4%84/index.xml" rel="self" type="application/rss+xml"/><item><title>多階段流程的 artifact 欄位契約：下游宣稱的輸入要能從上游產出推導、推導規則要明文</title><link>https://tarrragon.github.io/blog/report/pipeline-artifact-field-contract/</link><pubDate>Thu, 11 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/report/pipeline-artifact-field-contract/</guid><description>&lt;h2 id="結論">結論&lt;/h2>
&lt;p>「Stage B 以 Stage A 的清單為輸入」— 這句話讀起來像契約、實際上常常只是相鄰。它成立的條件在欄位層：&lt;strong>下游輸入的每一欄、要能對到上游產出的某個欄、或一條明文的推導規則&lt;/strong> — B 需要的每欄、A 的表裡有、或文件寫明「B 的欄 y 由 A 的欄 x 依規則 R 推導」。多階段流程（訪談協議、ETL、表單審批、CI pipeline）的每個交接處都適用這條檢查。&lt;/p>
&lt;p>缺口的形態很安靜：A 的表七欄、B 要求的第八種資訊不在七欄裡、也沒有任何地方說明從哪來 — 執行者到了 B 才發現缺、回頭從 A 的欄位自行腦補。可推導時每個執行者推得不一樣、不可推導時就空著或亂填；而缺的欄位往往正是流程分支的開關（「失敗語意 = 不可丟」觸發整個 durable 機制）、開關欄自由心證等於分支隨機。&lt;/p>
&lt;h2 id="能推導跟有規則是兩回事">能推導、跟有規則、是兩回事&lt;/h2>
&lt;p>「語意上推得出來」會讓設計者誤以為不用寫：失敗語意「顯然」能從失敗情境跟風險欄看出來。沒有明文規則時、三個執行者會用三種標準推、而且都覺得自己推得有道理。&lt;/p>
&lt;p>缺口在設計期隱形的原因是接縫沒有 owner：A 的表為 A 的目的設計（盤點操作）、B 的輸入為 B 的目的宣告（標 event 語意）、每一份單獨 review 都通過 — A 的作者覺得交付了、B 的作者覺得宣告了、欄位對不對得上沒有掛在任何人名下。浮現的唯一方法是把 B 的輸入逐欄對 A 的產出走一遍。&lt;/p>
&lt;h2 id="反模式與修法">反模式與修法&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>反模式&lt;/th>
 &lt;th>修法&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>下游欄位靠執行者從上游「看得出來」&lt;/td>
 &lt;td>寫明推導規則：「欄 y：上游欄 x 含金流 / 合約 / 通知義務 → 不可丟」&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>在上游表直接加欄、服務下游需求&lt;/td>
 &lt;td>可以、但要判斷：欄位屬於上游的語意就加欄、屬於下游的加工就寫推導規則 — 上游表塞滿下游欄位會失去自己的焦點&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>交接缺口出現時補一句「參考上游自行判斷」&lt;/td>
 &lt;td>這是把自由心證制度化、不是修復&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>只修這一個欄、不掃其他接縫&lt;/td>
 &lt;td>一個缺口浮現時、對全部階段交接跑一次逐欄走查 — 缺口成因（分開設計）作用在每個接縫上&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>逐欄走查的操作：列出下游輸入格式的欄位清單、每欄標注來源 —「上游欄位直給」「明文推導規則」「缺」三種狀態、「缺」逐個補。同一條契約在機器管線同樣成立：CI 的 deploy stage 宣稱以 build artifact 為輸入、需要的 version tag 卻沒有任何 stage 產 — 差別只在機器管線會當場報錯、文件協議的缺口靜默到執行者卡住那天。&lt;/p>
&lt;h2 id="跟其他抽象層原則的關係">跟其他抽象層原則的關係&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/report/review-miss-diagnose-design-vs-execution-gap/" data-link-title="Review 漏抓先分 design gap 與 execution gap、再決定改框架還是改執行" data-link-desc="Review 漏抓某類問題時，有兩個不同成因：design gap（框架根本沒有對應 frame）跟 execution gap（框架有 frame、但 reviewer 沒跑）。修法相反 —— design gap 要改框架（補 frame / keyword）、execution gap 要改執行（真的跑完該跑的輪）。診斷前先分清：把 execution gap 誤判成 design gap 會 framework bloat（一直加 frame 卻沒解決偷跑子集）、把 design gap 誤判成 execution gap 會永遠漏同類。常見陷阱是『加 keyword』感覺像進步、但對沒跑的輪毫無幫助。">#153 Review 漏抓先分 design gap 與 execution gap&lt;/a>：#153 立卡情境是 review 流程的漏抓、這裡把它的診斷分流借到流程設計：執行者標不出失敗語意、不是不認真、是設計沒給推導規則 — design gap、修法在文件、不在叮嚀執行者。&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/report/verification-timeline-checkpoints/" data-link-title="驗收的時間軸：四個 checkpoint" data-link-desc="驗收不是單一動作、是分散在四個時點（寫之前 / 開發中 / ship 前 / ship 後）的累積判斷。每個 checkpoint 能 catch 不同類型的失敗、成本不同。早期 checkpoint 抓越多、晚期 checkpoint 越輕鬆。實務上常常 collapse 成「寫的時候 &amp;#43; ship 後出問題才修」、跳過寫之前 / ship 前。">#68 驗收的時間軸：四個 checkpoint&lt;/a>：階段交接處是天然的驗收 checkpoint — 逐欄走查就是交接處的驗收動作、在「寫之前」的 checkpoint 跑一次、比執行者在第三階段卡住才回頭便宜。&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/report/single-source-of-truth/" data-link-title="Single Source of Truth：值的住址只能有一處" data-link-desc="同一個值（CSS token、視覺基準、runtime 量測）的權威來源只能有一個位置 — 多源時會分歧、會漏改、會讓讀者不知道哪個生效。本文是 #3 / #26 / #27 三篇實作的共同抽象。">#44 Single Source of Truth&lt;/a>：推導規則本身要有單一明文位置 — 沒有明文規則時、規則存在於每個執行者腦中、是 N 份互不一致的隱性源；寫下來不只是溝通、是把規則收斂成單源。&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/report/decision-table-conflict-reveals-missing-dimension/" data-link-title="決策表兩列同時命中且結論相反：缺的是一個上游區分維度" data-link-desc="判讀表 / 決策表的兩列規則被同一個真實案例同時命中、且指向相反結論時、問題通常出在表外：案例承載著兩種身分、而表缺少把身分拆開的上游維度 — 修法是補前置澄清問、把維度抬到表之前；拆不出身分的矛盾才是規則真衝突、回表內改規則。偵測方法是用真實案例 dry-run、不是逐列檢查 — 單列都正確的表仍可能整體矛盾。">#158 決策表兩列同時命中且結論相反&lt;/a>：同一族的「組合失效」— #158 是規則之間的矛盾、本卡是階段之間的缺口、偵測都要跨單元走查（#158 靠真實案例 dry-run、本卡靠逐欄對照）而不是單元內檢查；兩者常在同一次旅程模擬中被一起抓到。&lt;/li>
&lt;/ul>
&lt;h2 id="觸發-case">觸發 case&lt;/h2>
&lt;p>一個訪談協議的操作盤點階段產出七欄表（操作 / 角色 / 主情境 / 失敗情境 / 風險類型 / 前端引導 / 後端防護）、domain / event 切分階段的 event catalog 要求每個 event 標「失敗語意（可丟 / 不可丟）」— 且這一欄是 async-queue 維度升級為必展開的開關。讀者旅程 reviewer dry-run 時發現：七欄裡沒有失敗語意、兩份 reference 也都沒說明從哪推導、「runtime 要從失敗情境自行推導、可推但容易漏標」。修復落在 event catalog 的產出格式旁、把推導規則寫成明文 —「操作牽涉金流、合約或通知義務 → 它的 event 不可丟；event 只驅動可重算的衍生結果 → 可丟」— 上游的表一欄都沒加。&lt;/p></description><content:encoded><![CDATA[<h2 id="結論">結論</h2>
<p>「Stage B 以 Stage A 的清單為輸入」— 這句話讀起來像契約、實際上常常只是相鄰。它成立的條件在欄位層：<strong>下游輸入的每一欄、要能對到上游產出的某個欄、或一條明文的推導規則</strong> — B 需要的每欄、A 的表裡有、或文件寫明「B 的欄 y 由 A 的欄 x 依規則 R 推導」。多階段流程（訪談協議、ETL、表單審批、CI pipeline）的每個交接處都適用這條檢查。</p>
<p>缺口的形態很安靜：A 的表七欄、B 要求的第八種資訊不在七欄裡、也沒有任何地方說明從哪來 — 執行者到了 B 才發現缺、回頭從 A 的欄位自行腦補。可推導時每個執行者推得不一樣、不可推導時就空著或亂填；而缺的欄位往往正是流程分支的開關（「失敗語意 = 不可丟」觸發整個 durable 機制）、開關欄自由心證等於分支隨機。</p>
<h2 id="能推導跟有規則是兩回事">能推導、跟有規則、是兩回事</h2>
<p>「語意上推得出來」會讓設計者誤以為不用寫：失敗語意「顯然」能從失敗情境跟風險欄看出來。沒有明文規則時、三個執行者會用三種標準推、而且都覺得自己推得有道理。</p>
<p>缺口在設計期隱形的原因是接縫沒有 owner：A 的表為 A 的目的設計（盤點操作）、B 的輸入為 B 的目的宣告（標 event 語意）、每一份單獨 review 都通過 — A 的作者覺得交付了、B 的作者覺得宣告了、欄位對不對得上沒有掛在任何人名下。浮現的唯一方法是把 B 的輸入逐欄對 A 的產出走一遍。</p>
<h2 id="反模式與修法">反模式與修法</h2>
<table>
  <thead>
      <tr>
          <th>反模式</th>
          <th>修法</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>下游欄位靠執行者從上游「看得出來」</td>
          <td>寫明推導規則：「欄 y：上游欄 x 含金流 / 合約 / 通知義務 → 不可丟」</td>
      </tr>
      <tr>
          <td>在上游表直接加欄、服務下游需求</td>
          <td>可以、但要判斷：欄位屬於上游的語意就加欄、屬於下游的加工就寫推導規則 — 上游表塞滿下游欄位會失去自己的焦點</td>
      </tr>
      <tr>
          <td>交接缺口出現時補一句「參考上游自行判斷」</td>
          <td>這是把自由心證制度化、不是修復</td>
      </tr>
      <tr>
          <td>只修這一個欄、不掃其他接縫</td>
          <td>一個缺口浮現時、對全部階段交接跑一次逐欄走查 — 缺口成因（分開設計）作用在每個接縫上</td>
      </tr>
  </tbody>
</table>
<p>逐欄走查的操作：列出下游輸入格式的欄位清單、每欄標注來源 —「上游欄位直給」「明文推導規則」「缺」三種狀態、「缺」逐個補。同一條契約在機器管線同樣成立：CI 的 deploy stage 宣稱以 build artifact 為輸入、需要的 version tag 卻沒有任何 stage 產 — 差別只在機器管線會當場報錯、文件協議的缺口靜默到執行者卡住那天。</p>
<h2 id="跟其他抽象層原則的關係">跟其他抽象層原則的關係</h2>
<ul>
<li><a href="/blog/report/review-miss-diagnose-design-vs-execution-gap/" data-link-title="Review 漏抓先分 design gap 與 execution gap、再決定改框架還是改執行" data-link-desc="Review 漏抓某類問題時，有兩個不同成因：design gap（框架根本沒有對應 frame）跟 execution gap（框架有 frame、但 reviewer 沒跑）。修法相反 —— design gap 要改框架（補 frame / keyword）、execution gap 要改執行（真的跑完該跑的輪）。診斷前先分清：把 execution gap 誤判成 design gap 會 framework bloat（一直加 frame 卻沒解決偷跑子集）、把 design gap 誤判成 execution gap 會永遠漏同類。常見陷阱是『加 keyword』感覺像進步、但對沒跑的輪毫無幫助。">#153 Review 漏抓先分 design gap 與 execution gap</a>：#153 立卡情境是 review 流程的漏抓、這裡把它的診斷分流借到流程設計：執行者標不出失敗語意、不是不認真、是設計沒給推導規則 — design gap、修法在文件、不在叮嚀執行者。</li>
<li><a href="/blog/report/verification-timeline-checkpoints/" data-link-title="驗收的時間軸：四個 checkpoint" data-link-desc="驗收不是單一動作、是分散在四個時點（寫之前 / 開發中 / ship 前 / ship 後）的累積判斷。每個 checkpoint 能 catch 不同類型的失敗、成本不同。早期 checkpoint 抓越多、晚期 checkpoint 越輕鬆。實務上常常 collapse 成「寫的時候 &#43; ship 後出問題才修」、跳過寫之前 / ship 前。">#68 驗收的時間軸：四個 checkpoint</a>：階段交接處是天然的驗收 checkpoint — 逐欄走查就是交接處的驗收動作、在「寫之前」的 checkpoint 跑一次、比執行者在第三階段卡住才回頭便宜。</li>
<li><a href="/blog/report/single-source-of-truth/" data-link-title="Single Source of Truth：值的住址只能有一處" data-link-desc="同一個值（CSS token、視覺基準、runtime 量測）的權威來源只能有一個位置 — 多源時會分歧、會漏改、會讓讀者不知道哪個生效。本文是 #3 / #26 / #27 三篇實作的共同抽象。">#44 Single Source of Truth</a>：推導規則本身要有單一明文位置 — 沒有明文規則時、規則存在於每個執行者腦中、是 N 份互不一致的隱性源；寫下來不只是溝通、是把規則收斂成單源。</li>
<li><a href="/blog/report/decision-table-conflict-reveals-missing-dimension/" data-link-title="決策表兩列同時命中且結論相反：缺的是一個上游區分維度" data-link-desc="判讀表 / 決策表的兩列規則被同一個真實案例同時命中、且指向相反結論時、問題通常出在表外：案例承載著兩種身分、而表缺少把身分拆開的上游維度 — 修法是補前置澄清問、把維度抬到表之前；拆不出身分的矛盾才是規則真衝突、回表內改規則。偵測方法是用真實案例 dry-run、不是逐列檢查 — 單列都正確的表仍可能整體矛盾。">#158 決策表兩列同時命中且結論相反</a>：同一族的「組合失效」— #158 是規則之間的矛盾、本卡是階段之間的缺口、偵測都要跨單元走查（#158 靠真實案例 dry-run、本卡靠逐欄對照）而不是單元內檢查；兩者常在同一次旅程模擬中被一起抓到。</li>
</ul>
<h2 id="觸發-case">觸發 case</h2>
<p>一個訪談協議的操作盤點階段產出七欄表（操作 / 角色 / 主情境 / 失敗情境 / 風險類型 / 前端引導 / 後端防護）、domain / event 切分階段的 event catalog 要求每個 event 標「失敗語意（可丟 / 不可丟）」— 且這一欄是 async-queue 維度升級為必展開的開關。讀者旅程 reviewer dry-run 時發現：七欄裡沒有失敗語意、兩份 reference 也都沒說明從哪推導、「runtime 要從失敗情境自行推導、可推但容易漏標」。修復落在 event catalog 的產出格式旁、把推導規則寫成明文 —「操作牽涉金流、合約或通知義務 → 它的 event 不可丟；event 只驅動可重算的衍生結果 → 可丟」— 上游的表一欄都沒加。</p>
<h2 id="判讀徵兆">判讀徵兆</h2>
<table>
  <thead>
      <tr>
          <th>徵兆</th>
          <th>該做的事</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>文件寫「以上一階段的產出為輸入」</td>
          <td>逐欄走查：下游每一欄標「直給 / 明文推導 / 缺」</td>
      </tr>
      <tr>
          <td>執行者在中游階段問「這個欄位要填什麼、從哪看」</td>
          <td>當成欄位契約缺口處理、補推導規則、不歸因執行者</td>
      </tr>
      <tr>
          <td>下游有分支開關欄（觸發某機制、決定走哪條路）</td>
          <td>優先檢查 — 開關欄的自由心證代價最高</td>
      </tr>
      <tr>
          <td>同一欄不同執行者填出不同標準的值</td>
          <td>推導規則只存在各人腦中、收斂成明文</td>
      </tr>
  </tbody>
</table>
]]></content:encoded></item></channel></rss>