Skip to content

feat(editor): pitched GM guide voices + per-kind instrument picker (DAW 1.2/1.5) - #217

Merged
byrongamatos merged 2 commits into
mainfrom
feat/editor-gm-guide
Jul 12, 2026
Merged

feat(editor): pitched GM guide voices + per-kind instrument picker (DAW 1.2/1.5)#217
byrongamatos merged 2 commits into
mainfrom
feat/editor-gm-guide

Conversation

@ChrisBeWithYou

@ChrisBeWithYou ChrisBeWithYou commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

What

The guide can now play the charted notes as a General-MIDI instrument instead of the clap — charting-by-ear finally sounds like music, not just timing. DAW-workspace roadmap items 1.2 (pitched GM guide) and 1.5 (voice picker + defaults), scoped to the guide path.

  • Transport ▸ Guide voice: Clap / Instrument (GM) radio, plus per-part-kind instrument rows (curated FluidR3_GM programs for guitar / bass / keys — drums keep their clap; the drum strip owns drum sounds). Prefs are editor-side, never the pack.
  • Pitch truth is the roll's: pitches come from _rollMidiForNote — keys packing for keys parts, capo-aware sounding pitch for fretted — so the guide can never disagree with what the roll shows. Chord buckets (the clap's 1 ms dedupe resolution) ring up to 4 distinct pitches, each with its own sustain (capped at 1.6 s).
  • The clap is the permanent fallback: while a preset is loading, or no source can serve it, the guide claps — it never goes silent while enabled. A failed chord bucket claps once, not per note. All voices sum through the existing guide bus, so the mixer fader + limiter apply unchanged; no per-frame work, no new listeners/timers (nothing to teardown-register).

Asset sourcing — a chain, not a single origin

Per Christian's call, all three sources are wired, walked in order (editorGmVoiceSource pref: auto / pinned):

  1. plugin/api/plugins/editor/wafont/ serving assets/wafonts/ (the Virtuoso idiom: no runtime CDN dependency once assets are committed). Nothing is vendored in this PR — the route 404s cleanly and the chain moves on. assets/wafonts/README.md pins the provenance contract (FluidR3_GM renders only, mirroring Virtuoso's cleared set and its JCLive removal rationale). Vendoring the actual preset subset is a follow-up — flagging it here for your take on repo/package size.
  2. org — a base-URL editor-pref (editorGmVoiceBase) for when org-hosted WebAudioFont renders exist (e.g. a feedback-soundfonts release; today it hosts .sf2 for the desktop, a different format).
  3. cdn — the upstream WebAudioFont CDN that core's drum_highway_3d and the piano plugin already lazy-load from. Works out of the box.

The /wafont route validates with a whitelist regex (player + FluidR3 grammar only, \Z-anchored) plus a resolved-path containment check — traversal shapes and undocumented-provenance variants never reach the filesystem.

Tests

  • tests/gm_guide.test.mjs — 19 real-import ESM tests: the naming grammar, source order + URL builder (incl. org-base normalization and http(s)-only), kind inference (the start-anchored "Electric Piano is not keys" trap pinned), pref validation (the Number(null)=0 and parseInt('127.5') coercion traps — both caught by these tests during development), window grouping/chord-cap/per-voice sustain, and the Transport-menu rows.
  • tests/test_wafont_route.py — 4 tests: whitelist accepts player + FluidR3 names only; rejects traversal shapes (incl. NUL and trailing-newline), JCLive-class variants, and non-asset names.

Gates: full JS suite 108 files green, ESLint 0 errors (3 warnings = main's ratchet, unchanged), pytest 234 passed (routes.py touched).

Seams

New module + additive edits in audio.js (guide tick) / menu-bar.js (Transport menu) / routes.py; the usual CHANGELOG keep-both. Independent of the open #210/#212/#213/#214/#215/#216.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EBQCHCNA81E9tHmSDHSe2Q

Summary by CodeRabbit

  • New Features
    • Added pitched General-MIDI guide voices for playback, with guitar, bass, and keyboard selections (chart-driven pitches with chord sustain).
    • Added editor menu controls to switch between clap guide and pitched GM guide, including per-part GM instrument selection.
  • Bug Fixes
    • Improved resilience: if pitched voices aren’t ready/available, playback falls back to clap to avoid silence.
  • Documentation
    • Documented the GM guide voice asset chain and supported WebAudioFont files.
  • Chores
    • Added automated coverage for GM guide logic and the WebAudioFont route validation.

…AW 1.2/1.5)

The guide can now sound the charted notes as a General-MIDI instrument
instead of the clap. New src/gm-guide.js owns the voice model and loader;
the scheduler integration rides the existing guide tick, bus, fader and
limiter unchanged.

- Transport menu gains a Guide voice radio (Clap / Instrument (GM)) and
  per-part-kind instrument rows (curated FluidR3_GM programs for guitar /
  bass / keys; drums keep their clap). Prefs are editor-side, never the
  pack. Kind inference mirrors the repo rule (KEYS_PATTERN start-anchored
  > /bass/i > guitar).
- Pitches come from _rollMidiForNote — keys packing for keys parts,
  capo-aware sounding pitch for fretted — so the guide can never disagree
  with the roll. Chord buckets (the clap's 1 ms dedupe resolution) ring up
  to 4 distinct pitches, each with its own sustain (capped 1.6 s).
- The clap is the permanent fallback: while a preset loads (or no source
  serves it) the guide claps, never goes silent; a failed chord bucket
  claps ONCE, not per note.
- Assets lazy-load through a three-rung source chain: plugin-vendored
  (/api/plugins/editor/wafont/, a whitelisted route over assets/wafonts/;
  nothing vendored yet - the README pins the FluidR3-only provenance
  contract, mirroring Virtuoso's) -> org-hosted base URL (editor-pref
  editorGmVoiceBase) -> the upstream WebAudioFont CDN core's
  drum_highway_3d and the piano plugin already use. Pinnable via
  editorGmVoiceSource.
- routes.py: the /wafont route + _safe_wafont_name (whitelist regex, \Z
  anchored so a trailing newline can't slip past $).

tests/gm_guide.test.mjs (19, real-import ESM; suite crashes on main -
module absent): naming grammar, source chain + URL builder, kind
inference, pref validation (incl. the Number-vs-parseInt and
Number(null)=0 coercion traps), window grouping/cap/sustain, menu-model
rows. tests/test_wafont_route.py (4): whitelist accepts player+FluidR3
only, rejects traversal shapes, JCLive-class variants, and non-asset
names.
@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c7a0787e-34e8-49c0-84e8-681c693e131d

📥 Commits

Reviewing files that changed from the base of the PR and between 20be448 and 91499be.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • routes.py
  • src/audio.js
  • src/menu-bar.js

📝 Walkthrough

Walkthrough

Adds pitched General-MIDI guide voices with per-kind instrument selection, lazy-loaded WebAudioFont assets, roll-derived pitch scheduling, clap fallback, editor menu controls, and secure plugin asset serving.

Changes

GM guide voice runtime

Layer / File(s) Summary
GM voice contracts and runtime loading
src/gm-guide.js, tests/gm_guide.test.mjs
Defines GM choices, preference persistence, source fallback ordering, event processing, preset loading, waveform scheduling, and runtime degradation tests.
Pitched guide scheduling
src/audio.js, CHANGELOG.md
Adds GM mode persistence, capo-aware pitched event generation, GM scheduling, cross-tick deduplication, and clap fallback through the existing guide path.
Guide voice menu controls
src/menu-bar.js, tests/gm_guide.test.mjs
Adds Clap/GM controls, per-kind instrument rows, menu context derivation, dispatch handling, and rendering tests.
Secure WebAudioFont asset serving
routes.py, assets/wafonts/README.md, tests/test_wafont_route.py
Documents vendored asset constraints and adds whitelist-validated, path-contained asset serving with traversal and filename-shape tests.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Editor as Editor menu
  participant Audio as Guide scheduler
  participant GM as gm-guide.js
  participant AssetRoute as WebAudioFont asset route
  participant Player as WebAudioFontPlayer
  Editor->>Audio: Select GM guide voice
  Audio->>GM: Ensure selected preset
  GM->>AssetRoute: Request whitelisted asset
  AssetRoute-->>GM: Return JavaScript asset
  GM->>Player: Load preset and queue waveform
  Audio->>Audio: Schedule pitched events or clap fallback
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.27% 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 clearly captures the main editor change: pitched GM guide voices with per-kind instrument selection.
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 feat/editor-gm-guide

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: 2

🧹 Nitpick comments (1)
tests/test_wafont_route.py (1)

12-63: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Cover the route's security behavior, not only the helper.

These tests never exercise get_wafont_asset. Add route-level cases for invalid names → 400, valid-but-absent assets → 404, vendored files → JavaScript responses, and an in-tree symlink resolving outside assets/wafonts → rejection. The containment check is currently verified only by inspection.

🤖 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 `@tests/test_wafont_route.py` around lines 12 - 63, The tests currently cover
only _safe_wafont_name; add route-level tests exercising get_wafont_asset for
invalid names returning 400, valid but missing assets returning 404, existing
vendored files returning JavaScript responses, and an in-tree symlink resolving
outside assets/wafonts being rejected. Use the route’s existing test client and
temporary filesystem setup, and assert the containment check through the HTTP
response rather than inspection alone.
🤖 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 `@routes.py`:
- Around line 82-83: Update _WAFONT_NAME_RE to whitelist only the documented
ASCII filename forms: four-digit melodic names with an optional underscore
suffix, and five-digit percussion names beginning with the 128NN pattern and its
suffix. Replace \d with [0-9] and reject unsupported five-digit melodic names
such as 99999_FluidR3_GM_sf2_file.js; keep the WebAudioFontPlayer.js alternative
intact.

In `@src/gm-guide.js`:
- Around line 211-218: Update the GM preset-loading flow centered on
ensureGmPreset and _presetLoading so each source attempt has a timeout that
clears the stuck loading state and allows the plugin→org→CDN fallback chain to
continue. Add per-program retry backoff after fast failures to prevent repeated
full-chain starts on every guide tick, and reset that backoff after a successful
load or an explicit voice/source change such as editorSetGmVoice.

---

Nitpick comments:
In `@tests/test_wafont_route.py`:
- Around line 12-63: The tests currently cover only _safe_wafont_name; add
route-level tests exercising get_wafont_asset for invalid names returning 400,
valid but missing assets returning 404, existing vendored files returning
JavaScript responses, and an in-tree symlink resolving outside assets/wafonts
being rejected. Use the route’s existing test client and temporary filesystem
setup, and assert the containment check through the HTTP response rather than
inspection alone.
🪄 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: 508b41d9-4412-4b60-b376-aa23ece12acf

📥 Commits

Reviewing files that changed from the base of the PR and between e02a003 and 20be448.

📒 Files selected for processing (8)
  • CHANGELOG.md
  • assets/wafonts/README.md
  • routes.py
  • src/audio.js
  • src/gm-guide.js
  • src/menu-bar.js
  • tests/gm_guide.test.mjs
  • tests/test_wafont_route.py

Comment thread routes.py
Comment on lines +82 to +83
_WAFONT_NAME_RE = re.compile(
r"^(?:WebAudioFontPlayer\.js|\d{4,5}(?:_\d+)?_FluidR3_GM_sf2_file\.js)\Z")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the relevant files and inspect the surrounding code/docs.
git ls-files | rg '(^|/)(routes\.py|README(\.md)?|readme(\.md)?)$'

echo '--- routes.py outline ---'
ast-grep outline routes.py --view expanded || true

echo '--- routes.py relevant lines ---'
nl -ba routes.py | sed -n '1,180p'

echo '--- README mentions ---'
rg -n "WebAudioFontPlayer|FluidR3|128[0-9]{2}|melodic|percussion|NNNN|NNNNN" README.md . -g '!**/.git/**' || true

Repository: got-feedBack/feedBack-plugin-editor

Length of output: 5248


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# If routes.py is not at repo root, locate it and inspect the exact file.
fd -a '^routes\.py$' .

Repository: got-feedBack/feedBack-plugin-editor

Length of output: 202


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for the whitelist grammar and any tests for the route.
rg -n "_WAFONT_NAME_RE|_safe_wafont_name|webaudiofont|FluidR3_GM_sf2_file|WebAudioFontPlayer" . -g '!**/.git/**'

Repository: got-feedBack/feedBack-plugin-editor

Length of output: 4522


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect any nearby tests or fixtures that mention the accepted names.
fd -a 'test|spec' . | sed -n '1,120p'

Repository: got-feedBack/feedBack-plugin-editor

Length of output: 5935


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import re

pat = re.compile(r"^(?:WebAudioFontPlayer\.js|\d{4,5}(?:_\d+)?_FluidR3_GM_sf2_file\.js)\Z")
tests = [
    "1234_FluidR3_GM_sf2_file.js",
    "12345_FluidR3_GM_sf2_file.js",
    "99999_FluidR3_GM_sf2_file.js",
    "12800_1_FluidR3_GM_sf2_file.js",
    "١٢٣٤_FluidR3_GM_sf2_file.js",
]
for s in tests:
    print(s, bool(pat.fullmatch(s)))
PY

echo '--- routes.py ---'
nl -ba routes.py | sed -n '70,95p'

echo '--- README matches ---'
rg -n "WebAudioFontPlayer|FluidR3_GM_sf2_file|melodic|percussion|128[0-9]{2}|NNNN" README.md . -g '!**/.git/**'

Repository: got-feedBack/feedBack-plugin-editor

Length of output: 402


🌐 Web query:

WebAudioFont README melodic NNNN percussion 128NN_N FluidR3_GM_sf2_file.js

💡 Result:

In the WebAudioFont library, the file naming convention relates to the General MIDI (GM) standard, which separates instruments into melodic (programs 0–127) and percussion (often mapped as bank 128) [1][2]. The naming structure NNNN_Name_sf2_file.js typically breaks down as follows: 1. NNNN: Represents the MIDI program/patch number (e.g., 0000 for Acoustic Grand Piano) [3][4]. 2. Name: Indicates the source soundfont used (e.g., FluidR3_GM, GeneralUserGS, JCLive) [3][4][2]. 3. FluidR3_GM_sf2_file.js: This refers to a specific JavaScript-encoded wavetable file derived from the FluidR3_GM soundfont [3][5][1]. Regarding the percussion/melodic distinction and the 128NN_N pattern: - Melodic instruments are cataloged using programs 0–127 [1]. - Percussion is typically handled as a specific set of instruments [1]. In many WebAudioFont-compatible implementations, percussion kits are accessed via bank/program mappings where the bank 128 is used for drums [2]. The notation 128NN_N refers to these percussion drum notes (e.g., MIDI notes 27–81), where 128 signifies the percussion bank and NN_N represents the specific drum sound ID or MIDI note number [2]. The library provides a comprehensive catalog where developers can load these files to perform sample-based synthesis in the browser using the Web Audio API [1][6][7]. Instruments are stored in this standardized format to ensure compatibility across different web applications [6][8].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- routes.py around the whitelist ---'
sed -n '74,92p' /home/jailuser/git/routes.py | cat -n

echo '--- assets/wafonts/README.md relevant lines ---'
sed -n '1,40p' /home/jailuser/git/assets/wafonts/README.md | cat -n

echo '--- tests/test_wafont_route.py relevant lines ---'
sed -n '1,90p' /home/jailuser/git/tests/test_wafont_route.py | cat -n

Repository: got-feedBack/feedBack-plugin-editor

Length of output: 6012


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import re

pat = re.compile(r"^(?:WebAudioFontPlayer\.js|\d{4,5}(?:_\d+)?_FluidR3_GM_sf2_file\.js)\Z")

candidates = [
    "0000_FluidR3_GM_sf2_file.js",
    "0270_FluidR3_GM_sf2_file.js",
    "1270_FluidR3_GM_sf2_file.js",
    "12835_0_FluidR3_GM_sf2_file.js",
    "12800_1_FluidR3_GM_sf2_file.js",
    "99999_FluidR3_GM_sf2_file.js",
    "1234_FluidR3_GM_sf2_file.js",
    "١٢٣٤_FluidR3_GM_sf2_file.js",
]
for s in candidates:
    print(f"{s}: {bool(pat.fullmatch(s))}")
PY

Repository: got-feedBack/feedBack-plugin-editor

Length of output: 452


🌐 Web query:

surikov webaudiofont README file naming 12835_0_FluidR3_GM_sf2_file.js 0270_FluidR3_GM_sf2_file.js

💡 Result:

The file naming convention used in the WebAudioFont library follows a specific pattern designed to identify the MIDI instrument index, the source soundfont, and the file type [1][2]. A typical filename, such as 0270_FluidR3_GM_sf2_file.js, is structured as follows: 1. MIDI Instrument ID (e.g., 0270): The four-digit prefix corresponds to the instrument's MIDI index [1][2]. Note that while standard MIDI uses indices 0-127, WebAudioFont often uses a four-digit format where the first digit may represent a bank or variation [1][3]. 2. Soundfont Name (e.g., FluidR3_GM): This segment identifies the source soundfont library used to generate the wavetable (e.g., FluidR3_GM, GeneralUserGS, Aspirin, SoundBlasterOld) [1][4]. 3. File Type Suffix (e.g., _sf2_file.js): This indicates that the file contains data exported from an SF2 (SoundFont) file, structured as a JavaScript file for use by the WebAudioFont player [1][2]. The variable name inside each JavaScript file typically follows a similar pattern, prefixed with tone to avoid global namespace collisions (e.g., _tone_0270_FluidR3_GM_sf2_file) [1][5][2]. To use these files, you must load the.js file and refer to the specific variable name defined within it to initialize the instrument in your Web Audio API project [1][2].

Citations:


Tighten the filename whitelist

_WAFONT_NAME_RE still admits 5-digit melodic names like 99999_FluidR3_GM_sf2_file.js and Unicode decimal digits via \d. The README and tests only cover ASCII NNNN_... melodic files and 128NN_N_... percussion files, so narrow the regex to those explicit forms or update the docs/tests if the broader set is intentional.

🤖 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 `@routes.py` around lines 82 - 83, Update _WAFONT_NAME_RE to whitelist only the
documented ASCII filename forms: four-digit melodic names with an optional
underscore suffix, and five-digit percussion names beginning with the 128NN
pattern and its suffix. Replace \d with [0-9] and reject unsupported five-digit
melodic names such as 99999_FluidR3_GM_sf2_file.js; keep the
WebAudioFontPlayer.js alternative intact.

Comment thread src/gm-guide.js
Comment on lines +211 to +218
export function editorSetGmVoice(kind, gm) {
const program = _gmVoiceForKindPure(gm, kind);
if (program === null) return;
try { localStorage.setItem('editorGmVoice:' + kind, String(program)); } catch (_) {}
_presetError = ''; // a new choice deserves a fresh load attempt
const row = (GM_VOICE_CHOICES[kind] || []).find(c => c.gm === program);
setStatus(`Guide instrument (${kind}): ${row ? row.label : 'GM ' + program}`);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== Files ==\n'
git ls-files 'src/gm-guide.js' 'src/audio.js' || true

printf '\n== gm-guide outline ==\n'
ast-grep outline src/gm-guide.js --view expanded || true

printf '\n== search for ensureGmPreset and preset loading ==\n'
rg -n "ensureGmPreset|_presetLoading|_presetError|load|error|setTimeout|25 ms|25ms|preset" src/gm-guide.js src/audio.js || true

printf '\n== relevant slices from gm-guide.js ==\n'
nl -ba src/gm-guide.js | sed -n '1,380p'

printf '\n== relevant slices from audio.js around ensureGmPreset references ==\n'
nl -ba src/audio.js | sed -n '920,1045p'

Repository: got-feedBack/feedBack-plugin-editor

Length of output: 6816


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== locate tests or mocks mentioning gm preset ==\n'
rg -n "gm preset|ensureGmPreset|presetLoading|presetError|editorSetGmVoice|GM_VOICE_CHOICES|plugin→org→CDN|CDN" . || true

Repository: got-feedBack/feedBack-plugin-editor

Length of output: 4930


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== gm-guide.js 228-304 ==\n'
awk 'NR>=228 && NR<=304 {printf "%4d  %s\n", NR, $0}' src/gm-guide.js

printf '\n== audio.js 950-995 ==\n'
awk 'NR>=950 && NR<=995 {printf "%4d  %s\n", NR, $0}' src/audio.js

printf '\n== gm_guide tests around loading/retry behavior ==\n'
awk 'NR>=1 && NR<=320 {printf "%4d  %s\n", NR, $0}' tests/gm_guide.test.mjs

Repository: got-feedBack/feedBack-plugin-editor

Length of output: 20316


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== scheduler / guide timer interval ==\n'
rg -n "25 ms|25ms|setInterval|requestAnimationFrame|GUIDE_|guideTimer|tick" src/audio.js src/gm-guide.js

printf '\n== audio.js around the guide loop and timer setup ==\n'
awk 'NR>=520 && NR<=640 {printf "%4d  %s\n", NR, $0}' src/audio.js

printf '\n== any retry/backoff state in gm-guide.js ==\n'
rg -n "_presetLoading|_presetError|retry|backoff|deadline|timeout|abort|hung|hang" src/gm-guide.js tests/gm_guide.test.mjs

Repository: got-feedBack/feedBack-plugin-editor

Length of output: 11299


Bound GM preset loads and add retry backoff.
A hung script leaves _presetLoading stuck, so the plugin→org→CDN chain never advances past that source. If a source fails fast, ensureGmPreset() is retried on every 25 ms guide tick during playback, which can restart the full chain up to 40 times per second. Add a per-attempt timeout and a per-program retry delay that resets on success or an explicit voice/source change.

🧰 Tools
🪛 ast-grep (0.44.1)

[error] 216-216: React's useState should not be directly called
Context: setStatus(Guide instrument (${kind}): ${row ? row.label : 'GM ' + program})
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(usestate-direct-usage)

🤖 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/gm-guide.js` around lines 211 - 218, Update the GM preset-loading flow
centered on ensureGmPreset and _presetLoading so each source attempt has a
timeout that clears the stuck loading state and allows the plugin→org→CDN
fallback chain to continue. Add per-program retry backoff after fast failures to
prevent repeated full-chain starts on every guide tick, and reset that backoff
after a successful load or an explicit voice/source change such as
editorSetGmVoice.

@byrongamatos
byrongamatos merged commit 2a764a1 into main Jul 12, 2026
3 checks passed
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.

2 participants