v0.6.24 — JSON の項目名と JavaScript の継承を、分けていませんでした
⚠ 先に読むところ
1. 根は 2 つ。指摘は構文 4 つで、こちらは実箇所を 6 つ数えました
版を上げるかどうかを決める判定器(scripts/schemaLanguageDiff.mjs)に、
外部監査から P0 1 件・P1 1 件の指摘がありました。どちらもそのまま再現しました。
根A。 {} は toString も constructor も継承しています。
'toString' in {} → true (own property は無いのに)
({})['toString'] → 関数 (undefined ではない)
out['__proto__'] = x → own property にならない(prototype が差し替わる)
properties の key は受け手が決める名前なので toString も来ます。
判定器はそこを分けずに集合差を取っていたので、項目の追加が見えませんでした。
旧 { type:'object', additionalProperties:false, properties:{} }
新 { …, properties:{ toString:{ type:'string' } } }
ajv {"toString":"x"} が旧 invalid → 新 valid = **広がっている**
判定 HOLD / exit 0 ← 危険側
根B。 正当な再帰 schema(linked list)を比べると
RangeError: Maximum call stack size exceeded で判定を返せませんでした。
打ち切りの鍵が pointer 文字列で、/properties/next/properties/next/… と
伸び続けるため、同じ節へ戻っても一度も重複しません(実測: 8 段たどって重複 0 件)。
**根B は危険側ではありません。**誤った
HOLDを返すのではなく、
答えを返せない——版を決める門が使えなくなる形です。だから直し方も違います。
指摘は危険な構文を 4 つ名指ししていました。直す前に実箇所を数えたところ、
根A だけで 5 か所ありました。
A1a / A1b / A1c properties の集合差 3 か所 ← toString の反例はここ
A2 expandRefs の accumulator が {} ← __proto__ が own にならない
A3 op[k] / np[k] で引く
A4 deref の traversal
A5 resolvePointer の traversal
B 打ち切りの鍵が pointer 文字列
hasOwn / own / bag(=Object.create(null))を 1 か所に置き、全部そこへ通しました。
2. __proto__ だけは ajv でも真値が出せません
指摘の 2 件目は oneOf の枝の中で __proto__ の型を広げる形でした。
**こちらでは ajv が広がりを認めません。**対照行列で切り分けました。
toString / constructor / hasOwnProperty / valueOf → ajv は own property として正しく通す
__proto__ → **ajv 自身が新旧とも拒否**
正解器が同じ盲点を持っています。{"__proto__":"x"} を JSON.parse で作れば
own property になりますが、ajv の内部がそれを own key として扱えません。
だからこの 1 件は判定器の側だけを固定しました(条文 ①-c13 ⑦)。
「ajv が真値を出せる」という前提が崩れた初めての例です。
3. 変異対照で 3 か所が「外しても落ちない行」でした
回帰試験を先に入れ(条文 ①-c13 / ①-c14)、修正前に 5 件落ちることを実測しました。
そのあと直した箇所を 1 つずつ戻したところ、3 か所は消しても全件通りました。
実害を先に測ってから、3 つに分けています。
A1c 共通集合 **精度** 戻すと同じ項目を 2 回数え、正しくは HOLD_RECORD の
削除が **誤って BUMP** になる
A5 resolvePointer **正しさ** 判定は変わらない。contractMigration の
「その pointer は旧に在ったか」が**継承した関数を拾って true**
A3 op[k] / np[k] **falsify 不能** `k` は `Object.keys(op)` から来るので**定義上いつも own**。
どの形でも判定が変わらない
**A3 は消しても落ちません。**承知のうえで残しました——A1c が将来戻ったときに効きます。
コードとテストの両方にその申告を書いています。
足したあと、A3 以外の 7 か所+生成器 3 か所が変異で落ちます。
4. P1 の最初の直し方が間違っていました
「一度でも見た節の組」を覚える形にしたところ、別の試験が 1 件落ちました
——contractMigration の記録した差分が実物から消えていたのです
(/properties/nominalConfiguration/properties/windows/items)。
同じ節が 2 つの経路から来るとき、2 回目を飛ばしてその経路の差分を出さなかったからです。
「一度でも見たか」 → 別の経路から来た同じ節の結果まで消える
「いま辿っている経路上にあるか」 → 循環だけを止める(正しい)
seen をスタックとして使う形へ直しました——降りるときに入れ、戻るときに外す。
変異は 2 方向(鍵を pointer へ戻す/戻るときに外さない)とも落ちます。
出力が減るだけの欠陥は、落ちる試験が無ければ気づけません。
このときは既存の試験が拾ってくれました。
5. 現行 schema にこの 2 形は 1 件もありません
properties の key が prototype 名 0 件
循環する $ref 0 件
(現行 26 schema を走査)
実 schema 200 対(現行 26 schema × 直近 8 tag)で判定は 1 件も変わっていません。
この版の公開物への影響はありません。直したのは将来の版を決める道具です。
**試験の側も直しました。**v0.6.23 の生成器は
prototype 名の property を 0 件、再帰する $ref を 0 件しか作っていません。
補強後は 9 件 / 42 件です。
版数を上げていない根拠(すべて実測)
toolVersion 20 / CLI 結果契約 schemaVersion 2 / profile schemaVersion 3 のままです。
判定器は配布物か **違う**(releaseAssets に 0 回。対照: 検算ツールは 1 回 / 配布物 29 件)
配る検算ツール v0.6.23 と **byte 一致**
da1e5558d0a4cdf38c23274c4486bbbbf94cc79bf02a28a49cd01765af325401
実 schema での判定 **200 対中 0 件が変化**(現行 26 schema × 直近 8 tag)
CLI 出力の 10 経路 基準と byte 一致
profile のモデル数値 **0 件が変化**(葉 2267 / 3130 のうち、動いたのは由来 8 件だけ)
**それが今回直した欠陥です。**現行 schema にその形が無いので、
実 schema での判定が変わらなかっただけです。
まだやっていないこと
- **実測が 1 件も来ていません。**接点位置は全部仮定のままで、
導通測定も音響測定もしていません(verifiedPhysicalはfalse)。 - annotated tag への署名(v0.6.24 も署名なしです)。
mainの branch protection / ruleset。監査の P2 ですが、
リポジトリ設定の変更なので手を付けていません。- Half-Plug 下流の
release-lock v7/mechanism-binding v7(別 repo)。 nanoid3.3.16 の更新。踏む経路が無いと測ったまま据え置きです(SECURITY.md)。- BusyBox を oracle に足すこと(開発機にも CI にもありません)。
- A3 は falsify できないまま残しています(§3)。
- property-based 試験が見ているのは、いまも 1 つの性質だけです。
加えて §2 のとおり、正解器(ajv)にも盲点があることが分かりました。
数えたもの
| v0.6.23 | v0.6.24 | |
|---|---|---|
| 単体テスト | 1457 | 1474(skip 0 / 失敗 0) |
| 配る asset | 31 | 変わらず 31 |
| schema | 26 | 変わらず 26 |
| 検算ツール | toolVersion 20 |
変わらず 20(byte 一致) |
| CLI 結果契約 | schemaVersion 2 |
変わらず 2 |
| profile 契約 | schemaVersion 3 |
変わらず 3 |
| 止め方の名前(catalog) | 82 種類 | 変わらず 82 |
| 出力の基準(経路) | 10 | 変わらず 10(全件 byte 一致) |
検証対象(validate:profiles) |
14 | 14 |
| 記録された入力 | 32 | 32 |
| 区間 / event | TRS 23/32・TRRS 30/36 | 変わらず |
変わっていないもの
- **モデルの数値。**接点位置も走査結果も同じです。
verifiedPhysicalはfalse。実測記録は依然 0 件です。- IV028 は
13.3–13.52 mm/ASSUMPTION/ground-open-differential/
RETURN_OPEN_L_AND_R_ON_DISTINCT_CONDUCTORSのままです。 toolVersion20 / CLI 結果契約schemaVersion2 / profileschemaVersion3 / catalog 82 種類。- 止め方の名前の一覧・
archivePolicy・status・終了コードの意味。 - 公開済みの release 本文と asset は書き換えていません。
過去 875 件(v0.1.0〜v0.6.23)が byte 一致であることを、再生成の段ごとに実測しました
(対照として基準を 1 行壊すと 874 件へ落ち、v0.1.0の該当ファイルを名指しします)。