import hashlib, json, tomllibSHARED_KEYS = {"model", "timeout_s", "max_retries", "gate_thresholds"}def shared_fingerprint(config_path: str) -> str: with open(config_path, "rb") as f: data = tomllib.load(f) # 共有キーだけ抜き出し、順序を正規化してからハッシュ化する shared = {k: data[k] for k in sorted(SHARED_KEYS) if k in data} canonical = json.dumps(shared, sort_keys=True, ensure_ascii=False) return hashlib.sha256(canonical.encode("utf-8")).hexdigest()[:16]
def diff_shared(a_path: str, b_path: str) -> list[str]: def load(p): with open(p, "rb") as f: d = tomllib.load(f) return {k: d.get(k) for k in SHARED_KEYS} a, b = load(a_path), load(b_path) return [f"{k}: {a[k]!r} != {b[k]!r}" for k in SHARED_KEYS if a[k] != b[k]]
照合のタイミングをずらすコツとして、大きなツール更新の直後は臨時で1回多く回すようにしています。Antigravity のようにバージョンが活発に動くツールは、更新で既定値が変わることがあり、そのタイミングがドリフトの入りやすい瞬間だからです。App Store Connect の API キーのように、環境ごとに別管理する値はあえて照合対象から外し、共有すべき値だけに絞ることで、警告のノイズを抑えています。