# @upbond/sdk 設計記録（Phase 1）

決定日: 2026-07-09（決定: biz@upbond.io セッション）。対象: `packages/sdk` — Login 3.0 外部 SDK（BUILD-SPEC §1「数行で UPBOND ID＋埋め込みウォレット＋リカバリ」）。

## 目的

RP 開発者に auth0-spa-js（認証）と `@web3auth/*`（ウォレット）を直接使わせず、単一の `@upbond/sdk` で両方を提供する。ウォレットレッグは MPC/TSS（`@upbond/wallet-core-mpc`、wallet-core 抽象経由）— PnP/SSS は UAT 専用のまま（`docs/10-deploy-embedded-wallet.md`、憲章 §1）。

## 決定事項

### D1: 単一パッケージ + core/web 内部境界（ユーザー質問への回答）

`@upbond/sdk-core` / `@upbond/sdk-web` の 2 パッケージ分割は**しない**。単一 `@upbond/sdk` の内部を:

- `src/core/` — プラットフォーム非依存（auth クライアント・セッション状態機械・config・エラー）。ブラウザグローバル禁止、import は `@upbond/shared` / `jose` / core 内相対のみ。**`scripts/check-deps.mjs` が CI で強制**。
- `src/web/` — ブラウザ組成ルート（sessionStorage / location / history / createMpcWalletCore 配線）。core → web の import は禁止。

React Native 対応を実際に始める時点で `src/core` を `git mv` すれば `@upbond/sdk-core` として抽出できる。公開契約（`@upbond/sdk`）は抽出を跨いで不変。2 パッケージ分の保守コスト（バージョニング・リリース・import 間接化）を消費者ゼロの段階では払わない。

**ストレージスキーマ**（将来の RN アダプタと共有する契約）: `${storageKeyPrefix}:pending`（PendingAuthorization JSON、redirect 往復間のみ）/ `${storageKeyPrefix}:tokens`（TokenSet JSON）。prefix 既定 `upbond`、wallet-ui は既存セッション互換のため `upbond-wallet` を指定する。

### D2: WalletApp はラップせず、SDK 独自の `UpbondCoreClient`

wallet-ui の `WalletApp` は ChainGateway/残高込みの製品スコープ。SDK は認証 + ウォレットセッション + 署名に絞った独自状態機械を持ち、`use-wallet-app.ts` がブラウザ直書きでやっていた処理（callback 検出・PKCE 永続化・期限チェック）を**テスト済みコアロジック**として吸収する。最終的に wallet-ui が SDK を消費して WalletApp は削除（PR 5）。

### D3: セキュリティ性質（テストで担保）

- **PKCE pending は single-use**: コード交換の**前**に storage から削除（リプレイ・verifier 再利用不能）
- login は navigate **前**に pending 永続化
- 有効トークン復元はネットワーク 0 呼び出し／期限切れは purge して再ログイン（refresh は Phase 1.5）
- `/oauth/token` は form-encoded（auth0-api-compat.md §2）
- logout は MPC セッション → issuer RP-initiated logout の順（憲章 §4 レイヤリング）
- `Layer2Session` は公開 API に**一切出さない**（Layer 2 必須操作は儀式を内部実行、A2 以降はセッション内で保持・再利用し logout で破棄 — D7）— 契約不変条件

### D4: エラー契約

公開エラーは `UpbondError { code: UpbondErrorCode }` のみ。auth レッグの `AuthError` は同基底のサブクラス（code 不変）。wallet-core-mpc の実装エラー型は `src/web/wallet-errors.ts` のデコレータで code に変換し（`cause` に原本保持）、公開面に実装クラスを漏らさない。**code の union が凍結対象**であり、内部クラスの変動は契約に影響しない。

### D5: 認証専用モード

`config.wallet` 省略で認証だけの RP に対応（デモサイトのドッグフード対象）。ウォレット接続は lazy — MPC 初期化コスト（WASM 等）は `connectWallet()` まで発生しない。

**補正（2026-07-24, D18）**: `wallet` 省略はもはや「ウォレット無し」ではなく embedded（ウィジェット）既定になり、`init()` は widget iframe を premount する。auth-only の性質として残るのは「ウォレット系メソッドを呼ばなければ MPC/鍵に触れない・redirect 用 MPC チャンクはロードされない」まで。premount の含意（RP の CSP `frame-src` に wallet オリジン許可が必要、RP ページ訪問が wallet オリジンへ通知される）は D18 の移行ノート参照。

