Skip to content

chore(release): promote dev to main - #1552

Merged
JOY (JOY) merged 8 commits into
mainfrom
dev
Oct 31, 2026
Merged

JOY (JOY) merged 8 commits into
mainfrom
dev

Conversation

@JOY

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

Copy link
Copy Markdown
Contributor

Promote dev to main.

Merge with a merge commit, never squash (Docs/Resources/RELEASE.md).


📌 TL;DR

This PR introduces the database schema proposal (Phase P2) for the new criteria-based rating system, including SQL migrations for new tables (review_points, product_points) and columns for Bayesian rating scores. It also adds the comprehensive design documentation, verification scripts, and CI replay tests to validate the migration logic against the existing M1/M4 Item RPCs.

🎯 Type of Change

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

🔍 Changes Walkthrough

File Summary of Changes
.github/workflows/ci.yml Adds a new CI step to run scripts/test-criteria-ratings-proposal.mjs, ensuring the proposed migration is replayed and validated in Docker before any production application.
.gitignore Un-ignores the new proposal SQL files (main, rollback, verify) so they are tracked in the repository.
Docs/Proposals/2026-10-31-criteria-stars-pros-cons.html Adds the primary design document detailing the criteria model, data schema, UI mockups, and phased implementation plan (P0-P6) for the new rating system.
Docs/Proposals/2026-10-31-dos-me-criteria-ratings.md Adds the migration proposal summary, explaining the scope, order of operations, and known limits of the SQL changes.
Docs/Proposals/2026-10-31-dos-me-criteria-ratings.sql Adds the main SQL migration script. It creates new tables (review_points, product_points), adds columns to reviews and master_products, and implements functions/triggers to maintain Bayesian rating scores.
Docs/Proposals/2026-10-31-dos-me-criteria-ratings-rollback.sql Adds the rollback script to safely drop all objects introduced by the main migration.
Docs/Proposals/2026-10-31-dos-me-criteria-ratings-verify.sql Adds read-only verification queries to check schema integrity, RLS policies, function grants, and data consistency after the migration is applied.

📊 Architectural Flow

flowchart TD
    subgraph "CI Pipeline"
        A[GitHub Actions] --> B[Run test-criteria-ratings-proposal.mjs]
    end

    subgraph "Docker Replay Stack"
        B --> C[Apply Migration SQL]
        C --> D[Run Verify SQL]
        D --> E{Checks Pass?}
        E -- No --> F[Fail CI]
        E -- Yes --> G[Apply Rollback SQL]
        G --> H[Verify Rollback]
    end

    subgraph "Production Database (Future)"
        I[rate.reviews] -->|Triggers| J[rate.master_rating_extras]
        K[rate.review_flags] -->|Triggers| J
        J -->|Updates| L[rate.master_products]
        L -->|Stores| M[rating_score & criteria_scores]
    end
Loading

JOY (JOY) and others added 8 commits October 31, 2026 15:13
…tch (#1537)

* chore(deps): patch minimatch 10.x in the lockfile, with glob 14 to match (#1536)

minimatch 10.2.6 sits in a ReDoS advisory range (patched in 11.0.1); an
override moves it to 11.0.3. glob 13.0.6, used by @sentry/bundler-plugins
to find source maps, matches nothing with minimatch 11, so glob 13 moves to
14.0.3, which depends on minimatch 11 and is outside glob's own advisory.
The lockfile has no follow-redirects. minimatch 3.1.5 from ESLint 9 has no
patched 3.x and stays.

* chore(deps): move the fast-uri override to 3.1.9 (#1536)

fast-uri 3.1.8 is inside a newer advisory range (<3.1.9). After this,
pnpm audit lists only minimatch 3.1.5 from ESLint 9, which has no patched 3.x.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ener (#1541)

* fix(normalizer): hp folio laptops keep a key despite the accessory opener

isAccessoryTitle read "Folio" as a folio case, so a title such as
"Folio 13 HP Core i5 8GB" got an unkeyed key. A line word that is also
an accessory word now names the device when a model number follows it,
the title names the line's brand (HP) and no fit word ("cho", "for") or
other accessory word (case, sleeve, bao da) follows. Folio cases for
iPad or Samsung, and "Folio 13 cho HP", stay accessories.

Closes #1539

* fix(normalizer): read only the word after the hp brand for folio titles

Review of #1541. The first version scanned the whole title after the
line word for accessory and fit words, so a laptop's own text ("bàn
phím có đèn", "cho sinh viên") unkeyed it, while diacritic-less
accessories ("op lung", "tui chong soc") got a key. Now HP must come
right after the Folio model (13, 1040 G3, G1), and only the word right
after the brand is checked against the accessory openers, laptop
accessories (sleeve, adapter, túi) and fit words (cho, for, tương
thích). Promo words before the line ("Combo", "Hàng chính hãng") are
read as ACCESSORY_OPENER reads them.

Refs #1539

* fix(normalizer): catch diacritic-less and dashed accessories after folio hp

Codex round 2 on #1541. "Folio 13 HP sac 45W" and "Folio 13 HP ban
phim US" got a key, and a dash or bracket before the accessory ("Folio
13 HP - sleeve") hid it. The word after the brand is now read past
punctuation, and sac, cap and ban phim join the laptop accessory list.
"cho" leaves it, so "Folio 13 HP cho sinh viên Core i5" keeps a key.

Refs #1539

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…w value (#1533)

* docs(proposals): design weighted criteria stars, pros and cons, review value

Design proposal for #1531, for JOY to decide. Per-category rating criteria
with weights live in shared-data; a Rate review's star is the weighted
average of its criteria; pros, cons and a verdict are mandatory for Rate
reviews and optional for imported ones; product pros and cons are
clustered by code, then reworded by AI; a 0-100 review value score sorts
reviews and lifts a complete review's weight by at most 25%. It also
resolves #1143 (no derived criterion scores) and the headline question of
#1470 (one Bayesian rating, stored by DOS-Me). Proposal only: no code,
no SQL, no data changes.

Refs #1531

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…imal (#1478)

* ux(web): versus scores and battle cards show the product's own rating

#1470 (part): the versus scoreboard showed 4.98 and 5.00 while the
comparison matrix on the same page showed 5.0 and 5.0, and called a leader
on a 0.02 gap.

- The versus scoreboard's base score is the product's stored buyer rating
  (userScore5), the one the matrix, cards and compare show, instead of the
  leaderboard composite; persona weights still blend in the criteria.
- Scores, the verdict and the tie read at one decimal, like the matrix:
  5.0 against 5.0 is a tie.
- Home and compare battle cards show that rating at one decimal.

The product page's headline stays the Bayesian estimate (#1144); whether
lists and versus should show it too is open on #1470.

Refs #1470

* fix(web): versus keeps the composite for models with no buyer rating

Review of #1478: a model with no buyer rating falls back to its composite
instead of scoring 0; the gap, the leading note and the JSON export read
at one decimal, from the scores as shown; battle cards go back to the
composite they are ranked and paired by.

Refs #1470

* Merge remote-tracking branch 'origin/dev' into ux/one-rating

Resolve VersusInteractiveScoreboard against #1534: the scoreboard uses
StarRating at its default one decimal for the product's stored buyer rating,
and the summary line reads at one decimal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…orm rules (#1548)

* feat(shared-data): per-category rating criteria, weights and review form rules

Phase P1 of the #1531 design (D1, D5). rules/rating-criteria.ts holds
version 1 of the criteria lists and weights for smartphones, tablets,
laptops, smartwatches, earbuds and services, the weighted review star
at 0.1, the D5 check on criterion stars (half steps, at most two
skipped, value or price never) and the map from the five legacy form
keys. rules/review-form.ts holds the D5 text rules: verdict length, one
to five pros and cons, line length, evasive cons, duplicates and a line
given as both. No database change; wiring the web form is P3.

Closes #1542

* fix(shared-data): harden rating criteria and review text rules after review

Two reviews of #1548. Prototype keys ("toString", "__proto__") no
longer reach Object.prototype as a category or a rating; null is a
skipped criterion; the weighted star counts any stored star from 1 to
5, so legacy 0.1-step stars are kept; hasRatingCriteria tells a known
category from the phone fallback. The text rules count characters as
the writer sees them (NFKC, no zero-width characters), reject lines
with no words or one repeated character, keep diacritics when comparing
lines, never throw on a malformed body, and catch more dodging cons
("không có ạ", "chả có gì", "không chê được gì", "mọi thứ đều ổn").

Refs #1542

* fix(shared-data): match dodging cons word by word with their own diacritics

Round 2 review of #1548. Stripping diacritics made "hỏng luôn",
"không gập", "chưa có lời" and "mọi thứ đều ồn" read as dodges. Each
dodge word now matches as typed with its own diacritics or with none,
never with other ones. A pronoun may lead ("mình không thấy gì để
chê"), and "không có ý kiến", "không có gì để nói", "rất tốt" count.
A con longer than 150 characters is never a dodge, which keeps the
check linear on an oversized request.

Refs #1542

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

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

#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>
…tars (#1550)

* fix(web): per-criterion scores are real or null, never derived from stars (#1143)

computeJReviewsCriteriaScores added a spec and price delta to the star
rating, so every product rated about 4.85+ scored 5.00 on each criterion,
rankings tied and "#1 Màn hình" chips were invented. A criterion now reads
only its stored score and is null otherwise; earbuds have no screen
criterion.

- Leaderboard: null criteria leave the composite; a criterion tab lists only
  scored products and shows "Chưa đủ dữ liệu"; no screen tab for earbuds.
- Rank chips: a criterion ranks among scored products only, and needs two.
- Versus API and scoreboard: weights apply to criteria both sides have,
  else the main score; a criterion without data on both sides has null
  scores and no winner. The API adds custom_weighted_basis and
  compared_criteria; OpenAPI documents the nulls.
- Deals personas lean on a criterion only when it has a score.

Implements D4 of the #1531 design.

* fix(web): weighted ranks list scored products only; earbuds drop screen (#1143 review)

- A custom-weighted leaderboard no longer ranks a product by its combined
  score when it has no score on the weighted criteria, and a persona never
  brings back a product the active criterion tab has no score for.
- Only the category's own criteria weights count, so a screen weight left
  from phones does not empty the earbuds list; the screen slider is hidden.
- Switching to earbuds, or a URL with criterion=screen, opens the combined
  tab.
- Criterion blocks say the scores come from experts; empty bars are hidden.
- The versus API lists only the category's criteria, and the OpenAPI note on
  null scores is exact.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… (p2) (#1549)

* docs(proposals): dos-me migration for criteria ratings, pros and cons (p2)

Phase P2 of #1531 (D2, D3, D9, D10), for JOY to review and apply through
DOS-Me; nothing is applied from DOS/Rate. New review columns (exact
star, verdict, criteria version, value score), rate.review_points and
rate.product_points with RLS, and the master columns rating_score
(Bayesian, k 3, mu 4.2), rating_weight_sum and criteria_scores (D9
thresholds). The live refresh_master_product_rating is renamed to a
base and wrapped, so every caller also runs the new extras function.
Verify and rollback files, and a Docker replay in CI that applies it
on the reference stack and after M0 and M1+M2.

Refs #1543

* fix(proposals): keep criteria ratings current with triggers, not a wrapper

Review of #1549. Renaming refresh_master_product_rating to a base and
wrapping it broke when M1+M2 or its rollback replaced the function, and
the Item path (refresh_item_rating, votes) bypassed it. The migration
now replaces no function: triggers on reviews, review_flags and
master_products refresh the new columns, scoped like the live refresh
(per master, or the whole Item once M1+M2 is in). The schema change and
the backfill commit separately; criteria keys must look like the
shared-data keys; V3 checks PUBLIC and authenticated too, V4 the
triggers, and V6 recomputes every master. The replay applies it before
and after M1+M2 and through the M1+M2 rollback.

Refs #1543

* fix(proposals): no sibling deadlock and no-variant listings in criteria ratings

Round 2 review of #1549. Variants of an Item are written in id order
with SKIP LOCKED, as refresh_item_rating does, so two refreshes of
sibling variants never deadlock. Triggers resolve masters from
listings, so a review on an Item listing with no variant refreshes the
Item, and each Item is refreshed once per statement. Only changed
rating inputs fire a refresh. The CHECKs are added NOT VALID and
validated in the backfill transaction; V1 covers product_points. The
replay adds a no-variant review, an unchanged rewrite and its delete;
the runbook lists bulk flag imports, concurrent writers and listing
deletes as known limits.

Refs #1543

* chore(git): track the criteria ratings proposal sql files

The Secret scan job refuses tracked files that match .gitignore. The
three P2 proposal files get the same named exceptions as the earlier
DOS-Me proposals.

Refs #1543

* fix(proposals): store rating_score at three decimals so pages round once

The web rounded the stored 2-decimal score again for display, so 4.249
showed 4.3. rating_score is numeric(4,3) and the criterion scores keep 3
decimals too; pages round once, to 1 decimal. Replay expectations follow.

Refs #1543

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

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

@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:19pm UTC

Request Review

@coderabbitai

coderabbitai Bot commented Oct 31, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

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: acb1300c-36fd-4d4d-8562-b4db63591e6e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • 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

@github-actions github-actions Bot added ci CI/CD workflows and pipelines docs Documentation changes area:frontend Frontend / Next.js / UI area:shared Shared packages / contracts / configs area:crawlers labels Oct 31, 2026
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 (32 eligible files · 232,117 chars · 2 model call(s) · 8 PR unit(s))

Whole diff with bounded context at base 4aae9ad / head 1a9cd84.
Excluded by noise policy: pnpm-lock.yaml.

✅ CLEAN_PASS: Complete diff reviewed

Context investigation was bounded to the explicitly requested snapshot paths.

🔒 Dependency check

✅ Passed. Every new package version comes from the public registry or a source this lockfile already used for it, its checksum is pinned where the format records one, and OSV lists no new malicious package or high or critical vulnerability for the versions it was asked about.

Changed packages (5)
Package From To Lockfile
@isaacs/nonrecursive-glob-match new 1.0.3 pnpm-lock.yaml
fast-uri 3.1.8 3.1.9 pnpm-lock.yaml
glob 13.0.6 14.0.3 pnpm-lock.yaml
minimatch 10.2.6 11.0.3 pnpm-lock.yaml
path-scurry 2.0.2 3.0.0 pnpm-lock.yaml

This branch was successfully deployed

1 active deployment
Preview — 1a9cd842 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:crawlers area:frontend Frontend / Next.js / UI area:shared Shared packages / contracts / configs ci CI/CD workflows and pipelines docs Documentation changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant