In `.open_channel_from()`, when the `trio`-side parent task exits, it
signals the running `asyncio`-side task with `TrioTaskExited`; this is
our internal exit signal to any still-running `asyncio` task. When the
`asyncio`-side raises the issued signal, previously
`translate_aio_errors()` let it escape despite
`suppress_graceful_exits=True`, (in `piker`'s case) turning an expected
(and cached via `.trionics.maybe_open_context`) channel teardown into
a (quote-feed) task-restart failure.
Now if that task raises the same signal, `translate_aio_errors()`
suppresses it when `suppress_graceful_exits=True`, while preserving any
original `trio`-side error. There are two cooperating fixes:
1. `translate_aio_errors()` returns early without raising that TTE. This
prevents normal channel teardown from propagating it back up to
the originating task.
2. The `asyncio` done callback `signal_trio_when_done()` now returns
early for that same TTE ack and prevents it from
recancelling the already-unwinding `trio-side` or raising the signal
again as an unhandled callback error.
Deats,
- record the issued `TrioTaskExited` instance in
`LinkedTaskChannel._aio_owner_exit` before signalling the
`asyncio`-side task, retaining the original `trio`-side error
as its cause when present.
- use exception identity (`is`), rather than type, to recognize
that issued signal; a separately raised TTE or another
`asyncio`-side cleanup error retains existing error handling.
- in `translate_aio_errors()`, require the `trio`-side parent
task to have exited before handling the acknowledged signal:
- raise any original `trio_err` first, without making its own
exit signal its cause and creating an exception-cause cycle;
- OW return early under `suppress_graceful_exits=True`;
- with suppression disabled, raise the exact issued TTE.
- in `signal_trio_when_done()`, retrieve the task exception but
skip parent-task recancellation and callback error relay when
it is that issued TTE and the `trio`-side has already exited.
- in `wait_on_coro_final_result()`, retain the issued TTE in
`chan._aio_err` for the reporting decision above, logging its
receipt as an exit acknowledgement rather than a task failure.
- retain the actual `maybe_signal_aio_task()` delivery report
for both acknowledgement logs; include the `trio`-side parent
task via `pformat_task()`, its original error/cancellation cause,
and runtime-level diagnostics for each reporting decision.
Update docs/reporting,
- document the signal writer, readers and teardown outcomes;
- retain the actual signalling report for both acknowledgements;
- use `pformat_task()` to identify the `trio.Task` in diagnostics;
- distinguish the parent's error from its issued TTE;
- log suppression, strict reporting and `trio`-side-error precedence;
- clarify graceful suppression for cached-channel teardown;
- keep the queue-shutdown TODO beside its existing handler.
Qualification using a separate, uncommitted regression module:
- original matrix 8 failed / 4 passed; candidate matrix 12 passed.
- selected bridge/formatter run: 41 passed / 18 deselected.
- earlier `piker` real-channel integration: 4 passed.
- human reset traces acknowledge owner exit and preserve a quote
`TimeoutError`.
Prompt-IO: ai/prompt-io/20261028T193020Z_b64c89f0_cached_owner.md
(this patch was generated in some part by `opencode` using
`gpt-6.1-sol` (`openai`))