Skip to content

feat(web): one rating everywhere from the stored bayesian score #1545

Open

Description

@JOY

Refs #1531 (phase P4 of the design Docs/Proposals/2026-10-31-criteria-stars-pros-cons.html; JOY approved D1-D10 with the recommendations on 2026-10-31).

Outcome

Every page and the API show the same product rating: master_products.rating_score at one decimal (D2, D3; design 2.4). The expert score is shown separately with its label; the leaderboard combined score only breaks ties.

Scope

Product page, cards, compare, versus, watchlist, leaderboard, /api/v1/rate/* and the OpenAPI spec read rating_score; display-truth tests follow.

Acceptance

Depends on: P2 applied. Database: reads the P2 columns only.

Size: S

Follow-ups from PR #1478 (merged 3648fb0), to do once rating_score exists

  1. /api/v1/rate/versus still breaks ties with the composite and checks a tie at 2 decimals. The screen can show a tie while the API names a leader. Make it use the same one-decimal tie as the page, and keep the composite only as the tiebreak.
  2. The home and compare battle cards, the leaderboard and deals still show composite or persona scores at 2 decimals. Under D3 the composite only breaks ties: show rating_score at 1 decimal, and label any persona score as such.
  3. Small fixes:
    • The buyer score is rounded twice: 4.249 shows 4.3. Round once.
    • When neither model has a score, the summary prints "0.0" while the stars say "Chưa có đánh giá". Show "Chưa có đánh giá" in both.

Activity

  1. JOY commented on Oct 31, 2026

    @JOY
    ContributorAuthor

    Implementation plan (Web)

    I read the P2 migration in PR #1549 (Docs/Proposals/2026-10-31-dos-me-criteria-ratings.sql):

    • master_products.rating_score is numeric(3,2): Bayesian, k = 3, mu = 4.2, NULL when there are no reviews.
    • rating_weight_sum is also added.

    Every place that switches to rating_score (after P2 is applied)

    There is one reader change, and the rest follows from it:

    • resolveCompareEffectiveUserRating (lib/rate-domain.ts) reads rating_score first. Fallback to user_rating_weighted stays until the backfill is checked.
    • scoreMasterProductForLeaderboard userScore5 (lib/leaderboard-engine.ts) reads the same helper.

    Direct readers of user_rating_weighted or average_rating, which move to the helper:

    • Product page (smartphones/[slug]/page.tsx):
      • the headline computeBayesianRatingSummary reads the stored score, keeping the review list only for counts;
      • the peer cards.
    • Catalog cards: smartphones/page.tsx, rate-api.ts (the card value and the sort on user_rating_weighted).
    • Home: page.tsx, hero-products.ts, HeroSearchInspector.
    • Leaderboard: leaderboard/page.tsx.
    • Deals: server/rate/deals.ts.
    • Other callers of resolveCompareEffectiveUserRating: compare, watchlist, deep inspect, catalog toolbar. They follow automatically.
    • API: /api/v1/rate/* select lists add rating_score. Responses add rating_score_5, and the existing fields stay for one release. server/rate/openapi.ts documents it.

    Ranking follows D3:

    • The leaderboard ranks by rating_score. The composite only breaks ties.
    • Battle cards, leaderboard rows and the podium show rating_score at 1 decimal.
    • A persona or criterion view keeps its own score, labelled with the persona or criterion. It is not shown as "the rating".
    • display-truth tests follow.

    The three follow-ups from PR #1478

    1. Versus API tie rule. It can land before the migration. is_tie and overall_winner use the score at one decimal, like the page. The composite and price become the tiebreak only. margin_10 is the gap between the scores as shown, and the OpenAPI description follows. Switching the API's base score to rating_score waits for the column.
    2. Composite or persona scores at 2 decimals on battle cards, the leaderboard and deals. This waits for the column: showing a 1-decimal number that the list is not sorted by would make equal-looking scores rank differently.
    3. Small fixes:
      • "0.0" when neither model has a score. It can land before: the summary and verdict say "Chưa có đánh giá" like the stars.
      • Double rounding. I propose no code change before the column. The double rounding goes away when the screen reads rating_score directly. But the column itself is stored at 2 decimals, so a Bayesian 4.249 is stored as 4.25 and shown as 4.3. To round only once, P2 would store numeric(4,3) (or wider) and the screen would round to 1 decimal. A question for the P2 author (PR docs(proposals): dos-me migration for criteria ratings, pros and cons (p2) #1549), not a blocker: the error is at most 0.05 and only near x.x5.

    Order

  2. added
    status:in-progressTask currently claimed and being worked on by an Agent
    agent:webClaimed by Agent: Web
    and removed
    status:readyTask ready to be picked up by an Agent
    on Oct 31, 2026
  3. self-assigned this
    on Oct 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

agent:webClaimed by Agent: Webstatus:in-progressTask currently claimed and being worked on by an Agent

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions