Skip to content

PM-3926 ai screening phase#76

Open
vas3a wants to merge 6 commits intodevelopfrom
PM-3926_ai-screening-phase
Open

PM-3926 ai screening phase#76
vas3a wants to merge 6 commits intodevelopfrom
PM-3926_ai-screening-phase

Conversation

@vas3a
Copy link
Collaborator

@vas3a vas3a commented Mar 10, 2026

https://topcoder.atlassian.net/browse/PM-3926

This pull request introduces support for an "AI Screening" phase in challenges that have AI reviewers, ensuring that this phase is properly inserted after the submission phase and before review phases.

  • Added a new addAIScreeningPhaseForChallengeCreation method to challenge-helper.js to automatically insert the "AI Screening" phase after the submission phase for challenges with AI reviewers, update review phase predecessors, and recalculate phase dates.
  • Updated challenge creation logic in ChallengeService.js to invoke the new helper and recalculate challenge end date if the AI screening phase is added.
  • added migration file for inserting "AI Screening" phase definition + seed file
  • updated phase ordering in phase-helper.js to position the "AI Screening" phase correctly between submission and review phases, and update predecessors accordingly.

@vas3a vas3a requested review from jmgasper and kkartunov March 10, 2026 10:31
"updatedAt",
"updatedBy"
) VALUES (
'9f4e3b2a-7c1d-4e9f-b8a6-5d3c1a9f2b4e',

Choose a reason for hiding this comment

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

[⚠️ correctness]
Consider using a UUID generation function to ensure the id is unique and not hardcoded. This reduces the risk of ID collisions in the future.

'AI Screening Phase',
true,
14400,
'2025-03-10T13:08:02.378Z',

Choose a reason for hiding this comment

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

[⚠️ correctness]
The createdAt and updatedAt timestamps are hardcoded. Consider using the current timestamp function (e.g., NOW()) to ensure these fields reflect the actual time of insertion.

return response.data;
} catch (err) {
if (_.get(err, "response.status") === HttpStatus.NOT_FOUND) {
if (_.get(err, "response.status") === HttpStatus.StatusCodes.NOT_FOUND) {

Choose a reason for hiding this comment

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

[❗❗ correctness]
The change from HttpStatus.NOT_FOUND to HttpStatus.StatusCodes.NOT_FOUND is incorrect. The correct usage should be HttpStatus.NOT_FOUND as per the http-status-codes package documentation.

* @param {Function} logDebugMessage optional logging function
*/
async addAIScreeningPhaseForChallengeCreation(challenge, prisma, logDebugMessage = () => {}) {
if (!challenge || !challenge.phases || !Array.isArray(challenge.reviewers)) {

Choose a reason for hiding this comment

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

[⚠️ correctness]
Consider adding validation to ensure challenge.phases is an array before proceeding. This will prevent potential runtime errors if challenge.phases is not initialized as an array.


// Check if there are any AI reviewers
const hasAIReviewers = challenge.reviewers.some((reviewer) => !reviewer.isMemberReview && reviewer.aiWorkflowId);

Choose a reason for hiding this comment

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

[⚠️ security]
The condition reviewer.aiWorkflowId assumes that aiWorkflowId is a valid identifier. Ensure that aiWorkflowId is validated or sanitized to prevent potential security issues.


// Recalculate phase dates to keep timeline in sync
if (submissionPhase.scheduledEndDate) {
aiScreeningPhase.scheduledStartDate = submissionPhase.scheduledEndDate;

Choose a reason for hiding this comment

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

[💡 performance]
The use of moment for date manipulation is correct, but consider using native JavaScript date methods or a lighter library if possible, as moment is a large dependency and may impact performance.

// to incorrectly push earlier phases forward. Sorting by template order prevents that.
const orderIndex = new Map();
_.each(timelineTempate, (tplPhase, idx) => orderIndex.set(tplPhase.phaseId, idx));
const submissionPhaseName = SUBMISSION_PHASE_PRIORITY.find((name) =>

Choose a reason for hiding this comment

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

[⚠️ performance]
The use of _.some to find the submission phase name is potentially inefficient as it iterates over challengePhases multiple times. Consider using a single loop to find both the phase name and the phase itself to improve performance.

return updatedPhase;
});

const aiScreeningPhase = _.find(updatedPhases, (phase) => phase.name === "AI Screening");

Choose a reason for hiding this comment

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

[💡 maintainability]
The logic for updating the predecessor of phases that include 'review' in their name is case-insensitive, which is good. However, it might be more robust to explicitly list the review phases if they are known, to avoid accidental matches with other phases that might include 'review' in their name.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant