# ruff TC008: 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: TC008 (tool labels the fix: unknown, this fix reported as safe)
- Oracle: fix-changes-behavior
- Judge (Nemotron 3 Ultra, advisory): real, severity medium. The rule removes quotes from a PEP 613 type alias that uses concatenated string literals ('int' '|' 'None'), rewriting it to the unquoted union int|None. At runtime, the original alias evaluates to the string 'int|None' (no spaces), while the fixed alias evaluates to the types.Union object int | None (repr shows spaces). This changes the program's observable behavior: the printed representation differs, and any code inspecting the alias value would see a string vs a union object. The documentation presents the rewrite as removing unnecessary quotes but does not warn that concatenated string literals produce a different runtime value than the unquoted union, making the fix unsafe for this construct.
- Program: minimized from 4 to 3 lines

## Reproducer

```python
from typing import TypeAlias
BadAlias: TypeAlias = "int" "|" "None"
print(repr(BadAlias))
```

## Commands

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

## Observed

```
stdout before:
'int|None'
stdout after:
int | None
```

## Diff applied by the fix

```diff
--- orig.py	2026-10-22 13:31:25.571973028 -0400
+++ fixed.py	2026-10-22 13:31:27.675008309 -0400
@@ -1,3 +1,3 @@
 from typing import TypeAlias
-BadAlias: TypeAlias = "int" "|" "None"
+BadAlias: TypeAlias = int|None
 print(repr(BadAlias))
```

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

The original string literal `"int" \| \"None\"` evaluates to the exact text `int|None`, which prints as `'int|None'`. Replacing it with the type expression `int|None` creates a union type object whose `__repr__` yields `int | None` (spaces added by Python’s formatting). Since a string and a type are distinct objects with different representations, the change alters observable output, violating semantic equivalence.

## Upstream search

Queries: "TC008 fix", "TC008 TypeAlias string union", "TypeAlias literal pipe syntax", "ruff TC008 quoted types fix"

- no duplicate or related report found among 1 hits

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

- [github, open] [`docs`] Some rule's examples do not trigger out-of-the-box — https://github.com/astral-sh/ruff/issues/18972

</details>
