Examples
Input: ([('add_task', 'A'), ('add_task', 'B'), ('add_task', 'C'), ('add_dependency', 'B', 'A'), ('add_dependency', 'C', 'B'), ('fail_task', 'A'), ('get_status', 'A'), ('get_status', 'B'), ('get_status', 'C')],)
Expected Output: ['failed', 'failed', 'failed']
Explanation: B depends on A and C depends on B, so failing A cascades to B and then to C.
Input: ([('add_task', 'A'), ('add_task', 'B'), ('add_task', 'C'), ('add_task', 'D'), ('add_task', 'E'), ('add_dependency', 'B', 'A'), ('add_dependency', 'C', 'A'), ('add_dependency', 'D', 'B'), ('add_dependency', 'D', 'C'), ('add_dependency', 'D', 'C'), ('fail_task', 'A'), ('get_status', 'A'), ('get_status', 'B'), ('get_status', 'C'), ('get_status', 'D'), ('get_status', 'E')],)
Expected Output: ['failed', 'failed', 'failed', 'failed', 'active']
Explanation: D is reachable from A through both B and C, but it should still only be failed once. E is unrelated and stays active.
Input: ([('add_task', 'A'), ('add_task', 'B'), ('add_task', 'C'), ('add_dependency', 'C', 'B'), ('fail_task', 'A'), ('add_dependency', 'B', 'A'), ('get_status', 'A'), ('get_status', 'B'), ('get_status', 'C')],)
Expected Output: ['failed', 'failed', 'failed']
Explanation: A fails first. Later, B is declared to depend on failed A, so B must fail immediately, and C fails because it depends on B.
Input: ([('add_task', 'A'), ('add_task', 'B'), ('add_dependency', 'A', 'B'), ('add_dependency', 'B', 'A'), ('fail_task', 'A'), ('get_status', 'A'), ('get_status', 'B')],)
Expected Output: ['failed', 'failed']
Explanation: The cycle should not cause an infinite loop. Once A fails, B fails too, and already failed tasks are not processed again.
Input: ([('get_status', 'missing')],)
Expected Output: ['not_found']
Explanation: The task was never created or referenced, so its status is not_found.
Input: ([],)
Expected Output: []
Explanation: With no operations, there are no status queries to return.