YONAPO RESEARCH
研究記録
MedDSL(仮称)

RESEARCH / RECORD

P2-u:用語の版更新の監査(CPC 2026-09-08 → 2026-10-05)の意味設計

原文 docs/research/82-p2-u-design.md

23 KB

GitHubで見る

版 be280c0

この文書の目次 11項目

作成日:2026-10-21。状態:作成者側の設計草案。runtime・native 仕様・宣言・実行用 fixture・実データの実行は未実施。R4 の評価設計04 の D04(薬剤概念の版更新監査、一方向、SAB=RXNORM、独立確認者なし)を、P2 系列の契約として実装する設計です。利用者の指示(2026-10-21「CPC の版の監査に進みます」)と、範囲の確認(契約+架空の例+実データの実行、属性は宣言した方針で分類し未宣言は依頼)に従います。独立確認は未実施で、independent_review / evaluation_frozen は false のままです。実データの取り扱いは D03(03-data-access.md)と台帳(03-materials.json)に従い、生データ・記録の中身は Git に入れず、文書には集計と方法だけを残します。committed な例はすべて架空です。

1. 問い

ID 問い
Q1 月次更新のとき、既存の参照(旧版の概念 ID)ごとに、「新版でそのまま使えるか/何が変わったか/判断に追加情報が要るか」を、比較した範囲を明示して報告できるか
Q2 同じ ID が続くこと(継続)と、意味が同じであることを区別できるか。新版に ID がないとき、後継を名称の一致などで推測せず、不明と報告できるか
Q3 名称・関係・属性の差を別の面として比べ、どの面にも差がなかったときだけ「比較した範囲では差なし」と言えるか。比較していない面を差なしに数えないか
Q4 属性の重要度(定義にあたるのか、管理上の情報か)をライブラリが決めずに、宣言を受けて使い、未宣言の属性の差は推測せず依頼にできるか
Q5 この契約を、実際の 2 版(81,468 概念)に適用して、面ごとの変化の量と、宣言の違い(方針の感度)を測れるか

2. 下調べで分かっていること(設計の前に見た集計)

設計の前に、取得済みの 2 版(SAB=RXNORM)の差を、面ごとの件数だけで集計した。以下は予測ではなく、既知の値として扱い、予測(§8)は、まだ計算していない量と、契約の性質に限る。

面 既知の集計(9 月 → 10 月)
概念 9 月 81,468、10 月 81,620。両版にある 81,298、9 月だけ 170、10 月だけ 322
原子 両版にある原子 140,535 件は、用語種別・文字列・抑制の欄が 1 件も変わっていない。変わるのは追加(539)と削除(306)だけ。続く概念で原子が増減したのは 3 件(-2、+1)
概念間の関係 追加 1,932、削除 1,388。すべて追加・削除された概念につながる。両端が両版にある概念どうしの関係の変化は 0
属性 追加 2,521、削除 2,519((RXCUI, 属性名, 値) の集合)。続く概念に対する追加 1,723、削除 1,887。大半は NDC(削除 1,844、追加 1,751)。強度に関わる属性(RXN_AVAILABLE_STRENGTH、RXN_STRENGTH、RXN_BOSS_* など)も一部変わる
構造 SAB=RXNORM の RXNSAT は全行が原子(AUI)に付く。SUPPRESS は概念・関係・属性のすべてで空または N。RXNREL は概念対概念 553,500 行と、原子対原子 59,472 行
関係の向き has_ingredient・isa・consists_of・has_dose_form・tradename_of の用語種別の組(例:RXCUI1 が成分 IN、RXCUI2 が薬剤成分 SCDC)から、行は「RXCUI2 が RXCUI1 に対して RELA の関係にある」と読む向きに合う(NLM の説明と同じ。NLM の文書自体は未取得で、局所データの集計による裏付け)

この集計は、概念の定義にあたる部分がほぼ動かず、動いているのは「収載の出入り」と「属性の入れ替わり」だと示す。ただし意味が保たれたこと、廃止・置換が起きたこと、NDC の入れ替わりが定義の変化でないことは、この集計では示せない。

3. 設計判断

