fix: 15 code quality issues — generics, types, locale, dead code, naming#118
Conversation
- Replace (value as number) with narrowed type inference - Replace (exercicio as Record<string, unknown>) with Object.assign - Replace (exercicios as Exercicio[]) with type-safe mapping - Remove (result as WorkoutGeneratorAIOutput) cast
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
More reviews will be available in 12 minutes and 23 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the 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 include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (4)
WalkthroughThis PR enables noUnusedLocals/noUnusedParameters, adds centralized error helpers (getZodError, getErrorMessage, handleActionError), standardizes server-action error handling, removes unsafe casts, adds runtime guards (logger, i18n, AI flow), tightens internal exports, replaces magic numbers with constants, and adds tests/docs evidence. ChangesTypeScript Strictness and Type Safety
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
1 issue found across 25 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/ai/flows/workout-generator-flow.ts (2)
76-82:⚠️ Potential issue | 🔴 Critical | ⚡ Quick win
generateWorkoutPlancan returnnulldespite a non-null Promise signature.At Line 81,
outputis nullable fromai.generate(...), but the function promisesPromise<WorkoutGeneratorAIOutput>. This is a type and runtime contract break.As per coding guidelines, all code changes must pass `npm run typecheck` (TypeScript strict check) before merging.Proposed fix
export async function generateWorkoutPlan( input: WorkoutGeneratorInput ): Promise<WorkoutGeneratorAIOutput> { const { output } = await ai.generate({ @@ output: { schema: WorkoutGeneratorAIOutputSchema }, }); - return output; + if (!output) { + throw new Error('A IA não retornou um plano de treino válido.'); + } + return output; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/ai/flows/workout-generator-flow.ts` around lines 76 - 82, generateWorkoutPlan currently returns output from ai.generate which can be null, violating the Promise<WorkoutGeneratorAIOutput> contract; update generateWorkoutPlan to detect a null/undefined output from ai.generate (the call that uses googleAI.model('gemini-2.5-flash') and WorkoutGeneratorAIOutputSchema) and either throw a descriptive Error (e.g., "Workout generation returned no output for objetivo: ...") or return a safe fallback that matches WorkoutGeneratorAIOutput, then return that non-null value so the function's signature is honored; ensure the null-check is explicit and satisfies TypeScript strict checks so npm run typecheck passes.
3-4:⚠️ Potential issue | 🟠 Major | 🏗️ Heavy liftAlign Genkit dependencies to 1.31 (repo currently uses 1.32/1.34).
File: src/ai/flows/workout-generator-flow.ts (imports at lines 3-4)
- package.json declares Genkit/@genkit-ai ranges on
^1.32.0(genkit,@genkit-ai/google-genai,@genkit-ai/next).- package-lock.json resolves Genkit and some
@genkit-ai/*packages to1.34.0(and contains no Genkit1.31usage).Update dependencies/lockfile to use Genkit
1.31consistently so this AI flow layer matches the repository policy.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/ai/flows/workout-generator-flow.ts` around lines 3 - 4, The repo's Genkit packages must be pinned to 1.31; update package.json entries for "genkit", "`@genkit-ai/google-genai`", and "`@genkit-ai/next`" to use version "1.31.0" (or exact semver matching your policy), then regenerate the lockfile (run npm install or npm ci) so package-lock.json resolves all genkit and `@genkit-ai/`* packages to 1.31.0; verify the import sites such as the imports in src/ai/flows/workout-generator-flow.ts (symbols ai and googleAI) still work after the change and run tests/build to ensure no breaking API changes.
🧹 Nitpick comments (4)
src/lib/error.ts (1)
1-8: 💤 Low valueDocstring describes the wrong function.
The block comment at lines 1-4 ("Safely extracts message from an unknown error value… Returns 'Erro desconhecido'") describes
getErrorMessage, but it is positioned above theZodErrorLikeinterface andgetZodError. Move it directly abovegetErrorMessage(line 21).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/error.ts` around lines 1 - 8, The top comment describing "Safely extracts message from an unknown error value..." is placed above the ZodErrorLike interface/getZodError; move that docstring so it directly precedes the getErrorMessage function (and remove it from above ZodErrorLike/getZodError) so the comment accurately documents getErrorMessage; keep ZodErrorLike and getZodError unchanged and ensure their own comments (if any) remain appropriate.src/lib/actions/treinos.ts (1)
350-356: 💤 Low valueInconsistent: this action was not migrated to
handleActionError.
registrarHistoricoTreinoActionkeeps the inlineerror.name === 'ZodError'check and returns domain-specific generic messages ('Dados do histórico inválidos','Erro ao registrar treino. Tente novamente.'). This is intentional and actually safer thanhandleActionError(which surfaces rawerror.message), but it leaves the file with two error-handling styles. Decide on one approach: either extendhandleActionErrorto support a custom fallback/Zod message and use it here, or leave a brief comment explaining why this action keeps a bespoke handler.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/actions/treinos.ts` around lines 350 - 356, Replace the bespoke Zod check in registrarHistoricoTreinoAction with a call to an extended handleActionError: update handleActionError to accept optional parameters (e.g., fallbackMessage and zodMessage) and ensure it still captures/logs the exception (Sentry.captureException behavior remains inside); then in registrarHistoricoTreinoAction call handleActionError(error, { fallbackMessage: 'Erro ao registrar treino. Tente novamente.', zodMessage: 'Dados do histórico inválidos' }) and remove the inline error.name === 'ZodError' branch so the action uses the unified handler.src/lib/data.ts (1)
124-129: 💤 Low valueConstant names don't match the domain.
This block computes a dashboard growth projection, but
STREAK_MULTIPLIER(0.7) andBONUS_THRESHOLD(0.05) imply gamification/streak semantics. Names likeBASE_GROWTH_FACTORandMONTHLY_GROWTH_INCREMENTwould read more accurately.♻️ Proposed rename
- const STREAK_MULTIPLIER = 0.7; - const BONUS_THRESHOLD = 0.05; + const BASE_GROWTH_FACTOR = 0.7; + const MONTHLY_GROWTH_INCREMENT = 0.05; const meses = ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun']; const crescimentoAnual = meses.map((mes, idx) => ({ mes, - alunos: Math.floor(totalAlunos * (STREAK_MULTIPLIER + idx * BONUS_THRESHOLD)), + alunos: Math.floor(totalAlunos * (BASE_GROWTH_FACTOR + idx * MONTHLY_GROWTH_INCREMENT)), }));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/data.ts` around lines 124 - 129, The constants STREAK_MULTIPLIER and BONUS_THRESHOLD use gamification terms; rename them to domain-appropriate names (e.g., BASE_GROWTH_FACTOR and MONTHLY_GROWTH_INCREMENT) and update all references in this file (including the computation that builds meses and crescimentoAnual which uses totalAlunos) so the names reflect dashboard growth projection semantics; ensure mesos/localized variable names (meses, crescimentoAnual) remain consistent or are similarly renamed if desired, and run tests/linters to catch any remaining references to STREAK_MULTIPLIER or BONUS_THRESHOLD.src/services/gamificationService.ts (1)
75-75: 💤 Low valueLeftover magic numbers contradict the cleanup goal.
The streak bonus
50(Line 75) and level threshold1500(Lines 82-83) remain inline while neighboring literals were promoted to named constants. Consider extracting them too for consistency.♻️ Proposed constants
const BASE_XP_PER_WORKOUT = 100; const XP_PER_COMPLETED_SERIE = 10; +const STREAK_BONUS_XP = 50; +const LEVEL_UP_XP_PER_LEVEL = 1500; const MS_PER_DAY = 24 * 60 * 60 * 1000;- novaExp += 50; // Streak bonus + novaExp += STREAK_BONUS_XP; // Streak bonus- while (novaExp >= novoNivel * 1500) { - novaExp -= novoNivel * 1500; + while (novaExp >= novoNivel * LEVEL_UP_XP_PER_LEVEL) { + novaExp -= novoNivel * LEVEL_UP_XP_PER_LEVEL; novoNivel += 1; }Also applies to: 82-83
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/services/gamificationService.ts` at line 75, The code uses magic numbers for the streak bonus and level threshold—replace the inline 50 added to novaExp and the 1500 threshold used in the level-up check with descriptive named constants (e.g., STREAK_BONUS and LEVEL_UP_THRESHOLD or NOVA_STREAK_BONUS and NOVA_LEVEL_THRESHOLD) declared near other gamification constants in gamificationService.ts; update the addition (novaExp += 50) and the level check that uses 1500 to reference these constants to match surrounding cleanup and improve readability and maintainability.
🤖 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 `@src/ai/flows/workout-generator-flow.ts`:
- Around line 58-61: The call to sendChunk is passing chunk.output without
ensuring it matches the expected WorkoutGeneratorAIOutput type; add a runtime
type-narrowing check (or a small type-guard function isWorkoutGeneratorAIOutput)
before calling sendChunk so only validated WorkoutGeneratorAIOutput objects are
forwarded. Locate the for-await loop over responseStream.stream and replace the
direct sendChunk(chunk.output) call with a guarded branch that verifies required
properties/shape of chunk.output (or uses a type-guard) and only then calls
sendChunk; otherwise handle or ignore invalid payloads to satisfy TypeScript
strict checks.
In `@src/app/dashboard/treinos/treinos-client.tsx`:
- Around line 404-412: The current mapping in the exercicios payload uses
invalid fallbacks (series: 0 and repeticoes: '') that violate
ExercicioBaseSchema; update the mapping in treinos-client.tsx where exercicios
is built so series uses a valid minimum (e.g., series: series ?? 1) and
repeticoes uses a non-empty default (e.g., repeticoes: repeticoes ?? '1'), or
alternatively preserve undefined instead of injecting invalid defaults so
server/client-side validation can catch missing fields; ensure references to
ExercicioBaseSchema-compliant values in the exercicios mapping are corrected.
- Around line 215-218: The current branch that handles edits to exercicio for
field 'series' coerces empty/invalid input to 0 (exercicio[field] =
parseInt(...) || 0), producing invalid treino entries; change the logic in the
handler in treinos-client.tsx so that when field === 'series' you parse the
string and if parseInt yields a valid number assign that number, otherwise set
exercicio.series to undefined (or delete the property) instead of 0, ensuring
invalid/empty input does not silently become zero.
In `@src/components/providers/i18n-provider.tsx`:
- Around line 24-29: The language restore logic mismatches what setLanguage
writes and causes a type error by using 'pt-BR'; change the read path to
validate raw against the Language union and default to a valid Language (e.g.,
'pt') instead of 'pt-BR'. Specifically, read
localStorage.getItem('app-language') into raw, set savedLang: Language = raw ===
'pt' || raw === 'en' ? raw : 'pt', and then call setLanguageState(savedLang)
(remove the incorrect savedLang === 'pt' || savedLang === 'en' guard) so
persisted 'pt'/'en' values are correctly restored and the TypeScript type checks
pass.
In `@src/services/alunoService.ts`:
- Around line 14-15: The returned values from the untyped DB layer are currently
typed as unknown (db.insert, db.findById, db.update), so remove the breaking
change by restoring minimal, local casts to the expected domain types (e.g. cast
the result of db.insert(...) to Aluno, and db.findById/db.update results to
Aluno | null) in src/services/alunoService.ts where those calls occur;
alternatively, if you prefer a broader fix, update the db methods to be generic
(e.g. insert<T>(...), findById<T>(...), update<T>(...)) and propagate those
generics through the alunoService functions so the return types match
Promise<Aluno> / Promise<Aluno | null>. Ensure the chosen fix makes the
functions' declared return types and npm run typecheck pass.
---
Outside diff comments:
In `@src/ai/flows/workout-generator-flow.ts`:
- Around line 76-82: generateWorkoutPlan currently returns output from
ai.generate which can be null, violating the Promise<WorkoutGeneratorAIOutput>
contract; update generateWorkoutPlan to detect a null/undefined output from
ai.generate (the call that uses googleAI.model('gemini-2.5-flash') and
WorkoutGeneratorAIOutputSchema) and either throw a descriptive Error (e.g.,
"Workout generation returned no output for objetivo: ...") or return a safe
fallback that matches WorkoutGeneratorAIOutput, then return that non-null value
so the function's signature is honored; ensure the null-check is explicit and
satisfies TypeScript strict checks so npm run typecheck passes.
- Around line 3-4: The repo's Genkit packages must be pinned to 1.31; update
package.json entries for "genkit", "`@genkit-ai/google-genai`", and
"`@genkit-ai/next`" to use version "1.31.0" (or exact semver matching your
policy), then regenerate the lockfile (run npm install or npm ci) so
package-lock.json resolves all genkit and `@genkit-ai/`* packages to 1.31.0;
verify the import sites such as the imports in
src/ai/flows/workout-generator-flow.ts (symbols ai and googleAI) still work
after the change and run tests/build to ensure no breaking API changes.
---
Nitpick comments:
In `@src/lib/actions/treinos.ts`:
- Around line 350-356: Replace the bespoke Zod check in
registrarHistoricoTreinoAction with a call to an extended handleActionError:
update handleActionError to accept optional parameters (e.g., fallbackMessage
and zodMessage) and ensure it still captures/logs the exception
(Sentry.captureException behavior remains inside); then in
registrarHistoricoTreinoAction call handleActionError(error, { fallbackMessage:
'Erro ao registrar treino. Tente novamente.', zodMessage: 'Dados do histórico
inválidos' }) and remove the inline error.name === 'ZodError' branch so the
action uses the unified handler.
In `@src/lib/data.ts`:
- Around line 124-129: The constants STREAK_MULTIPLIER and BONUS_THRESHOLD use
gamification terms; rename them to domain-appropriate names (e.g.,
BASE_GROWTH_FACTOR and MONTHLY_GROWTH_INCREMENT) and update all references in
this file (including the computation that builds meses and crescimentoAnual
which uses totalAlunos) so the names reflect dashboard growth projection
semantics; ensure mesos/localized variable names (meses, crescimentoAnual)
remain consistent or are similarly renamed if desired, and run tests/linters to
catch any remaining references to STREAK_MULTIPLIER or BONUS_THRESHOLD.
In `@src/lib/error.ts`:
- Around line 1-8: The top comment describing "Safely extracts message from an
unknown error value..." is placed above the ZodErrorLike interface/getZodError;
move that docstring so it directly precedes the getErrorMessage function (and
remove it from above ZodErrorLike/getZodError) so the comment accurately
documents getErrorMessage; keep ZodErrorLike and getZodError unchanged and
ensure their own comments (if any) remain appropriate.
In `@src/services/gamificationService.ts`:
- Line 75: The code uses magic numbers for the streak bonus and level
threshold—replace the inline 50 added to novaExp and the 1500 threshold used in
the level-up check with descriptive named constants (e.g., STREAK_BONUS and
LEVEL_UP_THRESHOLD or NOVA_STREAK_BONUS and NOVA_LEVEL_THRESHOLD) declared near
other gamification constants in gamificationService.ts; update the addition
(novaExp += 50) and the level check that uses 1500 to reference these constants
to match surrounding cleanup and improve readability and maintainability.
🪄 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: 26bd38da-e6d6-4316-aacf-83db4c61da8d
📒 Files selected for processing (25)
src/ai/flows/workout-generator-flow.tssrc/ai/genkit.tssrc/app/actions/auth.tssrc/app/aluno/meus-treinos/meus-treinos-client.tsxsrc/app/dashboard/planos/planos-client.tsxsrc/app/dashboard/treinos/page.tsxsrc/app/dashboard/treinos/treinos-client.tsxsrc/components/dashboard/alunos/columns.tsxsrc/components/dashboard/alunos/data-table.tsxsrc/components/providers/i18n-provider.tsxsrc/hooks/use-toast.tssrc/lib/actions/alunos.tssrc/lib/actions/financeiro.tssrc/lib/actions/planos.tssrc/lib/actions/treinos.tssrc/lib/data.tssrc/lib/dummyDb.tssrc/lib/error.tssrc/lib/logger.tssrc/lib/placeholder-images.tssrc/services/alunoService.tssrc/services/gamificationService.tssrc/services/pagamentoService.tssrc/utils/supabase/middleware.tstsconfig.json
💤 Files with no reviewable changes (2)
- src/lib/placeholder-images.ts
- src/ai/genkit.ts
| exercicios: exercicios.map( | ||
| ({ id: _id, nomeExercicio, series, repeticoes, observacoes, descricao }) => ({ | ||
| nomeExercicio: nomeExercicio ?? '', | ||
| series: series ?? 0, | ||
| repeticoes: repeticoes ?? '', | ||
| observacoes: observacoes ?? null, | ||
| descricao: descricao ?? null, | ||
| }) | ||
| ), |
There was a problem hiding this comment.
Manual treino payload defaults violate the action schema contract.
At Line 407 and Line 408, fallback values (0 and '') conflict with ExercicioBaseSchema (series must be >= 1, repeticoes must be non-empty), leading to predictable server-side validation failures.
Proposed fix
exercicios: exercicios.map(
({ id: _id, nomeExercicio, series, repeticoes, observacoes, descricao }) => ({
nomeExercicio: nomeExercicio ?? '',
- series: series ?? 0,
- repeticoes: repeticoes ?? '',
+ series:
+ typeof series === 'number' && Number.isFinite(series) && series >= 1
+ ? Math.trunc(series)
+ : 1,
+ repeticoes:
+ typeof repeticoes === 'string' && repeticoes.trim().length > 0
+ ? repeticoes.trim()
+ : '1',
observacoes: observacoes ?? null,
descricao: descricao ?? null,
})
),🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/app/dashboard/treinos/treinos-client.tsx` around lines 404 - 412, The
current mapping in the exercicios payload uses invalid fallbacks (series: 0 and
repeticoes: '') that violate ExercicioBaseSchema; update the mapping in
treinos-client.tsx where exercicios is built so series uses a valid minimum
(e.g., series: series ?? 1) and repeticoes uses a non-empty default (e.g.,
repeticoes: repeticoes ?? '1'), or alternatively preserve undefined instead of
injecting invalid defaults so server/client-side validation can catch missing
fields; ensure references to ExercicioBaseSchema-compliant values in the
exercicios mapping are corrected.
EmiyaKiritsugu3
left a comment
There was a problem hiding this comment.
Code Review Summary
🔴 Critical: TypeScript Compilation Errors (9 issues)
The PR removes as casts that are actually necessary because getValue() returns unknown. TypeScript strict mode will fail compilation.
1. src/components/dashboard/alunos/columns.tsx (3 issues)
row.getValue('nomeCompleto')→unknownin JSXrow.getValue('dataCadastro')→unknowninnew Date()row.getValue('statusMatricula')→unknowningetStatusVariant()
Fix: Userow.original.nomeCompleto(typed) or restore casts.
2. src/ai/flows/workout-generator-flow.ts (2 issues)
chunk.outputisunknown—sendChunk()expectsWorkoutGeneratorAIOutputfinalOutput.outputnot properly narrowed after null check
Fix: Restoreas WorkoutGeneratorAIOutputcast or use Zod validation.
3. src/services/alunoService.ts (3 issues)
db.insert(),db.findById(),db.update()returnunknown
Fix: Restoreas Alunocasts or add runtime Zod validation.
4. src/components/providers/i18n-provider.tsx (1 issue)
const savedLang: Language = raw === 'pt-BR' || raw === 'en' ? raw : 'pt-BR'—'pt-BR'not assignable to'pt' | 'en'
Fix: Use'pt'consistently or updateLanguagetype.
⚠️ Runtime Bugs
5. i18n-provider.tsx:26 — Language persistence broken
- The
ifcondition checkssavedLang === 'pt', butsavedLangcan only be'pt-BR'or'en'— condition never matches for Portuguese. English works, Portuguese broken.
6. src/lib/actions/treinos.ts — Lost specific error message
handleActionError()returns generic'Dados inválidos'for all ZodErrors, losing the context-specific'Dados do treino inválidos'message.
📝 Recommendations
| Issue | File | Severity | Confidence |
|---|---|---|---|
row.getValue unknown casts |
columns.tsx |
HIGH | 100% |
| Genkit output casts | workout-generator-flow.ts |
HIGH | 100% |
| DB service casts | alunoService.ts |
HIGH | 100% |
| i18n type mismatch | i18n-provider.tsx |
HIGH | 100% |
| i18n logic bug | i18n-provider.tsx |
MEDIUM | 100% |
| Error message regression | treinos.ts |
HIGH | 100% |
| Logger cast | logger.ts |
LOW | 90% |
| Empty placeholder-images.ts | placeholder-images.ts |
LOW | 100% |
| Orphaned placeholder-images.json | placeholder-images.json |
LOW | 100% |
| Misleading constant names | data.ts |
MEDIUM | 85% |
Total: 9 HIGH, 2 MEDIUM, 4 LOW issues (all ≥80 confidence).
✅ Correct Changes
_iddestructuring pattern for unused params (correct)- Exercicios mapping without
id(correct — matchesExercicioBaseSchema) - Null-safe context spreading in logger (correct)
DAYS_PER_MONTHnaming (clear purpose)MS_PER_DAYcalculation (correct: 86,400,000)
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/ai/flows/workout-generator-flow.ts (1)
3-4:⚠️ Potential issue | 🟠 MajorAlign Genkit dependency to policy (1.31) before merge.
package.jsonpinsgenkit/@genkit-ai/*to^1.32.0(lines ~49-50, ~90), butpackage-lock.jsonresolves them to1.34.0, so the repo is drifting away from the required Genkit1.31range. Pingenkitand@genkit-ai/*to1.31.x(and regenerate the lockfile), or update the guideline source-of-truth if the policy has changed.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/ai/flows/workout-generator-flow.ts` around lines 3 - 4, The repo's Genkit packages are drifting from the mandated 1.31 range; update the dependency entries for "genkit" and all "`@genkit-ai/`*" packages in package.json to pin them to "1.31.x" (remove ^/looser ranges), then regenerate the lockfile by running a clean install (e.g., delete node_modules and package-lock.json then npm install or npm ci) so package-lock.json resolves to 1.31.*; ensure the updated package.json and package-lock.json are committed together.
♻️ Duplicate comments (2)
src/app/dashboard/treinos/treinos-client.tsx (2)
215-218:⚠️ Potential issue | 🟠 Major | ⚡ Quick winAvoid force-casting
undefinedintoseriesnumber fields.This path writes
undefined as unknown as number, which defeats strict typing and can leave edited exercises in an invalid numeric state.Proposed fix
if (field === 'series') { const parsed = typeof value === 'string' ? parseInt(value, 10) : value; - exercicio[field] = Number.isFinite(parsed) ? parsed : (undefined as unknown as number); + if (Number.isInteger(parsed) && parsed >= 1) { + exercicio[field] = parsed; + } } else { Object.assign(exercicio, { [field]: value }); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/app/dashboard/treinos/treinos-client.tsx` around lines 215 - 218, The current assignment uses a force-cast "undefined as unknown as number" which bypasses typing and can leave exercicio.series in an invalid state; instead, update the Exercise type to allow series?: number (or number | undefined) and change the branch in treinos-client.tsx (the block handling if (field === 'series') where exercicio[field] is set) to assign parsed when Number.isFinite(parsed) else assign undefined directly (no double-cast). If changing the model type is not possible, narrow the assignment by explicitly setting exercicio.series via a safe typed setter or adjust the field-specific assignment to handle 'series' separately using the concrete property (exercicio.series) rather than generic index typing.
385-388:⚠️ Potential issue | 🟠 Major | ⚡ Quick win
series/repeticoesfallbacks still violate the action payload contract.Using
0and empty-string defaults here can generate payloads that are predictably invalid for treino validation, causing avoidable save failures.Proposed fix
if (field === 'series') { const parsed = parseInt(String(value), 10); - return { ...ex, series: Number.isFinite(parsed) ? parsed : 0 }; + return { ...ex, series: Number.isInteger(parsed) && parsed >= 1 ? parsed : undefined }; } // payload normalization ({ id: _id, nomeExercicio, series, repeticoes, observacoes, descricao }) => ({ nomeExercicio: nomeExercicio ?? '', - series: series || 0, - repeticoes: repeticoes ?? '', + series: typeof series === 'number' && Number.isInteger(series) && series >= 1 ? series : 1, + repeticoes: + typeof repeticoes === 'string' && repeticoes.trim().length > 0 ? repeticoes.trim() : '1', observacoes: observacoes ?? null, descricao: descricao ?? null, }) // series input onChange const parsed = parseInt(e.target.value, 10); handleExercicioChange( exercicio.id!, 'series', - Number.isFinite(parsed) ? parsed : 0 + Number.isInteger(parsed) && parsed >= 1 ? parsed : 1 );Also applies to: 409-413, 560-567
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/app/dashboard/treinos/treinos-client.tsx` around lines 385 - 388, The current handlers for field === 'series' (and similar logic for 'repeticoes') replace invalid parses with 0 or '' which produces invalid action payloads; instead, when parseInt/Number.isFinite indicates an invalid number, do not inject a fallback value—return the existing object (ex) or omit the property (i.e., leave series/repeticoes undefined) so the action payload stays valid. Locate the branches using parseInt/Number.isFinite and the returned object spread (references: field === 'series', the parsed variable, Number.isFinite(parsed), and ex) and change the fallback from 0/'' to leaving the property unchanged or undefined; apply the same fix to the other occurrences mentioned (the blocks around the other series/repeticoes handlers).
🧹 Nitpick comments (2)
src/lib/error.ts (1)
6-15: 💤 Low valueConsider removing redundant non-null assertion.
Line 12 uses a non-null assertion (
!) after already verifying thatflattenis a function on line 10. The assertion is safe but unnecessary—TypeScript already knowsflattenis defined after thetypeofcheck.♻️ Optional simplification
if ( error instanceof Error && error.name === 'ZodError' && typeof (error as ZodErrorLike).flatten === 'function' ) { - return (error as ZodErrorLike).flatten!(); + return (error as ZodErrorLike).flatten(); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/error.ts` around lines 6 - 15, In getZodError, remove the redundant non-null assertion on (error as ZodErrorLike).flatten!()—you already guard that flatten is a function with the typeof check, so call (error as ZodErrorLike).flatten() instead; keep the rest of the function and return behavior unchanged..sisyphus/plans/pr118-correction-optimization.md (1)
185-194: 💤 Low valueConsider adding language identifiers to scenario code blocks.
The fenced code blocks in QA Scenarios sections lack language specifiers, triggering MD040 warnings. While these are pseudo-code test scenarios rather than executable code, markdown best practice recommends specifying a language identifier (e.g.,
textorgherkin).📝 Suggested improvement
Replace:
Scenario: ...With:
Scenario: ...Apply this pattern to all QA Scenario blocks throughout the document.
Also applies to: 256-269, 313-326, 404-417, 486-500, 561-574, 658-672, 716-729, 771-784
🤖 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 @.sisyphus/plans/pr118-correction-optimization.md around lines 185 - 194, The fenced QA Scenario code blocks that start with the literal "Scenario:" are missing language identifiers and trigger MD040; update each such block (e.g., the one shown and the others noted) by adding a language tag after the opening triple backticks (use `text` or `gherkin`) so the blocks become ```text (or ```gherkin) ... ``` throughout the document; search for code fences whose first line is "Scenario:" and apply the change to all occurrences.
🤖 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 `@src/lib/dummyDb.ts`:
- Around line 8-9: The type assertion in async function findById<T =
unknown>(_table: string, id: string): Promise<T | null> is redundantly casting
to "as T | null"; change the assertion to "as T" so the returned object is
asserted to T while the function signature still expresses T | null—update the
return statement in findById to return { id } as T.
---
Outside diff comments:
In `@src/ai/flows/workout-generator-flow.ts`:
- Around line 3-4: The repo's Genkit packages are drifting from the mandated
1.31 range; update the dependency entries for "genkit" and all "`@genkit-ai/`*"
packages in package.json to pin them to "1.31.x" (remove ^/looser ranges), then
regenerate the lockfile by running a clean install (e.g., delete node_modules
and package-lock.json then npm install or npm ci) so package-lock.json resolves
to 1.31.*; ensure the updated package.json and package-lock.json are committed
together.
---
Duplicate comments:
In `@src/app/dashboard/treinos/treinos-client.tsx`:
- Around line 215-218: The current assignment uses a force-cast "undefined as
unknown as number" which bypasses typing and can leave exercicio.series in an
invalid state; instead, update the Exercise type to allow series?: number (or
number | undefined) and change the branch in treinos-client.tsx (the block
handling if (field === 'series') where exercicio[field] is set) to assign parsed
when Number.isFinite(parsed) else assign undefined directly (no double-cast). If
changing the model type is not possible, narrow the assignment by explicitly
setting exercicio.series via a safe typed setter or adjust the field-specific
assignment to handle 'series' separately using the concrete property
(exercicio.series) rather than generic index typing.
- Around line 385-388: The current handlers for field === 'series' (and similar
logic for 'repeticoes') replace invalid parses with 0 or '' which produces
invalid action payloads; instead, when parseInt/Number.isFinite indicates an
invalid number, do not inject a fallback value—return the existing object (ex)
or omit the property (i.e., leave series/repeticoes undefined) so the action
payload stays valid. Locate the branches using parseInt/Number.isFinite and the
returned object spread (references: field === 'series', the parsed variable,
Number.isFinite(parsed), and ex) and change the fallback from 0/'' to leaving
the property unchanged or undefined; apply the same fix to the other occurrences
mentioned (the blocks around the other series/repeticoes handlers).
---
Nitpick comments:
In @.sisyphus/plans/pr118-correction-optimization.md:
- Around line 185-194: The fenced QA Scenario code blocks that start with the
literal "Scenario:" are missing language identifiers and trigger MD040; update
each such block (e.g., the one shown and the others noted) by adding a language
tag after the opening triple backticks (use `text` or `gherkin`) so the blocks
become ```text (or ```gherkin) ... ``` throughout the document; search for code
fences whose first line is "Scenario:" and apply the change to all occurrences.
In `@src/lib/error.ts`:
- Around line 6-15: In getZodError, remove the redundant non-null assertion on
(error as ZodErrorLike).flatten!()—you already guard that flatten is a function
with the typeof check, so call (error as ZodErrorLike).flatten() instead; keep
the rest of the function and return behavior unchanged.
🪄 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: 6da0a4e7-b1d3-4f87-bc14-95f85c14292d
📒 Files selected for processing (23)
.sisyphus/boulder.json.sisyphus/evidence/wave0-baseline.txt.sisyphus/evidence/wave0-constants.txt.sisyphus/evidence/wave0-imports.txt.sisyphus/plans/pr118-correction-optimization.mdCHANGELOG.mddocs/CURRENT-STATE.mddocs/superpowers/plans/2026-06-02-code-quality-correcoes.mdsrc/ai/flows/__tests__/workout-generator-validation.test.tssrc/ai/flows/workout-generator-flow.tssrc/app/dashboard/treinos/__tests__/nan-guards.test.tssrc/app/dashboard/treinos/treinos-client.tsxsrc/components/dashboard/alunos/columns.tsxsrc/components/providers/i18n-provider.tsxsrc/lib/__tests__/error.test.tssrc/lib/actions/treinos.tssrc/lib/data.tssrc/lib/dummyDb.tssrc/lib/error.tssrc/lib/logger.tssrc/lib/placeholder-images.jsonsrc/services/alunoService.tssrc/services/gamificationService.ts
💤 Files with no reviewable changes (1)
- src/lib/placeholder-images.json
✅ Files skipped from review due to trivial changes (4)
- CHANGELOG.md
- .sisyphus/boulder.json
- .sisyphus/evidence/wave0-baseline.txt
- src/components/dashboard/alunos/columns.tsx
🚧 Files skipped from review as they are similar to previous changes (5)
- src/lib/data.ts
- src/services/alunoService.ts
- src/components/providers/i18n-provider.tsx
- src/lib/actions/treinos.ts
- src/services/gamificationService.ts
There was a problem hiding this comment.
2 issues found across 23 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/ai/flows/workout-generator-flow.ts">
<violation number="1" location="src/ai/flows/workout-generator-flow.ts:60">
P1: Streaming chunks are validated as full objects, so partial chunks are discarded and incremental streaming can stop working.</violation>
</file>
<file name=".sisyphus/boulder.json">
<violation number="1" location=".sisyphus/boulder.json:2">
P1: `active_plan` uses a hardcoded absolute path tied to the local development machine (`/home/emiyakiritsugu/...`). This path will not resolve on any other developer's machine or CI environment, making this configuration file non-portable and effectively broken outside the original machine. The target file already exists at `.sisyphus/plans/pr118-correction-optimization.md` relative to the repo root, so a relative path can be used instead.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| for await (const chunk of responseStream.stream) { | ||
| if (chunk?.output) { | ||
| sendChunk(chunk.output as WorkoutGeneratorAIOutput); | ||
| const parsed = WorkoutGeneratorAIOutputSchema.safeParse(chunk.output); |
There was a problem hiding this comment.
P1: Streaming chunks are validated as full objects, so partial chunks are discarded and incremental streaming can stop working.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/ai/flows/workout-generator-flow.ts, line 60:
<comment>Streaming chunks are validated as full objects, so partial chunks are discarded and incremental streaming can stop working.</comment>
<file context>
@@ -57,15 +57,22 @@ export const streamWorkoutPlan = ai.defineFlow(
for await (const chunk of responseStream.stream) {
if (chunk?.output) {
- sendChunk(chunk.output);
+ const parsed = WorkoutGeneratorAIOutputSchema.safeParse(chunk.output);
+ if (parsed.success) {
+ sendChunk(parsed.data);
</file context>
| @@ -0,0 +1,22 @@ | |||
| { | |||
| "active_plan": "/home/emiyakiritsugu/Projetos_Antigravity/PWeb_Project/.sisyphus/plans/pr118-correction-optimization.md", | |||
There was a problem hiding this comment.
P1: active_plan uses a hardcoded absolute path tied to the local development machine (/home/emiyakiritsugu/...). This path will not resolve on any other developer's machine or CI environment, making this configuration file non-portable and effectively broken outside the original machine. The target file already exists at .sisyphus/plans/pr118-correction-optimization.md relative to the repo root, so a relative path can be used instead.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .sisyphus/boulder.json, line 2:
<comment>`active_plan` uses a hardcoded absolute path tied to the local development machine (`/home/emiyakiritsugu/...`). This path will not resolve on any other developer's machine or CI environment, making this configuration file non-portable and effectively broken outside the original machine. The target file already exists at `.sisyphus/plans/pr118-correction-optimization.md` relative to the repo root, so a relative path can be used instead.</comment>
<file context>
@@ -0,0 +1,22 @@
+{
+ "active_plan": "/home/emiyakiritsugu/Projetos_Antigravity/PWeb_Project/.sisyphus/plans/pr118-correction-optimization.md",
+ "started_at": "2026-06-04T01:25:46.597Z",
+ "session_ids": [
</file context>
…er actions Define ActionResult<T = void> in error.ts as a conditional type so void actions omit the data property. Annotate all 5 alunos server actions (createAlunoAction, updateAlunoAction, deleteAlunoAction, createMatriculaAction, finalizarTreinoAction) with explicit return types and use 'satisfies ActionResult<T>' on success returns. Resolves 8 TS2339 errors in alunos-client.tsx (3) and alunos.test.ts (5) caused by async-inferred return types widening 'success: true' literal to 'boolean', breaking discriminated-union narrowing in 'if (result.success)' branches. Vercel preview deploy also expected to pass since 'next build' runs the same TS check. Tests use toEqual/toMatchObject to assert discriminated unions without depending on Vitest's runtime-only .toBe() narrowing.
There was a problem hiding this comment.
1 issue found across 3 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/ai/flows/workout-generator-flow.ts">
<violation number="1" location="src/ai/flows/workout-generator-flow.ts:60">
P1: Streaming chunks are validated as full objects, so partial chunks are discarded and incremental streaming can stop working.</violation>
</file>
<file name=".sisyphus/boulder.json">
<violation number="1" location=".sisyphus/boulder.json:2">
P1: `active_plan` uses a hardcoded absolute path tied to the local development machine (`/home/emiyakiritsugu/...`). This path will not resolve on any other developer's machine or CI environment, making this configuration file non-portable and effectively broken outside the original machine. The target file already exists at `.sisyphus/plans/pr118-correction-optimization.md` relative to the repo root, so a relative path can be used instead.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
The unscoped 'supabase' npm package (^2.92.1) is flagged CRITICAL by GHSA-x96m-c5fj-q75c as a typosquatted malware publication. The legitimate Supabase JS client is '@supabase/supabase-js' (scoped). Verified zero imports of 'supabase' in src/ — all Supabase usage is the scoped '@supabase/supabase-js' + '@supabase/ssr' packages. The unscoped package was a leftover, unused, malicious dep that was blocking CI's 'npm audit --audit-level=high' security gate (exit 1 on critical). Removes package + lockfile entries (198 lines). No code changes. Audit now passes with 0 high/critical vulnerabilities. CI Quality Gates fully green: typecheck clean, lint 0 errors, 86/86 tests, audit pass.
…ull cleanup Two review comment follow-ups: 1. **cubic P1** (alunos.ts:78): HistoricoTreinoSchema requires 'exercicios[]' field that doesn't exist on the Prisma HistoricoTreino model (which uses a 'SeriesExecutadas' relation table instead). My earlier ActionResult annotation introduced this parse() call which throws ZodError on every successful treino finalization, masking the action result as failure. Fix: change finalizarTreinoAction return type from ActionResult<HistoricoTreino> to ActionResult (void), drop the broken parse, simplify the to not capture the now-unused return value. Consumer (dashboard-client.tsx) only checks result.success, never .data. 2. **CodeRabbit MINOR** (dummyDb.ts:9): findById's return type is already Promise<T | null> per the signature, so 'as T | null' on line 9 is a redundant union — the cast should be 'as T'. Both flagged by AI review after the initial CI fix. Resolves 2 review threads without behavioral changes. typecheck clean, lint 0 errors, 86/86 tests.
The pinned @689fb39b... commit is no longer supported and contains a security vulnerability (per upstream deprecation warning emitted on every CI run). Additionally the old version is failing the Tests & Coverage job with a 403 when downloading the JRE from scanner.sonarcloud.io. Upgrade to @v6 (latest stable) to pick up the security fix and restore the scanner's ability to download the JRE. Single-line change, no other workflow modifications needed (action inputs are compatible).
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/ai/flows/workout-generator-flow.ts">
<violation number="1" location="src/ai/flows/workout-generator-flow.ts:60">
P1: Streaming chunks are validated as full objects, so partial chunks are discarded and incremental streaming can stop working.</violation>
</file>
<file name=".sisyphus/boulder.json">
<violation number="1" location=".sisyphus/boulder.json:2">
P1: `active_plan` uses a hardcoded absolute path tied to the local development machine (`/home/emiyakiritsugu/...`). This path will not resolve on any other developer's machine or CI environment, making this configuration file non-portable and effectively broken outside the original machine. The target file already exists at `.sisyphus/plans/pr118-correction-optimization.md` relative to the repo root, so a relative path can be used instead.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
PR commit 9edd2f9 (SonarQube fixes) refactored prisma/seed-e2e.ts from a working .catch().finally() chain pattern to: try { await seed(); } catch { ... } finally { await prisma.$disconnect(); ... } This introduces top-level await at module scope, which esbuild (invoked via 'npx tsx' in CI's 'Seed E2E test users' step) refuses to compile under the project's CJS output format: ERROR: Top-level await is currently not supported with the 'cjs' output format (prisma/seed-e2e.ts:212:2, 217:2, 218:2) E2E step fails immediately at seed before any Playwright test runs. Fix: wrap the try/catch/finally in an async main() function and call main() — preserves the PR's SonarCloud-friendly try/catch pattern while removing the top-level await. CJS-compatible, typecheck clean, lint 0 errors, 86/86 unit tests pass.
Revert 'ci(sonar): upgrade sonarqube-scan-action to v6' from this branch. The v6 action internally invokes SonarScanner CLI 7.2.0, which attempts to download the JRE from https://scanner.sonarcloud.io/jres/... and gets HTTP 403 on every run. The previous pinned SHA (which was cache-warm with CLI 6.2.1.4610 from the GitHub Actions cache) worked without hitting the JRE download URL. SonarCloud's JRE CDN currently rejects the new scanner version's request, so downgrading the action's JRE path is the only way to keep the 'Tests & Coverage' job green. The deprecation warning is a known issue, non-blocking. Address the SonarQube action upgrade in a separate PR once the JRE CDN stabilizes.
|
#120) PR #118 (commit 7e98bab on main) shipped 1.4.0 with 15 code quality fixes, but the existing 1.4.0 entry in CHANGELOG only documented the original 8 fixes from the PR body. The 5 follow-up fixes I added during PR review (ActionResult, malware supabase removal, dummyDb 'as T' cleanup, E2E seed fix, sonar action revert) were unrecorded. This commit backfills: **CHANGELOG.md (1.4.0 entry)** - 'Added' section: ActionResult<T> + dummyDb cast cleanup - 'Security' section: typosquatted supabase dep removal (GHSA-x96m-c5fj-q75c) - 'Fixed (CI/workflow)' section: seed-e2e top-level await + HistoricoTreinoSchema regression - 'Tests' section: 86/86 (was 71/71), 13 suites (was 10), 0 TS errors (was 8 pre-existing) - Date stamp: 2026-06-04 (was 2026-06-03) **README.md (Quality Gates section)** - 'npm run test': 66/66 (10 suites) → 86/86 (13 suites) **docs/CURRENT-STATE.md** - 'O que foi feito' expanded with the 5 follow-up fixes detail - 'Testes' updated: 86/86, 13 suites, 0 TS errors - 'Pendências Técnicas': rewritten to reflect the 8 TS errors are now resolved; remaining items (treinos-client fallbacks, Genkit 1.31 pinning) noted as follow-up candidates out of scope for #118 All edits are documentation only, no code changes. Prettier-clean. Co-authored-by: Emiya Kiritsugu <emiyakiritsugu3@users.noreply.github.com>



Summary
Fixes 15 code quality issues from code review across 10 files. 24 commits total (16 original + 8 new fixes).
Changes (New — Commits 17-24)
unknownreturnsunknowncasts + missing null checkas Record<string, unknown>replacedPrevious Changes (Commits 1-16)
getErrorMessageutility for safe error extractionnoUnusedLocals+noUnusedParametersenabled in tsconfighandleActionError/getZodErrorhelpersVerification
Summary by CodeRabbit
Bug Fixes
Tests
Chores