Skip to content

Conversation

@Devnil434
Copy link

@Devnil434 Devnil434 commented Jan 30, 2026

Summary

This PR implements Phase 1 of Crowdsourced People’s Choice Judging in DebateAI.
Spectators can now vote on completed User-vs-Bot debates, and the aggregated audience verdict is returned alongside the existing AI Judge verdict.

The implementation is backend-only, minimal in scope, and does not modify core debate flow or AI judging logic.


Motivation

Debates are often judged differently by experts and general audiences. While DebateAI already provides AI-based judging focused on logical rigor, this feature introduces a social layer by exposing how popular opinion compares with the AI Judge’s verdict. This improves engagement and educational value without affecting debate integrity.


Implementation

  • Added a new Vote data model to store spectator votes with debate linkage, choice (User / Bot), IP-based duplicate prevention, and timestamp.
  • Integrated a new MongoDB votes collection during database initialization.
  • Implemented voting logic with validation to ensure:
    • Debate exists
    • Debate is finalized (AI verdict available)
    • Duplicate votes are prevented (best-effort, IP-based)
  • Added verdict aggregation logic to compute and return:
    • AI Judge verdict
    • People’s Choice winner and vote counts
  • Registered new debate routes for vote submission and verdict retrieval.

API Endpoints

Submit Vote

POST /vsbot/debate/:id/vote
{ "vote": "User" }

Design Scope (Phase 1)

  • Best-effort IP-based duplicate prevention
  • No spectator authentication
  • No real-time vote updates or analytics
  • AI Judge logic remains untouched
  • Clear separation between AI verdict and People’s Choice verdict

Verification

  • Backend builds successfully using:
go build ./cmd/server/main.go
  • Manual testing verified:

  • Voting on finalized debates

  • Duplicate vote prevention

  • Invalid debate handling

  • Pre-finalization vote rejection

closes #285

Summary by CodeRabbit

  • New Features

    • Added spectator voting system allowing users to vote on debate outcomes
    • Added verdict retrieval feature displaying AI assessment and aggregated people's choice votes
  • Improvements

    • Reduced password minimum length requirement from 8 to 6 characters
    • Enhanced AI response generation with improved prompt handling and output validation

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 30, 2026

📝 Walkthrough

Walkthrough

This PR implements crowdsourced "People's Choice" voting on debates by adding vote submission and verdict aggregation endpoints, restructuring bot response prompts to use system/user splits with response validation, and adjusting authentication password constraints. Configuration samples are removed and frontend validation is centralized.

Changes

Cohort / File(s) Summary
Voting Feature (Core)
backend/controllers/vote_controller.go, backend/models/vote.go, backend/db/db.go, backend/routes/debatevsbot.go
New vote submission and verdict retrieval endpoints; Vote model with debateId, vote choice, voterId, and timestamp; VotesCollection initialized in MongoDB; routes added for POST /debate/:id/vote and GET /debate/:id/verdicts.
Bot Prompt & Response System
backend/services/debatevsbot.go
Significant refactor: prompt construction split into system and user prompts; explicit phase determination logic; new validateResponse function to filter trivial responses; updated GenerateBotResponse to use dual-prompt approach with fallback retry on validation failure.
Model Invocation Layer
backend/services/gemini.go, backend/services/coach.go, backend/services/pros_cons.go, backend/services/transcriptservice.go
Added systemInstruction parameter to generateModelText and generateDefaultModelText; updated all callsites to pass systemInstruction (empty string or populated based on context).
Authentication Constraints
backend/structs/auth.go, frontend/src/Pages/Authentication/forms.tsx
Reduced password minimum length from 8 to 6 characters in SignUpRequest, LoginRequest, and VerifyForgotPasswordRequest; added MIN_PASSWORD_LENGTH frontend constant and centralized validation checks in login, signup, and reset flows.
Configuration Cleanup
.env.example, backend/config/config.prod.sample.yml
Removed example environment variable declarations (GEMINI_API_KEY, JWT_SECRET, GOOGLE_CLIENT_ID, VITE_* vars); deleted sample production configuration file with placeholder values.
TypeScript Improvements
frontend/src/Pages/OnlineDebateRoom.tsx
Added type annotation (string) to WS_BASE_URL replace callback parameter for improved type safety.

Sequence Diagram

