Skip to content

refactor(shared): split GuildAutomationService into Orchestrator + Repository - #982

Merged
LucasSantana-Dev merged 4 commits into
mainfrom
refactor/guild-automation-orchestrator-repo
May 24, 2026
Merged

LucasSantana-Dev merged 4 commits into
mainfrom
refactor/guild-automation-orchestrator-repo

Conversation

@LucasSantana-Dev

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

Copy link
Copy Markdown
Owner

What

Splits the monolithic guildAutomation/service.ts (535 LOC) into four focused modules:

  • IGuildAutomationRepository.ts — interface for all DB operations
  • GuildAutomationRepository.ts — Prisma implementation (~329 LOC)
  • GuildAutomationOrchestrator.ts — business logic with injected repository (~301 LOC)
  • service.ts — dependency wiring + public API re-exports (65 LOC)
  • guildAutomationHelpers.ts — shared JSON helpers (toJsonValue, toManifestDocument, isObject)

Why

The monolith mixed Prisma calls, business logic, and lock management in one class. Splitting behind an interface:

  • Makes the orchestrator unit-testable with a mock repository
  • Isolates all DB calls to one layer (easier to audit)
  • Removes the unsafe bare as Prisma.InputJsonValue cast (now runtime-validated via JSON round-trip)

Impact

Zero breaking changes. Public API (guildAutomationService + all exported functions/types) is identical. No caller files modified.

Summary by CodeRabbit

  • New Features
    • Per-guild locking to prevent concurrent automation runs.
    • Automated plan creation with drift detection and severity tracking.
    • Manifest validation and captured-state recording.
    • Protected-operation safeguards to block risky changes unless allowed.
    • Cutover flow gated by a parity checklist with opt-in completion.
    • Run history, status, and diagnostics tracking with detailed run records.

Review Change Stack

…pository

- Create IGuildAutomationRepository interface for DB operations
- Implement GuildAutomationRepository with all Prisma calls
- Extract business logic into GuildAutomationOrchestrator
- Slim service.ts to create dependency graph and export singleton

Public API unchanged: guildAutomationService methods work identically.
All tests pass. TypeScript strict mode enforced.
…d module

- Extract toManifestDocument(), toJsonValue(), and isObject() to guildAutomationHelpers.ts
- Remove duplicate implementations from GuildAutomationRepository and GuildAutomationOrchestrator
- Fix unsafe cast in toJsonValue(): now round-trips through JSON.stringify/parse for runtime validation
- Unify guard logic across both consumers (GuildAutomationRepository, GuildAutomationOrchestrator)
@vercel

vercel Bot commented May 24, 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 24, 2026 2:13am

Request Review

@greptile-apps greptile-apps 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.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@github-actions github-actions Bot added dependencies Pull requests that update a dependency file shared size/xl labels May 24, 2026
@github-actions

Copy link
Copy Markdown

Failed to generate code suggestions for PR

@github-actions

github-actions Bot commented May 24, 2026 •

Copy link
Copy Markdown

Size Change: 0 B

Total Size: 424 kB