判断 初回に採る設計 理由・見直す条件
UD1 単独の専用 R5を新設する(P2 系列の他の拡張に依存しない)。操作 run_terminology_audit:旧版の snapshot と新版の snapshot、比較範囲(出典)、属性の方針、監査する参照の列を受け、参照ごとの監査の行と、集計を返す。一方向(旧→新)。逆向きの成立を推定しない D04 の一方向。クラス R5:保存を主張しない診断(変わる点を記録、認定を出さない、臨床の主張を足さない)
UD2 snapshot は正規化した形:concepts[]={id, source, atoms[{id, kind, name, attributes[{name, value}]}], relations[{kind, target}]}。概念の同一性は (出典, id)。関係はその概念から出る向きで、向きの読み替えは呼び出し側(正規化)の責任。契約は向きを反転しない。属性は原子に付く。名前・属性名・値・種類は不透明な文字列で、内容を解釈しない 実データの構造(原子に付く属性、行の向き)に合わせる。不透明にして、第三者の語彙の内容に触れない
UD3 継続=新版に同じ (出典, id) の概念がある。名称・属性・関係の一致は継続の判定に使わない。新版にないときは not_found、successor: not_determined で、後継の候補を一つも返さない。追加情報の依頼(provide_official_history)を返す 名称の一致だけで概念を同一視しない(D03 の誤った扱い)。CPC は廃止・抑制された内容を含まないので、不在は廃止の証拠でない
UD4 比較する面は三つ:名称(原子の追加・削除・同じ id の種類/文字列の変更)、関係((種類, 対象) の集合の差。対象が各版に存在するかの旗つき)、属性(両版にある原子の (原子, 名前) ごとの値の集合の差)。面を混ぜた推論をしない。追加・削除された原子に付く属性は、属性の差でなく、名称の差に伴う件数(with_atom_change)として数える P-CPC-2 の期待(名称の変更を含量の変更と推定しない)。原子の増減と属性の増減を分ける
UD5 属性の方針は呼び出し側の宣言:policy.attributes[]={name, class}、class=definitional(定義にあたる)/administrative(管理上の情報)。ライブラリは属性名の意味を知らない。差のあった属性が未宣言なら、差を undeclared に分けて依頼(declare_attribute_class)にし、推測しない。使った宣言(差のあった属性)は assumptions に残す。使われなかった宣言は痕跡を残さない P2-q の status・code と同じ規則。専門的な判断を実装が決めない
UD6 継続した参照の state(優先順):changed(名称・関係の差、または定義にあたる属性の差がある)→needs_information(未宣言の属性の差がある)→changed_administrative_only(管理上の属性の差だけ)→unchanged_in_scope(比較した三つの面のどれにも差がない)。not_found・not_compared(出典が比較範囲の外)はそのまま。unchanged_in_scope は「比較した範囲で差なし」で、意味の同一ではない 比較不能を差なしとして扱わない
UD7 関係の対象が新版に存在しない(未解決)ときは unresolved_in_to={target, in_from} に出す。旧版に存在した対象が新版で未解決なら関係の面は changed、旧版でも存在しなければ既存の状態として報告だけ 依存の欠落を見逃さず、既存の不整合を差分に数えない
UD8 出力は参照ごとの行(presence・state・facets・requests・assumptions・successor)、比較範囲(出典・面・方針・比較していないもの)、集計(概念数・継続・旧のみ・新のみ・状態別の数)。認定は常に not_certified、推測で補った情報は常に空 P2-q 以降と同じ
UD9 料金:M=1+n_from+n_to+Σ(参照ごとの料金)+1。参照の料金は、比較範囲の外なら1、範囲内なら 1+A_f+T_f+R_f(旧版の原子数・属性数・関係数)に、新版にあるときだけ A_t+T_t+R_t(新版の同じ数)を足す。n は snapshot の概念数。入力不正は予算に依らない。未完了の行は値の欄を null にし、集計も null 手で導ける式
UD10 実データの実行は契約の関数を直接呼ぶ(JSON の大きさ・予算の限界を通らない)。実データの snapshot は、道具(scripts/research/audit-cpc-versions.py)が台帳のハッシュを確かめた ZIP から正規化して作る。正規化の写像(列の位置、行の向き、重複の除去、原子対原子の関係・原子に結べない属性の扱い)は、架空の RRF 形式の ZIP を使うテストで確かめる。実データの結果(行を含む)は Git 管理外の data/research/r4/ に置き、文書には集計だけを書く D03 の「生データを共有しない」

