You put configuration data in a tuple to prevent changes, yet a new item appears in the task list inside it. If tuples are immutable, how did the list change? The distinction is between a slot in the tuple and the list object that slot references.
Why does assigning a tuple item raise TypeError?
After a tuple is created, you cannot assign a different object to one of its item positions. Here, record[0] refers to the list named steps:
steps = ["draft"]
record = (steps, "open")
record[0] = ["reviewed"] # TypeError: 'tuple' object does not support item assignmentReplacing the slot itself with a new list fails. record[1] = "closed" would fail for the same reason. This is the scope of the tuple's immutability.
Why can you append to the list inside it?
Omit the failed assignment and start again with the same steps and record values:
The tuple's reference to the list remains in place. append() changes the list's contents, whereas assigning a new list to record[0] attempts to replace a tuple item.
steps = ["draft"]
record = (steps, "open")
record[0].append("reviewed")
print(record) # (['draft', 'reviewed'], 'open')
print(record[0] is steps) # Truerecord[0] still points to the same list. The list's contents changed, so printing the tuple now looks different even though its items were not reassigned. Calling steps.append() outside the tuple would produce the same visible change because both names reach that list.
Avoid assuming that record[0] += ["approved"] is safe. The in-place operation can append to the list before Python tries to assign the result back into the tuple and raises TypeError. An exception does not mean the list stayed unchanged; the Korean source verified both effects in a separate run.
Does wrapping a list in a tuple freeze the list?
No. A tuple around a list does not make the inner list immutable. If you need a fixed record of its current values, convert the inner list too:
steps = ["draft"]
record = (steps, "open")
snapshot = (tuple(steps), "open")
steps.append("reviewed")
print(record) # (['draft', 'reviewed'], 'open')
print(snapshot) # (('draft',), 'open')snapshot holds a separate tuple of strings as they were at that moment. If an inner item is itself mutable, one tuple() conversion will not freeze every nested object. Decide how deeply the values must remain unchanged.
What about a dictionary key?
A tuple containing a list is unhashable, so it cannot serve as a dictionary key. Being a tuple on the outside is insufficient. A key such as snapshot needs hashable contents all the way down. If later changes to a shared list must not change an earlier record, preserving the values at that moment matters even before you consider using them as a key.
Key takeaways
Tuple immutability prevents reassigning its item positions; it does not freeze a mutable object referenced there. record[0] = ... fails, while record[0].append(...) changes the existing list. For an unchanging record, inspect and copy or convert mutable inner values as needed.

