# ADR-0017: 局所可変状態 (`let mut`) とスコープ付き `Ref[T]`

- Date: 2026-02-21
- Status: partially-implemented
  - `let mut`: **実装済み** (項目 1)
  - `Ref[T]`: **abandoned** — ADR-0021 の Effect Handler で設計意図を代替
  - 軽量 effect 区分 (`pure`/`state_local`/`impure`): **未実装** — ADR-0003 拡張として再検討

## Context

vibe はコンテンツアドレス（Unison/Nix 型）を前提にしており、同一入力から同一
結果を得る決定性を壊さないことが重要である（ADR-0004）。

一方で実装上はループ・集約・バッファ操作などで `let mut` を多用したく、局所的な
可変状態を完全禁止すると実用性が落ちる。

懸念は次の2点:

1. 参照が関数値/クロージャ経由でスコープ外へ逃げると、評価順や実行形態に依存した
   非決定性が入りやすい
2. Rust 級の所有権/線形型を全面導入すると、実装コストと学習コストが高い

## Decision

段階導入で次を採用する。

1. **`let mut` は局所状態として許可（採用）**
   - `let mut` は「外部観測可能な副作用」ではなく、同期ブロック内で完結する
     局所更新として扱う
   - ユーザー向けの局所可変状態モデルは `let mut` を主軸とする
   - 変数はレキシカルスコープ内でのみ再代入可能
   - `await` / `spawn` をまたいで live のまま保持することを禁止
   - 非同期クロージャへの捕捉は禁止（値スナップショットを要求）

2. **`Ref[T]` を no-escape 制約付きで導入（採用）**
   - `Ref[T]` はスコープ内でのみ有効な capability として扱う
   - Phase 1 では `Ref[T]` をユーザー向けの汎用可変APIとしては推奨しない
   - `Ref[T]` の return / export / 永続格納（外側変数・グローバル・データ構造への保存）
     を禁止
   - `Ref[T]` の `await` / `spawn` 越し利用を禁止
   - 高階関数への受け渡しは「同一スコープ内で同期的に実行が確定する」場合のみ許可
   - （Phase 1 実装）`Ref[T]` を関数引数位置に宣言すること自体を禁止する
   - （Phase 1 実装）同期実行保証の静的証明が未実装のため、`Ref[T]` の関数引数受け渡しは
     保守的に一律禁止する

3. **軽量 effect 区分を追加（可能な範囲で併走採用）**
   - `pure`: 外部副作用なし、局所可変なし
   - `state_local`: `let mut` / no-escape `Ref[T]` のみ
   - `impure`: I/O, shell, 時刻, 乱数など外部観測可能な副作用
   - content-address の同一性は `pure` と `state_local` を決定的として扱う。
     既存の effect-set / `do` 境界の強制対象は `impure` を中心に維持する

## Consequences

良い面:
- Rust 級所有権なしでも、非決定性の主要因（参照エスケープ）を抑止できる
- `let mut` を実践的に使えるため、記述性と実行効率を両立しやすい
- content-address 前提と整合し、ハッシュ安定性を保ちやすい

悪い面/トレードオフ:
- `Ref[T]` を跨ぐ API 設計に制約がかかり、汎用ライブラリ実装で一部不便になる
- no-escape 検査と async 境界検査を型検査器に追加する実装コストが増える
- effect 区分の導入初期は、診断メッセージや仕様文書の移行コストが発生する
