<?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>Documentation-Drift on Tarragon</title><link>https://tarrragon.github.io/blog/tags/documentation-drift/</link><description>Recent content in Documentation-Drift on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Fri, 24 Jul 2026 00:00:00 +0800</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/documentation-drift/index.xml" rel="self" type="application/rss+xml"/><item><title>Domain Map 未實作 Bundle 衍生不可執行工作項目</title><link>https://tarrragon.github.io/blog/work-log/domain_map_unimplemented_bundle_false_positive/</link><pubDate>Fri, 24 Jul 2026 00:00:00 +0800</pubDate><guid>https://tarrragon.github.io/blog/work-log/domain_map_unimplemented_bundle_false_positive/</guid><description>&lt;p>domain-map 的 bundle 界定表是測試策略、任務派發、對齊度分析的權威依據——表上列了什麼 bundle，下游就對什麼 bundle 建測試、開工作項目。這張表如果混入了程式碼中不存在的概念，下游產出的工作項目在執行時才會發現目標不存在，整條工作鏈從分析到建票到派發全部白費。&lt;/p>
&lt;p>本章處理的判準：bundle 界定表的每一列是否對應到程式碼中實際存在的結構。與&lt;a href="https://tarrragon.github.io/blog/ddd/composition-root-reachability/" data-link-title="組裝層的可達性" data-link-desc="行為測試全綠、功能在實機上沒有入口的失效形態出現時使用。mock 換掉的正是組裝，組裝完成與否在行為測試裡沒有證言；把可達性當成組裝層的不變式，在測試、發版與設計文件各給一個強制點。">組裝層的可達性&lt;/a>互補——組裝層可達性守的是「已實作的功能有沒有接到入口」，本章守的是「文件宣告的結構有沒有在程式碼中存在」。兩者的共同根因是宣告與現況的落差，差別在觀察面：前者從程式碼往入口看，後者從文件往程式碼看。&lt;/p>
&lt;h2 id="一個-bundle-的失敗鏈">一個 bundle 的失敗鏈&lt;/h2>
&lt;p>一個專案建立了九份 domain-map，其中 synchronization domain 的 bundle 界定表列出了 &lt;code>PassthroughMerge&lt;/code> 和 &lt;code>TagTreeMerge&lt;/code> 兩個 bundle——來源是規格文件中描述的合併策略分類。分析代理人拿這張表比對測試目錄，發現這兩個 bundle 沒有對應的 unit test，列為測試缺口，建了一張補測試的工作項目。&lt;/p>
&lt;p>執行代理人認領這張工作項目後，用 grep 搜尋目標類別——程式碼中不存在 &lt;code>PassthroughMerge&lt;/code> 和 &lt;code>TagTreeMerge&lt;/code>。實際的合併邏輯在 &lt;code>SyncMergeService&lt;/code> 裡，沒有拆成獨立的策略類別。代理人花了 97k tokens 嘗試後回報失敗。&lt;/p>
&lt;p>事後追溯，失敗鏈有三個斷點：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>階段&lt;/th>
 &lt;th>發生了什麼&lt;/th>
 &lt;th>應該做的驗證&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>產出 domain-map&lt;/td>
 &lt;td>從規格描述反推 bundle 名稱，沒有 &lt;code>grep&lt;/code> 驗證對應類別是否存在&lt;/td>
 &lt;td>&lt;code>ls lib/domains/synchronization/&lt;/code> 確認目標路徑&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>消費 domain-map&lt;/td>
 &lt;td>直接消費 bundle 清單比對測試目錄，沒有二次驗證 bundle 對應的程式碼結構存在&lt;/td>
 &lt;td>&lt;code>grep -r &amp;quot;PassthroughMerge&amp;quot; lib/&lt;/code> 確認類別存在&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>建立工作項目&lt;/td>
 &lt;td>從分析報告的缺口清單建票，沒有對 &lt;code>where.files&lt;/code> 的目標做存在性確認&lt;/td>
 &lt;td>&lt;code>test -f lib/domains/synchronization/passthrough_merge.dart&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>三個斷點獨立發生——任何一個做了驗證都能攔截。但三個都沒做，背後是同一個信任假設：bundle 界定表列出的就是已實作的程式碼結構。&lt;/p>
&lt;h2 id="根因一張表兩種語意">根因：一張表兩種語意&lt;/h2>
&lt;p>bundle 界定表有兩種語意混在同一張表裡：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>語意&lt;/th>
 &lt;th>含義&lt;/th>
 &lt;th>下游用法&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>(a) 已實作&lt;/td>
 &lt;td>對應的類別、目錄、模組在程式碼中存在&lt;/td>
 &lt;td>可以建測試、分析覆蓋度、派發實作任務&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>(b) 規劃中&lt;/td>
 &lt;td>規格描述的概念分層，程式碼中尚未拆為獨立結構&lt;/td>
 &lt;td>不可建測試缺口工作項目；要先建實作工作項目&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>表上沒有區分 (a) 和 (b) 時，下游消費者的合理預設是全部為 (a)——bundle 界定表被定位為「程式碼結構的權威依據」，讀者沒有理由懷疑上面的條目不存在。&lt;/p>
&lt;p>這個混合不是文件「過期」。過期是指文件產出時正確、之後程式碼改了文件沒跟上。這裡的情況是文件產出時就沒驗證——規格描述的概念被直接搬進 bundle 界定表，從來沒有對應過程式碼。漂移在產出階段就發生了。&lt;/p>
&lt;h2 id="判準產出端驗證與消費端驗證">判準：產出端驗證與消費端驗證&lt;/h2>
&lt;h3 id="產出端每個-bundle-附程式碼路徑並驗證存在">產出端：每個 bundle 附程式碼路徑並驗證存在&lt;/h3>
&lt;p>bundle 界定表的每一列寫目標路徑後，跑一次驗證：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 驗證 bundle 目標路徑存在&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">ls lib/domains/synchronization/services/sync_merge_service.dart
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="c1"># 存在 → 已實作&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">ls lib/domains/synchronization/services/passthrough_merge.dart
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">&lt;span class="c1"># 不存在 → 標「規劃中」&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>驗證的對象是目標路徑欄位已經寫好的路徑——不需要額外設計，只需要對已填寫的路徑跑一次 &lt;code>ls&lt;/code> 或 &lt;code>grep&lt;/code>。&lt;/p>
&lt;h3 id="加一欄實作狀態">加一欄：實作狀態&lt;/h3>
&lt;p>在 bundle 界定表加一欄「實作狀態」，值只有兩種：「已實作」或「規劃中」。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-markdown" data-lang="markdown">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">| Bundle | 分類 | 目標路徑 | 測試層 | 實作狀態 |
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">|---|---|---|---|---|
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">| SyncMergeService | domain service | &lt;span class="sb">`lib/domains/sync/services/`&lt;/span> | unit | 已實作 |
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">| PassthroughMerge | domain service | &lt;span class="sb">`lib/domains/sync/strategies/`&lt;/span> | unit | 規劃中 |
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">| TagTreeMerge | domain service | &lt;span class="sb">`lib/domains/sync/strategies/`&lt;/span> | unit | 規劃中 |&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>這一欄讓消費者在讀表時就能區分，不需要自己去驗證。&lt;/p>
&lt;h3 id="消費端分析前過濾">消費端：分析前過濾&lt;/h3>
&lt;p>消費 domain-map 做測試對齊或缺口分析時，前置步驟過濾掉「規劃中」的 bundle：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">1. 讀取 bundle 界定表
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">2. 過濾：只保留「已實作」的 bundle
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl"> （或表中無實作狀態欄時，逐個 grep 驗證目標路徑存在）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">3. 對過濾後的清單執行分析&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>消費端驗證是防禦性措施——產出端做對了就不需要；但產出端的驗證品質不由消費端控制，所以消費端保留自己的檢查。&lt;/p>
&lt;h2 id="兩個專案的規模差異">兩個專案的規模差異&lt;/h2>
&lt;p>同一個框架的兩個專案在同一週內建立 domain-map：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>維度&lt;/th>
 &lt;th>專案 A（移動應用，v0.38）&lt;/th>
 &lt;th>專案 B（瀏覽器擴充，v1.6）&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>bundle 總數&lt;/td>
 &lt;td>~120&lt;/td>
 &lt;td>113&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>「規劃中」數&lt;/td>
 &lt;td>2（sync domain）&lt;/td>
 &lt;td>0&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>false positive 工作項目&lt;/td>
 &lt;td>1（97k tokens 白費）&lt;/td>
 &lt;td>0&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>專案 B 的 113 個 bundle 全部驗證為已實作——這不代表驗證是多餘的。專案 B 是成熟專案，功能已全部實作；專案 A 是開發中專案，規格描述領先於實作，混合的機率更高。&lt;/p></description><content:encoded><![CDATA[<p>domain-map 的 bundle 界定表是測試策略、任務派發、對齊度分析的權威依據——表上列了什麼 bundle，下游就對什麼 bundle 建測試、開工作項目。這張表如果混入了程式碼中不存在的概念，下游產出的工作項目在執行時才會發現目標不存在，整條工作鏈從分析到建票到派發全部白費。</p>
<p>本章處理的判準：bundle 界定表的每一列是否對應到程式碼中實際存在的結構。與<a href="/blog/ddd/composition-root-reachability/" data-link-title="組裝層的可達性" data-link-desc="行為測試全綠、功能在實機上沒有入口的失效形態出現時使用。mock 換掉的正是組裝，組裝完成與否在行為測試裡沒有證言；把可達性當成組裝層的不變式，在測試、發版與設計文件各給一個強制點。">組裝層的可達性</a>互補——組裝層可達性守的是「已實作的功能有沒有接到入口」，本章守的是「文件宣告的結構有沒有在程式碼中存在」。兩者的共同根因是宣告與現況的落差，差別在觀察面：前者從程式碼往入口看，後者從文件往程式碼看。</p>
<h2 id="一個-bundle-的失敗鏈">一個 bundle 的失敗鏈</h2>
<p>一個專案建立了九份 domain-map，其中 synchronization domain 的 bundle 界定表列出了 <code>PassthroughMerge</code> 和 <code>TagTreeMerge</code> 兩個 bundle——來源是規格文件中描述的合併策略分類。分析代理人拿這張表比對測試目錄，發現這兩個 bundle 沒有對應的 unit test，列為測試缺口，建了一張補測試的工作項目。</p>
<p>執行代理人認領這張工作項目後，用 grep 搜尋目標類別——程式碼中不存在 <code>PassthroughMerge</code> 和 <code>TagTreeMerge</code>。實際的合併邏輯在 <code>SyncMergeService</code> 裡，沒有拆成獨立的策略類別。代理人花了 97k tokens 嘗試後回報失敗。</p>
<p>事後追溯，失敗鏈有三個斷點：</p>
<table>
  <thead>
      <tr>
          <th>階段</th>
          <th>發生了什麼</th>
          <th>應該做的驗證</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>產出 domain-map</td>
          <td>從規格描述反推 bundle 名稱，沒有 <code>grep</code> 驗證對應類別是否存在</td>
          <td><code>ls lib/domains/synchronization/</code> 確認目標路徑</td>
      </tr>
      <tr>
          <td>消費 domain-map</td>
          <td>直接消費 bundle 清單比對測試目錄，沒有二次驗證 bundle 對應的程式碼結構存在</td>
          <td><code>grep -r &quot;PassthroughMerge&quot; lib/</code> 確認類別存在</td>
      </tr>
      <tr>
          <td>建立工作項目</td>
          <td>從分析報告的缺口清單建票，沒有對 <code>where.files</code> 的目標做存在性確認</td>
          <td><code>test -f lib/domains/synchronization/passthrough_merge.dart</code></td>
      </tr>
  </tbody>
</table>
<p>三個斷點獨立發生——任何一個做了驗證都能攔截。但三個都沒做，背後是同一個信任假設：bundle 界定表列出的就是已實作的程式碼結構。</p>
<h2 id="根因一張表兩種語意">根因：一張表兩種語意</h2>
<p>bundle 界定表有兩種語意混在同一張表裡：</p>
<table>
  <thead>
      <tr>
          <th>語意</th>
          <th>含義</th>
          <th>下游用法</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>(a) 已實作</td>
          <td>對應的類別、目錄、模組在程式碼中存在</td>
          <td>可以建測試、分析覆蓋度、派發實作任務</td>
      </tr>
      <tr>
          <td>(b) 規劃中</td>
          <td>規格描述的概念分層，程式碼中尚未拆為獨立結構</td>
          <td>不可建測試缺口工作項目；要先建實作工作項目</td>
      </tr>
  </tbody>
</table>
<p>表上沒有區分 (a) 和 (b) 時，下游消費者的合理預設是全部為 (a)——bundle 界定表被定位為「程式碼結構的權威依據」，讀者沒有理由懷疑上面的條目不存在。</p>
<p>這個混合不是文件「過期」。過期是指文件產出時正確、之後程式碼改了文件沒跟上。這裡的情況是文件產出時就沒驗證——規格描述的概念被直接搬進 bundle 界定表，從來沒有對應過程式碼。漂移在產出階段就發生了。</p>
<h2 id="判準產出端驗證與消費端驗證">判準：產出端驗證與消費端驗證</h2>
<h3 id="產出端每個-bundle-附程式碼路徑並驗證存在">產出端：每個 bundle 附程式碼路徑並驗證存在</h3>
<p>bundle 界定表的每一列寫目標路徑後，跑一次驗證：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 驗證 bundle 目標路徑存在</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">ls lib/domains/synchronization/services/sync_merge_service.dart
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c1"># 存在 → 已實作</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl">ls lib/domains/synchronization/services/passthrough_merge.dart
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="c1"># 不存在 → 標「規劃中」</span></span></span></code></pre></div><p>驗證的對象是目標路徑欄位已經寫好的路徑——不需要額外設計，只需要對已填寫的路徑跑一次 <code>ls</code> 或 <code>grep</code>。</p>
<h3 id="加一欄實作狀態">加一欄：實作狀態</h3>
<p>在 bundle 界定表加一欄「實作狀態」，值只有兩種：「已實作」或「規劃中」。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="ln">1</span><span class="cl">| Bundle | 分類 | 目標路徑 | 測試層 | 實作狀態 |
</span></span><span class="line"><span class="ln">2</span><span class="cl">|---|---|---|---|---|
</span></span><span class="line"><span class="ln">3</span><span class="cl">| SyncMergeService | domain service | <span class="sb">`lib/domains/sync/services/`</span> | unit | 已實作 |
</span></span><span class="line"><span class="ln">4</span><span class="cl">| PassthroughMerge | domain service | <span class="sb">`lib/domains/sync/strategies/`</span> | unit | 規劃中 |
</span></span><span class="line"><span class="ln">5</span><span class="cl">| TagTreeMerge | domain service | <span class="sb">`lib/domains/sync/strategies/`</span> | unit | 規劃中 |</span></span></code></pre></div><p>這一欄讓消費者在讀表時就能區分，不需要自己去驗證。</p>
<h3 id="消費端分析前過濾">消費端：分析前過濾</h3>
<p>消費 domain-map 做測試對齊或缺口分析時，前置步驟過濾掉「規劃中」的 bundle：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">1. 讀取 bundle 界定表
</span></span><span class="line"><span class="ln">2</span><span class="cl">2. 過濾：只保留「已實作」的 bundle
</span></span><span class="line"><span class="ln">3</span><span class="cl">   （或表中無實作狀態欄時，逐個 grep 驗證目標路徑存在）
</span></span><span class="line"><span class="ln">4</span><span class="cl">3. 對過濾後的清單執行分析</span></span></code></pre></div><p>消費端驗證是防禦性措施——產出端做對了就不需要；但產出端的驗證品質不由消費端控制，所以消費端保留自己的檢查。</p>
<h2 id="兩個專案的規模差異">兩個專案的規模差異</h2>
<p>同一個框架的兩個專案在同一週內建立 domain-map：</p>
<table>
  <thead>
      <tr>
          <th>維度</th>
          <th>專案 A（移動應用，v0.38）</th>
          <th>專案 B（瀏覽器擴充，v1.6）</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>bundle 總數</td>
          <td>~120</td>
          <td>113</td>
      </tr>
      <tr>
          <td>「規劃中」數</td>
          <td>2（sync domain）</td>
          <td>0</td>
      </tr>
      <tr>
          <td>false positive 工作項目</td>
          <td>1（97k tokens 白費）</td>
          <td>0</td>
      </tr>
  </tbody>
</table>
<p>專案 B 的 113 個 bundle 全部驗證為已實作——這不代表驗證是多餘的。專案 B 是成熟專案，功能已全部實作；專案 A 是開發中專案，規格描述領先於實作，混合的機率更高。</p>
<p>驗證的成本與 bundle 數量成線性關係（每個 bundle 一次 <code>ls</code>），false positive 的成本是非線性的（整條分析、建票、派發、執行鏈白費）。成熟專案的驗證結果全是「已實作」、看起來像浪費，但這是驗證的正確結果而非多餘的步驟——跟測試全綠是正確結果而非多餘的測試同理。</p>
<h2 id="一般化設計文件與程式碼的漂移管理">一般化：設計文件與程式碼的漂移管理</h2>
<p>domain-map 的 bundle 驗證是一個更普遍模式的特例：設計文件描述的結構與程式碼的現況之間存在漂移，漂移需要被管理而非假設不存在。</p>
<p>三個判準把這個模式從 domain-map 擴展到其他設計文件：</p>
<h3 id="判準一指向程式碼的宣告用工具驗證目標存在">判準一：指向程式碼的宣告用工具驗證目標存在</h3>
<p>「指向程式碼的宣告」包括 bundle 的目標路徑、spec 引用的類別名稱、架構圖標示的模組路徑。驗證手段是 <code>ls</code>、<code>grep</code>、<code>test -f</code>——工具比印象可靠，因為印象的驗證是「我記得這個類別存在」，工具的驗證是「這個路徑在檔案系統中有沒有對應的 entry」。</p>
<h3 id="判準二文件產出時就驗證不等消費時才驗證">判準二：文件產出時就驗證，不等消費時才驗證</h3>
<p>漂移有兩種形態：產出時就不正確（本章的案例）、產出後程式碼改了文件沒跟上（過期問題）。產出端驗證攔第一種，定期重新驗證攔第二種。只在消費端驗證等於把品質責任推給讀者——讀者的數量遠大於作者的數量，在讀者端分散驗證的總成本高於在作者端集中驗證。</p>
<h3 id="判準三語意差異用顯式欄位區分不靠讀者推斷">判準三：語意差異用顯式欄位區分，不靠讀者推斷</h3>
<p>bundle 界定表的「已實作」和「規劃中」是兩種不同的語意，但原始設計沒有欄位區分。讀者需要自己去驗證才能區分——這是一個設計缺口，不是讀者的責任。加一欄讓語意顯式化，消除了讀者需要推斷的負擔。</p>
<h2 id="邊界">邊界</h2>
<p>本章的判準適用於被下游消費者當作「程式碼結構權威依據」的設計文件。不適用的情況：</p>
<ul>
<li><strong>純概念文件</strong>（如技術提案、未來規劃）：讀者預期內容是規劃而非現況，不需要驗證</li>
<li><strong>文件與程式碼完全解耦</strong>（如使用者手冊）：指向的是操作流程而非程式碼結構</li>
<li><strong>產出與消費是同一人同一時間</strong>（如個人筆記）：作者即讀者，隱含知識不會造成誤判</li>
</ul>
<p>判準適用時，驗證的粒度跟文件的消費方式匹配：bundle 界定表被逐列消費，驗證就逐列做；架構圖被整體消費，驗證就對圖上每個模組做。</p>
<h2 id="與其他章節的關係">與其他章節的關係</h2>
<ul>
<li><a href="/blog/ddd/composition-root-reachability/" data-link-title="組裝層的可達性" data-link-desc="行為測試全綠、功能在實機上沒有入口的失效形態出現時使用。mock 換掉的正是組裝，組裝完成與否在行為測試裡沒有證言；把可達性當成組裝層的不變式，在測試、發版與設計文件各給一個強制點。">組裝層的可達性</a>：組裝層守「程式碼到入口」的連通性，本章守「文件到程式碼」的一致性。兩者的共同上游判準是「宣告的東西要能被驗證為存在」</li>
<li><a href="/blog/ddd/invariant-enforcement-layers/" data-link-title="不變式的強制層次" data-link-desc="業務約束落在文件層、型別層、執行層的差異與代價：違反時是靜默、編譯失敗還是當場拒絕。含不變式被撞時「需求違規 vs 約束錯形」的分辨、存在條件與輸入品質的分層邊界。">不變式的強制層次</a>：bundle 的實作狀態是一種文件層的不變式——「已實作」的 bundle 必須有對應的程式碼路徑。不變式的強制方式是產出時的 <code>ls</code>/<code>grep</code> 驗證，跟程式碼中不變式的強制方式（型別系統、建構子驗證）同源</li>
<li><a href="/blog/ddd/cross-boundary-reference-ownership/" data-link-title="跨邊界參照與狀態所有權" data-link-desc="下游持有上游資料的 id、操作靠這個 id 回寫時：上游的哪些操作會讓 id 死亡、有沒有跨操作不變的穩定身份、身份轉移後本端的狀態搬不搬家——參照設計的判準與遷移分工">跨邊界參照與狀態所有權</a>：bundle 名稱是 domain-map 對程式碼的參照，「程式碼有沒有這個名稱」是參照有效性的問題。判準一的驗證跟該章的「參照有效性三問」第一問（「對方的哪些操作會讓這個參照死亡？」）同源</li>
</ul>
]]></content:encoded></item></channel></rss>