diff --git a/dvc/dependency/param.py b/dvc/dependency/param.py
--- a/dvc/dependency/param.py
+++ b/dvc/dependency/param.py
@@ -125,9 +125,14 @@ def workspace_status(self):
             elif param not in info:
                 st = "new"
             elif actual[param] != info[param]:
-                st = "modified"
+                if (
+                    isinstance(actual[param], tuple)
+                    and list(actual[param]) == info[param]
+                ):
+                    continue
+                else:
+                    st = "modified"
             else:
-                assert actual[param] == info[param]
                 continue
 
             status[str(self)][param] = st

Can reproduce. Taking a look
When serializing the ParamsDependency to the lock file (`dvc.lock`), the tuple gets converted to a list (because `dvc.lock` is in YAML format).

On the subsequent `dvc repro` execution, the value in the params file gets correctly loaded as a tuple but compared against the serialized list (https://github.com/iterative/dvc/blob/main/dvc/dependency/param.py#L127), always reporting it as modified.
diff --git a/tests/unit/dependency/test_params.py b/tests/unit/dependency/test_params.py
--- a/tests/unit/dependency/test_params.py
+++ b/tests/unit/dependency/test_params.py
@@ -207,6 +207,22 @@ def test_read_params_py(tmp_dir, dvc):
     assert dep.read_params() == {"x": 4, "Klass.a": "val1"}
 
 
+def test_params_py_tuple_status(tmp_dir, dvc):
+    """https://github.com/iterative/dvc/issues/8803"""
+    parameters_file = "parameters.py"
+    tmp_dir.gen(parameters_file, "TUPLE = (10, 100)\n")
+    dep = ParamsDependency(Stage(dvc), parameters_file, ["TUPLE"])
+    # lock file uses YAML so the tuple will be loaded as a list
+    dep.fill_values({"TUPLE": [10, 100]})
+    assert dep.status() == {}
+    dep.fill_values({"TUPLE": [11, 100]})
+    assert dep.status() == {"parameters.py": {"TUPLE": "modified"}}
+    dep.fill_values({"TUPLE": [10]})
+    assert dep.status() == {"parameters.py": {"TUPLE": "modified"}}
+    dep.fill_values({"TUPLE": {10: "foo", 100: "bar"}})
+    assert dep.status() == {"parameters.py": {"TUPLE": "modified"}}
+
+
 def test_get_hash_missing_config(dvc):
     dep = ParamsDependency(Stage(dvc), None, ["foo"])
     with pytest.raises(MissingParamsError):

dvc repro: Tuples in parameters are always marked as modified
# Bug Report

<!--
## Issue name

Issue names must follow the pattern `command: description` where the command is the dvc command that you are trying to run. The description should describe the consequence of the bug.

Example: `repro: doesn't detect input changes`
-->

## Description

<!--
A clear and concise description of what the bug is.
-->
When tuples are used in parameters, dvc always marks them as modified.

```sh
dvc status
```
outputs
```yaml
train_model:
  changed deps:
    model/parameters.py:    
      modified: NGRAM_VECTORIZER_RANGE
```

regardless of whether `NGRAM_VECTORIZER_RANGE` has been changed


tests/unit/dependency/test_params.py::test_params_py_tuple_status
tests/unit/dependency/test_params.py::test_loads_params tests/unit/dependency/test_params.py::test_loads_params_without_any_specific_targets tests/unit/dependency/test_params.py::test_params_error[params0] tests/unit/dependency/test_params.py::test_params_error[params1] tests/unit/dependency/test_params.py::test_loadd_from tests/unit/dependency/test_params.py::test_dumpd_with_info tests/unit/dependency/test_params.py::test_dumpd_without_info tests/unit/dependency/test_params.py::test_read_params_nonexistent_file tests/unit/dependency/test_params.py::test_read_params_unsupported_format tests/unit/dependency/test_params.py::test_read_params_nested tests/unit/dependency/test_params.py::test_read_params_default_loader tests/unit/dependency/test_params.py::test_read_params_wrong_suffix tests/unit/dependency/test_params.py::test_read_params_toml tests/unit/dependency/test_params.py::test_read_params_py tests/unit/dependency/test_params.py::test_get_hash_missing_config tests/unit/dependency/test_params.py::test_get_hash_missing_param tests/unit/dependency/test_params.py::test_params_with_false_values[] tests/unit/dependency/test_params.py::test_params_with_false_values[false] tests/unit/dependency/test_params.py::test_params_with_false_values[[]] tests/unit/dependency/test_params.py::test_params_with_false_values[{}] tests/unit/dependency/test_params.py::test_params_with_false_values[null] tests/unit/dependency/test_params.py::test_params_status_without_targets