The atom of every grid problem: neighbours are computed, never stored, and the four-direction loop and the in-bounds guard are one unit. It also carries the smallest trap in the syllabus — when the new colour already equals the old one, the recursion has nothing left to change, so nothing ever stops it.
image[r][c] = newColor is the ONLY cycle breaker. If newColor == oldColor, the cell never changes and neighbors loop infinitely into StackOverflowError!
"The graph is implicit: edges are computed dynamically with DIRS = [[1,0],[-1,0],[0,1],[0,-1]] and bounds checked on each frame."
"If image[sr][sc] == newColor, we must return immediately. Because repainting acts as the visited mark, if newColor equals oldColor, the cells never change and neighbors ping-pong into StackOverflowError!"
"We repaint image[r][c] = newColor before recursing. While Down executes, the parent sits suspended on the stack waiting for Down to unwind."
"Time is O(m · n) as each connected cell is repainted once. Auxiliary space is governed by maximum Call Stack depth: O(m · n) in the worst-case snake component."
== old test next time, so when new == old nothing is ever marked. Any cell with a same-colour neighbour then bounces between the two forever — an isolated cell is the one case that still terminates, which is why the bug can pass a careless test.