YONAPO RESEARCH
研究記録
MedDSL(仮称)

RESEARCH / RECORD

P2-s:記録の観察者を必須にする(旧入力を拒否する版の更新)の実装と内部評価

原文 docs/research/78-p2-s-results.md

21 KB

GitHubで見る

版 be280c0

この文書の目次 8項目

作成日:2026-10-21。状態:期間つき数量(P2-i)の記録の observer を必須にして、不明は明示の値 {kind: unknown} で書かせ、依存する5拡張を再固定・採用し、版の記録と履歴の検査を追加。両 Python 版の全体回帰を通過。設計76・手指定期待77 に従いました(利用者の指示:2026-10-21「項目を必須にする版の更新(旧入力を拒否する)」。設計の確認事項 U1〜U3 は推奨どおり)。76・77 の「実装・版の記録は未作成」という記載は設計時点の記録として保持します。独立確認・評価用正解の凍結は未実施で、independent_review / evaluation_frozen は false のままです。数値・識別子はすべて架空です。外部資料は新たに参照していません。

1. 行ったこと

項目 内容
P2-i(draft-4) temporal_measurement.py と 仕様:記録の observer を必須にした。形は `{kind: human
P2-o(draft-3) 操作 record・correct の observer を必須にして台帳へそのまま渡す。ライブラリは欠落を unknown で補わない。確認の操作は観察者を持たない(変更なし)
P2-q(draft-3) 観察者が unknown のとき、観察者を持たない記録と同じに扱う(agent も依頼も流れの変化もなし)
再固定のみ P2-j(draft-4)、P2-m・P2-p(draft-3)。根拠をそのまま写す P2-j・P2-m は結果の中に record_observer が現れる
移行 生成器の既定の変更:全ての例の記録・操作に observer: {kind: unknown} を足す。手編集なし。期待を個別に変えたのは P2-i の O04(訂正が既定の unknown、元は人)だけ
実行例 新しい入力7件:P2-i に O20〜O23(欠落・明示 unknown・unknown に ref・既定)、P2-o に O73・N03-observer-missing・N03-observer-unknown-ref。P2-i 166 JSON・1,796必須パス、P2-o 150 JSON・2,559必須パス
宣言 義務を2つ足した(TM-14:観察者は必須で欠落は拒否、CL-14:ライブラリは欠落を補わない)。TM-13・CL-13 は「あるときだけ」から「常に」へ読み替えた。宣言の数は変わらない(23)。6宣言の版と依存の版を更新
検査 P2-i・P2-o・P2-q のテスト(観察者の全数、unknown の扱い、補完しないこと)、変異、別計算(P2-q)の更新。版の記録の履歴の検査(test_required_observer_version.py:比較器の単位テスト5、履歴の検査9)
版の記録 p2-temporal-measurement-draft-3-to-draft-4.json(p2-version-record-draft-2)。生成は make_required_observer_version_record.py
比較器 p2_checks.py に宣言の種類 required_field(request_leaf・result_leaf・substitution_refusal)を足した。変更は26行の追加と5行の削除。書式 p2-version-record-draft-2 は変えていない

旧版は、変更前のコミット ab4c358(P2-r の結果の追加後)として履歴に残ります。新版の実装は fe420cb、実装の誤りの修正は c586272(§4)、版の記録は b3c7e45(記録は自身を含む木のコミットを指せないため、別のコミット)。

2. 予測の結果(設計76の S1〜S10)

ID 予測 結果
S1 旧版 ab4c358 は旧コミットの木で再現できる(23宣言・316義務・498防護例) 成立。旧コミットの木で統合評価が合格し、23宣言・316義務・498防護例、manifest 4aa13b97…・束 4861a082… を再現
S2 旧入力を新版へそのまま渡すと、pin を持つ入力は profile_spec_mismatch で拒否され、他は同一。黙った再解釈は 0 成立。旧入力762件のうち、拒否703・同一59・変更0。拒否の状態と理由は全て unsupported_profile/profile_spec_mismatch
S3 旧い pin を新しい値へ置換した入力は、全て missing_field で拒否され、受理は 0(P2-r で置換だけで再固定できた3系列も) 成立。6系列×先頭3件の18件が全て invalid_input/missing_field。受理 0
S4 移行した入力は、旧入力と hash の値・宣言した observer の追加を除いて同一。期待は record_observer を確かめる少数の例を除いて同一。料金は変わらない 成立。要求が変わった入力733件は全て observer の追加(と hash の値)だけ。期待が変わった102件は observer を含む写しと、個別に決めた O04 だけ。料金が変わった入力 0。追加は宣言した7件(旧762、新769)
S5 旧入力の結果と移行した入力の結果の違いは、根拠の record_observer の追加だけ 一部成立(初回は外れ、直して成立)。(1) 初回の測定で、O12(人の観察者に ref がない)の error_path が record.observer から record.observer.ref に変わっていた(実装の副作用。§4)。入れ物のパスに直して、この違いは 0。(2) 予測外:結果の違いは record_observer だけでなく、結果が要求の原情報を写す retained_source の observer にもある。違う405件の内訳は、record_observer だけ129・写しの observer だけ83・両方193
S6 要求の側の変更は P2-r の比較器では宣言できず、宣言の種類 required_field と小さな拡張が要る 成立。required_field の宣言がない記録では、移行が宣言にない要求の変更として報告される(test_a_record_without_the_declaration_keeps_the_stricter_old_behaviour)。拡張は p2_checks.py の26行の追加と5行の削除で、書式は不変
S7 書き換わるファイルは800〜860 成立。820ファイル(P2-r は813、P2-l は739)
S8 affected() は6拡張を過不足なく列挙する。過小は P2-r と同じ9件。過大は100〜130件 成立(過大は下限)。6拡張は過不足なし。過小は予測と完全に一致(宣言6件とモジュール3件)。過大は100件(P2-r は118)
S9 unknown を含む入力は、旧版の木で invalid_observer により拒否される。人・機器の観察者だけの入力は、旧い pin に替えれば旧版が受理する 一部成立(拒否の理由が外れ)。新版の入力765件を旧い pin で旧版へ渡すと、unknown を含む734件は受理 0(未知の値を黙って受理しない)。だが拒否の理由は invalid_observer が2件だけで、585件は missing_field、147件は観察者の検査より前の理由(pin・形・予算など)。旧版は ref の有無を kind の値より先に検査するため。受理は8件:人・機器の観察者だけの入力7件と、新版が拒否する N03-observer-missing(旧版は受理)
S10 P2-q の unknown は依頼・agent・流れを変えない:移行後の P2-q の結果は selection.record_observer を除いて同じ 成立。P2-q の例の結果の違いは record_observer と写しの observer だけ(§2 の S5 の内訳)。別計算の全数(観察者〔既定の unknown・human・device〕×出自×型の宣言×Provenance の宣言)と一致し、別計算は unknown を観察者のない場合と同じに扱う

3. 反例の結果(設計76の W1〜W8)

ID 内容 結果
W1 記録に observer がない(台帳) invalid_input/missing_field(P2-i の O20)。補完しない
W2 操作に observer がない(ライブラリ) invalid_input/missing_field(P2-o の N03-observer-missing)。補完しない
W3 unknown に ref/human に ref がない 前者は unknown_field(O22、N03-observer-unknown-ref)、後者は missing_field(O12)
W4 P2-r の時点で有効だった入力を、pin だけ新しくして渡す 18件全て missing_field で拒否。受理 0(S3)
W5 unknown の記録の確認 確認は有効。unknown も内容の一部として hash に含まれ、観察者を書き換えると確認は合わない(P2-i の全数と O05)
W6 訂正が unknown、元の記録は人 選ばれた訂正の record_observer は unknown。元の観察者を継がない(O04)
W7 P2-q:unknown の観察者で Provenance を宣言 生成の agent は AI の1件だけ(観察者の agent を足さない)。依頼も流れの変化もなし
W8 新版の入力を旧版へ unknown を含む734件は拒否、受理されるのは unknown を含まない8件(S9)

4. 実装の最中に見つかった誤りと直し方

  • 版の記録の作成が止まった(実装の副作用):版の記録の作成器が、宣言にない結果の差として p2-temporal-measurement/o12.json の error_path を報告した。ref を条件つきの必須にした新しい検査が、欠落を record.observer.ref と報告していたが、旧版と他の検査(fields())は入れ物の record.observer を報告する。理由と状態は同じ(invalid_input/missing_field)で、期待は経路を固定していなかったため、テストでは見つからなかった。比較器が設計の宣言(observer の必須化)と無関係な診断の変化を見つけた例。新しい検査の報告を入れ物のパスに直した(c586272)。経路を宣言に足して許容する選択もあったが、意図した変更でなく、旧版との一致を保つほうが小さい変更だったため、実装の側を直した。この直しの後で版の記録を作った。
  • 履歴の検査の期待の誤り:S9 の「拒否は invalid_observer、拒否が受理より多い」を履歴の検査に書いていたため、測定(invalid_observer 2件)と合わなかった。検査を、予測でなく成り立つ性質(unknown を含む入力の受理 0、受理は unknown を含まない入力だけ、unknown を含む入力は受理より多い)に直し、理由の分布を版の記録の測定値に加えた(unknown_observer_first_reason)。予測の外れは §2 に残した。
  • 実装の誤り:上の1件のみ。設計77の手指定の期待(O20〜O23、O73、N03 の2件、O04 の変更)は、最終の例の期待と一致している(文書の値と例の期待を突き合わせた)。ただし 76・77 は実装と同じコミット(fe420cb)で履歴に入れたため、「実装前に固定した」ことは履歴からは示せない。

5. 分かったこと

  1. 任意の項目を必須にする更新でも、意味の局所性は保たれた。 旧入力762件は黙って再解釈されず(拒否703・同一59・変更0)、旧い pin を置換しただけの入力は18件全て欠落した必須項目で拒否された。移行は「欠落に明示の unknown を足す」だけで、期待を個別に変えたのは1例(O04)だった。一方、書き換わったファイルは820件と、任意の項目を足したとき(P2-r の813件)とほぼ同じ規模だった。
  2. 必須にすることは、答えの強制でなく、「聞いたが分からない」と「聞いていない」を分けることだった。 unknown は観察者を推測せず、Provenance の agent・依頼・流れを変えない。ただし unknown の細分(聞いていない/聞いたが分からない)は扱っていない。
  3. 比較器は、要求の側の変更を小さな拡張で宣言でき、宣言にない差も見つけた。 宣言の種類 required_field の追加は26行で、書式は不変。移行の差を許す一方で、宣言にない error_path の変化を失敗にした(§4)。

新しい発見

ID 発見 根拠 限界
F31 意味の変更を宣言する比較器は、意図しない診断の変化も見つける。 宣言した項目(observer・record_observer)以外の結果の差を失敗にするので、必須化の副作用の error_path の変化(理由・状態は同じ)が見つかった。手指定の期待が経路を固定していなければ、テストでは見つからない種類の変化 p2-temporal-measurement/o12.json の /error_path。c586272 宣言した名前の項目は、経路を問わず許容する(F32)
F32 宣言の照合は項目の名前(経路の末尾)で行うので粗い。 結果が要求の原情報を写す retained_source の observer も、根拠の record_observer も、同じ宣言で許される。無関係な場所に同名の項目が増えても許容される 比較器の only_declared_leaves。405件の内訳(写しだけ83・根拠だけ129・両方193) 経路全体の宣言は書いていない。写しと根拠を分けて宣言する拡張は未実施
F33 確認は仕様の版に結ばれるので、新旧の互換の部分集合は小さい。 台帳を直接持つ入力(P2-i・P2-j・P2-m)の確認は、記録の hash に仕様の hash を含むため、観察者の項目と無関係でも別の版では review_record_hash_mismatch で拒否される。旧版へ渡した765件のうち、旧版が受理するのは8件だけ。操作から台帳を組み立てる P2-o の入力は hash を持たないので、この拒否を受けない 前方の測定(受理8、unknown を含む入力の受理 0)。P2-i の O01 など4件が観察者以外の理由(確認の hash)で拒否 互換は、確認を使わない入力に限る。確認を版をまたいで引き継ぐ規則はない(既存の規則どおり)
F34 旧版の拒否の理由は、旧版の検査の順序で決まる。 旧版は ref の有無(missing_field)を kind の値の検査より先に行うため、新しい値 unknown は invalid_observer でなく missing_field で拒否された。値の追加が旧版でどの理由になるかは、旧版の実装を見ないと予測できない S9 の外れ(invalid_observer 2件、missing_field 585件) 拒否されること自体(受理 0)は旧版の検査の順序によらず成り立つか、は別の問い(旧版の別の実装では確かめていない)

6. 検査の強さ

  • 観察者の必須化:P2-i の全数(観察者 欠落/unknown/human/device × 訂正の鎖の2記録、記録の hash が観察者ごとに異なること)、不正な観察者の全数、確認の後の書き換え。P2-o の受け渡しの全数(操作の観察者 欠落/unknown/human/device × 確認の操作の観察者)。P2-q の全数。いずれも別計算または独立な計算と比べた。
  • 変異(テストに組み込んだもの):P2-i は、観察者の種類の検査の削除、record_observer を出さない、unknown に ref を許す、の3件(種類の検査は unknown を含む形に更新)。P2-o は、台帳へ渡さず unknown で置き換える(補完に当たる)、根拠に出さない、の2件。全件検出。
  • 変異(設計77の§6のうち、テストには組み込んでいないもの):使い捨ての作業木で一度だけ試した。(1) 欠落を unknown で補う(P2-i)、(2) unknown を ref が必要な種類と同じに扱う(P2-i)、(3) P2-q が unknown を観察者のない場合として正規化する行の削除、(4) 確認の操作が任意の observer を受理する(P2-o)。いずれも既存のテストが失敗して検出した((3) は多くのテストが ref の参照で異常終了するという粗い検出)。コミットした検査ではないので、再現するには変異を手で当てる。設計の「unknown で依頼を出す」変異は試していない。
  • 版の手順:V1〜V8 を履歴の検査9テストで確認した。比較器の単位テスト5は、宣言どおりの報告が通ること、宣言外の要求・期待・結果の差と、置換の拒否の理由の食い違いが報告されること、宣言のない記録が従来どおり厳しいことを確かめる。
  • 比較器の変異:G01〜G05・G10・G15・G16 と対照 Z0 を再実行(比較器を変えたため)。全件検出、対照は失敗0。

7. 検証

Python 3.14.4 と 3.11.17 で、全テスト系列と統合評価を実行しました(版の記録を加えた木 b3c7e45 で実行)。

系列 件数 Python 3.14.4 Python 3.11.17
開発 231 通過 通過
追加レビュー系列 52 通過 通過
保存監査 8 通過 通過
P2 460(P2-r の444に、P2-s のテストと版の履歴の検査〔比較器の単位テスト5、履歴9〕などを追加)。スキップなし 通過 通過
統合評価 P1/P0・拡張・全P2・予算・版比較(3記録)。版の記録を加えた後の履歴の検査も通過 通過 通過
P1-d の CLI 照合・保存監査・登録検査 P1 20条件・80 JSON・417必須パス、別枠 P0 の37 JSON・221必須パス、監査600+256+32+1、登録23/拒否0 通過 通過
統合評価の対象 P2-s 追加後の分母
登録・義務・防護例 23宣言・318義務・500防護例参照(P2-r の316・498から、2義務と防護例2を追加)。宣言の数は変わらない。防護例のない義務は3(変更なし)
証拠の強さ checked_native_template 201、finite_check 109、hand_derivation 8
独立な拡張の組 192/231(変更なし)
実行例の系列 P2-i 166 JSON・1,796必須パス(+4、+39)、P2-o 150・2,559(+3、+32)。他は変更なし
予算 1,453要求・掃引31,198回、違反0(P2-r は1,446要求・31,113回)。掃引の回数は実測で、予測ではない。両 Python 版で一致

予測した分母(義務・防護例・要求の数)は、実行の前に手で導いた値が一致しました(掃引の回数だけは実測)。旧い挙動 digest の回帰と、生成器による全例・宣言のバイト一致の検査は P2 系列に含まれ、通過しました。固定対象に、設計76・期待77・版の記録・検査・道具を加えました。作成者 snapshot で、independent_review / evaluation_frozen は false です。

  • 新 native 仕様 hash(先頭8桁):P2-i 5de7893a…(draft-3 は 168e9f87…)、P2-j 65550ac5…(旧 d1673a14…)、P2-m bd782f9c…(旧 8e84f905…)、P2-o 58abe63f…(旧 bb87cc22…)、P2-p 34f88aa6…(旧 3f8527fb…)、P2-q 062efe75…(旧 422285b0…)。数量の仕様 f52ea526… は変更なし
  • 追加前(ab4c358、P2-r の結果の追加後):1,732ファイル、manifest 4aa13b97…、束 4861a082…
  • 追加後:実装の木(fe420cb)は1,743ファイル、manifest e0aaae42…、束 9094f15b…。誤りの修正の木(c586272)は1,743ファイル、manifest e458292b…、束 2c368451…。版の記録を加えた木(b3c7e45)は1,744ファイル、manifest 0bbefd61…、束 4b4b83d4…(完全な値は各コミットの examples/p1-evaluation/manifest.json)。この文書と概要文書の更新で固定対象は変わらない(再スナップしても同じ manifest)

8. 限界と次

  • 必須にする更新は、1つの項目(observer)の1回の実演です。項目の意味の変更、削除、複数の項目の同時の更新は試していません。
  • 移行は有限の旧入力(762件)と生成器の既定の変更に基づきます。旧入力が行使しない新版の変更は旧入力の比較では見えません。一般の移行の正しさの証明ではありません。
  • unknown は「観察者が分からない」の一つの値で、聞いていない・聞いたが分からない、の細分、観察者の同一性・資格・履歴は扱いません。補完の層(画面など)も範囲外です。
  • 比較器の宣言の照合は項目の名前で行い、粗い(F32)。
  • 設計者・実装者・検査の作成者が同一で、独立確認はありません。
  • 次の候補は、revision の entity と activity の符号、CPC の版の監査、複数の出力先への射影の拡張です。着手前に利用者の確認を取ります。独立確認は将来の英語の別リポジトリで行います。

P2-s

同じ区分の文書