[aside] web の client projection(`web/src/projection.ts`)が server projection(`src/projection.rs`)の手動再実装で、event→列の materialize を 2 箇所で lockstep に保つ必要があり、ズレを検出する仕組みが無い。 PR #255(SPA read 基盤)で `encrypted_payload` 列を client projection に足す際に踏んだ観察。 - SPA は DuckDB-WASM で client 側に独自 projection を持ち、event log から `posts_raw` 等を **ブラウザ内で組み直す**。その SQL(`web/src/projection.ts`)は server の `src/projection.rs` と **別実装の手書き**で、同じ event→列ロジックを二重に保持している。 - 今回 server 側は既に `posts_raw.encrypted_payload` を持っていたが、client 側は `encrypted` フラグだけで envelope を落としていた。SPA で復号するには暗号文が要るので、client projection に 列 + INSERT の `json_extract` + view を **手で mirror** した(server と同じ形に揃える作業)。 - リスク: server に列/正規化を足しても client 側に反映し忘れると、**SPA だけ古い形のまま黙って動く**(今回の `encrypted_payload` 欠落がまさにそれ)。両者の一致を担保する test も codegen も無く、`norm_actor` の no-op alias(既存 aside n_01KSXV3A6YRKCHRGQVKHTFCHYB)のような個別ズレも同根。 - 今触らない理由: PR #255 は read 基盤が主眼で、projection 二重実装そのものの解消(共有 schema / codegen / 差分 test)は大きい別軸。 - 方向案: (a) projection の列定義を 1 source から server/web 両方へ generate、(b) もしくは「server と client projection が同じ `posts_raw` 列集合を持つ」ことを assert する test を足して drift を CI 検出。最低限、列追加時の checklist に「client `projection.ts` も mirror」を明記。 - トリガー: 次に server projection に列/正規化を足すとき、または client/server projection のズレで SPA だけ壊れる事象が出たとき。