MCP server specification · lipidmix

ms-data-parser 仕様書

MS-DIAL(LC-MS リピドミクス/メタボロミクス解析ソフト)の出力を読み、解析をサーバ側で実行して、LLM に要約だけを返す MCP サーバの完全仕様。各ツールの入力と出力、ツール同士のつながり、統計と行列計算の中身、書き出されるファイルの形までを 1 枚にまとめる。

71ツール 5リソース 3リソーステンプレート 6入力形式 4解析経路 v1エクスポート契約 基準: main@ed11448 2026-09-29
目次
  1. 全体像とアーキテクチャ
  2. 入力データと粒度
  3. 入口と 4 つの経路
  4. セッション状態と前提連鎖
  5. 全 71 ツール リファレンス
  6. 前処理・QC の計算
  7. PCA・差次的解析・v2 統計
  8. 同定と MS/MS 照合
  9. Console 実行層と pipeline
  10. エクスポートイメージ
  11. 想定ユースケース
  12. 知識蓄積層とリソース
  13. エラー契約とコード一覧
  14. 設定・制約・既知の限界
01

全体像とアーキテクチャ

MS-DIAL は解析結果を圧縮 MessagePack と独自バイナリで書くため、GUI の外では読めず、チャットに貼るには大きすぎる。このサーバはそれらを読み、標準的な解析(前処理・PCA・差次的解析・同定の裏取り)をサーバ側で回し、LLM には結論が埋もれない大きさの要約・TSV・PNG だけを返す。生の行列は LLM の文脈に載せない。

MCP クライアント Claude Desktop Claude Code Use-LLLM(WebUI) LLM が次の手を選ぶ tools/call 要約·TSV ·PNG ms-data-parser FastMCP · server.py(薄いファサード) MCP 公開層 — lipidmix/tools/ と各形式の tools.py 71 tools · 5 resources · 3 resource templates 形式別 reader arf arf2 pai2 dcl eic mztab library analysis/ 前処理 · PCA · Welch · BH v2 統計 · スペクトル照合 plots/ volcano · EIC · mirror · PCA payload か PNG session(AnalysisSession)— パーサ別に独立したスロット arf · arf2 · pai2 · eic · dataset · library · curation · assay_kind console/ 計画 · 実行 · 生成物収集 pipeline/ 受付 · run record · 再開 ファイルシステム MS-DIAL 出力フォルダ .arf .arf2 .pai2 .dcl .EIC.aef *_tags.xml .mddata .mdproject mzTab-M 2.0 analysis-job.json · 終了証跡 生データ .wiff .raw .d .mzML … 蓄積層 analyses/ reports/ knowledge/ playbook/ 置き場は環境変数で変更可 読む 読み書き pipeline worker 別プロセス · engine.run_engine pipeline-run.json を更新 launch_detached MS-DIAL Console 外部 exe(MSDIAL_EXE) 生データ → mzTab-M · .arf 等 supervise 書き出す console_run(手動経路) Europe PMC paper_search のみ外へ
図 1-1 構成。クライアントはツールを呼ぶだけで、数値計算はすべてサーバ内で閉じる。外部ネットワークへ出るのは paper_search(Europe PMC)だけ。生データからの自動統括は MCP プロセスとは別の worker プロセスが進めるので、MCP 接続が切れても run は進む。

設計原則

文脈を守る

生の行列を返さない

JSON は json_payload() で空白なし、一覧は列名 1 回の TSV、float は丸める。全ツールに structured_output=False(付けないと同じ内容が 2 回送られる)。

図は画像で

座標より PNG

volcano の点列は実測 183,578 字 ≒ 数万トークン、サーバで描いた PNG は約 327 画像トークン。画像トークンは 幅×高さ/750 なので dpi は上げない。

失敗の形

例外でなく封筒

前提状態が無いときは missing_state の JSON 封筒を返し、どのツールを先に呼べばよいかを機械可読で伝える(13 章)。

状態の分離

スロットは形式ごと

session.arf / .arf2 / .pai2 / .eic / .dataset / .library は互いに触らない。ピーク検証の往復で ARF の前処理行列が消えない。

推測しない

曖昧なら止める

複数候補のメソッドファイル・mzTab・ライブラリ・PCA 結果は、更新日時や辞書順で黙って選ばず、*_AMBIGUOUS などで止めて選ばせる。

根拠の水準

確度を名乗らせない

MS/MS の「フラグ」と「実スペクトル」、MS1 注釈と MS/MS 証拠、gap-fill と実検出を全経路で区別し、弱い根拠を強い根拠に数えない。

パッケージ構成と依存の向き

server.py import 副作用で @mcp.tool を登録し、各モジュールの __all__ を再エクスポートするだけ(ルートから動かさない) lipidmix/tools/ 入口・サンプル検索・目的・レポート・リソース・Console・pipeline lipidmix/{arf,arf2,pai2,dcl,eic}/ reader.py + tools.py mztab/DatasetState analysis/形式非依存の数値 plots/payload · 描画 msdial/タグ · クラス · 同定 library/.dbs/.msp · SQLite corpus/知識ノートの純ロジック pipeline/ · console/ · handoff/worker はグローバル session を import しない lipidmix/core/ — leafmcp_core(DATA_DIR 等の正準)· session_state · mcp_errors · serialization · atomic_io · process_control
図 1-2 依存は上から下へだけ流れる。lipidmix.core.mcp_core から形式別 tools や lipidmix.tools.* を import すると循環になる。可変状態(DATA_DIR KNOWLEDGE_DIR ANALYSES_DIR と session)の正準は core 側で、server.<name> はスナップショットにすぎない。アラインメントのキュレーション(lipidmix/curation/:証拠収集・機械判別・フラグ記録・ビューア HTML・MS-DIAL への書き戻し)は図では省いたが、analysis/ と同じ層にあり、公開層は lipidmix/tools/curation_tools.py。
02

入力データと粒度

同じ LC-MS データが、ファイルごとに別の粒度で書かれている。「1 行」が何を指すかを取り違えると、検出率も同定も壊れた数字になる。

アラインメント結果(全試料をまたぐ)列 = 試料(FileID)· 行 = スポット(MasterAlignmentID)S1S2S3S4QC1BLKspot 0spot 1spot 2spot 3spot 4.arf2(代表・同定)PC 34:1[M+H]+ · HeightAvg · Fill%Unknown— · HeightAvg · Fill%TG 52:2[M+NH4]+ · HeightAvg · Fill%Cer_NS 18:1;O2/16:0[M+H]+ · HeightAvg · Fill%low score: PE 38:4[M+H]+ · HeightAvg · Fill%実検出(MasterPeakID ≥ 0)gap-fill 補間(MasterPeakID < 0 · IsGapFilled)セル = .arf の 1 行(PeakHeight · Area · m/z · RT · S/N · IsMsms)· セル内の波形 = .EIC.aef の点列個別測定ファイル(S3)アライン前 · 1 ファイル = 1 試料.pai2 ピーク.dcl MSDecResultid 0 · m/z 496.34has_msms ✓dcl_index 0id 1 · m/z 524.37has_msms ✓dcl_index 1id 2 · m/z 760.59has_msms ✓dcl_index 2id 3 · m/z 782.57—dcl_index 3n_msms_peaks 0id 4 · m/z 806.57has_msms ✓dcl_index 4リスト順 = dcl_index で対応precursor m/z が 0.01 超ずれたら付与しないhas_msms はフラグ · 実スペクトルは .dclS3 の列 = 右の個別ファイル(FileID で対応)
図 2-1 粒度の関係。.arf の 1 行は「1 スポット × 1 試料」、.arf2 の 1 行は「全試料を統合した 1 スポット」。ハッチのセルは gap-fill(未検出を補間した値)で、検出率や存在判定では実測と別に扱う。ID はすべて 0 始まり。
形式中身1 行 / 1 要素の粒度エンコード読むツールスロット
.arf
*_PeakProperties.arf
アライン後の試料別ピーク(高さ・面積・m/z・RT・S/N・gap-fill・MS/MS 取得)1 スポット × 1 試料MessagePack ストリーム+LZ4 ブロック(AlignmentChromPeakFeature)arf_parser ほか ARF 系session.arf
.arf2スポット代表カタログ(名前・式・Ontology・SMILES・InChIKey・アダクト・強度統計・Fill%)。試料別強度は無い1 スポット(22 列)MessagePack [header, compressed]+LZ4(AlignmentSpotProperty)arf2_parser・arf2_annotate_identitiessession.arf2
.pai21 測定ファイルの検出ピーク(アライン前)1 ファイル内の 1 ピークMessagePack+LZ4(ChromatogramPeakFeature)pai2_parser・verify_peak_annotationsession.pai2
.dclデコンボリューション済み MS/MS(MSDecResult)1 プリカーサ独自リトルエンディアン・バイナリ(MessagePack ではない)dcl_parser・dcl_find_msms・自動充填なし
.EIC.aef抽出イオンクロマトグラム1 スポット × 1 試料の点列独自バイナリ(magic CSS1)eic_*session.eic
mzTab-M 2.0Console が産む標準交換形式。MTD / SML / SMF / SME の 4 表SMF 1 行 = 1 特徴タブ区切りテキストdataset_loadsession.dataset
サイドカー*_tags.xml(タグ)、.mddata(Class ID・注入順。ZIP)、.mdproject(.mddata へのポインタ)—XML / ZIPARF 系が自動で読む—

2.1 バイナリの解き方

