Skip to content

Debate statements displayed as long paragraphs instead of bullet points in UI#352

Open
Naman-kr404 wants to merge 5 commits intoAOSSIE-Org:mainfrom
Naman-kr404:main
Open

Debate statements displayed as long paragraphs instead of bullet points in UI#352
Naman-kr404 wants to merge 5 commits intoAOSSIE-Org:mainfrom
Naman-kr404:main

Conversation

@Naman-kr404
Copy link

@Naman-kr404 Naman-kr404 commented Mar 12, 2026

Addressed Issues:

Fixes #351

Screenshots/Recordings:

Before
image

Displaying these arguments in paragraph format makes the debate harder to read and follow, especially when multiple arguments are presented in a single response.

After
image

Summary by CodeRabbit

  • New Features

    • Bot opening statements now display as bullet points instead of prose format for improved clarity.
    • Message text formatting enhanced to detect and render bullet points automatically while preserving line breaks.
  • Bug Fixes

    • Improved stability of judgment and verdict display with better handling of missing or incomplete data scenarios.

@coderabbitai
Copy link

coderabbitai bot commented Mar 12, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR updates debate statement rendering to display as bullet points instead of prose, modifies the backend prompt to request bullet-point format, and adds defensive validation and null-safety handling to judgment popup components.

Changes

Cohort / File(s) Summary
Backend Prompt Update
backend/services/debatevsbot.go
Modified opening-statement instruction in constructPrompt to request bullet-point format instead of prose output; added blank line spacing.
Frontend Formatting
frontend/package.json
Corrected JSON indentation on devDependencies key.
Message Rendering
frontend/src/Pages/DebateRoom.tsx
Added conditional message rendering: detects bullet-point format (containing "- " pattern) and renders as <ul> list; otherwise preserves line breaks with whitespace-pre-line.
Judgment Data Validation & Rendering
frontend/src/Pages/DebateRoom.tsx, frontend/src/components/JudgementPopup.tsx
Introduced defensive validation in DebateRoom to detect missing opening_statement/verdict fields and build safe defaults; added setTimeout delay before showing judgment popup. Enhanced JudgementPopup with null-safety helpers (asNumber, asString), try/catch error handling, optional chaining for verdict/reason fields, and fallback rendering for missing judgment data.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~35 minutes

Possibly related PRs

Poem

🐰 Bullet points hop with glee,
No more prose paragraphs, see?
Judgment guards against the unknown,
Safe defaults help ideas be shown.
Debates now sparkle, crisp and bright! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: converting paragraph display format to bullet points in the UI, which is the core objective of the PR.
Linked Issues check ✅ Passed The PR addresses issue #351 by modifying both backend (bullet-point instruction) and frontend (bullet-point rendering logic) to render debate statements as bullet points instead of paragraphs.
Out of Scope Changes check ✅ Passed The frontend/package.json indentation fix is a minor formatting correction unrelated to the main feature but acceptable as a housekeeping change in the same PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

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 and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/services/debatevsbot.go`:
- Around line 172-185: The hard-coded "Maximum 5 bullets" in pointInstruction
causes cross-phase semantics issues; change the instruction generation to be
phase-aware by removing the global limit from pointInstruction and instead
generate or append a scoped bullet-count constraint only when appropriate (e.g.,
pass a maxBullets parameter or a boolean allowMultipleBullets into the function
that builds pointInstruction and similar strings at the other occurrence around
lines 251-283), and for the question/answer phase (the
single-question/single-answer flow driven by the frontend) ensure the generator
does not enforce multiple bullets—use a nil/0 or explicit maxBullets=1 to
enforce one bullet per turn. Ensure you update all occurrences (pointInstruction
and the other instruction string) to use this parameterized builder so phase
semantics remain consistent.

In `@frontend/src/Pages/DebateRoom.tsx`:
- Around line 682-689: The renderer currently treats any occurrence of "- "
inside msg.text as bullets; change it to detect bullets only at line starts by
checking msg.text.split('\n') for lines whose trimmed start begins with "- ".
When rendering, split only on newline boundaries, filter lines that start with a
leading hyphen (use trimmed start detection), strip the leading "- " from each
bullet line (e.g., remove /^\s*-\s+/), and render those as <li> items; keep the
existing whitespace-pre-line fallback when no line-start bullets are found.
Reference: msg.text in DebateRoom.tsx and the list rendering branch.
- Around line 4-5: The page imports Textarea but still renders <Input> at render
time, causing Input to be undefined; restore the original import by uncommenting
the Input import or replace the <Input> usage with <Textarea> consistently.
Locate the import line that currently comments out Input and either re-enable
"Input" in the import statement or update the JSX where Input is used (search
for "Input" and the render around line where <Input> appears) to use Textarea
props/handlers instead; ensure the component name and any props (value,
onChange, placeholder, className) match the chosen component to avoid prop
mismatches.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3749fc52-56da-4604-8e7a-790207082101

📥 Commits

Reviewing files that changed from the base of the PR and between 90fb523 and e43a65d.

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • backend/services/debatevsbot.go
  • frontend/package.json
  • frontend/src/Pages/DebateRoom.tsx

Comment on lines +172 to +185
pointInstruction := `
STRICT OUTPUT FORMAT:
- Write ONLY bullet points.
- Each bullet point MUST start with "- ".
- Each bullet MUST be on a NEW LINE.
- Do NOT place multiple bullets on the same line.
- Maximum 5 bullets.

Correct format example:
- First argument supporting your stance
- Second argument responding to the opponent
- Third argument with reasoning
- Fourth argument strengthening your case
`
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Scope the bullet-count rule by debate phase.

Applying Maximum 5 bullets to every response changes cross-examination semantics: the bot is now allowed to ask several questions in one "question" turn or spread one answer across several bullets. frontend/src/Pages/DebateRoom.tsx Lines 517-527 still drives that phase as one question / one answer per turn, so this can make the next turn ambiguous.

💡 Suggested fix
 pointInstruction := `
 STRICT OUTPUT FORMAT:
 - Write ONLY bullet points.
 - Each bullet point MUST start with "- ".
 - Each bullet MUST be on a NEW LINE.
 - Do NOT place multiple bullets on the same line.
 - Maximum 5 bullets.
 ...
 `
+
+singleBulletInstruction := `
+STRICT OUTPUT FORMAT:
+- Write ONLY one bullet point.
+- The bullet point MUST start with "- ".
+- Do NOT add extra prose before or after it.
+`
...
 switch strings.ToLower(currentPhase) {
 case "opening statement":
   phaseInstruction = "This is the Opening Statement phase..."
 case "cross examination":
   phaseInstruction = "This is the Cross Examination phase..."
 ...
 }
+
+formatInstruction := pointInstruction
+if strings.EqualFold(currentPhase, "Cross Examination") {
+  formatInstruction = singleBulletInstruction
+}
 
 return fmt.Sprintf(
   `You are %s, a %s-level debate bot arguing %s the topic "%s".
 ...
 %s
 Based on the debate transcript below, continue the discussion in the %s phase by responding directly to the user’s message.
 ...
 `,
 ...
- pointInstruction,
+ formatInstruction,
 ...
 )

Also applies to: 251-283

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/services/debatevsbot.go` around lines 172 - 185, The hard-coded
"Maximum 5 bullets" in pointInstruction causes cross-phase semantics issues;
change the instruction generation to be phase-aware by removing the global limit
from pointInstruction and instead generate or append a scoped bullet-count
constraint only when appropriate (e.g., pass a maxBullets parameter or a boolean
allowMultipleBullets into the function that builds pointInstruction and similar
strings at the other occurrence around lines 251-283), and for the
question/answer phase (the single-question/single-answer flow driven by the
frontend) ensure the generator does not enforce multiple bullets—use a nil/0 or
explicit maxBullets=1 to enforce one bullet per turn. Ensure you update all
occurrences (pointInstruction and the other instruction string) to use this
parameterized builder so phase semantics remain consistent.