4. 入口と型(予約名)

項目 予約する型・範囲
profile / operation p2-terminology-audit-draft-1 / run_terminology_audit
request / result p2-audit-request-draft-1 / p2-audit-result-draft-1
回答型 terminology_version_audit
要求 schema_version, operation, consumer, from, to, scope, policy, references, budget
from・to {ref, version, concepts[], source_sha256?}。ref が同じ(同じ用語)で version が異なること
scope {sources[]}(比較する出典。最大8)
policy {attributes[{name, class}]}(最大64)
references 旧版の概念 ID の列(最大256、重複なし、旧版に存在すること)

結果の行(results[]、参照の昇順):reference, source, presence, state, facets, requests, assumptions, successor, assessment_complete, reason_codes。presence=continues/not_found/not_compared。facets=継続の行だけ:names{state, added[], removed[], modified[]}、relations{state, added[], removed[], unresolved_in_to[]}、attributes{state, definitional[], administrative[], undeclared[], with_atom_change{added, removed}}。他は null。トップレベル:direction: from_to、reverse_inferred: false、versions、scope、policy、summary。

5. 判定の規則

  1. 参照の (出典, id) が旧版にあり、出典が scope.sources にない→not_compared。
  2. 新版に同じ (出典, id) がない→not_found(successor: not_determined、依頼 provide_official_history)。
  3. あれば継続。三つの面を比べる:名称(原子 id をキーに、追加・削除・種類/文字列の変更)、関係((種類, 対象) の集合。対象が各版に存在するか、新版で未解決か)、属性(両版にある原子の (原子, 名前) ごとに、値の集合が異なるもの。差を方針で definitional/administrative/undeclared に分ける)。
  4. UD6 の優先順で state。未宣言の属性の差があれば、状態に依らず依頼を返す。

6. 七欄と義務の主題

欄 内容
前提 属性の分類は宣言(作り手の判断)。正規化(出典の行の読み方)は呼び出し側。契約は不透明な文字列を比べる
版 自己の profile・仕様 hash を consumer が固定。用語の版は snapshot の version と任意の source_sha256
確認対象 確認は作らない。参照の継続と面ごとの差を報告する
情報の選択 比較範囲(出典・面)を明示。範囲外は比較しない
問い 「この参照は、新版でそのまま使えるか。何が変わり、何が判断できないか」
保持・喪失・追加 差の報告(追加・削除・変更)と、比較していないもの(履歴・意味・他の出典・原子間の関係・抑制)を明示。使った宣言を仮定として残す
資源・停止 UD9。停止の順序:静的検査→索引→参照ごと→最後の確定

義務(16:共通4+R5の3+AU-1〜9):AU-1(A)自己の版と実体。AU-2(I)各参照がちょうど一つの状態に入る(分割)。AU-3(I)継続の同一性と、後継を決めないこと。AU-4(I)面を別に比べ、差なしの条件。AU-5(I)属性の方針と依頼。AU-6(I)関係の向き・対象の存在・未解決。AU-7(I)比較範囲と範囲外・集計。AU-8(F・E)料金・停止の順序・未完了行。AU-9(H)推測で補わない(後継・逆向き・意味)。予測(H2):主題の外の義務は出ない(この契約は外部資料の事実を native に持たないため。実データの写像の事実は道具とそのテストが持つ)。

7. 実データの実行(道具)

scripts/research/audit-cpc-versions.py:台帳のハッシュで 2 つの ZIP を確かめ、RXNCONSO・RXNREL・RXNSAT の SAB=RXNORM の行を正規化して契約の関数に渡す。ZIP の展開・SQL の実行・通信は行わない。

正規化の写像 内容
概念 RXNCONSO の SAB=RXNORM の行の RXCUI(出典は RXNORM)。原子={id: RXAUI, kind: TTY, name: STR}。同じ原子は一つ
関係 RXNREL の SAB=RXNORM かつ STYPE1=STYPE2=CUI の行を、所有者=RXCUI2、種類=RELA(空なら REL)、対象=RXCUI1 の関係とする(局所データで向きを確認済み)。同じ組は一つ。原子対原子の行は比較しない(件数を報告)
属性 RXNSAT の SAB=RXNORM かつ STYPE=AUI の行を、原子(RXAUI)に付く {name: ATN, value: ATV} とする。原子に結べない行・重複は件数を報告

実データの属性の方針は、作り手の研究上の仮定(医学的判断ではない)として二通りを宣言する:P-full=NDC を administrative、データに現れる他の全ての属性名を definitional。P-partial=NDC を administrative、強度に関わる属性名だけを definitional、他は未宣言。方針の違いが状態の分布をどう変えるか(感度)を測る。

8. 実装前に固定する予測と反例

8.1 予測(契約の性質)

ID 予測 外れた場合に分かること
AP1 他の拡張・実装・仕様・宣言・旧実行例を一つも変えずに実装できる。変更は host.py の2行、手で持つ一覧(P2-q・P2-t と同じ11か所)、道具と台帳の追加だけ 標準の登録の手間
AP2 登録は25宣言・351義務・533防護例、独立な組は 232/276(新しい拡張は基底を除く他の23件と依存せず、23組が独立に増える) 依存の宣言
AP3 各参照がちょうど一つの状態に入る。状態別の数の和は参照の数に等しい。実データでも成り立つ AU-2
AP4 継続は (出典, id) だけで決まる。旧版の概念と同じ名称・属性・関係を持つ新しい ID の概念があっても、旧版の概念は not_found で、候補を返さない AU-3
AP5 面は独立:ある面の差は他の面の結果を変えない。比較した三つの面に差がなければ unchanged_in_scope AU-4
AP6 未宣言の属性の差は全て依頼になり、推測で分類されない。使われなかった宣言は痕跡を残さない AU-5
AP7 旧版と新版を入れ替えた監査は、継続した参照の各面の差を入れ替えたものになり(追加と削除、値の from と to)、not_found と新版のみの数が入れ替わる。結果は逆向きの推定を含まない(reverse_inferred: false) 一方向
AP8 料金 M の式が全要求で成り立つ。手で導いた値(例:2参照・全概念4・差なしで M=30)と一致する UD9
AP9 義務は R5 と必須欄で足りる。主題の外の義務は0 H2
AP10 affected():この拡張は他の拡張に影響されず、他の拡張に影響しない(自分だけ) 依存の効果

8.2 実データの予測(まだ計算していない量に限る)

ID 予測 備考
RP1 全 81,468 参照が一つの状態に入る。not_found=170、新版のみ=322(既知の値の再現)。名称の差のある概念=2(既知)。原子の modified=0(既知) 既知の値の再現の検査
RP2 続く参照のうち、属性の差が一つ以上ある概念(P-full・原子単位)は 1,500〜3,300 追加 1,723・削除 1,887 の件数から
RP3 そのうち NDC 以外の属性の差がある概念は 100〜600 NDC 以外の削除は約 675 件
RP4 関係の差がある続く参照は 100〜1,300。除かれた関係の対象は、全て新版に存在しない(target_in_to が真の除去は0) 両端が続く関係の変化は0(既知)から導かれる
RP5 続く参照で、新版で未解決かつ旧版に存在した対象(unresolved_in_to の in_from が真)は 0。旧版でも未解決の対象は少数 版内の整合
RP6 P-full での続く参照の changed は 300〜1,500、unchanged_in_scope は続く参照の 95% 以上(77,200 以上) 面ごとの件数の和から
RP7 P-partial では needs_information が 0 より大きく、changed の数は P-full と等しい(未宣言の属性の差だけの参照が、changed_administrative_only や unchanged_in_scope から needs_information に移るだけ) 方針の感度。優先順 UD6 の帰結

8.3 反例(83 に具体値を固定)