sequenceDiagram
    participant Client as Client
    participant Controller as Vote Controller
    participant Validator as Validator
    participant DB as MongoDB
    participant Aggregator as Vote Aggregator

    rect rgba(100, 200, 255, 0.5)
    Note over Client,Aggregator: Vote Submission Flow
    Client->>Controller: POST /debate/:id/vote {vote, voterId}
    Controller->>Validator: Validate debateId & payload
    Validator-->>Controller: Valid/Invalid
    alt Invalid Input
        Controller-->>Client: Error 400
    else Valid
        Controller->>DB: Check debate exists & is finalized
        alt Debate not found or not finalized
            Controller-->>Client: Error 404/400
        else Debate valid
            Controller->>DB: Check for duplicate vote by voterId
            alt Vote exists
                Controller-->>Client: Error 409 (Conflict)
            else New vote allowed
                Controller->>DB: Insert new Vote document
                DB-->>Controller: Insertion successful
                Controller-->>Client: Success 201
            end
        end
    end
    end

    rect rgba(200, 150, 255, 0.5)
    Note over Client,Aggregator: Verdict Retrieval Flow
    Client->>Controller: GET /debate/:id/verdicts
    Controller->>Validator: Validate debateId
    Validator-->>Controller: Valid/Invalid
    alt Invalid ID
        Controller-->>Client: Error 400
    else Valid
        Controller->>DB: Fetch AI verdict from DebateVsBot
        Controller->>DB: Aggregate votes from Votes collection
        DB-->>Controller: Verdict & votes
        Aggregator->>Aggregator: Compute winner (User/Bot/Draw)
        Aggregator->>Aggregator: Count vote distribution
        Aggregator-->>Controller: Aggregated result
        Controller-->>Client: JSON {debateId, aiVerdict, peoplesChoice}
    end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • bhavik-mangla

Poem

🐰 A vote for all, a choice so clear!
People decide what champions win here,
No more logic lone on its throne—
Democracy speaks in every phone! 🗳️✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Several changes are outside the scope of issue #285: password length reduction (6 vs 8), TypeScript typing enhancement, and unrelated AI bot response refactoring. Remove password validation changes, TypeScript annotation change, and debatevsbot.go refactoring from this PR. These should be submitted in separate, focused pull requests.
Docstring Coverage ⚠️ Warning Docstring coverage is 73.68% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Feat/crowdsourced people's choice judging' directly reflects the main feature implemented: crowdsourced People's Choice judging mechanism.
Linked Issues check ✅ Passed The PR comprehensively implements all primary coding objectives from issue #285: Vote data model, MongoDB collection, voting logic with validation, verdict aggregation, and new API endpoints.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

🧪 Unit Test Generation v2 is now available!

We have significantly improved our unit test generation capabilities.

To enable: Add this to your .coderabbit.yaml configuration:

reviews:
  finishing_touches:
    unit_tests:
      enabled: true

Try it out by using the @coderabbitai generate unit tests command on your code files or under ✨ Finishing Touches on the walkthrough!

Have feedback? Share your thoughts on our Discord thread!


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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
backend/routes/debatevsbot.go (1)

13-18: ⚠️ Potential issue | 🔴 Critical

The /vsbot routes including vote and verdict endpoints require authentication. The SetupDebateVsBotRoutes function is called with the auth RouterGroup (backend/cmd/server/main.go:127), which applies AuthMiddleware. This means unauthenticated spectators cannot vote as intended. Either exempt the vote and verdict routes from auth, or implement a separate unauthenticated endpoint for spectator voting.

backend/db/db.go (1)

17-62: ⚠️ Potential issue | 🟠 Major

Add a unique compound index to enforce duplicate vote prevention.
SubmitVote uses CountDocuments → InsertOne (vote_controller.go lines 50–71), which is a classic TOCTOU window. Without a unique index, concurrent requests from the same IP can both see count=0, then both insert successfully, inflating vote counts. Create a unique (debateId, voterId) index in ConnectMongoDB and update the error handler to distinguish and return 409 for duplicate-key violations instead of 500.

🛠️ Proposed index creation
 func ConnectMongoDB(uri string) error {
 	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
 	defer cancel()
@@
 	MongoDatabase = client.Database(dbName)
 	DebateVsBotCollection = MongoDatabase.Collection("debates_vs_bot")
 	VotesCollection = MongoDatabase.Collection("votes")
+
+	// Enforce one vote per (debateId, voterId)
+	_, err = VotesCollection.Indexes().CreateOne(ctx, mongo.IndexModel{
+		Keys: bson.D{
+			{Key: "debateId", Value: 1},
+			{Key: "voterId", Value: 1},
+		},
+		Options: options.Index().SetUnique(true),
+	})
+	if err != nil {
+		return fmt.Errorf("failed to create votes index: %w", err)
+	}
 	return nil
 }

