<?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>SSoT on Tarragon</title><link>https://tarrragon.github.io/blog/tags/ssot/</link><description>Recent content in SSoT 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/ssot/index.xml" rel="self" type="application/rss+xml"/><item><title>URL slug 必須顯式定義為 fact：跨工具 identifier 用單一定義源</title><link>https://tarrragon.github.io/blog/report/url-slug-must-be-explicit-fact/</link><pubDate>Tue, 28 Apr 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/report/url-slug-must-be-explicit-fact/</guid><description>&lt;h2 id="結論">結論&lt;/h2>
&lt;p>跨工具共用的 identifier（URL slug、API endpoint、route name、檔案 ID）必須&lt;strong>顯式定義在一處 fact&lt;/strong>、不能依賴各工具各自推導。多工具各自推導 = 推導鏈分歧 = silent 失敗（compile / lint 時看不出、跨工具接縫時才爆）。&lt;/p>
&lt;p>具體到 Hugo blog 的 URL slug：&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>Hugo 自動推導&lt;/td>
 &lt;td>&lt;code>title&lt;/code> 經 &lt;code>urlize&lt;/code>&lt;/td>
 &lt;td>runtime build&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>mdtools 字面比對&lt;/td>
 &lt;td>檔名（不含 &lt;code>.md&lt;/code>）&lt;/td>
 &lt;td>pre-commit&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>跨檔連結時的引用值&lt;/td>
 &lt;td>寫作者手動算 / 複製&lt;/td>
 &lt;td>寫作時&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>三個推導鏈 — 寫作者寫 &lt;code>[link](/posts/X/)&lt;/code> 時、X 應該是哪個？沒有 single source 給答案。&lt;/p>
&lt;p>&lt;strong>修法&lt;/strong>：把 slug 從 derivation 升級成 fact — 在 frontmatter 顯式定義 &lt;code>slug: &amp;lt;name&amp;gt;&lt;/code>、跟檔名對齊、所有工具基於此 fact 運作、跨檔連結用此 slug。&lt;/p>
&lt;hr>
&lt;h2 id="為什麼會散落">為什麼會散落&lt;/h2>
&lt;h3 id="各工具的預設行為都合理但不一致">各工具的預設行為都「合理但不一致」&lt;/h3>
&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>Hugo&lt;/td>
 &lt;td>title → slug 推導&lt;/td>
 &lt;td>不寫 slug 也能 build、降低門檻&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>mdtools&lt;/td>
 &lt;td>檔名 = slug&lt;/td>
 &lt;td>字面 lint、不執行 hugo runtime&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>寫作者&lt;/td>
 &lt;td>看心情寫&lt;/td>
 &lt;td>沒規範就靠記憶 / 複製貼上&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>每個決定本身沒錯、合起來形成「&lt;strong>沒有單一真相&lt;/strong>」的狀態。&lt;/p>
&lt;h3 id="hugo-的-urlize-不是純函式">Hugo 的 &lt;code>urlize&lt;/code> 不是純函式&lt;/h3>
&lt;p>Hugo 的 title → slug 推導用 &lt;code>urlize&lt;/code>、規則隨版本演進、對中文 / 全形字元 / 連字符的處理會變。寫的當下推導出來的 slug、未來 hugo 升級後可能變不同 — 這是「&lt;strong>runtime 推導 = 隱性依賴 hugo 版本&lt;/strong>」。&lt;/p>
&lt;p>而 frontmatter 的 &lt;code>slug: &amp;lt;value&amp;gt;&lt;/code> 是字面值、不依賴任何工具的推導邏輯、跨版本穩定。&lt;/p>
&lt;h3 id="能-build-就不寫是便利驅動偏移67">「能 build 就不寫」是便利驅動偏移（&lt;a href="../ease-of-writing-vs-intent-alignment/">#67&lt;/a>）&lt;/h3>
&lt;p>Hugo 不寫 slug 也能 build — 寫作的當下、加 slug 是「多餘工作」、看起來沒收益。便利驅動讓寫作者跳過。但這個便利是&lt;strong>借用未來的成本&lt;/strong> — 跨檔連結時、slug 推導不一致才暴露、那時要付的修復成本遠大於當初寫 slug 的成本。&lt;/p>
&lt;hr>
&lt;h2 id="fact-vs-derivationslug-該是哪一種">Fact vs Derivation：slug 該是哪一種&lt;/h2>
&lt;p>呼應 &lt;a href="../single-source-of-truth/">#44&lt;/a> 的區分：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>類型&lt;/th>
 &lt;th>定義&lt;/th>
 &lt;th>slug 的歸類&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Fact&lt;/strong>&lt;/td>
 &lt;td>設計決定、不能從別處算出&lt;/td>
 &lt;td>slug 應屬此類&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Derivation&lt;/strong>&lt;/td>
 &lt;td>從 fact 計算得出、無自主性&lt;/td>
 &lt;td>slug 不該屬此類&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>slug 必須是 fact&lt;/strong>、不是 derivation。理由：&lt;/p>
&lt;ul>
&lt;li>slug 的「值」是設計選擇 — 用什麼字串作為 URL 一部分、是 SEO / 可讀性 / 穩定性的決定、不該被自動推導左右&lt;/li>
&lt;li>一旦固定後就&lt;strong>不能改&lt;/strong>（改 slug = URL 改 = 外部連結全部死）&lt;/li>
&lt;li>「不能改」+「設計決定」= 應該是 fact&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>hugo 的 title→slug 推導&lt;/strong>：把一個 fact 偽裝成 derivation。表面上看「我只寫 title、slug 自動算出來」、實際上推導出來的 slug 變成了一個&lt;strong>新的 fact&lt;/strong>（一旦發布就不能改）、但這個 fact 的住址不在程式碼裡、在 hugo runtime 裡。&lt;/p></description><content:encoded><![CDATA[<h2 id="結論">結論</h2>
<p>跨工具共用的 identifier（URL slug、API endpoint、route name、檔案 ID）必須<strong>顯式定義在一處 fact</strong>、不能依賴各工具各自推導。多工具各自推導 = 推導鏈分歧 = silent 失敗（compile / lint 時看不出、跨工具接縫時才爆）。</p>
<p>具體到 Hugo blog 的 URL slug：</p>
<table>
  <thead>
      <tr>
          <th>推導鏈</th>
          <th>來源</th>
          <th>觸發時機</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Hugo 自動推導</td>
          <td><code>title</code> 經 <code>urlize</code></td>
          <td>runtime build</td>
      </tr>
      <tr>
          <td>mdtools 字面比對</td>
          <td>檔名（不含 <code>.md</code>）</td>
          <td>pre-commit</td>
      </tr>
      <tr>
          <td>跨檔連結時的引用值</td>
          <td>寫作者手動算 / 複製</td>
          <td>寫作時</td>
      </tr>
  </tbody>
</table>
<p>三個推導鏈 — 寫作者寫 <code>[link](/posts/X/)</code> 時、X 應該是哪個？沒有 single source 給答案。</p>
<p><strong>修法</strong>：把 slug 從 derivation 升級成 fact — 在 frontmatter 顯式定義 <code>slug: &lt;name&gt;</code>、跟檔名對齊、所有工具基於此 fact 運作、跨檔連結用此 slug。</p>
<hr>
<h2 id="為什麼會散落">為什麼會散落</h2>
<h3 id="各工具的預設行為都合理但不一致">各工具的預設行為都「合理但不一致」</h3>
<p>每個工具在自己的領域內都做了「合理的決定」、合起來才產生不一致：</p>
<table>
  <thead>
      <tr>
          <th>工具</th>
          <th>推導決定</th>
          <th>為什麼合理</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Hugo</td>
          <td>title → slug 推導</td>
          <td>不寫 slug 也能 build、降低門檻</td>
      </tr>
      <tr>
          <td>mdtools</td>
          <td>檔名 = slug</td>
          <td>字面 lint、不執行 hugo runtime</td>
      </tr>
      <tr>
          <td>寫作者</td>
          <td>看心情寫</td>
          <td>沒規範就靠記憶 / 複製貼上</td>
      </tr>
  </tbody>
</table>
<p>每個決定本身沒錯、合起來形成「<strong>沒有單一真相</strong>」的狀態。</p>
<h3 id="hugo-的-urlize-不是純函式">Hugo 的 <code>urlize</code> 不是純函式</h3>
<p>Hugo 的 title → slug 推導用 <code>urlize</code>、規則隨版本演進、對中文 / 全形字元 / 連字符的處理會變。寫的當下推導出來的 slug、未來 hugo 升級後可能變不同 — 這是「<strong>runtime 推導 = 隱性依賴 hugo 版本</strong>」。</p>
<p>而 frontmatter 的 <code>slug: &lt;value&gt;</code> 是字面值、不依賴任何工具的推導邏輯、跨版本穩定。</p>
<h3 id="能-build-就不寫是便利驅動偏移67">「能 build 就不寫」是便利驅動偏移（<a href="../ease-of-writing-vs-intent-alignment/">#67</a>）</h3>
<p>Hugo 不寫 slug 也能 build — 寫作的當下、加 slug 是「多餘工作」、看起來沒收益。便利驅動讓寫作者跳過。但這個便利是<strong>借用未來的成本</strong> — 跨檔連結時、slug 推導不一致才暴露、那時要付的修復成本遠大於當初寫 slug 的成本。</p>
<hr>
<h2 id="fact-vs-derivationslug-該是哪一種">Fact vs Derivation：slug 該是哪一種</h2>
<p>呼應 <a href="../single-source-of-truth/">#44</a> 的區分：</p>
<table>
  <thead>
      <tr>
          <th>類型</th>
          <th>定義</th>
          <th>slug 的歸類</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>Fact</strong></td>
          <td>設計決定、不能從別處算出</td>
          <td>slug 應屬此類</td>
      </tr>
      <tr>
          <td><strong>Derivation</strong></td>
          <td>從 fact 計算得出、無自主性</td>
          <td>slug 不該屬此類</td>
      </tr>
  </tbody>
</table>
<p><strong>slug 必須是 fact</strong>、不是 derivation。理由：</p>
<ul>
<li>slug 的「值」是設計選擇 — 用什麼字串作為 URL 一部分、是 SEO / 可讀性 / 穩定性的決定、不該被自動推導左右</li>
<li>一旦固定後就<strong>不能改</strong>（改 slug = URL 改 = 外部連結全部死）</li>
<li>「不能改」+「設計決定」= 應該是 fact</li>
</ul>
<p><strong>hugo 的 title→slug 推導</strong>：把一個 fact 偽裝成 derivation。表面上看「我只寫 title、slug 自動算出來」、實際上推導出來的 slug 變成了一個<strong>新的 fact</strong>（一旦發布就不能改）、但這個 fact 的住址不在程式碼裡、在 hugo runtime 裡。</p>
<hr>
<h2 id="反模式分散的-derivation-鏈">反模式：分散的 derivation 鏈</h2>
<h3 id="多工具各自推導--silent-不一致">多工具各自推導 = silent 不一致</h3>
<p>當多個工具各自從不同 source derive 同一個 identifier、寫的當下都通過、跨工具接縫時才爆：</p>
<table>
  <thead>
      <tr>
          <th>工具 X 看到</th>
          <th>工具 Y 看到</th>
          <th>看到時機</th>
          <th>後果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>一致</td>
          <td>一致</td>
          <td>寫作時</td>
          <td>表面 OK、累積債</td>
      </tr>
      <tr>
          <td>一致</td>
          <td>不一致</td>
          <td>跨工具時</td>
          <td>broken link / build fail</td>
      </tr>
      <tr>
          <td>不一致</td>
          <td>不一致</td>
          <td>多版本時</td>
          <td>升級後新舊推導規則不一致</td>
      </tr>
  </tbody>
</table>
<p><strong>寫的當下看不出</strong>、是這個反模式的核心難處。</p>
<h3 id="規則膨脹誘惑教-mdtools-認-hugo-規則">「規則膨脹」誘惑：教 mdtools 認 hugo 規則</h3>
<p>碰到 mdtools 不認 hugo title 推導時、直覺反應是「教 mdtools 也跑 urlize」。這是<strong>用字面工具模擬行為層</strong>（<a href="../literal-interception-vs-behavioral-refinement/">#82</a> 的反模式）：</p>
<ul>
<li>mdtools 是字面 lint、學會 urlize → 增加實作成本、要追 hugo 版本變動</li>
<li>解決了表面症狀、但根因（slug 是 derivation）沒動</li>
<li>下一個工具（如 search index）加進來、又要再學一次 urlize</li>
</ul>
<p>正解是<strong>消滅 derivation 鏈、把 slug 升成 fact</strong>。每個工具直接讀 fact、不需要學別人的推導規則。</p>
<h3 id="之後再補-slug的-trigger-缺失">「之後再補 slug」的 trigger 缺失</h3>
<p>「先這樣、之後系統性 backfill」是 <a href="../external-trigger-for-high-roi-work/">#72</a> 的典型訊號。沒有 trigger 時、debt 永遠累積：</p>
<ul>
<li>175 篇文章沒 slug、每多寫一篇 debt 多一份</li>
<li>backfill 沒被排上 → 永遠不做</li>
<li>直到某天有人引用中文 title 的文章、broken link 才浮現</li>
</ul>
<p>修法：lint 規則加 <code>missing-slug</code> check、把 trigger 結構性建立（<a href="../escalation-trigger-quantification/">#91</a> 量化 trigger 設計）。</p>
<hr>
<h2 id="修法兩層補強">修法：兩層補強</h2>
<h3 id="規範層解根因">規範層（解根因）</h3>
<p>每篇 content 文章 frontmatter 必須有 <code>slug</code>、值跟檔名對齊（不含副檔名）：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln">1</span><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w"></span><span class="nt">title</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Hugo 部落格支援 Mermaid 流程圖完整實現指南&#34;</span><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w"></span><span class="nt">slug</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;mermaid-gitgraph&#34;</span><span class="w">   </span><span class="c"># 跟檔名 mermaid-gitgraph.md 對齊</span><span class="w">
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="w"></span><span class="nt">date</span><span class="p">:</span><span class="w"> </span><span class="ld">2025-10-08</span><span class="w">
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="w"></span><span class="nn">---</span></span></span></code></pre></div><p>寫好後：</p>
<ul>
<li>Hugo 用 <code>slug:</code> 不再 derive title</li>
<li>mdtools 用檔名比對 frontmatter slug、字面對齊就過</li>
<li>跨檔連結 <code>[...](/posts/mermaid-gitgraph/)</code> 直接基於 slug、不需推算</li>
<li>SSoT 集中在 frontmatter、檔名是 mirror（自動驗證一致性）</li>
</ul>
<h3 id="工具層防呆">工具層（防呆）</h3>
<p>mdtools 加 lint 規則：</p>
<table>
  <thead>
      <tr>
          <th>規則 ID</th>
          <th>檢查</th>
          <th>error / warn</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>L1-missing-slug</td>
          <td>content 文章 frontmatter 缺 slug</td>
          <td>error（強制）</td>
      </tr>
      <tr>
          <td>L1-slug-filename-mismatch</td>
          <td>slug != 檔名 stem</td>
          <td>error</td>
      </tr>
      <tr>
          <td>L2-broken-internal-link</td>
          <td><code>/posts/&lt;slug&gt;/</code> slug 不存在</td>
          <td>error（既有）</td>
      </tr>
  </tbody>
</table>
<p>把問題從「跨檔 link 時 broken」提前到「寫作時就 catch」。</p>
<h3 id="歷史-backfill">歷史 backfill</h3>
<p>175 篇沒 slug 的文章需要 backfill。可寫 script：</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="k">for</span> f in content/posts/*.md content/work-log/*.md content/record/*.md content/report/*.md<span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="nv">slug</span><span class="o">=</span><span class="k">$(</span>basename <span class="s2">&#34;</span><span class="nv">$f</span><span class="s2">&#34;</span> .md<span class="k">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="k">if</span> ! grep -q <span class="s2">&#34;^slug:&#34;</span> <span class="s2">&#34;</span><span class="nv">$f</span><span class="s2">&#34;</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="c1"># 在 date: 後插入 slug: &lt;檔名&gt;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    sed -i.bak <span class="s2">&#34;/^date:/a\\
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="s2">slug: \&#34;</span><span class="nv">$slug</span><span class="s2">\&#34;&#34;</span> <span class="s2">&#34;</span><span class="nv">$f</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">  <span class="k">fi</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="k">done</span></span></span></code></pre></div><p>人工 review 確認 slug 沒衝突、commit。</p>
<hr>
<h2 id="跟其他抽象層原則的關係">跟其他抽象層原則的關係</h2>
<table>
  <thead>
      <tr>
          <th>原則</th>
          <th>關係</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="../single-source-of-truth/">#44 Single Source of Truth</a></td>
          <td><strong>本卡是 #44 在 identifier 維度的具體實例</strong> — slug 散落三處、fact 升級為主修法</td>
      </tr>
      <tr>
          <td><a href="../literal-interception-vs-behavioral-refinement/">#82 字面攔截 vs 行為精煉</a></td>
          <td>mdtools 是字面 lint、hugo urlize 是 runtime 行為 — 兩層之間的 gap 用「教字面學行為」解 = 規則膨脹、正解是消除 derivation</td>
      </tr>
      <tr>
          <td><a href="../ease-of-writing-vs-intent-alignment/">#67 寫作便利度跟意圖對齊反相關</a></td>
          <td>「能 build 就不寫 slug」是便利寫法、「顯式寫 slug」是對齊意圖（不依賴推導）</td>
      </tr>
      <tr>
          <td><a href="../external-trigger-for-high-roi-work/">#72 高 ROI 無外部觸發</a></td>
          <td>「之後系統性補 slug」沒 trigger = 永遠不會做、175 篇累積債就是這條訊號</td>
      </tr>
      <tr>
          <td><a href="../escalation-trigger-quantification/">#91 升級 trigger 的量化設計</a></td>
          <td>補 lint 規則是 trigger、把「應該補 slug」從紀律升級成結構性檢查</td>
      </tr>
      <tr>
          <td><a href="../visual-tool-error-layer-alignment/">#92 視覺手段對齊錯誤層次</a></td>
          <td>同骨：工具的 ceiling（mdtools 字面 vs hugo runtime）超出就 false confidence</td>
      </tr>
  </tbody>
</table>
<p>本卡跟 #82 / #92 共同形成「<strong>工具 ceiling pattern 系列</strong>」 — 每個工具都有能擋的層 / 擋不到的層、跨層之間需要「升級 fact」或「換工具」、不是「教工具學別人的規則」。</p>
<hr>
<h2 id="套用到本系統的-case">套用到本系統的 case</h2>
<h3 id="case-1175-篇-0-slug-的累積債">Case 1：175 篇 0 slug 的累積債</h3>
<p>實證資料（2026-04-28 撤查）：</p>
<table>
  <thead>
      <tr>
          <th>資料夾</th>
          <th>文章數</th>
          <th>有 frontmatter slug</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>posts/</td>
          <td>17</td>
          <td>0</td>
      </tr>
      <tr>
          <td>work-log/</td>
          <td>12</td>
          <td>0</td>
      </tr>
      <tr>
          <td>record/</td>
          <td>53</td>
          <td>0</td>
      </tr>
      <tr>
          <td>report/</td>
          <td>93</td>
          <td>0</td>
      </tr>
      <tr>
          <td><strong>合計</strong></td>
          <td>175</td>
          <td><strong>0</strong></td>
      </tr>
  </tbody>
</table>
<p>每一篇都是潛在的 broken link 觸發點、debt 未爆出來只因為「英文檔名跟 hugo 推導剛好一樣」。</p>
<h3 id="case-2mermaid-流程圖文章的引用-broken">Case 2：mermaid 流程圖文章的引用 broken</h3>
<p>寫 <a href="../visual-tool-error-layer-alignment/">#92</a> 的 case 2 提到 <code>mermaid_gitgraph_type_color_config</code> 文章、想連到既有的 <code>mermaid流程圖.md</code>。實際軌跡：</p>
<ol>
<li>第一直覺：寫 <code>[...](/posts/hugo-部落格支援-mermaid-流程圖完整實現指南/)</code>（hugo 推導出來的 URL）</li>
<li>mdtools L1-broken-link 失敗、它認檔名 <code>mermaid流程圖.md</code></li>
<li>改寫 <code>[...](/posts/mermaid流程圖/)</code>、hugo build 後變 404（因為 hugo 認 title 推導的 slug）</li>
<li>退而求其次：去掉超連結、改純文字提及</li>
</ol>
<p>問題的根本是「mermaid流程圖.md 沒寫 slug」 — fact 缺失、就只能在「mdtools 認的字面」跟「hugo 認的推導」中二選一、兩者都不對。</p>
<p>正解：給 mermaid流程圖.md 補 <code>slug: mermaid-gitgraph</code> 或類似、檔名 rename 對齊、所有工具基於同一 fact。</p>
<h3 id="case-3跨工具-identifier-的通用-pattern">Case 3：跨工具 identifier 的通用 pattern</h3>
<p>不只是 hugo blog — 任何「多工具共用 identifier」的情境都同樣 pattern：</p>
<table>
  <thead>
      <tr>
          <th>領域</th>
          <th>identifier</th>
          <th>散落的推導鏈</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Hugo blog</td>
          <td>URL slug</td>
          <td>檔名 / hugo title / frontmatter</td>
      </tr>
      <tr>
          <td>API server</td>
          <td>endpoint route</td>
          <td>controller path / OpenAPI spec / client SDK</td>
      </tr>
      <tr>
          <td>DB migration</td>
          <td>migration ID</td>
          <td>檔名 / hash / sequence</td>
      </tr>
      <tr>
          <td>Frontend route</td>
          <td>path identifier</td>
          <td>檔案位置 / route config / navigation</td>
      </tr>
      <tr>
          <td>LLM tool name</td>
          <td>tool 名稱</td>
          <td>function name / schema / prompt 引用</td>
      </tr>
  </tbody>
</table>
<p>每一類的修法都一樣：<strong>把 identifier 升成 fact、所有工具基於此 fact</strong>、不要讓各工具各自推導。</p>
<hr>
<h2 id="判讀徵兆">判讀徵兆</h2>
<table>
  <thead>
      <tr>
          <th>訊號</th>
          <th>該做的事</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>「這個 link 為什麼 broken」debug 半天</td>
          <td>推導鏈不一致、檢查 identifier 有沒有顯式 fact</td>
      </tr>
      <tr>
          <td>「教這個工具認另一個工具的規則」</td>
          <td>規則膨脹的開始、正解是消除 derivation</td>
      </tr>
      <tr>
          <td>「能跑就不寫 X 欄位」</td>
          <td>便利驅動、未來會在跨工具接縫爆</td>
      </tr>
      <tr>
          <td>「之後系統性補 backfill」</td>
          <td><a href="../external-trigger-for-high-roi-work/">#72</a> 缺 trigger、會永遠跳過</td>
      </tr>
      <tr>
          <td>兩個工具對同個 ID 算出不同值</td>
          <td>多源 derivation、改成單一 fact</td>
      </tr>
      <tr>
          <td>升級工具版本後 link / route 全壞</td>
          <td>依賴 runtime 推導、推導規則隨版本變</td>
      </tr>
      <tr>
          <td>「我手動算一下這個 slug 應該是什麼」</td>
          <td>identifier 不該需要心算、補 fact</td>
      </tr>
      <tr>
          <td>Lint 不報錯但 production broken</td>
          <td>字面 lint 跟 runtime 行為的 gap、補 lint 規則或補 fact</td>
      </tr>
  </tbody>
</table>
<p><strong>核心</strong>：跨工具共用的 identifier 必須是 fact、不是 derivation。<strong>Derivation 鏈把單一值散落在多工具的推導邏輯裡、寫的當下看不出問題、跨工具接縫才爆 — 而那時候 debt 已經累積到難以集中修</strong>。Fact 升級的成本（每篇加一行 frontmatter）遠小於 derivation 鏈失敗的修復成本（broken link / SEO 損失 / debugging 時間）。</p>
]]></content:encoded></item><item><title>引用章節用語意標題、不用位置編號：編號是結構排列的 derivation、會隨版本漂移</title><link>https://tarrragon.github.io/blog/report/reference-by-semantic-title-not-number/</link><pubDate>Thu, 11 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/report/reference-by-semantic-title-not-number/</guid><description>&lt;h2 id="結論">結論&lt;/h2>
&lt;p>跨段落、跨檔引用一個結構單位（章節、階段、條列項、輪次）時、&lt;strong>引用它的語意標題、不引用它的位置編號&lt;/strong>。「見核心問題」「在操作盤點階段確認」是穩定引用；「見 Stage 3」「Stage 1-3 出現訊號時」是把當下的排列順序寫死進引用點。&lt;/p>
&lt;p>編號可以存在、但只承擔兩個角色：當下閱讀的排序導覽（條列 1、2、3）、跟發布方凍結過的外部 contract（RFC 段號、法條條號）。活文件（會演進的規範、skill、教材、設計文件）的編號是&lt;strong>結構排列的 derivation&lt;/strong> — 插入一個新章節、所有後續編號全部位移、散落各處的引用點卻不會跟著動。&lt;/p>
&lt;p>這條原則同時定義了標題的責任：&lt;strong>每個結構單位都要有說明核心意義的語意標題、讓引用有東西可錨&lt;/strong>。只有編號沒有語意標題的章節（「Stage 3」「第五章」）、等於強迫所有引用者使用會漂移的錨點。&lt;/p>
&lt;hr>
&lt;h2 id="為什麼編號引用會-silent-失效">為什麼編號引用會 silent 失效&lt;/h2>
&lt;h3 id="編號是-derivation引用是複本">編號是 derivation、引用是複本&lt;/h3>
&lt;p>一個章節的編號由「它前面有幾個章節」決定 — 這是排列的衍生值、不是這個章節自身的事實。把「Stage 3」寫進另一個檔案的引用句、等於把這個 derivation 的快照複製出去當 fact 用；結構一變、所有快照同時過期、而且沒有任何機制通知它們過期了。&lt;/p>
&lt;h3 id="失效模式比-broken-link-更糟misdirected不是-dangling">失效模式比 broken link 更糟：misdirected、不是 dangling&lt;/h3>
&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>Broken link（dangling）&lt;/td>
 &lt;td>目標消失&lt;/td>
 &lt;td>工具可掃：link checker 直接報 404&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>編號錯位（misdirected）&lt;/td>
 &lt;td>目標位移、編號被新內容占據&lt;/td>
 &lt;td>工具掃不出來：「Stage 3」字面依然存在、只是指向了別的階段&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>連結斷掉會報錯；編號錯位會&lt;strong>成功解析到錯的內容&lt;/strong>。讀者照著「見 Stage 3」翻過去、看到的是一個真實存在、語意卻完全不同的階段 — 他沒有任何訊號知道引用已經過期。修復也只能靠人工逐處判讀：grep 找得到所有「Stage」字面、但無法判斷哪些語意還對、哪些已經錯位。&lt;/p>
&lt;h3 id="語意標題也會改名--兩種斷裂不同級">語意標題也會改名 — 兩種斷裂不同級&lt;/h3>
&lt;p>語意錨的最強反例是「標題也會改名、改名後所有語意引用一樣過期」。這個攻擊成立一半 — 引用確實會過期、但斷裂的型態與偵測條件完全不同。改名讓舊引用斷成 dangling：「見核心問題」找不到目標、grep 與讀者都判得出引用過期了；編號位移斷成 misdirected：成功解析到錯的內容、無人察覺。更關鍵的差異是操作者在場與否 — 改名是對目標單位的顯式操作、改名者當下就知道該掃引用面、修復可以發生在同一個 commit；編號位移是別處插入章節的副作用、被位移的章節沒有人碰過、它的引用過期沒有任何人在場負責。語意錨輸在「也會變」、贏在「變的時候可偵測、有人在場」。&lt;/p>
&lt;h3 id="時間維度的累積">時間維度的累積&lt;/h3>
&lt;p>寫下引用的當下、編號跟語意完全對得上 — 這正是這個反模式難以自察的原因。漂移發生在後續版本：插入新階段、合併兩章、把一節搬到另一個檔案。文件越活躍、引用點越多、每次重排的人工修復面就越大；漏修一處、就埋下一個 misdirected 引用等讀者踩。&lt;/p>
&lt;hr>
&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>「見 Stage 3」「進 Stage 4 前確認」&lt;/td>
 &lt;td>「見核心問題」「進維度展開前確認」— 用階段的語意名稱&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>「如第 3 點所述」「上述 1-3」&lt;/td>
 &lt;td>重述該點的語意：「如『底線告知協議』所述」「上述三個收斂判準」&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>「詳見第五章」（活文件）&lt;/td>
 &lt;td>「詳見『防護底線清單』章」— 標題即錨點&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>章節只有編號、沒有語意標題（「## Stage 3」）&lt;/td>
 &lt;td>編號與語意並列（「## Stage 3：核心問題」）、引用時取語意半邊&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>條列項被遠處引用（「套用流程的步驟 2」）&lt;/td>
 &lt;td>給該步驟一個名字、或引用時帶語意（「套用流程的『抽 findings』步」）&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>寫作時的判斷次序：先給結構單位一個承載核心意義的標題（這是標題的本職）、編號只作當下排序；引用時一律取語意名稱；引用點離目標越遠（跨檔、跨 surface）、越是只能用語意錨。&lt;/p>
&lt;h3 id="邊界凍結編號是-fact可以引用">邊界：凍結編號是 fact、可以引用&lt;/h3>
&lt;p>發布方承諾編號不變的外部規格、編號本身就是 contract：RFC 的 section number、法條的條號、含版本年份的 ISO 條款（如 ISO 9001:2015 — 跨版改版會重編條款、引用時鎖定版本才算凍結）、已出版書籍的章節。這些編號被凍結成 fact、引用它們反而比引用標題穩定（標題可能在翻譯與再版間變動）。內部活文件想獲得同樣性質、要先付出同樣代價：宣告編號凍結、只加不改 — 多數活文件不值得也做不到、所以預設走語意引用。&lt;/p>
&lt;hr>
&lt;h2 id="跟其他抽象層原則的關係">跟其他抽象層原則的關係&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/report/name-collections-by-role-not-count/" data-link-title="集合命名用角色、不內嵌數量：「核心七問」的七是成員數的 derivation、加一問就全面失真" data-link-desc="「核心七問」「成長六階段」「四大支柱」這類名稱把成員數量烤進名字裡 — 數量是集合當前成員的 derivation、不是集合的語意身分；成員增減時名稱失真、且名稱是被複製最多次的字串、缺陷隨每次引用繁殖。修法：命名只承載角色與層級（核心問題 / 次要問題 / 撞牆階段）、數量讓清單自己呈現。本卡是 #155 的命名端 sibling（#155 修引用端、本卡讓「語意標題是穩定錨」的前提真正成立）、#44 SSoT 在名稱內容的實例、#84 命名檢驗的數量維度。">#156 集合命名用角色、不內嵌數量&lt;/a>：命名端 sibling。本卡假設語意標題是穩定 fact、#156 負責讓這個假設成立 — 「核心七問」這種 count-bearing 標題一半是語意、一半是成員數的 derivation、引用端怎麼修都錨在會漂移的字串上。本卡初版的正面範例就用了「見核心七問」而未察覺、由 #156 抓出 — 兩卡是不同認知層的檢查、單獨跑任一個抓不到另一個的違規。&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>：本卡是 SSoT 在「結構引用」維度的實例。編號是位置的 derivation；把編號寫進多處引用點、等於把 derivation 當 fact 散寫多份複本 — fact（章節的語意身分）只在標題一處、引用就該錨在那裡。&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/report/url-slug-must-be-explicit-fact/" data-link-title="URL slug 必須顯式定義為 fact：跨工具 identifier 用單一定義源" data-link-desc="URL slug 在 Hugo 預設下從 title 自動推導、在 mdtools lint 下從檔名讀、在跨檔連結時又要寫第三個值 — 一個 identifier 散落在三個推導鏈、典型 SSoT 違反。當多個工具共用一個 identifier、推導不一致 = silent broken link。修法：把 slug 從 derivation（runtime 推導）升級成 fact（frontmatter 顯式定義）、檔名 / 連結都基於這個 fact。本卡是 #44 在 toolchain integration 情境的具體實例、是 #82 字面 vs 行為在 identifier 維度的展現。">#93 URL slug 必須顯式定義為 fact&lt;/a>：同屬「引用要錨在 fact」家族。#93 把跨工具 identifier 從推導值升級成顯式 fact；本卡把跨段落引用的錨點從位置推導值（編號）換成語意 fact（標題）。兩卡的失效模式同型：推導鏈分歧、silent 失效、compile / lint 階段看不出來。&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/report/naming-as-iterated-artifact/" data-link-title="Naming 是 iterated artifact：第一個名字幾乎不對、四輪 review 才收斂" data-link-desc="命名（變數 / 函式 / 檔名 / slug / API endpoint）幾乎沒有「一次寫對」的可能：第一個名字基於當下狹窄的 context、會在後續 cross-call-site / grep / 重構中暴露錯位。命名的正確設計是 iterated — 寫第一版 → grep-ability 測試 → cross-call-site 一致性 → impl 洩漏 → 重命名。本卡是 #83 在「命名」場景的特化。">#84 Naming 是 iterated artifact&lt;/a>：標題是名字。本卡要求標題承載可被引用的語意、等於對標題套用 #84 的 cross-call-site 檢驗 — 從引用者的角度看、這個標題單獨出現時讀者知道它指什麼嗎？只有編號的標題在這個檢驗下直接不及格。&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/report/metadata-surface-in-writing-review/" data-link-title="Metadata surface 要納入寫作 review 範圍" data-link-desc="寫作 review 的 surface 包含正文與 metadata surface：title、description、frontmatter、heading、link label、MOC 索引條。正文通過 positive wording 或 multi-pass review 只代表 body surface 收斂；讀者入口與索引入口也要跑同一套 frame，才能讓文章在第一眼、搜尋與跨篇路由上維持同一個概念錨點。">#97 Metadata surface 要納入寫作 review 範圍&lt;/a>：引用句屬於 #97 分類中的 navigation surface（跟 link label、索引條目同層）— 同樣是正文之外、卻直接決定讀者入口正確性的層。重排結構時、review 範圍要把散落各檔的引用句列入掃描面、而不是只改目標檔。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="觸發-case">觸發 case&lt;/h2>
&lt;p>設計一個多階段訪談 skill 時、初版流程四階段、各檔用「Stage 1 的核心七問」「Stage 3 收斂時」互相引用。下一版把流程改成六階段：操作盤點與領域切分插入在前、核心七問從 Stage 1 變成 Stage 3、決策收斂從 Stage 3 變成 Stage 5。&lt;/p></description><content:encoded><![CDATA[<h2 id="結論">結論</h2>
<p>跨段落、跨檔引用一個結構單位（章節、階段、條列項、輪次）時、<strong>引用它的語意標題、不引用它的位置編號</strong>。「見核心問題」「在操作盤點階段確認」是穩定引用；「見 Stage 3」「Stage 1-3 出現訊號時」是把當下的排列順序寫死進引用點。</p>
<p>編號可以存在、但只承擔兩個角色：當下閱讀的排序導覽（條列 1、2、3）、跟發布方凍結過的外部 contract（RFC 段號、法條條號）。活文件（會演進的規範、skill、教材、設計文件）的編號是<strong>結構排列的 derivation</strong> — 插入一個新章節、所有後續編號全部位移、散落各處的引用點卻不會跟著動。</p>
<p>這條原則同時定義了標題的責任：<strong>每個結構單位都要有說明核心意義的語意標題、讓引用有東西可錨</strong>。只有編號沒有語意標題的章節（「Stage 3」「第五章」）、等於強迫所有引用者使用會漂移的錨點。</p>
<hr>
<h2 id="為什麼編號引用會-silent-失效">為什麼編號引用會 silent 失效</h2>
<h3 id="編號是-derivation引用是複本">編號是 derivation、引用是複本</h3>
<p>一個章節的編號由「它前面有幾個章節」決定 — 這是排列的衍生值、不是這個章節自身的事實。把「Stage 3」寫進另一個檔案的引用句、等於把這個 derivation 的快照複製出去當 fact 用；結構一變、所有快照同時過期、而且沒有任何機制通知它們過期了。</p>
<h3 id="失效模式比-broken-link-更糟misdirected不是-dangling">失效模式比 broken link 更糟：misdirected、不是 dangling</h3>
<table>
  <thead>
      <tr>
          <th>失效類型</th>
          <th>觸發</th>
          <th>偵測難度</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Broken link（dangling）</td>
          <td>目標消失</td>
          <td>工具可掃：link checker 直接報 404</td>
      </tr>
      <tr>
          <td>編號錯位（misdirected）</td>
          <td>目標位移、編號被新內容占據</td>
          <td>工具掃不出來：「Stage 3」字面依然存在、只是指向了別的階段</td>
      </tr>
  </tbody>
</table>
<p>連結斷掉會報錯；編號錯位會<strong>成功解析到錯的內容</strong>。讀者照著「見 Stage 3」翻過去、看到的是一個真實存在、語意卻完全不同的階段 — 他沒有任何訊號知道引用已經過期。修復也只能靠人工逐處判讀：grep 找得到所有「Stage」字面、但無法判斷哪些語意還對、哪些已經錯位。</p>
<h3 id="語意標題也會改名--兩種斷裂不同級">語意標題也會改名 — 兩種斷裂不同級</h3>
<p>語意錨的最強反例是「標題也會改名、改名後所有語意引用一樣過期」。這個攻擊成立一半 — 引用確實會過期、但斷裂的型態與偵測條件完全不同。改名讓舊引用斷成 dangling：「見核心問題」找不到目標、grep 與讀者都判得出引用過期了；編號位移斷成 misdirected：成功解析到錯的內容、無人察覺。更關鍵的差異是操作者在場與否 — 改名是對目標單位的顯式操作、改名者當下就知道該掃引用面、修復可以發生在同一個 commit；編號位移是別處插入章節的副作用、被位移的章節沒有人碰過、它的引用過期沒有任何人在場負責。語意錨輸在「也會變」、贏在「變的時候可偵測、有人在場」。</p>
<h3 id="時間維度的累積">時間維度的累積</h3>
<p>寫下引用的當下、編號跟語意完全對得上 — 這正是這個反模式難以自察的原因。漂移發生在後續版本：插入新階段、合併兩章、把一節搬到另一個檔案。文件越活躍、引用點越多、每次重排的人工修復面就越大；漏修一處、就埋下一個 misdirected 引用等讀者踩。</p>
<hr>
<h2 id="反模式與修法">反模式與修法</h2>
<table>
  <thead>
      <tr>
          <th>反模式</th>
          <th>修法</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>「見 Stage 3」「進 Stage 4 前確認」</td>
          <td>「見核心問題」「進維度展開前確認」— 用階段的語意名稱</td>
      </tr>
      <tr>
          <td>「如第 3 點所述」「上述 1-3」</td>
          <td>重述該點的語意：「如『底線告知協議』所述」「上述三個收斂判準」</td>
      </tr>
      <tr>
          <td>「詳見第五章」（活文件）</td>
          <td>「詳見『防護底線清單』章」— 標題即錨點</td>
      </tr>
      <tr>
          <td>章節只有編號、沒有語意標題（「## Stage 3」）</td>
          <td>編號與語意並列（「## Stage 3：核心問題」）、引用時取語意半邊</td>
      </tr>
      <tr>
          <td>條列項被遠處引用（「套用流程的步驟 2」）</td>
          <td>給該步驟一個名字、或引用時帶語意（「套用流程的『抽 findings』步」）</td>
      </tr>
  </tbody>
</table>
<p>寫作時的判斷次序：先給結構單位一個承載核心意義的標題（這是標題的本職）、編號只作當下排序；引用時一律取語意名稱；引用點離目標越遠（跨檔、跨 surface）、越是只能用語意錨。</p>
<h3 id="邊界凍結編號是-fact可以引用">邊界：凍結編號是 fact、可以引用</h3>
<p>發布方承諾編號不變的外部規格、編號本身就是 contract：RFC 的 section number、法條的條號、含版本年份的 ISO 條款（如 ISO 9001:2015 — 跨版改版會重編條款、引用時鎖定版本才算凍結）、已出版書籍的章節。這些編號被凍結成 fact、引用它們反而比引用標題穩定（標題可能在翻譯與再版間變動）。內部活文件想獲得同樣性質、要先付出同樣代價：宣告編號凍結、只加不改 — 多數活文件不值得也做不到、所以預設走語意引用。</p>
<hr>
<h2 id="跟其他抽象層原則的關係">跟其他抽象層原則的關係</h2>
<ul>
<li><a href="/blog/report/name-collections-by-role-not-count/" data-link-title="集合命名用角色、不內嵌數量：「核心七問」的七是成員數的 derivation、加一問就全面失真" data-link-desc="「核心七問」「成長六階段」「四大支柱」這類名稱把成員數量烤進名字裡 — 數量是集合當前成員的 derivation、不是集合的語意身分；成員增減時名稱失真、且名稱是被複製最多次的字串、缺陷隨每次引用繁殖。修法：命名只承載角色與層級（核心問題 / 次要問題 / 撞牆階段）、數量讓清單自己呈現。本卡是 #155 的命名端 sibling（#155 修引用端、本卡讓「語意標題是穩定錨」的前提真正成立）、#44 SSoT 在名稱內容的實例、#84 命名檢驗的數量維度。">#156 集合命名用角色、不內嵌數量</a>：命名端 sibling。本卡假設語意標題是穩定 fact、#156 負責讓這個假設成立 — 「核心七問」這種 count-bearing 標題一半是語意、一半是成員數的 derivation、引用端怎麼修都錨在會漂移的字串上。本卡初版的正面範例就用了「見核心七問」而未察覺、由 #156 抓出 — 兩卡是不同認知層的檢查、單獨跑任一個抓不到另一個的違規。</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>：本卡是 SSoT 在「結構引用」維度的實例。編號是位置的 derivation；把編號寫進多處引用點、等於把 derivation 當 fact 散寫多份複本 — fact（章節的語意身分）只在標題一處、引用就該錨在那裡。</li>
<li><a href="/blog/report/url-slug-must-be-explicit-fact/" data-link-title="URL slug 必須顯式定義為 fact：跨工具 identifier 用單一定義源" data-link-desc="URL slug 在 Hugo 預設下從 title 自動推導、在 mdtools lint 下從檔名讀、在跨檔連結時又要寫第三個值 — 一個 identifier 散落在三個推導鏈、典型 SSoT 違反。當多個工具共用一個 identifier、推導不一致 = silent broken link。修法：把 slug 從 derivation（runtime 推導）升級成 fact（frontmatter 顯式定義）、檔名 / 連結都基於這個 fact。本卡是 #44 在 toolchain integration 情境的具體實例、是 #82 字面 vs 行為在 identifier 維度的展現。">#93 URL slug 必須顯式定義為 fact</a>：同屬「引用要錨在 fact」家族。#93 把跨工具 identifier 從推導值升級成顯式 fact；本卡把跨段落引用的錨點從位置推導值（編號）換成語意 fact（標題）。兩卡的失效模式同型：推導鏈分歧、silent 失效、compile / lint 階段看不出來。</li>
<li><a href="/blog/report/naming-as-iterated-artifact/" data-link-title="Naming 是 iterated artifact：第一個名字幾乎不對、四輪 review 才收斂" data-link-desc="命名（變數 / 函式 / 檔名 / slug / API endpoint）幾乎沒有「一次寫對」的可能：第一個名字基於當下狹窄的 context、會在後續 cross-call-site / grep / 重構中暴露錯位。命名的正確設計是 iterated — 寫第一版 → grep-ability 測試 → cross-call-site 一致性 → impl 洩漏 → 重命名。本卡是 #83 在「命名」場景的特化。">#84 Naming 是 iterated artifact</a>：標題是名字。本卡要求標題承載可被引用的語意、等於對標題套用 #84 的 cross-call-site 檢驗 — 從引用者的角度看、這個標題單獨出現時讀者知道它指什麼嗎？只有編號的標題在這個檢驗下直接不及格。</li>
<li><a href="/blog/report/metadata-surface-in-writing-review/" data-link-title="Metadata surface 要納入寫作 review 範圍" data-link-desc="寫作 review 的 surface 包含正文與 metadata surface：title、description、frontmatter、heading、link label、MOC 索引條。正文通過 positive wording 或 multi-pass review 只代表 body surface 收斂；讀者入口與索引入口也要跑同一套 frame，才能讓文章在第一眼、搜尋與跨篇路由上維持同一個概念錨點。">#97 Metadata surface 要納入寫作 review 範圍</a>：引用句屬於 #97 分類中的 navigation surface（跟 link label、索引條目同層）— 同樣是正文之外、卻直接決定讀者入口正確性的層。重排結構時、review 範圍要把散落各檔的引用句列入掃描面、而不是只改目標檔。</li>
</ul>
<hr>
<h2 id="觸發-case">觸發 case</h2>
<p>設計一個多階段訪談 skill 時、初版流程四階段、各檔用「Stage 1 的核心七問」「Stage 3 收斂時」互相引用。下一版把流程改成六階段：操作盤點與領域切分插入在前、核心七問從 Stage 1 變成 Stage 3、決策收斂從 Stage 3 變成 Stage 5。</p>
<p>後果具體呈現了上述失效模式：十多處跨檔引用要修、grep「Stage」找得到所有字面、但每一處都要人工判讀語意 — 「Stage 3 收斂時」字面完好、語意卻已指向錯誤階段（舊 Stage 3 是收斂、新 Stage 3 是核心七問）。實際修復中就有兩處漏網、靠第二輪全 repo 掃描才補上。若初版引用寫的是「核心問題」「決策收斂階段」這類語意名稱、這次重排的引用修復成本是零。</p>
<hr>
<h2 id="判讀徵兆">判讀徵兆</h2>
<ul>
<li>寫出「見 Stage N」「如第 N 點」「上一章提過」「§N」且目標是活文件時 — 改用語意標題引用。</li>
<li>章節標題只有編號或編號加泛稱（「階段三」「Part 2」）— 補語意半邊、否則其他文件只能用編號引用該章節。</li>
<li>Review 掃描可用：<code>rg &quot;Stage [0-9]|第 ?[一二三四五六七八九十0-9]+ ?(章|節|點|步|輪)|§[0-9]&quot;</code> — 命中是候選、要逐處判讀目標是凍結編號還是活文件。</li>
<li>結構重排（插入 / 合併 / 搬移章節）的 commit、檢查清單要包含「全 repo 掃引用句」、不是只改目標檔。</li>
</ul>
]]></content:encoded></item><item><title>集合命名用角色、不內嵌數量：「核心七問」的七是成員數的 derivation、加一問就全面失真</title><link>https://tarrragon.github.io/blog/report/name-collections-by-role-not-count/</link><pubDate>Thu, 11 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/report/name-collections-by-role-not-count/</guid><description>&lt;h2 id="結論">結論&lt;/h2>
&lt;p>集合型結構（問題清單、階段序列、原則組、支柱組）的命名&lt;strong>只承載角色與層級、把成員數量留給清單自己呈現&lt;/strong>。「核心問題」這個名稱承受任意的成員增減；「核心七問」把當前成員數烤進名字、加一問、七就變八：名稱本身先失真、散落各處的引用跟著全部過期。「次要問題」「撞牆階段」「防護底線」同理 — 角色詞完成分層、數量歸清單。&lt;/p>
&lt;p>區分核心問題跟次要問題、靠的是「核心 / 次要」這組角色詞；讀者選擇讀哪一組、不需要先知道組內有幾個成員。數字在名稱裡有真實的讀者側價值 — 記憶掛鉤與完整性提示（「五原則我只想起四個、漏了一個」）— 但這個價值在活集合下被漂移風險壓過、只有凍結集合能無風險收割它、這也是品牌名刻意用數字的原因；路由本身、角色詞已經完成。&lt;/p>
&lt;hr>
&lt;h2 id="為什麼數量入名比編號引用更深一層">為什麼數量入名比編號引用更深一層&lt;/h2>
&lt;h3 id="數量是-membership-的-derivation">數量是 membership 的 derivation&lt;/h3>
&lt;p>一個集合的成員數由「目前有哪些成員」決定 — 跟章節編號由「前面排了幾章」決定同構、都是會隨演進變動的衍生值。差別在寄生位置：編號寄生在&lt;strong>引用句&lt;/strong>、數量寄生在&lt;strong>名稱本身&lt;/strong>。名稱是整個知識系統裡被複製最多次的字串（標題、引用、索引、目錄、對話、commit message 都在複製它）、缺陷跟著名稱繁殖到每一個出現點。&lt;/p>
&lt;h3 id="它讓語意標題是穩定錨的前提失效">它讓「語意標題是穩定錨」的前提失效&lt;/h3>
&lt;p>引用該錨在語意標題、因為標題被假設是這個單位的 fact。「核心七問」打破這個假設：標題有一半是語意（核心問題）、一半是 derivation（七）。成員一變、想守住名實一致就得全面改名、改名又回到「散落引用逐處修」的老路；想省事不改名、就留下一個說謊的名字（標題寫七問、實際有八問）、比編號錯位更糟 — 錯在系統的權威命名層。&lt;/p>
&lt;h3 id="失真的兩條路都有代價">失真的兩條路都有代價&lt;/h3>
&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>名稱出現過的每一處（標題 / 引用 / 索引 / 歷史對話的延續）都要修、等同一次結構重排&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>保留舊名&lt;/td>
 &lt;td>名實不符常態化 — 讀者數了一下發現是八問、開始懷疑文件其他部分的可信度&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="反模式與修法">反模式與修法&lt;/h2>
&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>核心七問&lt;/td>
 &lt;td>核心問題&lt;/td>
 &lt;td>角色詞（核心）已完成分層、七是冗餘的快照&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>成長六階段&lt;/td>
 &lt;td>規模成長撞牆階段&lt;/td>
 &lt;td>階段數會隨教材演進增減&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>四大支柱&lt;/td>
 &lt;td>核心支柱（或直接「支柱」）&lt;/td>
 &lt;td>「大」字結構強迫帶數量、整個棄用&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>訪談流程（六階段）&lt;/td>
 &lt;td>訪談流程&lt;/td>
 &lt;td>流程有幾站、目錄自己會說&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>五個定錨問題&lt;/td>
 &lt;td>定錨問題&lt;/td>
 &lt;td>行內描述也一樣、數量讓清單自己呈現&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>寫作時的判斷：命名一個集合時、問「這個數字提供了角色詞沒提供的資訊嗎？」— 答案幾乎都是否。讀者需要知道數量的時刻、是看到清單本身的時刻、清單天然自帶數量。&lt;/p>
&lt;h3 id="邊界三種數字可以留">邊界：三種數字可以留&lt;/h3>
&lt;ol>
&lt;li>&lt;strong>外部凍結的品牌名&lt;/strong>：SOLID 五原則、OWASP Top 10、WRAP 四步驟 — 數量由發布方凍結、是名稱 fact 的一部分、跟引用 RFC 段號同理。&lt;/li>
&lt;li>&lt;strong>數字是概念內容本身&lt;/strong>：&lt;a href="https://tarrragon.github.io/blog/report/two-occurrence-threshold/" data-link-title="2 次門檻：第一次是運氣、第二次是訊號" data-link-desc="同一個問題出現第 2 次時、就該停下來把處理層級升一階 — 從推理升到量測、從手動驗證升到自動化、從同方向嘗試升到換思路。第 1 次失敗的資訊不足、第 2 次提供「重複出現」的證據、值得付出升級成本。本文是 #11 / #15 / #20 / #23 四篇實作的共同抽象。">兩次門檻&lt;/a> 的二是規則的閾值、不是成員數 — 改了二就是改了概念、這種數字承載語意、該留。&lt;/li>
&lt;li>&lt;strong>緊鄰清單的行內計數&lt;/strong>：「確認三件事：」後面直接跟三條列 — 數字跟清單同視野、改清單時順手改數字、漂移會立刻被看見。風險低、但仍是小負債、清單就在下面時「確認下列事項：」更省。&lt;/li>
&lt;li>&lt;strong>內部宣告凍結的集合&lt;/strong>：團隊把某個方法論名稱當內部品牌用、可以明文宣告凍結後收割記憶價值 — 代價比凍結編號更嚴：凍結編號還能往後加、凍結數量連加都不能加、成員增減等於名稱重新談判。&lt;/li>
&lt;/ol>
&lt;p>判別線是「這個數字是 fact 還是 derivation」：發布方凍結的、概念內容本身的是 fact；內部活集合的成員數是 derivation、不入名。&lt;/p>
&lt;hr>
&lt;h2 id="跟其他抽象層原則的關係">跟其他抽象層原則的關係&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/report/reference-by-semantic-title-not-number/" data-link-title="引用章節用語意標題、不用位置編號：編號是結構排列的 derivation、會隨版本漂移" data-link-desc="跨段落、跨檔引用結構單位（章節 / 階段 / 條列項）時、引用語意標題（副標題）、不引用位置編號（Stage 3、第 5 章、第 3 點）。編號是「目前結構排列」的 derivation、不是 fact；結構重排時編號全部位移、引用點不會報錯、而是 silent 指向錯的內容 — 比 broken link 更難偵測。標題的存在意義就是承載可被引用的語意。是 #44 SSoT 在結構引用維度的實例、#93 identifier-as-fact 家族的 sibling、#84 命名承載語意的引用面延伸。">#155 引用章節用語意標題、不用位置編號&lt;/a>：直接 sibling、分工在管線的兩端 — #155 修引用端（錨點選什麼）、本卡修命名端（錨點本身怎麼長）。#155 假設語意標題是穩定 fact、本卡負責讓這個假設成立：count-bearing 標題是「一半 fact 一半 derivation」的混合體、先淨化命名、#155 的引用紀律才有穩定的錨可用。實證：#155 卡初版自己用「見核心七問」當正面範例、修引用端時沒發現錨點內嵌數量。兩卡查的是不同層：引用端的檢查抓不到命名端的缺陷、反過來也一樣。&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>：成員數量的 truth 在清單本身（數一下就有）；把數量寫進名稱是把這個 derivation 複製成第二個源、且這個源被嵌進最高頻複製的字串裡：是 SSoT 違反裡擴散速度最快的形態。&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/report/naming-as-iterated-artifact/" data-link-title="Naming 是 iterated artifact：第一個名字幾乎不對、四輪 review 才收斂" data-link-desc="命名（變數 / 函式 / 檔名 / slug / API endpoint）幾乎沒有「一次寫對」的可能：第一個名字基於當下狹窄的 context、會在後續 cross-call-site / grep / 重構中暴露錯位。命名的正確設計是 iterated — 寫第一版 → grep-ability 測試 → cross-call-site 一致性 → impl 洩漏 → 重命名。本卡是 #83 在「命名」場景的特化。">#84 Naming 是 iterated artifact&lt;/a>：本卡給 #84 的命名 review 加一個檢查維度 — 數量入名是「第一版命名基於當下狹窄 context」的典型產物：寫名字的當下成員剛好七個、七看起來是這個集合的屬性；cross-time 檢驗（成員會不會變）才暴露它是快照。&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/report/ease-of-writing-vs-intent-alignment/" data-link-title="寫作便利度跟意圖對齊反相關" data-link-desc="寫程式時最容易寫出的版本、通常是離意圖最遠的版本。便利度建立在「現有上下文 / 已 materialize 資料 / 已存在 API」上、而意圖對齊需要找到正確的層、處理上游、跨抽象層 — 兩者方向相反。識別這個反相關 = 識別自己掉進「容易寫的陷阱」。">#67 寫作便利度跟意圖對齊反相關&lt;/a>：「七問」「六階段」順口、有節奏感、好記 — 正是便利驅動的選擇；意圖對齊的名稱（核心問題）平淡但誠實。便利的代價延遲到第一次成員變動才結算。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="觸發-case">觸發 case&lt;/h2>
&lt;p>同一份多階段訪談 skill、同一天內兩次命中：&lt;/p></description><content:encoded><![CDATA[<h2 id="結論">結論</h2>
<p>集合型結構（問題清單、階段序列、原則組、支柱組）的命名<strong>只承載角色與層級、把成員數量留給清單自己呈現</strong>。「核心問題」這個名稱承受任意的成員增減；「核心七問」把當前成員數烤進名字、加一問、七就變八：名稱本身先失真、散落各處的引用跟著全部過期。「次要問題」「撞牆階段」「防護底線」同理 — 角色詞完成分層、數量歸清單。</p>
<p>區分核心問題跟次要問題、靠的是「核心 / 次要」這組角色詞；讀者選擇讀哪一組、不需要先知道組內有幾個成員。數字在名稱裡有真實的讀者側價值 — 記憶掛鉤與完整性提示（「五原則我只想起四個、漏了一個」）— 但這個價值在活集合下被漂移風險壓過、只有凍結集合能無風險收割它、這也是品牌名刻意用數字的原因；路由本身、角色詞已經完成。</p>
<hr>
<h2 id="為什麼數量入名比編號引用更深一層">為什麼數量入名比編號引用更深一層</h2>
<h3 id="數量是-membership-的-derivation">數量是 membership 的 derivation</h3>
<p>一個集合的成員數由「目前有哪些成員」決定 — 跟章節編號由「前面排了幾章」決定同構、都是會隨演進變動的衍生值。差別在寄生位置：編號寄生在<strong>引用句</strong>、數量寄生在<strong>名稱本身</strong>。名稱是整個知識系統裡被複製最多次的字串（標題、引用、索引、目錄、對話、commit message 都在複製它）、缺陷跟著名稱繁殖到每一個出現點。</p>
<h3 id="它讓語意標題是穩定錨的前提失效">它讓「語意標題是穩定錨」的前提失效</h3>
<p>引用該錨在語意標題、因為標題被假設是這個單位的 fact。「核心七問」打破這個假設：標題有一半是語意（核心問題）、一半是 derivation（七）。成員一變、想守住名實一致就得全面改名、改名又回到「散落引用逐處修」的老路；想省事不改名、就留下一個說謊的名字（標題寫七問、實際有八問）、比編號錯位更糟 — 錯在系統的權威命名層。</p>
<h3 id="失真的兩條路都有代價">失真的兩條路都有代價</h3>
<table>
  <thead>
      <tr>
          <th>成員變動後的選擇</th>
          <th>代價</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>全面改名</td>
          <td>名稱出現過的每一處（標題 / 引用 / 索引 / 歷史對話的延續）都要修、等同一次結構重排</td>
      </tr>
      <tr>
          <td>保留舊名</td>
          <td>名實不符常態化 — 讀者數了一下發現是八問、開始懷疑文件其他部分的可信度</td>
      </tr>
  </tbody>
</table>
<hr>
<h2 id="反模式與修法">反模式與修法</h2>
<table>
  <thead>
      <tr>
          <th>反模式</th>
          <th>修法</th>
          <th>說明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>核心七問</td>
          <td>核心問題</td>
          <td>角色詞（核心）已完成分層、七是冗餘的快照</td>
      </tr>
      <tr>
          <td>成長六階段</td>
          <td>規模成長撞牆階段</td>
          <td>階段數會隨教材演進增減</td>
      </tr>
      <tr>
          <td>四大支柱</td>
          <td>核心支柱（或直接「支柱」）</td>
          <td>「大」字結構強迫帶數量、整個棄用</td>
      </tr>
      <tr>
          <td>訪談流程（六階段）</td>
          <td>訪談流程</td>
          <td>流程有幾站、目錄自己會說</td>
      </tr>
      <tr>
          <td>五個定錨問題</td>
          <td>定錨問題</td>
          <td>行內描述也一樣、數量讓清單自己呈現</td>
      </tr>
  </tbody>
</table>
<p>寫作時的判斷：命名一個集合時、問「這個數字提供了角色詞沒提供的資訊嗎？」— 答案幾乎都是否。讀者需要知道數量的時刻、是看到清單本身的時刻、清單天然自帶數量。</p>
<h3 id="邊界三種數字可以留">邊界：三種數字可以留</h3>
<ol>
<li><strong>外部凍結的品牌名</strong>：SOLID 五原則、OWASP Top 10、WRAP 四步驟 — 數量由發布方凍結、是名稱 fact 的一部分、跟引用 RFC 段號同理。</li>
<li><strong>數字是概念內容本身</strong>：<a href="/blog/report/two-occurrence-threshold/" data-link-title="2 次門檻：第一次是運氣、第二次是訊號" data-link-desc="同一個問題出現第 2 次時、就該停下來把處理層級升一階 — 從推理升到量測、從手動驗證升到自動化、從同方向嘗試升到換思路。第 1 次失敗的資訊不足、第 2 次提供「重複出現」的證據、值得付出升級成本。本文是 #11 / #15 / #20 / #23 四篇實作的共同抽象。">兩次門檻</a> 的二是規則的閾值、不是成員數 — 改了二就是改了概念、這種數字承載語意、該留。</li>
<li><strong>緊鄰清單的行內計數</strong>：「確認三件事：」後面直接跟三條列 — 數字跟清單同視野、改清單時順手改數字、漂移會立刻被看見。風險低、但仍是小負債、清單就在下面時「確認下列事項：」更省。</li>
<li><strong>內部宣告凍結的集合</strong>：團隊把某個方法論名稱當內部品牌用、可以明文宣告凍結後收割記憶價值 — 代價比凍結編號更嚴：凍結編號還能往後加、凍結數量連加都不能加、成員增減等於名稱重新談判。</li>
</ol>
<p>判別線是「這個數字是 fact 還是 derivation」：發布方凍結的、概念內容本身的是 fact；內部活集合的成員數是 derivation、不入名。</p>
<hr>
<h2 id="跟其他抽象層原則的關係">跟其他抽象層原則的關係</h2>
<ul>
<li><a href="/blog/report/reference-by-semantic-title-not-number/" data-link-title="引用章節用語意標題、不用位置編號：編號是結構排列的 derivation、會隨版本漂移" data-link-desc="跨段落、跨檔引用結構單位（章節 / 階段 / 條列項）時、引用語意標題（副標題）、不引用位置編號（Stage 3、第 5 章、第 3 點）。編號是「目前結構排列」的 derivation、不是 fact；結構重排時編號全部位移、引用點不會報錯、而是 silent 指向錯的內容 — 比 broken link 更難偵測。標題的存在意義就是承載可被引用的語意。是 #44 SSoT 在結構引用維度的實例、#93 identifier-as-fact 家族的 sibling、#84 命名承載語意的引用面延伸。">#155 引用章節用語意標題、不用位置編號</a>：直接 sibling、分工在管線的兩端 — #155 修引用端（錨點選什麼）、本卡修命名端（錨點本身怎麼長）。#155 假設語意標題是穩定 fact、本卡負責讓這個假設成立：count-bearing 標題是「一半 fact 一半 derivation」的混合體、先淨化命名、#155 的引用紀律才有穩定的錨可用。實證：#155 卡初版自己用「見核心七問」當正面範例、修引用端時沒發現錨點內嵌數量。兩卡查的是不同層：引用端的檢查抓不到命名端的缺陷、反過來也一樣。</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>：成員數量的 truth 在清單本身（數一下就有）；把數量寫進名稱是把這個 derivation 複製成第二個源、且這個源被嵌進最高頻複製的字串裡：是 SSoT 違反裡擴散速度最快的形態。</li>
<li><a href="/blog/report/naming-as-iterated-artifact/" data-link-title="Naming 是 iterated artifact：第一個名字幾乎不對、四輪 review 才收斂" data-link-desc="命名（變數 / 函式 / 檔名 / slug / API endpoint）幾乎沒有「一次寫對」的可能：第一個名字基於當下狹窄的 context、會在後續 cross-call-site / grep / 重構中暴露錯位。命名的正確設計是 iterated — 寫第一版 → grep-ability 測試 → cross-call-site 一致性 → impl 洩漏 → 重命名。本卡是 #83 在「命名」場景的特化。">#84 Naming 是 iterated artifact</a>：本卡給 #84 的命名 review 加一個檢查維度 — 數量入名是「第一版命名基於當下狹窄 context」的典型產物：寫名字的當下成員剛好七個、七看起來是這個集合的屬性；cross-time 檢驗（成員會不會變）才暴露它是快照。</li>
<li><a href="/blog/report/ease-of-writing-vs-intent-alignment/" data-link-title="寫作便利度跟意圖對齊反相關" data-link-desc="寫程式時最容易寫出的版本、通常是離意圖最遠的版本。便利度建立在「現有上下文 / 已 materialize 資料 / 已存在 API」上、而意圖對齊需要找到正確的層、處理上游、跨抽象層 — 兩者方向相反。識別這個反相關 = 識別自己掉進「容易寫的陷阱」。">#67 寫作便利度跟意圖對齊反相關</a>：「七問」「六階段」順口、有節奏感、好記 — 正是便利驅動的選擇；意圖對齊的名稱（核心問題）平淡但誠實。便利的代價延遲到第一次成員變動才結算。</li>
</ul>
<hr>
<h2 id="觸發-case">觸發 case</h2>
<p>同一份多階段訪談 skill、同一天內兩次命中：</p>
<ol>
<li><strong>已發生</strong>：skill 初版有「四大支柱」、第二版需求調整後支柱變六個 — 名稱被迫改成「六大支柱」、所有提到四大支柱的地方同步修。改完的新名字仍然內嵌數量、下次支柱增減會原樣重演。</li>
<li><strong>被預見</strong>：第二版的「核心七問」「成長六階段」被指出同樣結構 — 核心問題若加一問、「七」就散落在標題、引用、索引、路由表裡等著逐處修。</li>
</ol>
<p>更深的訊號是第三點：當天稍早為了修「Stage 3」編號引用立了一張卡（引用端）、該卡自己用「見核心七問」當正面範例；在專注檢查引用端時、命名端的同型缺陷完全隱形。確認了這是獨立的檢查維度、不是引用卡的子情況。</p>
<hr>
<h2 id="判讀徵兆">判讀徵兆</h2>
<ul>
<li>命名或標題出現「N 大 X」「N 問」「N 階段」「N 支柱」「N 原則」「N 步驟」且 X 是內部活集合時 — 抽掉數字、看角色詞夠不夠分層、幾乎都夠。</li>
<li>Review 掃描可用：<code>rg &quot;[一二三四五六七八九十0-9]+ ?(大|問|階段|支柱|原則|步驟|件事|個維度)&quot; --type md</code> — 掃出來的不全是病灶：外部凍結品牌與概念閾值是 fact、留；內部活集合的成員數是 derivation、改。</li>
<li>集合成員增減的 commit、檢查名稱是否還誠實 — 需要同步改名的話、這次改名時順便把數量抽掉、別讓下次再來一遍。</li>
</ul>
]]></content:encoded></item><item><title>語意錨用單一字串、同義雙名讓引用修復退回人腦對應</title><link>https://tarrragon.github.io/blog/report/semantic-anchor-single-string/</link><pubDate>Thu, 11 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/report/semantic-anchor-single-string/</guid><description>&lt;h2 id="結論">結論&lt;/h2>
&lt;p>一個結構單位的語意名稱&lt;strong>只能有一個 canonical 字串、所有引用使用同一字串&lt;/strong>。「決策收斂」跟「決策記錄 + scaffold 建議」都是語意名、都通過了「不用編號」的檢查 — 但兩個字串指同一個階段、語意引用的收益就漏了一半：工具掃描要掃兩個 pattern 才完整、漏配置一個就漏一半引用點；結構重排時、修復者要先在腦中建立「這兩個名字是同一個東西」的對應表、而這張表沒有寫在任何地方。&lt;/p>
&lt;p>語意引用的承諾是「錨點穩定、且機器與人都能單次比對」。同義雙名保住了穩定、丟掉了單次比對 — 等於把 fact 寫成兩種拼法。&lt;/p>
&lt;h2 id="為什麼雙名會自然發生">為什麼雙名會自然發生&lt;/h2>
&lt;p>雙名通常在不同檔案、不同時間寫下：標題在設計流程時取（描述產出物：「決策記錄 + scaffold 建議」）、引用在寫協作檔時取（描述階段角色：「決策收斂階段」）。每一次取名都在自己的當下語境裡合理、分裂要把兩個時間點的產物擺在一起才看得到 — 單檔 review 永遠只看到其中一個名字、所以雙名能安然通過所有單檔檢查。&lt;/p>
&lt;p>偵測需要跨檔視角：把每個結構單位的「標題語意半邊」列成清單、grep 全部引用句、比對引用字串是否落在清單內。引用字串語意對、字面不在清單內、就是雙名。&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>標題「Stage 5：決策記錄 + scaffold 建議」、引用「決策收斂階段」&lt;/td>
 &lt;td>二選一、全 repo 統一（標題改「Stage 5：決策收斂（決策記錄 + scaffold 建議）」、引用維持「決策收斂」）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>「domain / event 切分」與「領域切分」混用&lt;/td>
 &lt;td>取標題語意半邊為 canonical、其餘出現點改寫&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>縮寫與全名並存當引用錨（「ops 階段」「操作維運階段」）&lt;/td>
 &lt;td>全名為 canonical、縮寫只出現在已建立對應的同段內&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>修法的判斷次序：canonical 字串取「標題的語意半邊」（標題是該單位的 fact 所在）；標題語意半邊太長不適合引用時、先改標題、再統一引用 — 標題改短是一次成本、引用各自簡寫是持續發散。&lt;/p>
&lt;h2 id="跟其他抽象層原則的關係">跟其他抽象層原則的關係&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/report/reference-by-semantic-title-not-number/" data-link-title="引用章節用語意標題、不用位置編號：編號是結構排列的 derivation、會隨版本漂移" data-link-desc="跨段落、跨檔引用結構單位（章節 / 階段 / 條列項）時、引用語意標題（副標題）、不引用位置編號（Stage 3、第 5 章、第 3 點）。編號是「目前結構排列」的 derivation、不是 fact；結構重排時編號全部位移、引用點不會報錯、而是 silent 指向錯的內容 — 比 broken link 更難偵測。標題的存在意義就是承載可被引用的語意。是 #44 SSoT 在結構引用維度的實例、#93 identifier-as-fact 家族的 sibling、#84 命名承載語意的引用面延伸。">#155 引用章節用語意標題、不用位置編號&lt;/a>：本卡補 #155 的缺口。#155 把錨點從編號換成語意名稱、預設了「語意名稱是單一的」；雙名讓 #155 的修法只完成一半 — 錨點穩定了、可比對性沒跟上。三卡合起來是完整的引用紀律：#155 管引用端（錨什麼）、#156 管命名端的內容（名稱不含 derivation）、本卡管命名端的唯一性（一個單位一個字串）。&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/report/name-collections-by-role-not-count/" data-link-title="集合命名用角色、不內嵌數量：「核心七問」的七是成員數的 derivation、加一問就全面失真" data-link-desc="「核心七問」「成長六階段」「四大支柱」這類名稱把成員數量烤進名字裡 — 數量是集合當前成員的 derivation、不是集合的語意身分；成員增減時名稱失真、且名稱是被複製最多次的字串、缺陷隨每次引用繁殖。修法：命名只承載角色與層級（核心問題 / 次要問題 / 撞牆階段）、數量讓清單自己呈現。本卡是 #155 的命名端 sibling（#155 修引用端、本卡讓「語意標題是穩定錨」的前提真正成立）、#44 SSoT 在名稱內容的實例、#84 命名檢驗的數量維度。">#156 集合命名用角色、不內嵌數量&lt;/a>：sibling。#156 處理名稱「內容」的 fact 純度、本卡處理名稱「數量」的唯一性 — 一個名稱可以通過 #156（不含成員數）仍違反本卡（有同義變體）。&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>：同一語意身分的兩個字串就是同一個 fact 的兩個源 — 比值的多源更隱蔽、因為兩個字串「語意上相等」、讀者看不出這是違規、只有工具比對才會痛。&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/report/naming-as-iterated-artifact/" data-link-title="Naming 是 iterated artifact：第一個名字幾乎不對、四輪 review 才收斂" data-link-desc="命名（變數 / 函式 / 檔名 / slug / API endpoint）幾乎沒有「一次寫對」的可能：第一個名字基於當下狹窄的 context、會在後續 cross-call-site / grep / 重構中暴露錯位。命名的正確設計是 iterated — 寫第一版 → grep-ability 測試 → cross-call-site 一致性 → impl 洩漏 → 重命名。本卡是 #83 在「命名」場景的特化。">#84 Naming 是 iterated artifact&lt;/a>：#84 的輪 3 明文檢查「同一個概念在不同檔案用同名嗎」、判讀徵兆也列了「同概念出現兩個以上名字、選一個改另一個」— 本卡是這個檢查項在「結構單位的標題與引用」場景的應用：被檢查的從變數名換成章節 / 階段的語意錨、檢查動作相同。&lt;/li>
&lt;/ul>
&lt;h2 id="觸發-case">觸發 case&lt;/h2>
&lt;p>一份多階段訪談 skill 在一致性 audit 中被抓到兩處：階段標題寫「決策記錄 + scaffold 建議」、兩個協作檔的引用寫「決策收斂階段」；另一個階段的引用在「domain / event 切分」與「領域切分」之間混用。每個字串單獨檢查都合規（語意名、無編號、無數量）— audit reviewer 的原話是「語意可對上、但嚴格來說引用錨與標題語意半邊不同字串、下次重排時要靠人腦對應」。修法：標題語意半邊改成「決策收斂」、全 skill 引用統一；「領域切分」全部改寫為「domain / event 切分」。&lt;/p></description><content:encoded><![CDATA[<h2 id="結論">結論</h2>
<p>一個結構單位的語意名稱<strong>只能有一個 canonical 字串、所有引用使用同一字串</strong>。「決策收斂」跟「決策記錄 + scaffold 建議」都是語意名、都通過了「不用編號」的檢查 — 但兩個字串指同一個階段、語意引用的收益就漏了一半：工具掃描要掃兩個 pattern 才完整、漏配置一個就漏一半引用點；結構重排時、修復者要先在腦中建立「這兩個名字是同一個東西」的對應表、而這張表沒有寫在任何地方。</p>
<p>語意引用的承諾是「錨點穩定、且機器與人都能單次比對」。同義雙名保住了穩定、丟掉了單次比對 — 等於把 fact 寫成兩種拼法。</p>
<h2 id="為什麼雙名會自然發生">為什麼雙名會自然發生</h2>
<p>雙名通常在不同檔案、不同時間寫下：標題在設計流程時取（描述產出物：「決策記錄 + scaffold 建議」）、引用在寫協作檔時取（描述階段角色：「決策收斂階段」）。每一次取名都在自己的當下語境裡合理、分裂要把兩個時間點的產物擺在一起才看得到 — 單檔 review 永遠只看到其中一個名字、所以雙名能安然通過所有單檔檢查。</p>
<p>偵測需要跨檔視角：把每個結構單位的「標題語意半邊」列成清單、grep 全部引用句、比對引用字串是否落在清單內。引用字串語意對、字面不在清單內、就是雙名。</p>
<h2 id="反模式與修法">反模式與修法</h2>
<table>
  <thead>
      <tr>
          <th>反模式</th>
          <th>修法</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>標題「Stage 5：決策記錄 + scaffold 建議」、引用「決策收斂階段」</td>
          <td>二選一、全 repo 統一（標題改「Stage 5：決策收斂（決策記錄 + scaffold 建議）」、引用維持「決策收斂」）</td>
      </tr>
      <tr>
          <td>「domain / event 切分」與「領域切分」混用</td>
          <td>取標題語意半邊為 canonical、其餘出現點改寫</td>
      </tr>
      <tr>
          <td>縮寫與全名並存當引用錨（「ops 階段」「操作維運階段」）</td>
          <td>全名為 canonical、縮寫只出現在已建立對應的同段內</td>
      </tr>
  </tbody>
</table>
<p>修法的判斷次序：canonical 字串取「標題的語意半邊」（標題是該單位的 fact 所在）；標題語意半邊太長不適合引用時、先改標題、再統一引用 — 標題改短是一次成本、引用各自簡寫是持續發散。</p>
<h2 id="跟其他抽象層原則的關係">跟其他抽象層原則的關係</h2>
<ul>
<li><a href="/blog/report/reference-by-semantic-title-not-number/" data-link-title="引用章節用語意標題、不用位置編號：編號是結構排列的 derivation、會隨版本漂移" data-link-desc="跨段落、跨檔引用結構單位（章節 / 階段 / 條列項）時、引用語意標題（副標題）、不引用位置編號（Stage 3、第 5 章、第 3 點）。編號是「目前結構排列」的 derivation、不是 fact；結構重排時編號全部位移、引用點不會報錯、而是 silent 指向錯的內容 — 比 broken link 更難偵測。標題的存在意義就是承載可被引用的語意。是 #44 SSoT 在結構引用維度的實例、#93 identifier-as-fact 家族的 sibling、#84 命名承載語意的引用面延伸。">#155 引用章節用語意標題、不用位置編號</a>：本卡補 #155 的缺口。#155 把錨點從編號換成語意名稱、預設了「語意名稱是單一的」；雙名讓 #155 的修法只完成一半 — 錨點穩定了、可比對性沒跟上。三卡合起來是完整的引用紀律：#155 管引用端（錨什麼）、#156 管命名端的內容（名稱不含 derivation）、本卡管命名端的唯一性（一個單位一個字串）。</li>
<li><a href="/blog/report/name-collections-by-role-not-count/" data-link-title="集合命名用角色、不內嵌數量：「核心七問」的七是成員數的 derivation、加一問就全面失真" data-link-desc="「核心七問」「成長六階段」「四大支柱」這類名稱把成員數量烤進名字裡 — 數量是集合當前成員的 derivation、不是集合的語意身分；成員增減時名稱失真、且名稱是被複製最多次的字串、缺陷隨每次引用繁殖。修法：命名只承載角色與層級（核心問題 / 次要問題 / 撞牆階段）、數量讓清單自己呈現。本卡是 #155 的命名端 sibling（#155 修引用端、本卡讓「語意標題是穩定錨」的前提真正成立）、#44 SSoT 在名稱內容的實例、#84 命名檢驗的數量維度。">#156 集合命名用角色、不內嵌數量</a>：sibling。#156 處理名稱「內容」的 fact 純度、本卡處理名稱「數量」的唯一性 — 一個名稱可以通過 #156（不含成員數）仍違反本卡（有同義變體）。</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>：同一語意身分的兩個字串就是同一個 fact 的兩個源 — 比值的多源更隱蔽、因為兩個字串「語意上相等」、讀者看不出這是違規、只有工具比對才會痛。</li>
<li><a href="/blog/report/naming-as-iterated-artifact/" data-link-title="Naming 是 iterated artifact：第一個名字幾乎不對、四輪 review 才收斂" data-link-desc="命名（變數 / 函式 / 檔名 / slug / API endpoint）幾乎沒有「一次寫對」的可能：第一個名字基於當下狹窄的 context、會在後續 cross-call-site / grep / 重構中暴露錯位。命名的正確設計是 iterated — 寫第一版 → grep-ability 測試 → cross-call-site 一致性 → impl 洩漏 → 重命名。本卡是 #83 在「命名」場景的特化。">#84 Naming 是 iterated artifact</a>：#84 的輪 3 明文檢查「同一個概念在不同檔案用同名嗎」、判讀徵兆也列了「同概念出現兩個以上名字、選一個改另一個」— 本卡是這個檢查項在「結構單位的標題與引用」場景的應用：被檢查的從變數名換成章節 / 階段的語意錨、檢查動作相同。</li>
</ul>
<h2 id="觸發-case">觸發 case</h2>
<p>一份多階段訪談 skill 在一致性 audit 中被抓到兩處：階段標題寫「決策記錄 + scaffold 建議」、兩個協作檔的引用寫「決策收斂階段」；另一個階段的引用在「domain / event 切分」與「領域切分」之間混用。每個字串單獨檢查都合規（語意名、無編號、無數量）— audit reviewer 的原話是「語意可對上、但嚴格來說引用錨與標題語意半邊不同字串、下次重排時要靠人腦對應」。修法：標題語意半邊改成「決策收斂」、全 skill 引用統一；「領域切分」全部改寫為「domain / event 切分」。</p>
<h2 id="判讀徵兆">判讀徵兆</h2>
<ul>
<li>寫引用句時、回頭看目標標題：引用字串跟標題語意半邊逐字相同嗎？語意相同、字面不同 = 雙名。</li>
<li>跨檔 review 可操作：列出所有結構單位的語意半邊、<code>rg</code> 每個單位的引用句、引用字串不在清單內的逐處判讀。</li>
<li>同單位的引用在不同檔案用不同說法、且沒有任何一處寫明對應 — 雙名已經發生、統一的成本隨引用點數量成長。</li>
</ul>
]]></content:encoded></item><item><title>跨 surface 同主題內容要重新語境化、不是搬運：逐字相同句是未語境化的訊號</title><link>https://tarrragon.github.io/blog/report/cross-surface-recontextualize-not-transplant/</link><pubDate>Thu, 11 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/report/cross-surface-recontextualize-not-transplant/</guid><description>&lt;h2 id="結論">結論&lt;/h2>
&lt;p>同主題內容要落在兩個 surface（人類教材 ↔ agent 協議、公開文章 ↔ 內部 skill）時、每一份要&lt;strong>為自己的讀者與用途重寫、不是把句子搬過去&lt;/strong>。「各寫一份」的規範如果用複製貼上執行、得到的是最差組合：兩份字面綁定（改一邊、另一邊變成過期複本、且沒有任何機制提醒）、卻又各自沒有為自己的 surface 最佳化（教材句直接當協議用、agent 拿到的是給人類讀的敘述而不是可執行的指令）。&lt;/p>
&lt;p>語境化的可操作判準：&lt;strong>兩個 surface 之間 grep 逐字相同的完整句、命中就是候選&lt;/strong>。同一個原則、教材版該長成「為什麼 + 案例 + 判讀」、協議版該長成「步驟 + 條件 + 產出格式」— 兩版講同一件事、句子自然長得不一樣；句子一樣、代表至少有一邊在用別人的形狀。&lt;/p>
&lt;h2 id="為什麼搬運是預設行為">為什麼搬運是預設行為&lt;/h2>
&lt;p>寫第二份時、第一份就在手邊、而且它「已經寫對了」— 複製是零成本、重寫要重新思考這個 surface 的讀者需要什麼形狀。搬運在當下看起來甚至更安全（兩邊保證一致）；代價在第一次單邊修改時兌現：修了教材版的措辭、skill 版還是舊句、兩邊開始各說各話、而因為當初沒有宣告同源關係、沒有人知道要同步。&lt;/p>
&lt;p>「禁止跨 surface 引用」防的是顯性耦合；搬運建立的是隱性耦合 — 更糟、因為看不見。語境化重寫讓兩份真正獨立：主旨對應靠概念、不靠字串。&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>協議版改寫成操作指令（「gate 逐條業務流程過、混合結論寫進交付形態欄」）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>反向問的問句兩邊同字&lt;/td>
 &lt;td>教材版是讀者自問、協議版是「請使用者……然後對照」的訪談動作&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>比喻句 / 警句原樣複製（修辭跨 surface 失效最快）&lt;/td>
 &lt;td>各 surface 用自己的語感重寫、或協議版直接刪修辭留判準&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>表格整張複製&lt;/td>
 &lt;td>欄位依用途裁剪：教材表帶「為什麼」欄、協議表帶「下一步路由」欄&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>欄位與句式跟著用途走之後、兩份的字面自然分開；對照查漏時找的是概念缺口、不是字串差異。&lt;/p>
&lt;h2 id="跟其他抽象層原則的關係">跟其他抽象層原則的關係&lt;/h2>
&lt;ul>
&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>：逐字搬運讓同一段論述以兩份完整複本存在、誰是權威沒有任何標記。比一般 SSoT 違反更難修 — 第一步的困難不在改、在發現同源關係存在。&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/report/cadence-homogenization-in-batch-writing/" data-link-title="Cadence 同質化是模板的隱形維度" data-link-desc="規範定義「模板」時通常只指內容欄位（規模對照、tripwire、失敗模式），忽略句型骨架 / 段首語 / 段末收尾語 / 表格前導句 / 過渡詞同樣是模板的一種；批量寫作時最易讓 cadence 同質化、單篇看起來都合規、連讀多篇才浮現預期化；51 vendor 都用「四件事 → 任一缺失就是 X 邊界的待補項目」是案例；自檢要 grep 首句 / 段末句 / 表格前導句、不是只看欄位">#122 Cadence 同質化是模板的隱形維度&lt;/a>：偵測手段同構 — 都是 grep 句子層的字面重複；差別在範圍：#122 抓同 surface 多檔的句式骨架重複、本卡抓跨 surface 的完整句逐字重複。兩個掃描可以同一輪跑。&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/report/rule-codification-vs-self-audit/" data-link-title="規範化跟自審是兩種認知任務、立規範當下無法保護同批稿件" data-link-desc="把反模式抽象成規範卡、跟在自己稿件辨識該反模式的局部實例、是兩種不同認知任務；前者用『歸納共同特徵』的視角、後者用『局部 pattern matching』的視角；用相同概念詞、走不同神經路徑；案例：#146 卡描述「看 X 如何 Y」是反模式、同 batch 5 篇章節仍有 11 處該句型未被作者察覺；修法是規範化當下立刻把規範轉成 grep keyword、對同 batch 稿件主動 sweep；不修則 #122 主題語意 attractor 跟 #124 emergence 違規會在同 batch 內持續累積">#147 規範化跟自審是兩種認知任務&lt;/a>：本卡的 case 正是規範已存在（「各寫一份、語境化在各 surface 內」白紙黑字）、執行時仍搬運 — 立規範的人在執行時用了「各寫一份」的字面（檔案確實是兩個）、漏了「語境化」的實質（句子是同一批）。規範的字面合規與實質合規是兩層檢查。&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/report/teaching-register-states-not-addresses-reader/" data-link-title="教材用中性陳述、不對讀者喊話" data-link-desc="教材的 register 是中性陳述概念、不是對讀者說話。三種對讀者喊話的形式 —— 安撫情緒（很多人卡在）、第二人稱代入（你天天寫）、祈使控制閱讀（先讀懂 / 別搞混）—— 表面不同、共同違反是把讀者當成要管理的對話對象、而非把概念講清楚。問題不在精度（「你天天寫的 int count」精度完全正確）、在 stance。修法是換成中性陳述（常見的 int count）或描述性名詞標題（簽章的型別與名字拆解）。邊界：hook / narrative 段落的輕度第二人稱可幫讀者進入、不一律禁。">#150 教材用中性陳述、不對讀者喊話&lt;/a>：register 是語境化最敏感的維度 — 教材的中性陳述、協議的指令語氣、訪談的問句、三種 register 不可互換；搬運最先破壞的就是 register 對位。&lt;/li>
&lt;/ul>
&lt;h2 id="觸發-case">觸發 case&lt;/h2>
&lt;p>一個交付形態判讀主題同時寫進 blog 教學章節與 agent 訪談 skill。Cadence 審查跨 surface 比對、抓到三句完整句逐字相同：「官方首頁文案」反向問、「判讀單位是每條業務流程」、「同一個錯誤的兩個方向」。兩個 surface 的規範明文要求各寫一份語境化 — 檔案確實是兩份、句子卻是搬的。修法把 skill 版三句全部改寫成訪談操作語氣（「請使用者用一句話描述核心流程、然後對照」「gate 逐條業務流程過、混合結論直接寫進決策記錄的交付形態欄」）、修辭句直接刪除 — 改寫後兩邊各自更貼自己的用途、概念對應不變。&lt;/p>
&lt;h2 id="判讀徵兆">判讀徵兆&lt;/h2>
&lt;ul>
&lt;li>寫第二個 surface 時發現自己在開兩個視窗對照逐段抄 — 關掉第一份、憑概念重寫、寫完再對照查漏。&lt;/li>
&lt;li>跨 surface 掃描可操作：對兩份檔案跑完整句比對（句號切分後 grep 交集）、逐字相同的非術語句逐處判讀。&lt;/li>
&lt;li>兩份同主題內容的 register 相同（教材版讀起來像協議、或協議版讀起來像散文）— 即使句子不同、也是語境化不完整的訊號。&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<h2 id="結論">結論</h2>
<p>同主題內容要落在兩個 surface（人類教材 ↔ agent 協議、公開文章 ↔ 內部 skill）時、每一份要<strong>為自己的讀者與用途重寫、不是把句子搬過去</strong>。「各寫一份」的規範如果用複製貼上執行、得到的是最差組合：兩份字面綁定（改一邊、另一邊變成過期複本、且沒有任何機制提醒）、卻又各自沒有為自己的 surface 最佳化（教材句直接當協議用、agent 拿到的是給人類讀的敘述而不是可執行的指令）。</p>
<p>語境化的可操作判準：<strong>兩個 surface 之間 grep 逐字相同的完整句、命中就是候選</strong>。同一個原則、教材版該長成「為什麼 + 案例 + 判讀」、協議版該長成「步驟 + 條件 + 產出格式」— 兩版講同一件事、句子自然長得不一樣；句子一樣、代表至少有一邊在用別人的形狀。</p>
<h2 id="為什麼搬運是預設行為">為什麼搬運是預設行為</h2>
<p>寫第二份時、第一份就在手邊、而且它「已經寫對了」— 複製是零成本、重寫要重新思考這個 surface 的讀者需要什麼形狀。搬運在當下看起來甚至更安全（兩邊保證一致）；代價在第一次單邊修改時兌現：修了教材版的措辭、skill 版還是舊句、兩邊開始各說各話、而因為當初沒有宣告同源關係、沒有人知道要同步。</p>
<p>「禁止跨 surface 引用」防的是顯性耦合；搬運建立的是隱性耦合 — 更糟、因為看不見。語境化重寫讓兩份真正獨立：主旨對應靠概念、不靠字串。</p>
<h2 id="反模式與修法">反模式與修法</h2>
<table>
  <thead>
      <tr>
          <th>反模式</th>
          <th>修法</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>教材的判讀句逐字進協議（「判讀單位是每條業務流程」）</td>
          <td>協議版改寫成操作指令（「gate 逐條業務流程過、混合結論寫進交付形態欄」）</td>
      </tr>
      <tr>
          <td>反向問的問句兩邊同字</td>
          <td>教材版是讀者自問、協議版是「請使用者……然後對照」的訪談動作</td>
      </tr>
      <tr>
          <td>比喻句 / 警句原樣複製（修辭跨 surface 失效最快）</td>
          <td>各 surface 用自己的語感重寫、或協議版直接刪修辭留判準</td>
      </tr>
      <tr>
          <td>表格整張複製</td>
          <td>欄位依用途裁剪：教材表帶「為什麼」欄、協議表帶「下一步路由」欄</td>
      </tr>
  </tbody>
</table>
<p>欄位與句式跟著用途走之後、兩份的字面自然分開；對照查漏時找的是概念缺口、不是字串差異。</p>
<h2 id="跟其他抽象層原則的關係">跟其他抽象層原則的關係</h2>
<ul>
<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>：逐字搬運讓同一段論述以兩份完整複本存在、誰是權威沒有任何標記。比一般 SSoT 違反更難修 — 第一步的困難不在改、在發現同源關係存在。</li>
<li><a href="/blog/report/cadence-homogenization-in-batch-writing/" data-link-title="Cadence 同質化是模板的隱形維度" data-link-desc="規範定義「模板」時通常只指內容欄位（規模對照、tripwire、失敗模式），忽略句型骨架 / 段首語 / 段末收尾語 / 表格前導句 / 過渡詞同樣是模板的一種；批量寫作時最易讓 cadence 同質化、單篇看起來都合規、連讀多篇才浮現預期化；51 vendor 都用「四件事 → 任一缺失就是 X 邊界的待補項目」是案例；自檢要 grep 首句 / 段末句 / 表格前導句、不是只看欄位">#122 Cadence 同質化是模板的隱形維度</a>：偵測手段同構 — 都是 grep 句子層的字面重複；差別在範圍：#122 抓同 surface 多檔的句式骨架重複、本卡抓跨 surface 的完整句逐字重複。兩個掃描可以同一輪跑。</li>
<li><a href="/blog/report/rule-codification-vs-self-audit/" data-link-title="規範化跟自審是兩種認知任務、立規範當下無法保護同批稿件" data-link-desc="把反模式抽象成規範卡、跟在自己稿件辨識該反模式的局部實例、是兩種不同認知任務；前者用『歸納共同特徵』的視角、後者用『局部 pattern matching』的視角；用相同概念詞、走不同神經路徑；案例：#146 卡描述「看 X 如何 Y」是反模式、同 batch 5 篇章節仍有 11 處該句型未被作者察覺；修法是規範化當下立刻把規範轉成 grep keyword、對同 batch 稿件主動 sweep；不修則 #122 主題語意 attractor 跟 #124 emergence 違規會在同 batch 內持續累積">#147 規範化跟自審是兩種認知任務</a>：本卡的 case 正是規範已存在（「各寫一份、語境化在各 surface 內」白紙黑字）、執行時仍搬運 — 立規範的人在執行時用了「各寫一份」的字面（檔案確實是兩個）、漏了「語境化」的實質（句子是同一批）。規範的字面合規與實質合規是兩層檢查。</li>
<li><a href="/blog/report/teaching-register-states-not-addresses-reader/" data-link-title="教材用中性陳述、不對讀者喊話" data-link-desc="教材的 register 是中性陳述概念、不是對讀者說話。三種對讀者喊話的形式 —— 安撫情緒（很多人卡在）、第二人稱代入（你天天寫）、祈使控制閱讀（先讀懂 / 別搞混）—— 表面不同、共同違反是把讀者當成要管理的對話對象、而非把概念講清楚。問題不在精度（「你天天寫的 int count」精度完全正確）、在 stance。修法是換成中性陳述（常見的 int count）或描述性名詞標題（簽章的型別與名字拆解）。邊界：hook / narrative 段落的輕度第二人稱可幫讀者進入、不一律禁。">#150 教材用中性陳述、不對讀者喊話</a>：register 是語境化最敏感的維度 — 教材的中性陳述、協議的指令語氣、訪談的問句、三種 register 不可互換；搬運最先破壞的就是 register 對位。</li>
</ul>
<h2 id="觸發-case">觸發 case</h2>
<p>一個交付形態判讀主題同時寫進 blog 教學章節與 agent 訪談 skill。Cadence 審查跨 surface 比對、抓到三句完整句逐字相同：「官方首頁文案」反向問、「判讀單位是每條業務流程」、「同一個錯誤的兩個方向」。兩個 surface 的規範明文要求各寫一份語境化 — 檔案確實是兩份、句子卻是搬的。修法把 skill 版三句全部改寫成訪談操作語氣（「請使用者用一句話描述核心流程、然後對照」「gate 逐條業務流程過、混合結論直接寫進決策記錄的交付形態欄」）、修辭句直接刪除 — 改寫後兩邊各自更貼自己的用途、概念對應不變。</p>
<h2 id="判讀徵兆">判讀徵兆</h2>
<ul>
<li>寫第二個 surface 時發現自己在開兩個視窗對照逐段抄 — 關掉第一份、憑概念重寫、寫完再對照查漏。</li>
<li>跨 surface 掃描可操作：對兩份檔案跑完整句比對（句號切分後 grep 交集）、逐字相同的非術語句逐處判讀。</li>
<li>兩份同主題內容的 register 相同（教材版讀起來像協議、或協議版讀起來像散文）— 即使句子不同、也是語境化不完整的訊號。</li>
</ul>
]]></content:encoded></item></channel></rss>