@@ -12,6 +12,7 @@ const GRADES_COLUMNS = {
1212 PR_URL : 12 , // Column L
1313 FUNCTIONAL_SCORE : 5 , // Column E
1414 TECHNICAL_SCORE : 7 , // Column G
15+ STRETCH_SCORE : 9 , // Column I
1516 GRADING_STATUS : 11 // Column K
1617} as const ;
1718
@@ -134,18 +135,28 @@ function processPullRequest(pr: any): {updated: boolean, message?: string} {
134135 return { updated : false , message : "Already graded" } ;
135136 }
136137
137- // 6) Update PR URL if different
138- if ( currentPrUrl !== prHyperlink ) {
138+ // 6) Check if there's already a PR number in the cell - don't overwrite existing PRs
139+ const currentPrUrlStr = currentPrUrl ? currentPrUrl . toString ( ) . trim ( ) : "" ;
140+
141+ // Skip if there's already a different PR URL/hyperlink in the cell
142+ // This prevents overwriting existing PR submissions with newer ones
143+ if ( currentPrUrlStr !== "" && currentPrUrlStr !== prHyperlink ) {
144+ return { updated : false , message : "Different PR already exists" } ;
145+ }
146+
147+ // 7) Update PR URL only if cell is empty (first submission for this student/lesson)
148+ if ( currentPrUrlStr === "" ) {
139149 sheet . getRange ( targetRow , GRADES_COLUMNS . PR_URL ) . setValue ( prHyperlink ) ;
140150 }
141151
142- // 7 ) Perform grading if not already done and if GRADING-COPILOT.md exists
152+ // 8 ) Perform grading if not already done and if GRADING-COPILOT.md exists
143153 if ( ! gradingStatus || gradingStatus . toString ( ) . trim ( ) === "" ) {
144154 const gradingResult = gradePullRequest ( pr , lessonNumber , changedFiles , studentName ) ;
145155 if ( gradingResult . success ) {
146156 // Update scores and status
147157 sheet . getRange ( targetRow , GRADES_COLUMNS . FUNCTIONAL_SCORE ) . setValue ( gradingResult . functionalScore ) ;
148158 sheet . getRange ( targetRow , GRADES_COLUMNS . TECHNICAL_SCORE ) . setValue ( gradingResult . technicalScore ) ;
159+ sheet . getRange ( targetRow , GRADES_COLUMNS . STRETCH_SCORE ) . setValue ( gradingResult . stretchScore ) ;
149160 sheet . getRange ( targetRow , GRADES_COLUMNS . GRADING_STATUS ) . setValue ( GRADING_STATUS . RECEIVED ) ;
150161
151162 return { updated : true , message : `Graded: F${ gradingResult . functionalScore } /T${ gradingResult . technicalScore } ` } ;
@@ -157,6 +168,11 @@ function processPullRequest(pr: any): {updated: boolean, message?: string} {
157168 // If no GRADING-COPILOT.md found, just skip grading (don't mark as error)
158169 }
159170
171+ // Return success if PR was newly added (even if grading was skipped)
172+ if ( currentPrUrlStr === "" ) {
173+ return { updated : true , message : "PR added (grading skipped - no criteria found)" } ;
174+ }
175+
160176 return { updated : false } ;
161177
162178 } catch ( error ) {
@@ -342,6 +358,7 @@ function gradePullRequest(pr: any, lessonNumber: string, changedFiles: string[],
342358 success : true ,
343359 functionalScore : analysis . functionalScore ,
344360 technicalScore : analysis . technicalScore ,
361+ stretchScore : analysis . stretchScore ,
345362 reviewCreated : reviewCreated
346363 } ;
347364
@@ -478,6 +495,7 @@ Please provide your analysis in the following JSON format:
478495{
479496 "functionalScore": <number 1-5>,
480497 "technicalScore": <number 1-5>,
498+ "technicalScore: <number 1-5, or 0 if no stretch criteria is provided>
481499 "feedback": "<detailed feedback explaining the scores>"
482500}
483501
@@ -522,6 +540,7 @@ Guidelines:
522540 return {
523541 functionalScore : Math . min ( Math . max ( analysis . functionalScore || 5 , 0 ) , 10 ) ,
524542 technicalScore : Math . min ( Math . max ( analysis . technicalScore || 5 , 0 ) , 10 ) ,
543+ stretchScore : Math . min ( Math . max ( analysis . stretchScore || 0 , 0 ) , 10 ) ,
525544 feedback : analysis . feedback || "Analysis completed" ,
526545 gradingInstructions
527546 } ;
@@ -604,6 +623,7 @@ interface GradingResult {
604623 success : boolean ;
605624 functionalScore ?: number ;
606625 technicalScore ?: number ;
626+ stretchScore ?: number ;
607627 reviewCreated ?: boolean ;
608628 error ?: string ;
609629}
@@ -616,6 +636,7 @@ interface PRContent {
616636interface GradingAnalysis {
617637 functionalScore : number ;
618638 technicalScore : number ;
639+ stretchScore : number ;
619640 feedback : string ;
620641 gradingInstructions : string ;
621642}
@@ -884,6 +905,7 @@ function testGradingSystem(): void {
884905 `Lesson: ${ lessonNumber } \n` +
885906 `Functional Score: ${ gradingResult . functionalScore } /10\n` +
886907 `Technical Score: ${ gradingResult . technicalScore } /10\n` +
908+ `Stretch Score: ${ gradingResult . stretchScore } /10\n` +
887909 `Draft Review: ${ gradingResult . reviewCreated ? 'Created' : 'Failed' } ` ,
888910 ui . ButtonSet . OK
889911 ) ;
0 commit comments