Also update the error handler in SubmitVote (lines 72–74) to catch MongoDB error code 11000 and return 409 instead of 500.

🤖 Fix all issues with AI agents
In `@backend/controllers/vote_controller.go`:
- Around line 25-31: The request binding currently accepts any string for
req.Vote which risks storing invalid values; after binding JSON into the local
req struct (req.Vote) validate that the value is exactly "User" or "Bot" and
return a 400 with a clear error message if it is not; apply the same validation
in the other handler occurrence handling req.Vote (lines ~63-68) so only allowed
Vote values per the Vote model (backend/models/vote.go) are persisted and used
in aggregation.
- Around line 49-71: The current CountDocuments → InsertOne flow in VoteCreate
(uses db.VotesCollection.CountDocuments and db.VotesCollection.InsertOne with
models.Vote) is vulnerable to a TOCTOU race; add a unique compound index on
(debateId, voterId) during DB initialization (use
VotesCollection.Indexes().CreateOne with a mongo.IndexModel keyed by "debateId"
and "voterId" and SetUnique(true)) and then remove the pre-insert count-check in
the controller, instead attempting InsertOne directly and catching duplicate-key
errors (check for mongo.IsDuplicateKeyError or error code 11000) to return HTTP
409 when a duplicate vote is attempted.

In `@backend/models/vote.go`:
- Around line 11-15: The Vote model currently stores raw client IPs in VoterID;
change the usage so VoterID stores a hashed/obfuscated identifier instead (keep
type string but document it as HMAC(IP, serverSecret) or similar). Update
SubmitVote in backend/controllers/vote_controller.go (which currently reads
c.ClientIP()) to compute a stable hash (e.g., hashVoterID or computeVoterIDHash
using a server secret from env/config) before any DB queries or when setting
Vote.VoterID, and use that hashed value for duplicate checks and persistence;
ensure hashing uses HMAC with a secret and consider optional truncation/TTL if
desired.

In `@backend/services/debatevsbot.go`:
- Around line 124-131: The code can set currentPhase to an empty string when
lastMsg.Phase is empty, causing the later switch to hit the generic default;
update the logic after calling findLastUserMessage so that if lastMsg.Phase ==
"" (or strings.TrimSpace(lastMsg.Phase) == "") you assign a sensible fallback
(e.g., "Opening Statement" or the previous known phase) to currentPhase before
any phase normalization (the code around currentPhase and the existing
normalization for "first rebuttal"/"second rebuttal" should be reused).

In `@backend/structs/auth.go`:
- Line 5: The Password JSON binding tags in backend/structs/auth.go were
weakened to `min=6`; revert the minimum password length to `min=8` for all
Password struct fields (the Password field definitions used in signup/reset
request structs) by updating their `binding` tags back to `min=8` so the signup
and reset flows enforce the stronger policy; locate each Password field (same
name "Password") in this file and change the tag value from 6 to 8.
🧹 Nitpick comments (7)
frontend/src/Pages/Authentication/forms.tsx (1)

8-8: Centralize password-length config to avoid drift.

Consider moving MIN_PASSWORD_LENGTH to a shared auth validation/config module so client and server changes stay aligned in one place.

backend/models/vote.go (1)

9-14: Constrain Vote values to typed constants to avoid inconsistent data.
The model comment allows multiple values, but GetVerdicts only tallies "User"/"Bot" (backend/controllers/vote_controller.go lines 80‑135). Consider a typed enum plus validation in SubmitVote to avoid silent miscounts.

♻️ Suggested typing
+type VoteChoice string
+
+const (
+	VoteUser VoteChoice = "User"
+	VoteBot  VoteChoice = "Bot"
+)
+
 type Vote struct {
 	ID        primitive.ObjectID `json:"id" bson:"_id,omitempty"`
 	DebateID  primitive.ObjectID `json:"debateId" bson:"debateId"`
-	Vote      string             `json:"vote" bson:"vote"` // "User", "Bot", or "for", "against"
+	Vote      VoteChoice         `json:"vote" bson:"vote"`
 	VoterID   string             `json:"voterId" bson:"voterId"` // IP address or fingerprint
 	Timestamp time.Time          `json:"timestamp" bson:"timestamp"`
 }
backend/services/gemini.go (1)

21-21: Unused modelName parameter.

The modelName parameter is accepted but never used—Line 43 always passes defaultGeminiModel. Either remove the parameter or use it in the API call.

♻️ Option A: Use the parameter
-	resp, err := geminiClient.Models.GenerateContent(ctx, defaultGeminiModel, genai.Text(prompt), config)
+	resp, err := geminiClient.Models.GenerateContent(ctx, modelName, genai.Text(prompt), config)
♻️ Option B: Remove the unused parameter
-func generateModelText(ctx context.Context, modelName, systemInstruction, prompt string) (string, error) {
+func generateModelText(ctx context.Context, systemInstruction, prompt string) (string, error) {

Then update the call in generateDefaultModelText:

-	return generateModelText(ctx, defaultGeminiModel, systemInstruction, prompt)
+	return generateModelText(ctx, systemInstruction, prompt)

Also applies to: 43-43

backend/controllers/vote_controller.go (2)

97-116: Consider MongoDB aggregation pipeline for efficiency.

Fetching all votes and iterating client-side is inefficient at scale. MongoDB's aggregation pipeline can compute counts server-side in a single query.

♻️ Proposed aggregation approach
pipeline := mongo.Pipeline{
    {{Key: "$match", Value: bson.M{"debateId": debateID}}},
    {{Key: "$group", Value: bson.M{
        "_id":   "$vote",
        "count": bson.M{"$sum": 1},
    }}},
}
cursor, err := db.VotesCollection.Aggregate(context.Background(), pipeline)
if err != nil {
    c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to aggregate votes"})
    return
}
defer cursor.Close(context.Background())

userVotes, botVotes := 0, 0
for cursor.Next(context.Background()) {
    var result struct {
        ID    string `bson:"_id"`
        Count int    `bson:"count"`
    }
    if err := cursor.Decode(&result); err == nil {
        switch result.ID {
        case "User":
            userVotes = result.Count
        case "Bot":
            botVotes = result.Count
        }
    }
}

107-116: Silent error swallowing on cursor decode.

Decode errors at Line 109 are silently ignored. While this prevents crashes, it could mask data corruption issues. Consider logging decode failures for observability.

♻️ Add logging for decode errors
 	for cursor.Next(context.Background()) {
 		var vote models.Vote
-		if err := cursor.Decode(&vote); err == nil {
+		if err := cursor.Decode(&vote); err != nil {
+			log.Printf("Failed to decode vote: %v", err)
+			continue
+		}
 			if vote.Vote == "User" {
 				userVotes++
 			} else if vote.Vote == "Bot" {
 				botVotes++
 			}
-		}
 	}
backend/services/debatevsbot.go (2)

186-188: Dead code in validateResponse.

The casualFiller variable is defined as []uintptr with character codes, then immediately discarded with _ = casualFiller. This appears to be leftover/debug code.

🧹 Remove dead code
 	// Reject obvious casual filler if it's the only thing there
-	casualFiller := []uintptr{'h', 'e', 'l', 'l', 'o'}
-	_ = casualFiller // just avoiding unused
 	if strings.Contains(lowerText, "hello there") && len(text) < 30 {
 		return false
 	}

178-194: Validation logic is intentionally weak.

The inline comment acknowledges this is a "weak check." For Phase 1, this may be acceptable, but consider tracking a follow-up to implement more robust validation (e.g., topic keyword matching, response length distribution) if response quality issues persist in production.

Would you like me to open an issue to track improving response validation with topic keyword matching or other heuristics?

Comment on lines +25 to +31
var req struct {
Vote string `json:"vote" binding:"required"` // "User" or "Bot"
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request payload"})
return
}
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

Missing validation for vote value.

The req.Vote field accepts any string, but the Vote model comment indicates only "User" or "Bot" are valid (per backend/models/vote.go). Invalid values will be stored and silently ignored in aggregation, corrupting vote counts.

🛡️ Proposed fix
 	if err := c.ShouldBindJSON(&req); err != nil {
 		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request payload"})
 		return
 	}
+
+	if req.Vote != "User" && req.Vote != "Bot" {
+		c.JSON(http.StatusBadRequest, gin.H{"error": "Vote must be 'User' or 'Bot'"})
+		return
+	}

Also applies to: 63-68

🤖 Prompt for AI Agents
In `@backend/controllers/vote_controller.go` around lines 25 - 31, The request
binding currently accepts any string for req.Vote which risks storing invalid
values; after binding JSON into the local req struct (req.Vote) validate that
the value is exactly "User" or "Bot" and return a 400 with a clear error message
if it is not; apply the same validation in the other handler occurrence handling
req.Vote (lines ~63-68) so only allowed Vote values per the Vote model
(backend/models/vote.go) are persisted and used in aggregation.

Comment on lines +49 to +71
// Check if this voter has already voted for this debate
count, err := db.VotesCollection.CountDocuments(context.Background(), bson.M{
"debateId": debateID,
"voterId": voterID,
})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to check existing votes"})
return
}
if count > 0 {
c.JSON(http.StatusConflict, gin.H{"error": "You have already voted on this debate"})
return
}

vote := models.Vote{
ID: primitive.NewObjectID(),
DebateID: debateID,
Vote: req.Vote,
VoterID: voterID,
Timestamp: time.Now(),
}

_, err = db.VotesCollection.InsertOne(context.Background(), vote)
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

Race condition in duplicate vote prevention (TOCTOU).

The check-then-insert pattern (CountDocumentsInsertOne) allows duplicate votes if two requests arrive concurrently for the same voter/debate. Between the count check and the insert, another request could complete its insert.

Consider using a unique index on (debateId, voterId) in MongoDB to enforce uniqueness atomically, then handle the duplicate key error.

🔒 Proposed approach
  1. Create unique index in backend/db/db.go during initialization:
indexModel := mongo.IndexModel{
    Keys:    bson.D{{Key: "debateId", Value: 1}, {Key: "voterId", Value: 1}},
    Options: options.Index().SetUnique(true),
}
VotesCollection.Indexes().CreateOne(ctx, indexModel)
  1. Update the controller to handle duplicate key errors:
-	count, err := db.VotesCollection.CountDocuments(context.Background(), bson.M{
-		"debateId": debateID,
-		"voterId":  voterID,
-	})
-	if err != nil {
-		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to check existing votes"})
-		return
-	}
-	if count > 0 {
-		c.JSON(http.StatusConflict, gin.H{"error": "You have already voted on this debate"})
-		return
-	}
-
 	vote := models.Vote{
 		ID:        primitive.NewObjectID(),
 		DebateID:  debateID,
 		Vote:      req.Vote,
 		VoterID:   voterID,
 		Timestamp: time.Now(),
 	}

 	_, err = db.VotesCollection.InsertOne(context.Background(), vote)
 	if err != nil {
+		if mongo.IsDuplicateKeyError(err) {
+			c.JSON(http.StatusConflict, gin.H{"error": "You have already voted on this debate"})
+			return
+		}
 		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to submit vote"})
 		return
 	}
🤖 Prompt for AI Agents
In `@backend/controllers/vote_controller.go` around lines 49 - 71, The current
CountDocuments → InsertOne flow in VoteCreate (uses
db.VotesCollection.CountDocuments and db.VotesCollection.InsertOne with
models.Vote) is vulnerable to a TOCTOU race; add a unique compound index on
(debateId, voterId) during DB initialization (use
VotesCollection.Indexes().CreateOne with a mongo.IndexModel keyed by "debateId"
and "voterId" and SetUnique(true)) and then remove the pre-insert count-check in
the controller, instead attempting InsertOne directly and catching duplicate-key
errors (check for mongo.IsDuplicateKeyError or error code 11000) to return HTTP
409 when a duplicate vote is attempted.

Comment on lines +11 to +15
ID primitive.ObjectID `json:"id" bson:"_id,omitempty"`
DebateID primitive.ObjectID `json:"debateId" bson:"debateId"`
Vote string `json:"vote" bson:"vote"` // "User", "Bot", or "for", "against"
VoterID string `json:"voterId" bson:"voterId"` // IP address or fingerprint
Timestamp time.Time `json:"timestamp" bson:"timestamp"`
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

Avoid storing raw IPs in VoterID (PII).
The field comment suggests persisting client IPs; that’s sensitive data. For best‑effort duplicate prevention, store a hashed/obfuscated identifier (e.g., HMAC(IP, server‑secret) with optional truncation/TTL). SubmitVote currently uses c.ClientIP() (backend/controllers/vote_controller.go lines 36‑47), so that path should hash before storing and querying.

🔒 Suggested model adjustment (also update controller logic)
 type Vote struct {
 	ID        primitive.ObjectID `json:"id" bson:"_id,omitempty"`
 	DebateID  primitive.ObjectID `json:"debateId" bson:"debateId"`
 	Vote      string             `json:"vote" bson:"vote"` // "User", "Bot", or "for", "against"
-	VoterID   string             `json:"voterId" bson:"voterId"` // IP address or fingerprint
+	VoterHash string             `json:"voterHash" bson:"voterHash"` // HMAC(IP, secret) or anonymized fingerprint
 	Timestamp time.Time          `json:"timestamp" bson:"timestamp"`
 }
🤖 Prompt for AI Agents
In `@backend/models/vote.go` around lines 11 - 15, The Vote model currently stores
raw client IPs in VoterID; change the usage so VoterID stores a
hashed/obfuscated identifier instead (keep type string but document it as
HMAC(IP, serverSecret) or similar). Update SubmitVote in
backend/controllers/vote_controller.go (which currently reads c.ClientIP()) to
compute a stable hash (e.g., hashVoterID or computeVoterIDHash using a server
secret from env/config) before any DB queries or when setting Vote.VoterID, and
use that hashed value for duplicate checks and persistence; ensure hashing uses
HMAC with a secret and consider optional truncation/TTL if desired.

Comment on lines +124 to 131
currentPhase := "Opening Statement"
if len(history) > 1 {
lastMsg := findLastUserMessage(history)
currentPhase = lastMsg.Phase
if strings.ToLower(currentPhase) == "first rebuttal" || strings.ToLower(currentPhase) == "second rebuttal" {
currentPhase = "Cross Examination"
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if Phase field is always populated when messages are created
rg -n -A5 'Phase.*=' --type=go -g '!*_test.go' | head -100

Repository: AOSSIE-Org/DebateAI

Length of output: 6781


🏁 Script executed:

# Get the full context around the flagged lines
cat -n backend/services/debatevsbot.go | sed -n '120,145p'

Repository: AOSSIE-Org/DebateAI

Length of output: 1618


🏁 Script executed:

# Look for the findLastUserMessage function definition
rg -n -A20 'func.*findLastUserMessage' --type=go

Repository: AOSSIE-Org/DebateAI

Length of output: 1720


🏁 Script executed:

# Check for Phase field definition in message structures
rg -n 'Phase\s+string' --type=go

Repository: AOSSIE-Org/DebateAI

Length of output: 503


Edge case when lastMsg.Phase is empty: falls through to default switch case.

If the user's last message has an empty Phase field, currentPhase becomes "" and the switch at line 134 falls through to the default case, which provides generic debate instructions. While this behavior is handled gracefully and doesn't cause errors, it means phase-specific instructions won't be applied.

🤖 Prompt for AI Agents
In `@backend/services/debatevsbot.go` around lines 124 - 131, The code can set
currentPhase to an empty string when lastMsg.Phase is empty, causing the later
switch to hit the generic default; update the logic after calling
findLastUserMessage so that if lastMsg.Phase == "" (or
strings.TrimSpace(lastMsg.Phase) == "") you assign a sensible fallback (e.g.,
"Opening Statement" or the previous known phase) to currentPhase before any
phase normalization (the code around currentPhase and the existing normalization
for "first rebuttal"/"second rebuttal" should be reused).

type SignUpRequest struct {
Email string `json:"email" binding:"required,email"`
Password string `json:"password" binding:"required,min=8"`
Password string `json:"password" binding:"required,min=6"`
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

Avoid weakening password policy to 6 characters without explicit security sign‑off.

Line 5, Line 15, and Line 25 reduce the minimum length across signup and reset flows, which materially weakens password strength. Unless security requirements explicitly allow 6, please keep 8 (or higher) to preserve baseline protection.

🔐 Suggested revert
-	Password string `json:"password" binding:"required,min=6"`
+	Password string `json:"password" binding:"required,min=8"`
-	Password string `json:"password" binding:"required,min=6"`
+	Password string `json:"password" binding:"required,min=8"`
-	NewPassword string `json:"newPassword" binding:"required,min=6"`
+	NewPassword string `json:"newPassword" binding:"required,min=8"`

Also applies to: 15-15, 25-25

🤖 Prompt for AI Agents
In `@backend/structs/auth.go` at line 5, The Password JSON binding tags in
backend/structs/auth.go were weakened to `min=6`; revert the minimum password
length to `min=8` for all Password struct fields (the Password field definitions
used in signup/reset request structs) by updating their `binding` tags back to
`min=8` so the signup and reset flows enforce the stronger policy; locate each
Password field (same name "Password") in this file and change the tag value from
6 to 8.

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 Request: Crowdsourced “People’s Choice” Judging

1 participant