lifecycle: guard Simulation.stream after a failed jet update; scope docs

A set_jet_amplitude failure while creating the internal stream marked the
Simulation failed, but the public stream property still retried
cuda.Stream(). Guard it like the other device-touching methods and add a
regression test (no retry, close still retryable). Lifecycle wording now
names the guarded device-touching methods; cached readers and host staging
stay callable. compatibility.md records the caller-visible fail-closed change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-10-28 00:23:56 +00:00
1 parent 11cbf1194f
commit ddc4a1a6c4
4 files changed
+46 -4

No files matched your search

+5 -3
View File
@@ -90,6 +90,7 @@ class Simulation:
@context_bound
def stream(self) -> cuda.Stream:
"""Internal CUDA stream for async DTOH coordination."""
self._require_usable()
if self._stream is None:
self._stream = cuda.Stream()
return self._stream
@@ -174,9 +175,10 @@ class Simulation:
"""Change one jet's signed amplitude; re-uploads per-link velocity only.
Invalid input raises before any change. Any error after validation
leaves the host amplitude unchanged but the device column undefined,
so the Simulation is marked failed: every later call except close()
raises; close and recreate it.
(stream creation or upload) leaves the host amplitude unchanged but the
device column undefined, so the Simulation is marked failed: every later
device-touching public method (incl. ``stream``) raises; close() still
works. Close and recreate it.
"""
self._require_usable()
jet = self.bodies.jets[index].with_amplitude(amplitude)