<?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%B7%A5%E5%85%B7%E9%8F%88/</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>Fri, 26 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/%E5%B7%A5%E5%85%B7%E9%8F%88/index.xml" rel="self" type="application/rss+xml"/><item><title>跨 surface 鏡像的連結轉換 mapping 要窮盡、不能靠猜</title><link>https://tarrragon.github.io/blog/report/mirror-link-mapping-must-be-exhaustive/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/report/mirror-link-mapping-must-be-exhaustive/</guid><description>&lt;h2 id="論述基礎與限制">論述基礎與限制&lt;/h2>
&lt;p>本卡抽自 compositional-writing skill 鏡像同步的連續三次 CI 失敗。每次都是 &lt;code>mdtools cards&lt;/code> 報 broken link、每次都修幾個 mapping、每次都以為修完了、下次 push 又報新的。限制：evidence 來自單一 skill 的鏡像同步。&lt;/p>
&lt;h2 id="核心原則">核心原則&lt;/h2>
&lt;p>跨 surface 鏡像（&lt;code>.claude/skills/&lt;/code> → &lt;code>content/skills/&lt;/code>）的連結轉換有一個結構性約束：原始檔用相對連結（&lt;code>references/principles/xxx.md&lt;/code>，portable 設計），鏡像檔要用真實路徑（&lt;code>/report/slug/&lt;/code>，blog 內連結）。兩者的 slug 不一定一致——principle 卡的檔名是 skill 內部命名，report 卡的檔名是 blog 內部命名，兩者獨立演化。&lt;/p>
&lt;p>mapping 不完整時的失敗模式是&lt;strong>每次修一批漏一批&lt;/strong>：第一次靠 slug 精確匹配轉了 20 個、漏了 5 個不匹配的；第二次手動補了 3 個已知的 mismatch、漏了 2 個不知道對應哪張 report 的；第三次才把最後 2 個找到。三次 CI 失敗、三次 commit、三次 push。&lt;/p>
&lt;h2 id="情境">情境&lt;/h2>
&lt;p>compositional-writing 的 SKILL.md 有約 25 個 &lt;code>references/principles/xxx.md&lt;/code> 連結。鏡像同步時：&lt;/p>
&lt;ul>
&lt;li>第一輪：slug 精確匹配轉了 ~20 個，剩 5 個報 broken&lt;/li>
&lt;li>修了 3 個已知的 slug mismatch（teaching-prose → teaching-register、cross-expertise-scenario → cross-expertise-communication 等）&lt;/li>
&lt;li>CI 仍報 3 個 broken：decorative-symbols-keyword-bank、risk-asymmetric-audit-standard&lt;/li>
&lt;li>錯誤判斷「沒有對應 report 卡」→ 改成純文字&lt;/li>
&lt;li>使用者指出「一定有對應的 report 卡，找的方式有問題」&lt;/li>
&lt;li>重新用 rg 搜索 report 內容而非 slug 匹配，找到：decorative-symbols → visual-tool-error-layer-alignment、risk-asymmetric → security-teaching-rigor-asymmetry&lt;/li>
&lt;/ul>
&lt;p>根因是 mapping 的搜尋策略——只用 slug 精確匹配和少量已知 mismatch，沒有窮盡所有 principle 檔案。&lt;/p>
&lt;h2 id="理想做法">理想做法&lt;/h2>
&lt;p>建立 mapping 時用窮盡策略，不靠碰運氣：&lt;/p>
&lt;ol>
&lt;li>列出所有 principle 檔案：&lt;code>ls .claude/skills/&amp;lt;name&amp;gt;/references/principles/*.md&lt;/code>&lt;/li>
&lt;li>對每個 principle，讀它的標題和「來源」段，找出它從哪張 report 卡抽出&lt;/li>
&lt;li>用 report 卡的內容搜尋（&lt;code>rg &amp;quot;關鍵詞&amp;quot; content/report/&lt;/code>）而非 slug 匹配&lt;/li>
&lt;li>把完整 mapping 寫進腳本的 case 語句&lt;/li>
&lt;/ol>
&lt;p>mapping 的維護：每次新增 principle 卡時，同步在腳本裡加一行 case。&lt;/p>
&lt;p>自動化輔助：腳本跑完後如果有 WARN（unresolved），不要直接 commit——先確認這些 unresolved 是真的沒有 report 卡、還是 mapping 漏了。「沒有對應 report 卡」是需要證明的結論、不是搜尋失敗的預設。&lt;/p>
&lt;h2 id="沒這樣做的麻煩">沒這樣做的麻煩&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>三次 CI 失敗&lt;/strong>：每次以為修完、push 後又報新的 broken link，因為每次只修當前報錯的、沒有窮盡檢查全部 mapping&lt;/li>
&lt;li>&lt;strong>錯誤結論「沒有 report 卡」&lt;/strong>：slug 不匹配被誤判為「不存在」，實際是搜尋方式太窄（只靠檔名比對）。差點把有效連結改成純文字、損失 blog 內的導航&lt;/li>
&lt;li>&lt;strong>修法引入新問題&lt;/strong>：改成純文字後 mdtools cards 不報錯了，但讀者在 blog 上看到的是不可點擊的文字、失去了導航功能&lt;/li>
&lt;/ul>
&lt;h2 id="判讀徵兆">判讀徵兆&lt;/h2>
&lt;p>腳本輸出 WARN 時，問自己：「我用了什麼搜尋策略？只用 slug 比對、還是也搜了 report 卡的內容和標題？」如果只用 slug 比對，WARN 可能是 false negative（有對應卡但 slug 不同）。&lt;/p>
&lt;h2 id="跟其他抽象層原則的關係">跟其他抽象層原則的關係&lt;/h2>
&lt;ul>
&lt;li>→ &lt;a href="https://tarrragon.github.io/blog/report/cross-surface-recontextualize-not-transplant/" data-link-title="跨 surface 同主題內容要重新語境化、不是搬運：逐字相同句是未語境化的訊號" data-link-desc="同一個原則要同時存在於兩個 surface（教材章節與 agent 協議、blog 卡與 skill 卡）時、規範說「各寫一份、語境化在各 surface 內」— 語境化的可操作判準是：句子要跟著該 surface 的讀者與用途改寫、兩邊逐字相同的句子是未語境化的候選訊號、命中後逐處判讀。逐字搬運讓兩份內容形成沒人宣告的隱性同源、改一邊另一邊 silent 漂移、且兩邊都沒有為自己的讀者最佳化。">跨 surface 同主題內容要重新語境化、不是搬運&lt;/a>：鏡像連結轉換是跨 surface 語境化的一部分——portable skill 用相對連結、blog 用真實路徑、兩者的連結策略不同&lt;/li>
&lt;li>→ &lt;a href="https://tarrragon.github.io/blog/report/operational-how-needs-environment-specific-tooling/" data-link-title="操作指引的「怎麼做」要帶環境專屬的工具路徑" data-link-desc="操作型教材說「拍下現況」「匯出資料庫」「建立備份」時，不同執行環境（container / VM / 共享主機）的工具路徑完全不同。只寫動作不寫工具，讀者知道該做什麼但做不到。這個缺口在 fact-check 和 steelman 審查裡結構性隱形，因為動作本身在邏輯層是正確的。">操作指引要帶環境專屬工具路徑&lt;/a>：同一個「搜尋 mapping」動作在不同條件下（slug 匹配 vs 內容搜尋）的工具路徑不同，跟操作步驟缺工具指引是同構問題&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<h2 id="論述基礎與限制">論述基礎與限制</h2>
<p>本卡抽自 compositional-writing skill 鏡像同步的連續三次 CI 失敗。每次都是 <code>mdtools cards</code> 報 broken link、每次都修幾個 mapping、每次都以為修完了、下次 push 又報新的。限制：evidence 來自單一 skill 的鏡像同步。</p>
<h2 id="核心原則">核心原則</h2>
<p>跨 surface 鏡像（<code>.claude/skills/</code> → <code>content/skills/</code>）的連結轉換有一個結構性約束：原始檔用相對連結（<code>references/principles/xxx.md</code>，portable 設計），鏡像檔要用真實路徑（<code>/report/slug/</code>，blog 內連結）。兩者的 slug 不一定一致——principle 卡的檔名是 skill 內部命名，report 卡的檔名是 blog 內部命名，兩者獨立演化。</p>
<p>mapping 不完整時的失敗模式是<strong>每次修一批漏一批</strong>：第一次靠 slug 精確匹配轉了 20 個、漏了 5 個不匹配的；第二次手動補了 3 個已知的 mismatch、漏了 2 個不知道對應哪張 report 的；第三次才把最後 2 個找到。三次 CI 失敗、三次 commit、三次 push。</p>
<h2 id="情境">情境</h2>
<p>compositional-writing 的 SKILL.md 有約 25 個 <code>references/principles/xxx.md</code> 連結。鏡像同步時：</p>
<ul>
<li>第一輪：slug 精確匹配轉了 ~20 個，剩 5 個報 broken</li>
<li>修了 3 個已知的 slug mismatch（teaching-prose → teaching-register、cross-expertise-scenario → cross-expertise-communication 等）</li>
<li>CI 仍報 3 個 broken：decorative-symbols-keyword-bank、risk-asymmetric-audit-standard</li>
<li>錯誤判斷「沒有對應 report 卡」→ 改成純文字</li>
<li>使用者指出「一定有對應的 report 卡，找的方式有問題」</li>
<li>重新用 rg 搜索 report 內容而非 slug 匹配，找到：decorative-symbols → visual-tool-error-layer-alignment、risk-asymmetric → security-teaching-rigor-asymmetry</li>
</ul>
<p>根因是 mapping 的搜尋策略——只用 slug 精確匹配和少量已知 mismatch，沒有窮盡所有 principle 檔案。</p>
<h2 id="理想做法">理想做法</h2>
<p>建立 mapping 時用窮盡策略，不靠碰運氣：</p>
<ol>
<li>列出所有 principle 檔案：<code>ls .claude/skills/&lt;name&gt;/references/principles/*.md</code></li>
<li>對每個 principle，讀它的標題和「來源」段，找出它從哪張 report 卡抽出</li>
<li>用 report 卡的內容搜尋（<code>rg &quot;關鍵詞&quot; content/report/</code>）而非 slug 匹配</li>
<li>把完整 mapping 寫進腳本的 case 語句</li>
</ol>
<p>mapping 的維護：每次新增 principle 卡時，同步在腳本裡加一行 case。</p>
<p>自動化輔助：腳本跑完後如果有 WARN（unresolved），不要直接 commit——先確認這些 unresolved 是真的沒有 report 卡、還是 mapping 漏了。「沒有對應 report 卡」是需要證明的結論、不是搜尋失敗的預設。</p>
<h2 id="沒這樣做的麻煩">沒這樣做的麻煩</h2>
<ul>
<li><strong>三次 CI 失敗</strong>：每次以為修完、push 後又報新的 broken link，因為每次只修當前報錯的、沒有窮盡檢查全部 mapping</li>
<li><strong>錯誤結論「沒有 report 卡」</strong>：slug 不匹配被誤判為「不存在」，實際是搜尋方式太窄（只靠檔名比對）。差點把有效連結改成純文字、損失 blog 內的導航</li>
<li><strong>修法引入新問題</strong>：改成純文字後 mdtools cards 不報錯了，但讀者在 blog 上看到的是不可點擊的文字、失去了導航功能</li>
</ul>
<h2 id="判讀徵兆">判讀徵兆</h2>
<p>腳本輸出 WARN 時，問自己：「我用了什麼搜尋策略？只用 slug 比對、還是也搜了 report 卡的內容和標題？」如果只用 slug 比對，WARN 可能是 false negative（有對應卡但 slug 不同）。</p>
<h2 id="跟其他抽象層原則的關係">跟其他抽象層原則的關係</h2>
<ul>
<li>→ <a href="/blog/report/cross-surface-recontextualize-not-transplant/" data-link-title="跨 surface 同主題內容要重新語境化、不是搬運：逐字相同句是未語境化的訊號" data-link-desc="同一個原則要同時存在於兩個 surface（教材章節與 agent 協議、blog 卡與 skill 卡）時、規範說「各寫一份、語境化在各 surface 內」— 語境化的可操作判準是：句子要跟著該 surface 的讀者與用途改寫、兩邊逐字相同的句子是未語境化的候選訊號、命中後逐處判讀。逐字搬運讓兩份內容形成沒人宣告的隱性同源、改一邊另一邊 silent 漂移、且兩邊都沒有為自己的讀者最佳化。">跨 surface 同主題內容要重新語境化、不是搬運</a>：鏡像連結轉換是跨 surface 語境化的一部分——portable skill 用相對連結、blog 用真實路徑、兩者的連結策略不同</li>
<li>→ <a href="/blog/report/operational-how-needs-environment-specific-tooling/" data-link-title="操作指引的「怎麼做」要帶環境專屬的工具路徑" data-link-desc="操作型教材說「拍下現況」「匯出資料庫」「建立備份」時，不同執行環境（container / VM / 共享主機）的工具路徑完全不同。只寫動作不寫工具，讀者知道該做什麼但做不到。這個缺口在 fact-check 和 steelman 審查裡結構性隱形，因為動作本身在邏輯層是正確的。">操作指引要帶環境專屬工具路徑</a>：同一個「搜尋 mapping」動作在不同條件下（slug 匹配 vs 內容搜尋）的工具路徑不同，跟操作步驟缺工具指引是同構問題</li>
</ul>
]]></content:encoded></item></channel></rss>