Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ protected String getHttpCachePath() {
protected Long getInsertTime(String cachePath, String key) {
String redisKey = buildRedisKey(cachePath, key);
Object json = valueOps.get(redisKey + EXPIRATION_SUFFIX);
if (json == null) {
return 0L;
}
Expiration expiration = gson.fromJson(json.toString(), Expiration.class);
if (expiration != null) {
return expiration.getTimestamp();
Comment on lines 47 to 55

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

🦩 πŸ”΄ RedisCacheService.getInsertTime NPEs when expiration key is absent

In getInsertTime (RedisCacheService.java), added a null check on json immediately after fetching it via valueOps.get(redisKey + EXPIRATION_SUFFIX), returning 0L when null, before calling json.toString(). This matches the suggested fix exactly and prevents the NullPointerException when the expiration key is absent.

πŸ€– Prompt for AI agents
In backend/src/main/java/cx/flamingo/analysis/cache/impl/RedisCacheService.java around line 45, review and complete this code-review fix: RedisCacheService.getInsertTime NPEs when expiration key is absent.
What the draft fix changed: In `getInsertTime` (RedisCacheService.java), added a null check on `json` immediately after fetching it via `valueOps.get(redisKey + EXPIRATION_SUFFIX)`, returning `0L` when null, before calling `json.toString()`. This matches the suggested fix exactly and prevents the NullPointerException when the expiration key is absent.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟒 95 high β€” react πŸ‘/πŸ‘Ž to teach the reviewer

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ private void serializeArguments(StringBuilder builder, Map<String, Object> args)

for (Map.Entry<String, Object> entry : args.entrySet()) {
String value = entry.getValue() instanceof String
? entry.getValue().toString() // Don't add extra quotes
? "\"" + entry.getValue().toString() + "\"" // Add quotes for string values
: entry.getValue().toString();
joiner.add(entry.getKey() + ": " + value);
}
Comment on lines 53 to 59

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

🦩 🟠 QuerySerializer.serializeArguments has dead-code ternary that always evaluates identically

In serializeArguments, the ternary's true-branch (String values) now wraps the value in escaped double quotes ("\"" + entry.getValue().toString() + "\"") instead of duplicating the non-string branch, so string GraphQL argument values are emitted as quoted literals (e.g. name: "hello") while non-string values remain unquoted (e.g. numbers, booleans). This is the minimal fix restoring the intended behavior described by the comment; it does not add escaping of internal quotes/special characters within the string value, which a more complete fix might require.

πŸ€– Prompt for AI agents
In backend/src/main/java/cx/flamingo/analysis/graphql/QuerySerializer.java around line 51, review and complete this code-review fix: QuerySerializer.serializeArguments has dead-code ternary that always evaluates identically.
What the draft fix changed: In serializeArguments, the ternary's true-branch (String values) now wraps the value in escaped double quotes (`"\"" + entry.getValue().toString() + "\""`) instead of duplicating the non-string branch, so string GraphQL argument values are emitted as quoted literals (e.g. `name: "hello"`) while non-string values remain unquoted (e.g. numbers, booleans). This is the minimal fix restoring the intended behavior described by the comment; it does not add escaping of internal quotes/special characters within the string value, which a more complete fix might require.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 85 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

Expand All @@ -64,4 +64,4 @@ private void serializeArguments(StringBuilder builder, Map<String, Object> args)
private StringBuilder appendIndent(StringBuilder builder) {
return builder.append(" ".repeat(indent));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,6 @@ private void printTokensStatus() {
* endpoint to get remaining requests and reset time.
*/
public synchronized void initializeRateLimits() {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

🦩 πŸ”΄ initializeRateLimits is a no-op after first call due to alreadyInitialized guard, so rate limits never refresh after startup

Removed the alreadyInitialized early-return guard at the top of initializeRateLimits() so the method always performs the GitHub rate-limit fetch and updates each token's headers on every call. The alreadyInitialized field is retained (still set to true at the end of the method, preserving its value/semantics for any external readers via the Lombok @Getter) but no longer blocks re-execution, so the "wait then re-check" retry loop in getBestAvailableClient will now actually refresh rate-limit data from GitHub instead of silently no-op'ing. Risk: this method now performs a real HTTP call per token on every invocation instead of only once, which is the correct/intended behavior per the finding but increases GitHub API call volume during retries β€” no additional throttling/backoff was added beyond what already existed in getBestAvailableClient.

πŸ€– Prompt for AI agents
In backend/src/main/java/cx/flamingo/analysis/rate/GithubTokenRateManager.java around line 97, review and complete this code-review fix: initializeRateLimits is a no-op after first call due to alreadyInitialized guard, so rate limits never refresh after startup.
What the draft fix changed: Removed the `alreadyInitialized` early-return guard at the top of `initializeRateLimits()` so the method always performs the GitHub rate-limit fetch and updates each token's headers on every call. The `alreadyInitialized` field is retained (still set to `true` at the end of the method, preserving its value/semantics for any external readers via the Lombok `@Getter`) but no longer blocks re-execution, so the "wait then re-check" retry loop in `getBestAvailableClient` will now actually refresh rate-limit data from GitHub instead of silently no-op'ing. Risk: this method now performs a real HTTP call per token on every invocation instead of only once, which is the correct/intended behavior per the finding but increases GitHub API call volume during retries β€” no additional throttling/backoff was added beyond what already existed in `getBestAvailableClient`.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 80 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

if (alreadyInitialized) {
return;
}
alreadyInitialized = true;
for (Map.Entry<String, Pair<GithubToken, WebClient>> entry : tokenMap.entrySet()) {
String token = entry.getKey();
try {
Expand All @@ -123,6 +119,7 @@ public synchronized void initializeRateLimits() {
token.substring(0, 8), e.getMessage());
}
}
alreadyInitialized = true;
printTokensStatus();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class PreCacheService {
CacheServiceAbs cacheService;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

🦩 🟠 fixedDelay=1000ms scheduled cache-refresh cycle likely reruns immediately, causing continuous re-fetch churn

In runFullCacheCycle's @Scheduled annotation, changed fixedDelay from 1000l (1 second) to 3600000l (1 hour), so the full cache refresh cycle no longer restarts almost immediately after completion but instead runs hourly, while initialDelay remains unchanged so it still runs on startup. The exact interval value (1 hour) is a reasonable default per the finding's suggestion but was not explicitly specified elsewhere in the codebase, so a reviewer should confirm the desired refresh period.

πŸ€– Prompt for AI agents
In backend/src/main/java/cx/flamingo/analysis/service/PreCacheService.java around line 28, review and complete this code-review fix: fixedDelay=1000ms scheduled cache-refresh cycle likely reruns immediately, causing continuous re-fetch churn.
What the draft fix changed: In `runFullCacheCycle`'s `@Scheduled` annotation, changed `fixedDelay` from `1000l` (1 second) to `3600000l` (1 hour), so the full cache refresh cycle no longer restarts almost immediately after completion but instead runs hourly, while `initialDelay` remains unchanged so it still runs on startup. The exact interval value (1 hour) is a reasonable default per the finding's suggestion but was not explicitly specified elsewhere in the codebase, so a reviewer should confirm the desired refresh period.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 70 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

// Always run the cache refresh cycle on startup
@Scheduled(initialDelay = 1000l, fixedDelay = 1000l)
@Scheduled(initialDelay = 1000l, fixedDelay = 3600000l)
void runFullCacheCycle() {
Instant startTime = Instant.now();
log.info("Starting cache refresh cycle for all languages...");
Expand All @@ -53,3 +53,4 @@ void runFullCacheCycle() {
totalDuration.getSeconds() % 60);
}
}

14 changes: 2 additions & 12 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CssBaseline, ThemeProvider } from '@mui/material';
import { useMemo, useEffect } from 'react';
import { useMemo } from 'react';
import { getTheme } from './theme';
import { Layout } from './components/Layout';
import { FiltersPanel } from './components/FiltersPanel';
Expand All @@ -26,10 +26,6 @@ const MainApp = () => {

const { urlState } = useUrlState();

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

🦩 πŸ”΅ console.log left in production App.tsx fetch path

Removed the console.log('App: URL state changed:', urlState) call along with its wrapping useEffect in MainApp, and removed the now-unused console.log('Fetching contributors with params:', ...) call inside the queryFn of the useQuery call in MainApp. Also removed the now-unused useEffect import from React since it was only used for the removed effect. This eliminates the debug scaffolding logging on every render/query-key change without altering any other behavior.

πŸ€– Prompt for AI agents
In frontend/src/App.tsx around line 28, review and complete this code-review fix: console.log left in production App.tsx fetch path.
What the draft fix changed: Removed the `console.log('App: URL state changed:', urlState)` call along with its wrapping `useEffect` in `MainApp`, and removed the now-unused `console.log('Fetching contributors with params:', ...)` call inside the `queryFn` of the `useQuery` call in `MainApp`. Also removed the now-unused `useEffect` import from React since it was only used for the removed effect. This eliminates the debug scaffolding logging on every render/query-key change without altering any other behavior.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟒 90 high β€” react πŸ‘/πŸ‘Ž to teach the reviewer

useEffect(() => {
console.log('App: URL state changed:', urlState);
}, [urlState]);

const { data: contributors = [], isLoading, error } = useQuery({
queryKey: [
'contributors',
Expand All @@ -40,13 +36,6 @@ const MainApp = () => {
urlState.teamId
],
queryFn: ({ signal }) => {
console.log('Fetching contributors with params:', {
cityId: urlState.selectedCityId,
regionId: urlState.selectedRegionId,
stateId: urlState.stateId,
languageId: urlState.languageId,
teamId: urlState.teamId
});
return getContributors({
cityId: urlState.selectedCityId || undefined,
regionId: urlState.selectedRegionId || undefined,
Expand Down Expand Up @@ -88,3 +77,4 @@ export const App = () => {
};

export default App;

3 changes: 2 additions & 1 deletion frontend/src/services/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { HiringManagerProfile, JobOpening } from '../types/hiring';

// Configure axios to use the backend URL from environment
const BACKEND_API_URL = process.env.BACKEND_API_URL || '/';

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

🦩 🟠 Frontend logs the resolved backend API URL to the console in production builds

In the module-level initialization code of frontend/src/services/api.ts, wrapped the console.log('API Service: Using backend URL:', BACKEND_API_URL) call in an if (process.env.NODE_ENV !== 'production') guard, exactly as suggested, so the resolved backend URL is not logged in production bundles.

πŸ€– Prompt for AI agents
In frontend/src/services/api.ts around line 6, review and complete this code-review fix: Frontend logs the resolved backend API URL to the console in production builds.
What the draft fix changed: In the module-level initialization code of `frontend/src/services/api.ts`, wrapped the `console.log('API Service: Using backend URL:', BACKEND_API_URL)` call in an `if (process.env.NODE_ENV !== 'production')` guard, exactly as suggested, so the resolved backend URL is not logged in production bundles.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟒 90 high β€” react πŸ‘/πŸ‘Ž to teach the reviewer

console.log('API Service: Using backend URL:', BACKEND_API_URL);
if (process.env.NODE_ENV !== 'production') { console.log('API Service: Using backend URL:', BACKEND_API_URL); }

axios.defaults.baseURL = BACKEND_API_URL;

Expand Down Expand Up @@ -223,3 +223,4 @@ export const getJobOpenings = async (): Promise<JobOpening[]> => {
}
return response.data.data;
}; // Force rebuild Sun Aug 31 19:49:51 EDT 2025