active: true
derived: false
gherkin: |
  Feature: Retention specification
    Scenario: Parsing retention strings into seconds
      Given a retention string like "7d" or "12h"
      When parse_retention is called
      Then it returns the correct total number of seconds
groups:
- LIFE
header: |
  Retention 仕様
level: 2.17
links:
- ARCH007: CwMzyqNroQBWBsDCle5fnJuThTmWAJnkFAcL_z2OzCs=
normative: true
ref: ''
reviewed: VOdnIs2L4j1i9jlVfeKM7xi4cpM06PVcbM6pElJKPQI=
text: |
  ## インターフェース

  ```python
  def parse_retention(val: Any) -> float | None: ...
  ```

  ## 振る舞い

  ### 文字列パース
  - `"7d"` (7日), `"12h"` (12時間), `"30m"` (30分), `"10s"` (10秒) 形式を秒数に変換する。大文字小文字は区別しない。

  ### 数値・オブジェクト
  - `int`, `float`: 秒数としてそのまま扱う。
  - `timedelta`: `total_seconds()` を取得。
  - `None`: ポリシーに従う（または無期限）を意味する。

  ## パラメータ詳細 (単位)

  | 単位 | 倍率 (秒) | 備考 |
  |---|---|---|
  | `d` | 86400 | 日数 |
  | `h` | 3600 | 時間 |
  | `m` | 60 | 分 |
  | `s` | 1 | 秒 |

  ## エラーハンドリング

  - **不正な形式**: パーサが理解できない形式の場合は `ValidationError` を送出する。
  - **負の値**: 過去の時間は指定できず、`ValidationError` となる。

  ## エッジケース

  - **FOREVER**: 特別な定数 `Retention.FOREVER` (無限大の秒数) を提供し、ポリシーに関わらず永続化を指示できる。

  ## 設計判断

  ユーザーが直感的に理解しやすい文字列（例: '7d', '12h'）で有効期限を指定できるようにし、内部で秒数に正規化して統一的に処理するため。
