解釋中心
部件分冊 · 第 14 頁 · 上游工具鏈

兩支 C++ 的輸入是怎麼來的?

ISM 與 LongLineage 都不是從原始訊號開始的 —— 它們吃的是已經被四個外部工具處理過的資料。 這一層不是本專案寫的程式,但它決定了所有下游分析的品質上限, 而且藏著幾個會讓人得出相反結論的陷阱。

四樣輸入、四個來源

輸入產生者它回答什麼
甲基化訊號
MM/ML tag
Dorado basecaller 這條 read 上每個 CpG 有沒有甲基化、機率多高。資料進來時就已經在 BAM 裡了。
體細胞突變清單
VCF
ClairS(配對模式) 哪些位置是腫瘤才有、正常組織沒有的突變。
單倍型標籤
HP/PS
LongPhase-S 這條 read 來自父源還是母源那一套染色體。本交接的 frozen FIFO workflow 抽成 sidecar,該次 run 不新增落地 BAM;歷史 PRE-FIX workflows 曾落地 tagged BAM。
拷貝數
CN 區段
SAVANA(僅 cna) 哪些區段被複製或缺失。目前狀態是 NOT_INTEGRATED,尚未接入主線。
7 / 7
technical datasets sidecar 全部生產完成
5.83 GiB
7 technical datasets/6 biological IDs sidecar 總量(壓縮後)
14 PRE-FIX
3,709,322,840,333 bytes;7 paired_full sampled-ID 7/7 MATCH;無 full-file SHA;PARTIAL/NON_FINAL
294.2669×
exact stat-byte 跨世代 footprint quotient;不是壓縮率,舊 287× 無效

01完整前處理鏈(8 個步驟)

從原始訊號到兩支 C++ 吃得下的東西。步驟 ① 通常在資料交付時就已完成。

圖 1 · 上游前處理鏈,以及 FIFO 如何避免該次 run 新增落地 BAM
上游八步驟前處理鏈 從 ONT 原始訊號經 Dorado basecalling 產生帶甲基化標記的 BAM; 正常組織 BAM 經 Clair3 與 LongPhase 產生定相的 germline 變異; 腫瘤與正常配對經 ClairS 產生體細胞突變 VCF 並正規化; LongPhase-S 以 germline 單倍型為骨架標記每條 read, 在 FIFO workflow mode 中,tagged BAM 寫入具名管道由另一程序即時抽成 sidecar TSV,可避免為該次 run 新增落地 BAM; 最後另跑 SAVANA 取得拷貝數。 ① Dorado basecalling 電訊號 → 鹼基 + 甲基化機率 產出 MM / ML tag ② germline 定相 Clair3 叫變異 + LongPhase 定相 在 normal BAM 上做 ③ ClairS 體細胞突變 腫瘤 + 正常配對比較 134,122 筆 ④ VCF 正規化 只改一個欄位型別,不動任何 FILTER 守恆稽核:進出筆數必須相同 ⑤ LongPhase-S — 這裡產生 HP / PS 標籤 以 germline 單倍型為骨架,判斷每條 read 屬於 HP1 還是 HP2 若該 read 同時帶體細胞變異,再細分成 1-1 / 2-1(germline 骨架上的體細胞支系)或 3 執行參數:12 執行緒、MAPQ ≥ 20、標記補充比對、輸出體細胞 VCF ⑥ FIFO mode:tagged BAM 寫進具名管道,避免該次 run 新增落地 BAM LongPhase-S 寫出 tagged BAM 串流 (若落地 = 每樣本上百 GB) 具名管道 .fifo 另一程序邊讀邊抽 每條 read 抽 9 個欄位 CIGAR 只存 8 位元組摘要 sidecar TSV 5.83 GiB (7 technical datasets 合計) 該次 FIFO run 不新增落地 BAM;歷史 canonical 仍有 14 個 PRE-FIX tagged BAM 接著驗證:列數必須等於比對數、不得有未知的 HP 值、座標必須仍然有序,任一不過就中止 ⑦ FILTER 雙向重校正稽核 比對正規化前後的 VCF,逐位點統計狀態轉移 並確認除 FILTER 外其他欄位未被改動 見下方 §3 — 這裡有個容易算錯的地方 ⑧ SAVANA 拷貝數 在雜合位點數等位比例,擬合純度與倍性 刻意只跑 cna 子命令 跑完整流程會吃到 400–488 GB 記憶體近乎 OOM 為什麼要大費周章用管道,而不是存 tagged BAM? 14 PRE-FIX BAM:3,709,322,840,333 bytes;其中 7 paired_full = 1.6743647 TiB。 sampled-identity 7/7 MATCH;full-file SHA未算。294.2669×僅跨世代footprint;287×無效。 更重要的是:分析真正需要的資訊只有「哪條 read、在哪、屬於哪個單倍型」這 9 個欄位, SEQ/QUAL未納入九欄contract;占比與用途需另做byte decomposition。 代價:無法直接用 IGV 之類的工具看標籤(見下方 §4)。
這個設計是本系統最值得學習的工程決定之一 —— 它把「我需要什麼資訊」與「這些資訊被裝在什麼容器裡」分開來想, sidecar保留 frozen downstream contract要求的全部欄位;不代表保留所有可能有用BAM資訊。

02sidecar 長什麼樣 — exact-PS/LongLineage 的 commit-scoped contract

