# 方法細節

（全文方法節底稿。演算法在執行前寫定；任何修訂記入
`decision-log.md`。定義檔全文見 `prompts/`，執行紀錄見
`runs/`。）

## 自然編碼管線總覽

三個步驟：步驟 1 自由標註（兩次執行進池）→ 步驟 2 詞彙表
建構（詞向量分群，確定性）→ 步驟 3 全量編碼（2+1）。歌詞
只出現在步驟 1 與步驟 3；步驟 2 完全不接觸歌詞，也不呼叫
LLM。設計原則見 `research-plan.md`；本檔記載可重現的
演算法細節。

編號的所指為**研究程序的工序**，不是定義檔：步驟 1 與
步驟 3 有定義檔（`prompts/`），步驟 2 沒有——它是單一
確定性計算，由 `cluster-keywords` 一個子命令完成。有無
定義檔的區別即「該步是否為 LLM 判斷」，由 `prompts/` 是
否存在同號檔案直接可見。

## 步驟 2 詞彙表建構——詞向量分群

詞彙表由確定性程序產生，不經 LLM。完整分割（每個關鍵字
恰屬一組、不遺漏、不新增）由演算法結構保證，無須事後
驗證。

### 進池

兩次標註執行的全部關鍵字取聯集、逐字串精確去重、字典序
排列。失敗與拒答的記錄跳過（其歌曲不貢獻關鍵字）；解析
時偵測重複鍵，違規即失敗。同時記出處（欄位 Keyword、
Run、Song，一列一筆出現，依三欄排序），供收斂軌跡分析；
出處記錄不進任何下游輸入。

### 分群

- **嵌入**：`sentence-transformers/all-mpnet-base-v2`
  （釘定 revision），關鍵字的連字號先還原為空格再編碼，
  輸出 768 維向量並 L2 正規化。
- **分群**：階層式聚合分群（Ward linkage），k=100。
  向量既已正規化，歐氏距離與餘弦相似度單調對應；三種
  linkage 實測比較，Ward 於各個 k 的組內一致性均最高
  （average 與 complete 皆產生吞噬半數語料的巨大異質
  組）。
- **組數的取捨**：k 太小則壓縮比過高，樹上層被迫併入
  不相干的詞，組雖大而無主題（k=30 最大組 491 詞、
  組內一致性 0.41，成員橫跨籃球、海灘、外星人綁架）；
  k 太大則人工難以通覽。定於 100，理由是實測顯示雜物櫃
  組於此始裂解為有主題的組，且編碼實測未見碼數過多的
  副作用（詞彙表外的碼歸零、僅一個碼零使用）。
- **組名**：取 medoid——與該組中心（成員向量均值後
  正規化）餘弦相似度最高的成員詞。組名因此必為模型
  自己產出過的關鍵字，非任何人事後撰寫。已知限制：
  組越大越異質時，medoid 只是折衷詞，可能代表不了組內
  內容（實測 `mutual-individuality` 組內一致 0.70 而
  編碼從未使用）；此類碼於結果中呈現為零使用，據實
  報告，不事後改名。
- **取捨紀錄**：曾以 LLM 單發收斂（merge／cap 兩步）
  實作本步，四種模型六次執行全部無法維持完整分割，
  已棄用（詳見 `decision-log.md` 2026-08-05；棄用的
  定義檔止於 git 歷史，見 `git log -- prompts/`）。
- **產物**：六份，前綴分別標示來源與結果。
  `source-keywords.txt`（進池後的關鍵字，一行一個）與
  `source-provenance.csv`（出處）記錄進來的是什麼；
  `result-keywords.txt`（組名，一行一個）與
  `groups.csv`（欄位 Group、Keyword，一列一個成員）
  記錄算出來的分割；`keywords-to-merge.json`
  （`{"keywords": [...]}`）是實際交給模型的碼，即組名
  加上先驗主題詞——六份中只有這一份含研究者的介入。
  `meta.json` 記錄執行本身：進池的兩份執行歸檔與其有效
  筆數、嵌入模型與釘定 revision、分群參數與組數、外加
  的先驗詞、關鍵字總數，以及產生數字的套件版本。凡命令
  列上的選擇與環境事實皆在此，不記時間戳與輸入雜湊
  ——前者使同環境重跑逐位元組可再生，後者只會重述 git
  已保證的事。
- **可重現性**：同一輸入、同一釘定模型、同一參數逐次
  重現。不同 CPU／BLAS 實作的浮點尾數差異可能使邊界
  詞的歸屬翻動，屬已揭露的限制；論文所用碼表逐字
  commit，引用單位為該份定案檔案。

### women-power 的注入

定案詞彙表為 100 個分群組名再加上 `women-power` 一詞，
共 101 個碼。`women-power` 是研究者任意決定的先驗主題（即本
論文的主題本身），不由資料產生，屬揭露的儀器介入。該詞
於執行時以 `--extra-keyword` 明示加入，不寫死在程式裏
——研究者的介入因此每次都出現在重現命令上，而非無聲
發生；分群結果的兩份產物不含它，只有交給模型的碼表含
它。

