Root cause of the flaky pytest segfault (exit 139): the background scan and enrichment daemon threads (_scan_runner/_enrich_runner) use the shared MetadataDB connection, but test fixtures closed that connection in teardown without stopping them. A daemon thread mid-query on a freed SQLite conn is a native use-after-free → SIGSEGV. The app's startup kicks a scan, so almost any app-booting fixture was vulnerable. It only surfaced now because got-feedback/feedBack#728 added a push trigger, so ci/test runs on every push to main.
Fix: server.py retains the scan/enrich thread handles and adds _join_background_db_threads(); every test fixture now joins the workers before conn.close(). Verified: the full suite runs to completion (no segfault) where it previously crashed at ~25%.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(v3 library): A–Z fast-scroll jump rail on the Songs grid
Adds a vertical letter rail (Plex/Radarr/iOS-contacts pattern) pinned to the
right edge next to the scrollbar so you can jump the library to a starting
letter — tap, drag-to-scrub with a live letter bubble, or arrow-key between
letters. The classic (v2) tree already had letter selection; this brings the
new v3 grid to parity (it was the gap behind the "alphabetical scroll
selection next to the scrollbar" idea).
It shows ONLY for the grid view + alphabetical (artist/title) sorts, and only
offers letters present in the current sort AND filter set, so a tap always
lands on a real card (absent letters are dimmed + non-interactive). The grid
is forward-only, server-paged infinite scroll with no virtualization, so a
jump pages through to the target card then scrolls to it; a token guards
overlapping jumps (drag) so the newest wins. A keyset-seek + virtualized
window is the scaling follow-up for very large libraries.
Backend: /api/library/stats gains an optional `sort` param and an additive
`sort_letters` map — songs-per-first-letter of the ACTIVE sort column (artist
or title), filter-synced — so the rail's present-letters match the grid's real
order. The legacy `letters` (distinct-artist) field is unchanged, so the
dashboard + classic tree are unaffected. `sort` is dropped for providers whose
query_stats predates it (existing kwarg-filter), so third-party library
providers keep working (rail simply falls back / hides).
Frontend: static/v3/songs.js (refreshRail / jumpToLetter / pointer-drag +
keyboard, cards tagged data-letter), static/v3/v3.css (.v3-azrail + bubble).
Tests: tests/test_library_filters.py (sort_letters artist/title, song-vs-
distinct-artist counting), tests/test_library_providers.py (sort forwarded),
tests/js/v3_az_rail.test.js (gating, data-letter, load-through, drag/keys).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QbexxfTt8q2tAn436MqGWF
* fix(v3 library): harden A–Z jump rail (review P2/P3)
Addresses the PR #634 review findings (manual + Codex):
P2 correctness
- refreshRail prefers the active-sort `sort_letters`; falls back to the
artist-based `letters` only on an artist sort, and hides the rail on a
title sort when a legacy provider returns none (was mislabeling letters).
- reload() bumps `_jumpToken` so an in-flight letter jump can't scroll a
grid that's being rebuilt from page 0.
- songBucket no longer trims, matching the server SQL + grid ORDER BY raw
first-char bucketing (a leading-space title now buckets under '#' on both
sides).
P3 polish
- Paging guard is total-derived (ceil(total/PAGE_SIZE)+2) instead of a
magic 4000, keeping large libraries reachable while still bounded.
- Roving tabindex: only the first present letter is tabbable; arrow keys
move it. Removes up to 27 page tab stops.
- `sort_letters` is computed only when the caller opts in
(want_sort_letters / route `sort_letters=1`); the dashboard + v2 tree
skip the extra GROUP BY. Added sort + want_sort_letters to the optional
provider-kwargs so non-introspectable legacy providers drop them.
- _railToken supersedes stale refreshRail responses; hide the rail when no
letters are present instead of rendering disabled buttons.
Tests updated accordingly (v3_az_rail.test.js, test_library_filters.py).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: byrongamatos <xasiklas@gmail.com>
* Update GitHub repo references from feedback* to feedBack*
* rename: slopsmith -> feedBack, byron -> got-feedBack
Renames across the entire codebase:
- slopsmith/Slopsmith/SLOPSMITH/SlopSmith -> feedBack/FeedBack/FEEDBACK/FeedBack
- byron/Byron/Byrongamatos -> got-feedBack/got-feedBack/got-feedBack
- /home/byron/ -> /opt/got-feedBack/
- byron@ougsoft.com -> hi@got-feedBack.org
- github.com/byrongamatos/ -> github.com/got-feedback/
- com.byron. -> com.got-feedback.
- SLOPSMITH_ env vars -> FEEDBACK_ with backward-compat fallback
- Protocol/storage strings migrated with read-old/write-new pattern
- window.slopsmith JS API -> window.feedBack (canonical) + backward-compat alias
Refs: #rename-slopsmith
* rename: complete regen against current main + fix backward-compat alias
Regenerated the slopsmith->feedBack / byron->got-feedBack rename on top of
current main (3 commits had landed since the branch: #572/#554/#574),
resolving the four content conflicts in favour of main's newer content
(autoplay/auto-exit, accuracy-badge, Virtuoso re-home, feedpak badge).
Completion fixes on top of the mechanical rename:
- Re-apply rename to post-branch content the original rename never saw:
window.slopsmith(.Tour) consumers in lessons.js / notifications.js /
onboarding-tour.js, and the matching JS + python tests (autoplay_exit,
progression_*, test_feedpak_extension FEEDBACK_* env vars). The test env
vars now match server.py (which reads FEEDBACK_SYNC_STARTUP /
FEEDBACK_SKIP_STARTUP_TASKS), so the sync-startup test exercises the real
path again.
- Restore the window.slopsmith backward-compat alias dropped during conflict
resolution, and move the bus aliases to AFTER the _feedBackExisting merge
block so they reference the fully-assembled object (also fixes the
loop_api.test.js API-surface regex, which the original PR latently broke).
- Drop the stray empty data/web_library.db (runtime DB lives in CONFIG_DIR)
and gitignore it.
- Fix stale tone-source test: feed[dB]ack -> fee[dB]ack to match shipped
source labels.
Verified locally (org CI billing-blocked): JS 819/819 pass; pytest 1669
passed / 1683 collected with 0 import errors; zero residual slopsmith/byron
except the two intentional window.slopsmith aliases.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* rename: implement advertised backward-compat + prune dead community plugins
Address gaps where PR #537's "Backward compatibility" section was advertised
but not implemented, and clean up the community plugin list.
Env vars (FEEDBACK_* canonical, legacy SLOPSMITH_* honoured):
- New lib/env_compat.py (getenv_compat / env_flag_compat) + tests. server.py
(_env_flag + all FEEDBACK_* reads), diagnostics_hardware, gp2midi and
tailwind_rebuild now resolve the legacy alias, so existing SLOPSMITH_UI /
SLOPSMITH_PLUGINS_DIR / etc. deployments keep working.
- Fix the rename collapsing plugins/__init__.py and minigames/routes.py from
`FEEDBACK_PLUGINS_DIR or SLOPSMITH_PLUGINS_DIR` into a redundant
`FEEDBACK_ or FEEDBACK_` (the fallback was silently lost).
Storage (app.js update-channel):
- Read feedBack-update-channel, fall back to legacy slopsmith-update-channel,
and clear the legacy key on write — so a user's update-channel preference
survives the rename instead of resetting to "stable".
Community plugin list (README): the rename rewrote third-party repo URLs we
don't own. Probed every one; their owners never renamed, so:
- Restore the 13 live community plugins to their real slopsmith-* names.
- Prune 6 that are 404 to the public (topkoa splitscreen/stems, OmikronApex
tuner, Jafz2001 nam-rig-builder, DeathlySin song-preview, Erikcb91 shuffle).
- Fix a pre-existing Guitar Theory clone-command typo (nam-tone -> guitar-theory).
Verified: env_compat 7/7, JS 819/819, pytest 1690 collected / 0 import errors,
rename-sensitive + startup suites green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: byrongamatos <xasiklas@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reword comments/docstrings/strings and rename identifiers that referenced
the external game and its file formats:
- format-id "psarc" -> "archive"; local vars psarc_path -> song_path,
psarc_base -> tone_base
- lyrics provenance value "sng" -> "notechart" (legacy "sng" still accepted)
- highway_3d fret-ghost scope value "rocksmith" -> "chords" (invalid/legacy
values fall back to the default, preserving behaviour)
- neutralise references in prose, test names/data, .gitattributes and docs
No functional change beyond the renamed identifiers; all Python compiles.