InterSubMod 從 BAM aux tags 讀 HP/PS;exact-PS/LongLineage 使用 sidecar。 兩者是平行 provenance contracts,不是兩支引擎直接串接的執行期介面; tagged-BAM writer 只能依明示 feature/preview commit 宣稱。

#CHROM	START0	END0	QNAME	FLAG	MAPQ	CIGAR_B2	HP	PS
欄位內容
QNAMEread 的原始名稱,實測是明文 UUID(如 ec1d98d5-5fcf-45fc-9691-7641e8731385)。
CIGAR_B2比對形狀的 8 位元組摘要(不是完整 CIGAR)。省空間,但仍足以當比對用的鍵。
HP單倍型標籤。值域:1/2(germline)、1-1/2-1(帶體細胞變異的支系)、3、.(未定相)。
PS定相組編號 —— 同一組內的單倍型標籤才可互相比較。

7 個 technical datasets/6 個 biological IDs 的實際規模

資料集sidecar 列數備註
HCC139540,859,727主力樣本,1.43 GB(壓縮後)
HCC1395_DORADO40,033,094同一個生物樣本的另一次 basecalling,不是生物學重複
COLO8298,255,461有外部真值可對照
H143714,434,968純度 0.95
H200921,690,297純度 0.95
HCC1937 · HCC1954—HCC1937 的 BAM 是最大的(416 GiB)

7/7 PASS 全部生產完成並通過驗證(2026-07-11 起跑,隔日 01:31 全部驗證通過)。 7 個生產資料集 = 6 個生物樣本(HCC1395 有兩套 basecalling)。

03三個會讓你算錯數字的陷阱

● 陷阱一:突變數量會對不上,因為重校正是雙向的 LongPhase-S 不只把「原本不合格」的位點救回來,也會把原本合格的降級。 如果誤以為重校正只是「加分」,就會把重校正後的合格集當成原本合格集的超集 —— 那是錯的。
HCC1395 實測:救回 4,592 個、降級 5,528 個 → 淨變化 −936(113,997 → 113,061)。 用錯集合,骨幹突變數就會對不上。七個樣本的救回/降級數各不相同。
● 陷阱二:HP 標籤有兩種資料型別,用錯 parser 會靜默丟資料 同樣叫 HP 的欄位:LongPhase-S 寫的是字串(HP:Z:1-1), 另一個工具寫的是整數(HP:i:11),而且整數編碼是 11↔"1-1"、21↔"2-1"、33↔"3" 這種非直覺的映射。
用錯 parser 不會報錯 —— 只會讓所有「帶體細胞變異的支系」read 消失在分組之外, 看起來就像「這個樣本沒有亞群訊號」。這是最容易得出相反結論的一個坑。
● 陷阱三:1-1/2-1 不等於「已確認的亞群」 這兩個標籤的定義本身就是用體細胞變異切出來的 —— 它們是「在 germline 骨架上再被體細胞證據細分出來的 read 群」。
因此拿它去「驗證」體細胞變異的分群,就是循環論證。 ISM 甚至內建一個開關,專門把這些標籤降級成「未定相」來避免這個循環。
正確用法:HP 是鑑別器(幫忙排除「其實只是來自不同那套染色體」的假象),不是確認器。
另外兩個較次要但值得知道的限制

比對用的鍵不含序列與品質:sidecar 與 BAM 對回去時用的是 「read 名 + 染色體 + 起訖 + FLAG + CIGAR 摘要」。設計文件明寫這只能在特定條件全部成立時使用 —— 若上游 BAM 換版本、重新比對、或 read 名重複,同一把鍵可能對到多筆。 HCC1395 實測確實有 6,594,614 筆重複的完全相同比對列,但目前沒有衝突。

用的 LongPhase-S 是自訂修改版,未經上游審查。 原版在某些情況會直接中止整個程序,修改版改成印警告後繼續並保留該位點。 這改變了低品質位點的處置語意。HCC1395 出現 2 次該警告,其餘 6 個資料集為 0。 收據自己標註了「證據是有界的」。

04如果想要「帶標籤的 BAM」怎麼辦?

這是被問最多的需求之一,答案有點反直覺。

版本邊界(不可混講) InterSubMod 仍沒有寫 BAM 的能力(寫入 API 在本 repo 出現 0 次,所有開檔都是唯讀模式)。 LongLineage 則必須指定版本:private baseline/main snapshot 5daf50f 沒有 BAM writer;private public-preview candidate b9aaa12 已含 longlineage-tag-bam tagged-BAM 輸出,但仍是 NOT_READY/non-production,P3/P4/P5/P7/P8 BLOCKED。 因此「LongLineage 架構上禁止 BAM」已不是跨版本真實的敘述。

若以 private 5daf50f baseline 行為作參考,仍需獨立匯出工具;若評估 candidate b9aaa12,可測 longlineage-tag-bam。兩條路徑都依賴確定性的比對鍵:

private 5daf50f baseline 行為下的可行做法是寫一個獨立的匯出工具(讀凍結結果 + 原始 BAM,重算雜湊做比對);candidate 則要以實際 build/test receipt 確認 longlineage-tag-bam 的輸入契約與輸出語意,不可將「candidate 存在」當成「已公開/production 可用」。
● 但要先解決磁碟問題:2026-08-05 receipt 記錄當時約 617 GB available;這是 volatile observation,執行前必須用 scripts/site/doctor 或 df 重查。現有 14 個 PRE-FIX BAM 合計 3,709,322,840,333 bytes,但尚未 hash、壓縮/byte decomposition 與 production eligibility 都未驗;實務上建議只針對感興趣區間產生子集。