ID 内容 試すこと
Z1 同じ ID で強度(定義にあたる属性)が変わる 継続だが changed。ID の継続を意味の同一としない
Z2 管理上の属性(NDC など)だけが変わる changed_administrative_only。changed に混ぜない
Z3 未宣言の属性が変わる needs_information、依頼。分類を推測しない
Z4 旧版の概念が消え、同じ名称・属性・関係の新しい ID の概念が現れる not_found、successor: not_determined、候補なし
Z5 名称の一部(同義語の原子)だけが変わる changed(名称の面)。含量などの意味の変更と推定しない
Z6 関係の対象が新版から消える/関係だけが落ちる 対象の存在の旗が区別する。除去と依存の欠落
Z7 出典が比較範囲の外の参照 not_compared。範囲外の差は無視し、差なしにも数えない
Z8 旧版と新版の入れ替え AP7
Z9 原子が減ると属性も減る 属性の差でなく名称の差に伴う件数
Z10 出典が変わった同じ ID (出典, id) が違うので not_found(出典の変更は別の概念として扱う。限界として記録)
Z11 並びの違い(原子・関係・属性の順序) 差にならない
Z12 同じ版の組/別の用語の組 静的に拒否(same_version/system_mismatch)

9. 受入条件

  1. 期待・予測・反例を、runtime より先に別の文書(83)で固定し、実行結果から期待を更新しない。
  2. 専用 native・module・R5 宣言・fixture・独立な別計算・道具と、道具の正規化のテストを追加する。他の拡張は変更しない(AP1)。
  3. 別計算は、集合の演算で独立に書く(native の面ごとの差の計算を読まない)。
  4. 全数(属性の方針の部分集合×差の種類)、乱数、入れ替え、並びの不変性、料金の式、予算の掃引、入力の不変性、型破損、変異(継続を名称で決める、後継の候補を返す、方針の推測、面の混合、範囲外の比較、優先順の取り違え、先払いの省略)を検査する。
  5. 実データの実行を、方針二つで行い、集計(既知の再現、予測の結果、感度)を結果の文書に記録する。実行は 2 つの ZIP のハッシュと台帳の一致を確かめてから行う。
  6. Python 3.11/3.14 で、全テスト系列、版比較つき統合評価、旧い22,052件の挙動 digest を回帰する。分母の変更は旧い値を履歴として残す。
  7. 追加前は 8c6d600、固定対象1,827ファイル、manifest 94d5eabe7f4282c129e1fda3d407b35d7d5ca2d25006a2b95eecfc61e9a634e8、束 e2cd592909c79f76d3e251d1728c88e9547f17636f80e3478b8ef9aa9c9b591b。件数・hash・予測の結果・残る穴を結果の文書に残す。independent_review / evaluation_frozen は false。

10. 範囲外

後継・置換先の決定、廃止と収載条件の変化の区別、公式の履歴・対応表の利用、成分・含量・剤形の意味の解釈、治療上の代替、原子対原子の関係、SUPPRESS・CVF の比較、出典 MTHSPL など RXNORM 以外、週次更新、全体版、逆向きの監査の導出、未見の月次版への適用(設計の固定後に別途)、第三者の語彙の内容。

この設計は、版更新の監査の契約を、実際の 2 版に当てて面ごとの変化の量を測る一つの実演です。参照の更新を安全に行えることの証明でも、薬剤の意味が保たれることの主張でも、他の月に変化の量が一般化することの証明でもありません。最終目標は変化に耐える医療コード体系そのものの確立であり、この有限の設計はその一つの検査です。

11. 利用者に確認すること

ID 確認 推奨
U1 NLM の技術文書(関係の向き)と CPC の説明(収載の範囲)のページを、台帳のハッシュつきで取得するか。この設計では取得せず、向きは局所データの集計で裏付けた 取得しない(希望があれば取得して事実の表に結ぶ)
U2 実データの属性の方針(P-full、P-partial)は作り手の研究上の仮定で、医学的判断ではない そのとおり

利用者の指示は「進みます」だったため、推奨どおりに実装へ進みます。

P2-u

同じ区分の文書