Comment on lines +682 to +689
{msg.text.includes("- ") ? (
<ul className="list-disc pl-5 space-y-1">
{msg.text.split(/\n|-\s+/).filter(Boolean).map((point, i) => (
<li key={i}>{point.trim()}</li>
))}
</ul>
) : (
<div className="whitespace-pre-line">{msg.text}</div>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Detect bullets only at line starts.

includes("- ") plus split(/\n|-\s+/) is too broad: a normal message like A - B will be rendered as a list, and bullet content that contains " - " will be split into extra <li> items. Because this renderer is shared for both user and bot messages, that will misformat regular debate text.

💡 Suggested fix
-{msg.text.includes("- ") ? (
-  <ul className="list-disc pl-5 space-y-1">
-    {msg.text.split(/\n|-\s+/).filter(Boolean).map((point, i) => (
-      <li key={i}>{point.trim()}</li>
-    ))}
-  </ul>
-) : (
-  <div className="whitespace-pre-line">{msg.text}</div>
-)}
+{(() => {
+  const lines = msg.text
+    .split("\n")
+    .map((line) => line.trim())
+    .filter(Boolean);
+
+  const bulletPoints = lines
+    .filter((line) => /^-\s+/.test(line))
+    .map((line) => line.replace(/^-\s+/, ""));
+
+  return bulletPoints.length > 0 && bulletPoints.length === lines.length ? (
+    <ul className="list-disc pl-5 space-y-1">
+      {bulletPoints.map((point, i) => (
+        <li key={i}>{point}</li>
+      ))}
+    </ul>
+  ) : (
+    <div className="whitespace-pre-line">{msg.text}</div>
+  );
+})()}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/Pages/DebateRoom.tsx` around lines 682 - 689, The renderer
currently treats any occurrence of "- " inside msg.text as bullets; change it to
detect bullets only at line starts by checking msg.text.split('\n') for lines
whose trimmed start begins with "- ". When rendering, split only on newline
boundaries, filter lines that start with a leading hyphen (use trimmed start
detection), strip the leading "- " from each bullet line (e.g., remove
/^\s*-\s+/), and render those as <li> items; keep the existing
whitespace-pre-line fallback when no line-start bullets are found. Reference:
msg.text in DebateRoom.tsx and the list rendering branch.

@SoorejS
Copy link
Contributor

SoorejS commented Mar 12, 2026

The bullet rendering improvement looks useful for readability.
cool.....
However, enforcing bullet format in the backend prompt may affect debate phase semantics. In cross-examination phases, the system currently expects a single question/answer turn, but forcing up to 5 bullet points could make responses ambiguous.

Since the frontend renderer already detects bullet structures, would it be safer to handle formatting entirely on the frontend instead of enforcing output structure in the prompt?

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/services/debatevsbot.go`:
- Around line 172-185: The Opening Statement prompt currently comments out the
deterministic bullet template (pointInstruction) and injects a literal "// %s"
into prompts, causing the model to return paragraphs; restore the strict output
format by re-enabling the pointInstruction multi-line string (the commented
block) and use it when building the prompt instead of injecting "// %s" — update
the code paths that construct Opening Statement prompts (references:
pointInstruction, Opening Statement prompt construction in debatevsbot.go and
any places noted around lines ~172, ~203, ~220, ~260, ~279) so the prompt
concatenates or formats with pointInstruction to force "- " bullet lines rather
than leaving the template commented out or interpolated as a literal.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8368e52f-5999-419d-b5bb-69f403f5e7b9

📥 Commits

Reviewing files that changed from the base of the PR and between e43a65d and 35a0874.

📒 Files selected for processing (2)
  • backend/services/debatevsbot.go
  • frontend/src/Pages/DebateRoom.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/Pages/DebateRoom.tsx

Comment on lines +172 to +185
// pointInstruction := `
// STRICT OUTPUT FORMAT:
// - Write ONLY bullet points.
// - Each bullet point MUST start with "- ".
// - Each bullet MUST be on a NEW LINE.
// - Do NOT place multiple bullets on the same line.
// - Maximum 5 bullets.

// Correct format example:
// - First argument supporting your stance
// - Second argument responding to the opponent
// - Third argument with reasoning
// - Fourth argument strengthening your case
// `
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Re-enable deterministic bullet formatting for Opening Statement; current prompt can regress to paragraph rendering.

frontend/src/Pages/DebateRoom.tsx (Lines 681-684) only renders list items when lines use - . Here, strict formatting is commented out and // %s is injected literally into prompts, so bullet structure is not reliably produced.

💡 Suggested fix
@@
-	// pointInstruction := `
-// STRICT OUTPUT FORMAT:
-// - Write ONLY bullet points.
-// - Each bullet point MUST start with "- ".
-// - Each bullet MUST be on a NEW LINE.
-// - Do NOT place multiple bullets on the same line.
-// - Maximum 5 bullets.
-
-// Correct format example:
-// - First argument supporting your stance
-// - Second argument responding to the opponent
-// - Third argument with reasoning
-// - Fourth argument strengthening your case
-// `
+	pointInstruction := `
+STRICT OUTPUT FORMAT:
+- Write ONLY bullet points.
+- Each bullet point MUST start with "- ".
+- Each bullet MUST be on a NEW LINE.
+- Do NOT place multiple bullets on the same line.
+`
@@
 %s
 %s
-// %s
+%s
 %s
@@
-			// pointInstruction,
+			pointInstruction,
 			limitInstruction, baseInstruction,
@@
 %s
-// %s
 Based on the debate transcript below, continue the discussion in the %s phase by responding directly to the user’s message.
@@
-		// pointInstruction,

Also applies to: 203-205, 220-220, 260-260, 279-279

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/services/debatevsbot.go` around lines 172 - 185, The Opening
Statement prompt currently comments out the deterministic bullet template
(pointInstruction) and injects a literal "// %s" into prompts, causing the model
to return paragraphs; restore the strict output format by re-enabling the
pointInstruction multi-line string (the commented block) and use it when
building the prompt instead of injecting "// %s" — update the code paths that
construct Opening Statement prompts (references: pointInstruction, Opening
Statement prompt construction in debatevsbot.go and any places noted around
lines ~172, ~203, ~220, ~260, ~279) so the prompt concatenates or formats with
pointInstruction to force "- " bullet lines rather than leaving the template
commented out or interpolated as a literal.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
frontend/src/Pages/DebateRoom.tsx (1)

725-732: ⚠️ Potential issue | 🟠 Major

Only render a list when every non-empty line is actually a bullet.

This still triggers on any "- " substring, so normal text like A - B or mixed prose plus bullets gets split into bogus <li> items. Because this renderer is shared across all phases and both senders, it will misformat regular debate text.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/Pages/DebateRoom.tsx` around lines 725 - 732, The current
renderer treats any "- " substring as a list; update the conditional that
decides between rendering a list vs plain text (where msg.text is used) to only
render the <ul> when every non-empty line in msg.text actually starts with a
bullet marker (e.g., matches /^\s*-\s+/). To fix, split msg.text by newlines,
filter out empty lines, check that every remaining line matches the
bullet-prefix regex, and only then render the list (trim and strip the leading
"- " when mapping to <li>); otherwise render the plain whitespace-pre-line text
as before.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/src/components/JudgementPopup.tsx`:
- Around line 137-142: The current check for isUserBotFormat uses "'user' in
openingStatement" which can throw if openingStatement is a primitive (e.g.,
string); update the guard to ensure openingStatement is an object before using
the in operator (e.g., verify typeof openingStatement === 'object' &&
openingStatement !== null and optionally !Array.isArray(openingStatement)) and
then test "'user' in openingStatement"; apply this change where openingStatement
and isUserBotFormat are defined to safely handle malformed
JudgmentDataUserBot/JudgmentDataForAgainst payloads.

In `@frontend/src/Pages/DebateRoom.tsx`:
- Around line 633-645: The fallback verdict object creates a false-positive
winner by setting verdict.winner to "Unknown"; update the fallback used where
judgment is parsed (the verdict object built from judgment) to set winner to an
empty string "" instead, and make the subsequent error-fallback logic that
renders JudgementPopup rely on an empty winner to indicate "no result" (keep
references to verdict.winner, judgment, and the JudgementPopup consumer in mind
when changing the fallback).

---

Duplicate comments:
In `@frontend/src/Pages/DebateRoom.tsx`:
- Around line 725-732: The current renderer treats any "- " substring as a list;
update the conditional that decides between rendering a list vs plain text
(where msg.text is used) to only render the <ul> when every non-empty line in
msg.text actually starts with a bullet marker (e.g., matches /^\s*-\s+/). To
fix, split msg.text by newlines, filter out empty lines, check that every
remaining line matches the bullet-prefix regex, and only then render the list
(trim and strip the leading "- " when mapping to <li>); otherwise render the
plain whitespace-pre-line text as before.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e4134f5d-65d5-4be3-b3a8-f852a4a02002

📥 Commits

Reviewing files that changed from the base of the PR and between 9206fdf and 93ec5fa.

📒 Files selected for processing (3)
  • frontend/src/Pages/DebateRoom.tsx
  • frontend/src/components/JudgementPopup.tsx
  • frontend/tsconfig.app.tsbuildinfo
✅ Files skipped from review due to trivial changes (1)
  • frontend/tsconfig.app.tsbuildinfo

Comment on lines +137 to +142
// Some judge responses can be partial/malformed; keep rendering with safe fallbacks
const openingStatement = (judgment as Partial<JudgmentDataUserBot>).opening_statement as
| JudgmentDataUserBot['opening_statement']
| JudgmentDataForAgainst['opening_statement']
| undefined;
const isUserBotFormat = Boolean(openingStatement && 'user' in openingStatement);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, let's find and examine the specific file and lines in question
find . -name "JudgementPopup.tsx" -type f

Repository: AOSSIE-Org/DebateAI

Length of output: 107


🏁 Script executed:

# Once found, read the relevant section around lines 137-142
cat -n frontend/src/components/JudgementPopup.tsx | sed -n '130,150p'

Repository: AOSSIE-Org/DebateAI

Length of output: 1171


🏁 Script executed:

# Also check the type definitions to understand what opening_statement can be
rg "opening_statement" --type ts --type tsx -B 2 -A 2

Repository: AOSSIE-Org/DebateAI

Length of output: 90


🏁 Script executed:

# Check the JudgmentDataUserBot and JudgmentDataForAgainst types to understand the structure
ast-grep --pattern 'type JudgmentDataUserBot = $_'

Repository: AOSSIE-Org/DebateAI

Length of output: 1846


🏁 Script executed:

ast-grep --pattern 'type JudgmentDataForAgainst = $_'

Repository: AOSSIE-Org/DebateAI

Length of output: 1896


Guard the in check before probing malformed payloads.

On line 142, 'user' in openingStatement will throw a TypeError if opening_statement is a string, number, or other primitive instead of an object. The && operator only guards against falsy values, so truthy primitives like non-empty strings will pass through and crash on the in operator. This defeats the stated goal of safe fallbacks for partial/malformed payloads.

Suggested fix
-  const isUserBotFormat = Boolean(openingStatement && 'user' in openingStatement);
+  const isUserBotFormat =
+    typeof openingStatement === 'object' &&
+    openingStatement !== null &&
+    'user' in openingStatement;
📝 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
// Some judge responses can be partial/malformed; keep rendering with safe fallbacks
const openingStatement = (judgment as Partial<JudgmentDataUserBot>).opening_statement as
| JudgmentDataUserBot['opening_statement']
| JudgmentDataForAgainst['opening_statement']
| undefined;
const isUserBotFormat = Boolean(openingStatement && 'user' in openingStatement);
// Some judge responses can be partial/malformed; keep rendering with safe fallbacks
const openingStatement = (judgment as Partial<JudgmentDataUserBot>).opening_statement as
| JudgmentDataUserBot['opening_statement']
| JudgmentDataForAgainst['opening_statement']
| undefined;
const isUserBotFormat =
typeof openingStatement === 'object' &&
openingStatement !== null &&
'user' in openingStatement;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/JudgementPopup.tsx` around lines 137 - 142, The
current check for isUserBotFormat uses "'user' in openingStatement" which can
throw if openingStatement is a primitive (e.g., string); update the guard to
ensure openingStatement is an object before using the in operator (e.g., verify
typeof openingStatement === 'object' && openingStatement !== null and optionally
!Array.isArray(openingStatement)) and then test "'user' in openingStatement";
apply this change where openingStatement and isUserBotFormat are defined to
safely handle malformed JudgmentDataUserBot/JudgmentDataForAgainst payloads.

Comment on lines +633 to +645
verdict: {
winner: "Unknown",
reason:
typeof (judgment as any)?.verdict?.reason === "string"
? (judgment as any).verdict.reason
: "Judgment data missing/invalid.",
congratulations:
typeof (judgment as any)?.verdict?.congratulations === "string"
? (judgment as any).verdict.congratulations
: "",
opponent_analysis:
typeof (judgment as any)?.verdict?.opponent_analysis === "string"
? (judgment as any).verdict.opponent_analysis
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don't fabricate a winner in the invalid-judgment fallback.

Line 634 sets winner: "Unknown". JudgementPopup treats any non-empty verdict.winner as a real result, so malformed payloads will currently surface as Unknown Wins! instead of the intended unavailable/default state. Leave winner empty here, and align the error fallback below for the same reason.

💡 Minimal fix
-              winner: "Unknown",
+              winner: "",
📝 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
verdict: {
winner: "Unknown",
reason:
typeof (judgment as any)?.verdict?.reason === "string"
? (judgment as any).verdict.reason
: "Judgment data missing/invalid.",
congratulations:
typeof (judgment as any)?.verdict?.congratulations === "string"
? (judgment as any).verdict.congratulations
: "",
opponent_analysis:
typeof (judgment as any)?.verdict?.opponent_analysis === "string"
? (judgment as any).verdict.opponent_analysis
verdict: {
winner: "",
reason:
typeof (judgment as any)?.verdict?.reason === "string"
? (judgment as any).verdict.reason
: "Judgment data missing/invalid.",
congratulations:
typeof (judgment as any)?.verdict?.congratulations === "string"
? (judgment as any).verdict.congratulations
: "",
opponent_analysis:
typeof (judgment as any)?.verdict?.opponent_analysis === "string"
? (judgment as any).verdict.opponent_analysis
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/Pages/DebateRoom.tsx` around lines 633 - 645, The fallback
verdict object creates a false-positive winner by setting verdict.winner to
"Unknown"; update the fallback used where judgment is parsed (the verdict object
built from judgment) to set winner to an empty string "" instead, and make the
subsequent error-fallback logic that renders JudgementPopup rely on an empty
winner to indicate "no result" (keep references to verdict.winner, judgment, and
the JudgementPopup consumer in mind when changing the fallback).

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
frontend/src/components/JudgementPopup.tsx (1)

137-142: ⚠️ Potential issue | 🔴 Critical

Guard the in check before probing malformed payloads.

If opening_statement is a truthy primitive from a malformed judge response, 'user' in openingStatement throws before the fallback logic runs. That turns the new defensive path back into a render crash.

💡 Minimal fix
-  const isUserBotFormat = Boolean(openingStatement && 'user' in openingStatement);
+  const isUserBotFormat =
+    typeof openingStatement === 'object' &&
+    openingStatement !== null &&
+    !Array.isArray(openingStatement) &&
+    'user' in openingStatement;
In JavaScript/TypeScript, does using the `in` operator on a primitive value such as a string or number throw a TypeError? Please cite MDN or the ECMAScript spec.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/JudgementPopup.tsx` around lines 137 - 142, The
current runtime check uses "'user' in openingStatement" which will throw if
openingStatement is a primitive; change the isUserBotFormat computation to first
ensure openingStatement is a non-null object (e.g., typeof openingStatement ===
'object' && openingStatement !== null) before using the in operator, so update
the isUserBotFormat expression that references openingStatement (and types
JudgmentDataUserBot / opening_statement) to perform this guarded check and keep
existing fallbacks intact.
frontend/src/Pages/DebateRoom.tsx (1)

725-732: ⚠️ Potential issue | 🟠 Major

Only parse bullets from line-start markers.

includes("- ") plus split(/\n|-\s+/) is still too broad: a normal turn like A - B or any sentence containing " - " will be broken into multiple <li> items. Because this renderer is shared by both user and bot messages, regular questions/answers can be reformatted as lists by accident.

💡 Minimal fix
-            {msg.text.includes("- ") ? (
-  <ul className="list-disc pl-5 space-y-4">
-    {msg.text.split(/\n|-\s+/).filter(Boolean).map((point, i) => (
-      <li key={i}>{point.trim()}</li>
-    ))}
-  </ul>
-) : (
-  <div className="whitespace-pre-line">{msg.text}</div>
-)}
+            {(() => {
+              const lines = msg.text
+                .split("\n")
+                .map((line) => line.trim())
+                .filter(Boolean);
+
+              const bulletPoints = lines
+                .filter((line) => /^-\s+/.test(line))
+                .map((line) => line.replace(/^-\s+/, ""));
+
+              return bulletPoints.length > 0 &&
+                bulletPoints.length === lines.length ? (
+                <ul className="list-disc pl-5 space-y-4">
+                  {bulletPoints.map((point, i) => (
+                    <li key={i}>{point}</li>
+                  ))}
+                </ul>
+              ) : (
+                <div className="whitespace-pre-line">{msg.text}</div>
+              );
+            })()}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/Pages/DebateRoom.tsx` around lines 725 - 732, The current check
msg.text.includes("- ") and split(/\n|-\s+/) incorrectly breaks inline " - "
into bullets; instead detect bullet lists only when lines start with a dash and
split by lines. Replace the condition with a multiline-start test (e.g.
/^\s*-\s+/m.test(msg.text)) and change the splitting logic to split on '\n',
filter lines that match /^\s*-\s+/, and strip the leading dash/whitespace when
producing list items (update the rendering block around msg.text in
DebateRoom.tsx accordingly).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/src/components/JudgementPopup.tsx`:
- Around line 709-713: The header currently appends "Wins!" to any non-empty
verdict.winner, causing "Draw" to render as "Draw Wins!"; update the render
logic in JudgementPopup.tsx (the expression using (judgment as
any)?.verdict?.winner) to branch: if verdict.winner === 'Draw' render a plain
"Draw" (or a suitable draw label), otherwise render `${winner} Wins!`, ensuring
you reference the same judgment.verdict.winner field and keep null/undefined
handled as the existing 'Result unavailable' fallback.

---

Duplicate comments:
In `@frontend/src/components/JudgementPopup.tsx`:
- Around line 137-142: The current runtime check uses "'user' in
openingStatement" which will throw if openingStatement is a primitive; change
the isUserBotFormat computation to first ensure openingStatement is a non-null
object (e.g., typeof openingStatement === 'object' && openingStatement !== null)
before using the in operator, so update the isUserBotFormat expression that
references openingStatement (and types JudgmentDataUserBot / opening_statement)
to perform this guarded check and keep existing fallbacks intact.

In `@frontend/src/Pages/DebateRoom.tsx`:
- Around line 725-732: The current check msg.text.includes("- ") and
split(/\n|-\s+/) incorrectly breaks inline " - " into bullets; instead detect
bullet lists only when lines start with a dash and split by lines. Replace the
condition with a multiline-start test (e.g. /^\s*-\s+/m.test(msg.text)) and
change the splitting logic to split on '\n', filter lines that match /^\s*-\s+/,
and strip the leading dash/whitespace when producing list items (update the
rendering block around msg.text in DebateRoom.tsx accordingly).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 56866d0f-e016-4c91-83d5-04a9c0d9e6d4

📥 Commits

Reviewing files that changed from the base of the PR and between 93ec5fa and 892e4be.

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (4)
  • backend/services/debatevsbot.go
  • frontend/package.json
  • frontend/src/Pages/DebateRoom.tsx
  • frontend/src/components/JudgementPopup.tsx
✅ Files skipped from review due to trivial changes (2)
  • backend/services/debatevsbot.go
  • frontend/package.json

Comment on lines 709 to +713
<p className='mt-4 text-3xl font-bold'>
{judgment.verdict.winner} Wins!
{(judgment as any)?.verdict?.winner
? `${(judgment as any).verdict.winner} Wins!`
: 'Result unavailable'}
</p>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Handle draw verdicts separately.

backend/controllers/debatevsbot_controller.go:228-250 already treats "Draw" as a real outcome, but this header appends Wins! to any non-empty winner. A tie will therefore render as Draw Wins!, which is incorrect.

💡 Minimal fix
-          <p className='mt-4 text-3xl font-bold'>
-            {(judgment as any)?.verdict?.winner
-              ? `${(judgment as any).verdict.winner} Wins!`
-              : 'Result unavailable'}
-          </p>
+          {(() => {
+            const winner =
+              typeof (judgment as any)?.verdict?.winner === 'string'
+                ? (judgment as any).verdict.winner.trim()
+                : '';
+            const normalizedWinner = winner.toLowerCase();
+            const allowedWinners = new Set([
+              'user',
+              'bot',
+              'for',
+              'against',
+              player1Name.toLowerCase(),
+              player2Name.toLowerCase(),
+            ]);
+            const verdictTitle =
+              normalizedWinner === 'draw'
+                ? 'Draw'
+                : allowedWinners.has(normalizedWinner)
+                ? `${winner} Wins!`
+                : 'Result unavailable';
+
+            return <p className='mt-4 text-3xl font-bold'>{verdictTitle}</p>;
+          })()}
📝 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
<p className='mt-4 text-3xl font-bold'>
{judgment.verdict.winner} Wins!
{(judgment as any)?.verdict?.winner
? `${(judgment as any).verdict.winner} Wins!`
: 'Result unavailable'}
</p>
{(() => {
const winner =
typeof (judgment as any)?.verdict?.winner === 'string'
? (judgment as any).verdict.winner.trim()
: '';
const normalizedWinner = winner.toLowerCase();
const allowedWinners = new Set([
'user',
'bot',
'for',
'against',
player1Name.toLowerCase(),
player2Name.toLowerCase(),
]);
const verdictTitle =
normalizedWinner === 'draw'
? 'Draw'
: allowedWinners.has(normalizedWinner)
? `${winner} Wins!`
: 'Result unavailable';
return <p className='mt-4 text-3xl font-bold'>{verdictTitle}</p>;
})()}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/JudgementPopup.tsx` around lines 709 - 713, The
header currently appends "Wins!" to any non-empty verdict.winner, causing "Draw"
to render as "Draw Wins!"; update the render logic in JudgementPopup.tsx (the
expression using (judgment as any)?.verdict?.winner) to branch: if
verdict.winner === 'Draw' render a plain "Draw" (or a suitable draw label),
otherwise render `${winner} Wins!`, ensuring you reference the same
judgment.verdict.winner field and keep null/undefined handled as the existing
'Result unavailable' fallback.

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.

[FEATURE]: Debate statements displayed as long paragraphs instead of bullet points in UI

2 participants