Skip to content

fix: stop monkey-patching window.showScreen — listen to the screen events instead#38

Merged
byrongamatos merged 1 commit into
mainfrom
fix/no-showscreen-patch
Jul 12, 2026
Merged

fix: stop monkey-patching window.showScreen — listen to the screen events instead#38
byrongamatos merged 1 commit into
mainfrom
fix/no-showscreen-patch

Conversation

@byrongamatos

@byrongamatos byrongamatos commented Jul 12, 2026

Copy link
Copy Markdown
Collaborator

Refs got-feedBack/feedBack#924.

This plugin wrapped window.showScreen to tear down the stems graph when leaving the player. It was the third wrapper on that one global — and it shipped a bug.

What it broke

core publishes window.showScreen
  → the v3 shell wraps it (carrying the legacy home → v3-songs mapping)
  → THIS wraps it again

Each captures whatever happens to be there at the time — and plugins load asynchronously, so the chain links up in whatever order the race settles. When this wrapper won, the shell's mapping was silently dropped and the library opened on the dead legacy screen.

Testers reported it as "randomly, the library shows the old interface" (got-feedBack/feedBack#923, #924).

Core already emits screen events for exactly this. Listening costs nothing, cannot clobber another plugin, and cannot be clobbered by one.

Three things Codex caught, each a silent no-op

1. Timing. My first cut listened to screen:changed — which fires at the end of showScreen, after core awaits library and provider loads. The old wrapper ran before navigation began. Late teardown means the stems graph keeps playing on a non-player screen, and a slow or failing fetch skips it entirely. Core now emits screen:changing before it does anything.

2. Both events, because of cross-repo ordering. screen:changing is new — today's released host doesn't emit it. Listening only to the new one would mean teardown() never runs on the current host; only to the old one reintroduces the late-teardown problem once the host updates. So: both. Safe by construction — the wrapper this replaces called teardown() on every non-player navigation, so it's already idempotent.

3. Either bus. window.slopsmith is the legacy alias of the same object (core: window.slopsmith = window.feedBack), and the rest of this file reads it. Reading only window.feedBack would attach nothing on a build exposing just the old name.

And a pre-existing bug, found on the way

All three of this file's "bus is late" fallbacks listened for slopsmith:capabilities:ready.

Core dispatches feedBack:capabilities:ready (capabilities.js:1536). The slopsmith: name is the pre-DMCA event, and nothing has emitted it since the rename — so every one of those fallbacks has been dead, and wireLifecycleListeners / installCapabilityParticipant silently never wired whenever the bus was late.

All three now listen for the event that is actually dispatched (keeping the old alias too, harmlessly).

47/47 · Codex 0.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved plugin lifecycle handling when alternate event channels are available.
    • Fixed capability participation setup when the event bus becomes ready late.
    • Improved screen transition handling and ensured cleanup occurs when leaving the player screen.
    • Added fallback behavior to maintain functionality across supported navigation and event configurations.

…ents instead

This wrapped window.showScreen to tear down the stems graph when leaving the player. It was the
THIRD wrapper on that one global, and it shipped a bug.

Core publishes window.showScreen; the v3 shell wrapped it (carrying the legacy home -> v3-songs
mapping); this wrapped it again. Each captured whatever happened to be there AT THE TIME — and
plugins load ASYNCHRONOUSLY, so the chain linked up in whatever order the race settled. When this
wrapper won, the shell's mapping was silently dropped and THE LIBRARY OPENED ON THE DEAD LEGACY
SCREEN. Testers reported it as "randomly, the library shows the old interface"
(got-feedBack/feedBack#923, #924).

Core already emits screen events for exactly this. Listening costs nothing, cannot clobber
another plugin, and cannot be clobbered by one.

━━━ THREE THINGS CODEX CAUGHT, EACH A SILENT NO-OP ━━━

1. TIMING. My first cut listened to screen:changed — which fires at the END of showScreen, after
   core awaits library and provider loads. The old wrapper ran BEFORE navigation began. Late
   teardown means the stems graph keeps playing on a non-player screen, and a slow or failing
   fetch skips it entirely. Core now emits screen:changing before it does anything, and that is
   the event this wants.

2. BOTH EVENTS, because of cross-repo ordering. screen:changing is NEW — today's released host
   does not emit it. Listening only to the new one would mean teardown() NEVER runs on the current
   host. Listening only to the old one reintroduces the late-teardown problem once the host
   updates. So: both. It is safe by construction — the wrapper this replaces called teardown() on
   EVERY non-player navigation, so it is already idempotent.

3. EITHER BUS. window.slopsmith is the legacy alias of the SAME object (core: `window.slopsmith =
   window.feedBack`), and the rest of this file reads it. Reading only window.feedBack would attach
   nothing on a build that exposes just the old name.

━━━ AND A PRE-EXISTING BUG, FOUND ON THE WAY ━━━

All THREE of this file's "bus is late" fallbacks listened for `slopsmith:capabilities:ready`.
Core dispatches `feedBack:capabilities:ready` (capabilities.js:1536). The slopsmith: name is the
PRE-DMCA event and NOTHING has emitted it since the rename — so every one of those fallbacks has
been DEAD, and wireLifecycleListeners / installCapabilityParticipant silently never wired whenever
the bus was late. All three now listen for the event that is actually dispatched (keeping the old
alias too, harmlessly).

47/47, Codex 0.

Refs got-feedBack/feedBack#924

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The stems plugin adds feedBack readiness-event fallbacks, replaces the window.showScreen patch with screen transition listeners, and triggers teardown when navigation leaves the player screen.

Changes

Event-bus lifecycle wiring

Layer / File(s) Summary
Readiness event fallbacks
src/main.js
Lifecycle and capability participant setup now retry on feedBack:capabilities:ready alongside the existing slopsmith event.
Screen navigation teardown
src/main.js
Screen transitions use the available event bus, prefer screen:changing, fall back to screen:changed, and tear down when leaving player.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related issues

  • got-feedBack/feedBack#924 — Replaces the stems plugin’s window.showScreen monkey-patch with screen transition listeners that trigger teardown.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately highlights the main change: replacing the window.showScreen monkey-patch with screen event listeners.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/no-showscreen-patch

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/main.js`:
- Around line 1015-1021: Update wireLifecycleListeners() to resolve the
available event bus before registering lifecycle handlers, matching the
bus-resolution approach used by wireScreenListener(). Use that resolved bus for
every subscription instead of requiring window.slopsmith.on, while preserving
the existing lifecycle event handlers and readiness fallback listeners.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 97437c0b-57cb-49f1-94ac-4ef7f5d49f04

📥 Commits

Reviewing files that changed from the base of the PR and between 7940042 and 4b86b32.

📒 Files selected for processing (1)
  • src/main.js

Comment thread src/main.js
Comment on lines +1015 to 1021
// `feedBack:capabilities:ready` is what capabilities.js actually dispatches
// (capabilities.js:1536). The slopsmith: name is the PRE-DMCA event and nothing
// emits it any more — so this fallback has been DEAD since the rename, and the
// lifecycle listeners silently never wired when the bus was late. Keep the old
// alias too, harmlessly, for an older capabilities build.
window.addEventListener('feedBack:capabilities:ready', wireLifecycleListeners, { once: true });
window.addEventListener('slopsmith:capabilities:ready', wireLifecycleListeners, { once: true });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use the resolved bus for lifecycle subscriptions.

This retry wakes on feedBack, but wireLifecycleListeners() still requires and calls window.slopsmith.on. On a feedBack-only host, lifecycle handlers never subscribe, so stem initialization and teardown on playback events stop working. Mirror wireScreenListener() by resolving one bus and using it for every subscription.

Proposed fix
 const wireLifecycleListeners = () => {
-    if (!(window.slopsmith && typeof window.slopsmith.on === 'function')) {
+    const bus = window.feedBack || window.slopsmith;
+    if (!(bus && typeof bus.on === 'function')) {
         window.addEventListener('feedBack:capabilities:ready', wireLifecycleListeners, { once: true });
         window.addEventListener('slopsmith:capabilities:ready', wireLifecycleListeners, { once: true });
         return;
     }
-    window.slopsmith.on('song:loading', onLoading);
-    window.slopsmith.on('playback:loading', onLoading);
-    window.slopsmith.on('playback:ready', onReady);
-    window.slopsmith.on('song:loaded', onReady);
-    window.slopsmith.on('song:ready', onReady);
-    window.slopsmith.on('playback:stopped', onStopped);
-    window.slopsmith.on('playback:ended', onFinished);
+    bus.on('song:loading', onLoading);
+    bus.on('playback:loading', onLoading);
+    bus.on('playback:ready', onReady);
+    bus.on('song:loaded', onReady);
+    bus.on('song:ready', onReady);
+    bus.on('playback:stopped', onStopped);
+    bus.on('playback:ended', onFinished);
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// `feedBack:capabilities:ready` is what capabilities.js actually dispatches
// (capabilities.js:1536). The slopsmith: name is the PRE-DMCA event and nothing
// emits it any more — so this fallback has been DEAD since the rename, and the
// lifecycle listeners silently never wired when the bus was late. Keep the old
// alias too, harmlessly, for an older capabilities build.
window.addEventListener('feedBack:capabilities:ready', wireLifecycleListeners, { once: true });
window.addEventListener('slopsmith:capabilities:ready', wireLifecycleListeners, { once: true });
// `feedBack:capabilities:ready` is what capabilities.js actually dispatches
// (capabilities.js:1536). The slopsmith: name is the PRE-DMCA event and nothing
// emits it any more — so this fallback has been DEAD since the rename, and the
// lifecycle listeners silently never wired when the bus was late. Keep the old
// alias too, harmlessly, for an older capabilities build.
const bus = window.feedBack || window.slopsmith;
if (!(bus && typeof bus.on === 'function')) {
window.addEventListener('feedBack:capabilities:ready', wireLifecycleListeners, { once: true });
window.addEventListener('slopsmith:capabilities:ready', wireLifecycleListeners, { once: true });
return;
}
bus.on('song:loading', onLoading);
bus.on('playback:loading', onLoading);
bus.on('playback:ready', onReady);
bus.on('song:loaded', onReady);
bus.on('song:ready', onReady);
bus.on('playback:stopped', onStopped);
bus.on('playback:ended', onFinished);
🤖 Prompt for 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.

In `@src/main.js` around lines 1015 - 1021, Update wireLifecycleListeners() to
resolve the available event bus before registering lifecycle handlers, matching
the bus-resolution approach used by wireScreenListener(). Use that resolved bus
for every subscription instead of requiring window.slopsmith.on, while
preserving the existing lifecycle event handlers and readiness fallback
listeners.

@byrongamatos
byrongamatos merged commit 36293d6 into main Jul 12, 2026
3 of 4 checks passed
@byrongamatos
byrongamatos deleted the fix/no-showscreen-patch branch July 12, 2026 14:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant