# quacker identity/account 設計 — alignment 決定 (2026-06-01)

**役目**: account/identity 層を ATProto から自己主権へ移す設計の正本。2026-06-01 の設計対話で合意。実装はこの decision を起点に分解 dispatch する。背景 = standalone 方向(publish 撤去後、ATProto identity は消費しない federation コストを払うだけ)/ user の「nostr の方が思想に合う」表明(n_01KSPVRM)/ 実害なし=急がない。

## 決定済みの骨子

- **owner identity = did:webvh**。master_seed(SPA 乱数)を単一 root に Ed25519 署名鍵を派生して anchor。`owner_did` は不透明文字列 PK なので認可/projection/audience は無改修、移行は文字列 rewrite。did:key/nostr はローテ不可で owner 不適、ActivityPub はドメイン固着で除外。VC 不要(self-asserted closed ledger)。Rust は `ssi`(DIDKit は archived で不可)。
- **3 tier**: owner=did:webvh(重・復旧あり)/ collaborator=自前 DID(owner が追加)/ guest=did:key(使い捨て)。同じ DID モデルを「重力」で段階化。
- **agent = A1**(軽量 handle 維持、現行 token scope、UCAN/Biscuit 入れない)。**collaborator = B1**(DID 貼付 + TOFU)。**A2(agent=鍵+UCAN)/B2(検証セレモニー)は理想形か未確定で棚上げ**、非破壊で後付け可。
- **guest 投稿(優先)**: 開放主・gated 従。guest=ブラウザ自動 did:key、`g_public`+自動 `guest` タグ、ホーム feed デフォルト表示 + 「guest を隠す」フィルタ UI。moderation は既存 tag+view-side filter で primitive 化(新規モデリング無)、悪いものは `delete_post`。新規実体=未認証 did:key の write 経路 + Turnstile/rate-limit のみ。
- positioning(n_01KSxxx 系)の "+SNS" 面を初めて実体化する(personal tool が公開参加スペースも兼ねる)。

## 機械的決定(推奨、要 review)

### 1. seed→鍵派生
- master_seed を**単一 root に再利用**(rotate-in しない。既に E2E root)。purpose 分離した HKDF info string で派生:
  - 署名鍵: `HKDF(seed, "quacker.id.sign.v{N}")` — **version 付き**。鍵ローテ = N を進める(pre-rotation で N+1 の hash を前 entry に commit)。
  - 暗号鍵: 既存の `HKDF(seed, "quacker.x25519.group:"+group_id)` 据え置き。
- 限界(明記): 署名鍵も次鍵も seed 由来なので、pre-rotation は「公開署名鍵の leak」は守るが seed 全損は守らない。**seed が単一 root → ④ 復旧が生命線**。

### 2. did:webvh log
- `did.jsonl` は **quacker 自前 server で serve**(既に HTTP 持ち)。**pre-rotation ON**(将来ローテ要件)、**witness OFF**(1-owner に過剰)。
- portability: SCID 由来で key-rooted なので移行時に log を別 host へ移しても検証可能(移送 path は ① 実装時に詰める)。注意: log を自 domain に置く間は resolve 可用性が domain 依存(ただし identity 自体は暗号的に自分のもの、再 serve 可)。

### 3. owner_did → did:webvh 移行
- pre-alpha-clean に従い **clean one-shot rewrite**(dual-write しない、compat shim 無し)。event log の owner did:plc → 新 did:webvh を一括 rewrite(過去 migration 008 と同型)。owner は 1 人なので mapping は 1:1。
- タイミング = ① の cutover(それまで ATProto OAuth は生かす)。最大の risk step だが機械的(1 DID→1 DID 文字列置換)、旧 log 保持で巻き戻し可。collaborator は新規に自分の DID で入るので移行対象外。

### 4. owner の複数デバイス unlock(=④の一部)
- auth と custody を分離。master_seed が秘密、各デバイスに存在させる。
- envelope: seed を per-device KEK で wrap。provisioning = **BIP-39 mnemonic**(seed encode、Linux でも確実)を 1 回入力 or QR 転送。日常 unlock の KEK = passkey PRF(Apple/Windows/Android のみ)/ **Linux daily driver は passphrase wrap**(Firefox-Linux の PRF は HW キー要のため)。
- 印刷 BIP-39 を常時 recovery KEK。login(local/無)は seed-unlock と decouple。

## guest 面 仕様
- write 経路: 未認証訪問者の SPA が did:key を自動生成 → `create_post` を **g_public + 自動 `guest` タグ**に制約(server が tag を強制付与)。owner token 不要の新 endpoint。
- abuse: **Cloudflare Turnstile**(CF Workers 上なので低コスト)+ rate-limit(IP/key)。did:key は再生成で key-block 回避可なので IP/Turnstile を主に。
- 表示: ホーム feed デフォルト表示。SPA に「`guest` を隠す」フィルタ toggle(view-side filter、ViewMode 1 個)。
- E2E 非対象(g_public 平文)。owner+検証済 collaborator の E2E 面と分離。

## build 順序
1. **④ master_seed custody/復旧**(envelope + 印刷 BIP-39)— seed が identity root になる前提の安全網。最優先・独立。
2. **guest 面**(did:key write 経路 + Turnstile + 自動 tag + hide UI)— owner 移行と半ば独立、優先度高、早期/並行可。
3. **① owner did:webvh**(seed 派生鍵 → DID 発行、OAuth と併走 → cutover rewrite)。
4. **② ATProto OAuth 降格**(login 手段の 1 つに)、atrium-* 撤去。
5. **③ agent**: A1 のまま(現行 token)。collaborator B1 は実需が出たら。

## 棚上げ / open
- **A2**(agent=鍵+UCAN委譲)/ **B2**(safety-number 検証)= 理想形か未確定、実需 trigger で非破壊追加。
- 鍵管理 UX(Shamir/social recovery)は BIP-39 で当面足り、必要なら後で。

参照: memory `project_quacker_identity_account_direction` / `project_quacker_standalone_direction` / `project_quacker_e2e_master_seed` / `project_quacker_agent_identity_model`。

replies