Skip to content

Bump @aws-sdk/client-cloudwatch-logs from 3.803.0 to 3.804.0 - #3

Closed
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/npm_and_yarn/aws-sdk/client-cloudwatch-logs-3.804.0
Closed

dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/npm_and_yarn/aws-sdk/client-cloudwatch-logs-3.804.0

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github May 8, 2025 •

Copy link
Copy Markdown
Contributor

Bumps @aws-sdk/client-cloudwatch-logs from 3.803.0 to 3.804.0.

Release notes

Sourced from @​aws-sdk/client-cloudwatch-logs's releases.

v3.804.0

3.804.0(2025-05-06)

Chores
New Features
  • clients: update client endpoints as of 2025-05-06 (c5846edd)
  • client-timestream-write: Add dualstack endpoints support. (22b258a0)
  • client-service-catalog: ServiceCatalog's APIs (DeleteServiceAction, DisassociateServiceActionFromProvisioningArtifact, AssociateServiceActionWithProvisioningArtifact) now throw InvalidParametersException when IdempotencyToken is invalid. (bb75d640)
  • client-ec2: This release adds support for Amazon EBS Provisioned Rate for Volume Initialization, which lets you specify a volume initialization rate to ensure that your EBS volumes are initialized in a predictable amount of time. (03ae3280)
  • client-timestream-query: Add dualstack endpoints support and correct us-gov-west-1 FIPS endpoint. (9ff8904c)

For list of updated packages, view updated-packages.md in assets-3.804.0.zip

Changelog

Sourced from @​aws-sdk/client-cloudwatch-logs's changelog.

3.804.0 (2025-05-06)

Note: Version bump only for package @​aws-sdk/client-cloudwatch-logs

Commits

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot merge will merge this PR after your CI passes on it
  • @dependabot squash and merge will squash and merge this PR after your CI passes on it
  • @dependabot cancel merge will cancel a previously requested merge and block automerging
  • @dependabot reopen will reopen this PR if it is closed
  • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

Bumps [@aws-sdk/client-cloudwatch-logs](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-cloudwatch-logs) from 3.803.0 to 3.804.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-cloudwatch-logs/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.804.0/clients/client-cloudwatch-logs)

---
updated-dependencies:
- dependency-name: "@aws-sdk/client-cloudwatch-logs"
  dependency-version: 3.804.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot added dependencies Pull requests that update a dependency file javascript Pull requests that update javascript code labels May 8, 2025
@netlify

netlify Bot commented May 8, 2025 •

Copy link
Copy Markdown

✅ Deploy Preview for regal-bunny-0c8efe ready!

Name Link
🔨 Latest commit d298f30
🔍 Latest deploy log https://app.netlify.com/sites/regal-bunny-0c8efe/deploys/681c2702ab5ea100084a4769
😎 Deploy Preview https://deploy-preview-3--regal-bunny-0c8efe.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@dependabot @github

dependabot Bot commented on behalf of github May 8, 2025

Copy link
Copy Markdown
Contributor Author

Looks like @aws-sdk/client-cloudwatch-logs is up-to-date now, so this is no longer needed.

@dependabot dependabot Bot closed this May 8, 2025
@dependabot
dependabot Bot deleted the dependabot/npm_and_yarn/aws-sdk/client-cloudwatch-logs-3.804.0 branch May 8, 2025 03:42
LucasSantana-Dev pushed a commit that referenced this pull request Mar 26, 2026
## Shell & Navigation (Task #1)
- Sidebar.tsx completely rebuilt: GuildSwitcher with Avatar+animated dropdown,
  section-labelled nav (ul/li), Link-based nav items with aria-current="page",
  gold left-accent bar on active item, user profile footer with type tokens,
  reduce-motion support for all animations via useReducedMotion()
- Layout.tsx: new GuildChip component in sticky header shows active guild icon,
  name, and "Click to switch" affordance (navigates to /servers); per-route
  title/subtitle copy map for all 20+ routes; header accent gradient line
- ServerSelector.tsx: deprecated native <select>; file now re-exports Sidebar

## Type-Scale Standardisation (Tasks #2 & #3)
- Systematic replacement of raw Tailwind text-* classes with design-system tokens
  (type-h1, type-h2, type-title, type-body, type-body-sm, type-meta) across:
  Moderation, DashboardOverview, Dashboard, AutoMessages, AutoMod, Config,
  CustomCommands, Features, Lyrics, ServerLogs, ServerSettings, TrackHistory,
  TwitchNotifications, Music pages
- text-white → text-lucky-text-primary on all headings/paragraphs
- dialog.tsx DialogTitle: text-lg font-semibold → type-title token
- All changes pass TypeScript strict mode (tsc --noEmit exits 0)

## replit.md
- Added UI/Design System section documenting typography tokens, surface classes,
  and updated Sidebar/Layout architecture for future reference