ℹ️ View Unchanged
Filename Size
packages/frontend/dist/assets/Admin-BNVD3hM_.js 2.31 kB
packages/frontend/dist/assets/api-D7ggJ795.js 3.37 kB
packages/frontend/dist/assets/AutoMessages-DLQriTl8.js 2.66 kB
packages/frontend/dist/assets/AutoMod-DOSUYPNu.js 4.08 kB
packages/frontend/dist/assets/badge-BOr391aG.js 501 B
packages/frontend/dist/assets/Card-CExedsh4.js 506 B
packages/frontend/dist/assets/Changelog-DCj1i4d5.js 29.1 kB
packages/frontend/dist/assets/CommandsConfig-Bm3-HqmZ.js 1.46 kB
packages/frontend/dist/assets/Config-Cv7bD-2A.js 1.93 kB
packages/frontend/dist/assets/CustomCommands-DJW3KraY.js 2.11 kB
packages/frontend/dist/assets/DashboardOverview-DFlx7drT.js 3.9 kB
packages/frontend/dist/assets/dialog-D7uwzeNK.js 949 B
packages/frontend/dist/assets/Docs-C7mK_7E-.js 17.6 kB
packages/frontend/dist/assets/DocsShell-C9r5i_PN.js 1.42 kB
packages/frontend/dist/assets/EmbedBuilder-CTGiIdtL.js 3.32 kB
packages/frontend/dist/assets/Features-CkPtz7IA.js 755 B
packages/frontend/dist/assets/GuildAutomation-D4LMWATL.js 2.86 kB
packages/frontend/dist/assets/index-B9JDDOCt.js 54.8 kB
packages/frontend/dist/assets/index-lylX54iU.css 17.7 kB
packages/frontend/dist/assets/input-CdbkToCC.js 465 B
packages/frontend/dist/assets/label-CpwYElB3.js 476 B
packages/frontend/dist/assets/Landing-DhnmrLru.js 5.05 kB
packages/frontend/dist/assets/LastFm-CdmPqZ51.js 1.94 kB
packages/frontend/dist/assets/legalNav-B6k3CWsW.js 274 B
packages/frontend/dist/assets/Levels-QpqHlEY0.js 2.62 kB
packages/frontend/dist/assets/Login-CXxKH7-Y.js 2.5 kB
packages/frontend/dist/assets/Lyrics-DIOIM7bO.js 1.33 kB
packages/frontend/dist/assets/Moderation-DWAG6yue.js 3.82 kB
packages/frontend/dist/assets/Music-BDH-qxPB.js 7.1 kB
packages/frontend/dist/assets/MusicConfig-DLe9d0iT.js 1.6 kB
packages/frontend/dist/assets/PreferredArtists-Baz6l6IP.js 3.75 kB
packages/frontend/dist/assets/PrivacyPolicy-Dsc3hsYh.js 1.77 kB
packages/frontend/dist/assets/ReactionRoles-Byj_vQbC.js 1.87 kB
packages/frontend/dist/assets/rolldown-runtime-Cyuzqnbw.js 471 B
packages/frontend/dist/assets/SectionHeader-DGCF9Nny.js 896 B
packages/frontend/dist/assets/select-D8Ujnv3z.js 1.22 kB
packages/frontend/dist/assets/ServerLogs-BTwTXZR-.js 2.88 kB
packages/frontend/dist/assets/ServerSettings-lEGJMzr7.js 4.19 kB
packages/frontend/dist/assets/ServersPage-B9NK6weO.js 2.99 kB
packages/frontend/dist/assets/Skeleton-C4v6hFVb.js 238 B
packages/frontend/dist/assets/Spotify-Bc20xeUf.js 1.94 kB
packages/frontend/dist/assets/Starboard-Cg1D4UZH.js 2.06 kB
packages/frontend/dist/assets/StatTile-ab7MhX_s.js 637 B
packages/frontend/dist/assets/switch-C2AiGEsh.js 544 B
packages/frontend/dist/assets/TermsOfService-BouLR3Fa.js 1.61 kB
packages/frontend/dist/assets/TrackHistory-BZDxvowH.js 2.16 kB
packages/frontend/dist/assets/TwitchNotifications-Cw84kF1n.js 2.44 kB
packages/frontend/dist/assets/useActiveHeading-DLGm_mUR.js 1.35 kB
packages/frontend/dist/assets/useFeatures-D1M1HABb.js 2.03 kB
packages/frontend/dist/assets/usePageMetadata-DTv-6eVb.js 327 B
packages/frontend/dist/assets/vendor-forms-C-bof8GF.js 25.9 kB
packages/frontend/dist/assets/vendor-radix-CdD3qYv_.js 38.9 kB
packages/frontend/dist/assets/vendor-react-2NHyFaPT.js 55.7 kB
packages/frontend/dist/assets/vendor-state-Bw5Cn1Hd.js 24.2 kB
packages/frontend/dist/assets/vendor-ui-B2w0d3pe.js 65.5 kB

compressed-size-action

@coderabbitai

coderabbitai Bot commented May 24, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

@LucasSantana-Dev, we couldn't start this review because you've used your available PR reviews for now.

Your plan currently allows 1 review/hour. Refill in 53 minutes and 40 seconds.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more review capacity refills, 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 trial, open-source, and free plans. In all cases, review capacity refills continuously over time.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 64bc4145-2818-4584-b860-2dd86152f791

📥 Commits

Reviewing files that changed from the base of the PR and between f38da75 and f22d341.

📒 Files selected for processing (1)
  • packages/shared/src/services/guildAutomation/GuildAutomationRepository.ts
📝 Walkthrough

Walkthrough

