# instinct: ON CONFLICTありのUPSERTでも主キー重複(xxx_pkey violation)が出たらシーケンスずれを疑う

ON CONFLICT (自然キー) で正しく書かれたUPSERTなのに `xxx_pkey` (主キーid) の UniqueViolationError が出る場合、**ON CONFLICT条件の不備ではなく、idシーケンスが実データのMAX(id)より後ろにずれている**のが原因。新規INSERT時の自動採番が既存idと衝突する。

**Why:** 過去にidを明示指定してINSERTするETL/バックフィル(例: anime `cure_to_shadow_etl.py`)がシーケンスを更新しないと発生する。anime `wiki_anime_master_bot`(id=601)はこれで**7日間取り込みゼロ**(added=0)になっていた(2026-06-07発見・seq last_value=9787 vs MAX(id)=18251)。failed統計に出るだけで静かに止まるので気づきにくい。

**How to apply:**
1. 診断: `SELECT pg_get_serial_sequence('テーブル','id')` でシーケンス名取得 → `SELECT last_value FROM ` と `SELECT MAX(id) FROM テーブル` を比較。last_value <= MAX(id) なら確定
2. 修正: `SELECT setval('', (SELECT MAX(id) FROM テーブル), true)` で同期。**既存データに触れず採番開始点を直すだけの安全な回復操作**(要確認の本番DB書込だが破壊リスク極小)
3. id明示INSERTするETLには、処理後に上記setvalを必ず入れる(根本対策)

関連: [[instinct-group-id-range-hardcode]]・バッチINSERTの重複制約は ON CONFLICT DO NOTHING だけでは不十分(LLM Wiki)。anime DB接続は `bots.lib.db_utils.normalize_dsn` でSQLAlchemy形式(`postgresql+asyncpg`)→asyncpg形式へ変換が必要。

---
(migrated from local memory/instinct_postgres_sequence_drift_after_etl.md)