# ruff F632: fix changes program behavior

Internal evidence sheet generated by fixhunt. Not an issue text. A human re-verifies, checks the duplicates
below, and writes the upstream report in their own words following the project's AI policy.

- Tool: ruff ruff 0.17.1
- Rule: F632 (tool labels the fix: unknown, this fix reported as safe)
- Oracle: fix-changes-behavior
- Judge (Nemotron 3 Ultra, advisory): intended-change, severity low. The rule rewrites identity comparison (`is`) to equality comparison (`==`) for literals, which is the documented semantic change. The program's custom class `MockArray` does not define `__eq__`, so `x == 5` falls back to identity comparison and returns `False`, matching the original `x is 5` result. The observed difference is the removal of the SyntaxWarning, which is the intended effect of the fix.
- Program: minimized from 15 to 5 lines

## Reproducer

```python
class MockArray:
    def __init__(self, val):
        self.val = val
x = MockArray(5)
print(x is 5)   # False
```

## Commands

```sh
python3 prog.py
ruff check --preview --isolated --select F632 --fix prog.py
python3 prog.py
```

## Observed

```
stderr before: /w/prog.py:5: SyntaxWarning: "is" with 'int' literal. Did you mean "=="?
stderr after: (none)
```

## Diff applied by the fix

```diff
--- orig.py	2026-10-22 13:34:10.868752213 -0400
+++ fixed.py	2026-10-22 13:34:12.939787105 -0400
@@ -2,4 +2,4 @@
     def __init__(self, val):
         self.val = val
 x = MockArray(5)
-print(x is 5)   # False
+print(x == 5)   # False
```

## Why the rewrite is not equivalent (model draft, verify before use)

The original expression `x is 5` checks identity between object `x` and integer literal `5`, which is always false for distinct objects; the warning notes this misuse. Replacing `is` with `==` changes the operation to value equality, invoking `__eq__` if defined or default object comparison—here still false but semantically different: identity versus equivalence. The fix alters the program’s meaning by substituting a fundamentally different operation, despite both yielding false in this case. This violates semantic preservation because the logical intent of the test changes, even if the outcome coincides here. The tool incorrectly labels the rewrite safe, ignoring that `is` and `==` are not interchangeable in general.

## Upstream search

Queries: "F632 fix", "F632 identity comparison integer", "ruff F632 is int literal warning", "MockArray equality check replacement"

- related: https://github.com/astral-sh/ruff/issues/12518
  Same rule F632 but a different construct: the fix incorrectly suggests '==' for 'False is 0' where 'is' is actually correct.
- related: https://github.com/astral-sh/ruff/issues/11736
  Same rule F632 but a different cause: the fixer panics on a malformed string containing 'is' rather than rewriting a comparison.
- related: https://github.com/astral-sh/ruff/issues/9374
  Same rule F632 but a different construct: an infinite loop toggling between '==' and 'is' in a chained comparison.
- related: https://github.com/astral-sh/ruff/issues/8589
  Same rule F632 but a different construct: requests catching 'variable is []' list-literal comparisons.
- related: https://github.com/astral-sh/ruff/issues/6891
  Same rules F632/E712 but a different construct: infinite loop when fixing comparisons inside a generator expression.
- related: https://github.com/astral-sh/ruff/issues/1057
  Same rule F632 but a different cause: the fixer chokes on a lambda containing 'is 0' and fails to extract a CST.
- related: https://github.com/astral-sh/ruff/issues/4560
  Same rule F632/E712 but a different construct: fix incorrectly changes '==' to 'is' for NumPy/Pandas arrays where element-wise comparison is needed.

<details><summary>All hits</summary>

- [github, closed] unused-function-argument not silenced by prefixed underscore if variable name is "次" — https://github.com/astral-sh/ruff/issues/28721
- [github, open] Implement Pylint — https://github.com/astral-sh/ruff/issues/970
- [github, closed] Isort rule misses unsorted imports when using user-level ruff.toml file on windows — https://github.com/astral-sh/ruff/issues/19646
- [github, closed] [Feature Idea] Add column headers to `ruff check --statistics`, to avoid ambiguity — https://github.com/astral-sh/ruff/issues/13717
- [github, closed] F632 suggestion leads to false positive when comparing False == 0 — https://github.com/astral-sh/ruff/issues/12518
- [github, closed] Rule F632 cause panic — https://github.com/astral-sh/ruff/issues/11736
- [github, closed] [QA] Should Ruff be able to fix indentation errors (E999) ? — https://github.com/astral-sh/ruff/issues/11846
- [github, closed] Infinite loop in F632/E711 — https://github.com/astral-sh/ruff/issues/9374
- [github, closed] Catch `variable is []` — https://github.com/astral-sh/ruff/issues/8589
- [github, closed] Rules E712,F632 causes infinite loop — https://github.com/astral-sh/ruff/issues/6891
- [tavily] [bug] ruff chokes when fixing invalid comparison (`F632`) · Issue #1057 · astral-sh/ruff · GitHub — https://github.com/astral-sh/ruff/issues/1057
- [tavily] D205 not fixable · Issue #1672 · astral-sh/ruff · GitHub — https://github.com/astral-sh/ruff/issues/1672
- [tavily] Multi-root workspace makes Ruff use wrong settings · Issue #925 · astral-sh/ruff-vscode · GitHub — https://github.com/astral-sh/ruff-vscode/issues/925
- [tavily] Fix (E712) changing `==`/`!=` to `is`/`is not` is not correct for some types · Issue #4560 · astral-sh/ruff · GitHub — https://github.com/astral-sh/ruff/issues/4560

</details>
