SPA ↔ quacker-channel の共通ロジックを全コード調査 → 大半は load-bearing な並行実装、dedup は据え置き

きっかけ: 「SPA の作りで quacker-channel との共通ロジックの多さが気になる」。3 つの前線をコードで確認した結論:

- **apply ロジック(~1000 行): 還元不能**。gateway は常駐プロセスで新着イベントだけを永続 projection に増分適用(incremental catch-up ── local_sql.rs の seen / fetched_files、削除も per-event 反映)、SPA は空から full-rebuild する bulk SQL(projection.ts、DISTINCT-ON-latest は「batch = 全履歴」前提で増分には使えない)。実行モデルが別なので共有不能。
- **schema(~210 行): 意図的な別バリアントで単一化は設計悪化**。SPA は leaner + unfiltered ── posts_current は audience フィルタ無しの素 passthrough(データは wire で既に絞り済)、server 専用列(groups_current.encryption_enabled / group_members.member_pubkey / post_embeddings.updated_at)を省略、body は NOT NULL(server は metadata_only で nullable)。単一ソース化すると SPA に server 制約を背負わせることになる。
- **crypto: 唯一の真の冗長だが HKDF 派生レシピ ~130 行のみ**(凍結 info 文字列 `quacker.x25519.group:` 等)。age 封筒も bip39 も標準フォーマットで両側に準拠ライブラリがあり仕様経由の相互運用 = 我々の共有コードではない。その ~130 行は Rust 生成 golden vector を TS test が assert していて、drift は既に loud-fail で防がれている。

判断: WASM 化(keys.rs を Rust→WASM core にして SPA の派生実装を置換)は web build + CI に wasm-pack / wasm-bindgen を恒久追加するコストに対し、便益(~130 行が drift 不能になる)が薄いので **据え置き**。tier1(schema 単一化)・tier2(apply 共有)は上記理由で取り下げ。

再考トリガー: **鍵ローテーション**が来て crypto が育つ局面。そこで初めて「複数の鍵バージョン管理を 1 実装に寄せる」option value が立つ。

replies