メインコンテンツまでスキップ

同一性 — uid

三年前にセンサーが結んだ空間を、いまも同じものとして指せること。それが uid の仕事である。

space /L5/A/ldk ldk X1..X2 Y1..Y2 name:LDK uid:u-7f3k9m2qx4b8dhtv

何が同一性を持つか

対象同一性の出どころ
uid が書かれた空間・集約その uid が正典である。パスが変わっても同じものである
uid が書かれていない空間・集約パスで対応づく。改名すれば対応は切れる
関係(boundary)両端の空間から導かれる。関係に uid は書けない
開口・seg・柱それを含む対象と、その中で一意な名から導かれる

関係に uid を書けないのは、関係が必ず二つの空間の間にあるからである。両端が定まれば関係も定まる。関係ごとに uid を書けば関係の数が空間の数を上回り、「一棟が機械の視野に入る」という目的を自分で削ることになる。

同一性には責任を持ち、内容には持たない。

uid は必須ではない

必須にしないのは、保証の強さを書き手が選べるようにするためである。時点をまたいで指す必要がある空間にだけ付ければよい。リポジトリの中の参照はパスで足りる。uid が要るのは、外の台帳やセンサーと結ぶときである。

書ける対象は閉じている

uid を書けるのは spacezone だけであり、この一覧は閉じている。

  • 他の要素に書けば ATT03 — 台帳に無いキー
  • level に書けば構文エラー

黙って無視される経路は無い。

acme.uid: のように名前空間を付ければ書けるが、それは運搬層である — core は見ない。「同一性を持たせた」ことにはならない。

綴り

u-7f3k9m2qx4b8dhtv

接頭辞 u- + 16 字、合わせて 18 字。字母は Crockford base32 の小文字で、紛らわしい i l o u を持たない。接頭辞の u は字母に無いので、生成された uid は必ず一つだけ u を持ち、それが先頭である。

16 字 × 5 ビット = 80 ビット

接頭辞があるのは、数字だけの綴りを構造的に不可能にするためである(数値化するとトークンの区別が失われるので、数字だけの uid は UID01 で拒まれる)。空白も書けない。

種別は綴りに入れない。uid は不透明であり、綴りから何かが読めてはならない。

生成は乱数、付与は明示の行為

uid はパスからもモデルの中身からも導出しない。導出すれば改名でトークンが変わり、uid の意味(改名を跨ぐ)が消える。機械が作るときは乱数である。

import { newUids } from "@kensnzk/koyu";
const [a, b] = newUids(model, 2);

MCP なら new_uids

付与は明示の行為である。書き手が書くか、newUids / new_uids を呼ぶまで、どのツールも uid を書かない。write_layer も書かない。自分から付与するものは無いので、改名を跨いで指す必要が出たときにだけ呼ぶ。

衝突しないことの範囲

保証は二段である。混ぜてはならない。

相手保証
合成済みのモデル衝突しない。生成器が検査して作り、checkUID03 が証明する
まだ合成されていない層・他のリポジトリ確率でしか保証しない。80 ビットなので 100 万個を集めても衝突確率は 10⁻¹² を下回る

確実さが要るなら、合成して check を通すこと。実際に一意性を証明するのは UID03 だけである。

名は、一つのものを指していなければならない

「含む対象 + その中で一意な名」が同一性である以上、一つの名が二つを指す状態は同一性の破れである。合成の集合編集(= window W1 / - column C1)がどちらを指すのか決まらない。

これは検査され(UID04)、合成の側でも拒まれる。曖昧な名を狙った drop= は、黙って片方を選ばずに拒む

アセットから継いだ名は、同一性の主張ではない。

asset W1 window w:2600 h:2200 sill:0 name:掃き出し窓

この name は型の名であり、同じ建具を一枚の壁に二枚並べるのは普通の設計である。同一性の主張は、その開口の行に書かれた名だけである。

隣り合う頁