コンテンツにスキップ

壊さないもの

arkhe の設計は、その多くが拒否でできている。すべては 1 つの約束から出ている—— 一度配った名前が、別のものを指すようになることはない。

これらは方針文書ではなくコードで守っている。人が覚えていることに頼る規則は、 いつか破られる。たいていは深夜に、別の何かを直している最中に。

ARK は削除しない

行を消すと解決が止まる。解決しなくなった識別子は、壊れた識別子である。Ark は ORM の層で削除を拒む。

対象が本当に失われたときは tombstone にする。識別子と記述は残り、到達性だけが落ちる。

curl -X PUT /api/tombstone -d '{"ark": "ark:/99999/x9…", "commitment": "取り下げ"}'

以後リゾルバは、転送ではなく記述を返す。これは FAIR A2——データが利用できなくなっても メタデータは参照できるべき——そのものである。

名前空間も削除しない

shoulder を消すと、乱数割当が既に使われた文字列を再び当てうる。消さずに status=retired にする。既存の ARK は解決し続ける。

とくに delegated の shoulder は消せない——外部の minter が、この台帳の知らない名前を その中に作っている可能性がある。

採番が更新に化けない

arklet で最重大の欠陥がこれだった。 主キーの衝突が save() に吸収されて UPDATE に化け、既存の ARK の向き先を黙って書き換えていた。arkhe は採番を 1 か所の経路に閉じ、衝突は失敗させ、数えて、別の名前で採り直す。

衝突回数を握りつぶさず返しているのは、衝突率の上昇が名前空間の枯渇を知らせる唯一の 合図だから。

到達範囲はリクエストで広がらない

authority / manager_id / shoulder_id / allowed_scopes は登録の属性である。 リクエストは shoulder を名指すことはできるが、答えは常に「それが主体の範囲の内側か どうか」だけ。

トークンは自分が運ぶ scope を狭めることはできる。増やすことはできない。

人と機械は別の型

machine の主体は鍵で認証し、外部ログインでは名乗れないperson の主体は身元を 外部が保証し、API キーを持てない

前段のプロキシを正しく置けばなりすましは防げる。だが設定 1 つの誤りが「一括投入 バッチとして全件書き換え」に化けるのは、放置してよい鋭さではない。

記録は対象より長く残る

AuditEvent は他の表と外部キーで結んでいない。記録は対象が消えても残るべきもので、 参照整合性で縛ると逆の力が働く——「消せないから記録も消す」が楽になってしまう。

NAAN 以上に届く操作は全件記録する。届く範囲が広いほど、後から誰が何をしたかを 辿れる必要が高いから。

どこで守っているか

不変条件 実装
ARK と shoulder の削除禁止 db/models.pybefore_delete
retired から戻せない domain/admin_ops.py の遷移表
採番が更新に化けない domain/minting.py の単一 INSERT 経路
到達範囲は登録の属性 domain/authz.py(判断は 1 か所)
人と機械の別 auth/apikey.pyauth/login.pysubject_type 検査

いずれも、外すと落ちるテストが付いている。tests/test_models.pytests/test_authz.py を参照。