要約

  • JSON Type Definitionは、意図的に限定された構造契約にインスタンスが適合するかを調べる。合格は内容の真偽を保証しない。
  • 排他的な八形式、階層ごとの未知フィールド方針、二つのエラーポインタが、実装間の暗黙の解釈を減らす。
  • 認証、認可、業務上の不変条件、再送防止、永続化、結果確認は、スキーマ検証後の独立した判断である。

検証器が空のエラー配列を返した瞬間、運用画面は安心を演出する。しかし、その配列が空なのは、厳密な契約を満たしたからとは限らない。JTDのempty形式なら、どんなJSON値でも通り、エラーは一つも生まれない。

この例はRFC 8927の限界ではなく、限界を明示する強さを示す。JSON Type Definitionは、メッセージの形、型、必須項目、列挙値、タグ分岐を共通に評価するための小さな言語である。送信者が本人か、その操作を許可されているか、記載時刻が信頼できるか、保存が完了したかは扱わない。

表現力を抑える理由

RFC 8927はIndependent StreamのExperimental文書で、IETF consensusもStandards Trackの地位も持たない。実験の成功は、複数の独立実装が実際にJTDを使って情報交換することで測られる。番号の付与そのものは導入証明ではない。

形式はempty、ref、type、enum、elements、properties、values、discriminatorの八つで、互いに排他的である。definitionsはrootにだけ置かれ、refはその共通辞書を参照する。discriminatorのbranchはtagを別型として再定義できない。

これにより、処理順や入れ子の位置で意味が変わる余地を小さくする。CDDLはより豊かな制約を記述でき、RFC 8927自身もJTDの構文をCDDLで定義する。JTDが自分自身を記述できないことは、目的の失敗ではない。通常の型生成に必要な範囲へ共有仕様を絞った結果である。

Heng Luのminimum initial specificationは、まさにこの選択を説明する。共同層にすべての政策を押し込まず、独立実装が一致できる最小部分だけを固定する。

metadataは共同法ではない

JTDのmetadataには、文書、コード生成のhint、ローカルUI用の情報などを置ける。他者が理解するとは期待できず、portable validationを変えてはならない。検証動作を変える拡張は、関係者が帯域外で同じ意味を合意した場合にだけ共同契約になる。

したがって、「JTD合格」という記録だけでは再現できない。raw messageのhash、schemaのhashとversion、validator、extension profile、resource limitを結び付ける必要がある。同じメッセージでも、empty schemaと厳密なschemaでは証拠強度が全く違う。

外側を開いても内側は開かない

properties形式では、必須と任意のfieldを分け、未宣言fieldをdefaultで拒否する。additionalProperties:trueは、その指定があるobjectだけを開く。nested objectへ継承されない。

外側のenvelopeが将来のrouting fieldを許しても、内側の支払命令を閉じたままにできる。これをlibraryのglobal switchへ変えると、schema作者が残した境界が消える。監査には、unknown fieldの名前だけでなく、どの階層で、どのruleにより受理されたかが必要だ。

forward compatibilityは無条件の善ではない。古いconsumerが新しい重要命令を無視することもある。リスクを負う受信側が、各階層で将来判断を持つべきである。

二つの場所は原因順位ではない

標準error indicatorは、拒否された値を指すinstancePathと、拒否した規則を指すschemaPathを持つ。どちらもJSON Pointerである。データと契約が衝突した座標を対で保存できる。

ただしerrorの順序は規定されない。先頭がroot cause、最重要、最初に発生した問題という意味はない。Pointerも修正権限を与えない。正確な住所は判断主体ではない。

自動修復を行うなら、優先順位、所有者、rollbackを別のpolicyとして記録しなければならない。

型と時刻が証明しないもの

JTDはboolean、string、float32/64、符号あり・なしの8〜32 bit整数、timestampを扱う。timestampはRFC 3339とAtomによる絞り込みに適合する必要がある。しかし、正しい文字列は時計の信頼性や出来事の発生を保証しない。過去の正当なcommandを再送しても形は正しい。

int64とuint64を省いたのは、JSON実装が全範囲を正確に保持できないためである。I-JSONはbinary64で正確に共有できるより狭い整数範囲を示す。魅力的な型名で偽のportable promiseを作る代わりに、JTDは約束そのものをしない。

discriminatorもbranchを選ぶだけである。account_deleted tagと必要IDがそろっても、削除実行の証拠にはならない。送信者認証、権限判断、受理記録、永続化、readbackは別々のreceiptだ。

schemaも攻撃入力になる

root definitionへの参照はcycleを作り得る。RFC 8927はuser-supplied schemaを扱う実装にcycle検出と中止を勧める。単純な再帰評価は無限loopとなり、DoSの入口になる。RFC 8259も入力size、nesting depth、number precisionの制限を認める。

運用契約にはbyte、depth、reference expansion、error count、execution timeのbudgetがいる。schemaがtrusted artifactかtenant inputかremote dependencyかも区別する。JSONとして正しいことと、安全な計算量であることは別の現実である。

出典

  1. RFC 8927:JSON Type Definition
  2. RFC 8259:JSON Data Interchange Format
  3. RFC 7493:I-JSON Message Format
  4. RFC 6901:JSON Pointer
  5. RFC 3339:Internetの日時形式
  6. RFC 4287:Atom Syndication Format
  7. RFC 8610:Concise Data Definition Language
  8. Heng Lu:Running-Code Primacy
  9. Heng Lu:Minimum Initial Specification, Localized Future Decision, and Voluntary Adoption
  10. Heng Lu:On Reality Layers, Symbolic Power, and Why Clarity Feels So Hostile