This PR refactors guild automation into a repository interface, a Prisma-backed repository implementation, runtime validation/serialization helpers, and a stateful GuildAutomationOrchestrator with per-guild locking, plan/apply/cutover workflows, and run lifecycle management.

Changes

Guild Automation Orchestrator & Repository

Layer / File(s) Summary
Repository interface and validation helpers
packages/shared/src/services/guildAutomation/IGuildAutomationRepository.ts, packages/shared/src/services/guildAutomation/guildAutomationHelpers.ts
IGuildAutomationRepository defines the persistence contract for manifests, captures, runs, drift, status, and cutovers. Helpers isObject, toManifestDocument, and toJsonValue provide runtime validation and Prisma JSON serialization.
Prisma-backed repository implementation
packages/shared/src/services/guildAutomation/GuildAutomationRepository.ts
GuildAutomationRepository implements manifest upsert/read, recordCapture, createPlanRecord, per-module upsertDrift, run status transitions (updateRunStatus, markRunFailure, completeRun), getStatus aggregation, runCutover, listRuns, and createBlockedCutoverRun.
Orchestrator initialization, locking, and basic lifecycle
packages/shared/src/services/guildAutomation/GuildAutomationOrchestrator.ts (lines 1–63, 229–293)
Adds in-memory per-guild locks with TTL and cleanup; provides saveManifest, getManifest, recordCapture, getStatus, and listRuns delegating to repository.
Plan creation and apply execution
packages/shared/src/services/guildAutomation/GuildAutomationOrchestrator.ts (lines 74–205)
createPlan derives desired vs actual state, runs createAutomationPlan, computes module drift/severity, upserts drift, and creates plan record. createApplyRun acquires lock, builds plan, blocks or proceeds based on protected operations and allowProtected, updates run status, and releases lock in a finally block.
Cutover workflow and run management
packages/shared/src/services/guildAutomation/GuildAutomationOrchestrator.ts (lines 207–289)
runCutover enforces a parity checklist and may create a blocked cutover run unless completeChecklist is true; if allowed, it marks the manifest cutoverReady and invokes repository runCutover. Run-management helpers (markRunFailure, completeRun, updateRunStatus) forward to repository.
Service module refactoring and helper updates
packages/shared/src/services/guildAutomation/service.ts
Replaces the in-file service with composition: initializes Prisma, constructs GuildAutomationRepository, and exports GuildAutomationOrchestrator instance; parseManifestForDiff validates object shape; createAutomationPlanWithDefaults dynamically imports the plan generator and accepts schema-parse typed values.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Orchestrator as GuildAutomationOrchestrator
  participant Repository as GuildAutomationRepository
  participant PlanGen as createAutomationPlan
  Client->>Orchestrator: createApplyRun(guildId)
  Orchestrator->>Orchestrator: acquireLock(guildId)
  Orchestrator->>Repository: getManifestRow(guildId)
  Repository-->>Orchestrator: manifest + lastCapturedState
  Orchestrator->>PlanGen: createAutomationPlan(desired, actual)
  PlanGen-->>Orchestrator: plan + operations + protectedOperations
  alt protectedOperations && !allowProtected
    Orchestrator->>Repository: createPlanRecord(..., status=blocked)
  else
    Orchestrator->>Repository: createPlanRecord(..., status=running)
  end
  Orchestrator->>Orchestrator: releaseLock(guildId)
  Orchestrator-->>Client: runMetadata + plan
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • LucasSantana-Dev/Lucky#171: Introduces the original shared guildAutomation/service.ts lifecycle and backend wiring that this PR refactors into the new orchestrator and repository architecture.
  • LucasSantana-Dev/Lucky#179: Overlaps changes to guild automation apply/reconcile locking and execution flow; both PRs touch the shared orchestration layer.

Suggested labels

