[handoff] server 薄型化 post-③ の後続作業 一括引き継ぎ(2026-06-02、このセッションが長く出力も乱れたので fresh session 用に文書化)
## 完了済(このセッション、全 merged)
content-write 再ホーム = `answer_feedback`(#330)/ `annotate_post`+`create_post_anchor`(#331)。leak fix(#340、private post mutation の公開ストリーム漏れ → boot で routing index 再導出)。SPA reply audience(#343)。docs staleness sweep(#342)。MCP decrypt-overlay(#346、posts_view が encrypted_payload を project + 復号後 envelope strip + decrypt_error)。delete_group guard dead-read(#345、apply_routing_only に Post/CurationDeleted tombstone)。残骸掃除(#323 projection_db / #326 rebuild_projection CLI)。
## 🔴 進行中(最優先)= server body-drop(confidentiality)
**問題**: runtime `persist`(`src/server.rs:2241`)が全 event を full `apply` するので、server projection が **plaintext の post body を in-memory に蓄積**(post-boot 分、restart で reset)。E2E で守るべき message content を server が持つ = 「server は content-blind」前提を破る。user が confidentiality 修正として greenlit 済。
**スコープ確定(grep 済)**: server は runtime に **body を一切読まない**(`src/server.rs` の body 読みは 3340/3310 行 = test のみ)。server が読む content は tags(`claim_goose_jobs`)/ encrypted フラグ(`post_is_encrypted`)/ feedback 件数(`request_feedback`)/ audience / deleted / owner ── これらは E2E 設計上 plaintext で良い routing metadata(暗号化されるのは body のみ)なので残す。**落とすのは post body(+ 派生 mentions + ciphertext envelope)だけ**。
**実装(worktree `server-body-blind` は作成済・編集ゼロ。clean なので fresh で切り直して可)**:
1. `Projection`(`quacker-core/src/projection.rs:26-28`、現状 `conn` のみ、構築は 56・72 行)に `retain_bodies: bool` を追加。
2. `Projection::open()` = retain_bodies=true(gateway/test/既定)。`open_metadata_only()`(retain_bodies=false)を新設。`open_at`(69 行、test 用)は true。
3. `apply` の PostCreated arm(~907)= !retain_bodies なら body=NULL・encrypted_payload=NULL・`reindex_post_mentions` skip(encrypted フラグ/audience/owner/ts/tags は従来通り書く)。PostUpdated arm(~925)= !retain_bodies なら body UPDATE を skip。
4. `serve()`(`src/lib.rs` ~101)の authz_projection を `open_metadata_only()` で構築。gateway(`local_sql.rs` の `LocalSql::new` → `Projection::open()`)は full のまま(run_sql に body が要る)。boot(#345 の `apply_routing_only`)は元々 body 無しなので不変。
5. test: body 無し projection が PostCreated を body 抜き(audience/encrypted/tags 込み)で fold すること + 既存 server read(`audience_of_post`/`post_is_encrypted`/guard)が不変なこと。
**注意**: persist は #279/#286(起動 hang/OOM)を踏んだ hot path。body 以外は behavior-identical を gate に。**過去の私の「runtime を routing-only に倒す」は誤り**(server は tags/encrypted/feedback を読む)── 正しいスコープは「body だけ落とす」。
## 残タスク(優先度順、各 aside が一次情報)
1. **#334 high-level MCP read tools**(read_post/list_posts/search_by_tag/read_curation/read_thread)── feature。#346 の decrypt overlay の上に、gateway 側で envelope strip + decrypt_error 構造化。`run_sql` は power-user 用に残す。
2. **delete_group guard の curation 穴**(aside `n_01KT4CHJ`)── #345 で curation tombstone は入れたが guard が live curation を数えない(write-only)。`authorize_group_empty`(`src/server.rs` ~2010)に `SELECT COUNT(*) FROM curations_raw WHERE audience_group_id=? AND deleted=FALSE` を足し >0 で reject(post 側と対称)。小・機械的。
3. **#335 probe/smoke post hygiene** ── approach 選択要(ephemeral field / g_probe group / cleanup_probes tool / tag 規約)。design alignment が要る。
4. **claim_goose_jobs**(aside `n_01KT47CQE` の片割れ)── ③ server で current_tags 空読みで 0 claim になりうるが、goose PR は実際出ている = 走ってる dispatcher の upstream が ③ でない疑い。**まず調査**(binary/env mismatch か)。
5. **create_post reply の tool-description**(aside `n_01KT4BB0`)── 「reply は audience_group_id 省略」と書くが ③ 後 server は必須化(resolver が解決して渡す)。description を直す。小・docs。
6. **proxy.rs doc 誤配置**(aside `n_01KT4CE9Y`)── create_post 用 doc が `apply_annotate_post_overlay` に紛れ `apply_create_post_overlay` が doc 無し。① 領域(#330/#331/#343 hot file)なので落ち着いて。
7. **boot の `store.read_all` 全ロード**(aside `n_01KT3JYCT`/`n_01KT13B7P`)── 全 log をメモリに読んでから filter。latent memory、低優先。
8. **verify/sandbox infra**(aside `n_01KT496385` sandbox --clearenv / `n_01KT46SGC`・`SM3` の .rustc_info.json replay・--offline build.rs / `n_01KT49W5X` goose --watch isolation)── infra、一部要調査。
9. **log-framework refactor**(note `n_01KT47S86`、本丸・大物)── log-core engine + LogModule、content/authz/agent_run domain 分割。**body-drop はこの down-payment**。私のリプライ(`n_01KT488N4`)で reconcile 2 点指摘済:(a) gateway の LocalSql が新 Projection 消費者、(b) content domain / 共有 DuckDB がどのノードで走るか(③ で server は content-blind = content domain は gateway/agent 側)。
## 引き継ぐ設計不変条件(これを踏まないと逆走する)
- **authz-trust litmus**(aside `n_01KT484F`):gateway 解決の事実は「server が authz projection から security 判断を再導出できる」なら trust 安全(annotate の write-gate=`authorize_group_visibility` / #340 の routing)。再導出できない読み取り可視性 gate(answer_feedback)は resolver 層 + single-owner。
- **SPA は /mcp 直叩き**(aside `n_01KT3WWRV`):content 依存の server 要求は SPA でも解決して渡す要(answer_feedback #330 / anchor #331 / reply #343)。tag/update/delete は #340 の server routing index で吸収済 = このクラスは概ね closed。
- **server content-blind は boot 限定**(aside `n_01KT4A1EV`):runtime full-apply が body 蓄積 → body-drop(上記🔴)で解消。
- 正本 memory: `project_quacker_server_thinning_direction`(全状況 + 方式2 到達点 + litmus を集約済)。canonical note: `n_01KT2CV84…`。
引き継ぎはここまで。fresh session は 🔴(body-drop)から、`server-body-blind` worktree を切り直して着手するのが筋。