fix(BUY-65693): sentinel-price guard for find_similar (flat price:number shape) - #310
Conversation
Regression coverage addedPushed File: Coverage pins:
Test run on this branch: Reviewer tip: Merge-order note: this branch is stacked on top of PR #309 ( Cc @Reviewer — please ack and merge order: #309 first, then rebase #310, then #310. 🎯 |
Heartbeat 2026-08-04T00:01ZPR #310 still open, 0 reviews since 2026-07-31. Awaiting human review per [[buywhere-pr-review-gate-pattern]]. New finding (relevant to this PR): the canonical sentinel product (871873063695734596, BUY-52807) now returns Live state: https://buywhere.ai/, https://mcp.buywhere.ai/, https://api.buywhere.ai/ all HTTP 200. Sentinel query Status: still |
Heartbeat 2026-08-07T20:45ZPR #310 still open, 0 reviews, 0 PR-level comments since 2026-07-31 — awaiting human review per [[buywhere-pr-review-gate-pattern]]. Discovered this run:
Merge-stack status: PR #310 ref Discovered blocker: finding a Action items:
Cc @Reviewer |
…ber shape) Mirrors BUY-65685 / PR #309 for handleFindSimilar in src/routes/mcp.ts. Adds formatSimilarPriceField helper in src/lib/response.ts that returns either the sentinel hint string (when amount < 10 / null / non-finite) or the structured {amount, currency} object. Cannot reuse formatPriceField 1:1 because find_similar returns a flat shape with sibling price+currency fields (not a wrapper). When the structured form is returned, the sibling currency field is omitted from the JSON-RPC output to avoid redundancy. When the sentinel form is returned, currency is kept so AI agents still see the currency context if they parse the flat shape. Blocked by PR #309 (BUY-65685) merge + Railway redeploy for live verification on mcp.buywhere.ai/mcp. Co-Authored-By: Claude <noreply@anthropic.com>
…mcp-railway
Pin the contract of:
- isSentinelPrice: classifies amount<10 / null / non-finite as sentinel
- formatPriceField: returns string when sentinel, {amount,currency} otherwise
- formatSimilarPriceField: same shape; intended for find_similar's flat shape
21 cases, including boundary checks (amount=PRICE_SENTINEL_MIN is NOT sentinel),
defensive string-coercion checks, and the exact PRICE_UNAVAILABLE_TEXT wording
so future copy edits trigger a test failure.
These tests give reviewers and the post-merge Railway smoke probe a deterministic
way to confirm find_similar's sentinel guard works before it ships.
01cb4b2 to
53db470
Compare
Summary
Follow-up to #309 (BUY-65685) — extends the sentinel-price guard to
handleFindSimilar(the 6th JSON-RPC tool, not covered by the parent PR).The other 5 tools (
search_products,get_product,compare_products,get_deals,find_best_price) return a nested{price: {amount, currency}}shape and were rewrapped byformatPriceFieldin PR #309.find_similarreturns a flat shape with siblingprice: number+currency: stringfields, which is why it could not reuseformatPriceField1:1.What lands
+32 / -3across 2 files inmcp-railway/:src/lib/response.ts(+18 / -0) — newformatSimilarPriceFieldhelper that returnsProductPrice | string(delegates toformatPriceFieldbut documents the flat-shape contract).src/routes/mcp.ts(+14 / -3) —handleFindSimilarparses the raw DB price into a number, applies the sentinel guard, and:{amount, currency}in thepriceslot (and drops the now-redundant siblingcurrency) when amount ≥ 10priceslot (and keepscurrencyfor context) when amount < 10 / null / non-finiteWhy
Catalog rows where
price.amount < 10(typically written as1by the BuyWhere ingest pipeline when the merchant page had no parseable price — see BUY-52807) surface as.00in AI-agent responses likePrice: $1.00 SGD. The fix surfaces a "see merchant" hint instead so MCP clients (AI agents) do not quote a fake price.Behavior
price=1500, currency=SGD{price: "1500", currency: "SGD"}{price: {amount: 1500, currency: "SGD"}}(currency sibling dropped)price=1, currency=SGD{price: "1", currency: "SGD"}{price: "see merchant …", currency: "SGD"}price=null, currency=USD{price: null, currency: "USD"}{price: "see merchant …", currency: "USD"}Blocker / verification
Blocked by #309 merge + Railway redeploy for live verification on
mcp.buywhere.ai/mcp. The smoke-test pattern from BUY-65685 applies here — pick a sentinel reference product (e.g.id=871873063695734596, Gigabyte A16, sentinel amount=1) and confirmfind_similarrows surface the sentinel string instead of.00.Branching
This branch is stacked on top of
fix/BUY-65685-mcp-railway-sentinel-guard(PR #309). If #309 merges first, this PR rebases ontomaincleanly (the only BUY-65685-specific change isformatPriceField, which is still imported and used). If reviewers prefer a single combined PR, this branch can be merged into the BUY-65685 branch instead of main.🤖 Generated with Claude Code