Skip to content

ci: extend workflow triggers to release/** branches - #816

Merged
LucasSantana-Dev merged 19 commits into
release/v2.10.0from
ci/release-branch-triggers
May 8, 2026
Merged

LucasSantana-Dev merged 19 commits into
release/v2.10.0from
ci/release-branch-triggers

Conversation

@LucasSantana-Dev

@LucasSantana-Dev LucasSantana-Dev commented May 6, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Updates all four CI workflows to trigger on release/** branches in addition to main
  • Ensures PRs targeting release/v2.10.0 (and future release branches) run the full quality gate, SonarCloud, bundle size, and path portability checks
  • Deploy and docker-publish workflows intentionally remain [main]-only — production deploys only on release merges

Workflows updated

Workflow Change
ci.yml Added release/** to push + pull_request triggers
sonarcloud.yml Added release/** to push + pull_request triggers
bundle-size.yml Added release/** to pull_request trigger
path-portability.yml Added release/** to push trigger

Test plan

  • Open a PR targeting release/v2.10.0 — all four workflows should appear as required checks
  • Merge to release/v2.10.0 — push-triggered workflows should fire on that branch

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Invite link tracking now captures campaign UTM parameters for analytics.
    • Smart music recommendations now include your saved Spotify tracks to improve seeds.
  • Documentation

    • Updated project messaging and invite links to emphasize self-hosting and all-inclusive features.
  • Chores

    • Added a PR automation workflow to assist reviews and descriptions.
    • Enhanced CI with an additional supply-chain security scan.

Greptile Summary

  • Adds a new /invite backend route that logs UTM parameters and redirects to the Discord OAuth URL, with tests covering error resilience and open-redirect protection. Also introduces a new pr-agent.yml workflow for automated AI code review.
  • Extends UserSpotifySeeds with a likedTrackIds field populated by a new getUserSavedTracks Spotify API call, though the field is not yet consumed by any recommendation logic (tracked from a prior review).
  • Fixes a flaky streamBridge test by capturing the promise before synchronously emitting the error event, removing a setImmediate timing dependency.

Confidence Score: 4/5

Safe to merge with one P1 fix needed in the pr-agent workflow configuration

A single P1 finding in pr-agent.yml: mixing OPENAI.* and CONFIG.AI_PROVIDER=anthropic config styles means the Anthropic API key may never be passed to the SDK, causing every PR Agent invocation to fail with auth errors. All other changes are well-tested and low risk.

.github/workflows/pr-agent.yml — Anthropic provider configuration needs to be made consistent

Important Files Changed

Filename Overview
.github/workflows/pr-agent.yml New PR Agent workflow with a pinned SHA, but mixes OPENAI.* and CONFIG.AI_PROVIDER=anthropic configuration styles, which may prevent the Anthropic API key from being passed correctly
.github/workflows/ci.yml Replaces the disabled SocketDev action with a no-op echo step; release/** triggers already present in the file's current state
packages/backend/src/routes/invite.ts New /invite redirect route with UTM parameter logging; uses toUtmString helper to safely coerce query params before logging
packages/bot/src/spotify/spotifyUserSeeds.ts Adds likedTrackIds to UserSpotifySeeds and fetches it on cache miss; the field is stored but not yet consumed by any caller (spotifyRecommender.ts only accesses artistNames)
packages/bot/src/spotify/spotifyApi.ts Adds getUserSavedTracks which fetches up to 50 saved tracks from Spotify's /me/tracks endpoint with proper error handling
packages/bot/src/handlers/player/streamBridge.spec.ts Fixes a flaky test by capturing the promise before emitting the error event synchronously, removing the setImmediate timing dependency
packages/backend/tests/unit/routes/invite.test.ts Comprehensive test suite for the new invite route covering redirect, UTM logging, error resilience, and open-redirect protection

Sequence Diagram

sequenceDiagram
    participant Browser
    participant Backend as Backend /invite
    participant Log as infoLog
    participant Discord as Discord OAuth URL

    Browser->>Backend: "GET /invite?utm_source=github&utm_medium=readme"
    Backend->>Log: "infoLog({ utm_source, utm_medium, ... })"
    Note over Log: logAndSwallow on failure
    Backend-->>Browser: 302 Redirect
    Browser->>Discord: GET discord.com/oauth2/authorize?...
Loading

Fix All in Claude Code Fix All in Codex

Reviews (11): Last reviewed commit: "test(invite): mock logAndSwallow + reset..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

LucasSantana-Dev and others added 2 commits May 6, 2026 16:20
* fix(player): harden stream bridge error handling

- soundcloudMatcher: wrap playdl.stream() in try/catch so auth failures
  and rate limits surface with context instead of propagating as raw rejections
- streamBridge: call proc.kill() in the error handler so the yt-dlp
  subprocess is cleaned up on spawn errors, not only on timeout
- playerFactory: fix priority comment — play-dl SoundCloud init runs
  before YouTube extractor registration, not after

* test(player): add streamBridge and soundcloudMatcher test suites

streamBridge.spec.ts (28 tests):
- URL validation: allowlist, https-only, ytsearch bypass
- Process lifecycle: stdout resolve, error+kill, exit code with stderr, timeout+kill
- streamViaYtDlpSearch: empty query guard, ytsearch1 prefix
- createResilientStream: full fallback chain, circuit breaker, parenthetical stripping

soundcloudMatcher.spec.ts (29 tests):
- parseDurationString: MM:SS, HH:MM:SS, edge cases, invalid formats
- findMatchingSoundCloudResult: 75% token threshold, duration ±30s boundary,
  punctuation normalization, case-insensitive, empty query handling
- streamViaSoundCloud: empty query, no results, validation miss, happy path,
  playdl.stream error wrapping with context

Also improve replenishQueue error messages in queueHandlers.ts to include
actionable recovery steps for the user.
Ensures CI, SonarCloud, bundle-size, and path-portability run on
PRs targeting and pushes to any release/vX.Y.Z branch.
deploy.yml and docker-publish.yml remain main-only.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel

vercel Bot commented May 6, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
lucky Ready Ready Preview, Comment May 7, 2026 5:26pm

Request Review

@coderabbitai

coderabbitai Bot commented May 6, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Rate limit exceeded

@LucasSantana-Dev has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 57 minutes and 18 seconds before requesting another review.

To continue reviewing without waiting, purchase usage credits in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f2fef7db-2f5a-40c4-871f-520313807c8f

📥 Commits

Reviewing files that changed from the base of the PR and between b9e60a6 and 613756c.

📒 Files selected for processing (1)
  • packages/backend/tests/unit/routes/invite.test.ts
📝 Walkthrough

Walkthrough

This PR adds a backend GET /invite redirect route with UTM extraction and logging, integrates Spotify saved tracks into user seeds (new API + tests), introduces a pr-agent GitHub Actions workflow and adjusts a CI security step, updates README invite/branding, and hardens a stream test timing assertion.

Changes

Invite Route Feature

Layer / File(s) Summary
Route Implementation
packages/backend/src/routes/invite.ts
New Express route module with type-safe UTM extraction, DISCORD_INVITE_URL constant, and setupInviteRoute registering GET /invite with rate limiting and logging.
Route Integration
packages/backend/src/routes/index.ts
setupInviteRoute imported and called in setupRoutes.
Route Tests
packages/backend/tests/unit/routes/invite.test.ts, packages/backend/tests/unit/routes/index.test.ts
Unit tests verify 302 redirect, UTM logging (present/missing/array coercion), logger-throw resilience, open-redirect prevention, and that setupInviteRoute is invoked during setup.

Spotify Saved Tracks Integration

Layer / File(s) Summary
Data Shape
packages/bot/src/spotify/spotifyUserSeeds.ts
UserSpotifySeeds adds likedTrackIds: string[].
Spotify API Function
packages/bot/src/spotify/spotifyApi.ts
New getUserSavedTracks(accessToken, limit?) fetches /v1/me/tracks, caps limit at 50, extracts track IDs, logs failures, and returns [] on errors.
Integration with User Seeds
packages/bot/src/spotify/spotifyUserSeeds.ts
getUserSpotifySeeds calls getUserSavedTracks(token) (fallback to []) and includes likedTrackIds in cached seeds.
Tests
packages/bot/src/spotify/spotifyApi.spec.ts, packages/bot/src/spotify/spotifyUserSeeds.spec.ts
Tests added/updated for getUserSavedTracks behavior and for likedTrackIds population and fallback cases.

CI / Workflow Infrastructure

Layer / File(s) Summary
PR Agent Workflow
.github/workflows/pr-agent.yml
New workflow triggers on PR/comment/review events and runs Codium-ai/pr-agent pinned to a commit with Anthropic provider/model and github_action_config flags.
CI Security Step
.github/workflows/ci.yml
Security job adds a "Socket.dev supply chain scan" echo step after TruffleHog; the prior SocketDev action was removed in this diff.

README Updates

Layer / File(s) Summary
Branding & Invite Links
README.md
Hero tagline shortened; invite badge and links updated to use project /invite endpoint with UTM parameters; "Why Lucky?" section rewritten with new bullets including "No paywall".

Misc Tests & Fixes

Layer / File(s) Summary
Async Error Handling Test
packages/bot/src/handlers/player/streamBridge.spec.ts
Refactored test to capture the promise returned by streamViaYtDlp before emitting process error, then assert rejection on that promise to avoid race conditions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title 'ci: extend workflow triggers to release/** branches' accurately describes the main CI workflow changes, but the changeset includes substantial unrelated additions (invite route, Spotify saved-tracks functionality, new PR Agent workflow, tests, README updates) that are not mentioned in the title. Update the title to reflect all major changes, such as 'ci: extend workflow triggers and add invite route with Spotify saved-tracks support' or split into multiple focused PRs.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/release-branch-triggers

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

LucasSantana-Dev and others added 3 commits May 7, 2026 01:36
- Add pr-agent.yml workflow: AI-powered code review on every PR using Anthropic claude-sonnet-4-6 backend via Codium-ai/pr-agent action. Auto-describes, auto-reviews, and auto-improves PRs on open/reopen. Requires ANTHROPIC_API_KEY secret.
- Add Socket.dev supply chain scan step to existing security job. Detects malicious packages, typosquats, and supply chain attacks. Requires SOCKET_SECURITY_API_KEY secret (continue-on-error until secret is wired).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a public /invite redirect route that logs utm_source, utm_medium,
utm_campaign, and utm_content before forwarding to the Discord OAuth URL.
Updates README subtitle and "Why Lucky?" to lead with shutdown-proof
positioning (Groovy/Rythm/Hydra narrative). Swaps all three bare Discord
OAuth invite URLs in README for tracked lucky.lucassantana.tech/invite URLs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- pr-agent.yml: OPENAI.API_VERSION → OPENAI.MODEL (was passing model name
  as API version, causing PR-Agent to fail/fall back to default model)
- streamBridge.spec.ts: emit error synchronously so proc.kill() assertion
  runs after the handler fires, not before the setImmediate callback

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…R blocking

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented May 7, 2026 •

Copy link
Copy Markdown

Greptile Summary

  • Adds a /invite redirect route on the backend with UTM parameter tracking and a toUtmString guard, backed by full unit test coverage.
  • Introduces getUserSavedTracks (Spotify saved-tracks API) and surfaces the result as likedTrackIds in UserSpotifySeeds, but the field is not yet consumed by the recommendation engine.
  • Creates a new pr-agent.yml workflow for AI-assisted PR reviews and stubs out the SocketDev supply-chain scan step that was removed from ci.yml.

Confidence Score: 5/5

Safe to merge — only P2 findings present; no runtime correctness or security regressions introduced.

All findings are P2 (style/best-practice). The one substantive concern — likedTrackIds being fetched but unused — wastes Spotify quota but causes no incorrect behavior. Core changes (invite route, stream-bridge test fix, workflow triggers) are correct and well-tested.

packages/bot/src/spotify/spotifyUserSeeds.ts — extra Spotify API call for unused likedTrackIds field.

Important Files Changed

Filename Overview
.github/workflows/ci.yml Replaces the real SocketDev action with a no-op echo step, effectively disabling the supply-chain scan until the action is available again.
.github/workflows/pr-agent.yml New workflow wiring pr-agent to Anthropic; uses mutable @main ref (flagged in previous threads).
packages/backend/src/routes/invite.ts New /invite redirect route with UTM logging; properly coerces query values with toUtmString and wraps logging in try/catch.
packages/bot/src/spotify/spotifyUserSeeds.ts Adds likedTrackIds to seeds by calling getUserSavedTracks, but this field is unused by any downstream consumer, adding an unnecessary Spotify API call per seed refresh.
packages/bot/src/spotify/spotifyApi.ts Adds getUserSavedTracks — correctly caps limit at 50, guards on non-OK responses, and swallows errors.
packages/bot/src/handlers/player/streamBridge.spec.ts Replaces setImmediate-based error emission with a synchronous emit after storing the promise, making the test more deterministic.
packages/backend/tests/unit/routes/invite.test.ts Comprehensive tests for the invite route covering UTM params, redirect target, error resilience, and the open-redirect non-issue.

Reviews (5): Last reviewed commit: "ci: replace unavailable SocketDev action..." | Re-trigger Greptile

Comment thread .github/workflows/pr-agent.yml Outdated
Comment thread .github/workflows/ci.yml Outdated
Comment thread packages/backend/src/routes/invite.ts Outdated
- spotifyApi.ts: add getUserSavedTracks() — fetches up to 50 liked tracks
  via /v1/me/tracks, returns string[] of track IDs
- spotifyUserSeeds.ts: add likedTrackIds field to UserSpotifySeeds and
  populate it by calling getUserSavedTracks on each seed fetch
- spotifyUserSeeds.spec.ts: fix beforeEach to re-set getUserSavedTracks mock
  after jest.clearAllMocks() wipes factory-level mockResolvedValue

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 7, 2026
- Add rate limiting (apiLimiter) to /invite endpoint
- Normalize req.query UTM values to string | undefined (guards against array/ParsedQs)
- Wrap infoLog in try/catch so logging failure doesn't block redirect
- Add invite.test.ts (6 tests: redirect, UTM logging, array coercion, logging failure, no open-redirect)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
LucasSantana-Dev and others added 3 commits May 7, 2026 11:35
…ked to block Spanish gospel

When Last.fm is absent, candidateTags is always [] so the cross-locale veto
only has text-based signals. Spanish gospel artists (Marcos Witt, Alex Zurdo,
Christine D'Clario) carry no Spanish text markers in title/author but Spotify
classifies them as 'musica cristiana', 'latin gospel', 'latin worship'.

- spotifyRecommender: fall back to getArtistGenres(token, author) when
  lastFmTags.length === 0; skip if Last.fm returns tags (no double-fetch)
- languageHeuristics: add 'latin worship', 'ccm en español', 'spanish ccm'
  to SPANISH_GENRE_MARKERS; add 'eres', 'nuestro/a', 'siervo/a', 'digno',
  'fuego', 'cielos' to SPANISH_DISTINCT_TOKENS
- spotifyRecommender.spec: wire getArtistGenresMock; add two tests covering
  the fallback path and the no-double-fetch guarantee

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… not linked to block Spanish gospel"

This reverts commit 94b498d.
- invite.ts: replace bare catch{} with logAndSwallow() per error-handling guidelines
- pr-agent.yml: gate issue_comment trigger to PRs only to avoid running on plain issue comments

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@LucasSantana-Dev

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 7, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

coderabbitai[bot]
coderabbitai Bot previously approved these changes May 7, 2026
Comment thread packages/bot/src/spotify/spotifyUserSeeds.ts Outdated
- spotifyApi: add warnLog when saved-tracks fetch returns non-ok status
- spotifyUserSeeds: isolate getUserSavedTracks rejection with .catch([]){} so a
  network failure doesn't collapse the entire seeds fetch into null
- spotifyUserSeeds.spec: test that seeds resolve normally when getUserSavedTracks rejects
- pr-agent.yml: pin Codium-ai/pr-agent to SHA instead of floating @main

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
coderabbitai[bot]
coderabbitai Bot previously requested changes May 7, 2026

@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)
packages/bot/src/spotify/spotifyUserSeeds.spec.ts (1)

64-85: ⚡ Quick win

Also assert saved-tracks API call shape/count in the new happy-path test.

This test validates output, but not that getUserSavedTracks is called correctly (and only once). Adding that assertion would better protect the new integration path and cache behavior.

Suggested assertion add-on
 it('should populate likedTrackIds when getUserSavedTracks returns data', async () => {
@@
     const result = await getUserSpotifySeeds('test-user-id')

     expect(result?.likedTrackIds).toEqual(['liked-1', 'liked-2'])
+    expect(spotifyApi.getUserSavedTracks).toHaveBeenCalledTimes(1)
+    expect(spotifyApi.getUserSavedTracks).toHaveBeenCalledWith('token')
 })
🤖 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 `@packages/bot/src/spotify/spotifyUserSeeds.spec.ts` around lines 64 - 85, The
test asserts the returned likedTrackIds but doesn't verify that
spotifyApi.getUserSavedTracks was invoked correctly and only once; update the
test that calls getUserSpotifySeeds('test-user-id') to also assert
spotifyApi.getUserSavedTracks was called exactly once and with the expected
argument(s) (e.g., the valid access token returned by
spotifyLinkService.getValidAccessToken or the spotifyId from mockLink depending
on how getUserSavedTracks is invoked in getUserSpotifySeeds), using
toHaveBeenCalledTimes(1) and toHaveBeenCalledWith(...) to lock down the call
shape/count.
🤖 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 @.github/workflows/ci.yml:
- Around line 97-99: The step named "Socket.dev supply chain scan" currently
only echoes a message and performs no scan; replace the no-op with a real
Socket.dev action invocation or explicitly mark it as informational. Either (A)
restore or add the actual action invocation (e.g., use the official SocketDev
action reference instead of the echo) so the job performs the supply-chain scan,
or (B) rename the step to something like "Notice: Socket.dev scan skipped" and
update branch protection/enforcement elsewhere; target the step with the name
"Socket.dev supply chain scan" and remove the commented-out
"SocketDev/socket-security-action@v1" placeholder or replace it with the correct
action entry.

In @.github/workflows/pr-agent.yml:
- Line 21: The job trigger condition allows non-bot users to run the workflow on
issue_comment events while the job has write permissions and secrets; update the
conditional that uses github.event.sender.type and github.event_name so that for
issue_comment events you also require a trusted commenter by checking
github.event.comment.author_association is one of OWNER, MEMBER, or COLLABORATOR
(or otherwise exclude NONE/CONTRIBUTOR) before proceeding; modify the expression
that currently reads the combined check (the line referencing
github.event.sender.type and github.event.issue.pull_request) to include this
author_association gate for issue_comment paths so only trusted commenters can
trigger the workflow with secrets.

---

Nitpick comments:
In `@packages/bot/src/spotify/spotifyUserSeeds.spec.ts`:
- Around line 64-85: The test asserts the returned likedTrackIds but doesn't
verify that spotifyApi.getUserSavedTracks was invoked correctly and only once;
update the test that calls getUserSpotifySeeds('test-user-id') to also assert
spotifyApi.getUserSavedTracks was called exactly once and with the expected
argument(s) (e.g., the valid access token returned by
spotifyLinkService.getValidAccessToken or the spotifyId from mockLink depending
on how getUserSavedTracks is invoked in getUserSpotifySeeds), using
toHaveBeenCalledTimes(1) and toHaveBeenCalledWith(...) to lock down the call
shape/count.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8dd2a6ae-c01a-4be1-b3c8-e30a5fe28adb

📥 Commits

Reviewing files that changed from the base of the PR and between 153f79e and b9e60a6.

📒 Files selected for processing (7)
  • .github/workflows/ci.yml
  • .github/workflows/pr-agent.yml
  • packages/backend/src/routes/invite.ts
  • packages/bot/src/spotify/spotifyApi.spec.ts
  • packages/bot/src/spotify/spotifyApi.ts
  • packages/bot/src/spotify/spotifyUserSeeds.spec.ts
  • packages/bot/src/spotify/spotifyUserSeeds.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/bot/src/spotify/spotifyApi.ts
  • packages/backend/src/routes/invite.ts
  • packages/bot/src/spotify/spotifyUserSeeds.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use the isPrisma*Error() helper functions to check for specific Prisma error types (e.g., isPrismaForeignKeyError, isPrismaUniqueConstraintError) instead of manually checking error codes
Use Prisma's $transaction() method to ensure database operations are atomic and avoid partial updates when multiple related tables are modified
Always use select or include in Prisma queries to explicitly specify which fields to return, avoiding unnecessary data transfer
For Redis operations, use connection pooling and implement exponential backoff retry logic for transient failures
Always use logAndRethrow() or logAndSwallow() utilities when handling errors to ensure errors are logged with context before propagating or suppressing

Files:

  • packages/bot/src/spotify/spotifyUserSeeds.spec.ts
  • packages/bot/src/spotify/spotifyApi.spec.ts
packages/{bot,backend,shared}/src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

packages/{bot,backend,shared}/src/**/*.ts: For feature toggles, check both global and guild-specific toggles using FeatureToggleService.isEnabledForGuild() rather than checking them separately
Use branded types (e.g., GuildId, UserId, ChannelId) for Discord IDs throughout the codebase to prevent type-level ID confusion