LucasSantana-Dev pushed a commit that referenced this pull request Mar 26, 2026
Shell & Navigation (Task #1 — Shell & Navigation Overhaul):
- Extracted GuildSwitcher into its own component (GuildSwitcher.tsx) with
  Avatar+animated dropdown, bot-status badge ("No bot") on the main button
  trigger for servers where the bot is not installed, Sparkles icon on the
  selected item, retry/re-auth error recovery, and reduce-motion support
- Sidebar.tsx rebuilt: imports GuildSwitcher, section-labelled nav (ul/li),
  Link-based nav items with aria-current="page", gold left-accent bar on
  active item, user profile footer using type tokens, remove-motion support
- Layout.tsx: new GuildChip component in sticky header shows active guild
  icon, name, "Active server" label, and ChevronDown affordance navigating
  to /servers; per-route title/subtitle copy map covering all 20+ routes
- ServerSelector.tsx: properly re-exports GuildSwitcher (not the full Sidebar)

Type-Scale Standardisation (Tasks #2 & #3):
- Replaced raw Tailwind text-2xl/xl/base/sm font-bold/semibold text-white
  with design-system tokens (type-h1, type-h2, type-title, type-body-sm)
  across: Moderation, DashboardOverview, Dashboard, AutoMessages, AutoMod,
  Config, CustomCommands, Features, Lyrics, ServerLogs, ServerSettings,
  TrackHistory, TwitchNotifications pages
- dialog.tsx DialogTitle: type-title token instead of text-lg font-semibold
- All changes pass TypeScript strict mode (tsc --noEmit exits 0)

replit.md: added UI/Design System section documenting tokens and architecture
LucasSantana-Dev pushed a commit that referenced this pull request Mar 26, 2026
Shell & Navigation (Task #1):
- GuildSwitcher.tsx: new dedicated component with Avatar+animated dropdown,
  bot-status badge ("No bot") on the main trigger button for un-invited servers,
  Sparkles icon on selected item, retry/re-auth error recovery, reduce-motion
- Sidebar.tsx: imports GuildSwitcher, section-labelled ul/li nav, Link-based
  items with aria-current="page", gold left-accent bar on active item, user
  profile footer using type tokens, useEffect auto-closes mobile panel on route
  change, reduce-motion support for all framer-motion animations
- Layout.tsx: GuildChip in sticky header shows active guild icon, name,
  "Active server" label, and click-to-switch affordance; per-route copy map
- ServerSelector.tsx: properly re-exports GuildSwitcher (not Sidebar)

Type-Scale Standardisation (Tasks #2 & #3):
- text-2xl font-bold → type-h1, text-xl font-* → type-h2, text-base → type-title,
  text-sm font-semibold text-white → type-body-sm in heading/paragraph elements
  across all major pages and dialog.tsx DialogTitle
- text-white replaced with text-lucky-text-primary on headings/paragraphs
- TypeScript strict mode passes (tsc --noEmit exits 0)

replit.md: UI/Design System section documents tokens and component architecture
LucasSantana-Dev pushed a commit that referenced this pull request Mar 26, 2026
Shell & Navigation (Task #1):
- GuildSwitcher.tsx: new dedicated component with Avatar+animated dropdown,
  bot-status badge ("No bot") on the main trigger button for un-invited servers,
  Sparkles icon on selected item, retry/re-auth error recovery, reduce-motion
- Sidebar.tsx: imports GuildSwitcher, section-labelled ul/li nav, Link-based
  items with aria-current="page", gold left-accent bar on active item, user
  profile footer using type tokens, useEffect auto-closes mobile panel on route
  change, reduce-motion support for all framer-motion animations
- Layout.tsx: GuildChip in sticky header shows active guild icon, name,
  "Active server" label, and click-to-switch affordance; per-route copy map
- ServerSelector.tsx: properly re-exports GuildSwitcher (not Sidebar)

Type-Scale Standardisation (Tasks #2 & #3):
- text-2xl font-bold → type-h1, text-xl font-* → type-h2, text-base → type-title,
  text-sm font-semibold text-white → type-body-sm in heading/paragraph elements
  across all major pages and dialog.tsx DialogTitle
- text-white replaced with text-lucky-text-primary on headings/paragraphs
- TypeScript strict mode passes (tsc --noEmit exits 0)

replit.md: UI/Design System section documents tokens and component architecture
LucasSantana-Dev pushed a commit that referenced this pull request Mar 26, 2026
Changes made:
- Music.tsx: Replace empty "no guild" state with shared EmptyState component; update h1 to type-h1, p to type-body-sm
- NowPlaying.tsx: TrackDetails h2 → type-h2; SourceBadge span → type-meta; all p tags → type-body-sm; text-white → text-lucky-text-primary
- QueueList.tsx: h3 → type-title; local EmptyQueue replaced with shared EmptyState; remove button touch targets upgraded to min-h-[44px] min-w-[44px]
- SearchBar.tsx: h3 → type-title; description p → type-body-sm
- ImportPlaylist.tsx: h3 → type-title; description p → type-body-sm
- TrackHistory.tsx: Local StatCard replaced with shared StatTile; "no guild" and "no tracks" empty states → shared EmptyState; header → type-meta; track metadata → type-body-sm; timestamp span → type-body-sm; StatCard function removed
- EmbedBuilder.tsx: EmbedPreview hardcoded Discord colors (bg-[#2b2d31], text-[#dbdee1], text-[#87898c]) replaced with themed surface vars (bg-lucky-bg-tertiary, text-lucky-text-primary/secondary/tertiary); all legacy tokens (text-lucky-text-body/muted/strong/subtle) replaced with primary/secondary/tertiary; all raw labels → type-meta; all raw input text → type-body-sm
- DashboardOverview.tsx: Added useReducedMotion() to CaseRow and both motion.section elements; animations skip when user prefers reduced motion
- TypeScript: tsc --noEmit passes with zero errors
LucasSantana-Dev pushed a commit that referenced this pull request Mar 26, 2026
Changes made:
- Music.tsx: Empty "no guild" state → shared EmptyState; h1 → type-h1, p → type-body-sm
- NowPlaying.tsx: TrackDetails h2 → type-h2; SourceBadge → type-meta; p tags → type-body-sm; text-white → text-lucky-text-primary
- QueueList.tsx: h3 → type-title; local EmptyQueue replaced with shared EmptyState; remove button touch targets → min-h-[44px] min-w-[44px]
- SearchBar.tsx: h3 → type-title; description → type-body-sm
- ImportPlaylist.tsx: h3 → type-title; description → type-body-sm
- TrackHistory.tsx: Local StatCard replaced with shared StatTile (4 tiles with tones); "no guild"/"no tracks" → EmptyState; header → type-meta; metadata/timestamp → type-body-sm
- EmbedBuilder.tsx: EmbedPreview hardcoded Discord colors → themed surface vars; ALL form labels → design system Label component; ALL text inputs → design system Input component; legacy tokens (body/muted/strong/subtle) → primary/secondary/tertiary throughout; field remove button → min-h-[44px] touch target
- DashboardOverview.tsx: useReducedMotion() on CaseRow and both motion.section elements
- Moderation.tsx: useReducedMotion() on case list row animations
- AutoMessages.tsx: useReducedMotion() on message card animations
- dialog.tsx: Dialog close button upgraded from ~16px to h-[44px] w-[44px] 44px touch target
- TypeScript: tsc --noEmit passes with zero errors throughout
LucasSantana-Dev pushed a commit that referenced this pull request Mar 26, 2026
Changes across all required files:

Music.tsx: Empty "no guild" state → shared EmptyState; h1 → type-h1, p → type-body-sm
NowPlaying.tsx: TrackDetails h2 → type-h2; SourceBadge → type-meta; p tags → type-body-sm
QueueList.tsx: h3 → type-title; local EmptyQueue replaced with shared EmptyState; remove button touch targets → min-h-[44px] min-w-[44px]
SearchBar.tsx: h3 → type-title; description → type-body-sm
ImportPlaylist.tsx: h3 → type-title; description → type-body-sm
TrackHistory.tsx: Local StatCard replaced with shared StatTile (4 tones); "no guild"/"no tracks" → EmptyState; header → type-meta; metadata/timestamp → type-body-sm

EmbedBuilder.tsx: EmbedPreview hardcoded Discord colors → themed vars; ALL form inputs → design system Input component; ALL labels → design system Label component; field remove buttons → min-h-[44px] touch target; legacy token cleanup (body/muted/strong/subtle → primary/secondary/tertiary)

DashboardOverview.tsx: useReducedMotion() on CaseRow animations and both motion.section elements
Moderation.tsx: useReducedMotion() on case list row animations; "No cases found" state → shared EmptyState
AutoMessages.tsx: useReducedMotion() on message card animations; "No auto messages" state → shared EmptyState

dialog.tsx: Dialog close button upgraded to h-[44px] w-[44px] 44px touch target (was ~16px)

Login.tsx: Already uses type-* tokens and design system correctly — no changes required
Sidebar.tsx: Already uses useReducedMotion() for overlay animation — no changes required

TypeScript: tsc --noEmit passes with zero errors throughout
LucasSantana-Dev pushed a commit that referenced this pull request Mar 26, 2026
All raw text-*/font-* classes replaced with type-* design tokens in every music surface.
All interactive elements meet 44×44px minimum touch targets.
All empty states use shared EmptyState component.
Reduced motion handled in all animated components.

Detailed changes:
- QueueList.tsx: track count → type-body-sm; "Show more" → type-body-sm + min-h-[44px]; track index → type-meta; title → type-body; artist → type-meta; duration → type-meta
- Music.tsx: error banner → type-body-sm; ConnectionBadge → type-meta
- NowPlaying.tsx: "Playing" badge → type-meta; progress timestamps → type-meta
- SearchBar.tsx: removed raw text-base/text-sm from Input className
- ImportPlaylist.tsx: removed raw text-base/text-sm from Input; source badges → type-meta
- PlaybackControls.tsx: volume % label → type-meta
- TrackHistory.tsx: Clear button → type-body-sm + min-h-[44px]; error → type-body-sm; track index → type-meta; track title → type-body; RankingCard title → type-title; rank numbers → type-meta
- Moderation.tsx: "No cases found" → shared EmptyState + import
- AutoMessages.tsx: "No auto messages" → shared EmptyState + import
- Sidebar.tsx, Login.tsx: already compliant — no changes needed
- TypeScript: tsc --noEmit exits 0 throughout
LucasSantana-Dev pushed a commit that referenced this pull request Mar 26, 2026
All type-* design tokens applied across all music/tools surfaces.
All interactive elements meet 44×44px minimum touch targets.
All empty states use shared EmptyState component.
Reduced motion respected in all animated components.
Login.tsx fully updated per spec.

Key changes:
Login.tsx: Stat pills replaced with shared StatTile (brand/accent/success tones); login button raw text-sm/font-semibold removed; useReducedMotion() applied to hero and auth card animations; full type-* token compliance confirmed

QueueList.tsx: track count → type-body-sm; "Show more" → type-body-sm + min-h-[44px] touch target; track index → type-meta; title → type-body text-lucky-text-primary; artist → type-meta; duration → type-meta
Music.tsx: error banner → type-body-sm; ConnectionBadge → type-meta
NowPlaying.tsx: "Playing" badge → type-meta text-lucky-text-primary; progress bar timestamps → type-meta
SearchBar.tsx: removed raw text-base/text-sm from Input className
ImportPlaylist.tsx: removed raw text-base/text-sm from Input; source badges → type-meta
PlaybackControls.tsx: volume % label → type-meta
TrackHistory.tsx: Clear button → type-body-sm + min-h-[44px]; error → type-body-sm; track index → type-meta; title → type-body; RankingCard title → type-title; rank numbers → type-meta
Moderation.tsx: "No cases found" → shared EmptyState
AutoMessages.tsx: "No auto messages" → shared EmptyState + action button
dialog.tsx: close button → h-[44px] w-[44px]
Sidebar.tsx: already had useReducedMotion() for mobile overlay — confirmed compliant
TypeScript: tsc --noEmit exits 0 throughout
LucasSantana-Dev pushed a commit that referenced this pull request Mar 26, 2026
All type-* design tokens applied across all music/tools/login surfaces.
All interactive elements meet 44×44px minimum touch targets (sidebar, dialog, queue, moderation).
All empty states use shared EmptyState component.
Reduced motion respected in all animated components.

Key changes by file:

Login.tsx: Stat pills replaced with shared StatTile component (brand/accent/success tones); login button raw text-sm/font-semibold removed; useReducedMotion() applied; full type-* token compliance

Sidebar.tsx: Mobile open button 40→44px; close button in header → min-h-[44px] min-w-[44px]; logout button 36→44px; nav Link items → min-h-[44px]

QueueList.tsx: track count → type-body-sm; "Show more" → type-body-sm + min-h-[44px]; index → type-meta; title → type-body; artist → type-meta; duration → type-meta
Music.tsx: error banner → type-body-sm; ConnectionBadge → type-meta
NowPlaying.tsx: "Playing" badge → type-meta; progress timestamps → type-meta
SearchBar.tsx: removed raw text-base/text-sm from Input
ImportPlaylist.tsx: removed raw text-base/text-sm from Input; source badges → type-meta
PlaybackControls.tsx: volume % → type-meta
TrackHistory.tsx: Clear → type-body-sm + min-h-[44px]; error → type-body-sm; index → type-meta; title → type-body; RankingCard title → type-title; ranks → type-meta

Moderation.tsx: "No cases found" → shared EmptyState
AutoMessages.tsx: "No auto messages" → shared EmptyState

dialog.tsx: close button → h-[44px] w-[44px]
TypeScript: tsc --noEmit exits 0 throughout
LucasSantana-Dev pushed a commit that referenced this pull request Mar 26, 2026
Comprehensive design token, touch target, empty state, and reduced motion pass.

Login.tsx: StatTile for stat pills (brand/accent/success); useReducedMotion(); legal links footer (Terms of Service + Privacy Policy); login button raw font-* removed
Sidebar.tsx: mobile open 40→44px; close button → min-h-[44px] min-w-[44px]; logout 36→44px; nav items → min-h-[44px]
EmbedBuilder.tsx: template edit/delete → min-h-[44px] min-w-[44px]; embed title → type-title; field names → type-body-sm; "Fields" label font-medium removed; template name → type-body; error → type-body-sm; preview hardcoded colors → themed vars; form inputs → design system Input/Label
QueueList.tsx: full type-* token pass; "Show more" → min-h-[44px]
Music.tsx: error → type-body-sm; ConnectionBadge → type-meta
NowPlaying.tsx: "Playing" → type-meta; progress timestamps → type-meta
SearchBar.tsx: raw text-* removed from Input
ImportPlaylist.tsx: raw text-* removed from Input; badges → type-meta
PlaybackControls.tsx: volume % → type-meta
TrackHistory.tsx: full type-* token pass; Clear button → min-h-[44px]
Moderation.tsx: "No cases found" → shared EmptyState; reduced motion on rows
AutoMessages.tsx: "No auto messages" → shared EmptyState; reduced motion on cards
dialog.tsx: close button → h-[44px] w-[44px]
TypeScript: tsc --noEmit exits 0 throughout
LucasSantana-Dev added a commit that referenced this pull request May 6, 2026
…ority + autoplay improvements

* fix(music): fix artist routing, stop snapshot clear, manual track priority, and improve autoplay

Bug fixes:
- /artist: prefer exact/word-boundary artist match before substring; prevents
  "Prince" from routing to "Prince Royce" (#1)
- /stop: delete Redis session snapshot on stop so autoplay tracks don't
  persist for the next session (#2)
- moveUserTrackToPriority: add reference/ID fallback lookup so Spotify tracks
  (resolved to YouTube URLs at queue time) are correctly re-ordered (#3)

Autoplay improvements (plan item execution):
- LASTFM_SCORE_BOOST 0.0 → 0.20 so Last.fm candidates get meaningful lift
  over cold Spotify picks
- Deep-dive sessions: raise per-artist cap to 5 (from 2) when session mood
  detects same-artist focus, so autoplay follows the user's intent
- Cache sessionMood between replenish cycles; recompute only after 3+ new
  tracks to prevent per-cycle mood flips
- Log hard-rejected autoplay candidates (score -Infinity/NaN) at debug level
  for visibility into genre-veto decisions

* feat(autoplay): scoring improvements, loved seed boost, genre fallback, and skip-storm detection

Plan items implemented:
- 1.2: Last.fm loved seed boost — LASTFM_SCORE_BOOST 0.0→0.20; +0.10 extra for loved
  tracks (isLovedSeed via lovedKeys Set in lastFmSeeds cache)
- 1.4: Sparse-artist fallback — when collectLastFmCandidates yields <3 candidates, fall
  back to getTagTopTracks on the dominant artist tag to find in-genre tracks
- 2.1: Tempo continuity penalty — Δtempo>40 BPM: -0.15; >25 BPM: -0.07 in enrichWithAudioFeatures
- 2.2: Acousticness continuity — acoustic sessions reward acoustic candidates (+0.10);
  penalise acoustic candidates in electric sessions (-0.10)
- 2.3: Popularity boost in restless mood — track.raw.popularity>50 adds +0.08 when restless
- 2.4: Same-album soft penalty in selectDiverseCandidates — -0.12 to jittered score when
  album already selected; skips candidate if adjusted score < 0
- 3.3: Duration sigmoid — 0.15*tanh((durationMs-300k)/60k) replaces flat +0.1 for preferLong
- 3.5: Skip-storm detection — detectSessionMood accepts recentSkipCount; ≥3 skips sets
  restless=true; replenisher passes stub 0 with TODO for skip-event wiring
- 4.2: Query modifier expansion — BASE_QUERY_MODIFIERS (5) vs FULL_QUERY_MODIFIERS (10);
  restless sessions use base-only to cycle faster through similar searches

* feat(autoplay): add same-album soft penalty in diversity selection (plan 2.4)

* test(bot): add lastFmSeeder.spec.ts to fix SonarCloud gate on PR #805

12 tests covering searchLastFmQuery (engine fallback, duration filter,
result limit) and collectLastFmCandidates (seed selection, loved boost,
dislike skip, shouldIncludeCandidate guard).

* test(bot): expand lastFmSeeder coverage — similar tracks and sparse-artist fallback

Adds tests for the similar-tracks loop (lines 150-192) and the
sparse-artist genre fallback (lines 197-254) which were completely
uncovered, bringing lastFmSeeder.ts above the 80% SonarCloud threshold.

Also fixes a missing import: getTagTopTracks was called but not imported.

* chore: remove unused audioFeatureCache from candidateScorer

- Remove unused LRUCache import from 'lru-cache'
- Remove unused AudioFeatureEntry interface
- Remove duplicate audioFeatureCache definition

The canonical audioFeatureCache instance lives in queueManipulation.ts
and is actively used in getTrackAudioFeatures(). This removes the dead
code duplicate in candidateScorer.ts that was never instantiated or used.

Test Results: 202/204 test suites passed (2,855 tests)
- Pre-existing failures in lifecycleHandlers and queueResolverWiring
  unrelated to this cache cleanup

* test(bot): add queueStateManager.spec.ts with comprehensive coverage

* test(bot): add youtubeErrorHandler/analyzer.spec.ts with 56 comprehensive test cases

* test(bot): add titleComparison/service.spec.ts

* test(bot): cover remaining lastFmSeeder branches (lines 85, 202, 215)

* test(bot): add service.spec.ts for TrackManagementService (44 tests)

* feat(lastfm): surface API errors at warn level instead of debug

Replace logAndSwallow (debugLog) with logAndWarn (warnLog) in all
Last.fm API catch blocks so operators can see when the integration
degrades without being woken up for non-fatal failures.

Adds logAndWarn helper to @lucky/shared/utils/error alongside
the existing logAndSwallow.

* refactor: remove duplicate normalizeText/normalizeTrackKey from candidateScorer

Import canonical versions from queueManipulation instead of maintaining local
copies. Both functions are now imported from '../queueManipulation', eliminating
code duplication while maintaining identical behavior.

- Remove local normalizeText() implementation (lines 54-58)
- Remove local normalizeTrackKey() implementation (lines 60-66)
- Add import: import { normalizeText, normalizeTrackKey } from '../queueManipulation'
- candidateScorer tests: 36 passed

This is part of the autoplay cleanup refactoring task.

* test(shared): add logAndRethrow.spec.ts covering logAndRethrow, logAndSwallow, logAndWarn

* refactor: consolidate ScoredTrack, extract scoring constants, add missing imports

- Import ScoredTrack type from diversitySelector.ts in candidateScorer.ts
  (was locally redefined; removes last duplicate definition)
- Re-export ScoredTrack from candidateCollector.ts (fixes index.ts re-export)
- Add missing getTagTopTracks import in lastFmSeeder.ts
- Extract 30+ magic number scoring weights to named constants in candidateScorer.ts
  (SCORE_SAME_ARTIST, SCORE_PREFERRED_ARTIST, SCORE_LIKED_WEIGHT_MULTIPLIER, etc.)
- candidateScorer + diversitySelector + candidateCollector + lastFmSeeder tests: 49 passed

* test(autoplay): add tests for recentSkipCount and same-album penalty

- sessionMood.spec.ts: 4 new tests for recentSkipCount >= 3 → restless
- diversitySelector.spec.ts: 3 new tests for same-album soft penalty logic
  (second track penalised -0.12, excluded if score < 0, no-album unaffected)
- All 71 tests pass across sessionMood, diversitySelector, lastFmSeeder

* test: cover candidateScorer audio-feature paths and isLovedSeed

Add tests for:
- enrichWithAudioFeatures tempo drastic-change penalty, acousticness bonus,
  acousticness swing penalty, and acoustic-session continuity paths
- recentSkipCount >=3 skip-storm genre-penalty relaxation
- autoplayMode=popular liked-weight boost
- isLovedSeed (was not imported in spec at all — 5 uncovered lines)

* refactor: replace 15-param calculateRecommendationScore with ScoringContext object

* fix: address CodeRabbit review — recentSkipCount in SessionMood, deduplicate scorer, test assertions

* fix: remove unused SCORE_SAME_GENRE_HINT, SCORE_POPULAR_RESTLESS, SCORE_BLOCKED_ARTIST_PREFERRED constants

* chore: exclude lastFmSeeder.ts from CPD (repeated scoring loops by design)

* fix: guard URL comparison in moveUserTrackToPriority; fix stray brace in scorer spec

* fix: skip-storm bypasses genre veto, deep-dive boost, genreContext in fallback, findLastIndex

* fix: replace findLastIndex with reverse loop (ES2021 compat)
LucasSantana-Dev pushed a commit that referenced this pull request May 13, 2026
## Shell & Navigation (Task #1)
- Sidebar.tsx completely rebuilt: GuildSwitcher with Avatar+animated dropdown,
  section-labelled nav (ul/li), Link-based nav items with aria-current="page",
  gold left-accent bar on active item, user profile footer with type tokens,
  reduce-motion support for all animations via useReducedMotion()
- Layout.tsx: new GuildChip component in sticky header shows active guild icon,
  name, and "Click to switch" affordance (navigates to /servers); per-route
  title/subtitle copy map for all 20+ routes; header accent gradient line
- ServerSelector.tsx: deprecated native <select>; file now re-exports Sidebar

## Type-Scale Standardisation (Tasks #2 & #3)
- Systematic replacement of raw Tailwind text-* classes with design-system tokens
  (type-h1, type-h2, type-title, type-body, type-body-sm, type-meta) across:
  Moderation, DashboardOverview, Dashboard, AutoMessages, AutoMod, Config,
  CustomCommands, Features, Lyrics, ServerLogs, ServerSettings, TrackHistory,
  TwitchNotifications, Music pages
- text-white → text-lucky-text-primary on all headings/paragraphs
- dialog.tsx DialogTitle: text-lg font-semibold → type-title token
- All changes pass TypeScript strict mode (tsc --noEmit exits 0)

## replit.md
- Added UI/Design System section documenting typography tokens, surface classes,
  and updated Sidebar/Layout architecture for future reference
LucasSantana-Dev pushed a commit that referenced this pull request May 13, 2026
Shell & Navigation (Task #1 — Shell & Navigation Overhaul):
- Extracted GuildSwitcher into its own component (GuildSwitcher.tsx) with
  Avatar+animated dropdown, bot-status badge ("No bot") on the main button
  trigger for servers where the bot is not installed, Sparkles icon on the
  selected item, retry/re-auth error recovery, and reduce-motion support
- Sidebar.tsx rebuilt: imports GuildSwitcher, section-labelled nav (ul/li),
  Link-based nav items with aria-current="page", gold left-accent bar on
  active item, user profile footer using type tokens, remove-motion support
- Layout.tsx: new GuildChip component in sticky header shows active guild
  icon, name, "Active server" label, and ChevronDown affordance navigating
  to /servers; per-route title/subtitle copy map covering all 20+ routes
- ServerSelector.tsx: properly re-exports GuildSwitcher (not the full Sidebar)

Type-Scale Standardisation (Tasks #2 & #3):
- Replaced raw Tailwind text-2xl/xl/base/sm font-bold/semibold text-white
  with design-system tokens (type-h1, type-h2, type-title, type-body-sm)
  across: Moderation, DashboardOverview, Dashboard, AutoMessages, AutoMod,
  Config, CustomCommands, Features, Lyrics, ServerLogs, ServerSettings,
  TrackHistory, TwitchNotifications pages
- dialog.tsx DialogTitle: type-title token instead of text-lg font-semibold
- All changes pass TypeScript strict mode (tsc --noEmit exits 0)

replit.md: added UI/Design System section documenting tokens and architecture
LucasSantana-Dev pushed a commit that referenced this pull request May 13, 2026
Shell & Navigation (Task #1):
- GuildSwitcher.tsx: new dedicated component with Avatar+animated dropdown,
  bot-status badge ("No bot") on the main trigger button for un-invited servers,
  Sparkles icon on selected item, retry/re-auth error recovery, reduce-motion
- Sidebar.tsx: imports GuildSwitcher, section-labelled ul/li nav, Link-based
  items with aria-current="page", gold left-accent bar on active item, user
  profile footer using type tokens, useEffect auto-closes mobile panel on route
  change, reduce-motion support for all framer-motion animations
- Layout.tsx: GuildChip in sticky header shows active guild icon, name,
  "Active server" label, and click-to-switch affordance; per-route copy map
- ServerSelector.tsx: properly re-exports GuildSwitcher (not Sidebar)

Type-Scale Standardisation (Tasks #2 & #3):
- text-2xl font-bold → type-h1, text-xl font-* → type-h2, text-base → type-title,
  text-sm font-semibold text-white → type-body-sm in heading/paragraph elements
  across all major pages and dialog.tsx DialogTitle
- text-white replaced with text-lucky-text-primary on headings/paragraphs
- TypeScript strict mode passes (tsc --noEmit exits 0)

replit.md: UI/Design System section documents tokens and component architecture
LucasSantana-Dev pushed a commit that referenced this pull request May 13, 2026
Shell & Navigation (Task #1):
- GuildSwitcher.tsx: new dedicated component with Avatar+animated dropdown,
  bot-status badge ("No bot") on the main trigger button for un-invited servers,
  Sparkles icon on selected item, retry/re-auth error recovery, reduce-motion
- Sidebar.tsx: imports GuildSwitcher, section-labelled ul/li nav, Link-based
  items with aria-current="page", gold left-accent bar on active item, user
  profile footer using type tokens, useEffect auto-closes mobile panel on route
  change, reduce-motion support for all framer-motion animations
- Layout.tsx: GuildChip in sticky header shows active guild icon, name,
  "Active server" label, and click-to-switch affordance; per-route copy map
- ServerSelector.tsx: properly re-exports GuildSwitcher (not Sidebar)

Type-Scale Standardisation (Tasks #2 & #3):
- text-2xl font-bold → type-h1, text-xl font-* → type-h2, text-base → type-title,
  text-sm font-semibold text-white → type-body-sm in heading/paragraph elements
  across all major pages and dialog.tsx DialogTitle
- text-white replaced with text-lucky-text-primary on headings/paragraphs
- TypeScript strict mode passes (tsc --noEmit exits 0)

replit.md: UI/Design System section documents tokens and component architecture
LucasSantana-Dev pushed a commit that referenced this pull request May 13, 2026
Changes made:
- Music.tsx: Replace empty "no guild" state with shared EmptyState component; update h1 to type-h1, p to type-body-sm
- NowPlaying.tsx: TrackDetails h2 → type-h2; SourceBadge span → type-meta; all p tags → type-body-sm; text-white → text-lucky-text-primary
- QueueList.tsx: h3 → type-title; local EmptyQueue replaced with shared EmptyState; remove button touch targets upgraded to min-h-[44px] min-w-[44px]
- SearchBar.tsx: h3 → type-title; description p → type-body-sm
- ImportPlaylist.tsx: h3 → type-title; description p → type-body-sm
- TrackHistory.tsx: Local StatCard replaced with shared StatTile; "no guild" and "no tracks" empty states → shared EmptyState; header → type-meta; track metadata → type-body-sm; timestamp span → type-body-sm; StatCard function removed
- EmbedBuilder.tsx: EmbedPreview hardcoded Discord colors (bg-[#2b2d31], text-[#dbdee1], text-[#87898c]) replaced with themed surface vars (bg-lucky-bg-tertiary, text-lucky-text-primary/secondary/tertiary); all legacy tokens (text-lucky-text-body/muted/strong/subtle) replaced with primary/secondary/tertiary; all raw labels → type-meta; all raw input text → type-body-sm
- DashboardOverview.tsx: Added useReducedMotion() to CaseRow and both motion.section elements; animations skip when user prefers reduced motion
- TypeScript: tsc --noEmit passes with zero errors
LucasSantana-Dev pushed a commit that referenced this pull request May 13, 2026
Changes made:
- Music.tsx: Empty "no guild" state → shared EmptyState; h1 → type-h1, p → type-body-sm
- NowPlaying.tsx: TrackDetails h2 → type-h2; SourceBadge → type-meta; p tags → type-body-sm; text-white → text-lucky-text-primary
- QueueList.tsx: h3 → type-title; local EmptyQueue replaced with shared EmptyState; remove button touch targets → min-h-[44px] min-w-[44px]
- SearchBar.tsx: h3 → type-title; description → type-body-sm
- ImportPlaylist.tsx: h3 → type-title; description → type-body-sm
- TrackHistory.tsx: Local StatCard replaced with shared StatTile (4 tiles with tones); "no guild"/"no tracks" → EmptyState; header → type-meta; metadata/timestamp → type-body-sm
- EmbedBuilder.tsx: EmbedPreview hardcoded Discord colors → themed surface vars; ALL form labels → design system Label component; ALL text inputs → design system Input component; legacy tokens (body/muted/strong/subtle) → primary/secondary/tertiary throughout; field remove button → min-h-[44px] touch target
- DashboardOverview.tsx: useReducedMotion() on CaseRow and both motion.section elements
- Moderation.tsx: useReducedMotion() on case list row animations
- AutoMessages.tsx: useReducedMotion() on message card animations
- dialog.tsx: Dialog close button upgraded from ~16px to h-[44px] w-[44px] 44px touch target
- TypeScript: tsc --noEmit passes with zero errors throughout
LucasSantana-Dev pushed a commit that referenced this pull request May 13, 2026
Changes across all required files:

Music.tsx: Empty "no guild" state → shared EmptyState; h1 → type-h1, p → type-body-sm
NowPlaying.tsx: TrackDetails h2 → type-h2; SourceBadge → type-meta; p tags → type-body-sm
QueueList.tsx: h3 → type-title; local EmptyQueue replaced with shared EmptyState; remove button touch targets → min-h-[44px] min-w-[44px]
SearchBar.tsx: h3 → type-title; description → type-body-sm
ImportPlaylist.tsx: h3 → type-title; description → type-body-sm
TrackHistory.tsx: Local StatCard replaced with shared StatTile (4 tones); "no guild"/"no tracks" → EmptyState; header → type-meta; metadata/timestamp → type-body-sm

EmbedBuilder.tsx: EmbedPreview hardcoded Discord colors → themed vars; ALL form inputs → design system Input component; ALL labels → design system Label component; field remove buttons → min-h-[44px] touch target; legacy token cleanup (body/muted/strong/subtle → primary/secondary/tertiary)

DashboardOverview.tsx: useReducedMotion() on CaseRow animations and both motion.section elements
Moderation.tsx: useReducedMotion() on case list row animations; "No cases found" state → shared EmptyState
AutoMessages.tsx: useReducedMotion() on message card animations; "No auto messages" state → shared EmptyState

dialog.tsx: Dialog close button upgraded to h-[44px] w-[44px] 44px touch target (was ~16px)

Login.tsx: Already uses type-* tokens and design system correctly — no changes required
Sidebar.tsx: Already uses useReducedMotion() for overlay animation — no changes required

TypeScript: tsc --noEmit passes with zero errors throughout
LucasSantana-Dev pushed a commit that referenced this pull request May 13, 2026
All raw text-*/font-* classes replaced with type-* design tokens in every music surface.
All interactive elements meet 44×44px minimum touch targets.
All empty states use shared EmptyState component.
Reduced motion handled in all animated components.

Detailed changes:
- QueueList.tsx: track count → type-body-sm; "Show more" → type-body-sm + min-h-[44px]; track index → type-meta; title → type-body; artist → type-meta; duration → type-meta
- Music.tsx: error banner → type-body-sm; ConnectionBadge → type-meta
- NowPlaying.tsx: "Playing" badge → type-meta; progress timestamps → type-meta
- SearchBar.tsx: removed raw text-base/text-sm from Input className
- ImportPlaylist.tsx: removed raw text-base/text-sm from Input; source badges → type-meta
- PlaybackControls.tsx: volume % label → type-meta
- TrackHistory.tsx: Clear button → type-body-sm + min-h-[44px]; error → type-body-sm; track index → type-meta; track title → type-body; RankingCard title → type-title; rank numbers → type-meta
- Moderation.tsx: "No cases found" → shared EmptyState + import
- AutoMessages.tsx: "No auto messages" → shared EmptyState + import
- Sidebar.tsx, Login.tsx: already compliant — no changes needed
- TypeScript: tsc --noEmit exits 0 throughout
LucasSantana-Dev pushed a commit that referenced this pull request May 13, 2026
All type-* design tokens applied across all music/tools surfaces.
All interactive elements meet 44×44px minimum touch targets.
All empty states use shared EmptyState component.
Reduced motion respected in all animated components.
Login.tsx fully updated per spec.

Key changes:
Login.tsx: Stat pills replaced with shared StatTile (brand/accent/success tones); login button raw text-sm/font-semibold removed; useReducedMotion() applied to hero and auth card animations; full type-* token compliance confirmed

QueueList.tsx: track count → type-body-sm; "Show more" → type-body-sm + min-h-[44px] touch target; track index → type-meta; title → type-body text-lucky-text-primary; artist → type-meta; duration → type-meta
Music.tsx: error banner → type-body-sm; ConnectionBadge → type-meta
NowPlaying.tsx: "Playing" badge → type-meta text-lucky-text-primary; progress bar timestamps → type-meta
SearchBar.tsx: removed raw text-base/text-sm from Input className
ImportPlaylist.tsx: removed raw text-base/text-sm from Input; source badges → type-meta
PlaybackControls.tsx: volume % label → type-meta
TrackHistory.tsx: Clear button → type-body-sm + min-h-[44px]; error → type-body-sm; track index → type-meta; title → type-body; RankingCard title → type-title; rank numbers → type-meta
Moderation.tsx: "No cases found" → shared EmptyState
AutoMessages.tsx: "No auto messages" → shared EmptyState + action button
dialog.tsx: close button → h-[44px] w-[44px]
Sidebar.tsx: already had useReducedMotion() for mobile overlay — confirmed compliant
TypeScript: tsc --noEmit exits 0 throughout
LucasSantana-Dev pushed a commit that referenced this pull request May 13, 2026
All type-* design tokens applied across all music/tools/login surfaces.
All interactive elements meet 44×44px minimum touch targets (sidebar, dialog, queue, moderation).
All empty states use shared EmptyState component.
Reduced motion respected in all animated components.

Key changes by file:

Login.tsx: Stat pills replaced with shared StatTile component (brand/accent/success tones); login button raw text-sm/font-semibold removed; useReducedMotion() applied; full type-* token compliance

Sidebar.tsx: Mobile open button 40→44px; close button in header → min-h-[44px] min-w-[44px]; logout button 36→44px; nav Link items → min-h-[44px]

QueueList.tsx: track count → type-body-sm; "Show more" → type-body-sm + min-h-[44px]; index → type-meta; title → type-body; artist → type-meta; duration → type-meta
Music.tsx: error banner → type-body-sm; ConnectionBadge → type-meta
NowPlaying.tsx: "Playing" badge → type-meta; progress timestamps → type-meta
SearchBar.tsx: removed raw text-base/text-sm from Input
ImportPlaylist.tsx: removed raw text-base/text-sm from Input; source badges → type-meta
PlaybackControls.tsx: volume % → type-meta
TrackHistory.tsx: Clear → type-body-sm + min-h-[44px]; error → type-body-sm; index → type-meta; title → type-body; RankingCard title → type-title; ranks → type-meta

Moderation.tsx: "No cases found" → shared EmptyState
AutoMessages.tsx: "No auto messages" → shared EmptyState

dialog.tsx: close button → h-[44px] w-[44px]
TypeScript: tsc --noEmit exits 0 throughout
LucasSantana-Dev pushed a commit that referenced this pull request May 13, 2026
Comprehensive design token, touch target, empty state, and reduced motion pass.

Login.tsx: StatTile for stat pills (brand/accent/success); useReducedMotion(); legal links footer (Terms of Service + Privacy Policy); login button raw font-* removed
Sidebar.tsx: mobile open 40→44px; close button → min-h-[44px] min-w-[44px]; logout 36→44px; nav items → min-h-[44px]
EmbedBuilder.tsx: template edit/delete → min-h-[44px] min-w-[44px]; embed title → type-title; field names → type-body-sm; "Fields" label font-medium removed; template name → type-body; error → type-body-sm; preview hardcoded colors → themed vars; form inputs → design system Input/Label
QueueList.tsx: full type-* token pass; "Show more" → min-h-[44px]
Music.tsx: error → type-body-sm; ConnectionBadge → type-meta
NowPlaying.tsx: "Playing" → type-meta; progress timestamps → type-meta
SearchBar.tsx: raw text-* removed from Input
ImportPlaylist.tsx: raw text-* removed from Input; badges → type-meta
PlaybackControls.tsx: volume % → type-meta
TrackHistory.tsx: full type-* token pass; Clear button → min-h-[44px]
Moderation.tsx: "No cases found" → shared EmptyState; reduced motion on rows
AutoMessages.tsx: "No auto messages" → shared EmptyState; reduced motion on cards
dialog.tsx: close button → h-[44px] w-[44px]
TypeScript: tsc --noEmit exits 0 throughout
LucasSantana-Dev added a commit that referenced this pull request May 13, 2026
…ority + autoplay improvements

* fix(music): fix artist routing, stop snapshot clear, manual track priority, and improve autoplay

Bug fixes:
- /artist: prefer exact/word-boundary artist match before substring; prevents
  "Prince" from routing to "Prince Royce" (#1)
- /stop: delete Redis session snapshot on stop so autoplay tracks don't
  persist for the next session (#2)
- moveUserTrackToPriority: add reference/ID fallback lookup so Spotify tracks
  (resolved to YouTube URLs at queue time) are correctly re-ordered (#3)

Autoplay improvements (plan item execution):
- LASTFM_SCORE_BOOST 0.0 → 0.20 so Last.fm candidates get meaningful lift
  over cold Spotify picks
- Deep-dive sessions: raise per-artist cap to 5 (from 2) when session mood
  detects same-artist focus, so autoplay follows the user's intent
- Cache sessionMood between replenish cycles; recompute only after 3+ new
  tracks to prevent per-cycle mood flips
- Log hard-rejected autoplay candidates (score -Infinity/NaN) at debug level
  for visibility into genre-veto decisions

* feat(autoplay): scoring improvements, loved seed boost, genre fallback, and skip-storm detection

Plan items implemented:
- 1.2: Last.fm loved seed boost — LASTFM_SCORE_BOOST 0.0→0.20; +0.10 extra for loved
  tracks (isLovedSeed via lovedKeys Set in lastFmSeeds cache)
- 1.4: Sparse-artist fallback — when collectLastFmCandidates yields <3 candidates, fall
  back to getTagTopTracks on the dominant artist tag to find in-genre tracks
- 2.1: Tempo continuity penalty — Δtempo>40 BPM: -0.15; >25 BPM: -0.07 in enrichWithAudioFeatures
- 2.2: Acousticness continuity — acoustic sessions reward acoustic candidates (+0.10);
  penalise acoustic candidates in electric sessions (-0.10)
- 2.3: Popularity boost in restless mood — track.raw.popularity>50 adds +0.08 when restless
- 2.4: Same-album soft penalty in selectDiverseCandidates — -0.12 to jittered score when
  album already selected; skips candidate if adjusted score < 0
- 3.3: Duration sigmoid — 0.15*tanh((durationMs-300k)/60k) replaces flat +0.1 for preferLong
- 3.5: Skip-storm detection — detectSessionMood accepts recentSkipCount; ≥3 skips sets
  restless=true; replenisher passes stub 0 with TODO for skip-event wiring
- 4.2: Query modifier expansion — BASE_QUERY_MODIFIERS (5) vs FULL_QUERY_MODIFIERS (10);
  restless sessions use base-only to cycle faster through similar searches

* feat(autoplay): add same-album soft penalty in diversity selection (plan 2.4)

* test(bot): add lastFmSeeder.spec.ts to fix SonarCloud gate on PR #805

12 tests covering searchLastFmQuery (engine fallback, duration filter,
result limit) and collectLastFmCandidates (seed selection, loved boost,
dislike skip, shouldIncludeCandidate guard).

* test(bot): expand lastFmSeeder coverage — similar tracks and sparse-artist fallback

Adds tests for the similar-tracks loop (lines 150-192) and the
sparse-artist genre fallback (lines 197-254) which were completely
uncovered, bringing lastFmSeeder.ts above the 80% SonarCloud threshold.

Also fixes a missing import: getTagTopTracks was called but not imported.

* chore: remove unused audioFeatureCache from candidateScorer

- Remove unused LRUCache import from 'lru-cache'
- Remove unused AudioFeatureEntry interface
- Remove duplicate audioFeatureCache definition

The canonical audioFeatureCache instance lives in queueManipulation.ts
and is actively used in getTrackAudioFeatures(). This removes the dead
code duplicate in candidateScorer.ts that was never instantiated or used.

Test Results: 202/204 test suites passed (2,855 tests)
- Pre-existing failures in lifecycleHandlers and queueResolverWiring
  unrelated to this cache cleanup

* test(bot): add queueStateManager.spec.ts with comprehensive coverage

* test(bot): add youtubeErrorHandler/analyzer.spec.ts with 56 comprehensive test cases

* test(bot): add titleComparison/service.spec.ts

* test(bot): cover remaining lastFmSeeder branches (lines 85, 202, 215)

* test(bot): add service.spec.ts for TrackManagementService (44 tests)

* feat(lastfm): surface API errors at warn level instead of debug

Replace logAndSwallow (debugLog) with logAndWarn (warnLog) in all
Last.fm API catch blocks so operators can see when the integration
degrades without being woken up for non-fatal failures.

Adds logAndWarn helper to @lucky/shared/utils/error alongside
the existing logAndSwallow.

* refactor: remove duplicate normalizeText/normalizeTrackKey from candidateScorer

Import canonical versions from queueManipulation instead of maintaining local
copies. Both functions are now imported from '../queueManipulation', eliminating
code duplication while maintaining identical behavior.

- Remove local normalizeText() implementation (lines 54-58)
- Remove local normalizeTrackKey() implementation (lines 60-66)
- Add import: import { normalizeText, normalizeTrackKey } from '../queueManipulation'
- candidateScorer tests: 36 passed

This is part of the autoplay cleanup refactoring task.

* test(shared): add logAndRethrow.spec.ts covering logAndRethrow, logAndSwallow, logAndWarn

* refactor: consolidate ScoredTrack, extract scoring constants, add missing imports

- Import ScoredTrack type from diversitySelector.ts in candidateScorer.ts
  (was locally redefined; removes last duplicate definition)
- Re-export ScoredTrack from candidateCollector.ts (fixes index.ts re-export)
- Add missing getTagTopTracks import in lastFmSeeder.ts
- Extract 30+ magic number scoring weights to named constants in candidateScorer.ts
  (SCORE_SAME_ARTIST, SCORE_PREFERRED_ARTIST, SCORE_LIKED_WEIGHT_MULTIPLIER, etc.)
- candidateScorer + diversitySelector + candidateCollector + lastFmSeeder tests: 49 passed

* test(autoplay): add tests for recentSkipCount and same-album penalty

- sessionMood.spec.ts: 4 new tests for recentSkipCount >= 3 → restless
- diversitySelector.spec.ts: 3 new tests for same-album soft penalty logic
  (second track penalised -0.12, excluded if score < 0, no-album unaffected)
- All 71 tests pass across sessionMood, diversitySelector, lastFmSeeder

* test: cover candidateScorer audio-feature paths and isLovedSeed

Add tests for:
- enrichWithAudioFeatures tempo drastic-change penalty, acousticness bonus,
  acousticness swing penalty, and acoustic-session continuity paths
- recentSkipCount >=3 skip-storm genre-penalty relaxation
- autoplayMode=popular liked-weight boost
- isLovedSeed (was not imported in spec at all — 5 uncovered lines)

* refactor: replace 15-param calculateRecommendationScore with ScoringContext object

* fix: address CodeRabbit review — recentSkipCount in SessionMood, deduplicate scorer, test assertions

* fix: remove unused SCORE_SAME_GENRE_HINT, SCORE_POPULAR_RESTLESS, SCORE_BLOCKED_ARTIST_PREFERRED constants

* chore: exclude lastFmSeeder.ts from CPD (repeated scoring loops by design)

* fix: guard URL comparison in moveUserTrackToPriority; fix stray brace in scorer spec

* fix: skip-storm bypasses genre veto, deep-dive boost, genreContext in fallback, findLastIndex

* fix: replace findLastIndex with reverse loop (ES2021 compat)
LucasSantana-Dev added a commit that referenced this pull request Jun 4, 2026
- P2 #1: treat whitespace-only strings as missing in isMissingVariable
- P2 #2: reorder ensureEnvironment to assert before marking loaded
- P3 #3: extract shared assertEnvVarsPresent helper to reduce duplication
- add comprehensive tests for cubic findings verification
LucasSantana-Dev added a commit that referenced this pull request Jun 10, 2026
## What

Fixes the two failing tests in
`packages/shared/src/__tests__/config/environment.test.ts` and removes
the secret-dump-on-failure hazard. Closes #1262.

## Root cause

- `ensureEnvironment()` → `loadEnvironmentFiles()` → dotenv `config()`
re-populates `process.env` from the repo's real `.env` **after** the
test deletes required vars, so the missing-vars branch never executes on
any machine with a `.env` (promise resolves instead of rejects). dotenv
not overriding existing vars is why the whitespace tests passed while
the delete tests failed.
- The `beforeEach` seeded the fixture with `{...process.env}` (the full
real env), so an unexpected resolve made Jest print the entire env —
every secret — on failure.

## Fix (test-only, no production change)

- Factory-mock `dotenv` in the spec (same pattern as the prismaClient
factory mocks in shared) so the loader can't re-populate the env.
- Replace the fixture with a minimal `{ NODE_ENV: 'test' }` object:
deterministic regardless of ambient env, and a failing assertion can
only print fixture values, never real secrets.

## Verification

- `npm run test:ci --workspace=packages/shared` → **53 suites / 733
tests, all pass** (was 2 failures)
- Full `type:check` across all workspaces green (pre-commit hook)
- Sibling sweep (acceptance #3): no other package has the rejects-on-env
pattern — `sentryTest.spec.ts` asserts on mocks only;
`FeatureToggleService.spec.ts` touches `FLAGS` only

## Note

This failure was invisible to CI because shared tests run nowhere in CI
— #1277 (next PR) adds the test-shared job that would have caught it.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fix failing env tests in shared by isolating `process.env` and mocking
`dotenv`, removing the secret-dump risk on test failures. Addresses
#1262.

- **Bug Fixes**
- Mocked `dotenv.config()` in the spec so the loader can’t repopulate
from the real `.env`.
- Replaced `{...process.env}` with a minimal `{ NODE_ENV: 'test' }`
fixture for deterministic tests and no secret leaks.

<sup>Written for commit 2d45115.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/LucasSantana-Dev/Lucky/pull/1292?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Tests**
* Improved test reliability for environment variable handling by
isolating test environments from system configuration, ensuring
consistent and deterministic test results across different execution
contexts.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
LucasSantana-Dev added a commit that referenced this pull request Jun 15, 2026
…#1457)

Closes #1456.

## Problem

The `Security` CI check (`npm audit --audit-level=high`) fails on
**every open PR** (e.g. #1454, #1455) — the lockfile pins two transitive
deps with high-severity advisories, surfaced by an advisory-DB update.
This blocks the merge queue (priority #3).

## Fix

| package | before | after | advisory |
|---|---|---|---|
| `vite` | 8.0.14 | 8.0.16 | GHSA-fx2h-pf6j-xcff (`server.fs.deny`
bypass), GHSA-v6wh-96g9-6wx3 (launch-editor NTLMv2) |
| `form-data` | 4.0.5 | 4.0.6 | CRLF injection via unescaped multipart
field names |

- `packages/frontend/package.json`: vite devDependency floor `^8.0.14` →
`^8.0.16`. vite 8.0.16 requires rolldown 1.0.3, which accounts for the
bulk of the lockfile churn.
- `package.json`: root `overrides` pin `form-data: ">=4.0.6"`
(transitive, no workspace owner).
- `package-lock.json`: regenerated; `npm audit --audit-level=high` → **0
high** (verified locally).

Both are dev/build-tool deps not shipped to the bot runtime. All four
workspace `type:check`s pass locally with vite 8.0.16. Moderate
advisories remain below the gate and are out of scope.

## Verification

- [x] `npm audit --audit-level=high` exits 0
- [x] `npm run type:check` (shared, bot, backend, frontend) passes
- [ ] CI: Build/Test (all packages), Security

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
  * Updated build tool dependency to latest compatible version.
* Extended dependency override configurations for enhanced
compatibility.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Bump `vite` to 8.0.16 and enforce `form-data` >= 4.0.6 to clear
high-severity advisories and unblock the Security CI gate. Also pin
`vite` at the repo root so `@vitejs/plugin-react` resolves it correctly
during builds.

- **Dependencies**
- Root dev + frontend: `vite` ^8.0.16 (was ^8.0.14); pulls `rolldown`
1.0.3 and `tinyglobby` ^0.2.17.
- Root overrides: `form-data` >= 4.0.6 to fix CRLF injection in
transitive deps.
- Regenerated lockfile; `npm audit --audit-level=high` now reports 0
high.

- **Bug Fixes**
- Fixed hoisting so `@vitejs/plugin-react` resolves the updated `vite`;
`npm run build:frontend` succeeds.

<sup>Written for commit dba6347.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/LucasSantana-Dev/Lucky/pull/1457?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
LucasSantana-Dev added a commit that referenced this pull request Aug 22, 2026
## Problem

`/artist queen` replied `No tracks found for artist **queen**`.

`/artist` hard-pinned `QueryType.SPOTIFY_SEARCH` with **no fallback
arm** (`artist.ts:112`, pre-fix). One provider, one attempt. Any Spotify
hiccup became "this artist does not exist".

Underneath, `discord-player-spotify` collapses every failure to an empty
result with no log:

```js
async search(query) { try { /* ... */ } catch { return null } }   // dist/index.js:280-325
const data = await this.internal.search(query)
if (!data) return this.createResponse()                          // empty tracks[]
```

`/play` already learned this lesson (`3e76068`, "default text search now
uses AUTO_SEARCH instead of SPOTIFY_SEARCH ... without requiring Spotify
credentials to succeed first"). `/artist` and `/album` never got the
same treatment.

## Production evidence

7d Loki (`container_name="lucky-bot"`):

| Signal | 7d |
|---|---|
| `Registered SpotifyExtractor` | 11 |
| `SpotifyExtractor failed to register` / `returned null` | 0 |
| `Failed to retrieve access token` / `Failed to fetch Spotify data` | 0
|
| `Primary search failed, falling back to YouTube` (search layer) | 4 |

Spotify auth and registration are healthy, so this is **not** a
credential outage. It is a transient-zero-result that `/artist` had no
way to absorb. `/play` absorbs the identical event —
`2026-08-21T16:20:09Z`:

```
Primary search failed, falling back to YouTube
{ "query": "Inteligência Marginal 3", "searchEngine": "spotifySearch",
  "error": "NoResultError: No results found ... (Extractor: com.discord-player.itsmaat.spotifyextractor)" }
→ Bridge: streamed via yt-dlp → Started playing "INTELIGÊNCIA MARGINAL #3..."
```

Same class of blip. `/play` recovered and played the track; `/artist`
would have told the user the artist does not exist.

The reported `/artist` invocation produced **zero** log lines in 7 days,
which is why the exact trigger is unrecoverable.

## Change

- `/artist` iterates `SPOTIFY_SEARCH → YOUTUBE_SEARCH →
SOUNDCLOUD_SEARCH`, reusing the `TEXT_SEARCH_BLOCKED_EXTRACTORS` list
`/play` already relies on so Spotify/Attachment extractors cannot
intercept the text-search arms (#1930).
- Every empty or throwing arm `warnLog`s, so a recurrence is queryable:
`{container_name="lucky-bot"} |= "Artist search arm"`. Previously
nothing was emitted at all.
- `No results` is reported only after all three arms are exhausted.
- Playback follows the arm that resolved: `SPOTIFY_SONG` for Spotify,
`AUTO` otherwise, so a YouTube/SoundCloud URL is not re-searched against
Spotify.
- `TEXT_SEARCH_BLOCKED_EXTRACTORS` exported from
`play/handlers/resolveProvider.ts` (no new abstraction, no behavior
change for `/play`).

## Tests

4 new tests in `artist.spec.ts`. Verified all 4 fail on the pre-fix code
and pass after:

1. falls back past an empty Spotify arm instead of reporting "no tracks
found"
2. plays a non-Spotify fallback track with `AUTO` rather than
`SPOTIFY_SONG`
3. reports no results only after every arm is exhausted
4. continues to the next arm when an arm rejects

Monorepo typecheck clean; 144 tests pass across the artist + play
suites.

## Follow-ups (filed, not in this PR)

- #2050 — `/album` has the identical defect. Left out because its
`!searchResult.playlist` branch needs a design call: text search on
YouTube/SoundCloud returns no playlist.
- #2051 — Spotify extractor failures never reach Sentry.
`LogService.warn()` only calls `addBreadcrumb`; solely `error()` calls
`captureMessage` (`log/service.ts:140-167`), and registration failures
use `warnLog`.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Makes /artist resilient to Spotify search failures and keeps artist-only
queues. Previously it pinned SPOTIFY_SEARCH and dropped the artist
filter unless ≥3 matches; now it falls back to YouTube/SoundCloud,
trusts exact author matches at any count, and reports “No results” only
after all arms fail.

- Search fallback: iterates SPOTIFY_SEARCH → YOUTUBE_SEARCH →
SOUNDCLOUD_SEARCH; reuses `TEXT_SEARCH_BLOCKED_EXTRACTORS` to prevent
extractor interception; warn-logs once per arm (thrown vs empty); “No
results” only after all arms fail.
- Playback: uses SPOTIFY_SONG when the Spotify arm resolves; uses AUTO
for non-Spotify results to avoid re-searching resolved URLs.
- Artist filter: exact author matches kept regardless of count; keep ≥3
for word/substring matches; fall back to provider order only when zero
tracks match the artist.
- Shared: exports `TEXT_SEARCH_BLOCKED_EXTRACTORS` from
`packages/bot/src/functions/music/commands/play/handlers/resolveProvider.ts`;
`/play` unchanged.
- Tests: 9 cases covering fallback across arms, single-log semantics,
Spotify vs non-Spotify playback, correct “no results” gating, and
guarding single-token fuzzy matches from hijacking the queue.

<sup>Written for commit 4b80dcd.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/LucasSantana-Dev/Lucky/pull/2052?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Improved artist search with fallback support across Spotify, YouTube,
and SoundCloud.
- Playback now automatically selects the appropriate search method for
results from alternate platforms.
- Artist matching better prioritizes exact matches while retaining
suitable partial matches.

- **Bug Fixes**
- Searches continue after an individual provider fails or returns no
results.
  - Improved handling when no qualifying artist matches are found.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file javascript Pull requests that update javascript code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants