YONAPO RESEARCH
研究記録
MedDSL(仮称)

RESEARCH / RECORD

P2-a の結果:宣言の書式・10件の後付け・検査

原文 docs/research/21-p2-a-results.md

13 KB

GitHubで見る

版 be280c0

この文書の目次 6項目

実施日:2026-10-19。契約版:p0-draft-2。状態:作成者(AI-001)の単独・内部実施の結果。独立確認前。実行契約 20 に従い、既存の handler に拡張契約の宣言を後付けし、宣言・登録・非干渉・再検証範囲の検査を実装した記録です。実装・契約の振る舞いは変えていません。追加は src/med_dsl/extensions.py、scripts/research/check-extensions.py、extensions/(宣言10件と索引)、tests/p2/(39テスト)で、P0/P1・レビュー系列とは別の分母です。

追記:本書の数値と記述は 25f6cf3 時点(P2-a の直後)です。その後、拡張ホストの分離、防護例の追加(防護例のない義務 24 件 → 3 件)、宣言の固定対象への追加を行い、22 に記録しました。このため §1 の「防護例のない義務は24件」、§3-5 の内訳、§3-6 の過大な列挙(handover.py が 1 モジュール)、§6 の「宣言・tests/p2 は固定対象に含まれない」は、その時点の記述です。

1. 到達点

項目 結果
宣言の書式 p2-extension-manifest-draft-1(必須18項目、未知の項目は拒否)
後付けの宣言 10件:基底 1、host 1、R1 1(定義追加)、R2 1(有限予測)、R3 2(事象化、参考意味の恒等テンプレート)、R4 1(射影)、R5 2(欠落の診断、可用性の点検)、COMP 1(事象化+改名の鎖)
義務 76件。防護例 95件(拒否 70・変換しない 19・境界 6)。防護例のない義務は24件(32%)で、すべて理由つき
証拠の強さ(拡張ごとの最も弱い義務) checked_native_template 7、finite_check 2(事象化・参考意味)、hand_derivation 1(鎖)
登録 10件すべて登録。防護例95件を実際に評価し、宣言どおりの結果を確認
テスト tests/p2 39件(Python 3.14.4/3.11.17 とも通過)
検査自体の検査 extensions.py への変異 37件。最初は31件を検出、6件が生き残り(再検証範囲の列挙の規則が他の規則と重なって見えなかった)、人工の木の単体テストを足して37/37 検出
既存の系列 231開発テスト、レビュー系列 52、追加監査 8、P1 20条件・80 JSON・417必須パス(P0 37 JSON・221必須パス)に変化なし。固定対象は 169 → 170 ファイル(extensions.py)、共通 manifest を再固定

2. 受入条件の結果

条件 結果 補足
X01 欠落の拒否 達成 必須項目18のすべてについて、欠落を拒否し、登録が変わらないことを確認。書式の不正19種も個別の理由で拒否
X02 名前の衝突 達成 操作・schema・profile・回答型・述語・能力の6種別と、名前空間の重なりを検査
X03 非干渉 達成 8つの拡張(予測、事象化、host、鎖、射影、参考意味、欠落の診断、点検)をそれぞれ不活性にし、131例を評価。その拡張と依存先に属さない 70〜128 例の結果は不変、属する例は変わる(無効化が効いている)。表は §3
X06 クラス別の義務 達成 10拡張×クラス別の必須義務を一つずつ外して拒否を確認
X07 防護例 一部達成(設計の文言とは異なる実現) 設計は「各ゲートに拒否する負例が一つ以上」だった。P2-a は「防護例または理由つきの欠落」に置き換えた。防護例の結果の不一致・実在しない例・理由のない欠落・併存は拒否する。防護例のない義務は24件残る(理由は §3-5)。欠落は既知の一覧に固定し、増減はテストが検出する。24件に拒否例を作る作業は未実施
X13 再検証範囲 達成(過大な列挙を含む) draft-2 の変更(validation.py と P0 契約)から列挙した再生成の対象は10拡張・46ファイルと共通 manifest。git 履歴(e73d4ba→2b501c1)と比べて、(a) 三つの hash の置換だけで変わった p1-c 等の例 27件がすべて含まれる(漏れなし)。(b) 46件のうち e73d4ba に存在した 30件はすべて実際に変わっていた(27件+共通の handover.py・handover_spec.json・p1-c の manifest)。残る 16件(examples/review/ 等)は後から追加された実体で、この履歴では確かめられない。設計の「一致」ではなく、漏れなしと、確認できた範囲での過剰なしの組。再検証する拡張は10件すべてと列挙され、モジュール粒度のため過大になり得る(§3-6)。実際に再検証が要った拡張の範囲は、この履歴では測っていない

X03 の対象と範囲

無効にした拡張 属する例(依存先を含む) 属さない例
p1-finite-forecast 31 100
p1-events 61 70
p1-handover-host 39 92
p1-event-chain 22 109
p1-projection 8 123
p1-reference 6 125
p1-absence 3 128
p1-replay 10 121

方法:該当の handler を、unsupported_profile で止まる不活性な代用に差し替えて全131例(P0 37+P1 80+レビュー系列 14)を評価し、差し替えなしの結果と正規化 hash で比較する。宣言の誤りを検出できることも確認した:p1-replay が archive の意味引き継ぎで鎖の認定(run_chain)を呼ぶ読み取りを宣言から落とすと、鎖を無効にしたとき replay の例が変わり、検査が破れを報告する(test_an_undeclared_read_is_exposed_by_disabling_the_extension_that_is_read)。

3. 後付けで分かったこと

後付けの作業そのものが、契約の設計を点検した。

  1. host という層が要る。 引き継ぎの5操作は、schema・profile・仕様・P0 実体の固定を共有する。操作ごとの宣言だけでは、共有する名前の所有者が決められず、HOST クラス(操作を持たない共有の前段)と BASE(基底)を契約に加えた。設計(19)の分類は R1〜R5+合成だった。

  2. embedded_in は拡張ごとではなく、pin ごとに和で見る。 events の仕様 hash は、events 自身の宣言と host の宣言の両方で pin される。埋め込み先の漏れは、pin を宣言した拡張すべての和に対して検査する(最初の検査が、host 単独では漏れていると報告して分かった)。

  3. 名前を組み立てる実装は、名前空間で宣言する。 events は述語の URN を "urn:med-dsl:events:role:" + 役割 で作る。文字列として現れないため、最初は owned_name_not_found で拒否された。末尾が : の名前を名前空間として所有する規則を加えた。

  4. 未宣言の読み取りがあった。 最初の宣言で、p1-replay が鎖の認定を読むことを書き落としていた。コードを読んで気付き、上の非干渉の検査が同じ誤りを検出することを確認して、宣言を直した。宣言は作者の主張なので、検査で突き合わせる仕組みが要ることの実例。

  5. 防護例のない義務の分布。 24件の内訳は、共通の義務 15件(K-RES 8、K-STOP 4、K-INV 3)とクラス固有 9件。宣言の guard_gap に書かれた理由で分けると次のとおり。

    • テストで検査していて、例ファイルがない(12件):予算・上限の境界(K-RES 8、K-STOP のうち 3)と、範囲外の問いで認定が出ないこと(鎖の COMP-2)。例を作ると境界値の構成が大きい、または乱数照合が担っている。
    • 別の防護例またはテストが担う(6件):K-INV 3(認定が定義パッケージだけを読み新しい出力がない、COMP-1 の防護例が担う、全例の入力保持をテストで検査)、host の K-STOP(各操作の拒否例が担う)、p0-definitions の R1-3(R1-1・R1-2・R1-4 が担う)、参考意味の R3-4(R3-1 の防護例が担う)。
    • 構造の性質で、拒否する入力の例がない(3件):事象化の R3-4(新理論の範囲)、基本予測の R2-2(報告専用の固定 package しか検証に渡さない)、鎖の COMP-3(この鎖に損失のある段がない)。
    • 手作業の導出(1件):事象化の R3-3(被覆)。反例の検査は参考意味が担い、事象化自身は有限照合だけ。宣言の上で、証拠が弱い義務として見えるようになった。
    • 該当なし(2件):参考意味の R3-5(履歴を持たない)と R3-6(恒等の翻訳で新しい名前を導入しない)。これらは「証拠がない」ではなく、義務が空になる理由を宣言に残したもの。

    「別の防護例が担う」「該当なし」の判断は作成者の主張で、独立の確認は受けていない。

  6. 列挙はモジュールの粒度で過大になる。 handover.py 一つに引き継ぎの全操作があるため、events・projection・reference の変更は host とその全操作に及ぶと列挙される(漏れではなく過大)。操作ごとの実装の分離で改善できるが、挙動を変えるリファクタリングなので P2-a では行わなかった。

4. 設計(19)からの変更

設計 実際 理由
後付けは6件(S1/S2、forecast、events、鎖、射影、参考意味) 10件(基底、host、欠落の診断、可用性の点検を追加) ディスパッチされる全操作に所有者を決めるため。host は §3-1
義務の「負例」 「防護例」(refusal/non_conversion/boundary) 「確率1でも supported にしない」など、拒否ではなく変換しないことを守る例を含めるため
拡張ホストの分離を P2-a に含める 行わない X03 は、handler の差し替えで実現できた。分離は挙動を変えないリファクタリングで、固定ファイルを広く変え、再固定を要する。宣言と検査を先に固定し、必要は P2-b の前に判断する
証拠の強さ4段階 5段階(hand_derivation を finite_check と checked_native_template の間に追加) 手作業の導出(S1/S2 のモデル拡張、事象化の被覆)を、有限照合と区別するため

5. 再現

python3 scripts/research/check-extensions.py            # 10件を登録し、防護例を評価(--strict で防護例のない義務を失敗扱い、--json で機械可読)
python3 -m unittest discover -s tests/p2 -v             # 39テスト
python3 -m unittest discover -s tests -v                # 231(従来)
python3 -m unittest discover -s tests/review -v         # 52
python3 scripts/research/evaluate-p1-d.py --cli --output data/research/p1-d/p2a   # 20条件

変異検査の script とログは data/research/review-001/(Git管理外)の mutrun_p2.py と logs/mutation-p2*.log。

6. 限界と次

  • 宣言と検査は、意味の正しさを検査しない(実行契約 20 の §7)。独立の確認者は未割当で、independent_review の主張は拒否される。
  • 宣言・tests/p2・check-extensions.py は P1-d の固定対象に含まれない(固定対象は 169 → 170 ファイルで、増えたのは src/med_dsl/extensions.py だけ)。宣言の改ざんや取り違えは、固定された hash では検出できない。固定対象に加えるかは P2-b の前に判断する。
  • 防護例を実際に評価する登録は、今ある例が宣言どおりの結果を返すことを確かめる。ゲートを壊す実装の変更を検出できるかは別で、extensions.py 自体は変異 37件で確かめたが、既存の handler の防護例が各ゲートの変異を検出するかは、P2-a では測っていない(RV-01 の変異検査は P0/P1 の handler について実施済み。17)。
  • X04・X05・X08〜X12・X14 は P2-b 以降。X05(回答型の暗黙変換がない)の機械的な検査は、回答型の宣言と結果の schema の突き合わせが要る。
  • 次は P2-b:パイロット「概念の分割」(19 の §7)を、この契約に沿って設計・実装する。最初の作業は、新しい意味(候補集合と情報要求)の宣言を書き、義務を手作業で導くこと。実装に入る前に、利用者の確認を取る。

P2-a

同じ区分の文書