tractor/ai/prompt-io/20261028T193020Z_b64c89f0_c...

141 lines
6.8 KiB
Markdown
Raw Normal View History

to_asyncio: fix `trio`-side-exit handling 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`))
2026-10-29 21:28:20 +00:00
---
created_at: 2026-10-28T19:30:20Z
generated_by:
harness: opencode
provider: openai
model: openai/gpt-6-astra
git_ref: b64c89f0
scope: code
substantive: true
raw_file: 20261028T193020Z_b64c89f0_cached_owner.raw.md
---
## Prompt and scope
The human authorized investigation in an isolated Tractor worktree
after cherry-picking Piker's original 4af885d9 onto the in-use
e929fdc2 baseline (replay eb0514c3). They asked to verify related
connectivity work, challenged calling this a Tractor regression,
and then said to investigate the issue for real.
The separate worktree is wkt/cached_aio_owner_exit, rooted at
b64c89f05a9fc8ac2878551eb5eda36574ebef6a. Installed environments and
the original Piker ownership patch are preserved. No verified dialog
ID was available, so dialog/worktree association was not recorded.
## Live evidence
On October 28, QQQ backfill hit IB pacing error 162 at 15:02:57.
Farm reset proceeded to recovery messages at 15:02:59--15:03:00.
QQQ and MNQ quote consumers closed their cached owners to restart.
_Cache.run_ctx injected TrioTaskExited into producer tasks 23 and 11.
The exit signal escaped through translate_aio_errors() and the cache
into stream_quotes(), entering PDB and cancelling the daemon tree.
The final root error after debugger continuation still named the
datad.ib TrioTaskExited. Broken pipes, late cancel acknowledgements,
and EMS ContextCancelled groups followed the initial failure. This
is an operational reset failure rather than ordinary SIGINT noise.
The evaluated Piker history already contains socket-disconnect
propagation efa72980 and bounded reset coordination 0846cbd4. Its
missing timer/sampler changes d126302f, c0dae89a and a26e060c do not
alter this bridge exit path. They remain separate integration work.
## Contract and implementation
docs/guide/asyncio.rst already states that the default
suppress_graceful_exits=True absorbs TaskExited signals. A reduced
Tractor-only test reproduces the violation without IB or Piker.
No historical first-bad Tractor commit has been established.
LinkedTaskChannel._aio_owner_exit records the exact object issued
by open_channel_from() at owner exit. The done callback consumes
that echo instead of cancelling its owner and raising it again.
The translator preserves genuine Trio errors, suppresses normal
echoes by default, and reports the same object under explicit policy.
Type-only suppression is deliberately avoided; cleanup errors and
newly constructed TrioTaskExited instances retain propagation.
## Verification
Tractor environment: existing /home/goodboy/repos/tractor/.venv,
pytest 9.1.0, Trio 0.33.0, Greenback 1.2.1, msgspec 0.21.1.
TRACTOR_SPAWN_METHOD and TRACTOR_LOGLEVEL were unset. PYTHONPATH
selected only this worktree. Greenback required the existing Nix
GCC library directory in LD_LIBRARY_PATH; no packages were installed.
Initial development runs exposed two test-environment/harness issues:
successful RPCs left the test actor running until its nursery timed
out, and Greenback could not load libstdc++. Those were corrected
in the test shutdown and process-local environment respectively.
They are not evidence of additional production runtime failures.
- Original pin + corrected new test: 8 failures / 4 passes.
Normal owner exits fail with the echoed signal; strict reporting
also fails its exact-identity assertion. Independent-error controls
pass. Both native and Greenback paths are exercised.
- Fixed new matrix: 12 passes, including overlapping cached users
in distinct Trio tasks, two generations and two RPCs per case.
- New matrix + root infection + selected infected-asyncio tests:
36 passes, 18 deselected, 24 multiprocessing deprecation warnings.
SIGINT and interactive debugger selections were excluded; those
paths are not claimed qualified by this run.
- Frozen Piker e929fdc2 + original 4af885d9 + existing real bridge
reproducer, with the duplicate --ll compatibility removal:
4 passes with candidate Tractor imported via process-local paths.
Both actor survival and strict callback cleanliness now pass.
External IB and VNC inputs in that reproducer are replayed; its
actor, cache, bridge, event delivery and lifetime boundaries are real.
- The human advanced the evaluation worktree during investigation to
sampler_tick_time_guard at 790dc0a51c9d93e77258360f954c959d11d09a7c.
Repeated the same four Piker checks on that exact source tip with
candidate Tractor and the same test-only harness adaptation:
4 passed. Its working tree/index were preserved, and its installed
to_asyncio.py still has the original b64c89f0 blob fingerprint.
The Piker integration used its existing py313 environment and pinned
native dependency paths. Import probes verified both source roots.
Raw baseline/integration output remains in the session scratch files
cached-owner-baseline-final.log and cached-owner-piker-final.log.
The human subsequently reported that a backfill data-connection reset
no longer crashed at the previous owner-exit failure. Supplied live
traces resolve Tractor to this worktree and show both asyncio task
and completion acknowledgements of the issued owner-exit signal.
At 16:29:07, a separate initial IB get_quote() timeout survived proxy
teardown with both owner-exit acknowledgements. After the human
continued PDB at 16:31:40, the chart received that TimeoutError at
16:31:41. IB also reported competing-session error 10197 for MNQ
request 822; its identity with the timed-out request is unverified.
This is bounded live evidence, not complete recovery qualification.
Separate unresolved observations include final-result send_nowait()
raising BrokenResourceError and a callback bookkeeping assertion;
samplerd result delivery on a closed socket; cancellation-only
exception groups relayed as errors on SIGINT; Qt self-SIGINT during
close; and Piker EMS request loss followed by a req=None fill crash.
Sampler timestamp warnings and volume spikes also remain separate.
Live connection, TSDB, VNC, account and order operations were performed
only by the human. The agent misread a request for a commit plan and
created commit 6142d52efc0e5797a240eba0c0b00a24b211fe0e. The human
clarified that review must precede committing and authorized a soft
reset to b64c89f05a9fc8ac2878551eb5eda36574ebef6a. All five files
were preserved staged; the replacement plan is human-executed.
## Files changed
- tractor/to_asyncio.py: exact owner-exit echo classification.
- tests/test_cached_aio_owner_exit.py: real contract regressions.
- docs/guide/asyncio.rst: explain ownership-specific suppression.
- This provenance pair.
## Human edits
The human supplied live failures and teardown traces, required reuse
inspection of connectivity branches, and corrected the distinction
between a contract defect and an established historical regression.
No direct manual edits to this new Tractor worktree were observed.