### D6: パッケージング・契約凍結

private / ESM / raw-TS exports / 0.1.0（リポジトリ慣行どおり）。tsup dist + npm publish は「初の外部顧客」マイルストーンで導入。**憲章 §6 の契約凍結は初の外部リリースから適用** — それまでの 0.x では本書に変更を記録する。

### D7: A2 整合 — Layer 2 儀式はクライアント内部で保持・再利用（2026-07-11）

署名儀式の A2 決定（`docs/22-mpc-signing-ceremony.md`、人手承認済）に SDK を整合。`UpbondCoreClient` は Layer-1 セッションにつき **1 つの `Layer2Session` を内部フィールドで保持**し、`unlockWallet`/`setupWallet`/`recoverWallet`/`signTransaction`/`signMessage` が共有、破棄は `logout()` のみ。旧「操作ごとに儀式生成→破棄」は、A2 実装の `MpcWalletCore.logout(layer2)` が Layer-1 セッションごと破棄するため **setupWallet 直後の署名が死ぬ**うえ、再 unlock が消費済み id_token の再送（Duplicate token found）になるバグだった。署名失敗時も儀式は破棄しない（破棄するとセッションが座礁する）。署名毎の生体ゲートは `MpcWalletCore` 側が保証するため、D3 の不変条件（Layer 1 単独で署名不可・署名毎生体）は維持。

### D8: 単回使用 id_token のライフサイクルは SDK が一元管理（2026-07-11）

id_token は Web3Auth ネットワークで単回使用。**儀式の直前に永続化 TokenSet を storage から burn** し（当初は「リロードが消費済みトークンのセッションを復元して再送する事故を**構造的に排除**する」と記述 → 下記 2026-07-12 補正で多層防御に格下げ）、メモリ内コピーだけを auth レッグの読み取り（getUser/getIdToken）と logout の `id_token_hint`（B1）に残す。リロード後は再ログイン（＝儀式の再確立には常に fresh token）。将来の A1（`prompt=none` サイレント再認証）はこの消費点に差し込む。あわせて `MpcWalletCore` 側もリカバリ・フォールバックで **REQUIRED_SHARE で停止した kit をセッション単位で保持・再開**し、`unlockLayer2` 失敗→`recoverWallet` の経路でも loginWithJWT が 1 回に収まるようにした（docs/22 のフォローアップ参照）。

**補正（2026-07-12, セレモニートークン・ゲート導入に伴う）**: 上記の「儀式前 burn がリロードによる消費済みトークン再送を**構造的に排除**する」は、もう正確でない。issuer の id_token TTL（3600s）はウォレットセッションより短く、`#freshIdToken` が refresh_token グラントでローテートした TokenSet を storage へ**再永続化**する（`packages/sdk/src/core/client.ts` の `#freshIdToken`、§D13 のサイレント復元と同じ set）ため、儀式後も storage にトークンが座り得る（ただし再永続化されるのは常に**未使用**トークン）。したがって「消費済みトークンの再送阻止」の保証は**多層防御に格下げ**する:
- **儀式前 burn**（本 D8）は引き続き実施され有効 — 通常経路では消費点の直前に永続コピーを消し、その時点でのリロードは fresh token での再ログインに落とす。ただし単独では構造的保証ではない（リフレッシュが未使用トークンを再永続化し得る）。
- **バックストップ**は wallet-core-mpc 側のランタイム防御 — **spent レジストリ ＋ 単回 duplicate 再試行**（docs/22 フォローアップ 2026-07-12「セレモニートークン・ゲート」）。使用済みトークンがどこから提出されても、提出前の鮮度ゲートで弾くか、`Duplicate token found` を捕えて fresh token で 1 回だけ再試行する。`offline_access`（refresh_token）が前提。

### D9: wallet 設定の環境プリセット（2026-07-11）

`wallet.environment: 'staging'` が UPBOND インフラ定数（network=sapphire_devnet / verifier=upbond-auth-stg / recovery 3 URL、正典は docs/30）を充填。明示フィールドはプリセットをフィールド単位で上書き、`recovery: null` はプリセットの recovery 配線を明示無効化。

