Skip to content

fix(web): versus api ties at one decimal and unrated pairs say so - #1551

Merged
JOY (JOY) merged 1 commit into
devfrom
fix/1545-versus-tie
Oct 31, 2026
Merged

JOY (JOY) merged 1 commit into
devfrom
fix/1545-versus-tie

Conversation

@JOY

@JOY JOY (JOY) commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Refs #1545 (P4 of #1531). This is the part that needs no new column, following the plan in #1545 (comment). #1545 stays open for the rating_score switch after P2 is applied.

What changes

  • /api/v1/rate/versus: the tie and the winner (follow-up 1 from PR fix(web): versus scoreboard shows the product's own rating at one decimal #1478).
    • is_tie and overall_winner now come from the custom_weighted_score_10 values as the response shows them, at one decimal.
    • The composite score, then the lower price, then side A only break a tie.
    • Before, a 2-decimal gap on the /5 score, or a gap on the composite alone, could name a leader while both shown scores were equal.
    • The rule is the pure versusApiWinner in lib/versus-verdict.ts. The OpenAPI description follows.
  • Versus scoreboard with no score (follow-up 3).
    • When a model has no score, the summary line shows "Chưa có đánh giá" (starRating.empty) instead of "0.0".
    • When neither model has a score, the verdict uses the new versusAutoVerdictNoScore copy (vi, en, cs) instead of a "0.0" tie.

Not in this PR

These wait for P2 (PR #1549, master_products.rating_score):

  • the API's base score;
  • the reader switch everywhere;
  • leaderboard ranking and battle cards (follow-up 2).

The double rounding is a question on the P2 column type; see the plan comment.

Tests

  • locale-format.test.ts: versusApiWinner cases (a lead, 9.04 against 8.96 as a tie broken by the composite, a price tiebreak, side A) and the no-score verdict.
  • spec-scope.test.ts: on the mocked route, is_tie and overall_winner.side / margin_10 agree with the shown /10 scores.
  • pnpm test, tsc and eslint pass locally.

🤖 Generated with Claude Code


📌 TL;DR

This PR refactors the 1v1 comparison logic to determine winners and ties based on the displayed 1-decimal scores (instead of raw 2-decimal precision) and introduces a new "no score" verdict state for unrated models. It also updates the UI to display a localized "empty" state instead of "0.0" when a model lacks a rating.

🎯 Type of Change

  • 🚀 New feature
  • 🐛 Bugfix
  • 🧹 Refactor
  • ⚡ Performance
  • 📚 Documentation
  • ⚙️ CI / Configuration

🔍 Changes Walkthrough

File Summary of Changes
apps/web/locales/cs.json Added versusAutoVerdictNoScore translation for Czech.
apps/web/locales/en.json Added versusAutoVerdictNoScore translation for English.
apps/web/locales/vi.json Added versusAutoVerdictNoScore translation for Vietnamese.
apps/web/src/app/api/v1/rate/__tests__/spec-scope.test.ts Updated tests to verify that is_tie and overall_winner are derived from the 1-decimal custom_weighted_score_10 values.
apps/web/src/app/api/v1/rate/versus/route.ts Replaced inline winner/tie logic with the new versusApiWinner utility. Updated is_tie to rely on the new logic rather than raw 2-decimal string comparison.
apps/web/src/components/compare/VersusInteractiveScoreboard.tsx Added handling for the versusAutoVerdictNoScore key. Updated score display to show a localized "empty" string instead of "0.0" when the score is 0.
apps/web/src/lib/__tests__/locale-format.test.ts Added unit tests for versusApiWinner (tie-breaking logic) and versusVerdictCopy (no-score case).
apps/web/src/lib/versus-verdict.ts Implemented versusApiWinner to determine winner/tie based on 1-decimal scores with composite/price tie-breakers. Updated versusVerdictCopy to return the new "no score" verdict when scores are 0.
apps/web/src/server/rate/openapi.ts Updated API documentation to reflect the new tie-breaking logic (1-decimal precision and specific tie-break order).

📊 Architectural Flow

flowchart TD
    A[API Request: /api/v1/rate/versus] --> B[Calculate Scores]
    B --> C{Check Scores}
    C -->|Score A != Score B| D[Winner: Higher Score]
    C -->|Score A == Score B| E[Check Composite Score]
    E -->|Composite A > Composite B| F[Winner: A]
    E -->|Composite B > Composite A| G[Winner: B]
    E -->|Composite Tie| H[Check Price]
    H -->|Lower Price B| I[Winner: B]
    H -->|Lower Price A or Equal| J[Winner: A]
    
    D --> K[Set is_tie = false]
    F --> L[Set is_tie = true]
    G --> L
    I --> L
    J --> L
    
    K --> M[Return API Response]
    L --> M
    
    M --> N[UI: VersusInteractiveScoreboard]
    N --> O{Check Verdict Key}
    O -->|versusAutoVerdictNoScore| P[Display 'Empty' Rating]
    O -->|versusAutoVerdictTie| Q[Display Tie Message]
    O -->|Other| R[Display Winner Message]
Loading

#1545 (the part that needs no new column):
- /api/v1/rate/versus decides is_tie and the winner on the /10 scores as
  the response shows them, at one decimal; the composite and then the lower
  price only break a tie. Before, a 2-decimal gap or a composite gap
  named a leader for scores shown equal.
- The scoreboard summary and the verdict say "no rating yet" instead of
  "0.0" when a model has no score, like the stars.

Refs #1545

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
rate Ready Ready Preview Oct 31, 2026 7:02pm UTC

Request Review

@claude claude 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.

⚠️ Code review skipped — your organization has no extra usage available to pay for this review.

If your organization's extra usage balance is empty, an organization admin can add extra usage credits at claude.ai/admin-settings/usage. If its monthly spend limit was reached, an admin can raise it on the same page. If neither applies, contact Anthropic support.

Once extra usage is available, someone with write access to this repository can comment @claude review on this pull request to trigger a review.

@coderabbitai

coderabbitai Bot commented Oct 31, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 54 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: da28d6bb-ba7e-4132-b908-8c2fe7a13266
Commits

Reviewing files that changed from the base of the PR and between 7840cc2 and 6a12b09.

Files selected for processing: 9
  • apps/web/locales/cs.json
  • apps/web/locales/en.json
  • apps/web/locales/vi.json
  • apps/web/src/app/api/v1/rate/__tests__/spec-scope.test.ts
  • apps/web/src/app/api/v1/rate/versus/route.ts
  • apps/web/src/components/compare/VersusInteractiveScoreboard.tsx
  • apps/web/src/lib/__tests__/locale-format.test.ts
  • apps/web/src/lib/versus-verdict.ts
  • apps/web/src/server/rate/openapi.ts
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

dos[bot]
dos Bot approved these changes Oct 31, 2026

@dos dos 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.

⏱️ Code Review completed (9 eligible files · 13,092 chars · 4 model call(s) · 1 PR unit(s))

Whole diff with bounded context at base 7840cc2 / head 6a12b09.

✅ No verified defects

1 possible issue(s) could not be grounded in or verified against the snapshot source, so they are not published.

Context investigation was bounded to the explicitly requested snapshot paths.

@JOY
JOY (JOY) merged commit eaf6cf7 into dev Oct 31, 2026
18 checks passed
@JOY
JOY (JOY) deleted the fix/1545-versus-tie branch October 31, 2026 19:07
@JOY JOY (JOY) mentioned this pull request Oct 31, 2026
2 of 6 tasks

This branch was successfully deployed

1 active deployment
Preview — 6a12b09a Deployed Oct 31, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:frontend Frontend / Next.js / UI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant