active: true
derived: false
groups:
- CACHE
header: |
  cached_run 実装
level: 2.2
links:
- SPEC002: zhXSv1MBui7ien0r07Hqoub6YJCAaeTioJ9DFsmJjYE=
normative: true
ref: ''
references:
- path: src/beautyspot/core.py
  type: file
reviewed: CfXgvR_Nsv72OUCaCvSww7Jhy_LncbZmN_1x_GRjzjc=
text: |
  ## 実装概要

  `Spot.cached_run()` はコンテキストマネージャとして実装。
  渡された関数群を内部で `mark()` と同等のラッピングを行い、
  コンテキスト内で呼び出すとキャッシュが効く一時的なラッパーを返す。

  ## 設計判断

  ### スマートリターンの型分岐

  単一関数の場合は結果を直接返し、複数関数の場合はタプルで返す。
  これにより `wrapped_fn = spot.cached_run(fn)` のように自然に書ける。
  0個の場合は `ValidationError` で早期失敗させる。

  ### コンテキストマネージャパターン

  `@contextmanager` デコレータを使用。`__enter__` でラップ済み関数を返し、
  `__exit__` で後処理（drain 等）は `with spot:` に委譲する設計。

  ## 実装メモ

  - 型推論（pyright/mypy）で戻り値型が正しく推論されるよう、`@overload` を使用している
  - 外部ライブラリ関数のラッピングでは `functools.wraps` が元関数に適用される