**補正（2026-07-24）**: プリセットの適用範囲と既定値は D18（2 パラメータ設定）で全面改定 — environment はトップレベルへ昇格し issuer とウォレット配線全体（UPBOND の `web3authClientId` 込み）を充填、既定は `'production'`。

### D10: facade 完全化（2026-07-11）

- `login(hints?)` — `connection`/`login_hint` を issuer へ転送（プロバイダ選択スキップ）。`beginAuthorization` にも同オプション。
- `unlockWallet()` — 儀式の明示確立（最初の生体プロンプトをユーザージェスチャ上の予測可能な時点で）。
- `signMessage(message)` — EIP-191（M3 で WalletCore に入って以来 facade に欠けていた）。
- `connectWallet()` は冪等（再呼び出しは live セッションを返す — 再 loginWithIdToken は live 儀式を孤児化するため）。

### D11: アプリは `@upbond/sdk` のみを消費（2026-07-11）

`@upbond/wallet-core-mpc` を import してよいのは **SDK（createUpbond 内の dynamic import）と wallet-ui（ウォレット製品自身のオリジン: embed host / auth popup）だけ**。`check-deps.mjs` の CONFINED で強制。MPC デモ（uat-embedded-wallet/mpc-main.ts）は createUpbond だけの SDK ドッグフードに移行し、独自 auth.ts・トークン運用・儀式管理を全削除。

### D17: ウォレット i18n ja/en（2026-07-12）

P2 の残件「言語」の消化。`wallet-ui/src/i18n.ts` — フラット辞書2言語（~120キー）、`MessageKey` 型で ja/en のキー完全一致をコンパイル時強制、`{var}` 補間。モジュールレベルの現在言語ストア＋`useT()`（useSyncExternalStore で言語切替に追従）。設定に `lang: auto|ja|en`（auto は `navigator.language` 解決、既定 auto）。両エントリがブート時に適用、Settings の「言語」セグメントで即時切替。`Intl` 系（フィアット・日付）もロケール追従。SDK のエラーコード→消費者向けコピーの対訳も辞書へ移設（`recovery-view` 含む）。i18n ライブラリは不採用（2言語・型で十分）。**SDK 公開 API 不変。** P2 の残りはカードオンランプ実配線のみ（事業者選定待ち）。

### D16: ウォレット機能パリティ P2 — 表示設定・マルチネットワーク・Add Funds（2026-07-12）

D15 の続き。**SDK 公開 API は不変**（バージョン据え置き）。すべて wallet-ui 内の表示専用機能。

- **設定統合**: `SettingsScreen` は 外観（自動/ダーク/ライト）・表示通貨（JPY/USD）・ネットワーク選択 と、既存の リカバリ節（standalone のみ、`port.recovery` 注入時に表示）を1画面に統合。widget では表示設定のみ。タブ行の ⚙ から両サーフェスで到達。
- **テーマ**: `settings.ts`（localStorage 永続化・`applyTheme` が `data-theme` を root に付与、'auto' は OS 設定を解決）。ライトテーマは styles.css のトークン上書きのみ（コンポーネント規則は共通）。
- **マルチネットワーク**: `AppConfig` を `networks: NetworkConfig[]`（chain＋explorerBase＋indexerBase）+ `defaultChainId` に再構成。`VITE_NETWORKS`（JSON 配列）で複数登録、未指定は従来 env から Sepolia 1件。read 系は `read-services.ts`（gateway/indexer/prices の合成）に一本化し両エントリで共有。**RP 向け EIP-1193 chainId は defaultChainId 固定** — ウィジェット内の切替はウォレット表示のみを変える（provider の chainChanged は発火しない。RP 契約の変更は将来 `wallet_switchEthereumChain` 対応時に別途）。
- **Add Funds**: Home に「＋追加」→ 受取（QR/アドレス）への導線 + カード購入は正直に「準備中」プレースホルダ（オンランプ事業者選定まで機能は載せない）。
- **P2 残**: 言語 ja/en（全画面コピーの i18n 化 — 未着手）、カードオンランプ実配線。

### D15: ウォレット機能パリティ P1 + CSS 一本化（2026-07-11）

web3auth Wallet Services（wallet.web3auth.io/v6 実地調査）とのギャップ埋め第1弾。すべて**表示専用**（署名パス・セッション機構は不変）。