MessagePack の Key 番号の正解表は docs/schema/*.md(MS-DIAL の C# クラスの [Key(N)] から上流 commit 45a531c 時点で抽出)。インデックス定数を変える前に必ずここを見る。推測で直さない。

.arf · arf/reader.py

LZ4 包みの MessagePack ストリーム

  1. トップレベルの msgpack オブジェクト(ExtType か [header, ExtType|bytes])を順に読む。
  2. ブロック先頭の msgpack int が展開後サイズ。lz4.block.decompress(rest, size) で中身を得る。
  3. 中身はスポット「群」(行のリスト)。群の通し番号が MasterAlignmentID。
  4. unpacker は unicode_errors="ignore"(POS ファイルに壊れた UTF-8 がある)・strict_map_key=False・1 GiB バッファ。

行の Key: 0 FileID · 1 FileName · 2 MasterPeakID(負 = gap-fill)· 3 PeakID · 9 MS2RawSpectrumID · 10 MS2RawSpectrumID2CE(非空 = MS/MS 取得)· 15 ChromXsTop(RT)· 18 PeakHeightTop · 20 AreaAboveZero · 21 AreaAboveBaseline · 22 Mass · 37 PeakShape [noise, S/N]

.dcl · dcl/reader.py

固定長ブロックの独自形式

  1. ヘッダ 11 B: "DC" + int32 版 + bool 注釈 + int32 件数。続いて件数 × int64 のシーク位置。
  2. レコードごと: Scan 60 B(+8 ScanID、+12 RawSpectrumID、+16 PrecursorMz f64、+24 IonMode i32、+28 RT f64)→ Quant 5×f64 → Scoring 5×f32(amp・purity・quality・S/N・noise)→ Counts 3×i32 → ピーク 20 B ずつ(mass f64・intensity f64・quality i32)。
  3. dcl_index が同名 .pai2 のピーク順に対応する設計。
.EIC.aef · eic/reader.py

CSS1 形式

magic CSS1 → offset 10 へ → int32 スポット数 → int64 ポインタ列。スポットごとに 4×f32(rt・ri・mass・drift)・i8 main_type・i32 試料数、試料ごとに i32 file_id・i32 点数・f32 top/left/right、続いて (f32 x, f32 強度) × 点数。描画系は必要なスポットだけをポインタで直接読む。

.arf2 / .pai2

単発 unpackb + LZ4

.arf2: 0 MasterAlignmentID · 4 TimesCenter→RT · 5 MassCenter · 11 IonMode · 12 Name · 13 Formula · 14 Ontology · 15 SMILES · 16 InChIKey · 31 HeightAverage · 49 FillParcentage(原文ママ)· 54 AdductType

.pai2: 3/4/5 time left/top/right · 9 area · 11 MasterPeakID→id · 18 MS2RawSpectrumID · 19 CE map · 25 Name · 29 InChIKey · 40 PeakShape[1]→S/N · 43 Mass

has_msms = bool(ce_map) or ms2_id ≥ 0。取得参照があるだけで、スペクトル本体は .dcl にある。

2.2 mzTab-M の 2 つの同定の出所

SMF(特徴) SMF_ID · exp_mass_to_charge retention_time_in_seconds · abundance_assay[N] 名前も構造もここには無い SME(証拠) スペクトル照合の候補(rank 順) MS/MS が割り当てられた同定だけ → feature_metadata / candidates SML(代表) 代表同定。Text DB の MS1 照合も ここにだけ載る → feature_annotations(ラベル) SME_ID_REFS SMF_ID_REFS 1 SML → 複数 SMF(1|2)= 同一分子の複数アダクト。全 feature に同じ注釈を付ける。 複数 SML → 1 SMF = 決められないので {"ambiguous": true, "name": null}。
図 2-2 SME と SML は意味が違う。MS-DIAL は Text DB 由来の同定を SME に書かない(ShouldWriteSmeLine が除外)ので、Text DB 運用では SME 0 行・SML のみが正常。identified_by の sme(MS/MS 証拠あり)と sml_only(MS1 注釈のみ)を足して「同定件数」にしない。
gap-fillmzTab-M の abundance_assay[N] は非ゼロでも実測か補間かを区別しない。実データ(60 試料 × 714 特徴)ではセルの 70.0% が gap-fill で、非ゼロを検出と数えると検出率を 3 倍以上に過大評価する。隣接 .arf が同一アライメントだと数値で確かめられたときだけ(スポット数一致と全特徴の m/z 差 0.01 Da 以内)ds.detected_mask を取り込む。
InChIKeyderive_inchikey は database_identifier(InChIKey の正規表現に一致するとき)→ InChI → SMILES の順に RDKit で導出する。MS-DIAL は SML の inchi を常に null で書き、database_identifier は <db>:<name> 形式なので、SML から InChIKey に届くのは SMILES 経由だけ。

2.3 読み間違えやすい値

値見た目実際の意味
Name同定名空文字・Unknown・no MS2:・low score: を含みうる。存在するだけで確定同定ではない。| は複数候補の連結で左が代表とは限らない
Ontology化合物名脂質クラス(headgroup 分類)。空文字と文字列 Unknown は別扱い
ARF HeightAverage全試料平均現実装ではグループ先頭試料の値。統合統計は ARF2 側を使う
ARF 要約 named_compounds注釈済み件数空文字も数える。注釈率には使わない
PAI2 has_msmsMS/MS あり取得参照があるだけ。実スペクトルは .dcl
DCL n_msms_peaks返した本数間引き前の元本数。top_n_peaks 適用後の配列長と違いうる
EIC peak_topピーク強度頂点の横軸座標(RT)。強度は max_intensity
EIC total_samples試料数全スポットのエントリ総数。ユニーク数は len(unique_file_ids)
ARF2 FillPercentage百分率0..1 の比率
mzTab-M RT分ファイル上は秒。DatasetState は分に揃える

2.4 脂質名の文法(assay_kind=lipid のときだけ)

表記意味例
クラストークン先頭の脂質クラス = OntologyPC TG Cer_NS
C:D全アシル鎖合計の炭素数:二重結合数(species レベル、鎖は未確定)PC 34:1
C:D/C:D と _鎖を確定した molecular species。/ は sn 位置まで、_ は sn 順不明PC 16:0/18:1 · 18:1_16:0
;O ;O2追加酸素・水酸基の数Cer 18:1;O2/16:0
O- / P-アルキルエーテル / プラズマローゲン。pygoslin は species レベルで PC P-34:0 を PC O-34:1 に同一化するPC O-34:1

一般代謝物(assay_kind=metabolite)ではこの文法は成り立たず、同定の実体は候補集合(アダクト・異性体・候補順位)になる。種別が未確定のあいだはどちらの規則も当てない。

03

入口と 4 つの経路

利用者が手元に何を持っているかで入口が決まる。サーバ共通指示(MCP_INSTRUCTIONS の ENTRY POINT / GATEWAY)はこの判定を LLM に教え、最初に呼ぶツールを 1 つに絞らせる。

利用者が渡すもの フォルダ · ファイル · 質問 生データフォルダ .wiff .raw .d .mzML … MS-DIAL 未処理 MS-DIAL 出力フォルダ AlignmentResult_*.arf … GUI で解析済み mzTab-M / Console ジョブ *.mzTab · analysis-job.json 標準交換形式 この 1 ピークは本物か .pai2 + .dcl 同定の裏取り pipeline_run 自動 · 永続 run load_dataset arf2 概観 → arf PCA dataset_load mztab_path | job_path | pipeline_path pai2_parser → verify_peak_annotation 手動なら console_plan → console_run → dataset_load フォルダ未指定なら LIPIDMIX_DATA_DIR 3 つのうち 1 つだけ指定 (0 個・2 個以上はエラー) sample_search で .pai2/.dcl の実パスを引く
図 3-1 入口の判定。どこから入っても最初に load_dataset / arf_parser などが返す「意味論ダイジェスト」(出力の読み方の必須注意)が 1 回だけ前置される。アッセイ種別(assay_kind)が確定したときにもう 1 回だけ届く。

経路の全体地図

4 本の経路は別々のセッションスロットを使うので、並行して進めても互いの状態を壊さない。矢印は「前段が書いた状態を後段が前提として読む」を表す。実線は必須の前提、破線は任意。各箱の 2 行目は、そのツールが書く状態または出力。

ARF 経路mzTab-M / DatasetState 経路pipeline 経路同定・確認系灰色の箱 = 出力・任意ツール
ARF 経路MS-DIAL GUI 出力mzTab-M 経路DatasetStatepipeline生データ一括同定・確認ピーク · EIC · 照合load_dataset入口 · arf2+arf 一括arf_parser生行列 PCA · featuresarf_exclude任意 · 除外集合arf_list_sample_roles確認 · 役割 TSVarf_preprocessfeature_matrixarf_pca_preprocessedlast_pcaarf_differentiallast_differentialsave_pca_figurePNG ファイルarf_plot_volcanoPNG / payloadarf_export_differential契約 TSVconsole_plananalysis-job.jsonconsole_runmzTab-M · 証跡dataset_loadsession.datasetdataset_set_sample_metadata任意 · 群/順を訂正dataset_preprocess前処理済み行列dataset_build_matrixv2 · analysis-matrixdataset_pcalast_pcadataset_differentiallast_differentialdataset_statisticv2 · stat_<id>dataset_export_differential契約 TSVsave_*_figuresource=mztabpipeline_plan任意 · 解決結果を確認pipeline_runpipeline-run.jsonworker(別プロセス)が工程を順に進める1. prepare_input2. upstream3. validate_outputs4. load_dataset5. resolve_metadata6. preprocess7. pca8. resolve_comparisons9. differential:*10. export:*11. reportpipeline_status読取専用pipeline_resume訂正 · 再開pipeline_canceldataset_load(pipeline_path=…) で対話へ引き継ぐpai2_parsersession.pai2 · .dcl 充填verify_peak_annotationドシエ · MSIdcl_find_msmsprecursor で MS/MSarf2_annotate_identitiesGOSLIN · ID · MSIlibrary_loadsession.librarylibrary_match_featurelast_matchlibrary_plot_mirror対向 PNGeic_search_by_*spot_id を特定eic_plot_chromatograms1 spot × 試料eic_plot_compounds複数物質 × 1 試料save_eic_figurePNG ファイルlibrary 読込済みなら verify に spectral_match を追加
図 3-2 経路地図。pipeline 経路の成果物は dataset_load(pipeline_path=…) で mzTab-M 経路の対話セッションへそのまま引き継げる(同じ run の DatasetState・試料対応表・binding・解析行列をまとめて載せる)。save_pca_figure / save_volcano_figure は ARF と mzTab-M の両方を入力にでき、両方に有効な結果があると AMBIGUOUS_RESULT_SOURCE で止まる。
経路入力正準状態行の ID 空間向いている場面
ARFMS-DIAL GUI の .arf(+兄弟 .arf2、.mddata、*_tags.xml)session.arfMasterAlignmentIDGUI で解析済みのデータを探索的に見る。タグ・Class ID・因子トークンで柔軟に絞る
mzTab-MmzTab-M 2.0(Console 出力)。隣接 .arf があれば検出状態もsession.dataset(DatasetState)SMF_ID来歴を検証したいとき。実験情報シートで群・順序を訂正したいとき。v2 統計
pipeline生データフォルダ 1 つ(+任意で analysis-request.json / sample-manifest.tsv)pipeline-run.json(別プロセス)SMF_ID生データから品質レポートまで無人で。中断・訂正・再開を冪等に
同定・確認.pai2・.dcl・.EIC.aef・.arf2・参照ライブラリsession.pai2 / .eic / .libraryピーク ID · spot_id「この注釈は本物か」を MS/MS・精密質量・クロマトグラムで確かめる
キュレーションアラインメントの .arf2(+兄弟 .arf・.dcl・.EIC.aef・*_tags.xml)と、アラインメントに使った参照ライブラリ<アラインメントのフォルダ>/curation/flags.jsonl(正本)+ session.curationMasterAlignmentID注釈付きスポットを一覧で確かめ、「間違い」「疑わしい」を記録してエクスポートと MS-DIAL に返す(独立した枝・いつでも)
注意ARF 経路と mzTab-M 経路は ID 空間も RT の単位も違う(mzTab-M のファイル上の RT は秒、DatasetState は分に揃える)。同じ「spot_id」列でも MasterAlignmentID と SMF_ID を混ぜて読まない。mzTab-M 経路のエクスポートはメタ行 # id_space = mztab_smf_id で ID 空間を宣言する。

3.1 独立した枝:アラインメントのキュレーション

MS-DIAL の GUI で 1 件ずつ見ていた注釈の確認(EIC・対向プロット・Δm/z・ΔRT・RT–m/z の線形性)を、一覧と機械判別で短くする枝。どの経路とも状態を共有せず、いつでも入れる。前提は 2 本で、どちらも missing_state で止まる:.arf2 が解決できること(load_dataset か arf2_parser)と、参照ライブラリが読み込み済みであること(library_load。アラインメントと同じフォルダの *_Loaded.msp2.dbs を推奨)。

  1. curation_review — 一覧と機械判別

    注釈付きスポット(既定は全部、ontology でクラス、name_contains で名前)の証拠を集めて判定し(8.4 節)、ビューア HTML を書く。LLM に返すのは suspect 以上とフラグ済みの TSV・件数・クラス別の傾向要約・html_path だけで、EIC 系列とスペクトルは返さない。

  2. ユーザーがビューアで確かめる

    html_path をブラウザで開く。likely_wrong は赤の破線枠で「間違い」が初期選択、メモ欄には判定根拠が入っている。クラスの選択肢の「<クラス> › 自動判別: 間違い」で絞れる。直したら「送信用テキストをコピー」してチャットに貼る。

  3. curation_submit — 記録と MS-DIAL への反映

    貼られた文をそのまま渡す。flags.jsonl に追記し(正本)、アラインメントの _tags.xml の Misannotation を付け外しする(wrong → 付ける、取消 → 外す、suspect → 触らない)。

  4. エクスポートと表に効く

    arf_export_differential / dataset_export_differential は既定で wrong のスポットを同定なしとして外し、メタ行 # curation = … で宣言する(10.1 節)。arf2_annotate_identities は curation_flag 列を持つ。curation_flags で有効なフラグを一覧できる。

フラグの意味記録するのは「間違い」(wrong)と「疑わしい」(suspect)だけ。無印は「間違っていない」の意で、何も記録しない。フラグは .arf2 の sha256 と MasterAlignmentID の組で持つので、MS-DIAL を再実行してアラインメントが変わると古いフラグは当たらなくなる(件数は warnings で知らせる)。
04

セッション状態と前提連鎖

サーバは 1 プロセスに 1 つの session = AnalysisSession() を持つ。ツールは前段が書いた状態を読み、無ければ例外ではなく missing_state 封筒で「先にどれを呼ぶか」を返す。クライアントはそれを読んでリプレイする。

session(lipidmix.core.session_state)module 修飾で参照する。server.<name> に当てたパッチは効かない.arf ArfStatefeatures · filtered_featurestag_index · class_index · excluded_*feature_matrix · sample_meta · recipelast_pca(_plot) · last_differential書く: arf_parser · arf_preprocess · arf_differential.dataset DatasetStatemzTab-M 由来 · detected_mask · feature_qc前処理済み行列 · recipelast_pca · last_differentialanalysis_matrices · results書く: dataset_* 系.pai2features(.dcl の MS/MS 充填済み)filtered_features · filter_params書く: pai2_parser.arf2features(22 列のカタログ)書く: arf2_parser · load_dataset.eicfeatures · last_plot(payload)書く: eic_* 系.librarystore(SQLite)· source_path · last_match書く: library_load · library_match_feature解釈の切替と注意書きのガードassay_kind: lipid | metabolite | unknown(既定)caveat_emitted_kind · output_format_seen · sections_seenダイジェストは種別ごとに 1 回(unknown で 1 回、確定で 1 回)。未読トピックには 1 行の section_hint を毎回添える。その他current_job_path — Console ジョブの指針(正準はディスク)pipeline は別プロセスで、この session に一切触れない。進行状況は pipeline-run.json と worker の runtime にだけある。LIPIDMIX_CAVEAT_MODE=off で注意書きを止める
図 4-1 スロットは形式ごとに独立。あるパーサが別スロットを触らない(pai2_parser が ARF の前処理行列を無言で破棄した過去のバグの再発防止)。ArfState.load_data() はパスかタグディレクトリが変わったときだけ再パースし、切り替え時は派生状態を reset_analysis() で消す。図に無い session.curation は直近の review_id とレビューの保存先だけを持つ(判定結果とフラグの正本はディスク)。

4.1 前提状態の連鎖表

「このツールを呼ぶには何が要るか」。前提が無いときに返る封筒の required_tools は OR の代替候補で、クライアントは候補のうち本セッションで成功した直近の呼び出しを記録済みの引数のまま再実行する(LLM に再実行させると前処理の引数が変わりうる)。

ツール必要な状態required_tools(生成元)
arf_list_classes arf_list_tags arf_list_sample_roles arf_exclude arf_preprocessARF データarf_parser / load_dataset
arf_pca_preprocessed arf_differential前処理済み行列 preprocessed_matrixarf_preprocess
arf_plot_volcano2 群の差次的結果arf_differential
arf_export_differential2 群の差次的結果 + 兄弟 .arf2arf_differential
pai2_inspect_peak verify_peak_annotationpai2_datasetpai2_parser
library_match_featuresession.library.storelibrary_load
library_plot_mirrorlast_match(候補 1 件以上)library_match_feature
dataset_status dataset_preprocess dataset_set_sample_metadata dataset_build_matrixsession.datasetdataset_load
dataset_pca dataset_differential前処理済み DatasetStatedataset_preprocess
dataset_export_differential現在の前処理から出た差次的結果dataset_differential
dataset_statistic登録済みの解析行列dataset_build_matrix / dataset_load(pipeline_path)
dataset_build_matrix(base="internal_standard_ratio")feature_bindingsdataset_load(pipeline_path)(v2 run)
save_pca_figurePCA 結果(ARF か mzTab-M)arf_parser / arf_pca_preprocessed / load_dataset / dataset_pca
save_volcano_figure差次的結果arf_differential / dataset_differential
save_eic_figureEIC payloadeic_plot_chromatograms / eic_plot_compounds
console_run計画済みジョブconsole_plan
curation_review.arf2(arf2_file)+ session.library.store(library)load_dataset / arf2_parser、library_load
curation_flags.arf2(arf2_file)load_dataset / arf2_parser

EIC の検索系(eic_parser と eic_search_*・eic_rank_by_max_intensity)は EicState.load_data() を通るので、どれから呼んでも未ロードなら読み込まれ、missing_state にはならない。

4.2 ツールの annotations

全ツールが MCP 標準の ToolAnnotations を宣言する。readOnlyHint=true は「サーバの外(ファイル・ネットワーク)に副作用が無い」を意味し、サーバ自身の解析セッション状態の更新は副作用に数えない(依存関係は封筒で伝えるため二重に表現しない)。openWorldHint=true は paper_search だけ。同じ引数での再実行が安全かは readOnlyHint か idempotentHint で判断できる。curation_submit は destructiveHint=true:記録は追記だが、MS-DIAL の _tags.xml を書き換え、取消では Misannotation を外すため(書く前に控えを取る)。

05

全 71 ツール リファレンス

各カードは「シグネチャ・何をするか・入力・出力・前提・状態変更・注意」を同じ順で持つ。見出しをクリックすると開く。引数名と既定値は実登録のシグネチャから取った。

書込 ファイル・外部状態を変える(readOnlyHint=false)net 外部ネットワーク 前提 先行ツールが必要 長時間 数十分かかりうる

3データ探索・入口

どこから入っても最初に触れる 3 ツール。

list_data_filesフォルダ内のファイルを拡張子別に一覧する。
シグネチャ
list_data_files(extension=None, directory=None, all_files=False)
入力
directory(省略時 DATA_DIR)、extension(例 .arf2)、all_files(生データも含める)
出力
拡張子ごとの絶対パス一覧。既定は解析できる拡張子だけ(.arf .arf2 .pai2 .dcl .EIC.aef .mddata .mdproject)。all_files=True で abf/ibf/cdf/mzml/wiff/raw/d/wiff2/qgd/lcd/lrp/imzml も。.d と Waters の .raw はフォルダ=1 検体なので末尾に /
前提
なし
状態変更
なし
注意
実データでは 495 ファイル中 7 割以上が生データだったため既定で隠す。フォルダ形式の判定は console/job_manager.is_raw_input()(MS-DIAL の isVendorDirectory と同じ規則)を借りる。見つからなければ空リスト。
load_datasetMS-DIAL 出力フォルダの入口。arf2 概観 → arf PCA を一括実行する。
シグネチャ
load_dataset(directory=None)
入力
directory(省略時 LIPIDMIX_DATA_DIR)
出力
意味論ダイジェスト、バッチ選択の説明(複数バッチなら最新 AlignmentResult_<timestamp> を選んだ旨)、arf2_parser の要約、arf_parser の PCA 要約。更新があれば冒頭行に通知
前提
なし
状態変更
mcp_core.DATA_DIR を差し替え、session.arf2 と session.arf を埋める
注意
PeakProperties.arf を DriftSpots.arf より優先して自動選択する。複数バッチの告知は解析対象の .arf/.arf2 のタイムスタンプだけで判断する。

2ARF2(スポット代表カタログ)

サンプル別強度を持たない軽量なメタ層。PCA はできない。

arf2_parser.arf2 を読み、データセット全体のメタデータ概観を要約する。
シグネチャ
arf2_parser(file_path=None)
入力
file_path(省略時は最新バッチ)
出力
総スポット数、注釈数と注釈率、RT/m/z 範囲、強度中央値、イオンモード内訳、S/N 中央値、Ontology 上位 10(自然言語テキスト)
前提
なし
状態変更
session.arf2 にカタログ(22 列)を保持
注意
annotated_count は Name が空・null・Unknown 以外の件数で、確度は考慮しない。FillPercentage は 0..1 の比率。
arf2_annotate_identitiesスポット注釈を GOSLIN 正規化・RefMet/LIPID MAPS ID・MSI レベルで一括標準化する(オフライン)。
シグネチャ
arf2_annotate_identities(file_path=None, max_rows=50)
入力
file_path、max_rows
出力
TSV 表(列名 1 回。末尾列 curation_flag = wrong / suspect / 空)。ヘッダ行に総スポット数と未表示件数。ファイル先頭から max_rows 件で、強度順でも MSI 順でもない。フラグ記録が読めなければ一覧は返し、curation_flag を空にして注記する
前提
なし
状態変更
なし
注意
ARF2 には MS/MS 取得フラグも精密質量誤差も無いので has_msms=False・バンド UNKNOWN の保守評価(クラス上限)。参照表はモジュールで 1 回だけ読み、.arf2 は load_catalog()(パス+mtime+サイズでキャッシュ)経由。

10ARF(サンプル別強度・PCA・差次的解析)

session.arf を介して状態を受け渡す主経路。生行列 PCA と前処理後 PCA は独立した経路。

arf_parser.arf を読み PCA を実行する。フィルタ条件を変えた再 PCA も本ツールの再呼び出しで行う(再パースは走らない)。
シグネチャ
arf_parser(file_path=None, props=None, components=None, top_features=10, log_transform=False, min_detection_rate=0.0, min_intensity=0.0, annotation_keyword=None, tag_labels=None, tag_mode='any', tag_scope='sample_peak', tag_directory=None, missing_sample_policy='error', class_ids=None, class_missing_sample_policy='error', group_levels=None, group_factors=None, include_roles=None, spot_ids=None, ontologies=None)
入力
行列: props(既定 height)、min_detection_rate、min_intensity(スポット平均強度の下限)。選択: annotation_keyword(部分一致。ARF2 名を優先)、spot_ids、ontologies(完全一致)— 各 AND。タグ: tag_labels・tag_mode(any/all/none/not_all)・tag_scope(sample_peak/alignment_spot)。試料: class_ids(OR、大小無視)、include_roles(既定で QC/blank を外す)。色分け: group_levels / group_factors
出力
Markdown 1 件: 総スポット数、フィルタ・手動除外の注記、Class ID 分布、タグ件数、PCA 行列形状、PC1/PC2 寄与率、ローディング上位、スコアプロット用ブロック(群別件数・描画指示・points[] の json 点列)
前提
なし
状態変更
session.arf に features / filtered_features / tag_index / class_index / last_pca / last_pca_plot。選択を変えると古い前処理行列・差次結果を無効化
注意
部分集合で TIC 正規化すれば分母が、BH 補正すれば検定数が変わる。全体の FDR を保ったまま候補を見るなら全体で解析した結果を参照する。選択後に PCA 次元が足りなくても選択は保存し、PCA をスキップした理由を返す。
arf_list_classes現在の ARF データセットで使える Class ID と因子トークンを一覧する。前提
シグネチャ
arf_list_classes()
入力
なし
出力
.mddata のパス、Class ID 別サンプル数、位置別の因子語彙(JSON)
前提
arf_parser か load_dataset
状態変更
なし
注意
語彙は常にデータセット全体(session.arf.features)から作る。直前の絞り込みを引き継ぐと痩せた語彙を返してしまうため。
arf_list_tagsロード済み ARF の MS-DIAL タグを一覧する。前提
シグネチャ
arf_list_tags()
入力
なし
出力
タグ定義、サンプルファイル対応数、タグ付与数(JSON)
前提
arf_parser か load_dataset
状態変更
なし
arf_list_sample_roles試料を sample / qc / blank に分類して前処理前に確認する。前提
シグネチャ
arf_list_sample_roles()
入力
なし
出力
TSV(列: sample / role / group / batch / run_order / excluded)。全行同値の batch_source はヘッダ行へ
前提
arf_parser か load_dataset
状態変更
なし
注意
前処理は適用しない。
arf_excludePCA の外れ試料や特定スポットを名前/ID で手動除外・再包含する(可逆・非破壊)。前提
シグネチャ
arf_exclude(exclude_samples=None, exclude_spots=None, mode='add')
入力
exclude_samples(file_name 完全一致)、exclude_spots(MasterAlignmentID)、mode = add / remove / clear / list
出力
JSON: status・mode・excluded_samples・excluded_spots・samples_before/after・spots_before/after・unmatched_samples/spots・caveats
前提
arf_parser か load_dataset
状態変更
session.arf.excluded_samples / excluded_spots。filtered_features は変えない
注意
存在しない指定は unmatched として警告し、一致分だけ反映(タイプミスに寛容)。新ファイルのロードでリセット。行列を組む直前に prune_spots() が適用される。
arf_preprocessロード済み ARF 行列に前処理レシピを適用する(6 章)。前提
シグネチャ
arf_preprocess(normalize='none', blank_min_fold=None, drift_correct=False, max_qc_rsd=None, impute='half_min', props=None)
入力
normalize(tic/median/pqn/none)、blank_min_fold、drift_correct、max_qc_rsd(比率)、impute(half_min/knn/column_mean/none)、props
出力
JSON report: recipe_applied / skipped、steps、caveats、features_before/after、features_removed_total、unscaled_samples、qc_interspersion、excluded_from_matrix
前提
arf_parser か load_dataset
状態変更
session.arf.feature_matrix / pp_sample_names / pp_feature_names / sample_meta / preprocessing_recipe
arf_pca_preprocessed前処理済み行列で PCA を実行する。前提
シグネチャ
arf_pca_preprocessed(components=None, top_features=10, log_transform=False, group_levels=None, group_factors=None)
入力
components、top_features、log_transform、色分け軸
出力
arf_parser と同じ構造のテキスト+前処理レシピ。QC 点を含む(群ラベルは QC の Class ID か qc)
前提
arf_preprocess
状態変更
session.arf.last_pca
注意
色分けや log 変換だけを変えて再実行しても前処理はやり直さない。
arf_differential前処理後行列で 2 群比較(Welch t+log2FC、BH)を行う。前提
シグネチャ
arf_differential(group_a=None, group_b=None, q_threshold=0.05, log2fc_threshold=1.0, log_transform=True)
入力
group_a(基準)/ group_b(比較): 因子トークンでプール指定可、閾値、log_transform
出力
summary(n_tested / n_significant / n_up / n_down / top 15)、resolved_samples、n_a / n_b、resolved_class_ids、caveats、volcano_note。全量 volcano は同梱しない
前提
arf_preprocess
状態変更
session.arf.last_differential
注意
QC/blank は常に除外(オーバーライド不可)。上位ヒットの名前は ARF が Unknown のとき同一アラインメントの兄弟 .arf2 から補う(name_source)。多群は非公開。
arf_export_differential直近の差次的結果を InChIKey 付きの契約 TSV 1 ファイルへ書き出す。前提書込
シグネチャ
arf_export_differential(output_path, apply_curation=True)
入力
output_path、apply_curation(既定 true。キュレーションで wrong のスポットを同定なしとして外す)
出力
メタ行+15 列 TSV(10 章)。有意行だけでなく InChIKey が付いた全行
前提
arf_differential(2 群)+ 同一語幹の兄弟 .arf2
状態変更
なし(ファイルを上書き)
注意
.arf2 の MasterAlignmentID で InChIKey・Ontology・m/z・RT を結合。InChIKey 無しの行は本文から外し件数だけ残す。0 行ならエラー。契約版・符号が現行と違う結果は再実行を要求。フラグがあればメタ行 # curation = … を足し、payload の curation に {state, wrong_excluded, suspect, orphaned}。flags.jsonl に読めない行があれば書き出さずに止まる(wrong を黙って落とさない)。
arf_plot_volcano直近の 2 群比較を volcano 図で返す。前提
シグネチャ
arf_plot_volcano(max_points=800, title=None, output=None)
入力
output(image 既定 / payload)、max_points(payload の ns 間引き上限)、title
出力
image: PNG + up= down= ns= の件数キャプション(全特徴を描画)。payload: lipidmix.volcano.v1(up/down 全件、ns は等間隔で間引き、selection に件数)
前提
arf_differential
状態変更
なし
注意
ファイルは書かない。保存は save_volcano_figure。

6EIC(.EIC.aef)

クロマトグラムの検索と描画。peak_top は座標であって強度ではない。

eic_parser.EIC.aef を読み要約を返す。
シグネチャ
eic_parser(file_path=None)
入力
file_path
出力
JSON: total_spots、rt_range、mz_range、total_samples(エントリ総数。ユニーク数ではない)、total_peaks(全点数)、unique_file_ids
前提
なし
状態変更
session.eic
eic_search_by_mz_rangem/z 範囲でスポットを探す。
シグネチャ
eic_search_by_mz_range(file_path=None, min_mz=0.0, max_mz=1500, max_results=20)
入力
m/z 範囲(上限既定 1500。TG/DGDG/CL を切り落とさない)、max_results
出力
spot_id / rt / mz / num_samples の表(境界値を含む)
前提
なし
状態変更
未ロードなら session.eic を読む
eic_search_by_rt_rangeRT 範囲でスポットを探す。
シグネチャ
eic_search_by_rt_range(file_path=None, min_rt=0.0, max_rt=20.0, max_results=20)
入力
RT 範囲(分)
出力
同上
前提
なし
状態変更
未ロードなら session.eic を読む
eic_rank_by_max_intensity各試料のクロマトグラム最大強度の最大値で降順に並べる。
シグネチャ
eic_rank_by_max_intensity(file_path=None, top_n=20)
入力
top_n
出力
spot_id / rt / mz / num_samples / max_intensity
前提
なし
状態変更
未ロードなら session.eic を読む
注意
旧ツールは peak_top(RT 座標)で並べており、実質「遅い RT の一覧」だったので置き換えた。
eic_plot_chromatograms1 スポットの EIC 系列をクライアント中立の構造化プロット情報で返す。
シグネチャ
eic_plot_chromatograms(spot_id, file_path=None, file_ids=None, normalize='none', title=None)
入力
spot_id、file_ids(最大 12。省略時は試料 12 以下なら全部)、normalize(none / per_trace_max)
出力
lipidmix.eic.v1: axes、spot rt/mz、series[].x/y(4 桁丸め)・file_id・label・peak_left/top/right
前提
なし
状態変更
payload をセッションに記録(save_eic_figure の入力)
注意
画像を作らない。1 スポット分だけを CSS1 から直接読む。
eic_plot_compounds脂質名/オントロジーで選んだ複数物質の EIC を 1 試料分だけ重ねる。
シグネチャ
eic_plot_compounds(file_id, names=None, ontologies=None, file_path=None, arf2_path=None, normalize='none', top_n=8, title=None, output=None)
入力
file_id(必須・1 試料)、names(部分一致)と ontologies(完全一致)の和集合、top_n(既定 8)、output
出力
image: PNG + 描いた物質と落とした物質の 1 行キャプション。payload: lipidmix.eic.multi.v1(sample、series[] を RT 昇順、selection.candidates / candidates_evaluated / plotted / dropped[])
前提
なし
状態変更
payload をセッションに記録
注意
ARF2 の同定を EIC スポットの rt/mz(±0.02 min / ±0.01 Da)で検証し、外れを dropped に理由付きで残す(rt_mismatch / mz_mismatch / spot_out_of_range / file_id_absent / below_top_n)。一致 300 件超は HeightAverage 上位 300 に予備選抜。図に無い=試料に無い、ではない。

3PAI2 とアノテーション検証

1 ファイル = 1 試料のアライン前ピーク。MS/MS の実体は .dcl にある。

pai2_parser.pai2 を読み、ピーク在庫要約を返す。兄弟 .dcl を探して実フラグメントを充填する。
シグネチャ
pai2_parser(file_path, filter_threshold=None)
入力
file_path(必須)、filter_threshold(強度下限)
出力
total_peaks、annotated_peaks(Unknown・no MS2:・low score: を除く)、annotated_fraction、ion_mode_counts、mz/rt_range、height_summary、sn_summary、top_by_height(10)、msms_attachment(attached / dcl_file / caveat)
前提
なし
状態変更
session.pai2(features / filtered_features。MS/MS 充填済み)
注意
PCA はしない(単一試料)。precursor m/z が 0.01 超ずれたら付与しない。.dcl が無くても caveat を付けて続行(未確認であって不在ではない)。
pai2_inspect_peak特定ピークの強度・S/N・MS/MS 相当フィールドの有無を返す。前提
シグネチャ
pai2_inspect_peak(peak_id=None, peak_name=None)
入力
peak_id か peak_name(部分一致、複数可)
出力
matches[]: id / name / m/z / rt / height / area / signal_to_noise / has_msms_like_fields / formula / adduct / comment
前提
pai2_parser
状態変更
なし
注意
has_msms_like_fields はキー名の有無だけで、実スペクトルが非空かは見ない。
verify_peak_annotation1 ピークの注釈妥当性を検証するドシエを返す。前提
シグネチャ
verify_peak_annotation(peak_id=None, peak_name=None)
入力
peak_id か peak_name
出力
ドシエ: analytical_checks(精密質量誤差 ppm・アダクト整合・msms.band = PASS / FLAG_ONLY / ABSENT、PASS かつライブラリ読込済みなら spectral_match)、identity_normalization(goslin / reference / msi / class_token)、エーテル caveat、蓄積ノートの語彙ヒット、llm_decision.deterministic_summary
前提
pai2_parser
状態変更
なし
注意
MSI Level 2 を主張する前に band を見る。PASS = 実スペクトルを見た、FLAG_ONLY = フラグだけ。Level 1 は決して主張しない(8 章)。

2DCL(デコンボリューション済み MS/MS)

MessagePack ではない独自バイナリ。dcl_index が同名 .pai2 のピーク順に対応する。

dcl_parser.dcl を読み在庫要約と先頭数件の主要フラグメントを返す。
シグネチャ
dcl_parser(file_path=None, top_n_peaks=None, preview=5)
入力
file_path(特定試料なら明示)、top_n_peaks(既定 10、0 で全件)、preview
出力
summary(total_results / with_msms / msms_rate_pct / 中央値・最大フラグメント数 / precursor・RT 範囲)+ preview[](dcl_index / precursor_mz / rt / n_msms_peaks / signal_to_noise / top_fragments)
前提
なし
状態変更
なし
注意
n_msms_peaks は間引き前の元本数。
dcl_find_msmsprecursor m/z(任意で RT)に一致する MS/MS を引く。
シグネチャ
dcl_find_msms(precursor_mz, file_path=None, rt=None, mz_tol=0.01, rt_tol=0.2, top_n_peaks=None)
入力
precursor_mz、rt(同一 m/z の別溶出ピークを分離)、許容幅
出力
一致した MSDecResult のリスト、または status="not_found"
前提
なし
状態変更
なし
注意
該当ゼロは「MS/MS 未取得」であって「フラグメント不在」ではない。同定を否定する根拠にしない。

3参照ライブラリ(MS/MS スペクトル照合)

library_load → library_match_feature → library_plot_mirror の 1 本道。

library_load参照ライブラリを解決し、照合用 SQLite store を構築(またはキャッシュ再利用)する。書込
シグネチャ
library_load(file_path=None, rebuild=False, ion_mode=None)
入力
file_path、ion_mode(positive/negative → MSDIAL_MSP_POS/NEG)、rebuild
出力
record_count、ion_modes、compound_classes 上位 10、search_params(.dbs 由来のみ)、source_sha256、skipped_no_precursor_mz、records_without_ion_mode、non_utf8_lines、note
前提
なし
状態変更
session.library.store / source_path。last_match をリセット
注意
解決順: file_path → ion_mode の環境変数 → *_Loaded.msp2.dbs → 設定済み環境変数 → *.msp。複数候補は MSP_AMBIGUOUS(更新日時で選ばない)。キャッシュキーは sha256(サイズ・mtime と組で覚えて再計算を省く)。.msp は行ごとに UTF-8 → cp932 → latin-1。
library_match_feature測定 MS/MS(.dcl、全ピーク)を候補と照合し、上位をスコア付き TSV で返す。前提
シグネチャ
library_match_feature(precursor_mz, rt=None, ion_mode=None, dcl_file=None, mz_tol=None, ms2_tol=None, rt_tol=None, top_n=5)
入力
precursor_mz、rt、ion_mode、dcl_file、許容幅(明示 > store の search_params > 既定)、top_n
出力
status(success / not_found / no_candidates)、candidates_table(rank・name・5 指標・total_score)、ranked_by、scoring(rule / use_rt / ms1_tol / rt_tol)
前提
library_load
状態変更
session.library.last_match(座標・alignment・unscored_mz)
注意
並び順は MS-DIAL の GetTotalScore 移植(正規化しない和で 1 を超える)。上流の順位付けタプル全体は再現していないので、1 位の妥当性は対向プロットで確かめる。.dcl を引く窓は常に固定(0.01 Da / 0.2 分)。
library_plot_mirror直近の照合結果から対向プロット(上 = 測定、下 = 参照)を描く。前提
シグネチャ
library_plot_mirror(rank=1, output=None, scale='relative', label_policy='auto')
入力
rank、output、scale(relative / sqrt / log10)、label_policy(auto / msdial)
出力
image: PNG(採点外ピークは灰色、凡例と caption に件数)。payload: lipidmix.mirror.v2(座標は正規化前の生値)
前提
library_match_feature(候補 1 件以上)
状態変更
なし
注意
precursor がベースピークのスペクトルは relative だと診断イオンが潰れるので sqrt を使う。

4アラインメントのキュレーション

注釈付きスポットを一覧と機械判別で確かめ、ユーザーのフラグを記録して、エクスポートと MS-DIAL の _tags.xml に返す(3.1 節・8.4 節)。

curation_review注釈付きスポットの証拠を集めて機械判別し、ビューア HTML を書く。LLM には要約 TSV だけを返す。前提書込
シグネチャ
curation_review(ontology=None, name_contains=None, file_ids=None, max_traces=12, thresholds=None, file_path=None, max_rows=100)
入力
対象: 既定は注釈付き全部、ontology(クラスの一覧)、name_contains(名前の部分一致)。証拠: file_ids(EIC を重ねる試料。.arf に無い ID はエラー)、max_traces(既定 12。代表試料を必ず含む)。判定: thresholds(ppm_pass=5・ppm_borderline=10・dmz_fail_mda=10・drt_pass=0.5・drt_borderline=1.0 分 など。未知のキーはエラー)。max_rows(返す TSV の行数)
出力
review_id、counts(ok / suspect / likely_wrong)、table(suspect 以上とフラグ済みだけの TSV、判定の重い順に先頭 max_rows 行。列 spot_id name ontology adduct verdict reasons ppm dmz_mda drt wdot mpp eic_good trend_z flag)、n_table_rows_total / n_table_rows_shown、クラス別の傾向要約(点数・R²・外れ数)、warnings、html_path
前提
.arf2(load_dataset / arf2_parser)と library_load(アラインメントと同じフォルダの *_Loaded.msp2.dbs を推奨)
状態変更
session.curation(直近の review_id と保存先)。ディスクに <アラインメントのフォルダ>/curation/review-<id>.json と .html
注意
EIC 系列とスペクトルは返さない(全件はビューアにある)。1 回の上限は 3000 スポット。呼ぶたびに新しい review を作る(非冪等)。参照を引けた割合が半分未満なら別ライブラリを読んでいる疑いを warnings で出す。
curation_submitユーザーのフラグを記録し、アラインメントの _tags.xml の Misannotation に反映する。前提書込
シグネチャ
curation_submit(submission_text=None, review_id=None, flags=None, source='user', file_path=None)
入力
submission_text(ビューアの送信用テキストをそのまま。CURATION_SUBMIT で始まる行だけを読む)か、review_id + flags=[{spot_id, flag: wrong|suspect|clear, note}]。source(user = ユーザー自身の判断 / llm = LLM の提案にユーザーが同意)、file_path
出力
recorded、n_wrong / n_suspect(有効フラグの件数)、tags_xml = {path, added, removed, created, backup, note}(失敗時は error と message)
前提
その review_id のレビューがディスクにあること(セッションの記録 → 送信用テキストの arf2_path → file_path → 既定の .arf2 の順に探すので、サーバ再起動の後でも貼り直せば通る)
状態変更
curation/flags.jsonl へ追記。アラインメントの _tags.xml の Misannotation(タグ Id 3)を wrong で付け、clear で外す(suspect と他のタグは触らない)。書く前に curation/tags-backup/ へ控え
注意
ユーザーの同意なしに呼ばない。不正な要素・同じ spot_id の二重指定が 1 つでもあれば何も書かない。レビュー後に .arf2 が変わっていれば拒否。flags.jsonl が正本で、_tags.xml への反映が失敗しても記録は残る。MS-DIAL でプロジェクトを開いたままだと GUI の保存で上書きされるので、閉じてから開き直す。destructiveHint=true。
curation_flags現在のアラインメントで有効なフラグを TSV で返す。前提
シグネチャ
curation_flags(file_path=None)
入力
file_path(省略時は既定の .arf2)
出力
alignment_file、n_flags、table(spot_id flag note source ts。スポットごとの最新 1 行、取消済みは除く)
前提
.arf2(load_dataset / arf2_parser)
状態変更
なし
注意
今の .arf2 の sha256 に付いたフラグだけを数える。flags.jsonl に読めない行があればファイル名と行番号を返して止まる。
curation_view_dataMCP Apps のビューア専用。レビューのスポット証拠を 1 ページずつ返す。LLM は呼ばない。
シグネチャ
curation_view_data(review_id, page=0)
入力
review_id、page
出力
review(メタ)、spots(1 ページ 50 件。EIC 系列・対向スペクトルを含む)、page、n_pages
前提
レビューがディスクにあること
状態変更
なし
注意
会話内表示(ui://ms-data-parser/curation-viewer)用。Claude Desktop のローカル stdio サーバでは _meta.ui が落ちる不具合があり未検証で、ブラウザで html_path を開く経路が主。

8MS-DIAL Console 実行層(生データ → mzTab-M)

GUI で作ったメソッドファイルを使い、MS-DIAL 本体を CLI 実行する手動経路。9 章に詳細。

console_plan実行計画を作り analysis-job.json を生成する。書込
シグネチャ
console_plan(dataset_root, method_file=None, polarity='positive', measure='peak_height', omics='lipidomics', save_project=True, timeout_s=21600, lbm_file=None)
入力
dataset_root(生データフォルダ)、method_file(省略時は GUI が自動保存した <project>_param_<時刻>.txt から極性一致の最新)、polarity、measure、omics、save_project、timeout_s(6 時間)、lbm_file
出力
job_path、解決済みメソッド・LBM・極性、warnings(既存アライメント結果など)
前提
なし
状態変更
session.current_job_path、run_dir/effective-method.txt(元ファイルは変更しない)
注意
止まる条件: METHOD_FILE_NOT_GIVEN / METHOD_FILE_CHOICE_REQUIRED / METHOD_FILE_NOT_TEXT(.mdproject/.mddata は ZIP)/ METHOD_FILE_POLARITY_MISMATCH / LBM_NOT_FOUND / LBM_AMBIGUOUS / UNSUPPORTED_AREA_CONSOLE / MSDIAL_EXE_NOT_FOUND / MSDIAL_EXE_NOT_CONSOLE / MIXED_RAW_FORMATS。
console_runMS-DIAL Console を実行する。前提書込長時間
シグネチャ
console_run(job_path=None, detach=False)
入力
job_path(省略時 session.current_job_path)、detach(監視ワーカーを切り離して即座に戻る)
出力
status(completed / partial / failed)、終了証跡、生成物の要約。detach=True なら監視ワーカーの pid(pid_of: "worker")
前提
console_plan
状態変更
run_dir/execution-result.json、生成物(-o エクスポート先と生データフォルダの 2 か所)
注意
終了コード 0 だけでは completed にしない(主 mzTab-M が一意・構造妥当・有限値あり・予定入力が全て assay に 1 対 1)。同じジョブを別プロセスが実行中なら JOB_BUSY。実データ 60 試料で約 44 分。
console_statusジョブの現在のステータスを返す(読取専用)。
シグネチャ
console_status(job_path=None, include_artifacts=False)
入力
job_path、include_artifacts
出力
status、artifact_count、artifacts_by_role(既定)、include_artifacts=True で path/role/format/root の TSV、execution(save_project / timeout_s)、execution_receipt、server_version、update_available
前提
なし
状態変更
なし
注意
完了処理はしない(監視ワーカーが確定させる)。旧方式のジョブは生成物の有無だけで完了と判定せず EXECUTION_UNRESOLVED。60 試料で 313 件出るため既定で全文は返さない。
console_prepare_input計測フォーマットが 1 種類だけの入力フォルダを作る。書込
シグネチャ
console_prepare_input(dataset_root, keep_extension='wiff', out_dir=None)
入力
dataset_root、keep_extension、out_dir(省略時 <元>_<拡張子>)
出力
作成したフォルダと集めたファイル数
前提
なし
状態変更
なし
注意
MIXED_RAW_FORMATS の解消手段。指定拡張子と随伴ファイル(.wiff.scan / .timeseries.data 等)だけをハードリンク(別ボリュームならコピー)。フォルダ形式も扱う。元フォルダは一切変更しない。
console_method_template既存パラメータから別極性用のメソッドファイルを作る。書込
シグネチャ
console_method_template(out_path, polarity, based_on=None, dataset_root=None, omics='lipidomics')
入力
out_path、polarity、based_on(省略時は候補から 1 件なら採用)
出力
作成したファイルと差し替えた項目
前提
なし
状態変更
なし
注意
まず console_plan の method_file 省略を試す。差し替えるのは Ion mode と Searched adduct ions だけで、空の Lbm file path も解決して埋める。候補が複数なら METHOD_FILE_CHOICE_REQUIRED。
console_method_candidates使えるメソッドファイルの候補を列挙する。
シグネチャ
console_method_candidates(dataset_root, polarity=None, omics='lipidomics', search_dirs=None)
入力
dataset_root、polarity、search_dirs
出力
候補ごとに origin(same_dir / sibling / past_run / given)、usable(direct / needs_polarity_conversion)、key_params(10 件以下のとき)
前提
なし
状態変更
なし
注意
探すのは dataset_root 直下 → 兄弟フォルダ直下 → 過去 run が使ったメソッド。再帰しない。
console_cleanupあるジョブが生成したファイルだけを一覧・削除する。書込
シグネチャ
console_cleanup(job_path=None, dry_run=True)
入力
job_path、dry_run(既定 True)
出力
削除対象(または削除した)一覧、warnings
前提
なし
状態変更
削除後のジョブ status は cleaned
注意
消すのは analysis-job.json が記録した生成物だけで、タイムスタンプの推測はしない(記録なしは NO_JOB_OUTPUT)。生データには触れない。監視ワーカーが実行中なら JOB_BUSY。
job_listdataset_root/runs/ 以下のジョブを新しい順に返す。
シグネチャ
job_list(dataset_root)
入力
dataset_root
出力
ジョブ一覧
前提
なし
状態変更
なし

9DatasetState(mzTab-M 経路)

mzTab-M 2.0 を正準状態として読み、ARF 経路と同じ前処理・PCA・差次的解析を回す。session.dataset は独立スロット。

dataset_loadmzTab-M 2.0 を読み session.dataset を作る。書込
シグネチャ
dataset_load(mztab_path=None, job_path=None, pipeline_path=None, allow_incomplete=False)
入力
mztab_path / job_path / pipeline_path のいずれか 1 つ、allow_incomplete
出力
要約: 特徴数・試料数・定量尺度、検出状態の行、同定の出所内訳(SME / SML のみ / なし)、inchikey_coverage、source_verification(verified / legacy_unverified / direct_unverified)、warnings
前提
なし
状態変更
session.dataset(pipeline_path なら試料対応表・binding・解析行列も同じ run から)
注意
隣接 .arf が同一アライメントだと数値で検証できたときだけ検出状態を取り込む。completed 以外のジョブは INCOMPLETE_ANALYSIS_JOB。allow_incomplete=True なら探索専用になり、差次的解析とエクスポートは EXPLORATORY_ONLY_DATASET で拒否。
dataset_status現在の DatasetState の概要を返す。前提
シグネチャ
dataset_status()
入力
なし
出力
samples(name/role の TSV。dataset_differential の群名はこれをそのまま使う)、detection(available・gap-fill 率)、inchikey_coverage、update_available
前提
dataset_load
状態変更
なし
注意
available=false の間は検出率・欠測率を語ってはいけない。
dataset_preprocess定量行列に前処理レシピを適用する(引数は arf_preprocess と同一+検出率)。前提
シグネチャ
dataset_preprocess(normalize='none', blank_min_fold=None, drift_correct=False, max_qc_rsd=None, impute='half_min', min_detection_rate=0.0)
入力
レシピ、min_detection_rate(gap-fill を除いた実検出率。検出状態があるときだけ)
出力
report(arf_preprocess と同形)+ detection.n_samples、sample_meta の batch_source / run_order_source
前提
dataset_load
状態変更
session.dataset の前処理済み行列と recipe
注意
注入順とバッチは MTD の MS:4000089 / MS:4000088 から読むので drift_correct が実際に効く。バッチラベルは 2 値以上のときだけ採用(MS-DIAL 既定は全件 1)。
dataset_pca前処理済み DatasetState で PCA を行う。前提
シグネチャ
dataset_pca(n_components=5, log_transform=False)
入力
n_components、log_transform
出力
スコア、寄与率、run_order_correlation、caveats
前提
dataset_preprocess
状態変更
session.dataset.last_pca(ローディング全量)
dataset_differential前処理済み行列で 2 群比較(Welch+BH-FDR)を行う。前提
シグネチャ
dataset_differential(group_a, group_b, q_threshold=0.05, log2fc_threshold=1.0, log_transform=True, group_a_label='group_a', group_b_label='group_b')
入力
group_a / group_b = サンプル名のリスト(dataset_status の samples)、閾値、ラベル
出力
summary、n_a / n_b、caveats、result_id。正の log2FC は group_b が高い
前提
dataset_preprocess
状態変更
session.dataset.last_differential(全特徴・volcano 点列)
注意
群名から向きを推測しない汎用ツール。pipeline の明示比較(resolve_comparison / run_comparison)の前提検証は経ない。
dataset_export_differential指定した差次的結果を契約 TSV へ書き出す。前提書込
シグネチャ
dataset_export_differential(output_path, result_id=None, apply_curation=True)
入力
output_path、result_id(省略時は直近)、apply_curation(既定 true)
出力
メタ行(result_id / preprocess_id / source_verification / id_space)+ 15 列
前提
dataset_differential
状態変更
なし
注意
前処理をやり直した後の古い結果は書かない(STALE_ANALYSIS_RESULT)。一時ファイルから置換して確定。InChIKey は mzTab-M 由来、ontology と msi_level は空欄。キュレーションのフラグは SMF_ID と MasterAlignmentID の対応が検証できたときだけ当てる(applied / not_applied / unmapped)。flags.jsonl が読めなければ CURATION_FLAGS_INVALID。
dataset_set_sample_metadata実験情報シート(sample-manifest.v1 / v2、TSV)を全件検証してから一括反映する。前提書込
シグネチャ
dataset_set_sample_metadata(manifest_path)
入力
manifest_path
出力
changed_fields、無効化した結果、warnings
前提
dataset_load
状態変更
session.dataset の試料メタデータ
注意
一部だけ適用される状態は作らない(不備があれば何も変えずにエラー)。前処理入力が変われば前処理・PCA・差次を無効化、group だけなら差次だけ。
dataset_build_matrixv2 の解析行列(analysis-matrix.v1)を 1 本作る。前提
シグネチャ
dataset_build_matrix(recipe, recipe_id='default')
入力
recipe(base / normalize / drift_correct / filter / impute の 5 キー。profile の matrix_recipes と同じ検証)
出力
matrix_id(入力 identity の hash)、形状、eligibility の要約、caveats
前提
dataset_load
状態変更
ds.analysis_matrices[matrix_id](値は戻り値に載せない)
注意
base="internal_standard_ratio" は binding が要るので missing_state。検出状態不明なら filter は not_evaluable で feature を落とさない。
dataset_statistic名指しした解析行列に v2 統計を 1 件実行する。前提
シグネチャ
dataset_statistic(specification, matrix_result_id)
入力
specification(kind = welch / anova_tukey / pca と群・変換・閾値)、matrix_result_id
出力
statistic-result.v1 の要約(effect_size_definition、groups、bh_population、件数)
前提
dataset_load + 登録済みの解析行列
状態変更
session.dataset.results["stat_<id>"]
注意
行列が無ければ ANALYSIS_RESULT_NOT_FOUND(近い行列で代用しない)。

5pipeline(生データフォルダ起点の統括)

生データフォルダ 1 つを渡すだけで、Console 実行から品質レポートまでを 1 本の永続 run として進める。

pipeline_run入力検査・計画保存・worker 起動までを一括で行い、短時間で pipeline_path を返す。書込長時間
シグネチャ
pipeline_run(dataset_root, request=None, request_id=None)
入力
dataset_root、request(target / polarity / method_file / sample_manifest / preprocess / comparisons …)、request_id(冪等性キー)
出力
receipt: pipeline_path、status、launch.handshake、needs_input
前提
なし
状態変更
<pipeline_root>/pipeline-run.json、worker プロセス
注意
優先順位は request の明示値 > analysis-request.json > 既定値(preprocess は子キー単位)。同一内容の再送は同じ結果、別内容は IDEMPOTENCY_CONFLICT。壊れた実験情報シートは Console を起動せず needs_input。
pipeline_planpipeline_run と同じ入力検査・計画保存だけを行い、worker を起動しない。書込
シグネチャ
pipeline_plan(dataset_root, request=None, request_id=None)
入力
同上
出力
receipt + resolved(method の source_path・sha256、LBM、polarity の value・source)
前提
なし
状態変更
pipeline-run.json(status planned / needs_input)
pipeline_statusrun の状態を読む(読取専用)。
シグネチャ
pipeline_status(pipeline_path, include_details=False)
入力
pipeline_path、include_details
出力
status、stage_statuses、needs_input、warnings、running なら observed_health(ok / worker_missing / unknown)と recovery_hint
前提
なし
状態変更
なし
注意
生存確認に失敗しても status は変えず別軸で返す。呼ばなくても worker は最後まで進める。
pipeline_resume入力訂正・下流の再計算・中断した工程からの再開を行う。書込長時間
シグネチャ
pipeline_resume(pipeline_path, updates=None, request_id=None, rerun_upstream=False)
入力
updates(target / sample_manifest / preprocess / comparisons に限定)、rerun_upstream
出力
receipt(新 revision、pending に戻した stage)
前提
なし
状態変更
新しい attempt / revision を記録
注意
rerun_upstream=True を明示しない限り Console は再実行しない(自動再試行なし)。再実行時は新しい attempt ディレクトリ。
pipeline_cancel取消要求を保存する。書込
シグネチャ
pipeline_cancel(pipeline_path)
入力
pipeline_path
出力
受理の receipt(停止の確定は pipeline_status で確認)
前提
なし
状態変更
協調的な取消フラグ(小さな JSON)
注意
生データを削除しない。二重に呼んでも同じ状態(冪等)。

2実験目的の記録

gap 駆動の文献探索の前提になる目的と小問を analyses/ に保存する。

record_objective確定した実験目的を analyses/<analysis_id>.md に記録する。書込
シグネチャ
record_objective(analysis_id, dataset, polarity, groups, comparison, sub_questions, biological_context='', inferred_objective='', confirmed_objective='', expected_biology=None, assay_kind='unknown')
入力
目的・比較・群・小問 Q1..Qn、assay_kind(lipid / metabolite / unknown)
出力
保存先と記録内容
前提
なし
状態変更
session.assay_kind を切り替え(以後の解釈規則が変わる)
update_objective目的・文脈・状態・assay_kind を更新し、創発的な小問を追記する。書込
シグネチャ
update_objective(analysis_id, confirmed_objective=None, biological_context=None, status=None, add_subquestions=None, assay_kind=None)
入力
更新する項目
出力
更新後の要約
前提
なし
状態変更
なし

7知識カバレッジ・文献探索・取り込み

小問ごとの知識の穴を見つけ、文献を隔離区画に取り込み、人の確認を経て信頼知識へ昇格させる。12 章に流れ図。

knowledge_coverageobjective の各小問を COVERED / WEAK / GAP に分類する。
シグネチャ
knowledge_coverage(analysis_id)
入力
analysis_id
出力
小問ごとの分類と根拠ノート。未探索の GAP が自動探索の対象
前提
なし
状態変更
なし
ingest_stage関連候補を knowledge/_inbox に speculative として隔離する。書込
シグネチャ
ingest_stage(title, abstract, source, found_for, query, relevance_score=None, doi=None)
入力
出典必須、どの小問のためか
出力
作成したノートの slug
前提
なし
状態変更
なし
ingest_review_queue_inbox の保留ノートを analysis_id × Qi でグループ化して返す。
シグネチャ
ingest_review_queue()
入力
なし
出力
レビュー待ち一覧
前提
なし
状態変更
なし
ingest_promote保留ノートを knowledge/ へ昇格する。書込
シグネチャ
ingest_promote(slug, claim_strength='suggested', links=None)
入力
slug、claim_strength、links
出力
昇格したノート
前提
なし
状態変更
なし
注意
信頼知識化の唯一の経路。
ingest_reject保留ノートを破棄する。書込
シグネチャ
ingest_reject(slug)
入力
slug
出力
結果
前提
なし
状態変更
なし

6図の保存・レポート

通常の対話では PNG ファイルを作らない。利用者が明示したときだけ保存する。

save_pca_figure指定した PCA 結果を reports/figures/ に PNG で保存する。前提書込
シグネチャ
save_pca_figure(analysis_id, title=None, source='auto', result_id=None)
入力
analysis_id、source(arf / mztab / auto)、result_id
出力
保存先、選ばれた source と result_id
前提
PCA 実行済み(ARF か mzTab-M)
状態変更
なし
注意
有効な結果が 2 つ以上なら AMBIGUOUS_RESULT_SOURCE(どちらも優先しない)。古い結果は選べない。探索専用データセットの図には但し書きを焼き込む。
save_volcano_figure指定した 2 群比較を volcano PNG として保存する。前提書込
シグネチャ
save_volcano_figure(analysis_id, title=None, source='auto', result_id=None)
入力
同上
出力
保存先、source、result_id
前提
arf_differential か dataset_differential
状態変更
なし
注意
arf_plot_volcano の画像モードと同じ描画関数。
save_eic_figure直近の EIC プロット情報を PNG 化して保存する。前提書込
シグネチャ
save_eic_figure(analysis_id, title=None)
入力
analysis_id
出力
reports/figures/<analysis_id>_eic.png
前提
eic_plot_chromatograms か eic_plot_compounds
状態変更
なし
注意
plot_schema(eic.v1 / eic.multi.v1)で描画関数を選ぶ。
write_report解析・解釈レポートを reports/<analysis_id>.md に上書き保存する。書込
シグネチャ
write_report(analysis_id, dataset, body, status='draft', knowledge_refs=None)
入力
本文 Markdown、status、参照した知識ノート
出力
保存先
前提
なし
状態変更
なし
read_report過去レポートを読み戻す(最新更新のもの)。
シグネチャ
read_report(analysis_id)
入力
analysis_id
出力
レポート本文
前提
なし
状態変更
なし
list_reports既存レポートの 1 行索引を返す。
シグネチャ
list_reports()
入力
なし
出力
analysis_id / date / status
前提
なし
状態変更
なし

1サーバ自身の更新

解析の流れには現れない保守ツール。

server_updateこのクローンを origin/main へ早送りし、requirements.txt が変わったときだけ依存を入れ直す。書込
シグネチャ
server_update()
入力
なし
出力
status = up_to_date / updated / updated_with_warning / refused、reason、再起動を促す message
前提
なし
状態変更
なし
注意
プロセスは操作しない(クライアントの再起動は利用者)。未コミット変更・main 以外・早送り不可・オフラインなら何もせず refused。
06

前処理・QC の計算

解析行列は行 = 試料(assay)、列 = 特徴量で持つ。DatasetState.feature_matrix は(特徴 × assay)で保存され、解析の入口で転置される。v1(ARF ツール・dataset_* ツール・v1 pipeline)と v2(LC–MS メタボロミクス profile)は別の実装で、数値の約束事も違う。この章は v1 を扱い、v2 の行列は 7.6 節で扱う。

6.1 入力行列の組み立て

ARF 経路 · build_pca_matrix()
  • 行 = 試料(FileName)、列 = Spot_<MasterAlignmentID>_<prop>。既定の prop は height(area area_above_baseline m_z rt signal_to_noise も可)。
  • None は 0.0。gap-fill 値(MasterPeakID < 0)も値として残すが、検出には数えない。
  • 残る NaN は列平均で埋め、全 NaN 列は 0。分散 0 の列(ddof=1)は落とす。
  • min_detection_rate > 0 なら「非 gap-fill 試料数 / 全試料数」が閾値未満の列を落とす。
  • 結果として ARF 経路では impute 前に NaN がほぼ残らず、half_min は事実上何もしない。
mzTab-M 経路 · build_dataset_pp_inputs()
  • feature_matrix を転置。実験情報シート適用済みなら include=false の行を落とす。
  • role・batch・注入順はシート由来。無ければ role は detect_sample_roles、batch は MTD の batch label(2 値以上あるときだけ採用)→ ファイル名の 8 桁日付、注入順は MTD の injection sequence label(MS:4000089)。
  • 検出率フィルタは前処理の前(_apply_detection_filter)。gap-fill と実測の区別は正規化・補完のあとでは付かないため。分母は include=true の試料だけ(全 role)。
  • 検出状態が無いのに min_detection_rate > 0 なら bad_request(「無い」と「全部未検出」は解釈が正反対)。

役割の判定(sample / qc / blank)

detect_sample_roles() はファイル名と Class ID を _ で区切り、大小無視でトークン照合する。既定トークンは qc と blank。blank を先に評価し、どちらにも当たらなければ sample。detect_qc_strata() は QC 名から 8 桁日付・数字・qc・neg・pos を除いた残りで層を判定し(例 20240311_QC_Cerebellum_ICR_NEG_1 → cerebellum_icr)、層が 2 つ以上なら「全 QC を 1 系列扱いするドリフト補正/RSD は近似」と警告する。

6.2 前処理レシピの実行順

preprocessing.preprocess(matrix, sample_names, roles, run_order, recipe) の実行順。既定は何も適用しない opt-in(ツール既定: normalize="none"、blank_min_fold=None、drift_correct=False、max_qc_rsd=None、impute="half_min")。

入力 X(試料 × 特徴) step 0 失敗 QC 検出 生強度で判定 値は変えない step 1 ブランク除去 列マスクを作る blank_min_fold step 2 正規化 値を変える tic·median·pqn step 3 ドリフト補正 値を変える drift_correct step 4 QC RSD 列マスク max_qc_rsd step 5 マスク適用 X[:, keep] 1 と 4 の AND step 6 欠損補完 NaN だけ埋める half_min 既定 呼出側 blank 行を除外 QC 行は残す drop_samples_by_role マスクは即座には適用せず step 5 でまとめて列を落とす mzTab-M 経路だけ: 検出率フィルタ _apply_detection_filter → step 0 より前 report に残るもの recipe_applied · recipe_skipped · steps · caveats features_before / after · features_removed_total
図 6-1 前処理の順序。緑の箱は列を落とす判定(マスク)、青の箱は値を書き換える処理。ブランクは背景除去の参照に使い終えてから行ごと外す(残すと桁違いに低い総強度が PC1 を支配する)。QC は PCA で締まり具合を見るために残す。steps[*].removed はフィルタごとの独立件数で重なり得るので足し合わせず、総数は features_removed_total を読む。

6.3 各ステップの式

step 0 · 失敗 QC 注入の検出 detect_failed_qc(min_ratio=0.2)

QC 注入 q の総強度TICq = Σj xqj
失敗の判定TICq < 0.2 × median(TICQC) (QC が 3 本以上あるときだけ評価)

失敗注入を残したまま max_qc_rsd を掛けると QC の RSD が全特徴で跳ね上がり、ほぼ全特徴が落ちる(実測: kidney aging NEG で 1345 → 51)。「閾値が厳しすぎる」ように見える現象の真因は QC 側にあることが多いので、arf_exclude で除外して前処理し直す。

step 1 · ブランク除去 blank_filter(min_fold)

特徴 j の比rj = meansample(x·j)meanblank(x·j) (分母 ≤ 0 なら +∞)
残す条件rj ≥ blank_min_fold (QC 行は平均に入れない)

blank 行か sample 行が無ければ未実施(status="skipped" と caveat)。ツール既定は off、conservative-v1 の auto では 3.0。

step 2 · 正規化 normalize(method)

どの方法も行(試料)ごとの係数で割る: x′ij = xij / fi。v1 に内部標準比は無い(v2 の base="internal_standard_ratio" だけ)。

method係数 fi水準の保存注意
ticΣj xij(NaN 無視)fi ← fi / median(有効な f)総和 > 0 なので疎データでも安全
medianmedianj xij同上未検出 = 0 が過半の試料で 0 になりやすい
pqnmedianj( xij / refj )、refj = QC 行の median(QC が無ければ全行の median。この段では blank も含む)。refj = 0 は NaN 扱い再スケールしない積分での事前正規化は無い。report.pqn_reference = qc_median / all_sample_median
none——差次的解析で「未正規化」caveat
縮退係数が 0 または非有限の試料は、行を NaN 化して捨てず 係数 1(未正規化のまま)で残し、report["unscaled_samples"] と caveat で明示する。旧実装はこの行を NaN で消し、疎データで多数の試料を黙って失っていた。pipeline(conservative-v1)ではこれが 1 件でもあると NORMALIZATION_DEGENERATE で止まる。

step 3 · QC ドリフト補正 qc_drift_correct(min_qc=4, window=5)

名前は QC-RLSC に倣うが LOESS ではない。実装は QC を注入順に並べた移動中央値+区分線形補間で、特徴ごとに全ラン 1 系列として補正する(バッチ別の扱いは無い)。

1102030405060406080100120注入順(run order)強度global_level = median(QC)trend = 移動中央値(窓 5)→ np.interp で全注入へQC試料補正: x′ = x × global_level / trend(order)
図 6-2 ドリフト補正の仕組み(模式図)。QC(四角)の移動中央値が系統ドリフト。np.interp は QC 区間の外で端値を定数外挿するので、QC を全試料の後にまとめて流した設計(例: 試料 1–48 → Blank 49 → QC 50–56)では補正した外見だけが残る。そのため QC 区間に入る試料が 0 なら未実施、半数未満なら「外挿補正」caveat を付ける(report["qc_interspersion"] の covered / qc_range / sample_range)。
有効窓w = min(5, nQC)、偶数なら −1(奇数に)
トレンドtrendj = movmedianw(QCj を注入順に並べた列) 端では窓が縮む
全注入へ補間Tij = interp(orderi; orderQC, trendj)
補正x′ij = xij × median(QCj)Tij (T ≤ 0 なら係数 1、median が 0/非有限なら特徴ごと無補正)

未実施になる条件: 注入順を持たない試料がある / 注入順つき QC が 4 本未満 / QC 区間に入る試料が 0(covered == 0)。注入順は ARF 経路では .mddata の analytical_order、mzTab-M 経路では MTD assay[N]-custom[...] の MS:4000089、pipeline では実験情報シート。

step 4 · QC RSD フィルタ qc_rsd_filter(max_rsd)

相対標準偏差RSDj = sd(QCj; ddof=1)mean(QCj) (mean ≤ 0 なら +∞)
残す条件RSDj ≤ max_qc_rsd 比率で指定(0.30 = 30%)。QC 2 本未満なら未実施

step 6 · 欠損補完 impute(method)

method埋める値備考
half_min(既定)列 j の非 NaN 最小値 / 20 も最小値に数えるので、0 を含む列は 0 で埋まる。全 NaN 列は 0
column_mean列平均(旧実装互換)全 NaN 列は 0
knnsklearn.impute.KNNImputer(n_neighbors=min(5, max(1, n−1)))試料間距離で近傍平均
none補完しないNaN が残ると PCA は失敗する

preprocess に対数変換とスケーリングの段は無い。対数は PCA(log10)と差次的解析(log2(x+1))がそれぞれ下流で掛ける。Pareto スケーリングはコードのどこにも無い。

6.4 pipeline の自動判定 conservative-v1

dataset_service.preprocess_auto が使う方針(lipidmix/analysis/preprocess_policy.py、POLICY_VERSION="conservative-v1")。数えるのは include=true の行だけ。前提が揃わない処理は掛けない側に倒す。

ゲート

batch_ok

全行に confidence=="confirmed" のバッチがあり、値がちょうど 1 種類。

ゲート

same_pool

全 QC に確定した qc_pool があり、プールが 1 つ。

ゲート

¬failed_qc

含める部分行列で detect_failed_qc が失敗注入を出さない。3 つの AND が qc_eligible。

項目"auto" の解決値条件明示指定したのに前提が無いとき
normalizepqn(満たさなければ none)qc_eligible ∧ nQC ≥ 3QC プールが曖昧か nQC=0 のときだけ拒否。弱い QC で走らせた場合は assumptions.normalize_weak_qc_reference に記録
blank_min_fold3.0nblank ≥ 1 ∧ nsample ≥ 1PREPROCESS_PREREQUISITE_MISSING
drift_correctTrueqc_eligible ∧ nQC ≥ 4 ∧ 全注入順が確定 ∧ 全試料が QC 区間内
max_qc_rsd0.30qc_eligible ∧ nQC ≥ 3
imputehalf_min常に—

計算のあと・確定の前に check_applied_policy が走り、解決した処理が recipe_applied に無ければ PREPROCESS_STEP_NOT_APPLIED、未正規化試料があれば NORMALIZATION_DEGENERATE、特徴が 0 件なら PREPROCESS_FEATURES_EXHAUSTED で止める。v2 はこの方針を通らず explicit_policy(recipe)(profile-explicit-v2)で profile の指定をそのまま使う。

6.5 caveat の前景化

QC・ブランク・注入順が欠けて飛ばした処理は黙って消えず、report["caveats"] に文言で残る。LLM はこれを解釈結果とレポートの注意点として引用する契約になっている。

  • QC も blank も無い → 常に caveat。
  • 残存特徴が 0 件 → 「全特徴が除去(閾値が厳しすぎる可能性、解析不能)」。90% 超除去 → 残存割合を注記。
  • QC 層が複数 → 1 系列扱いは近似。
  • 正規化で未正規化のまま残した試料がある → 件数つきで注記。
  • 手動除外(arf_exclude)が有効 → 0 件でも「ユーザ手動除外: サンプル N 件 / スポット M 件」を必ず開示。
07

PCA・差次的解析・v2 統計

PCA の正準は lipidmix/analysis/pca.py の run_pca、2 群比較は lipidmix/analysis/differential.py。ARF 経路と mzTab-M 経路は同じ純関数を共有しているので、同じ行列からは同じ数字が出る。

7.1 PCA run_pca(matrix, n_components=None, log_transform=False, scaling="autoscale")

X n 試料 × p 特徴 前処理済み行列 任意 log10 log10(max(x, 1)) 標準化 z = (x − μ) / σ σ は母標準偏差(ddof=0) Z n × p = U n × k Σ k × k Vᵀ k × p scores = UΣ(components) loadings = Vᵀ の各行(単位ノルム) explained_variance_ratio = σ²ₖ / Σ σ²
図 7-1 PCA の行列計算。分解は sklearn.decomposition.PCA(既定ソルバの SVD)。成分数 k = min(指定, n, p)、2 未満なら ValueError。NaN の扱いは持たないので入力は補完済みであること。主成分の符号は数学的に反転しうるので、正負そのものではなく試料と特徴の相対関係で読む。
呼び出し元入力行列成分数返すもの補足
arf_parserbuild_pca_matrix の生行列(フィルタ・除外後)全成分スコア点列(PC1/PC2)、ローディング上位前処理を経ない探索用
arf_pca_preprocessedsession.arf.feature_matrixcomponents 指定同上+前処理レシピQC 点を含む。blank は無い
dataset_pca前処理済み DatasetState5スコア(4 桁丸め)、寄与率、run_order_correlationローディング全量は session.dataset.last_pca だけに持つ
dataset_statistic(kind="pca")名指しした v2 行列min(指定 or 5, rank, n−1, p)スコア、寄与率(6 桁)、sample_ids学習行は include ∧ role=sample だけ。非有限・SD 0 の列は除外。ローディングは返さない

ローディング上位(get_pca_loading_features(top_n=10, n_pcs=2)): PC ごとに係数の大きい側上位 10 と小さい側上位 10 を、MasterAlignmentID・注釈名・m/z・RT つきで返す。注入順相関(dataset_pca): 各 PC スコアと注入順の Pearson r(注入順つき試料 3 以上かつ SD > 0 のとき、3 桁丸め)。|r| ≥ 0.5 なら「PC がドリフトを拾っている」caveat。

7.2 2 群比較(v1)two_group_test

group_a が基準(対照)、group_b が比較対象。特徴ごとに Welch の t 検定を行う。ツール既定は q_threshold=0.05、log2fc_threshold=1.0、log_transform=True。

変換(既定)ℓ = log2( max(x, 0) + 1 ) 検定は ℓ で行う
Welch tt = ℓ̄B − ℓ̄A√sA²/nA + sB²/nB (s² は ddof=1)
自由度(W–S)ν = ( sA²/nA + sB²/nB )²(sA²/nA)²/(nA−1) + (sB²/nB)²/(nB−1)
両側 pp = 2 · tsf( |t|, ν ) scipy が無ければ正則化不完全ベータ関数(Lentz 連分数)で同じ値
log2FC(既定)log2FC = ℓ̄B − ℓ̄A = (x+1) の幾何平均比の log2。正 = 群 B で高い
log_transform=Falselog2FC = log2( (max(x̄B,0)+1) / (max(x̄A,0)+1) ) 検定は生値
符号t は「比較 − 基準」で計算し、log2FC・Tukey の mean_difference と同じ向き(正 = 群 B / test が高い。v1・v2 とも)。t の向きは 2026-09-27 に揃えたもので、それ以前の出力の t は符号が逆。log2FC の符号の約束は 2026-08-31 に慣習(log2(比較/基準))へ反転しており、それ以前の出力とは log2FC の符号が逆。エクスポートのメタ行 # log2fc_sign = positive means group_b is higher が宣言する。

検定不能になる条件: どちらかの群で有限値が 2 未満、または両群とも分散 0(分母 ≤ 0)→ p=NaN。mean_a / mean_b はどちらのモードでも生値の算術平均を返す。

多重検定補正(Benjamini–Hochberg)bh_fdr

順位付け有限の p を昇順に p(1) ≤ … ≤ p(m)(m = 有限 p の個数。NaN は位置を保ったまま q=NaN)
q 値q(i) = mink ≥ i ( p(k) · m / k )、[0, 1] にクリップして元の位置へ戻す

計算例(m = 10)。下から累積最小を取るので、3〜5 位の生値 0.13 / 0.1025 は 5 位の 0.084 に引き下げられる。

順位 ipp·m/iq(累積最小)判定(0.05)
10.0010.001×10/1 = 0.01000.0100q ≤ 0.05
20.0080.008×10/2 = 0.04000.0400q ≤ 0.05
30.0390.039×10/3 = 0.13000.0840
40.0410.041×10/4 = 0.10250.0840
50.0420.042×10/5 = 0.08400.0840
60.0600.060×10/6 = 0.10000.1000
70.0740.074×10/7 = 0.10570.1057
80.2050.205×10/8 = 0.25620.2356
90.2120.212×10/9 = 0.23560.2356
100.3600.360×10/10 = 0.36000.3600

有意判定と volcano の分類

down A で高い up B で高い ns −1 +1 log2FC q=0.05 有意の軸は q
図 7-2 分類。up = q ≤ 閾値 ∧ log2FC ≥ +閾値、down = q ≤ 閾値 ∧ log2FC ≤ −閾値。
  • エクスポート 15 列目 significant の判定は export_contract.is_significant(q, log2fc, …) に一本化されている(q ≤ q_thr ∧ |log2fc| ≥ fc_thr、欠測・NaN は false)。ARF 側は q_value、DatasetState 側は q というキーで同じ量を持つため、判定を経路ごとに置くと 2 実装に分裂する。
  • volcano の縦軸は生の p の −log10 で、分類は q で行う。横破線 −log10(q 閾値) は p 軸上の目安であって有意判定と厳密には一致しない。件数は図の点を数えずキャプションや selection.significant_total を読む。
  • summarize_two_group(top_n=15) は n_tested(有限 p の数)・n_significant・n_up・n_down と q 昇順の上位 15 件を返す。全量の volcano 点列はセッションにだけ持つ。

7.3 群の解決と交絡検査

因子トークンによるプール指定。ARF 経路の group_a / group_b は Class ID とサンプル名の両方から因子トークンを解決する(sample_factors.expand_sample_specs)。

指定意味
group_a="24M", group_b="9w"24M_* を全てプールして 9w_* と比べる(多因子デザインで主効果を見る経路)
group_a="24M_GF"_ で繋いだトークンは AND(24M かつ GF)
group_a="ILG_6h", group_b="ILG_0h"Class ID が同じで、サンプル名の因子(時点)だけ違う 2 群も切り出せる
一致ゼロ・両群が同じ試料を掴む指定status="error"(n=0 を成功扱いで返すと「有意 0 件=差なし」と誤読されるため)

QC・blank は群ラベルを None にしてから展開するので、Class ID が指定トークンを含んでいても(例 QC_24M と group_a="24M")どちらのプールにも入らない。応答の resolved_samples が群の定義そのもの、n_a / n_b が除外後の実 n。mzTab-M 経路の dataset_differential はサンプル名のリストを直接受け、重複除去・未知名と QC/blank の除外・両群の重なり拒否・各群 n ≥ 2(満たさなければ bad_request。ARF 経路は caveat のみ)を行う。

交絡あり(confounded) 群 control / LPS 群 ILG / G_uralensis batch 20220901 batch 20220902 処理効果とバッチを分離できない 交絡なし 群 A 群 B batch 1 batch 2 両群が両バッチにまたがる 判定は必ずプール解決後の実際に比べる 2 群で行う。バッチ情報が無い・既知バッチが 2 未満なら「評価不可」であって「交絡あり」ではない。
図 7-3 check_confounding。細かい Class ID 単位で見ると各群が単一バッチに見えやすく、健全な設計を交絡と誤報するため、プール後に判定する。pipeline の比較(run_comparison)は交絡を allow_confounded=true の明示なしには実行せず CONFOUNDED_COMPARISON で止める。

差次的解析の必須 caveat

  1. 交絡(群⟂バッチ) — 上図の条件で警告。
  2. 正規化状態 — レシピに正規化が無ければ「未正規化データの log2FC は測定量差を含み得る」。
  3. 群サイズ — n < 2 なら「各群 n ≥ 2 が必要」、2 ≤ n < 4 なら小 n(検出力の限界)。
  4. 退化 — 検定できた特徴が 0 件なら「全特徴で p=NaN。『有意 0 件』を『群間差なし』と解釈しない」。20% 未満しか検定できなくても注記。
多群多群 ANOVA は MCP に公開していない。MS-DIAL のメタデータに「因子 → 水準」の対応が無く、全 Class ID を水準にした誤った設計を返しかねないため。3 群以上は関心の 2 群を因子トークンで切り出す。differential.one_way_anova()(古典的 F 検定、n < 2 の群は黙って落とす)は関数として残るが未公開。多群は v2 の anova_tukey で、群を実験情報シートで明示したときだけ行う。

7.4 v2 統計 dataset_statistic(specification, matrix_result_id)

v2 は名指しした解析行列(analysis-matrix.v1)にだけ統計を掛け、直近の前処理を暗黙に使わない。recipe 違いの行列が 2 本並ぶ前提の設計で、どの行列の数字かを結果に残す。kind は welch / anova_tukey / pca の 3 つだけ(Kruskal–Wallis・Mann–Whitney・対応あり検定・標準化効果量は無く、反復測定は REPEATED_MEASURES_UNSUPPORTED)。

v1 dataset_differentialv2 dataset_statistic(kind="welch")
対象行列直近の前処理済み行列matrix_result_id で名指し。無ければ ANALYSIS_RESULT_NOT_FOUND(近い行列で代用しない)
試料の選び方呼び出し側が名前のリストを渡すinclude ∧ role=sample ∧ group∈groups。biological_sample_id 必須で重複不可
変換log2(max(x,0)+1)(pseudocount 1)none か log2。log2 は有限かつ > 0 の値だけ、他は NaN(pseudocount なし)
検定Welch(同じ welch_t。t・ν・p は同一式)
効果量変換空間の平均差log2_arithmetic_mean_ratio = log2( mean(生 test) / mean(生 ref) )。どちらかの平均 ≤ 0 なら None
BH の母集団有限 p を持つ全特徴検定できた特徴だけ(bh_population に件数)
有意分類up / down / ns を付ける付けない(閾値は仕様からの反響として記録するだけ)
群サイズn ≥ 2(未満は拒否)n ≥ 2(STATISTIC_GROUP_TOO_SMALL。群を落とさない)

anova_tukey(multigroup.test_feature)

一元配置 FF = SSB / (k−1)SSW / (N−k) scipy.stats.f_oneway、群 3 つ以上
事後比較scipy.stats.tukey_hsd、信頼区間 1−α(α 既定 0.05)。対 (i<j) ごとに mean_j − mean_i・ci・p_adjusted
補正の範囲Tukey の補正は特徴の中だけ(within_feature_group_pairs)。特徴間は ANOVA p に BH

どれかの群で有限値が 2 未満、または全群で分散 0 なら not_testable。scipy が無ければ STATISTIC_DEPENDENCY_MISSING で止まり、別の検定へ黙って切り替えない。

7.5 v2 の内部標準比・feature binding・QC

internal_standards.py

内部標準比

ratio = target / standard。分母が有限かつ > 0(検出マスクがあれば実検出)のセルだけ計算し、それ以外は NaN で locked(後段で補完しない)。標準の列は生値のまま support_feature_ids に残る。1 target に標準は 1 つ・自己参照・循環・未知 ID は INTERNAL_STANDARD_MAP_INVALID。内部標準比と normalize ≠ none の併用は MATRIX_RECIPE_INVALID。

feature_bindings.py

feature binding

profile の対象ごとに全 feature を評価: m/z の ppm 誤差 = |obs − exp| / exp × 10⁶、|ΔRT|、同定子(InChIKey・式・CAS・HMDB・KEGG・PubChem。名前は数えない)、要求証拠(mass_rt / library_match / authentic_standard_match)。合格がちょうど 1 件なら resolved、0 件・複数件は FEATURE_BINDING_UNRESOLVED で止め、強度や順番で選ばない。

assay_evidence.py

注入ごとの測定証拠

.arf の AlignedPeakProperties から注入ごとの RT・m/z・検出状態(gap_filled / detected)を読む。スポット数一致と m/z 照合(0.01 Da、外れ 1% 以下、1 Da 超は拒否)で特徴軸を、assay_sources の raw 名で試料軸を確かめ、どちらかが崩れれば部分表を作らず availability=False。

assay_qc.py

固定母集団 QC

6 指標: pooled_qc_rsd(%、プール×バッチごと、QC 3 本以上)、blank_fold(中央値比)、detection_rate、standard_rt_error、standard_mass_error_ppm、internal_standard_valid_fraction。閾値は profile が与え、コードに数値の既定は無い。集計は P/N ≥ t で pass、(P+U)/N < t で fail、それ以外は評価不可(t 既定 1.0)。

行列の流れ(matrix_state.py): qc_raw が無処理の __raw__ 行列で QC 評価集合をフィルタ前に固定 → preprocess が recipe ごとに make_matrix(補完しない。検出率 filter は列を消さず eligibility_mask だけに効く)→ qc_processed が固定集合で処理後 QC を評価し、落ちた feature を eligibility に反映してから finalize_matrix で補完(locked セルは補完後に NaN へ戻す)。matrix_id は値ではなく入力の identity の hashなので、同じ入力なら同じ ID になる。保存は npz(allow_pickle=False)+メタ JSON で、読むときにメタ hash・配列ごとの SHA-256・形状を検証する。

7.6 結果の鮮度と無効化

前処理入力が変わる role · batch · 注入順 · qc_pool · include 群だけが変わる group · biological_sample_id 前処理済み行列 PCA 差次的解析 差次的解析 PCA 維持 消す 差次的解析だけ消す
図 7-4 無効化(result_state.invalidate_results)。結果は preprocess_fingerprint = hash(dataset, recipe, metadata[PP_FIELDS]) と群の指紋で鮮度を持ち、古くなった結果をエクスポート・図保存に渡すと STALE_ANALYSIS_RESULT で止まる。array_fingerprint は dtype・形状・生バイトの SHA-256 なので NaN と 0 は別 hash。同一指紋なら再計算せず再利用する。
08

同定と MS/MS 照合

目的は「付いている名前は本当か」を、人が数値と図の両方で判断できるようにすること。同定名の標準化・同定信頼度の推定・実スペクトルの照合はすべてオフラインで、pygoslin(同梱)と同梱 TSV と参照ライブラリだけを使う。

8.1 verify_peak_annotation の判定の流れ

PAI2 ピーク name · formula · adduct m/z · ion_mode · .dcl MS/MS 精密質量誤差 m/z_theo = (n_mol·M + shift) / z ppm = (obs − theo) / theo × 10⁶ PASS≤5 · BORDERLINE≤10 · FAIL · UNKNOWN アダクト整合 アダクトの電荷符号 と ion_mode PASS · FAIL · UNKNOWN(クラス典型は助言) MS/MS 証拠 msms.band PASS .dcl の実スペクトルあり(上位 5 本) FLAG_ONLY has_msms だけ立つ(根拠が弱い) ABSENT フラグもスペクトルも無い PASS かつ library 読込済み → spectral_match Level 2 · putative annotated compound 名前あり ∧ MS/MS 取得 ∧ 質量 PASS ∧ アダクト PASS/UNKNOWN FLAG_ONLY で到達した場合は rationale に「根拠が弱い」と明記 Level 3 · putative class-level Ontology が判別できる(Unknown 以外)が Level 2 を満たさない Level 4 · unknown 名前もクラスも無い Level 1 は決して主張しない 標準品照合は扱わない · heuristic=True を返す
図 8-1 MSI レベルの推定。3 つの帯は決定論的に出し、msi_level() がそれを組み合わせる。アダクト表は [M+H]+ [M+NH4]+ [M+Na]+ [M-H2O+H]+ [M-H]- [M+HCOO]-(= [M+FA-H]-)[M+CH3COO]- [M+Cl]- [2M-H]- [M-2H]2-、元素表は D・F・Br・¹³C を含む。診断フラグメントやクラス固有の MS/MS 規則による検査はしない。

ドシエの出力キー: status、identity(id・name・ontology・formula・adduct・observed_mz・rt・ion_mode・S/N)、analytical_checks(mass_error・adduct_consistency・msms)、biological_plausibility(蓄積ノートの語彙ヒットと候補 slug)、identity_normalization(goslin・reference・msi・class_token)、llm_decision(指示文と deterministic_summary、例 msms=PASS)。名前に P- / O- があればエーテル caveat を付け、プラズマローゲンの知識ノートへ繋ぐ。

8.2 名前の標準化(GOSLIN)と参照表

  1. MS-DIAL の限定子を剥がす

    no MS2: w/o MS1: w/o MS2: low score: unsettled: を大小無視で除去し、A|B なら先頭を取る(stripped=True)。RIKEN N-VS1 ID-… のような真の未同定名は解析不能のまま(正しい)。

  2. pygoslin で解析

    normalize_lipid_name は parse_ok・normalized・level(SPECIES / MOLECULAR_SPECIES …)・lipid_maps_category を返す。未導入でも解析不能でも例外を投げず parse_ok=False。

  3. クラストークンで同梱表を引く

    reference/lipidmaps_classes.tsv(カテゴリ・メインクラス)と reference/refmet_map.tsv(RefMet 名)はキュレート済みの部分集合で、置き場所はリポジトリ直下の reference/ に固定(REFERENCE_DIR。起動ディレクトリに依存しない)。表に無いクラスは matched=False と caveat「同梱マッピング表に無いため ID 未付与」で返し、推測しない。

metabolite一般代謝物では GOSLIN は不適用(parse_ok=False は「未同定」でなく「脂質名ではない」)、RefMet/LIPID MAPS 表は脂質のみ、MSI ヒューリスティックは参照しない。質量・アダクト整合だけは再利用できる。

8.3 スペクトル照合(MS-DIAL MsScanMatching.cs の忠実移植)

目的は MS-DIAL との数値の一致で、実装の改善ではない。上流の「変な点」(未使用の中間値、両枝が同一の分岐、打ち消える ×999、隣接窓への二重計上を許すカーソル走査、Li et al. 2021 の低エントロピー重みの不在)は意図的にそのまま写してある。

窓の合算焦点 m/z ごとに [m − b, m + b) の強度和、b = ms2_tol(既定 0.025 Da)。各系列を自身の最大値で割って Im,k・Ir,k
weightedS² = ( Σ √(Im,kIr,k) · mzk )²( Σ Im,k·mzk )( Σ Ir,k·mzk ) × penalty (Im ≥ 0.01 の窓だけ)
penalty参照側で相対強度 > 0.1 の窓が 1 → 0.75、2 → 0.88、3 → 0.94、4 → 0.97、それ以外 1.0
reverse同じ式を参照ピークの範囲だけで、0.01 の足切りを参照側に掛ける
simpleS² = ( Σ √(ImIr) )² / ( ΣIm · ΣIr ) m/z 重み・ペナルティなし
matched peakspercentage = 一致窓数 / 参照ヒット窓数(参照和 ≥ 最大参照ピーク × 0.01)、count = 一致窓数
entropysim = 1 − ( 2·HAB − HA − HB ) / 2 (log2 の Shannon エントロピー、総強度で正規化、合成スペクトルは 0.5 倍)
返す値3 つの dot product は √ を取った値(mzTab の id_confidence_measure[4..6] と同じ土俵)
ガウス類似度g(a, r, tol) = exp( −½ ((a − r)/tol)² ) 値が欠けるか ≤ 0 なら −1
質量許容の補正mass ≤ 500 ならそのまま、超えれば ppm = |round(tol/500 × 10⁶, 4)|、tol′ = ppm × mass / 10⁶
total_score= [rt_similarity(use_rt のとき)] + mass_similarity + (weighted + simple + reverse)/3(weighted > 0 のとき)+ matched_peaks_percentage 正規化しない和で 1 を超える
−1 と 0−1 は「比較していない」(どちらかのスペクトルが空)、0 は「合わなかった」。混同すると「照合していない」が「合わなかった」に化ける。mzTab の dot product 3 列は上流で −1 を 0 にクランプしてから √ を取るので、比較不能はそこでは 0 として出る。
窓の分離ライブラリ候補の検索窓(mz_tol / rt_tol、明示 > .dbs の search_params > 既定 0.01 / 0.2)と、.dcl から測定スペクトルを引く窓(常に 0.01 Da / 0.2 分)は別物。.dbs の RtTolerance 既定 100.0 を .dcl 側に流すと、m/z が近い別ピークのスペクトルを黙って拾う。

参照ライブラリの store。library_load は .dbs/.lbm2/.msp を読み、元ファイルの sha256 をキーにした SQLite キャッシュ(既定 data/.library-cache)へ初回変換する。precursor m/z を持たないレコードは 1 件ずつ読み飛ばして skipped_no_precursor_mz に数え、極性欄の無いレコードは極性不明として候補に残す(ion_mode 比較は COLLATE NOCASE)。研究室の参照ライブラリは外部流出禁止で、リポジトリの外に置いて MSDIAL_MSP_POS / MSDIAL_MSP_NEG で指す。

8.4 アラインメントのキュレーション(機械判別)

curation_review はスポットごとに 5 系統の帯(PASS / BORDERLINE / FAIL / UNKNOWN)と理由コードを出し、総合判定 verdict にまとめる。画像ではなく数値に対して判定する。MS-DIAL 自身が同定時に出した判定(MsScanMatchResult のフラグ)を主にし、こちらでの再計算は食い違いの検出にだけ使う。UNKNOWN(MS/MS 未取得・参照 RT なし)は不一致に数えない。

系統見るもの基準
msmsMS-DIAL の is_reference_matched・脂質規則フラグ、.dcl の実スペクトルでの再照合参照一致なら PASS、MS/MS はあるのに不一致なら FAIL(low_score)、MS/MS なしは UNKNOWN
mz代表試料の m/z − 参照 precursor(引けなければ組成式の理論値)Δppm 5 / 10、|Δm/z| ≥ 10 mDa、MS-DIAL の precursor 判定、アダクトの電荷と測定極性
rt代表試料の RT − 参照 RT0.5 / 1.0 分
eic試料ごとの EIC 形状(点数・頂点と半値幅から決まる理想ガウスとの R²・極大の数。最適化を伴う当てはめは使わない)と、頂点 RT の試料間ばらつき良い試料の割合 0.5 / 0.2、頂点 RT の標準偏差 0.1 分
trendクラス × 不飽和度ごとの RT–m/z 頑健回帰からの外れ(頑健 z)z > 3 かつそのクラスの当てはめ R² ≥ 0.7。単独では判定を上げず、他の BORDERLINE と重なったときだけ補強する(不飽和度が上がると線形性が落ちるため)
判定条件理由コード
likely_wrong強い理由が 1 つでも立つpolarity_mismatch(アダクトの電荷と極性が矛盾)· precursor_unmatched(MS-DIAL の precursor 判定が不一致)· dmz_out(|Δm/z| ≥ 10 mDa)· class_rule_rejected(MS/MS ありで MS-DIAL の脂質クラス規則=診断イオンで棄却)
suspect強い理由は無く、いずれかの系統が FAIL、または BORDERLINE が 2 つ以上、または BORDERLINE 1 つ + 傾向の外れ弱い: ppm_out(Δppm > 10)· low_score · drt_out · eic_poor。帯のみ: ppm_borderline · drt_borderline · eic_borderline · rt_scatter · trend_outlier
okそれ以外—

判定を動かさない情報コードもある: msms_absent · reference_not_found · rescore_discrepancy(こちらの再照合が MS-DIAL の値と 0.1 以上ずれた)· adduct_differs_from_reference · manually_modified · class_rules_not_run(脂質クラス規則が評価されていない=未検証であって誤りではない)· chains_unsupported(鎖レベルの名前なのに is_lipid_chains_match=False。MS-DIAL は照合に失敗しても参照名から | 付きの名前を作るので、| 名は鎖組成の証拠ではない)ほか。

脂質規則は脂質データでだけ読むMS-DIAL の脂質規則フラグ(IsLipidClassMatch / IsLipidChainsMatch / IsOtherLipidMatch)は Lipidomics 採点器でしか立たず、他の採点器では全部 false になる。そのまま読むと low score が全件「規則で棄却」に化けるので、対象スポットに規則フラグが 1 件でも true のときだけ 3 コードを使い、無ければ warnings で知らせる。
実測kidney(マウス腎、neg / pos、注釈 1468 / 2196 件)で likely_wrong は 424 / 563 件、うち class_rule_rejected が 370 / 404、dmz_out が 139 / 232。MS-DIAL の代表候補の再現は全件一致、参照の解決は 100%、1 回のレビューは約 5〜16 秒。

ビューアとフラグの流れ

  • 判定根拠のメモ。likely_wrong と suspect のカードは、メモ欄の既定値が判定根拠の文になる(例 自動: 精密質量 — Δm/z 12.4 mDa(≥10 mDa) / MS2 — 参照と一致せず(low score))。
  • 「間違い」の初期選択。likely_wrong は開いた時点で「間違い」が選ばれた未送信の変更になる。記録済みのフラグがあるもの・人が取り消したもの(flag_cleared)には掛けない。「なし」に戻して送れば取消として記録され、次のレビューで掛け直さない。
  • 枠。自動判別の likely_wrong は赤の破線、記録されて(または人が選び直して)「間違い」になると実線。人の「疑わしい」は橙の実線。
  • 対向プロット。ピークの m/z ラベルは library_plot_mirror と同じ規則(強度降順の貪欲法、縦横とも重なるものを飛ばす、片側 25 本まで、実測と参照は独立)。縦軸は各側の最大値を 100 とした相対強度で 0 / 50 / 100 の目盛り。
  • MS-DIAL への書き戻し。curation_submit はアラインメントの <stem>_tags.xml を上流 AlignmentResultContainer.Save と同じ形(<Peak Id="MasterAlignmentID"><Tag>3</Tag></Peak>、UTF-8 BOM・CRLF)で書く。実物の写しで付与 → 除去の往復がバイト一致することを確かめてある。
09

Console 実行層と pipeline

生データを扱う経路は 2 つある。個々のツールを手で繋ぐ Console 経路と、生データフォルダ 1 つから品質レポートまでを永続 run として自動で進める pipeline 経路。どちらも終了コード 0 だけでは成功と言わず、終了証跡・生成物の構造・試料の 1 対 1 対応まで確かめる。

9.1 Console 経路:計画 → 実行 → 確定

console_plan メソッドファイルの解決 1. 引数 method_file 2. dataset_root 直下 → 兄弟フォルダ → 過去 run <project>_param_<時刻>.txt Ion mode が polarity と一致する最新 脂質ライブラリ .lbm2 の解決 1. メソッドの宣言 2. MsdialWorkbench のビルド生成物 3. MSDIAL_LBM 4. exe と同じフォルダ ちょうど 1 件でなければ停止(空だと同定 0 件) 書くもの runs/<job_id>/analysis-job.json runs/<job_id>/effective-method.txt session.current_job_path 元のメソッドファイルは変更しない console_run → supervise OS ロック job.lock(2 秒) 別プロセス実行中なら JOB_BUSY MS-DIAL Console を起動 exe lcms -i root -o run_dir/msdial -m method [-p] 0.1 秒ごとに監視 · timeout_s exited · timeout · cancelled worker_lost · launch_failed どの終了経路でも残す execution-result.json(console-execution.v1) worker.json · msdial.log command・method・exe の sha256 process identity(pid+生成時刻) 確定(監視ワーカーが行う) 生成物の収集 前後スナップショットの差分 -o 側と生データフォルダ側の 2 か所 primary_mztab · peak_matrix_source spot_catalog · msms_evidence … 出力の検証 主 mzTab-M が一意に選べる 構造が妥当 · 定量行列に有限値 予定入力 ↔ assay が 1 対 1 MTD ms_run[N]-location で照合 (表示名では照合しない) completion_status completed exited ∧ exit 0 ∧ 検証 ok partial それ以外で生成物あり failed 生成物なし · 自動再試行なし
図 9-1 Console 経路。detach=True なら監視ワーカー(python -m lipidmix.console.worker)を切り離して即座に戻る。同期でも切り離しでも同じ execution.supervise を通るので、console_status を呼ばなくても結果は確定する。実データ 60 試料で約 44 分かかり、同期実行では呼び出し元が中断されると生成物ごと失う。
ジョブの状態(JobStatus)意味
plannedconsole_plan 直後
running監視ワーカーが Console を見張っている
needs_input人の判断待ち(試料対応表の承認など)
completed終了証跡・検証とも合格
partial生成物はあるが完了条件を満たさない。dataset_load は既定で拒否(INCOMPLETE_ANALYSIS_JOB)
failed生成物なし
cleanedconsole_cleanup が記録済み生成物を削除した

analysis-job.json の主な欄(analysis-job.v2、profile を持つ v2 run は .v3): job_id(job_<日時>_<pos|neg>_<h|a>_<uuid8>)、status、dataset_root、method_file、omics、polarity、measure、run_dir、primary_mztab_files[](path・polarity・measure・sha256・validation・root)、artifacts[](path・role・format・sha256・root)、sample_manifest、warnings、error。run ディレクトリはリポジトリの外(生データ側の runs/)でなければならない(DATASET_ROOT_IN_REPO)。

Smart App Controlsave_project=true(既定)だと MS-DIAL は全検体の解析とアライメントを終えた後にプロジェクトを書き、その段で読むアセンブリが未署名のローカルビルドだと Windows のポリシーに弾かれる(実測: 41 検体で 13 分半後に失敗)。pipeline は計画時に「ポリシーが Enforce ∧ アセンブリ未署名」を確かめて PROJECT_SAVE_BLOCKED で止める。対処は要求に "save_project": false。

9.2 pipeline:受付と worker

MCP プロセス(数秒で戻る) pipeline_rundataset_root, request resolve_request明示 > ファイル > 既定 inspect_inputs形式・メソッド・LBM _precheck_manifest壊れたシートを検出 find_or_create_runfingerprint と request_id で冪等 新規 planned → launch_detached で worker を起動 → 最大 3 秒 handshake(超えても失敗にせず not_confirmed) シート不正 → needs_input で保存し、起動しない 既存 run → 起動せず receipt だけ返す worker プロセス(python -m lipidmix.pipeline.worker · cwd = このチェックアウト) run_engine → owner lock(PIPELINE_ALREADY_RUNNING)→ _run_stage_loop(各 stage の直前に run record を読み直す)→ finish_success → evaluate_target
図 9-2 受付と実行の分離。worker はグローバル session・mcp_core・lipidmix.tools.* を import しない(AST テストが固定)。走っている最中に届いた pipeline_resume は、worker が stage の境目で要求版の変化に気づいて計画を組み直す(有限回まで、超えると REQUEST_REVISION_CHURN)。

9.3 工程(stage)と成果物

#v1 stageやること成果物・記録再開時
1prepare_input生データ・随伴ファイル・有効メソッドを input/ に配置record.inputs成功済みなら信じる
2upstreamconsole/attempt-NNNN/ にジョブを作り supervise を直接呼ぶ(cancel_path 付き)upstream.verification(status・termination・exit_code)。非 completed は MSDIAL_EXECUTION_FAILED成功済みなら信じる。やり直しは rerun_upstream
3validate_outputs生成物の検証、save_project なら GUI プロジェクトを登録無ければ warning GUI_PROJECT_UNAVAILABLE成功済みなら信じる
4load_datasetload_dataset_state(job_path)worker の runtime常に再実行
5resolve_metadata実験情報シートを読む(無ければ自動生成)inputs.manifest・manifest_source(シートの内容 hash)
6preprocesspreprocess_auto(conservative-v1)preprocess 結果
7pcaPCA と図results/pca.png、スコア(ローディングは落とす)
8resolve_comparisons比較の前提検証(exploratory では省略)COMPARISON_REQUIRED / CONFOUNDED_COMPARISON結果参照の hash 検証に落ちたら再実行
9differential:<cid>run_comparison(Welch+BH)比較ごとの結果
10export:<cid>volcano と契約 TSVresults/volcano_<cid>.png・results/differential_<cid>.tsv
11report(常に最後)品質レポートreports/pipeline-quality-report.md

v2(stage_plan.BASE_V2_STAGE_IDS): prepare_inputs → execute_console → validate_outputs → load_dataset → resolve_metadata → load_assay_evidence → resolve_feature_bindings → qc_raw → preprocess → qc_processed → statistics:<sid> → export:<sid> → report。成果物は results/feature-table.tsv(+ .annotations.tsv)、results/statistic-<sid>.tsv(+ .tukey.tsv)、quality-report.md。v2 は合成入力と fake Console までしか検証されておらず、routine 目的は PROFILE_VALIDATION_INVALID で止まる(draft profile + execution_purpose="validation" を使う)。

9.4 run の状態遷移

planned running worker 起動 completed partial failed needs_input cancelled evaluate_target 必須出力が揃い hash 一致 一部の結果だけ 結果なしで失敗 入力を直せば進める停止 取消フラグを stage 境界で検出 pipeline_resume(updates)
図 9-3 状態遷移。活動中は planned / running / needs_input、終端は completed / partial / failed / cancelled。pipeline_status は読取専用で、worker の生存確認に失敗しても status は書き換えず observed_health=worker_missing と recovery_hint を別軸で返す。

要求(pipeline-request.v1)の欄と既定値

欄既定説明
targetautoauto は比較があれば differential、無ければ exploratory
polarity / method_file / lbm_file推定Console 経路と同じ解決規則
measurepeak_heightpeak_height のみ
timeout_s / save_project / keep_extension21600 / true / —
sample_manifestsample-manifest.tsv列 sample_id · source_file · role(sample/qc/blank/unknown)· group · batch · injection_order · qc_pool · include。null は「自動生成」
preprocessconservative-v1normalize / blank_min_fold / drift_correct / max_qc_rsd = auto、impute = half_min、min_detection_rate = 0
comparisons[]空comparison_id · reference_group · test_group · q_threshold 0.05 · log2fc_threshold 1.0 · log_transform true · allow_confounded false

再開で変えられるのは target / sample_manifest / preprocess / comparisons だけで、それ以外は NEW_PIPELINE_REQUIRED。値の出所は value_sources(explicit / request_file / default / explicit_update)に残る。run record の results は追記専用で、既存要素の書き換えは拒否される。

再開(prepare_resume)の判断順

  1. 見張られていない Console が生きていれば止める

    EXECUTION_UNRESOLVED。

  2. 上流が未完なら明示を求める

    rerun_upstream なしでは UPSTREAM_RERUN_REQUIRED。Console の自動再試行はしない。

  3. 入力と有効メソッドの hash を再検証

    変わっていれば INPUT_CHANGED。

  4. 更新をマージ

    内容が同じなら新しい revision を作らない(request_id 付き再送は直前の結果を返す)。

  5. pending に戻す stage を決める

    rerun_upstream は全部、シート・前処理・目標の変更は比較以降と report、比較の変更はその比較の stage だけ。同じパスのシートを書き直した訂正も manifest_source の hash で検出する。

10

エクスポートイメージ

ツールが返すもの・書き出すものの見本。列名・メタ行の順序・書式・ファイル名は実装どおりで、例示値 の付いた数値と化合物名は説明用の架空の値。

10.1 差次的エクスポート(契約 v1、別リポ massbank-context との契約)

arf_export_differential と dataset_export_differential は同じ関数(export_contract.build_meta / format_row)で書く。列の追加・改名・並べ替えは CONTRACT_VERSION の引き上げと下流の同時更新なしにしてはいけない。メタ行の順序も契約の一部。

differential_ILG6h_vs_control6h.tsv例示値
# contract_version = 1
# exported_at = 2026-09-27T05:12:44.918203+00:00
# source_arf = AlignmentResult_2026_05_15_10_13_35_PeakProperties.arf
# source_arf2 = AlignmentResult_2026_05_15_10_13_35.arf2
# group_a = control_6h	n_a = 4
# group_b = ILG_6h	n_b = 4
# log2fc_sign = positive means group_b is higher
# q_threshold = 0.05	log2fc_threshold = 1.0	log_transform = true
# preprocess = normalize=pqn blank_min_fold=3.0 drift_correct=true max_qc_rsd=0.3 impute=half_min
# n_features_total = 1345	n_with_inchikey = 412	n_unannotated = 933
# msi_note = msi_level は .arf2 由来のクラス上限の保守評価で、MS/MS 取得の有無を表さない
spot_id	name	name_source	ontology	inchikey	inchikey_source	msi_level	mz	rt	log2fc	p_value	q_value	mean_a	mean_b	significant
474	SL 33:0;O|SL 17:0;O/16:0	arf2	SL	QXKZ…-UHFFFAOYSA-N	arf2	3	580.4221	9.8812	2.418733	3.1e-05	0.0102	18342.5	98221.7	true
1248	PC 16:0_18:1	arf2	PC	WTJK…-JQQJRHCPSA-N	arf2	3	804.5760	7.0214	-1.302114	0.00041	0.0467	412330	166904	true
2031	TG 52:2	arf2	TG	CEJY…-KFDAUHNHSA-N	arf2	3	876.8015	12.4430	0.412008	0.182	0.611	1.20e+06	1.61e+06	false
3107	FA 18:2	arf2	FA	OYHQ…-HZJYTTRNSA-N	arf2	3	279.2330	3.1120	0.023117			5220.1	5301.4	false
#列書式意味
1spot_id整数ARF: MasterAlignmentID / mzTab-M: SMF_ID(メタ行 # id_space = mztab_smf_id)
2name文字列代表名
3name_sourcearf2 / mztab_sme / mztab_smlmztab_sml は MS1 照合のみ。行単位で出所を 1 つに決める(InChIKey を供給した側)
4ontology文字列脂質クラス。mzTab-M 経路は空欄
5inchikey文字列下流の結合キー。無い行は本文から外す(件数はメタ行)
6inchikey_sourcearf2 / database_identifier / inchi_derived / smiles_derivedどこから導出したか
7msi_level整数 / 空ARF2 のクラス上限推定。mzTab-M 経路は常に空欄(「この経路では取得していない」)
8–9mz rt.4f代表 m/z、RT(分)
10log2fc.6f正 = group_b が高い
11–12p_value q_value.6gWelch の p、BH の q
13–14mean_a mean_b.6g各群の生値の算術平均
15significanttrue / falseis_significant()。非有限は false
キュレーションのメタ行キュレーションのフラグがあるときだけ、メタ行に # curation = <state> curation_flags = N[ curation_wrong_excluded = N curation_suspect = N] curation_flags_sha256 = <hex> が 1 行足される(角括弧内の件数は applied のときだけ。15 列の契約自体は変えないので CONTRACT_VERSION は据え置き。下流の meta パーサは未知キーを保持するだけ)。state は applied(wrong を同定なしとして本文から外した)/ not_applied(apply_curation=false)/ unmapped(mzTab-M 経路で ID の対応を検証できず当てていない)。suspect は行も値も変えない。フラグが 0 件なら何も足さず、出力はキュレーション導入前と完全に同じ。pipeline_run が書くエクスポートにはフラグを当てない。

NaN・inf・None は文字列化せず空セルにする(上の 4 行目: 両群とも分散 0 で検定不能なので p と q が空)。有意行だけでなく InChIKey が付いた全行を出すのは、下流の濃縮解析が「検出された化合物」を背景に取るため。mzTab-M 経路のメタ行には source_mztab / source_job / source_verification / result_id / preprocess_id が入り、前処理条件は現在の状態ではなくその結果自身の来歴から書く。

10.2 図

arf_plot_volcano → PNG(output="image")例示
Volcano (control_6h vs ILG_6h)-4-202402468log2 fold change-log10 pup (B で高い)down (A で高い)ns破線: |log2FC| = 1横破線: -log10(0.05)(p 軸上の目安。判定は q)
up=11 down=4 ns=505 not_testable=0 · q≤0.05 かつ |log2FC|≥1 · 全 520 特徴を描画
save_pca_figure → reports/figures/<id>_pca.png例示
PCA score plot(前処理済み: PQN · QC-RSD 0.30 · half_min)-30-1501530-20-1001020PC1 (38.2%)PC2 (14.7%)control (n=8)LPS (n=8)ILG (n=8)G_uralensis (n=8)qc (n=7)QC は行列に残す:中央に締まれば前処理良好blank は除外済み
PC1 (38.2%) × PC2 (14.7%) · 群別: control=8 LPS=8 ILG=8 G_uralensis=8 qc=7
eic_plot_chromatograms → lipidmix.eic.v1 を描いた例例示
EIC spot 1248 · m/z 760.5851 · RT 7.02 min66.577.5803000006000009000001.2e+06Retention time [min]Intensitycontrol_6h_1control_6h_2LPS_6h_1LPS_6h_2ILG_6h_1QC_01peak_left … peak_right
1 スポット × 最大 12 試料。normalize="per_trace_max" で系列ごとの最大値を 1 にできる
library_plot_mirror → PNG例示
PC 16:0_18:1 [M+H]+ · rank 1 · total_score 2.61200300400500600700800m/zmeasured ↑reference ↓184.07496.34478.33522.36577.52760.59MeasuredReferenceMatchedBelow cutoff (not scored)
一致ピークは縦の薄い帯で結ぶ。採点外ピーク(足切り)は灰色で残し、件数を caption に出す

lipidmix.volcano.v1 payload(output="payload")

{"plot_schema":"lipidmix.volcano.v1","title":"Volcano (control_6h vs ILG_6h)",
 "axes":{"x":{"label":"log2 fold change"},"y":{"label":"-log10 p"}},
 "comparison":{"group_a":"control_6h","group_b":"ILG_6h","n_a":4,"n_b":4},
 "thresholds":{"q":0.05,"log2fc":1.0},
 "points":[{"feature":"Spot_474_height","log2fc":2.4187,"neg_log10_p":4.5086,"sig":"up"}, …],
 "render_hints":{"color_by":"sig","guides":{"x":[-1.0,1.0],"y":[1.3010]}},
 "selection":{"total":1345,"plotted":846,"significant_total":46,"significant_plotted":46,
   "ns_total":1299,"ns_plotted":800,"max_points":800,"dropped_nonfinite":0}}

payload では up/down を全件残し、ns だけを等間隔で決定的に間引く。selection.plotted < total のとき図は全点ではないので、有意件数は必ず significant_total を読む。dropped_nonfinite は「有意でない」ではなく検定不能(分散 0・欠損・片群のみ検出)。

10.3 ツールの戻り値の形

arf_list_sample_roles(TSV、列名 1 回)例示値
# batch_source = filename_date
sample	role	group	batch	run_order	excluded
20220901_RAW_control_0h_1_NEG	sample	control	20220901	3	false
20220901_RAW_LPS_6h_2_NEG	sample	LPS	20220901	11	false
20220901_QC_01_NEG	qc	QC	20220901	1	false
20220901_Blank_01_NEG	blank	Blank	20220901	0	false
20220902_RAW_ILG_6h_1_NEG	sample	ILG	20220902	27	true
library_match_feature(candidates_table)例示値
rank	name	adduct	total_score	weighted_dot_product	simple_dot_product	reverse_dot_product	matched_peaks_percentage	matched_peaks_count	entropy_similarity
1	PC 16:0_18:1	[M+H]+	2.6143	0.8921	0.9104	0.9337	0.8333	5	0.7412
2	PC 18:1_16:0	[M+H]+	2.5980	0.8874	0.9051	0.9290	0.8333	5	0.7388
3	PE 19:0_18:1	[M+H]+	1.4410	0.2105	0.3310	0.2892	0.2500	1	0.1934
scoring = {rule: MS-DIAL GetTotalScore, use_rt: false, ms1_tol: 0.01, rt_tol: null}
arf_differential(要約だけを返す。全量は session)例示値
{"status":"success","group_a":"control_6h","group_b":"ILG_6h","n_a":4,"n_b":4,
 "resolved_samples":{"a":["…control_6h_1…", …],"b":["…ILG_6h_1…", …]},
 "summary":{"n_tested":1345,"n_significant":46,"n_up":28,"n_down":18,
   "top":[{"feature":"Spot_474_height","spot_id":474,"name":"SL 33:0;O|SL 17:0;O/16:0","name_source":"arf2","log2fc":2.4187,"q":0.0102}, …]},
 "caveats":["交絡: 各群が単一バッチ(control=20220901, ILG=20220902)。処理効果と測定バッチを分離できない",
            "小n: 各群 n<4 のため検出力に限界"],
 "volcano_note":"全特徴の点列は session に保持。図は arf_plot_volcano"}

10.4 pipeline が書くもの

<dataset_root>/runs/pipeline_<UUID>/
pipeline_3f9c…/
├─ pipeline-run.json          # run record(pipeline-run.v1)
├─ requests/revision-0001.json # 要求の各版
├─ control/
│  ├─ worker.lock  pipeline.lock
│  ├─ cancel-request.json      # 取消フラグ
│  └─ worker-launch.log
├─ input/                      # 生データのリンク+有効メソッド
├─ console/attempt-0001/       # attempt ごとに分ける
│  ├─ analysis-job.json
│  ├─ execution-result.json    # 終了証跡
│  ├─ worker.json  msdial.log
│  └─ msdial/*.mzTab …
├─ results/
│  ├─ pca.png
│  ├─ volcano_<cid>.png
│  └─ differential_<cid>.tsv   # 契約 v1
└─ reports/pipeline-quality-report.md
pipeline-run.json(抜粋)例示値
{"schema":"pipeline-run.v1",
 "identity":{"pipeline_id":"3f9c…","source_root":"D:/raw/NEG", …},
 "request":{"revision":2,"request_id":"req-0927-a",
   "content_hash":"sha256:…","effective_target":"differential"},
 "status":"completed","state_revision":41,
 "stages":{"upstream":{"status":"succeeded","attempt":1, …},
   "differential:ilg_vs_ctrl":{"status":"succeeded","result_refs":[…]}},
 "upstream":{"verification":{"status":"completed",
   "termination":"exited","exit_code":0}},
 "results":[…],   // 追記専用
 "needs_input":null,"warnings":[…],
 "worker":{"identity":{…},"started_at":"…"}}
reports/pipeline-quality-report.md(節の順は固定)例示値
# Pipeline quality report
status_at_report_time: completed · reason_codes: []
自動の生物学的解釈は含まない。

## Source            D:/raw/NEG · 41 raw files (.wiff)
## Method / LBM / version  param_20260915.txt (sha256 …) · Lipids.lbm2 · MS-DIAL 5.x
## Execution evidence  termination=exited exit_code=0 · execution_id … · mzTab sha256 一致
## Sample provenance   role/group: sample-manifest.tsv · batch: manifest · injection_order: manifest
## Applied / skipped steps  normalize=pqn ✓ · blank_min_fold=3.0 ✓ · drift_correct ✓ · max_qc_rsd=0.30 ✓
## PCA               PC1 31.4% · PC2 12.0% · run_order_correlation PC1 r=0.12
## Comparisons       ilg_vs_ctrl: n=8/8 · tested 698 · significant 37(up 22 / down 15)
## InChIKey coverage  with_inchikey 214 / 714 · identified_by: sme 0 · sml_only 214 · none 500
## Unverified conditions  注入順が確定していない試料 0 件 …

10.5 v2 の表(feature_export)

ファイル列
results/feature-table.tsv(縦持ち)dataset_id · feature_id · assay_id · matrix_result_id · value · unit · detected · gap_filled · imputed · exclusion_reason
<stem>.annotations.tsvfeature_id · candidate_rank · identification_status(candidate / ms1_annotation / unidentified)· name · database_identifier · inchikey · adduct · charge · confidence_measure · confidence_value · mz · rt_min
results/statistic-<sid>.tsv(welch)feature_id · status · reason · n_reference · n_test · t_statistic · p_value · q_value · log2fc
同(anova_tukey)feature_id · status · reason · f_statistic · df_between · df_within · p_value · q_value · group_n
<stem>.tukey.tsvfeature_id · reference_group · test_group · mean_difference · ci_low · ci_high · p_adjusted · alpha

未同定の特徴も unidentified として 1 行残す(消すと「同定できたものだけの世界」になる)。ms1_annotation は m/z 照合だけで、v2 の required_evidence では library_match も authentic_standard_match も満たさない。

10.6 レポートと目的ノート

analyses/<analysis_id>.md(record_objective)例示値
---
type: objective
analysis_id: licorice-neg-6h
confirmed: true
status: active
assay_kind: lipid
---
## 確定目的
ILG 処置 6h で変動する脂質クラスを特定する
## 推測の根拠 …
## 派生する小問
- Q1: スフィンゴ脂質は ILG で増えるか
- Q2: PC/PE 比の変化は膜リモデリングを示すか
## 創発的に追記された小問
## 探索ログ(search_log)
- Q1 · "isoliquiritigenin sphingolipid" · hits 7 · promoted 2
reports/<analysis_id>.md(write_report)例示値
---
type: report
analysis_id: licorice-neg-6h
dataset: 2_lipidome_lcms/NEG
date: 2026-09-27
status: draft
knowledge_refs: [sphingolipid-inflammation]
---
## 結果
46 特徴が有意(q≤0.05, |log2FC|≥1)…
## 注意
- 群とバッチが交絡(20220901 / 20220902)
- 各群 n=4
## 図
![volcano](figures/licorice-neg-6h_volcano.png)
11

想定ユースケース

利用者がチャットで頼むことと、LLM が呼ぶツールの並び。色は経路(3 章の凡例)と同じ。

A. GUI で解析済みのデータを探索し、2 群を比べる

「このフォルダの PCA を見せて。ILG 6h と control 6h で何が変わった?」
load_dataset→record_objective→arf_list_sample_roles→arf_exclude→arf_preprocess→arf_pca_preprocessed→arf_differential→arf_plot_volcano→arf_export_differential
  1. load_dataset が最新バッチを選び、ARF2 概観と生行列 PCA を返す。LLM は目的の候補を 1〜2 個示し、利用者の確認を得てから record_objective(assay_kind="lipid") で記録する(GATEWAY)。
  2. PCA で外れた QC を見つけたら arf_exclude で外す(失敗注入を残すと QC RSD でほぼ全特徴が落ちる)。
  3. arf_preprocess(normalize="pqn", blank_min_fold=3, drift_correct=True, max_qc_rsd=0.3)。飛ばした処理は caveat に残る。
  4. arf_differential(group_a="control_6h", group_b="ILG_6h")。Class ID に時点が無くても、サンプル名の因子トークンで 2 群を切り出せる。交絡・小 n の caveat をレポートの注意点に写す。
  5. 画面で見るなら arf_plot_volcano(PNG が直接返る)、下流のパスウェイ解析へ渡すなら arf_export_differential(output_path)。

B. 生データから全自動で品質レポートまで

「D:\raw\NEG を解析して、ILG と control を比べて」
pipeline_run→pipeline_status→pipeline_resume→pipeline_status→dataset_load(pipeline_path)→dataset_status
  1. 生データの拡張子を見た LLM は、要求そのものを起動の確認とみなして pipeline_run(dataset_root, request={"comparisons":[{"comparison_id":"ilg_vs_ctrl","reference_group":"control","test_group":"ILG"}]}) を呼ぶ。数秒で pipeline_path が返る。
  2. worker が Console を回す(数十分)。pipeline_status で進捗を見る。呼ばなくても worker は最後まで進める。
  3. 群がバッチと完全に交絡していれば CONFOUNDED_COMPARISON の needs_input で止まる。利用者が納得したうえで pipeline_resume(updates={"comparisons":[{…,"allow_confounded":true}]})。Console は再実行されない。図には「UNADJUSTED」の但し書きが焼き込まれる。
  4. 完了後、dataset_load(pipeline_path=…) で同じ run の DatasetState・試料対応表を対話セッションへ引き継ぎ、追加の比較や図を作る。

C. 実験情報の誤記を直して再計算する

「QC_05 は実はバッチ 2 だった。群も 1 つ入れ違っている」
dataset_load(job_path)→dataset_set_sample_metadata→dataset_preprocess→dataset_pca→dataset_differential→dataset_export_differential
  1. 訂正したシートを dataset_set_sample_metadata(manifest_path) で渡す。全件検証に 1 件でも落ちれば何も変えずにエラーを返すので、直して再送すればよい。
  2. batch が変われば前処理・PCA・差次的解析が無効化される(changed_fields で確認)。group だけの変更なら PCA は生きる。
  3. 古い結果をエクスポートしようとすると STALE_ANALYSIS_RESULT で止まり、取り違えが起きない。pipeline の run なら同じ訂正を pipeline_resume(updates={"sample_manifest":…}) で行う(書き直しは内容 hash で検出される)。

D. 上位ヒットの同定を裏取りする

「spot 474 の SL 33:0;O は本物?」
sample_search→pai2_parser→verify_peak_annotation→library_load→library_match_feature→library_plot_mirror→eic_plot_chromatograms
  1. sample_search(specs=["ILG_6h"]) で .pai2 / .dcl の実パスを引き、pai2_parser がスペクトルを充填する。
  2. verify_peak_annotation の msms.band が PASS なら実スペクトルを見ている。FLAG_ONLY なら dcl_find_msms で確かめる。質量誤差の帯・アダクト整合と合わせて MSI Level 2/3/4 が出る(Level 1 は出さない)。
  3. library_load(ion_mode="negative")(研究室ライブラリ)→ library_match_feature(precursor_mz, rt) で候補を total_score 順に並べ、library_plot_mirror(scale="sqrt") で目視確認する。
  4. クロマトグラムの形は eic_search_by_mz_range で spot_id を確かめてから eic_plot_chromatograms。

H. 注釈を一覧で確かめ、誤同定を MS-DIAL に返す

「PG の注釈、全部まとめて見たい。間違いは MS-DIAL にも印を付けて」
load_dataset→library_load→curation_review→ビューアで確認→curation_submit→arf_export_differential
  1. library_load(file_path=".../Dataset_*_Loaded.msp2.dbs") でアラインメントに使ったライブラリを読む(別ライブラリだと参照を引けず warnings が出る)。
  2. curation_review(ontology=["PG"])。LLM は件数と suspect 以上の TSV だけを受け取り、html_path をユーザーに渡す。
  3. ユーザーはブラウザで開き、赤破線の likely_wrong(「間違い」が初期選択・メモに根拠)を確かめて直し、「送信用テキストをコピー」してチャットに貼る。
  4. curation_submit(submission_text=…) が記録し、_tags.xml の Misannotation を付ける。MS-DIAL でプロジェクトを開き直すと GUI に出る。
  5. 以後の arf_export_differential は wrong のスポットを同定なしとして外し、メタ行で宣言する。

E. 結果を文献に照らして解釈し、レポートに残す

「この変動は既知の現象? 根拠つきでまとめて」
knowledge_coverage→paper_search→ingest_stage→log_search→ingest_review_queue→ingest_promote→save_volcano_figure→write_report
  1. knowledge_coverage が小問ごとに COVERED / WEAK / GAP を出す。GAP の小問だけ、利用者が確認したクエリで paper_search(ファイル名由来の語は外へ送らない)。
  2. 関連候補は ingest_stage で _inbox に speculative として隔離し、log_search で探索済みを記録。人が ingest_promote / ingest_reject を決める。
  3. 観測データと文献が食い違えば平均せず、観測を優先して食い違いを明示する。save_volcano_figure の PNG を貼り、write_report で保存する。

F. 生データを手で Console に掛ける(極性を足す)

「POS はまだ GUI で回していない。NEG の設定から作れる?」
console_method_candidates→console_method_template→console_prepare_input→console_plan→console_run(detach)→console_status→dataset_load(job_path)
  1. 候補を列挙し、NEG のメソッドを土台に console_method_template(polarity="positive")。差し替えるのは Ion mode と Searched adduct ions だけ。
  2. フォルダに .wiff と .wiff2 が混在していれば MIXED_RAW_FORMATS なので、console_prepare_input(keep_extension="wiff") でハードリンクの単一形式フォルダを作る。
  3. console_run(detach=True) で待たずに戻り、console_status で確認。completed になったら dataset_load(job_path=…)。不要になった生成物は console_cleanup(dry_run=True) で一覧してから消す。

G. メタボロミクス v2(内部標準比と多群)

「内部標準で割った行列で 3 群を ANOVA+Tukey で比べたい」
pipeline_run(v2 request · profile)→dataset_load(pipeline_path)→dataset_build_matrix→dataset_statistic(anova_tukey)
  1. profile(lcms-profile.v1)が method・依存・対象 feature・QC 方針を決める唯一の情報源。resolve_feature_bindings が対象を 1 件に決められなければ止まる。
  2. 対話で recipe を変えた行列を追加で作り、matrix_id を名指しして統計を掛ける。どの行列の数字かが結果に残る。
  3. v2 は合成入力と fake Console までしか検証されていない。実データの結論に使う前に docs/workflow/metabolomics.md の検証範囲を確認する。
12

知識蓄積層とリソース

文献由来の知識(knowledge/)と再利用できる解析手順(playbook/)を MCP リソースとして配信し、解析の目的(analyses/)とレポート(reports/)をツールで読み書きする。セッションをまたいで所見が積み上がる。

record_objective小問 Q1..Qnanalyses/ knowledge_coverageCOVERED · WEAK · GAPbigram Jaccard paper_searchGAP だけ · 確認済みクエリ · Europe PMC ingest_stagespeculative で隔離knowledge/_inbox ingest_promote / reject人が決める · 唯一の昇格経路knowledge/ log_search(再探索を防ぐ) 昇格したノートが次回のカバレッジに効く 要旨は信頼できないデータとして扱い、指示として読まない。ファイル名由来の語は確認前に外部へ送らない。
図 12-1 gap 駆動の文献探索(playbook gap-driven-literature-discovery)。カバレッジは語彙の同義語展開つき文字 bigram Jaccard で、最良 < 0.06 なら GAP、≥ 0.15 かつ established のノートなら COVERED、それ以外は WEAK。paper_search はプレプリントと要旨なしを除き、撤回(Europe PMC の pubType と Crossref)と既存 DOI/PMID/タイトルの重複を落とす。
URI種類返すもの
lipidmix://docs/output-format静的出力フィールドの意味の共通核(最初に読む)。読むと注意書きのガードが既読になる
lipidmix://docs/output-format/{topic}テンプレートトピック別の定義: arf · arf2 · pai2 · dcl · eic · identity · mztab · library · curation
lipidmix://knowledge/index静的知識ノートの 1 行索引 - slug: description [claim_strength]
lipidmix://playbook/index静的手順ノートの索引 - slug: when_to_use
lipidmix://knowledge/inbox静的レビュー待ちの _inbox ノート(found_for・query・score、analysis_id/Qi ごと)
lipidmix://knowledge/expand/{slug}テンプレートノート本体+1 hop の [[wikilink]] 近傍(本体 5 件・約 15,000 トークンまで。超過分は索引行に格下げ)
lipidmix://playbook/expand/{slug}テンプレート同上(playbook を先に探す)
ui://ms-data-parser/curation-viewer静的(text/html;profile=mcp-app)キュレーションのビューア(MCP Apps 用)。curation_review の _meta.ui が指し、証拠は curation_view_data で取る。ブラウザで開く html_path と同じ HTML

GATEWAY の規則: 目的と生物学的文脈とアッセイ種別を確認してから索引を読み、未解決の小問に答えるノートだけを展開し、どのノートがどの小問に効いたかを明示する。ノート同士が食い違えば両方を source / claim_strength つきで示し、speculative を明示する。これらは硬いゲートではなく指針だが、解釈はゲートを通ることが前提。

13

エラー契約とコード一覧

失敗は例外ではなく、本文の JSON 封筒で返す(SDK の isError 経路は structuredContent を落とすため)。どの封筒も error.code が機械可読の識別子、message が人と LLM 向けの説明。

missing_state(前提状態が無い)
{"error":{"code":"missing_state",
  "state":"preprocessed_matrix",
  "required_tools":["arf_preprocess"],
  "message":"前処理後の行列がありません。先に arf_preprocess を実行してください。"}}

state は不透明な文字列として扱う。required_tools は OR の代替で、サーバは実際の生成元を漏れなく列挙する義務がある。

console_error / mztab_error / DomainError
{"error":{"code":"METHOD_FILE_CHOICE_REQUIRED",
  "message":"positive のメソッドが無く、negative の候補があります",
  "details":{"searched":[…],"candidates":[…]},
  "required_tools":["console_method_template"]}}

Console が外部の操作を要するとき(exe 未設定など)は human_action_required と設定手順を封筒に載せる。

領域コードいつ
ConsoleMSDIAL_EXE_NOT_FOUND MSDIAL_EXE_NOT_CONSOLE実行体が未設定 / GUI を指している(--help で確かめる)
METHOD_FILE_NOT_GIVEN METHOD_FILE_NOT_FOUND METHOD_FILE_NOT_TEXT METHOD_FILE_POLARITY_MISMATCH METHOD_FILE_CHOICE_REQUIREDメソッドファイルが決まらない・ZIP を渡した・極性が違う・候補が複数
LBM_NOT_FOUND LBM_AMBIGUOUS脂質ライブラリが 1 件に決まらない
MIXED_RAW_FORMATS INPUT_PREP_FAILED DATASET_ROOT_IN_REPO UNSUPPORTED_AREA_CONSOLE入力フォルダの問題、area 指定
MSDIAL_TIMEOUT MSDIAL_NONZERO_EXIT JOB_BUSY JOB_NOT_FOUND JOB_NOT_PLANNED JOB_POST_RUN_FAILED EXECUTION_UNRESOLVED実行と確定
NO_JOB_OUTPUT削除対象の記録が無い(推測で消さない)
mzTab-M / DatasetMZTAB_NOT_FOUND MZTAB_STRUCTURE_INVALID QUANTIFICATION_CONFLICT POLARITY_MISMATCH AMBIGUOUS_PRIMARY_MZTAB正準の mzTab-M を 1 つに決められない(辞書順にも LLM にも決めさせない)
INCOMPLETE_ANALYSIS_JOB EXPLORATORY_ONLY_DATASET STALE_ANALYSIS_RESULT AMBIGUOUS_RESULT_SOURCE未完了ジョブ・探索専用・古い結果・図の入力元が曖昧
SAMPLE_DESIGN_MISSING COMPANION_ARTIFACT_MISSING ARTIFACT_HASH_MISMATCH DATASET_BAD_REQUEST MATRIX_RECIPE_INVALID NO_ANNOTATED_FEATURES ANALYSIS_RESULT_NOT_FOUND設計・付随ファイル・改ざん・引数・行列
前処理・比較PREPROCESS_PREREQUISITE_MISSING PREPROCESS_STEP_NOT_APPLIED NORMALIZATION_DEGENERATE PREPROCESS_FEATURES_EXHAUSTED QC_PREREQUISITE_MISSINGconservative-v1 / v2 行列の前提と事後検査
COMPARISON_REQUIRED CONFOUNDED_COMPARISON比較の指定忘れ・完全交絡
STATISTIC_GROUP_TOO_SMALL BIOLOGICAL_SAMPLE_ID_REQUIRED REPEATED_MEASURES_UNSUPPORTED STATISTIC_DEPENDENCY_MISSINGv2 統計
pipelinePIPELINE_REQUEST_INVALID IDEMPOTENCY_CONFLICT NEW_PIPELINE_REQUIRED PROJECT_SAVE_BLOCKED受付
MSDIAL_EXECUTION_FAILED UPSTREAM_RERUN_REQUIRED UPSTREAM_NOT_VERIFIED INPUT_CHANGED PIPELINE_ALREADY_RUNNING REQUEST_REVISION_CHURN STATE_REVISION_CONFLICT実行・再開・同時更新
REQUIRED_OUTPUT_MISSING RESULT_INTEGRITY_MISMATCH ANALYSIS_PRECONDITION_MISSING ANALYSIS_PRECONDITION_INVALID PCA_PRECONDITION_MISSING完了判定・handler から漏れた前提エラー(needs_input に変換)
v2 profilePROFILE_VALIDATION_INVALID PROFILE_ADAPTER_UNSUPPORTED FEATURE_BINDING_UNRESOLVED FEATURE_BINDING_OVERRIDE_INVALIDprofile と対象 feature の対応付け
INTERNAL_STANDARD_MAP_INVALID EVIDENCE_UNIT_UNSUPPORTED内部標準・測定証拠
libraryMSP_AMBIGUOUS MSP_ENV_NOT_FOUND LIBRARY_NOT_FOUND INVALID_ION_MODEライブラリを 1 つに決められない(message に置き場所は入れない)
キュレーションCURATION_FLAGS_INVALIDflags.jsonl に読めない行がある(dataset_export_differential)。curation_* と arf_export_differential は {"status":"error","message","flags_file","line"} で同じ事態を返し、書き出さない。その行を直すか消してから再実行する

pipeline で needs_input になるのは入力を直せば進める停止(PREPROCESS_PREREQUISITE_MISSING NORMALIZATION_DEGENERATE PREPROCESS_FEATURES_EXHAUSTED COMPARISON_REQUIRED CONFOUNDED_COMPARISON と、_as_needs_input が包む前提エラー)。それ以外の例外は failed(結果があれば partial)になり、traceback はログへ残る。

14

設定・制約・既知の限界

14.1 起動と環境変数

C:/Python314/python.exe server.py            # 既定 stdio。依存は requirements.txt(Python 3.13+)
C:/Python314/python.exe -m pytest tests -q   # リポジトリルートから
python -m lipidmix.library.store --ion-mode negative   # 大きな .msp の初回構築を事前に
変数既定用途
LIPIDMIX_DATA_DIR<repo>/dataデータ探索先(load_dataset(directory) で実行時に差し替わる)
LIPIDMIX_KNOWLEDGE_DIR LIPIDMIX_PLAYBOOK_DIR LIPIDMIX_ANALYSES_DIR LIPIDMIX_REPORTS_DIRリポジトリ内蓄積先の置き場の上書き用(NAS 共有運用は 2026-09-28 に撤回)。reports は書けなければ DATA_DIR/reports へ退避し、退避したことを返り値で開示
LIPIDMIX_TRANSPORT LIPIDMIX_HOST LIPIDMIX_PORTstdio · 127.0.0.1 · 8000HTTP 待受
LIPIDMIX_CAVEAT_MODEdigestoff で意味論ダイジェストを止める
LIPIDMIX_PLOT_OUTPUTimage描画系の戻り値。Plotly で自分で描くクライアント(Use-LLLM)は payload
MSDIAL_EXE MSDIAL_LBM—Console 実行体(msdialcui.exe / msdialconsoleapp.exe)と脂質ライブラリ
MSDIAL_MSP_POS MSDIAL_MSP_NEG—研究室の参照ライブラリ(外部流出禁止。パスを追跡対象に書かない)
LIPIDMIX_LIBRARY_CACHE_DIRdata/.library-cache照合用 SQLite キャッシュ
LIPIDMIX_PIPELINE_INDEX_DIR%LOCALAPPDATA%/Lipidmix/pipeline-indexpipeline の冪等性索引

14.2 戻り値を小さく保つ決まり

JSON

json_payload()(separators=(",",":")、ensure_ascii=False)。indent=2 は書かない(実測で戻り値の 15〜57% が空白だった)。

表

行が並ぶ一覧は format_spots_as_table() の TSV(列名 1 回、float は約 4 桁、区切りを含むセルは引用符)。

数値

float は丸めてから返す(round_floats() 既定 6 桁、座標は 4 桁)。既定 repr は 17 桁出る。

二重送信を防ぐ

全ツールに structured_output=False。付けないと outputSchema が導出され、同じ内容が content と structuredContent の両方で送られる。

中間データ

座標配列・ローディング全量・全特徴の差次結果・スペクトル座標はセッションに持ち、図保存・エクスポートがそこから読む。

画像

dpi 100 固定。画像トークン ≈ 幅 × 高さ / 750 なので dpi を上げると二乗で増える。

14.3 既知の限界

  • 版依存。バイナリリーダは MS-DIAL の内部クラス配置に従う。クラスを変える MS-DIAL のリリースでは docs/schema/ の Key 番号の再確認が要る。
  • 多群 ANOVA は v1 では非公開。MS-DIAL のメタデータに因子と水準の対応が無いため。v2 の anova_tukey は実験情報シートで群を明示したときだけ。
  • 同定確度は報告するだけで仮定しない。MS/MS のフラグと実スペクトルを全経路で区別する。Level 1 は主張しない。スペクトル照合の順位付けは上流のタプル全体を再現していない。
  • ドリフト補正は移動中央値+線形補間(LOESS ではない)で、バッチ別の補正は無い。
  • ARF 経路では欠損が 0、gap-fill 値もデータとして使うので、half_min はほぼ効かない。検出率で絞るなら min_detection_rate を使う。
  • v2 の検証範囲。合成入力と fake Console まで。実 Console 接続と profile の科学的検証は未了。
  • 生成物は追跡しない。data/ analyses/ reports/ はクリーンチェックアウトに無い。
  • キュレーションの会話内表示は未検証。Claude Desktop のローカル stdio サーバでは MCP Apps の _meta.ui が落ちる(anthropics/claude-ai-mcp#1069)。ブラウザで html_path を開き、送信用テキストを貼る経路が主。
  • MS-DIAL は _tags.xml を丸ごと書き直す。アラインメントを保存するたびにメモリ上のタグで上書きし、読むのはプロジェクトを開くときだけ。curation_submit の反映は、プロジェクトを閉じてから送り、開き直して確かめる。GUI での表示そのものはまだ確かめていない。
  • MS-DIAL で絞り込まれたデータの likely_wrong。MS-DIAL は同定時に precursor の許容幅を課しているので、precursor_unmatched はまず立たない。強い理由の大半は class_rule_rejected と dmz_out。likely_wrong が少なくても「全部正しい」ではなく、suspect の理由コードを読む。
  • 2026-09-27 に解消した食い違い: 同梱参照表を起動ディレクトリに依存せず読むよう修正(以前はリポジトリ外から起動すると ID 付与が黙って全滅していた)。t 値の符号を log2FC と同じ向きに統一。MCP_INSTRUCTIONS とリソース説明のトピック一覧に mztab / library を追加し、テストで固定。library_plot_mirror の説明を mirror.v2 に、ドリフト補正・行列の欠損処理の docstring とコメントを実装どおりに、output_format 文書の log2FC 定義・p 値の計算法・旧ファイル名・スロットの位置を修正。