sound: constructor ordering, tab lookup by name, and a sync-probe crash fix - #833
Conversation
Fixes #828 (csg-review nitpicks that also apply to sound): - The channel guard ran after super() had already handed BaseModulePlugin an [undefined] channels array; a throw before super() is legal as long as `this` isn't touched, so move the check above the super() call. - Look up the tab by SOUND_TAB_NAME instead of tabs[0], matching protocol.ts and failing loudly if the tab is ever missing. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
|
@coderabbitai review |
✅ Action performedReview finished.
|
WalkthroughThe sound plugin now validates its required channel before base initialization and resolves the host tab by the exported sound tab name rather than by position. ChangesSound plugin updates
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/bundles/sound/src/index.ts`:
- Around line 412-414: Update the tab lookup boundary in the relevant Sound
initialization method: when `__tabLoader.tabs.find(...)` cannot locate
`SOUND_TAB_NAME`, throw or propagate a clear internal error instead of
returning. Ensure callers such as `init_record()` and `play()` observe the
explicit failure and do not continue with tab-dependent operations or retry
silently.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: d808ed07-3a2e-451c-87d5-3bc479eefea3
📒 Files selected for processing (1)
src/bundles/sound/src/index.ts
…nd-trip closureToWave's sync-fast-path probe assumed closure_call_sync could only fail cleanly, by returning undefined before the closure ever runs. That assumption breaks once a closure's own compiled sync body calls back into a different closure that genuinely needs a host round-trip (for example a student-authored wave transformer closing over one of this module's own wave closures and getting passed to a different module). That inner call has no way to suspend from inside an already-synchronous body, so it throws instead of returning undefined, and the throw was propagating straight out of the probe and crashing the whole sample. Wrapped the probe in a try/catch: any throw is now treated exactly like an undefined result, and the wave falls back to the always-correct async path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CodeRabbit review on this PR: looking the tab up by name instead of position was supposed to fail loudly if the tab is ever missing (per #828), but the lookup still just returned silently, leaving __tabLoaded false and letting callers like play()/init_record() carry on as if the tab had loaded. Throw the same kind of plain internal Error the constructor's channel check uses, for the same reason: this is an unreachable-from-student-code wiring precondition, not a student-facing runtime error. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Summary
Two small, unrelated sound fixes bundled together since both are tiny.
Fixes #828, two low-priority nitpicks found while reviewing csg:
SoundModulePlugin's constructor ran aftersuper(conduit, [soundChannel], evaluator), soBaseModulePluginalready got handed an[undefined]channels array before the check fired. A throw is legal beforesuper()as long asthisisn't touched, so the guard now runs first.__ensureTabLoadedpicked the tab by position (tabs[0]) instead of by name. It now usestabs.find(tab => tab === SOUND_TAB_NAME), matching the existingSOUND_TAB_NAMEexport inprotocol.ts, and fails loudly if the tab is ever missing instead of silently.Also fixes a real crash surfaced while testing csg, related to the same family of issues as py-slang#348/#350 and modules#832:
On py2js only, this threw
<module function>() needs a frontend round-trip and cannot be called from a synchronous module callback, even though the code is completely valid.Root cause:
closureToWave's sync-fast-path probe (inindex.ts) assumedclosure_call_synccould only ever fail cleanly, by returningundefinedbefore the closure runs. That assumption breaks here: the composed Python closure gets a real sync-compiled body from py2js, and that body itself callsw(thesine_waveclosure passed in as an argument), which needs a genuine host round-trip once it's crossed back into student code this way. There's no way to suspend from inside an already-synchronous body, so it throws instead of returningundefined, and that throw was propagating straight out of the probe and crashing the whole sample instead of being treated as "no sync twin available, fall back to async."Fixed by wrapping the probe in a try/catch: any throw during the probe is now treated exactly like an
undefinedresult, and the wave falls back to the always-correct async path.This patches the symptom here in sound so it no longer crashes, but the actual reason
wneeds a round-trip at all in this case is a still-open gap in py-slang:moduleToPythonmarks every module closureasyncOnlyunconditionally, regardless of whether it actually has a.synctwin. py-slang#353 fixes that at the engine level, giving a module closure crossing into student code (likesine_wave's returned wave here) a real synchronous fast path when one is available, instead of an unconditional round-trip. Once #353 merges, this exact doppler-style composition should stop needing the async fallback at all and start getting the sync fast path for free; this PR's catch just makes sure things don't crash in the meantime (and afterward, for any other closure that genuinely can't go sync).Test plan
tsc --noEmitonsrc/bundles/soundshows no new errors from either changeeslinton the changed file is cleanindex.ts'sclosureToWave, matching how prior sync-fast-path fixes in this file (see git history) landed without new tests; no behavior change expected for waves that don't hit this specific nested case