- **SDK（§6 契約の加法変更, 0.2.0）**: `WalletView` 型に `'activity'` を追加（`openWallet('activity')`）。既存 RP コードはそのまま動く（union の拡張のみ）。
- **wallet-ui**: `ChainIndexer` 境界（`indexer.ts`、Blockscout REST v2 実装 — 取引履歴 + ERC-20 自動発見、キーレス・CORS）、`PriceSource`（`prices.ts`、CoinGecko 単純価格、60s キャッシュ・失敗は null）、Activity 画面（ホーム/アクティビティのタブナビ）、Home にプロフィールヘッダ（id_token の name/email/picture claim）とフィアット換算行。indexer/fiat は `VITE_INDEXER_BASE` / `VITE_FIAT_CURRENCY`（`none` で無効化）— 無効時も UI は同一に動作（エンハンスメントであって依存ではない）。
- **CSS 一本化**: `app/styles.css` が唯一のコンポーネント意匠（topbar/brand/secure-chip 含む — standalone にも同じ topbar を表示）。`embed/widget.css` はオーバーレイ chrome（scrim・パネル形状・出現アニメ・パネル内レイアウト調整）**のみ**に縮小（324→約100行）。widget とスタンドアロンの見た目が構造的に乖離不能に（D14 の CSS 版）。
- **意図的な非パリティ**: web3auth の「秘密鍵 Download or copy」（Settings > Privacy and security）は実装しない — 鍵素材の露出経路であり、対応物はリカバリ設定（憲法 §1/§4）。Swap・オンランプ・WalletConnect・NFT/DeFi タブ・マルチチェーン切替は P2/P3 として延期。

### D14: 単一ウォレットフロントエンド（P2, 2026-07-11）

web3auth Wallet Services の「1つの SPA をスタンドアロンでも frame 内でも配信」に倣い、ウォレット表示（Home/Send/Receive のシェル＝どの画面を出すか・残高更新・送金配線・openWallet(view) ハンドリング）を `packages/wallet-ui/src/app/WalletView.tsx` に単一実装として抽出。スタンドアロン製品アプリ（`App.tsx`）と埋め込みウィジェット（`embed/main.tsx`）の**両方が同じ WalletView をレンダー**し、差分は chrome（フルページ vs ドロワー）と port の裏側（SDK facade vs WidgetController／セッションと署名の backend）だけ。これで2面のウォレット画面が視覚的・挙動的に乖離しない。`WalletViewPort`（address/loadAssets/send/onLogout）で backend を注入。**セキュリティ上重要な silent-signing 不能性（WidgetController の confirm ゲート）とセッション機構には触れていない** — 統合したのは表示シェルのみ。confirm カード・未接続状態・ログイン/オンボーディングは各エントリ固有のまま。

### D13: サイレントセッション復元（localStorage 永続化 + offline_access, 2026-07-11）

再訪時に「ウォレットURLを開くだけでサインイン済み」（web3auth Wallet Services と同型）を実現する Phase 1.5 宿題の消化。`persistence: 'local'` で TokenSet を localStorage に置き、`initFromUrl` の復元が **期限切れかつ refresh_token 有り**なら `refreshGrant` で無音更新（ローテートされた set を再永続化）。offline_access 未付与（refresh_token 無し）の期限切れは従来どおり purge。既定は `'session'`（sessionStorage、タブで消える）で認証専用RPの挙動不変。**wallet オリジン専用**（共有端末の別オリジンには使わない）。wallet-ui と MPCデモは `persistence:'local'` + scope に `offline_access` を付与 — Issue #5 のクレームと合わせて「再訪→生体ゼロで即ウォレット」。これは単一フロントエンド化（P1: セッション統一）の第一段：wallet.stg 本体と埋め込みウィジェットが同一オリジンで同じ永続セッションを共有する土台。

### D12: embedded モードを createUpbond に統合（2026-07-11）

