turbo-tasks-backend: treat reads and connects of collected tasks as errors (#99646)
### What?
- Reading a cell or output of a task that no longer exists returns an
ordinary error instead of panicking. That covers a task collected by GC,
whether still soft-deleted in memory or already evicted.
`lock_task_and_optional_reader` opens the target with `AllowMissing` and
returns before any dependency edge is added.
- `connect_task` skips the connect when the task no longer exists. The
output read that follows then fails with the same error.
- `MustExist` stays everywhere in edge maintenance (cleanup,
aggregation, `task_pair`), where a missing task means a GC bug.
### Why?
GC does not keep a cell producer alive for its dependents, so a stale
task can hold a collected task's `Vc` in its **arguments**. Such a task
is in a "dead but doesn't know it yet" state but it still may be
optimistically executed, so these errors are expected in 'eventual
consistency cases'.
`connect_task` had a worse version. An `OperationVc` held without a pin
can name a collected task. Connecting it from outside any task (a
top-level `run`, as NAPI code would) materialized a blank entry,
scheduled it, and its execution panicked outside the per-task panic
boundary, aborting the process. This is considered a bug, the caller
should have added a 'pin' but in the mean time we can regularize the
failure mode.
### How?
New tests in `tests/gc_cross_session.rs`:
- `reading_a_collected_task_is_an_error`: a reader holds the collected
target in its arguments and re-executes.
- `connecting_a_soft_deleted_operation_is_an_error` and
`connecting_an_evicted_collected_operation_is_an_error`: a task holds an
`OperationVc` it never connected, and connects it after the operation is
collected.
- `parentless_connect_of_an_evicted_operation_does_not_abort`: also
asserts no entry is materialized.