注入而非另設篩選軌的理由：讓研究者的主題詞與模型自己
收斂出的類別（分群已自行長出 `female-empowerment` 等組）
在同一份提示詞、同一個判斷體制下受檢，避免單目標提問
把該主題的顯著性人為抬高。兩者的落點差異本身即可報告
的結果。

## 步驟 3 編碼的 2+1 比對與仲裁

- **步驟 3-1 code**：逐首比對兩次執行的標籤集合（引述不
  參與比對）。兩次皆有的標籤為共識保留、兩次皆無為
  共識不標；單邊標籤送仲裁。
- **步驟 3-2 arbitration**：仲裁者看歌詞全文與該標籤的引述
  （不含執行別），裁決保留者附仲裁者自己的引述，剔除
  者不列。剔除集合＝送裁鍵減輸出鍵，由程式推得。
- 仲裁者的引述可能與原引述不同：仲裁是對歌詞的重新
  判讀，其引述是該裁決自身的依據，非轉抄。
- 送入仲裁的標籤即模型自身不穩定的邊界判斷，其裁決為
  單次記錄性決定，不宣稱可再生；可重現性依計畫定義為
  「程序透明＋可稽核」，裁決與其輸入全程歸檔。

## 女性力量候選集

候選集為兩類歌曲的合集：定案編碼含 `women-power` 者，
以及定案編碼含研究者指認之女性力量概念域分群組者。
指認於詞彙表定案後、黃金標準編碼開始前完成，指認清單
與理由記入決策日誌。

## 軌跡對映（診斷用）

沿收斂軌跡的機械對映：原始關鍵字 →（出處記錄）歌曲、
原始關鍵字 →（分群）組，純程式查表，決定性。以其結果
與步驟 3 直接編碼的差異率作為「收斂軌跡扭曲」的診斷量，
不作主結果。

## 全管線的交接契約

每一步的輸出如何變成下一步的輸入，皆為確定性程序，規則
明定如下：

- **歌詞輸入檔（步驟 1）**：`export-llm-input` 自工作
  儲存產出，每筆 `{"id": "song-<ID>", "content": <歌詞>}`，
  依歌曲 ID 升序。步驟 3 的輸入由同一子命令、同一工作
  儲存產出（見下），兩步的語料同一性由此成立；各步
  輸入檔的 SHA-256 記入該步 meta。
- **步驟 1 → 2**：`cluster-keywords` 讀兩份執行歸檔的
  `output.jsonl`（一律以換行字元 `\n` 切行——歌詞含
  U+0085 等控制字元時，`str.splitlines()` 類的通用切行
  會截斷 JSON 字串，實測踩中），進池後直接分群，一次
  產出上列六份檔案。
- **步驟 2 → 3 輸入檔**：`export-llm-input --extras
  <定案碼表>` 自工作儲存產出步驟 3 的輸入，每筆
  `{"id": "song-<ID>", "content": <字串>}`，`content` 為
  固定鍵序序列化的 `{"lyrics": …, "keywords": [...]}`，
  依歌曲 ID 升序。碼表以參數傳入而非填進定義檔——定義
  檔只規定任務形狀，換詞彙表、換演算法都不必改它。
- **步驟 3-1 兩次執行 → 3-2**：逐首比對標籤集合（鍵
  集合，引述不參與比對）；僅有分歧的歌入仲裁輸入
  JSONL，依歌曲 ID 升序，每筆 `id` 沿用 `song-<ID>`、
  `content` 為固定鍵序序列化的
  `{"lyrics": …, "disagreements": …}`，disagreements
  鍵按字典序。
- **步驟 3 定案**：每首歌的最終標籤為共識標籤加上仲裁
  保留的標籤，寫入逐首紀錄檔（歌依 ID 升序、標籤按
  字典序，各標籤附其定案時的引述與來源層——共識或
  仲裁）。
- **序列化通則**：所有中間檔為 UTF-8，欄序、鍵序與元素
  序皆依上列規則明定，無時間戳、無隨機成分；JSON 解析
  一律偵測重複鍵，違規即失敗。人讀為主的產物採純文字或
  CSV（CSV 依 RFC 4180，標題列字首大寫），機器交接檔採
  JSON。給定相同的 LLM 執行輸出，全部交接產物逐位元組
  可再生。

## 執行與稽核

- LLM 步驟以 `run-llm <定義檔> <輸入檔> <歸檔目錄>`
  執行；2+1 步驟的兩次執行＝重現命令清單上的兩行命令，
  各自歸檔（`runs/<步驟>/run1`、`run2`），仲裁為獨立
  步驟、獨立歸檔。
- 確定性步驟（進池、分群、比對、裁決套用、對映）為
  子命令，其輸入輸出檔同隨 `runs/` 歸檔；因無執行變異，
  歸檔目錄下不分 `run<N>` 層。
- Batch API 的每筆請求自含全部脈絡且互不可見（平台
  契約），歌與歌之間的獨立性由此成立；兩次執行的獨立
  性由「兩次呼叫、兩個批次、兩份歸檔」的執行結構自明。
- 每次 `run-llm` 執行的 token 用量與費用記入
  `run-costs.md`，被取代的執行一併保留供總支出核算。

## 映射分析方法

（依 2026-07-30 決策，於看到結果前寫定；待黃金標準
編碼展開前補入。）
