Examples Before Algorithms
If you cannot say what should happen with a concrete example, you are not ready to implement it. Normal, edge and invalid cases for every operation; predict before running; examples become tests; find the bug from the example.
Cart = [] → add Laptop → [Laptop × 1] → add Laptop → [Laptop × 2] → add Mouse → [Laptop × 2, Mouse × 1]. Four states and three operations, and the algorithm for addItem is already visible in them. If you cannot explain what should happen with a concrete example, you are probably not ready to implement it.
For every operation, three examples: the normal case, the edge case, and the invalid one. addItem: a new product; a product already present; quantity 0. The normal case writes the happy path, the edge case finds the branch, the invalid case fixes where the checks go and proves the state survives rejection.
Before running cart.add("laptop"); cart.add("laptop"); cart.add("mouse"), write what the cart will contain. Then run it. The gap between predicted and actual is where your model of the code is wrong — and a prediction about state, not just about the outcome, tells you which line.
Requirements → examples → expected behaviour → tests. The concept record's tests each name the example they came from: "adding the same product twice increases the quantity" is add-again, encoded. A test that cannot name its example is testing the code's shape, not the cart's behaviour.
"Every addItem call inserts a new row." Before running it, say what happens when the same product is added twice. Duplicate entries — and the missing line is a rule, not a typo. Reading code for the example it would get wrong is how you review a cart you did not write.