Phase 2 の @internal 部品（`mountWidgetFrame`/`runAuthHandoff`/`WidgetProvider`）を facade に昇格。`wallet: { mode: 'embedded', environment: 'staging' }` だけで RP は `connect()`（ユーザージェスチャー内で同期 popup → 封緘ハンドオフ）・`getEthereumProvider()`（EIP-1193、初回呼び出しで iframe を lazy mount・single-flight）・`openWallet(view)` / `closeWallet()` を得る。staging プリセットに `walletOrigin`（wallet.stg.upbond.io）を追加。embedded モードでは RP 側に MPC 設定（web3authClientId 等）は不要 — 儀式は wallet オリジン内。redirect モードのメソッドと embedded モードのメソッドは相互に `wallet_not_configured` を投げる。新エラーコード `popup_blocked`。オーケストレーションは `web/embedded/embedded-wallet.ts`（DI シームで node テスト）。widget 側の実 E2E は M5 の 3 オリジンハーネスで担保済み。

## 明示的な延期

| 項目 | 時期 |
|---|---|
| EIP-1193 provider（`getEthereumProvider()`） | Phase 1.5（RP 統合の本命。chain 設定の追加が必要） |
| refresh token / silent renewal（offline_access） | Phase 1.5 |
| チェーン/残高ヘルパ | Phase 1.5 or wallet-ui 専用のまま |
| RN アダプタ + sdk-core 抽出 | モバイルネイティブ着手時 |
| 埋め込み iframe/中央オリジン層 | Phase 2（サードパーティオリジンの WebAuthn/ストレージ分割問題の解） |
| FactorVault v2（マルチデバイス継続） | Issue #25（別トラック） |
| npm publish + semver/移行ガイド機構 | 初の外部顧客 |

### D18: 2 パラメータ設定 — environment トップレベル化・production 既定（2026-07-24）

顧客インテグレーションの必須入力を **`clientId` の 1 つ**（+ 任意の `environment`）に縮小した。ユーザー指示（2026-07-24）: 「設定するのは client ID と environment の 2 つだけ。environment の既定は production。staging を指定したら staging の issuer と wallet に繋がる」。

- `UpbondConfig.environment?: 'production' | 'staging'`（既定 `'production'`）が `issuer` と wallet レッグ全体を充填。`WalletEnvironment` は `UpbondEnvironment` の deprecated エイリアスとして温存。
- **production プリセット**（定数の出典: ローンチ runbook #137 / `.env.production.local`）: issuer=`https://auth.upbond.io`、Web3Auth=`BA8q4fy…CQCPI`（UPBOND MPC, sapphire_mainnet）、verifier=`upbond-auth-prod`、walletOrigin=`https://wallet.upbond.io`、**recovery 配線なし**（D3 recovery dark ローンチ。prod recovery ペア稼働時に追記する）。
- `redirectUri` は `window.location.origin` を既定に（Auth0 SPA SDK 整合）。issuer 側へのその値の登録は引き続き必要。
- **デフォルト mode は `'embedded'`（ユーザー決定 2026-07-24）**: 2 パラメータ設定の既定はウィジェット方式 — 鍵・パスキー・儀式は wallet オリジン内、RP は EIP-1193 のみ、パートナー追加時の Web3Auth ダッシュボード作業ゼロ、パスキー rpId も upbond.io に統一。`wallet` 省略＝プリセットの embedded 配線（init() で widget iframe を premount）。**mode 推論**: `mode` 省略でもローカル MPC 系フィールド（web3authClientId / network / verifier / rpId / recovery）を明示した設定は `'redirect'` と解釈 — pre-D18 の設定（wallet-ui / デモ / 0.0.2 消費者）が無言でウィジェットに化けるのを防ぐ。auth-only の性質（D5）は維持: MPC チャンク（redirect）はウォレット系メソッドを呼ぶまでロードされない。`WalletStatus 'unavailable'` は「redirect モードのウォレット配線が無い」（embedded モード、または loadWalletCore 無しのホスト）の意味に再定義。
- `wallet.environment` はトップレベル environment を既定とするレッグ単位の上書きとして温存。
- 明示フィールドは常にプリセットに勝つ（フィールド単位）。

## 変更記録（0.x）

- 2026-07-24: **D18 移行ノート（0.0.2 → 0.0.3）**: 明示設定は全て後方互換だが、**`wallet` *省略*の意味が変わる** — 旧: ウォレット完全無効 / 新: embedded 既定で `init()` が wallet オリジンの hidden iframe を premount。auth-only RP への影響: ① CSP `frame-src` に wallet.upbond.io（staging は wallet.stg.upbond.io）の許可が必要（未許可でも premount は握り潰されページは壊れないが `connect()` 系は失敗）② ページ訪問が wallet オリジンに通知される。ウォレットを一切出したくない RP は現状「ウォレット系メソッドを呼ばない」で実質不変（iframe のみ）。
- 2026-07-24: **公開 0.0.3**（`sdk-v0.0.3` タグ → release workflow）。内容 = D18 一式（下記 2 エントリ）。
- 2026-07-24: **D18 — 2 パラメータ設定（既存明示設定は全て後方互換）** — `environment` をトップレベル化（既定 `'production'`、issuer + wallet 配線全体を充填、production プリセット新設）。`issuer`/`redirectUri`/`wallet` が省略可に（redirectUri 既定 = `window.location.origin`）。`wallet` 省略 = プリセットの **embedded（ウィジェット）** 配線が既定（ローカル MPC 系フィールドを明示した pre-D18 設定は redirect と推論）。`UpbondEnvironment` 追加、`WalletEnvironment` は deprecated エイリアス。staging プリセットに UPBOND の `web3authClientId` も充填。
- 2026-07-19: **公開ライン改番 0.3.0 → 0.0.2（API 変更なし）** — npm 初回公開の
  バージョン方針を 0.0.x に決定（docs/27）。内部版 0.2.0 / 0.3.0 は一度も publish
  されていないため改番可能（0.0.1 はプレースホルダで使用済み）。以下の履歴の
  バージョン表記は当時の内部版のまま。
- 2026-07-18: **0.3.0（加法・移行作業不要）** — マルチウォレット基盤（docs/28）。`UpbondState.wallets: WalletRef[]`（`wallet_accounts` クレームの射影、サインイン直後から有効）を追加、`IdTokenClaims.wallet_accounts?` を型定義、`WalletRef`/`WalletKind`/`WalletAccountClaim` を re-export。`walletAddress` ほか既存フィールドの意味・値は不変（今日の `wallets` は常に 0〜1 件）。widget の `eth_accounts` はアクティブアドレス先頭 + クレーム上の他ウォレット後続（現状は従来どおり 1 要素）。
- 2026-07-12: **0.2.0（加法・バージョン据え置き）** — `ProviderEvent` 型を公開面に追加（`WidgetProvider.on` のシグネチャに現れるため型として re-export、実装変更なし）。あわせて公開 API 全シンボルに TSDoc を整備し、`docs/api/`（TypeDoc→Markdown 生成・コミット管理）、`EXAMPLES.md`（embedme で `examples/*.ts` と同期）、リリース runbook `docs/27-sdk-release.md` を追加。

- 2026-07-11: **0.2.0** — D15。`WalletView` に `'activity'` を追加（加法変更、移行作業不要）。wallet-ui にアクティビティ/プロフィール/フィアット/トークン発見（表示専用）、widget CSS をオーバーレイ chrome のみに縮小。
- 2026-07-09: 初版。auth クライアントを wallet-ui から移設、`createUpbond()`（認証専用）実装。
- 2026-07-09: ウォレットレッグ（connect/setup/recover/sign、MPC は dynamic import で lazy）。`postLoginPath` 追加（マルチページ RP 用の callback 後 URL）。uat-auth0-sdk に sdk.html ドッグフードページ + Playwright スモーク 3 本。
- 2026-07-09: wallet-ui が SDK を消費（D2 完了）。WalletApp / 未テストのブラウザ糊は削除、send フローは wallet-ui の `transfer.ts`（compose → SDK sign → broadcast）に再構成。状態機械はリポジトリに SDK の 1 つのみ。
- 2026-07-10: Phase 2 M0 — `recoverWallet()` が同期パスキー復元（FactorVault v2）優先・リカバリアン儀式フォールバックに。
- 2026-07-10: Phase 2 M1 — `@upbond/shared` に widget-protocol（envelope/検証/EIP-1193 エラー表）、`mountWidgetFrame` を @internal で公開（埋め込みモードの createUpbond 統合までは §6 契約対象外）。
- 2026-07-10: Phase 2 M2 — 認証ハンドオフ。`core/handoff-crypto`（ECDH P-256→HKDF→AES-GCM 封緘、AAD=handoffId‖nonce‖rpOrigin）、`refreshGrant`（Phase 1.5 の宿題も解消）、`popup-coordinator`（同期 popup + handoffId 中継）を @internal 公開。**opener.frames 直接配送を Chromium/WebKit/Firefox で実証済み**（spike）。wallet-ui 側: WidgetSessionHost（adopt/refresh）、WidgetAuthReceiver、widget-auth popup。フル OIDC popup E2E は M5 の多オリジンハーネスへ。
- 2026-07-10: Phase 2 M3 — `WalletCore.signMessage`（EIP-191、実鍵で復元検証）、widget 側 `WidgetController`（**silent-signing 不能をテストで証明**: 署名系 RPC は pending に停留し明示 Approve なしに unlockLayer2 へ到達しない。4001/-32602/4200/-32002）、ConfirmRequest UI（origin バッジ + 承認/拒否）、SDK `WidgetProvider`（EIP-1193 over MessagePort、widget:open/close で overlay 自動制御、connect/accountsChanged/chainChanged イベント）。eth_sendTransaction は素の送金のみ（data 付きは 4200、M4+ で拡張）。
- 2026-07-10: Phase 2 M4 — フルウォレット埋め込み。**「create() は常に popup・get() は常に iframe」の全ブラウザ統一設計**（Safari の iframe 内 create() 不可を仕様に昇華、FactorVault v2 のサーバミラーが popup↔iframe のストレージ分断を橋渡し）。auth popup がオンボーディング儀式を内包（初回接続 = ログイン + パスキー登録が 1 回の popup）、封緘ペイロードを {tokens, walletAddress} に拡張、EmbedApp に Home/Send/Receive 転用 + RP 発 openWallet(view)、Firefox(PRF 無し)は署名時に明示メッセージ。widget スイート（handshake+封緘配送）を Chromium/WebKit/Firefox の 3 ブラウザ CI 対象に（6/6）。
- 2026-07-10: Phase 2 M5 — **フルフロー E2E 緑**（RP → popup 実 OIDC → 封緘配送 → iframe にウォレット表示 + RP 窓にトークン素材無しを走査、3 オリジンハーネス）。auth-receiver セキュリティマトリクス（origin/replay/TTL/AAD 改ざん）+ ハンドオフ TTL 実施。`docs/25-widget.md`（決定記録 + RP 統合ガイド + 残存リスク）新設。Phase 2（埋め込みウィジェット）機能完成。残: staging デプロイ（widget クライアント登録 + wallet-ui/デモ再ビルド）と実機 MPC 儀式確認。
- 2026-07-11: D14 — 単一ウォレットフロントエンド（WalletView 抽出、standalone/embedded 両エントリが同一実装をレンダー、silent-signing 機構は不変）。
- 2026-07-11: D13 — サイレントセッション復元（`persistence:'local'` + offline_access 期限切れ時の refresh_token 無音更新）。wallet-ui/MPCデモを local 永続化に。web3auth 型「開くだけでサインイン」UX。
- 2026-07-11: D12 — embedded モードを createUpbond に統合（`wallet.mode:'embedded'`＋プリセット walletOrigin、`connect()`/`getEthereumProvider()`/`openWallet(view)`/`closeWallet()`、`popup_blocked`）。MPC デモに埋め込みウィジェット節を追加。
- 2026-07-12: D8 補正 — 儀式前 burn の「構造的排除」を多層防御に格下げ（`#freshIdToken` が refresh 後の**未使用**トークンを再永続化するため）。消費済みトークン再送のバックストップは wallet-core-mpc のランタイム spent レジストリ＋単回 duplicate 再試行（docs/22 フォローアップ 2026-07-12「セレモニートークン・ゲート」、`offline_access` 前提）。公開 API・契約は不変。
- 2026-07-11: D7〜D11 — SDK を A2 儀式に整合（Layer2 内部保持・logout でのみ破棄、旧 setup→sign 死亡バグ修正）、id_token 単回使用を SDK が一元管理（儀式前に storage から burn、メモリのみ保持）、`wallet.environment` プリセット、`login(hints)`/`unlockWallet()`/`signMessage()` 追加、`connectWallet` 冪等化。wallet-core-mpc は RecoveryRequired で停止した kit を保持し `recoverWallet`/unlock 再試行が**再開**（loginWithJWT はセッション 1 回、fake も単回トークンを強制）。MPC デモを createUpbond ドッグフードへ全面移行（auth.ts 削除）、`@upbond/wallet-core-mpc` の import を sdk/wallet-ui に限定（check-deps CONFINED）。
