[design] 汎用評価層 ── CLI 統計 + エージェント活動を合成した grounding 基盤

quacker-credit / quacker-aside の「評価プロセスを客観化できるか」から出発して、評価プロセス自体の抽象に到達した設計メモ(2026-06-02、user と alignment 済 / 実装前)。文体 micro-feedback loop(1 例目)・コード品質コーパス loop(2 例目)の上位抽象にあたる。

## 問い

CLI client の usage 統計(`<usage>`)+ エージェントの活動情報(transcript の tool-call trace)を合成して、**汎用的な評価層**を作れるか。

## 抽象 ── 評価プロセス = 信頼を作る手の menu + precondition gate

評価プロセスは subject を trusted verdict に変換するもので、設計の中身は「verdict の信頼をどう作るか」に尽きる。信頼を作る手は独立に積めて、各手が 1 つの failure mode を潰す代わりに 1 つの precondition を要求する:

- 採点者を作業者から分離(A)→ 潰す: self-stake バイアス / 要: 作業トレースの外部化
- 採点者を分布ごと変える(別モデル / 人間)→ 潰す: 相関 prior / 要: 別 rater
- rubric 固定 → 潰す: 採点者間の非互換 / 要: 事前の基準言語化
- trace に grounding → 潰す: judge が現場に居ない / 要: 消費トレース(B1)
- machine アンカー(usage / retrieval ログ)→ 潰す: vibes / 要: 機械観測点
- 多数集計(頻度)→ 潰す: 単一観測ノイズ / 要: 観測の蓄積
- hold-out → 潰す: 過適合 / 要: **subject の再実行可能性**
- pre-registration → 潰す: ゴールポスト移動 / 要: 事前固定

**「客観化」は二値でなく、この menu のどこまで積むか。** 既存の各仕掛けは部分集合 ── mizchi の prompt-tuning ≈ フルスタック、credit(現状)≈ 自己採点 + 集計、aside ≈ 人間 rater + ゲート。aside / credit が非対称に見えたのは menu 上の位置が違うから(aside は人間評価者の隅、credit は自己/AI 評価者でゲート無し)。

## 境界 ── 汎用化するのは grounding 基盤だけ

- grounding 基盤(stats + activity)= content 非依存 → 汎用化が安全・正しい
- verdict(rubric / 何を「効いた」とするか)= content 依存 → per-process のまま

汎用評価層 = 前者。verdict は各 process が持つ(後者を汎用化すると実例 0 で型を切る procrustean に陥る)。

## 構造(α / β)

- **α(基盤)**: run ごとに `(stats, activity_trace, produced_artifacts)` を正規化した queryable な record。
  - `stats`: tool_uses / duration / tokens / web tool 回数(= `<usage>`)
  - `activity`: tool-call 列。派生 index に `posts_read`(run_sql 結果の post id)/ `files_touched` / `artifacts`
- **β(評価エンジン、interface まで)**: `evaluate(run_record, config) → verdict[]`。
  - config = menu の各手 ── `subject_extractor` / `evidence_selector` / `rubric` / `judge`(self | fresh_subagent | machine_threshold)/ `machine_anchors` / `aggregation`
  - verdict = `{subject, label, rationale, evidence_refs, judge_id, run_id}`
- **credit が 1 例目 consumer**。β のフル machinery は credit path のみ実装、他 config(prompt-tuning / 文体)は「その config 型で表現できる」interface 検証のみ(= β を overbuild しない境界)。

## 確定した設計判断(credit)

- **D1** subject = (session, post) ペア
- **D2** trace 源 = 作業セッションの transcript を後追い parse(D2-b、自己申告でなく機械)
- **D3** 評価者 = fresh Task subagent(self-stake バイアス除去)
- **D5** verdict の住所 = flat `useful` tag に収まらない(`{judge_id, evidence_refs, run_id}` を持つ)→ **`post_used` 相当の first-class event に graduate**(tag は presence 投影のみ担う)。β を描いたから確定した。
- **refinement** = 「query 結果に出現 = 引いた」は necessary だが broad(scan 1 発で多数)。**出現 kind(targeted fetch vs broad scan、行位置)で重み付け**を β に持たせる(SQL 形 + row 数で機械判別可)

## feasibility = GREEN(既存 transcript の後追い parse で建つ)

`~/.claude/projects/<proj>/<session>.jsonl` を実地検査して確認:

- `stats`: assistant message ごとに `.message.usage` に full(input / output / cache tokens、web_search / web_fetch 回数、service_tier、speed)
- run_sql 入力 SQL: `.input.sql` に full 保持
- run_sql tool_result: full 保持(最大 35KB の結果も無切り、truncation sentinel 0 件)、結果行に post id(ULID)が出る
- 規模感: 1 session で run_sql 4 回 → distinct post id 34(backlog scan が一発で多数返す = 出現 kind 重み付けの根拠)
- → **新規 runtime hook 不要**。mizchi の「監視を建てず戻り値 / 記録から拾う」がそのまま成立。ただし `<usage>` 件数だけでは「どの post か」に届かないので活動 trace 側が必須。

## 次

- D5: verdict event(`post_used` 相当)の schema を切る
- α extractor の発火点(session 末に transcript→run_record。Stop hook? 後追いバッチ?)
- 消費(useful 頻度で優先 retrieval / 剪定)は従来どおり別途(開ループのまま)

## A / B 整理(過程の要点)

- 「採点者分離(A)」は B を完全には切らない ── A は B の前半(消費トレース記録 = B1)を前提として引き込む。トレース無しの分離評価者は corpus 関連度の推測 = quacker-suggest に潰れる。A が外せるのは B 後半(影響の機械計測)だけで、そこは judge の判定に残せる。
- machine アンカーに寄せるほど「Claude 同士の相関 prior」に依らなくなる ── A の judge を信用可能にするのが B の役目。A と B は択一でなく積む。