- **`NewSetting` のTalk/Whisperブロック重複**(`model/setting.go:53-207`): 約70行×2のほぼ同一コード。`newTalkSetting(cfg)` ヘルパーで約120行削減可能。`json:",inline"` は encoding/json のオプションではなく、空タグ名のフォールバックで動いているだけなので通常の埋め込みに変更 - **`RemainCountMap *map[Agent]int`**(`model/game_status.go:12-14`): pointer-to-map は不要(mapは参照型でnilで未設定を表現できる)。全参照箇所の `(*...)[...]` が不要になる - **手書き `MarshalJSON` の重複**: `model/info.go` / `model/setting.go:196-207` / `model/match_weight.go:40-53` は構造体キーmap→文字列キーmapの変換のためだけに存在。`Role` に `encoding.TextMarshaler` を実装すれば削除できる - **`CreateAgents*` 4変種の重複**(`util/game_util.go:58-118`): 役職コピー/シャッフル/ループの骨組みが重複。プロフィール有無でパラメータ化した2つに統合(#40 のシャッフル修正を1箇所に集約できる) - **`util/auth_util.go` の2関数がコピペ同一**: claims述語だけ差し替えられる `parseToken` に統合 - **ファイル名タイポ**: `util/dynaic_profile_util.go` → `dynamic_profile_util.go`。また JSON schema 名が OpenAI ドキュメント例の `"math_response"` のまま
NewSettingのTalk/Whisperブロック重複(model/setting.go:53-207): 約70行×2のほぼ同一コード。newTalkSetting(cfg)ヘルパーで約120行削減可能。json:",inline"は encoding/json のオプションではなく、空タグ名のフォールバックで動いているだけなので通常の埋め込みに変更RemainCountMap *map[Agent]int(model/game_status.go:12-14): pointer-to-map は不要(mapは参照型でnilで未設定を表現できる)。全参照箇所の(*...)[...]が不要になるMarshalJSONの重複:model/info.go/model/setting.go:196-207/model/match_weight.go:40-53は構造体キーmap→文字列キーmapの変換のためだけに存在。Roleにencoding.TextMarshalerを実装すれば削除できるCreateAgents*4変種の重複(util/game_util.go:58-118): 役職コピー/シャッフル/ループの骨組みが重複。プロフィール有無でパラメータ化した2つに統合(assignRole がmapイテレーション順に依存し、役職割り当てが一様でない #40 のシャッフル修正を1箇所に集約できる)util/auth_util.goの2関数がコピペ同一: claims述語だけ差し替えられるparseTokenに統合util/dynaic_profile_util.go→dynamic_profile_util.go。また JSON schema 名が OpenAI ドキュメント例の"math_response"のまま