Status: Completed
Scope: Phase 253 (`--profile quick` 回帰: mutable-acc-spec / accumulator 判定の改善)
Related:
- docs/development/current/main/10-Now.md
- docs/development/current/main/phases/phase-252/README.md

# Phase 253: `json_lint_vm` 回帰（mutable-acc-spec）

## 現象（最初の FAIL）

`./tools/smokes/v2/run.sh --profile quick` が `json_lint_vm` で失敗する。

エラー:

```
[ERROR] ❌ MIR compilation error: [joinir/mutable-acc-spec] Assignment form not accumulator pattern (required: target = target + x)
```

## 背景（なぜここで落ちるか）

`Pattern2` の pipeline は、ループ本体の代入から「mutable accumulator（`x = x + y`）」を検出して
最適化/簡略化に利用する。ところが現在の analyzer が Fail-Fast すぎて、
“accumulator ではない単なる代入” を見つけた時点で Err にしてしまい、JoinIR 経路全体を落としている。

対象 SSOT:
- `src/mir/loop_pattern_detection/mutable_accumulator_analyzer.rs`

## 方針（構造的に直す）

### 原則

- “accumulator pattern を検出できた時だけ” spec を返す。
- それ以外は Err ではなく `Ok(None)` に戻して **別経路（通常 lowering）へ譲る**。
- 例外として、本当に矛盾があるケースだけ Err（例: 同一変数への複数代入など、既に `Ok(None)` にしている）。

### 対処療法の禁止

- 特定関数名（`StringUtils.*`）や特定 script 名（`json_lint_vm`）で分岐しない。
- “`-` の時だけ” のような場当たりでなく、spec と契約として整理する。

## 実装タスク（P0）

### 1) Analyzer の振る舞いを “検出器” に寄せる

ファイル:
- `src/mir/loop_pattern_detection/mutable_accumulator_analyzer.rs`

変更案:
- 以下のケースを `Err` ではなく `Ok(None)` に変更する（= accumulator ではないと判断する）
  - `value_node` が `BinaryOp` ではない（例: `i = s.length() - 1`）
  - `BinaryOperator` が `Add` 以外（例: `i = i - 1`）
  - 左辺が `target` と一致しない（例: `x = y + x`）
  - RHS が Literal/Variable 以外（例: `x = x + (i + 1)`）

目的:
- “accumulator っぽくない代入” が混ざる loop でも、JoinIR 全体を落とさずに進める。

### 2) `-`（decrement）を accumulator として扱うかの設計を決める（P1 で可）

選択肢:
- A) `i = i - 1` は “accumulator としては未対応” なので `Ok(None)`（安全・最小）
- B) `i = i - 1` を “step=-1” として spec に載せる（将来の表現力は上がるが、下流の取り扱い整備が必要）

まずは quick を緑に戻す目的で A を推奨。

## テスト（仕様固定）

- unit tests を追加して「非 accumulator 代入があっても Err にならず `Ok(None)`」を固定する。
  - 例: ループ body に `local i = s.length() - 1` 相当の Assignment があるケース
  - 例: `i = i - 1` があるケース

## 受け入れ基準

- `./tools/smokes/v2/run.sh --profile quick` が PASS
- “たまたま `json_lint_vm` だけ通す” ための by-name 分岐を追加していない
- analyzer の戻り値契約が docs と tests で固定されている

## 結果（Phase 253 終点）

- `mutable_accumulator_analyzer` は “検出器” として振る舞うようになり、非 accumulator 代入で Err を出さず `Ok(None)` に譲る。
- quick の最初の FAIL は次に切り出し（Phase 254）:
  - `[joinir/freeze] Loop lowering failed: JoinIR does not support this pattern`
  - Function: `StringUtils.index_of/2`