database

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
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 (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the primary refactoring: splitting a monolithic service into two focused components (Orchestrator and Repository).
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.

✏️ 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 refactor/guild-automation-orchestrator-repo

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.

@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: 3

🧹 Nitpick comments (5)
packages/shared/src/services/guildAutomation/service.ts (1)

51-51: 💤 Low value

Consider static import if circular dependencies are not a concern.

The dynamic import adds a slight overhead on each call (module resolution, even if cached). If this change was intentional to avoid circular dependencies or enable code splitting, it's fine. Otherwise, a static import at the top of the file would be marginally more efficient.

🤖 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/shared/src/services/guildAutomation/service.ts` at line 51, The
dynamic import of createAutomationPlan inside service.ts (const {
createAutomationPlan } = await import('./diff.js')) adds runtime overhead;
replace it with a static top-level import (import { createAutomationPlan } from
'./diff.js') to eliminate per-call module resolution, unless you need the
dynamic import to avoid a circular dependency or for code-splitting—if circular
references exist, instead refactor to break the cycle or keep the dynamic import
with a brief comment explaining why.
packages/shared/src/services/guildAutomation/GuildAutomationOrchestrator.ts (3)

265-275: 💤 Low value

Consider explicit handling of undefined parity.

Spreading manifest.parity when it may be undefined (line 267) works correctly but could be more explicit. While JavaScript spreading undefined results in no properties, the intent would be clearer with explicit handling.

♻️ Optional refactor for clarity
 const nextManifest: GuildAutomationManifestDocument = {
     ...manifest,
     parity: {
-        ...manifest.parity,
+        ...(manifest.parity ?? {}),
         cutoverReady: true,
         checklist: checklist.map((item) => ({
             ...item,
             done: true,
         })),
     },
 }
🤖 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/shared/src/services/guildAutomation/GuildAutomationOrchestrator.ts`
around lines 265 - 275, The code constructs nextManifest by spreading
manifest.parity which can be undefined; make the intent explicit by defaulting
parity before spreading — e.g., compute a parity base from manifest.parity (or
{} if undefined) and then assign cutoverReady: true and checklist filled via
checklist.map; update the block that builds nextManifest in
GuildAutomationOrchestrator (the nextManifest variable) to use this explicit
defaulting so parity is always an object rather than relying on spreading
undefined.

112-119: 💤 Low value

Consider extracting severity thresholds as named constants.

The hardcoded thresholds (< 3, < 8) for drift severity classification would be more maintainable and self-documenting as named constants.

♻️ Suggested refactor
+const DRIFT_SEVERITY_LOW_THRESHOLD = 3
+const DRIFT_SEVERITY_MEDIUM_THRESHOLD = 8
+
 async createPlan(
     guildId: string,
     options?: {
         actualState?: GuildAutomationManifestInput
         initiatedBy?: string
         runType?: Extract<AutomationRunType, 'plan' | 'apply' | 'reconcile'>
     },
 ) {
     // ... existing code ...
     
     for (const [moduleName, count] of Object.entries(
         plan.summary.byModule,
     )) {
         const severity: 'none' | 'low' | 'medium' | 'high' =
             count === 0
                 ? 'none'
-                : count < 3
+                : count < DRIFT_SEVERITY_LOW_THRESHOLD
                   ? 'low'
-                  : count < 8
+                  : count < DRIFT_SEVERITY_MEDIUM_THRESHOLD
                     ? 'medium'
                     : 'high'
🤖 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/shared/src/services/guildAutomation/GuildAutomationOrchestrator.ts`
around lines 112 - 119, Extract the numeric thresholds for drift severity into
named constants (e.g., SEVERITY_THRESHOLD_LOW = 3 and SEVERITY_THRESHOLD_MEDIUM
= 8) and replace the hardcoded comparisons in GuildAutomationOrchestrator where
severity is computed (the ternary using count === 0 ? 'none' : count < 3 ? 'low'
: count < 8 ? 'medium' : 'high') to use those constants; define the constants at
module or class scope with brief comments and update the ternary/operator logic
to reference SEVERITY_THRESHOLD_LOW and SEVERITY_THRESHOLD_MEDIUM so the
thresholds are self-documenting and easier to change.

90-94: 💤 Low value

Consider avoiding redundant schema parsing.

Line 91 parses options.actualState even when it may already be a validated manifest. While Zod parsing is idempotent and safe, it adds unnecessary overhead. Consider accepting a type that distinguishes validated vs. raw input, or document that callers should pass raw input here.

🤖 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/shared/src/services/guildAutomation/GuildAutomationOrchestrator.ts`
around lines 90 - 94, The code redundantly calls
guildAutomationManifestSchema.parse on options.actualState even when callers may
pass an already-validated manifest; update the logic so parsing only happens for
raw input: add an explicit discriminator (e.g., options.actualStateIsValidated
boolean) or change the options type to accept a union (ValidatedManifest |
RawManifest) and only call guildAutomationManifestSchema.parse when the value is
the raw variant; keep the fallback to manifestRow.lastCapturedState via
toManifestDocument unchanged and reference the variables actual,
options.actualState, guildAutomationManifestSchema.parse, toManifestDocument,
and manifestRow.lastCapturedState when making the change.
packages/shared/src/services/guildAutomation/GuildAutomationRepository.ts (1)

283-288: ⚡ Quick win

Clamp limit before querying runs.

Passing limit through unbounded can become an accidental hot query path. Guarding it at repository boundary keeps this endpoint safer under upstream misuse.

♻️ Proposed guard
     async listRuns(guildId: string, limit = 10) {
+        const safeLimit = Math.min(Math.max(limit, 1), 100)
         return this.prisma.guildAutomationRun.findMany({
             where: { guildId },
             orderBy: { createdAt: 'desc' },
-            take: limit,
+            take: safeLimit,
         })
     }
🤖 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/shared/src/services/guildAutomation/GuildAutomationRepository.ts`
around lines 283 - 288, The listRuns method currently forwards an unbounded
limit to prisma.guildAutomationRun.findMany; clamp the incoming limit in
GuildAutomationRepository.listRuns to a safe max (e.g., const MAX_RUNS = 100)
and ensure it's at least 1 (use Math.max(1, Math.min(limit, MAX_RUNS)) or
equivalent) before passing to the take option on
prisma.guildAutomationRun.findMany so the DB query cannot be abused by large
limits.
🤖 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 `@packages/shared/src/services/guildAutomation/GuildAutomationOrchestrator.ts`:
- Around line 13-44: The current lock via locks Map with LOCK_TTL_MS and
cleanupLocks can expire mid-operation causing race conditions; update the
locking strategy in GuildAutomationOrchestrator by adding a refresh/heartbeat
mechanism and ownership validation: modify acquireLock to store an owner token
and expiresAt in locks (use unique token per operation), add a
refreshLock(token, guildId) method that extends expiresAt periodically from
long-running tasks, ensure critical sections check that the stored token still
matches the operation's token before proceeding, and call releaseLock(guildId,
token) to only remove locks owned by that token; alternatively, if you prefer
the simpler path, increase LOCK_TTL_MS to a safe maximum and validate expiresAt
immediately before entering critical sections in methods that perform
apply/reconcile.

In `@packages/shared/src/services/guildAutomation/GuildAutomationRepository.ts`:
- Around line 67-98: The manifest upsert and run creation must be executed
atomically: wrap guildAutomationManifest.upsert and guildAutomationRun.create in
a single Prisma transaction so the run is only persisted if the manifest write
succeeds (use this.prisma.$transaction and run the upsert and create on the
transaction client, e.g., tx.guildAutomationManifest.upsert then
tx.guildAutomationRun.create), return or use the transactional results; apply
the same change for the second occurrence (the other grouped writes in
recordCapture and runCutover).
- Around line 254-270: The cutover path only writes the manifest JSON and the
run summary drops the provided checklist, causing version/checklist drift;
update the guildAutomationManifest.update call (guildAutomationManifest.update,
nextManifest, manifestRow) to also set the manifest row's version and checklist
columns from nextManifest.version and nextManifest.checklist, and include the
checklist (and optionally version) inside the guildAutomationRun.create summary
payload so the cutover run records the checklist that triggered the cutover
(guildAutomationRun.create, summary, nextManifest.checklist).

---

Nitpick comments:
In `@packages/shared/src/services/guildAutomation/GuildAutomationOrchestrator.ts`:
- Around line 265-275: The code constructs nextManifest by spreading
manifest.parity which can be undefined; make the intent explicit by defaulting
parity before spreading — e.g., compute a parity base from manifest.parity (or
{} if undefined) and then assign cutoverReady: true and checklist filled via
checklist.map; update the block that builds nextManifest in
GuildAutomationOrchestrator (the nextManifest variable) to use this explicit
defaulting so parity is always an object rather than relying on spreading
undefined.
- Around line 112-119: Extract the numeric thresholds for drift severity into
named constants (e.g., SEVERITY_THRESHOLD_LOW = 3 and SEVERITY_THRESHOLD_MEDIUM
= 8) and replace the hardcoded comparisons in GuildAutomationOrchestrator where
severity is computed (the ternary using count === 0 ? 'none' : count < 3 ? 'low'
: count < 8 ? 'medium' : 'high') to use those constants; define the constants at
module or class scope with brief comments and update the ternary/operator logic
to reference SEVERITY_THRESHOLD_LOW and SEVERITY_THRESHOLD_MEDIUM so the
thresholds are self-documenting and easier to change.
- Around line 90-94: The code redundantly calls
guildAutomationManifestSchema.parse on options.actualState even when callers may
pass an already-validated manifest; update the logic so parsing only happens for
raw input: add an explicit discriminator (e.g., options.actualStateIsValidated
boolean) or change the options type to accept a union (ValidatedManifest |
RawManifest) and only call guildAutomationManifestSchema.parse when the value is
the raw variant; keep the fallback to manifestRow.lastCapturedState via
toManifestDocument unchanged and reference the variables actual,
options.actualState, guildAutomationManifestSchema.parse, toManifestDocument,
and manifestRow.lastCapturedState when making the change.

In `@packages/shared/src/services/guildAutomation/GuildAutomationRepository.ts`:
- Around line 283-288: The listRuns method currently forwards an unbounded limit
to prisma.guildAutomationRun.findMany; clamp the incoming limit in
GuildAutomationRepository.listRuns to a safe max (e.g., const MAX_RUNS = 100)
and ensure it's at least 1 (use Math.max(1, Math.min(limit, MAX_RUNS)) or
equivalent) before passing to the take option on
prisma.guildAutomationRun.findMany so the DB query cannot be abused by large
limits.

In `@packages/shared/src/services/guildAutomation/service.ts`:
- Line 51: The dynamic import of createAutomationPlan inside service.ts (const {
createAutomationPlan } = await import('./diff.js')) adds runtime overhead;
replace it with a static top-level import (import { createAutomationPlan } from
'./diff.js') to eliminate per-call module resolution, unless you need the
dynamic import to avoid a circular dependency or for code-splitting—if circular
references exist, instead refactor to break the cycle or keep the dynamic import
with a brief comment explaining why.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d0a2221f-82f2-4f7a-a2a3-65688a021ab2

📥 Commits

Reviewing files that changed from the base of the PR and between bfcf438 and ec8d2d3.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json, !**/package-lock.json
📒 Files selected for processing (5)
  • packages/shared/src/services/guildAutomation/GuildAutomationOrchestrator.ts
  • packages/shared/src/services/guildAutomation/GuildAutomationRepository.ts
  • packages/shared/src/services/guildAutomation/IGuildAutomationRepository.ts
  • packages/shared/src/services/guildAutomation/guildAutomationHelpers.ts
  • packages/shared/src/services/guildAutomation/service.ts

Comment thread packages/shared/src/services/guildAutomation/GuildAutomationRepository.ts Outdated
Comment thread packages/shared/src/services/guildAutomation/GuildAutomationRepository.ts Outdated
…actions

- recordCapture: manifest upsert + run create now atomic
- runCutover: manifest update + run create now atomic; also persist
  version and checklist in the cutover run summary to prevent audit drift

@greptile-apps greptile-apps 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.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/shared/src/services/guildAutomation/GuildAutomationRepository.ts`:
- Around line 277-279: The repository is persisting the original checklist
variable instead of the finalized/normalized snapshot; when summary:
toJsonValue({ checklistComplete: true, checklist }) is written, replace the
persisted checklist with the normalized snapshot from nextManifest (use
nextManifest.parity.checklist) so that when completeChecklist is true the stored
checklist reflects the all-done normalization; update the summary construction
in GuildAutomationRepository (the toJsonValue call) to use
nextManifest.parity.checklist rather than checklist.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6ffcb9a9-411e-442b-9ae6-f215a9201825

📥 Commits

Reviewing files that changed from the base of the PR and between ec8d2d3 and f38da75.

📒 Files selected for processing (1)
  • packages/shared/src/services/guildAutomation/GuildAutomationRepository.ts

Comment thread packages/shared/src/services/guildAutomation/GuildAutomationRepository.ts Outdated

@greptile-apps greptile-apps 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.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@sonarqubecloud

Copy link
Copy Markdown

@LucasSantana-Dev
LucasSantana-Dev merged commit b710faf into main May 24, 2026
32 of 33 checks passed
@LucasSantana-Dev
LucasSantana-Dev deleted the refactor/guild-automation-orchestrator-repo branch May 24, 2026 02:17
LucasSantana-Dev added a commit that referenced this pull request May 24, 2026
## Summary

Replaces the 15+ positional arguments passed through the autoplay
collector pipeline with a single `AutoplayContext` value object,
improving call-site clarity and making the pipeline easier to extend.

### Changes
- Introduce `AutoplayContext` interface in `autoplayContext.ts`
- Update `candidateCollector`, `lastFmSeeder`, `spotifyRecommender`,
`replenisher`, and `candidateFallback` to accept `AutoplayContext`
instead of positional args
- Fix missing `beforeEach` mock setup in `candidateCollector` tests
- Remove leftover `.bak` file from refactor

### Why
Positional argument lists of 15+ items are hard to read, easy to
misorder, and brittle to extend. A named value object surfaces intent at
every call site and isolates future additions to one interface
definition.

Part of the architecture refactor series (T1–T5):
- T1 #979 ✅ — extract `MessagePipeline`
- T2 #980 ✅ — introduce `IGuildAutomationRepository`
- T3 #981 ✅ — `AutomationPlan` result type
- T4 #982 ✅ — `GuildAutomationRepository` / `Orchestrator` split
- T5 (this PR) — `AutoplayContext` value object
@LucasSantana-Dev
LucasSantana-Dev restored the refactor/guild-automation-orchestrator-repo branch May 24, 2026 15:18
LucasSantana-Dev added a commit that referenced this pull request May 24, 2026
ADRs for the 5 refactors merged in PRs #979–#983 and the Phase 4 test
reduction strategy.

## Decision records added

- `2026-05-23-artist-suggestion-service.md` — ArtistSuggestionService
extraction (#980)
- `2026-05-23-autoplay-context-value-object.md` — AutoplayContext value
object (#983)
- `2026-05-23-bot-test-reduction-phase4-replacement-strategy.md` — Phase
4 test replacement strategy
- `2026-05-23-guild-automation-orchestrator-repository-split.md` —
GuildAutomationService split (#982)
- `2026-05-23-message-pipeline-handler-chain.md` — MessagePipeline
handler chain (#981)
- `2026-05-23-recommendation-engine-single-entrypoint.md` —
recommendTracks() single entrypoint (#979)

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

## Summary by CodeRabbit

* **Documentation**
* Added architecture decision records documenting planned service
refactoring, test optimization strategies, and API consolidation
initiatives to improve system maintainability.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/LucasSantana-Dev/Lucky/pull/1040?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
LucasSantana-Dev added a commit that referenced this pull request May 25, 2026
## Summary

- Bumps all package.json files from `2.14.1` → `2.15.0`
- Populates `CHANGELOG.md` with everything since v2.14.1
- Adds ADR `docs/decisions/2026-05-24-ci-runtime-baseline-accepted.md`
(CI runtime baseline: 3–4 min accepted, Jest sharding deferred)

### Changes included in this release

**Added**
- ServerLogs + ServerSettings UI pages (#965)
- AutoMessages executor wiring into execution service (#950)

**Changed**
- 4 UI redesigns: Admin, Config, Login, ServersPage, CustomCommands,
GuildAutomation, Spotify, LastFm (#967–#970)
- 5 refactors: AutoplayContext VO (#983),
GuildAutomationOrchestrator/Repository split (#982), MessagePipeline
chain (#981), ArtistSuggestionService (#980), recommendTracks entrypoint
(#979)

**Fixed** — deploy CI gap sweep (A–F)
- Gap A: hard-fail on OAuth 429 (#1045)
- Gap B: surface async deploy via commit statuses (#1046)
- Gap C: bot healthcheck polls Discord gateway, not Redis TCP (#1047)
- Gap D: post error status on lock contention (#1052)
- Gap E: add bot to required containers, remove dead unhealthy grep
(#1054)
- Gap F: wait for homelab-deploy completion on docker_rebuilt=true path
(#1056)
- lockfile-hash BuildKit cache key (#1016)
- squash-merged release branch archive (#946)

**Internal**
- Phase 4 test cleanup — 93 tests removed (#956–#1035)
- Pre-commit hooks: husky + lint-staged + tsc (#1007)
- madge gate promoted to blocking
- Dependabot routine bumps (#971–#977, #1042)

> **Note:** #1054 (Gap E) may still be in CI — merge this PR after #1054
lands.

This branch was successfully deployed

1 active deployment
Preview — f22d3419 Deployed May 24, 2026 by vercel[bot]
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 shared size/xl

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants