Repository navigation
Conversation
…#1119) * fix(web): view offers read the merchant metadata DOSafe score (#1108) The trust view's metadata column is the product's, so a seller scored only in merchants.metadata.dosafe_risk_score showed "-" on the view path and a number on the fallback path. The existing merchants side read now also fetches that score for sellers the view has none for, and it only fills a missing view score. A test pins threat_source in TRUST_VIEW_SELECT through the request URL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(web): any threat_source string marks a joined threat_intel row (#1108) dosafe.threat_intel.source is NOT NULL in the DOS-Me ledger, so a string threat_source, even a blank one, means the LEFT JOIN found a row and its 0 is a real score. Only null or absent means no row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(web): keep follower counts when the metadata path is rejected (#1108) Review round 1: one merchants read carried both values, so a rejected metadata->dosafe_risk_score path also dropped the #685 follower adjustment. Fall back to the id, follower_count read for unscored sellers. Tests cover a seller missing both scores, the rejected path, and a view row with no seller. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
… toggle) (#1118) * fix(a11y): keep late content inert and clear only our inert (#1110) - inertOutside watches the kept ancestors with a MutationObserver, so content added while the phone menu is open (a toast, a portal, new content after a soft navigation) becomes inert too. - A shared hold count marks the inert set by inertOutside; the undo clears only that, once no other open call holds the element, and gives up an element whose inert other code changes meanwhile. - The phone drawer is min(320px, 100vw - 56px) wide, so at a 320px viewport it no longer covers the live menu toggle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(a11y): release removed nodes and size the drawer without the scrollbar (#1110) Review follow-ups: a node removed while the menu is open is released and no longer watched; the drawer width uses 100% of its fixed box, so a classic scrollbar does not push it over the toggle; drop a wrong comment about the opening slide in the 320px test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…1113) (#1121) * fix(normalizer): key Apple lines sold in several sizes by their size (#1113) The 11 and 13 inch iPad Pro, the 13 and 15 inch MacBook Air, the 14 and 16 inch MacBook Pro and the 42 and 46mm Watch Series are separate products at separate prices, but the normalizer gave each pair one key, so their listings could land on one master. A title that names its size now keys with it ("apple:ipad-pro-m5-11:256gb"), which is also how the published masters are keyed. A title without its size keeps the size-less key, and one-size lines (Watch Ultra, iPad mini, MacBook Neo) never carry one. The benchmark registry is still read per line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(normalizer): read Apple sizes past core counts, part codes and OS versions (#1113) Review follow-up. A bare number is no size before "nhân"/"lõi" core words, a "16G" RAM, inside a part code ("Z15S") or after "RAM" or "macOS"; a MacBook Air is only 13 or 15 inch. The registry's screen and battery describe one size of a line, so a title of the other size no longer takes them. Each whitespace gap is one optional space (CodeQL js/polynomial-redos). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(normalizer): skip a bundled accessory's size and read "13.0 inch" (#1113) Adversarial review follow-up. The size is read only before a "+" bundle ("iPad Pro M4 256GB + bàn phím 11 inch" is no 11 inch iPad), except "GPS + Cellular", and "13.0 inch" is the 13 inch iPad. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…WH- (#1116) (#1122) * fix(shared-data): earbuds regex reads glued tiers and drops over-ear WH- (#1116) EARBUDS_TITLE_REGEX now allows a number after a tier ("BudsPro3", "FreeBudsPro4"), a "pro"/"se" tier after FreeBuds, and "GalaxyBuds" glued to the brand ("SamsungGalaxyBuds3"). "wh-" is dropped: Sony WH- models are over-ear headphones and keep the device floor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(shared-data): pin model-key forms for the earbuds floor (#1116) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(shared-data): keep the earbuds regex free of polynomial backtracking (#1116) CodeQL js/polynomial-redos flagged the back-to-back digit runs around the optional tier. Moving the trailing digits inside the tier group matches the same strings (300k random probes, no difference) in linear time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…#1126) * fix(normalizer): a Watch band's size no longer keys the watch (#1124) Retailers name the case size before the band ("46mm Viền nhôm Dây cao su S/M"), so readAppleSize now skips a size after "dây"/"band"/"strap"/"loop"/ "bracelet" up to the next ")", ",", "|" or " - ". A title whose only size is the band's keeps the size-less key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(normalizer): keep a lone band size as the Watch case size (#1124) Review (P2): Apple sells a band by the case it fits ("Dây Cao Su 46mm"), so a lone size after a band word is the case's. A size outside a band phrase still wins, and a band size counts only when the title names no other size. Band phrases also end at ";" and an en dash. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(normalizer): pin each Watch band word and separator (#1124) Review follow-ups: "không dây" (wireless) is no band word, a glued "Sportband" is, and fixtures now fail when any band word, separator or the lone-size rule is removed. Adds the bracketed retailer title "Viền nhôm dây cao su [40mm/GPS]", which keeps its case size. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…i nghe titles (#1125) (#1127) * fix(shared-data): earbuds regex reads glued brands and drops over-ear titles that say tai nghe (#1125) Any brand glued to Buds, FreeBuds, AirPods or WF1000XM now reads as earbuds (PixelBudsPro2, HuaweiFreeBudsPro4, SonyWF1000XM5), as do AirPodsPro2 and two glued tiers (Buds3ProFE). An anchored lookahead keeps over-ear WH- titles on the device floor even when they also say "tai nghe". The pattern stays linear: the lookahead runs once and no two repeats share characters. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(shared-data): over-ear WH with a space or underscore, glued Redmi/Samsung/Enco/Tune Buds (#1125) Review follow-up on PR #1127. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(shared-data): any Sony WH- model, brand-bound AirPods, title and URL read together (#1125) Codex review follow-up on PR #1127: WH-L600/WH-RF400 are over-ear, "repairpods" is not AirPods, and an over-ear title wins over tai-nghe in the URL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
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.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the
|
|
[Agent: PO] |
There was a problem hiding this comment.
⏱️ Code Review completed (9 eligible files · 52,066 chars · 4 model call(s) · 2 PR unit(s))
Whole diff with bounded context at base a3ad4ba / head 69e8b84.
✅ No verified defects
2 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.
Promote dev to main.
Merge with a merge commit, never squash (Docs/Resources/RELEASE.md).
📌 TL;DR
This PR introduces size-based product keying for Apple devices (e.g., distinguishing 11" vs 13" iPad Pros) to improve data accuracy, refactors the web focus-trap to handle dynamic DOM changes and foreign inert states, and enhances the listing price floor logic to correctly classify over-ear headphones vs. earbuds.
🎯 Type of Change
🔍 Changes Walkthrough
apps/importer/src/shopee/product-normalizer.tsreadAppleSizeto extract screen/case sizes from titles. Updates model keying to include size (e.g.,ipad-pro-m4-11). Adjusts benchmark enrichment logic to only apply screen/battery specs when the registry entry matches the detected size.apps/importer/src/shopee/__tests__/open-core-intelligence.test.tsapps/web/src/lib/focus-trap.tsinertOutsideto use aMutationObserverand a reference-counting map (inertHolds). This ensures dynamically added elements become inert while the menu is open, and thatinertstates set by other code are preserved upon cleanup.apps/web/e2e/phone-menu-focus-trap.spec.tsapps/web/src/app/style/scss/style.scssmin(320px, calc(100% - 56px))to ensure the menu toggle button remains visible and accessible on narrow screens.apps/web/src/lib/rate-api.tsmetadata_dosafe_risk_scorefrommerchantstable. UpdatesmapTrustViewRowToMerchantOfferto use metadata scores when the view's DOSafe score is missing (null), improving risk scoring accuracy.apps/web/src/server/rate/__tests__/core-rate-architecture.test.tsthreat_sourceis selected and metadata is only used when the view score is missing.packages/shared-data/src/rules/listing-price-floor.tsEARBUDS_TITLE_REGEXto exclude over-ear headphones (e.g., Sony WH-1000XM5) and handle glued brand names (e.g.,SamsungGalaxyBuds3). ChangesminimumListingPriceVndto evaluate title and URL as a single text to prevent URL keywords from overriding title classification.packages/shared-data/src/__tests__/shared-data.test.ts📊 Architectural Flow
flowchart TD subgraph "Product Normalization (Importer)" A[Shopee Product Title] --> B{Is Apple Device?} B -->|Yes| C[readAppleSize] C --> D{Size Detected?} D -->|Yes| E[Append Size to Model Key<br>e.g., ipad-pro-m4-11] D -->|No| F[Keep Base Model Key] E --> G[Lookup Benchmark Registry] F --> G G --> H{Size Matches Registry?} H -->|Yes| I[Apply Screen/Battery Specs] H -->|No| J[Ignore Size-Specific Specs] end subgraph "Focus Trap (Web)" K[Menu Opens] --> L[inertOutside] L --> M[Observe DOM Mutations] M --> N{New Element Added?} N -->|Yes| O[Set inert=true] N -->|No| P[Check Foreign Inert] P --> Q[Preserve Foreign Inert State] R[Menu Closes] --> S[Release Holds] S --> T[Clear Only Own Inert States] end subgraph "Price Floor (Shared Data)" U[Title + URL] --> V[Join Texts] V --> W{Match EARBUDS_REGEX?} W -->|Yes| X[Apply Earbuds Floor<br>400k VND] W -->|No| Y[Apply Device Floor<br>1.2M VND] end