[design] quacker log framework ── log-core engine + LogModule 契約(content=core / agent-activity=最初の非 core)

設計確定(2026-06-02、user alignment 済 / 実装前。末尾に ③ reconcile 追記)。capture 機構 note(n_01KT3TXAZ…)の「store = quacker-native AgentRun」を、quacker 全体の log/projection 方針に一般化した結論。

## 方針

- quacker の **core プリミティブ = content のみ**(post/tag/ref/curation/group…、永久)。
- 非 core の log(agent-activity 等)は core に足さず、**`LogModule` framework 経由で別 namespace に register**。
- = core を content-only に保つ原則の帰結。framework は「非 core log が core を汚さず quacker に乗る境界」。動機は multi-log roadmap でなく **core 純度**(この点は会話で誤解→訂正済)。

## engine = quacker-log-core

現コードの機構(NDJSON store / chunked replay / `_projection_meta` catch-up / DuckDB projection)は既にほぼ generic、癒着は `Event` enum + `apply` の 21-arm match のみ。これを domain trait の裏に移して engine 化:

- namespaced store(read_since)
- chunked replay + **per-namespace catch-up**(`_projection_meta` を namespace ごとに stamp ── 片方の migration が他方を replay しない)
- DuckDB projection driver(domain の apply を呼ぶ)、**1 DuckDB 共有で cross-namespace join 維持**

## LogModule 契約(= 固めた「projectable log の形」)

`namespace` / `Event`(自分の typed、core enum に足さない) / `init_schema` / **`apply`(一様冪等=必須)** / `migrations`(独立系統) / `retention`(Forever|Ttl|Rollup)。

- **冪等必須** = content の per-arm 不均一(PostCreated は ON CONFLICT 無し等)という anti-pattern を、新規 log では構造的に禁止。

## 当てはめ

- **content = core domain**(その Event+apply を trait impl へ移す)。namespace `content` 特権・永久・retention=Forever。「core プリミティブは content のみ」= core 指定 namespace は content だけ。
- **agent_run = 最初の非 core domain**: Event=`agent_run_started`/`ended`(`activity` 予約)、tables=`agent_runs`/`tool_calls`/`posts_read`/`produced`、retention=Ttl|Rollup。core enum には入らない。
- core 性 = engine 上の**指定**であって別機構ではない(機構二重化しない)。

## content 載せ替え = 採択 (A)

content も engine に載せ替える(clean・機構二重なし・「core=content の特権 namespace」が綺麗に表現できる)。risk = prod incident を踏んだ replay/projection path に触る → **behavior-identical test を gate** にする。安全版 (B: agent-activity 先行・content 後日・一時二重) は不採用。

## 実装順

1. quacker-log-core **一般化**(`LogModule` trait + engine。quacker-core は既に crate=③、抽出でなく一般化)
2. content を content domain に載せ替え(behavior-identical test gate ── **gateway `LocalSql` 経路も含む**、下記 reconcile)← risk step
3. agent_run domain 実装(新規・content risk 無し)
4. capture レーン配線(ACP client / transcript parser が engine 経由で emit) ── capture 機構 note 参照

## ③ reconcile(review n_01KT488N… + origin/main 確認、2026-06-02)

server 薄型化 ③ は既に shipped(#318 server content read-model 削除 / #312 content-independent authz projection / #330 feedback re-home / #327-329 **quacker-core crate 抽出済**。#331 は in-flight)。本 note を ③ 後の現実に補正:

- **engine 化 = 「抽出」でなく「一般化」**: `quacker-core` は既に crate(events.rs/projection.rs はそこ)。残るのは content-specific な `Event`/`apply` を LogModule engine に一般化する作業(実装順 1)。
- **実行ノード = gateway/手元の `LocalSql`、server ではない**: #318 で server は content-blind(authz/membership のみ)。content domain・agent_run domain の projection、および「1 DuckDB 共有 cross-namespace join / replay path」は **content が既に住む gateway/agent の `LocalSql`** で走る。quacker-core engine は node 非依存・projection 実行ノードは domain 次第。server に content+agent_run DuckDB を置くのは ③ 逆行=しない。
- **content 載せ替えの test scope**: server authz projection だけでなく **gateway `LocalSql` 経路(re-home 済 write tools の lookup + run_sql 復号 overlay + #330 feedback path)もカバー必須**。

## 由来

汎用評価層(n_01KT3C0Q…)の α grounding を「どこに保存するか」が、quacker の log 方針一般化に発展したもの。capture(どう取るか)= n_01KT3TXAZ…、本 note = store/framework(どこに置くか)。

replies