Skip to content

Main - #33

Open
sharvesh300 wants to merge 9 commits into
stagingfrom
main
Open

Main#33
sharvesh300 wants to merge 9 commits into
stagingfrom
main

Conversation

@sharvesh300

@sharvesh300 sharvesh300 commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features
    • Added SQLite SQL question creation, editing, previews, test cases, execution, and result tables.
    • Added question import previews with loading, retry, and error states.
    • Added per-submission score editing and summaries for contest reviews.
  • Bug Fixes
    • Improved contest-session status messaging, access controls, and registration cancellation rules.
    • Improved API error messages and validation feedback.
    • Added confirmation dialogs and loading states for destructive actions.
  • Style
    • Reformatted configuration and UI files without changing behavior.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d74aea69-6a5f-429f-8e41-e6086e945f33

📥 Commits

Reviewing files that changed from the base of the PR and between 3994229 and 93a2e20.

📒 Files selected for processing (1)
  • .gitignore

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

This PR adds SQLite question authoring, execution, preview, and contest rendering. It also updates contest-session status handling, API error normalization, deletion confirmations, registration cancellation, contest form errors, and submission score editing.

Changes

Question authoring and SQL execution

Layer / File(s) Summary
SQL contracts and payloads
src/constant/question-template.ts, src/hooks/use-question-form.ts, src/hooks/use-question-payload.ts, src/components/questions/question-metadata-card.tsx, src/components/questions/question-code-editor.tsx, src/components/questions/question-wizard.tsx, src/components/banks/bank-question-editor-client.tsx
Adds SQL question state, SQLite templates, SQL payload generation, question-type selection, fixed SQLite language handling, and ordered test-case defaults.
SQL editor and result authoring
src/components/contest/question-editor-shell.tsx, src/components/questions/sql-code-editor.tsx, src/components/questions/test-case-manager.tsx, src/components/shared/sql-result-table.tsx, src/components/questions/question-preview.tsx
Adds SQL-specific editor steps, validation, execution, expected-result generation, row-order controls, result parsing, and SQL preview rendering.
SQL preview and contest rendering
src/components/banks/question-import-client.tsx, src/components/student/contest/session/editor-panel.tsx, src/components/contest/shared/submission-viewers.tsx, src/components/student/contest/results/member-question-review.tsx
Adds question import previews and SQLite-aware contest output rendering and language mapping.

Session and contest workflows

Layer / File(s) Summary
Session status and API errors
src/lib/contest-session-status.ts, src/lib/handle-api-error.ts, src/lib/api/error.ts, src/lib/providers/tanstack-query-provider.tsx, src/components/student/contest/student-contest-detail-client.tsx, src/components/student/contest/session/session-client.tsx, src/app/(app)/student/contest/[id]/session/layout.tsx
Centralizes session completion and missed-state handling, normalizes structured API errors, suppresses duplicate mutation toasts, and updates session messages and status indicators.
Contest management and score interactions
src/components/audiences/audiences-client.tsx, src/components/contest/contest-detail-client.tsx, src/components/contest/contest-form.tsx, src/components/contest/contest-question-editor-client.tsx, src/components/contest/team-member-analytics/member-question-review.tsx, src/components/student/contest/contest-team-cards.tsx, src/components/student/contest/your-team-card.tsx, src/query/contest-query.ts
Adds controlled deletion dialogs, contest form field-error mapping, question-type creation, submission-level score editing, conditional registration cancellation, pending-state feedback, and removal of the obsolete score-hook re-export.

Formatting and configuration

Layer / File(s) Summary
Formatting and configuration support
.github/workflows/deploy.yml, components.json, eslint.config.mjs, postcss.config.mjs, src/app/not-found.tsx, src/components/ui/input.tsx, src/components/ui/textarea.tsx, .gitignore
Reformats workflow, tool, UI, and page files, nests the PostCSS plugin under plugins, and ignores graphify-out/.

Estimated code review effort: 5 (Critical) | ~120 minutes

Merge Risk: ⚪ Minimal · up to 93a2e

No actionable merge-blocking risk remains; the PR is merge-ready after normal checks and review.

Suggested reviewers: aksaykanthan

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.76% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 51 functions across 31 files. (1 skipped: 1 unsupported.) Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title "Main" is too vague and does not identify the pull request's primary changes. Replace "Main" with a concise title that describes the primary changes, such as SQL question support and improved contest-session error handling.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch main

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.

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

🧹 Nitpick comments (7)
src/components/audiences/audiences-client.tsx (1)

442-446: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reuse the shared API error helper.

This handler reads err.response.data.message directly. The repository already has handleApiError in src/lib/handle-api-error.ts, and toApiError in src/lib/api/error.ts. Both normalize Axios errors, network failures, and non-standard bodies. Use one of them here to keep error messages consistent across the app.

♻️ Proposed refactor
                 onError: (err: unknown) => {
-                    const msg = (err as { response?: { data?: { message?: string } } })?.response
-                        ?.data?.message;
-                    toast.error(msg || "Failed to delete audience");
+                    toast.error(handleApiError(err).message || "Failed to delete audience");
                 },

Add the import:

import { handleApiError } from "`@/lib/handle-api-error`";
🤖 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/components/audiences/audiences-client.tsx` around lines 442 - 446, Update
the delete audience onError handler in the audience client to use the shared
handleApiError helper instead of directly reading err.response.data.message, and
add the corresponding import from "`@/lib/handle-api-error`". Preserve the
existing fallback message and toast.error behavior while delegating API error
normalization to the shared helper.
src/components/student/contest/contest-team-cards.tsx (1)

372-375: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Define the cancellation rule through the shared session-status helpers.

src/lib/contest-session-status.ts already owns this domain logic, so canCancelRegistration should be a helper that handles completion_status and the already_started fallback. The generated status is already exposed as ContestSessionCompletionStatus, so centralizing the rule avoids a separate "NOT_STARTED" literal in this UI branch.

🤖 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/components/student/contest/contest-team-cards.tsx` around lines 372 -
375, Update the cancellation logic in the component around canCancelRegistration
to use a shared helper from contest-session-status.ts that accepts
completion_status and the already_started fallback, rather than comparing the
"NOT_STARTED" literal in the UI. Reuse the existing
ContestSessionCompletionStatus type and preserve the current behavior for both
explicit completion statuses and sessions without one.
src/components/questions/sql-code-editor.tsx (2)

27-44: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

STEP_COPY is typed as Record<string, …>, which removes the exhaustiveness check.

Line 67 reads STEP_COPY[step] and Lines 138-141 dereference the result. The index signature makes copy non-optional for any string key, so a future step value without an entry throws at runtime instead of failing the build. Key the record by the prop union.

STEP_COPY.starter is also unused: the editor shell never renders SqlCodeEditor with step="starter". See the related finding on ALL_STEPS_SQL in src/components/contest/question-editor-shell.tsx.

♻️ Key STEP_COPY by the step union
-const STEP_COPY: Record<string, { label: string; hint: string }> = {
+type SqlEditorStep = "schema" | "seed" | "starter" | "solution";
+
+const STEP_COPY: Record<SqlEditorStep, { label: string; hint: string }> = {
 interface SqlCodeEditorProps {
-    step: "schema" | "seed" | "starter" | "solution";
+    step: SqlEditorStep;
🤖 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/components/questions/sql-code-editor.tsx` around lines 27 - 44, Update
STEP_COPY to use the existing step prop union as its key type instead of
Record<string, …>, so missing step entries are caught at build time and
STEP_COPY[step] remains safely typed. Remove the unused starter entry, since
SqlCodeEditor is not rendered with step="starter", while preserving the existing
schema, seed, and solution copy.

204-222: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Replace the hard-coded palette colors with semantic status tokens.

Lines 208-209 use bg-emerald-500/10 text-emerald-500 and bg-amber-500/10 text-amber-500. Line 218 uses border-red-500/20 bg-red-500/10 text-red-400. The coding guidelines forbid hard-coded palette colors in components and define semantic pairs for status UI. The text-red-400 value also gives weak contrast on the light-theme tint.

Use success, warning, and destructive tokens instead. The same substitution applies to Lines 244-245, 266, and 279-284.

♻️ Use semantic status tokens
                                             "rounded-full px-2 py-0.5 text-[9px] font-bold",
                                             passedCount === totalCount
-                                                ? "bg-emerald-500/10 text-emerald-500"
-                                                : "bg-amber-500/10 text-amber-500",
+                                                ? "bg-success/10 text-success"
+                                                : "bg-warning/10 text-warning",
                                         )}
-                                <div className="flex items-start gap-2.5 rounded-lg border border-red-500/20 bg-red-500/10 p-3 text-xs text-red-400">
+                                <div className="flex items-start gap-2.5 rounded-lg border border-destructive/30 bg-destructive/5 p-3 text-xs text-destructive">

As per coding guidelines: "Do not hard-code palette colors in components unless there is a narrow external-branding requirement" and "Use semantic status UI pairs: bg-destructive text-destructive-foreground, bg-success text-success-foreground, bg-warning text-warning-foreground, and bg-info text-info-foreground".

🤖 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/components/questions/sql-code-editor.tsx` around lines 204 - 222, Replace
the hard-coded emerald, amber, and red classes in the status UI with the
semantic success, warning, and destructive token pairs, including the
corresponding usages around the passed-count badge and execution-error sections
at the other referenced locations. Use bg-success/text-success-foreground,
bg-warning/text-warning-foreground, and
bg-destructive/text-destructive-foreground as appropriate, preserving the
existing conditional status behavior.

Source: Coding guidelines

src/components/contest/question-editor-shell.tsx (1)

431-462: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

The step prop uses a type assertion instead of narrowing.

activeStep as "schema" | "seed" | "solution" disables the compiler check. If a step is later added to the SQL editor branch without updating the assertion, the mismatch stays silent. The nested ternary for value and the if/else chain for onChange also duplicate the same step-to-field mapping in two places.

Consider a single lookup table keyed by step, which removes the assertion and the duplication.

♻️ Map each SQL step to its field once
+                                        {/* Defined near the component top: */}
+                                        {/* const SQL_FIELDS = {
+                                                schema: [code.sqlSchema, code.setSqlSchema],
+                                                seed: [code.sqlSeed, code.setSqlSeed],
+                                                solution: [code.sqlSolution, code.setSqlSolution],
+                                            } as const; */}
🤖 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/components/contest/question-editor-shell.tsx` around lines 431 - 462,
Replace the `activeStep as "schema" | "seed" | "solution"` assertion and
duplicated `value`/`onChange` mappings in the `SqlCodeEditor` block with a
single typed lookup keyed by the supported SQL steps. Narrow `activeStep`
through that lookup before rendering, and use the selected entry’s value and
setter while preserving the existing `showExecution`, schema, and seed behavior.
src/hooks/use-question-payload.ts (1)

40-65: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract the shared payload fields to remove the duplicated return shape.

The SQL branch and the standard branch repeat ten identical fields. A future field addition must be applied twice.

♻️ Share a base payload between both branches
+        const base = {
+            title: metadata.title,
+            difficulty: metadata.difficulty,
+            question_text,
+            time_limit_ms: metadata.timeLimit,
+            memory_limit_mb: metadata.memoryLimit,
+            tag_ids: metadata.tags.filter(Boolean),
+            testcases: formattedTestCases,
+            score: metadata.score,
+            duration: metadata.duration ? Number(metadata.duration) : null,
+            max_submission: metadata.maxSubmission ? Number(metadata.maxSubmission) : null,
+        };
+
         if (isSql) {
             // SQL is single-language (SQLite): one implicit language, one template.
             const templates: QuestionTemplateCreate[] = [
                 {
                     language_id: SQL_LANGUAGE_ID,
                     starter_code: code.sqlStarter || "",
                     solution_code: code.sqlSolution || "",
                     driver_code: "",
                 },
             ];
             return {
-                title: metadata.title,
+                ...base,
                 question_type: QuestionType.SQL,
-                difficulty: metadata.difficulty,
-                question_text,
-                time_limit_ms: metadata.timeLimit,
-                memory_limit_mb: metadata.memoryLimit,
                 allowed_languages: [SQL_LANGUAGE_ID],
-                tag_ids: metadata.tags.filter(Boolean),
-                testcases: formattedTestCases,
                 templates,
-                score: metadata.score,
-                duration: metadata.duration ? Number(metadata.duration) : null,
-                max_submission: metadata.maxSubmission ? Number(metadata.maxSubmission) : 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/hooks/use-question-payload.ts` around lines 40 - 65, Refactor the payload
construction in the hook so the fields shared by the SQL and standard branches
are assembled once in a common base payload before the branch. Keep SQL-specific
values such as question_type, allowed_languages, and templates in the SQL
branch, while preserving the existing standard-branch overrides and returned
behavior.
src/components/shared/sql-result-table.tsx (1)

60-64: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use semantic theme tokens for the fallback output.

The dark:border-white, dark:bg-slate-950, and dark:text-slate-100 classes hard-code palette colors. Remove these overrides and retain the existing semantic border-border, bg-muted, and text-foreground tokens.

As per coding guidelines, “Do not hard-code palette colors in components unless there is a narrow external-branding requirement.”

🤖 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/components/shared/sql-result-table.tsx` around lines 60 - 64, Update the
fallback output `<pre>` styling in the SQL result table to remove the hard-coded
dark-mode palette overrides (`dark:border-white/10`, `dark:bg-slate-950/70`, and
`dark:text-slate-100`), retaining the existing semantic `border-border`,
`bg-muted`, and `text-foreground` tokens.

Source: Coding guidelines

🤖 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 @.github/workflows/deploy.yml:
- Around line 14-15: Update the checkout step using actions/checkout@v4 to set
persist-credentials to false, ensuring the GITHUB_TOKEN is not retained in
.git/config for subsequent Docker build steps.

In `@src/components/contest/contest-form.tsx`:
- Around line 406-426: Separate the instructor assignment call in the contest
submission flow from the contest-creation error handling: after
createContestMutation.mutateAsync succeeds, catch assignment errors
independently, report them as assignment failures, and still execute
router.push("/contest") and router.refresh() for the successfully created
contest. Keep contest creation failures on the existing "Could not create
contest" path, using createdContestId and assignInstructorsMutation as the
implementation anchors.

In `@src/components/contest/contest-question-editor-client.tsx`:
- Around line 84-95: Update the score field in the contest question editor to
make its non-persisted state clear when editing an existing contest-linked
question: disable the input in update mode or add a concise adjacent hint, while
preserving normal score editing for create mode.

In `@src/components/contest/question-editor-shell.tsx`:
- Line 38: Make the SQL question flow include the editable starter step: add
"starter" to ALL_STEPS_SQL and STEP_GROUPS_SQL, add its sidebar entry, and
update the SQL editor branch and value/onChange mapping to read and write
code.sqlStarter. Preserve the existing starter handling for non-SQL questions.

In `@src/components/contest/team-member-analytics/member-question-review.tsx`:
- Around line 421-431: Update the wrapper’s onKeyDown handler to process Enter
and Space only when event.target is the wrapper element itself, allowing key
events from SubmissionScoreEditor’s input and buttons to work normally. Preserve
the existing onToggle behavior for direct wrapper keyboard interaction; consider
removing role="button" and moving the toggle affordance to a dedicated chevron
button if implementing the ARIA follow-up.

In `@src/components/questions/question-metadata-card.tsx`:
- Around line 208-222: Update the question-type buttons in the question metadata
card to replace the ineffective outline suppression with the required visible
focus style using focus-visible:ring-ring, while preserving existing styling.
Add aria-pressed based on isActive so assistive technology can identify the
selected question type.

In `@src/components/questions/sql-code-editor.tsx`:
- Around line 104-108: Centralize schema-and-seed fixture construction by
exporting a compileSqlFixture(schema, seed) helper from question-template.ts,
then replace the inline `${schema}\n${seed}` expressions in this component,
use-question-payload, and handleGenerateExpectedOutput with that helper.
Preserve the current fixture output while ensuring all authoring, persistence,
and expected-output paths share one implementation.

In `@src/components/shared/sql-result-table.tsx`:
- Around line 24-28: Update the text-to-lines handling in the SQL result table
to preserve blank rows and trailing spaces: normalize CRLF line endings, remove
only one final record newline, and split without trimming or filtering lines so
values such as SELECT '' remain rendered.

In `@src/hooks/use-question-form.ts`:
- Around line 73-78: The SQL state handling around useQuestionPayload must not
fall back to any testcase.input value. When parsedText.sql is missing or
invalid, clear sqlSchema and sqlSeed, and preserve testcase.input unchanged;
require explicit author confirmation before allowing the payload to save.

In `@src/lib/providers/tanstack-query-provider.tsx`:
- Around line 45-51: Deduplicate the mapped detail messages in the apiError
toast construction before limiting them to three entries. Update the
detailMessages pipeline near toast.error so repeated messages are removed after
excluding apiError.message, while preserving the existing ordering and separator
formatting.

---

Nitpick comments:
In `@src/components/audiences/audiences-client.tsx`:
- Around line 442-446: Update the delete audience onError handler in the
audience client to use the shared handleApiError helper instead of directly
reading err.response.data.message, and add the corresponding import from
"`@/lib/handle-api-error`". Preserve the existing fallback message and toast.error
behavior while delegating API error normalization to the shared helper.

In `@src/components/contest/question-editor-shell.tsx`:
- Around line 431-462: Replace the `activeStep as "schema" | "seed" |
"solution"` assertion and duplicated `value`/`onChange` mappings in the
`SqlCodeEditor` block with a single typed lookup keyed by the supported SQL
steps. Narrow `activeStep` through that lookup before rendering, and use the
selected entry’s value and setter while preserving the existing `showExecution`,
schema, and seed behavior.

In `@src/components/questions/sql-code-editor.tsx`:
- Around line 27-44: Update STEP_COPY to use the existing step prop union as its
key type instead of Record<string, …>, so missing step entries are caught at
build time and STEP_COPY[step] remains safely typed. Remove the unused starter
entry, since SqlCodeEditor is not rendered with step="starter", while preserving
the existing schema, seed, and solution copy.
- Around line 204-222: Replace the hard-coded emerald, amber, and red classes in
the status UI with the semantic success, warning, and destructive token pairs,
including the corresponding usages around the passed-count badge and
execution-error sections at the other referenced locations. Use
bg-success/text-success-foreground, bg-warning/text-warning-foreground, and
bg-destructive/text-destructive-foreground as appropriate, preserving the
existing conditional status behavior.

In `@src/components/shared/sql-result-table.tsx`:
- Around line 60-64: Update the fallback output `<pre>` styling in the SQL
result table to remove the hard-coded dark-mode palette overrides
(`dark:border-white/10`, `dark:bg-slate-950/70`, and `dark:text-slate-100`),
retaining the existing semantic `border-border`, `bg-muted`, and
`text-foreground` tokens.

In `@src/components/student/contest/contest-team-cards.tsx`:
- Around line 372-375: Update the cancellation logic in the component around
canCancelRegistration to use a shared helper from contest-session-status.ts that
accepts completion_status and the already_started fallback, rather than
comparing the "NOT_STARTED" literal in the UI. Reuse the existing
ContestSessionCompletionStatus type and preserve the current behavior for both
explicit completion statuses and sessions without one.

In `@src/hooks/use-question-payload.ts`:
- Around line 40-65: Refactor the payload construction in the hook so the fields
shared by the SQL and standard branches are assembled once in a common base
payload before the branch. Keep SQL-specific values such as question_type,
allowed_languages, and templates in the SQL branch, while preserving the
existing standard-branch overrides and returned behavior.
🪄 Autofix

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e619d8f6-ad58-407e-bf21-55d5f83be40a

📥 Commits

Reviewing files that changed from the base of the PR and between 14f5505 and 3994229.

⛔ Files ignored due to path filters (26)
  • src/api/generated/contests/contests.ts is excluded by !**/generated/**
  • src/api/generated/images/images.ts is excluded by !**/generated/**
  • src/api/generated/model/contestCreate.ts is excluded by !**/generated/**
  • src/api/generated/model/contestDetailResponse.ts is excluded by !**/generated/**
  • src/api/generated/model/contestSessionCompletionStatus.ts is excluded by !**/generated/**
  • src/api/generated/model/contestSummaryResponse.ts is excluded by !**/generated/**
  • src/api/generated/model/contestUpdate.ts is excluded by !**/generated/**
  • src/api/generated/model/draftTestCase.ts is excluded by !**/generated/**
  • src/api/generated/model/index.ts is excluded by !**/generated/**
  • src/api/generated/model/instructorDashboardContest.ts is excluded by !**/generated/**
  • src/api/generated/model/questionCreate.ts is excluded by !**/generated/**
  • src/api/generated/model/questionResponse.ts is excluded by !**/generated/**
  • src/api/generated/model/questionTestCaseCreate.ts is excluded by !**/generated/**
  • src/api/generated/model/questionTestCaseResponse.ts is excluded by !**/generated/**
  • src/api/generated/model/questionType.ts is excluded by !**/generated/**
  • src/api/generated/model/studentContestSessionStatus.ts is excluded by !**/generated/**
  • src/api/generated/model/updateSubmissionScoreRequest.ts is excluded by !**/generated/**
  • src/api/generated/students/students.ts is excluded by !**/generated/**
  • src/api/generated/submissions/submissions.ts is excluded by !**/generated/**
  • src/api/generated/zod/bank-questions/bank-questions.ts is excluded by !**/generated/**
  • src/api/generated/zod/contests/contests.ts is excluded by !**/generated/**
  • src/api/generated/zod/images/images.ts is excluded by !**/generated/**
  • src/api/generated/zod/instructors/instructors.ts is excluded by !**/generated/**
  • src/api/generated/zod/questions/questions.ts is excluded by !**/generated/**
  • src/api/generated/zod/students/students.ts is excluded by !**/generated/**
  • src/api/generated/zod/submissions/submissions.ts is excluded by !**/generated/**
📒 Files selected for processing (38)
  • .github/workflows/deploy.yml
  • components.json
  • eslint.config.mjs
  • postcss.config.mjs
  • src/app/(app)/student/contest/[id]/session/layout.tsx
  • src/app/not-found.tsx
  • src/components/audiences/audiences-client.tsx
  • src/components/banks/bank-question-editor-client.tsx
  • src/components/banks/question-import-client.tsx
  • src/components/contest/contest-detail-client.tsx
  • src/components/contest/contest-form.tsx
  • src/components/contest/contest-question-editor-client.tsx
  • src/components/contest/question-editor-shell.tsx
  • src/components/contest/shared/submission-viewers.tsx
  • src/components/contest/team-member-analytics/member-question-review.tsx
  • src/components/questions/question-code-editor.tsx
  • src/components/questions/question-metadata-card.tsx
  • src/components/questions/question-preview.tsx
  • src/components/questions/question-wizard.tsx
  • src/components/questions/sql-code-editor.tsx
  • src/components/questions/test-case-manager.tsx
  • src/components/shared/sql-result-table.tsx
  • src/components/student/contest/contest-team-cards.tsx
  • src/components/student/contest/results/member-question-review.tsx
  • src/components/student/contest/session/editor-panel.tsx
  • src/components/student/contest/session/session-client.tsx
  • src/components/student/contest/student-contest-detail-client.tsx
  • src/components/student/contest/your-team-card.tsx
  • src/components/ui/input.tsx
  • src/components/ui/textarea.tsx
  • src/constant/question-template.ts
  • src/hooks/use-question-form.ts
  • src/hooks/use-question-payload.ts
  • src/lib/api/error.ts
  • src/lib/contest-session-status.ts
  • src/lib/handle-api-error.ts
  • src/lib/providers/tanstack-query-provider.tsx
  • src/query/contest-query.ts
💤 Files with no reviewable changes (1)
  • src/query/contest-query.ts

Comment on lines +14 to +15
- name: Checkout code
uses: actions/checkout@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow deploy.yml excerpt =="
if [ -f .github/workflows/deploy.yml ]; then
  nl -ba .github/workflows/deploy.yml | sed -n '1,120p'
else
  echo "missing .github/workflows/deploy.yml"
fi

echo
echo "== files likely relevant to Docker context =="
git ls-files | { grep -E '(^|/)Dockerfile(|\..*)$|^\.dockerignore$|workflow|docker' -i || true; }

echo
echo "== docker ignore and checkout persistence mentions =="
rg -n --hidden -S "persist-credentials|docker build|\.\s*$|\.git|GITHUB_TOKEN|actions/checkout" .github/workflows/deploy.yml .dockerignore Dockerfile .dockerignore 2>/dev/null || true

echo
echo "== deterministic diff check with git =="
git diff -- .github/workflows/deploy.yml .dockerignore Dockerfile 2>/dev/null | sed -n '1,200p' || true

Repository: Amrita-ICPC/Amrita-ICPC-Frontend

Length of output: 244


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
p = Path('.github/workflows/deploy.yml')
text = p.read_text() if p.exists() else ''
checks = {
    'has_checkout_v4': 'actions/checkout@v4' in text,
    'has_persist_false': 'persist-credentials: false' in text or 'persist-credentials: false' in text,
    'has_docker_build': 'docker build' in text or 'docker/build-action' in text,
    'has_dot_context': 'context: .' in text or 'context: "."' in text or '.gitignore' in text,
}
for k, v in checks.items():
    print(f'{k}={v}')
PY

Repository: Amrita-ICPC/Amrita-ICPC-Frontend

Length of output: 259


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow deploy.yml excerpt =="
python3 - <<'PY'
from pathlib import Path
p = Path('.github/workflows/deploy.yml')
for i, line in enumerate(p.read_text().splitlines(), 1):
    if i <= 120:
        print(f"{i:4}: {line}")
PY

echo
echo "== relevant files =="
git ls-files | grep -E '(^|/)Dockerfile(|\..*)$|^\.dockerignore$|\.github/workflows/deploy.yml' || true

echo
echo "== targeted repository content search =="
python3 - <<'PY'
from pathlib import Path
import re

paths = [Path('.github/workflows/deploy.yml')]
for root in Path('.').rglob('*'):
    name = root.name
    if root.is_file() and (name == 'Dockerfile' or name == '.dockerignore'):
        paths.append(root)

for path in paths:
    print(f"\n--- {path} ---")
    try:
        text = path.read_text(errors='replace')
    except Exception as e:
        print(e); continue
    for i, line in enumerate(text.splitlines(), 1):
        if any(k in line for k in ['actions/checkout', 'persist-credentials', 'docker build', 'docker/', 'context:', '.', '.git', 'GITHUB_TOKEN', 'cat', 'cp', 'ADD', 'COPY', 'RUN']):
            print(f"{i:4}: {line}")

print("\n--- config indicators ---")
text = Path('.github/workflows/deploy.yml').read_text()
checks = {
    'checkout_v4': bool(re.search(r'actions/checkout@v[0-9]', text)),
    'persist_false': 'persist-credentials: false' in text,
    'docker_build': 'docker build' in text or 'docker/build-action' in text,
    'docker_context_dot': bool(re.search(r'context:\s*["'']?\.,?\s*["'']?|context:\s*["'']?[.]?["'']?\n', text, re.S)),
    'gitignore_git': '.git' in Path('.gitignore').read_text(errors='replace') if Path('.gitignore').exists() else False,
    'dockerignore_git': '.git' in Path('.dockerignore').read_text(errors='replace') if Path('.dockerignore').exists() else False,
}
for k, v in checks.items():
    print(f"{k}={v}")
PY

Repository: Amrita-ICPC/Amrita-ICPC-Frontend

Length of output: 3120


🌐 Web query:

actions/checkout v4 persist-credentials default true

💡 Result:

In the GitHub actions/checkout v4 action, the persist-credentials input parameter defaults to true [1][2][3]. When set to true (the default), the action configures the Git authentication token or SSH key into the local Git configuration [1][4]. This allows subsequent steps in the same job to execute authenticated Git commands without requiring further configuration [1][5]. The token or key is removed during the action's post-job cleanup [1][4]. To disable this behavior, you must explicitly set persist-credentials to false in your workflow file [1][4]: - uses: actions/checkout@v4 with: persist-credentials: false While the default remains true [6], users should be aware that this configuration grants any subsequent step in the job the ability to use the credentials [4][7]. If your workflow does not require authenticated Git operations after the checkout step, setting this to false is a recommended security practice [6][7].

Citations:


Sensitive Data Exposure (CWE-522): Insufficiently Protected Credentials

Reachability: External · Exploitability: Moderate

Disable checkout credential persistence.

actions/checkout@v4 persists GITHUB_TOKEN in .git/config by default, and the following Docker build uses the repository context with local secrets in build args. Set persist-credentials: false for checkout so the token is not available to later build steps.

Proposed checkout change
             - name: Checkout code
               uses: actions/checkout@v4
+              with:
+                  persist-credentials: false
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Checkout code
uses: actions/checkout@v4
- name: Checkout code
uses: actions/checkout@v4
with:
persist-credentials: false
🧰 Tools
🪛 zizmor (1.29.0)

[warning] 14-15: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

🤖 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 @.github/workflows/deploy.yml around lines 14 - 15, Update the checkout step
using actions/checkout@v4 to set persist-credentials to false, ensuring the
GITHUB_TOKEN is not retained in .git/config for subsequent Docker build steps.

Source: Linters/SAST tools

Comment on lines +406 to +426
const createdContest = await createContestMutation.mutateAsync({
data: payload,
});
const createdData = createdContest.data;
const createdContestId =
createdData &&
typeof createdData === "object" &&
"id" in createdData &&
typeof createdData.id === "string"
? createdData.id
: null;
if (createdContestId && values.instructor_ids?.length) {
await assignInstructorsMutation.mutateAsync({
contestId: createdContestId,
data: { instructor_ids: values.instructor_ids },
});
}
}
}

router.push("/contest");
router.refresh();
router.push("/contest");
router.refresh();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Report instructor assignment failures separately from contest creation.

assignInstructorsMutation.mutateAsync runs inside the same try block. If contest creation succeeds and instructor assignment fails, the catch block shows "Could not create contest" and skips router.push("/contest"). The contest already exists. The user sees a create failure and can submit the form again, which creates a duplicate contest.

Handle the instructor assignment failure separately, and still navigate after a successful create.

🐛 Proposed fix
                     if (createdContestId && values.instructor_ids?.length) {
-                        await assignInstructorsMutation.mutateAsync({
-                            contestId: createdContestId,
-                            data: { instructor_ids: values.instructor_ids },
-                        });
+                        try {
+                            await assignInstructorsMutation.mutateAsync({
+                                contestId: createdContestId,
+                                data: { instructor_ids: values.instructor_ids },
+                            });
+                        } catch (instructorError) {
+                            toast.error("Contest created, but instructors were not assigned", {
+                                description: handleApiError(instructorError).message,
+                            });
+                        }
                     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const createdContest = await createContestMutation.mutateAsync({
data: payload,
});
const createdData = createdContest.data;
const createdContestId =
createdData &&
typeof createdData === "object" &&
"id" in createdData &&
typeof createdData.id === "string"
? createdData.id
: null;
if (createdContestId && values.instructor_ids?.length) {
await assignInstructorsMutation.mutateAsync({
contestId: createdContestId,
data: { instructor_ids: values.instructor_ids },
});
}
}
}
router.push("/contest");
router.refresh();
router.push("/contest");
router.refresh();
const createdContest = await createContestMutation.mutateAsync({
data: payload,
});
const createdData = createdContest.data;
const createdContestId =
createdData &&
typeof createdData === "object" &&
"id" in createdData &&
typeof createdData.id === "string"
? createdData.id
: null;
if (createdContestId && values.instructor_ids?.length) {
try {
await assignInstructorsMutation.mutateAsync({
contestId: createdContestId,
data: { instructor_ids: values.instructor_ids },
});
} catch (instructorError) {
toast.error("Contest created, but instructors were not assigned", {
description: handleApiError(instructorError).message,
});
}
}
}
router.push("/contest");
router.refresh();
🤖 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/components/contest/contest-form.tsx` around lines 406 - 426, Separate the
instructor assignment call in the contest submission flow from the
contest-creation error handling: after createContestMutation.mutateAsync
succeeds, catch assignment errors independently, report them as assignment
failures, and still execute router.push("/contest") and router.refresh() for the
successfully created contest. Keep contest creation failures on the existing
"Could not create contest" path, using createdContestId and
assignInstructorsMutation as the implementation anchors.

Comment on lines +84 to +95
// Note: the backend currently has no endpoint to update a question's score
// once it's linked to a contest (nor one that returns its current
// order/duration/max_submission, which would be needed to safely re-link
// it). The score field stays editable in the UI, but changes made here
// are not persisted until that capability exists on the backend.
const onUpdate = async () => {
await updateMutation.mutateAsync({
contestId,
questionId: questionId!,
data: payload,
});
await updateScoreMutation.mutateAsync({
contestId,
questionId: questionId!,
data: { score: payload.score },
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the score field reflect that edits are discarded.

The comment states that score changes are not persisted for a contest-linked question. The field stays editable, so a user can change the score, see a "Question updated successfully!" toast, and assume the score was saved. Disable the score input in update mode, or show a short hint next to it, until the backend endpoint exists.

I can open a tracking issue for the missing backend capability and prepare the UI change. Do you want me to do that?

🤖 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/components/contest/contest-question-editor-client.tsx` around lines 84 -
95, Update the score field in the contest question editor to make its
non-persisted state clear when editing an existing contest-linked question:
disable the input in update mode or add a concise adjacent hint, while
preserving normal score editing for create mode.

"driver",
"testcases",
] as const;
const ALL_STEPS_SQL = ["details", "statement", "schema", "seed", "solution", "testcases"] as const;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

ALL_STEPS_SQL omits the starter step, so the SQL starter query is never editable.

STEP_GROUPS_SQL also omits it. The author therefore cannot change code.sqlStarter, and useQuestionPayload persists the untouched DEFAULT_SQL_STARTER value (-- Write your query here) as starter_code for every new SQL question. Students then receive that placeholder as their initial query.

Two signals indicate the omission is unintentional: the starter case at Lines 220-223 contains an isSql branch that cannot be reached, and STEP_COPY in src/components/questions/sql-code-editor.tsx defines copy for a starter step that is never rendered.

If a fixed placeholder is intended, remove the unreachable isSql branch and the unused STEP_COPY.starter entry. Otherwise add the step.

🐛 Add the starter step to the SQL flow
-const ALL_STEPS_SQL = ["details", "statement", "schema", "seed", "solution", "testcases"] as const;
+const ALL_STEPS_SQL = [
+    "details",
+    "statement",
+    "schema",
+    "seed",
+    "starter",
+    "solution",
+    "testcases",
+] as const;

Also add the sidebar entry:

         title: "Judge Configuration",
         steps: [
             { id: "schema", label: "Schema" },
             { id: "seed", label: "Seed Data" },
+            { id: "starter", label: "Starter Query" },
             { id: "solution", label: "Solution Query" },
             { id: "testcases", label: "Test Cases" },
         ],

And include starter in the SQL editor branch:

-                                        {isSql &&
-                                            ["schema", "seed", "solution"].includes(activeStep) && (
+                                        {isSql &&
+                                            ["schema", "seed", "starter", "solution"].includes(
+                                                activeStep,
+                                            ) && (

The value/onChange mapping needs a matching starter case that reads and writes code.sqlStarter.

🤖 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/components/contest/question-editor-shell.tsx` at line 38, Make the SQL
question flow include the editable starter step: add "starter" to ALL_STEPS_SQL
and STEP_GROUPS_SQL, add its sidebar entry, and update the SQL editor branch and
value/onChange mapping to read and write code.sqlStarter. Preserve the existing
starter handling for non-SQL questions.

Comment on lines +421 to +431
<div
role="button"
tabIndex={0}
onClick={onToggle}
className="flex w-full flex-col gap-3 p-4 text-left transition-colors hover:bg-muted/30 sm:flex-row sm:items-center sm:justify-between"
onKeyDown={(event) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
onToggle();
}
}}
className="flex w-full cursor-pointer flex-col gap-3 p-4 text-left transition-colors hover:bg-muted/30 sm:flex-row sm:items-center sm:justify-between"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

The wrapper key handler intercepts keys from the nested score controls.

onKeyDown is attached to the wrapper, so it also receives events that bubble from the descendants. The wrapper now contains SubmissionScoreEditor, which renders a number input and submit/cancel buttons.

Two results follow:

  • A user presses Enter in the score input. The wrapper calls event.preventDefault() and onToggle(). This blocks the implicit form submit and toggles the card.
  • A user presses Space on the save or cancel button. The wrapper toggles the card.

onClick is already isolated with stopPropagation in the editor, but keydown is not. Restrict the wrapper handler to events that originate on the wrapper itself.

Also note that role="button" with focusable descendants is invalid ARIA. Consider moving the toggle affordance to a dedicated chevron button so the header is not a button role.

🐛 Proposed fix
                 onKeyDown={(event) => {
+                    if (event.target !== event.currentTarget) return;
                     if (event.key === "Enter" || event.key === " ") {
                         event.preventDefault();
                         onToggle();
                     }
                 }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div
role="button"
tabIndex={0}
onClick={onToggle}
className="flex w-full flex-col gap-3 p-4 text-left transition-colors hover:bg-muted/30 sm:flex-row sm:items-center sm:justify-between"
onKeyDown={(event) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
onToggle();
}
}}
className="flex w-full cursor-pointer flex-col gap-3 p-4 text-left transition-colors hover:bg-muted/30 sm:flex-row sm:items-center sm:justify-between"
<div
role="button"
tabIndex={0}
onClick={onToggle}
onKeyDown={(event) => {
if (event.target !== event.currentTarget) return;
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
onToggle();
}
}}
className="flex w-full cursor-pointer flex-col gap-3 p-4 text-left transition-colors hover:bg-muted/30 sm:flex-row sm:items-center sm:justify-between"
🤖 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/components/contest/team-member-analytics/member-question-review.tsx`
around lines 421 - 431, Update the wrapper’s onKeyDown handler to process Enter
and Space only when event.target is the wrapper element itself, allowing key
events from SubmissionScoreEditor’s input and buttons to work normally. Preserve
the existing onToggle behavior for direct wrapper keyboard interaction; consider
removing role="button" and moving the toggle affordance to a dedicated chevron
button if implementing the ARIA follow-up.

Comment on lines +208 to +222
<button
key={opt.value}
type="button"
disabled={typeLocked}
onClick={() => setQuestionType(opt.value)}
className={cn(
"flex-1 py-2.5 px-4 rounded-lg border text-left transition-all duration-200 outline-none",
typeLocked
? "cursor-not-allowed opacity-70"
: "cursor-pointer",
isActive
? "border-primary text-primary bg-primary/10 dark:bg-primary/20 dark:border-primary/50"
: "border-border/60 hover:border-primary/40 bg-card hover:bg-muted/40 text-muted-foreground",
)}
>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add a visible focus indicator to the question-type buttons.

The buttons set outline-none and define no replacement focus style. A keyboard user cannot see which option has focus. The coding guidelines require focus-visible:ring-ring for focus rings.

Consider also exposing the selected state to assistive technology with aria-pressed.

🛡️ Add focus-visible ring and pressed state
                                 <button
                                     key={opt.value}
                                     type="button"
                                     disabled={typeLocked}
+                                    aria-pressed={isActive}
                                     onClick={() => setQuestionType(opt.value)}
                                     className={cn(
-                                        "flex-1 py-2.5 px-4 rounded-lg border text-left transition-all duration-200 outline-none",
+                                        "flex-1 py-2.5 px-4 rounded-lg border text-left transition-all duration-200 outline-none focus-visible:ring-2 focus-visible:ring-ring",
                                         typeLocked
                                             ? "cursor-not-allowed opacity-70"
                                             : "cursor-pointer",

As per coding guidelines: "Use border-border, border-input, and ring-ring/focus-visible:ring-ring for borders, inputs, and focus rings".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<button
key={opt.value}
type="button"
disabled={typeLocked}
onClick={() => setQuestionType(opt.value)}
className={cn(
"flex-1 py-2.5 px-4 rounded-lg border text-left transition-all duration-200 outline-none",
typeLocked
? "cursor-not-allowed opacity-70"
: "cursor-pointer",
isActive
? "border-primary text-primary bg-primary/10 dark:bg-primary/20 dark:border-primary/50"
: "border-border/60 hover:border-primary/40 bg-card hover:bg-muted/40 text-muted-foreground",
)}
>
<button
key={opt.value}
type="button"
disabled={typeLocked}
aria-pressed={isActive}
onClick={() => setQuestionType(opt.value)}
className={cn(
"flex-1 py-2.5 px-4 rounded-lg border text-left transition-all duration-200 outline-none focus-visible:ring-2 focus-visible:ring-ring",
typeLocked
? "cursor-not-allowed opacity-70"
: "cursor-pointer",
isActive
? "border-primary text-primary bg-primary/10 dark:bg-primary/20 dark:border-primary/50"
: "border-border/60 hover:border-primary/40 bg-card hover:bg-muted/40 text-muted-foreground",
)}
>
🤖 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/components/questions/question-metadata-card.tsx` around lines 208 - 222,
Update the question-type buttons in the question metadata card to replace the
ineffective outline suppression with the required visible focus style using
focus-visible:ring-ring, while preserving existing styling. Add aria-pressed
based on isActive so assistive technology can identify the selected question
type.

Source: Coding guidelines

Comment on lines +104 to +108
test_cases: testCases.map((tc) => ({
input: `${schema}\n${seed}`,
expected_output: tc.output,
is_ordered: tc.is_ordered ?? true,
})),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

The schema-plus-seed fixture rule is duplicated in three places.

This component builds `${schema}\n${seed}`. src/hooks/use-question-payload.ts Line 28 builds the same string for the saved testcase input, and handleGenerateExpectedOutput in src/components/questions/test-case-manager.tsx builds it a third time. If one site changes the separator or adds a statement terminator, the authoring run stops matching the persisted fixture and expected results silently drift.

Export a single helper, for example compileSqlFixture(schema, seed), from src/constant/question-template.ts and call it from all three sites.

🤖 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/components/questions/sql-code-editor.tsx` around lines 104 - 108,
Centralize schema-and-seed fixture construction by exporting a
compileSqlFixture(schema, seed) helper from question-template.ts, then replace
the inline `${schema}\n${seed}` expressions in this component,
use-question-payload, and handleGenerateExpectedOutput with that helper.
Preserve the current fixture output while ensuring all authoring, persistence,
and expected-output paths share one implementation.

Comment on lines +24 to +28
const lines = text
.replace(/\r\n/g, "\n")
.split("\n")
.map((l) => l.trimEnd())
.filter((l) => l.length > 0);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve empty and trailing-space SQL values.

filter((l) => l.length > 0) drops blank data rows. trimEnd() removes trailing spaces from values. A result such as SELECT '' can render with a missing row.

Normalize line endings, then remove only one final record newline.

Proposed fix
-    const lines = text
-        .replace(/\r\n/g, "\n")
-        .split("\n")
-        .map((l) => l.trimEnd())
-        .filter((l) => l.length > 0);
+    const normalized = text.replace(/\r\n/g, "\n");
+    const lines = (normalized.endsWith("\n") ? normalized.slice(0, -1) : normalized).split("\n");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const lines = text
.replace(/\r\n/g, "\n")
.split("\n")
.map((l) => l.trimEnd())
.filter((l) => l.length > 0);
const normalized = text.replace(/\r\n/g, "\n");
const lines = (normalized.endsWith("\n") ? normalized.slice(0, -1) : normalized).split("\n");
🤖 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/components/shared/sql-result-table.tsx` around lines 24 - 28, Update the
text-to-lines handling in the SQL result table to preserve blank rows and
trailing spaces: normalize CRLF line endings, remove only one final record
newline, and split without trimming or filtering lines so values such as SELECT
'' remain rendered.

Comment on lines +73 to +78
// Shared SQL schema/seed live in a namespaced sub-object; the
// compiled testcase.input is a derived artifact and ignored here.
if (parsedText.sql) {
setSqlSchema(parsedText.sql.schema ?? "");
setSqlSeed(parsedText.sql.seed ?? "");
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether persisted SQL questions carry the `sql` blob and how testcase.input is consumed.
set -euo pipefail

# Find every producer/consumer of the namespaced sql blob.
rg -n -C4 'parsedText\.sql|sql:\s*\{\s*schema' --type=ts --type=tsx

# Inspect the generated testcase response contract for an input field usable as fallback.
fd -t f 'questionTestCaseResponse.ts' src/api/generated --exec cat -n

Repository: Amrita-ICPC/Amrita-ICPC-Frontend

Length of output: 202


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files matching use-question-form and use-question-payload and generated testcase response =="
fd -i 'use-question-form\.(ts|tsx)\|use-question-payload\.(ts|tsx)\|questionTestCaseResponse\.(ts|tsx)' .

echo
echo "== search SQL blob references =="
rg -n -C4 'parsedText\.sql|sql:\s*\{\s*schema|DEFAULT_SQL_SCHEMA|DEFAULT_SQL_SEED|recompile|useQuestionPayload' --glob '*.{ts,tsx}' .

echo
echo "== generated testcase response contracts =="
fd -i 'questionTestCaseResponse\.(ts|tsx)' . --exec cat -n \;

Repository: Amrita-ICPC/Amrita-ICPC-Frontend

Length of output: 9481


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== src/hooks/use-question-form.ts =="
cat -n src/hooks/use-question-form.ts

echo
echo "== src/hooks/use-question-payload.ts =="
cat -n src/hooks/use-question-payload.ts

echo
echo "== question template SQL defaults =="
cat -n src/constant/question-template.ts

echo
echo "== question-related API responses/models =="
fd -i 'questionResponse|testCase|question' src/api/generated -e ts -e tsx -e json | sort | xargs -r -n 1 sh -c 'echo "--- $0"; sed -n "1,220p" "$0"'

Repository: Amrita-ICPC/Amrita-ICPC-Frontend

Length of output: 50389


Do not reuse testcase input as the SQL schema/seed fallback.

useQuestionPayload builds SQL testcase input from code.sqlSchema and code.sqlSeed, while test cases are loaded with the stored input values. Deriving the fallback from the first testcase input would replace testcase.input with schema/seed content instead of preserving it. When the sql blob is missing or invalid, clear sqlSchema/sqlSeed and require explicit author confirmation before saving.

🤖 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/hooks/use-question-form.ts` around lines 73 - 78, The SQL state handling
around useQuestionPayload must not fall back to any testcase.input value. When
parsedText.sql is missing or invalid, clear sqlSchema and sqlSeed, and preserve
testcase.input unchanged; require explicit author confirmation before allowing
the payload to save.

Comment on lines +45 to +51
const detailMessages = apiError.errors
.map((detail) => detail.message)
.filter((message) => message !== apiError.message);
toast.error(apiError.message, {
description: detailMessages.length
? detailMessages.slice(0, 3).join(" • ")
: undefined,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Deduplicate detail messages before truncation.

The current filter removes only the primary message. Repeated detail messages can fill all three slots and hide a distinct validation error. Deduplicate detailMessages before slice(0, 3).

Proposed fix
-                    const detailMessages = apiError.errors
-                        .map((detail) => detail.message)
-                        .filter((message) => message !== apiError.message);
+                    const detailMessages = [
+                        ...new Set(
+                            apiError.errors
+                                .map((detail) => detail.message)
+                                .filter((message) => message !== apiError.message),
+                        ),
+                    ];
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const detailMessages = apiError.errors
.map((detail) => detail.message)
.filter((message) => message !== apiError.message);
toast.error(apiError.message, {
description: detailMessages.length
? detailMessages.slice(0, 3).join(" • ")
: undefined,
const detailMessages = [
...new Set(
apiError.errors
.map((detail) => detail.message)
.filter((message) => message !== apiError.message),
),
];
toast.error(apiError.message, {
description: detailMessages.length
? detailMessages.slice(0, 3).join(" • ")
: undefined,
🤖 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/providers/tanstack-query-provider.tsx` around lines 45 - 51,
Deduplicate the mapped detail messages in the apiError toast construction before
limiting them to three entries. Update the detailMessages pipeline near
toast.error so repeated messages are removed after excluding apiError.message,
while preserving the existing ordering and separator formatting.

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