Files:

  • packages/bot/src/spotify/spotifyUserSeeds.spec.ts
  • packages/bot/src/spotify/spotifyApi.spec.ts
packages/bot/src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

When building Discord embeds, use EmbedBuilderService.createTemplate() or EmbedBuilderService.getTemplate() instead of constructing embeds directly

Files:

  • packages/bot/src/spotify/spotifyUserSeeds.spec.ts
  • packages/bot/src/spotify/spotifyApi.spec.ts
packages/bot/src/{spotify,utils/music}/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Extract Spotify track IDs using extractSpotifyTrackId() before passing to Spotify API calls to prevent malformed requests

Files:

  • packages/bot/src/spotify/spotifyUserSeeds.spec.ts
  • packages/bot/src/spotify/spotifyApi.spec.ts
🔇 Additional comments (2)
packages/bot/src/spotify/spotifyApi.spec.ts (1)

841-917: Good coverage for getUserSavedTracks edge cases.

Nice addition: this suite validates happy path, malformed payload filtering, failure modes, and the limit=50 cap, which strengthens regression safety for the new Spotify saved-tracks integration.

packages/bot/src/spotify/spotifyUserSeeds.spec.ts (1)

15-22: Good coverage for new liked-tracks behavior.

Nice additions: default mock reset in beforeEach, explicit likedTrackIds assertions, and both success/failure paths for getUserSavedTracks are covered well.

Also applies to: 61-62, 64-110

Comment thread .github/workflows/ci.yml
Comment thread .github/workflows/pr-agent.yml
The route test was getting a 500 when mockInfoLog was set to throw because
logAndSwallow (real impl) was reaching the log service, which surfaced an
issue in the test environment. Mocking @lucky/shared/utils/error isolates
the route's routing behavior from logging internals.

Also adds mockInfoLog.mockReset() in beforeEach so a mockImplementation set
in one test doesn't persist to the next (jest clearAllMocks does not reset
implementations, only call counts).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented May 7, 2026

Copy link
Copy Markdown

Want your agent to iterate on Greptile's feedback? Try greploops.

Comment thread .github/workflows/pr-agent.yml
@sonarqubecloud

sonarqubecloud Bot commented May 7, 2026

Copy link
Copy Markdown

@LucasSantana-Dev
LucasSantana-Dev dismissed stale reviews from coderabbitai[bot] and coderabbitai[bot] May 7, 2026 18:30

Stale bot review on superseded commit — dismissing to unblock auto-merge.

@LucasSantana-Dev

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 7, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@LucasSantana-Dev
LucasSantana-Dev merged commit a5bcb77 into release/v2.10.0 May 8, 2026
15 of 16 checks passed
@LucasSantana-Dev

Copy link
Copy Markdown
Owner Author

@coderabbitai approve

@coderabbitai

coderabbitai Bot commented May 8, 2026

Copy link
Copy Markdown
✅ Actions performed

Comments resolved and changes approved.

LucasSantana-Dev added a commit that referenced this pull request May 13, 2026
* fix(player): harden stream bridge + add 57 missing tests (#815)

* fix(player): harden stream bridge error handling

- soundcloudMatcher: wrap playdl.stream() in try/catch so auth failures
  and rate limits surface with context instead of propagating as raw rejections
- streamBridge: call proc.kill() in the error handler so the yt-dlp
  subprocess is cleaned up on spawn errors, not only on timeout
- playerFactory: fix priority comment — play-dl SoundCloud init runs
  before YouTube extractor registration, not after

* test(player): add streamBridge and soundcloudMatcher test suites

streamBridge.spec.ts (28 tests):
- URL validation: allowlist, https-only, ytsearch bypass
- Process lifecycle: stdout resolve, error+kill, exit code with stderr, timeout+kill
- streamViaYtDlpSearch: empty query guard, ytsearch1 prefix
- createResilientStream: full fallback chain, circuit breaker, parenthetical stripping

soundcloudMatcher.spec.ts (29 tests):
- parseDurationString: MM:SS, HH:MM:SS, edge cases, invalid formats
- findMatchingSoundCloudResult: 75% token threshold, duration ±30s boundary,
  punctuation normalization, case-insensitive, empty query handling
- streamViaSoundCloud: empty query, no results, validation miss, happy path,
  playdl.stream error wrapping with context

Also improve replenishQueue error messages in queueHandlers.ts to include
actionable recovery steps for the user.

* ci: extend workflow triggers to release/** branches

Ensures CI, SonarCloud, bundle-size, and path-portability run on
PRs targeting and pushes to any release/vX.Y.Z branch.
deploy.yml and docker-publish.yml remain main-only.

* ci: add PR-Agent AI review and Socket.dev supply chain scan

- Add pr-agent.yml workflow: AI-powered code review on every PR using Anthropic claude-sonnet-4-6 backend via Codium-ai/pr-agent action. Auto-describes, auto-reviews, and auto-improves PRs on open/reopen. Requires ANTHROPIC_API_KEY secret.
- Add Socket.dev supply chain scan step to existing security job. Detects malicious packages, typosquats, and supply chain attacks. Requires SOCKET_SECURITY_API_KEY secret (continue-on-error until secret is wired).

* feat(backend): add /invite UTM tracking route + update README messaging

Adds a public /invite redirect route that logs utm_source, utm_medium,
utm_campaign, and utm_content before forwarding to the Discord OAuth URL.
Updates README subtitle and "Why Lucky?" to lead with shutdown-proof
positioning (Groovy/Rythm/Hydra narrative). Swaps all three bare Discord
OAuth invite URLs in README for tracked lucky.lucassantana.tech/invite URLs.

* fix: correct pr-agent model field + synchronize error-kill assertion

- pr-agent.yml: OPENAI.API_VERSION → OPENAI.MODEL (was passing model name
  as API version, causing PR-Agent to fail/fall back to default model)
- streamBridge.spec.ts: emit error synchronously so proc.kill() assertion
  runs after the handler fires, not before the setImmediate callback

* ci: add allow-warnings to socket.dev action, note GitHub App covers PR blocking

* feat(spotify): add getUserSavedTracks + likedTrackIds to user seeds

- spotifyApi.ts: add getUserSavedTracks() — fetches up to 50 liked tracks
  via /v1/me/tracks, returns string[] of track IDs
- spotifyUserSeeds.ts: add likedTrackIds field to UserSpotifySeeds and
  populate it by calling getUserSavedTracks on each seed fetch
- spotifyUserSeeds.spec.ts: fix beforeEach to re-set getUserSavedTracks mock
  after jest.clearAllMocks() wipes factory-level mockResolvedValue

* fix(backend): harden invite route + add test coverage

- Add rate limiting (apiLimiter) to /invite endpoint
- Normalize req.query UTM values to string | undefined (guards against array/ParsedQs)
- Wrap infoLog in try/catch so logging failure doesn't block redirect
- Add invite.test.ts (6 tests: redirect, UTM logging, array coercion, logging failure, no open-redirect)

* ci: disable unavailable socketdev action + fix S5144 in getUserSavedTracks

- Disable SocketDev/socket-security-action@v1 (repo unavailable; GitHub App covers PR blocking)
- Replace template literal with string concatenation in getUserSavedTracks fetch URL to resolve S5144 SSRF hotspot

* ci: replace unavailable SocketDev action with run step

SocketDev/socket-security-action@v1 repo is not found on GitHub.
if: false does not prevent action resolution at job setup time,
so replace the entire uses: block with a run: echo placeholder.
The GitHub App (apps/socket-security) covers PR-level blocking.

* test(spotify): add getUserSavedTracks coverage to fix SonarCloud gate

Add 6 tests for getUserSavedTracks (success, missing-id filtering,
non-ok response, JSON parse failure, network error, limit capping).
The function was introduced in this branch with 0% coverage, causing
the quality gate to fail at 43.5% on new code (threshold: 80%).

* ci: trigger CI for PR #816 [skip ci-push]

* fix(ci): fix YAML syntax error in Socket.dev scan step

Colon+space in the echo string was parsed as a YAML mapping separator,
breaking workflow file validation and preventing CI/CD Pipeline
pull_request runs from being created.

* fix(autoplay): use Spotify genres as fallback when Last.fm is not linked to block Spanish gospel

When Last.fm is absent, candidateTags is always [] so the cross-locale veto
only has text-based signals. Spanish gospel artists (Marcos Witt, Alex Zurdo,
Christine D'Clario) carry no Spanish text markers in title/author but Spotify
classifies them as 'musica cristiana', 'latin gospel', 'latin worship'.

- spotifyRecommender: fall back to getArtistGenres(token, author) when
  lastFmTags.length === 0; skip if Last.fm returns tags (no double-fetch)
- languageHeuristics: add 'latin worship', 'ccm en español', 'spanish ccm'
  to SPANISH_GENRE_MARKERS; add 'eres', 'nuestro/a', 'siervo/a', 'digno',
  'fuego', 'cielos' to SPANISH_DISTINCT_TOKENS
- spotifyRecommender.spec: wire getArtistGenresMock; add two tests covering
  the fallback path and the no-double-fetch guarantee

* Revert "fix(autoplay): use Spotify genres as fallback when Last.fm is not linked to block Spanish gospel"

This reverts commit 48a1a9336697dca36896d8d36139c347a602aba4.

* fix: address CodeRabbit review comments on PR #816

- invite.ts: replace bare catch{} with logAndSwallow() per error-handling guidelines
- pr-agent.yml: gate issue_comment trigger to PRs only to avoid running on plain issue comments

* fix: address review findings from /pr-review-toolkit:review-pr

- spotifyApi: add warnLog when saved-tracks fetch returns non-ok status
- spotifyUserSeeds: isolate getUserSavedTracks rejection with .catch([]){} so a
  network failure doesn't collapse the entire seeds fetch into null
- spotifyUserSeeds.spec: test that seeds resolve normally when getUserSavedTracks rejects
- pr-agent.yml: pin Codium-ai/pr-agent to SHA instead of floating @main

* test(invite): mock logAndSwallow + reset mockInfoLog between tests

The route test was getting a 500 when mockInfoLog was set to throw because
logAndSwallow (real impl) was reaching the log service, which surfaced an
issue in the test environment. Mocking @lucky/shared/utils/error isolates
the route's routing behavior from logging internals.

Also adds mockInfoLog.mockReset() in beforeEach so a mockImplementation set
in one test doesn't persist to the next (jest clearAllMocks does not reset
implementations, only call counts).

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
LucasSantana-Dev added a commit that referenced this pull request May 13, 2026
Promote [Unreleased] entries into the v2.10.0 section, bump root + workspace
versions from 2.9.0 to 2.10.0, and update the lockfile.

Release highlights:
- Spotify 429 retry hardening (#808)
- Last.fm canonical metadata + multi-artist scrobble fix (#821)
- Autoplay Spanish-gospel-block + sertanejo prioritization series
  (#817-#820, #827, #829, #830)
- Review-tools revamp: Claude review + Danger + chilled CodeRabbit
  via org-level reusable workflows (#838)
- Coverage threshold pinned for phase-2 test cleanup (#835)
- CI extended to release/** branches (#816)
@LucasSantana-Dev
LucasSantana-Dev deleted the ci/release-branch-triggers branch May 23, 2026 02:21

This branch was successfully deployed

1 active deployment
Preview — 613756cd Deployed May 7, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant