gridscoot
◆ trust · how rankings work · updated phase 14.7

No retailer pays to rank higher.

Every other AU comparison engine sorts by what advertisers pay. We don’t. This page shows the exact three-stage sort we ship — product match, offer cheapest-first, and alternatives ranking (ADR-0007: pure-cheapest default with an opt-in trust slider) — the inputs, and which inputs we never read at rank-time. Source lives in apps/web/src/lib/search/run-search.ts, apps/web/src/lib/alternatives/, and the hybrid_search SQL migration.

◆ pledge 01
No paid placement
Ever. Retailers cannot buy slots, accent badges, or sort tweaks. The same algorithm runs for every product. Holds at the default trust_weight=0 (pure cheapest) and at every opt-in value the user sets.
◆ pledge 02
No retailer bias at default
At trust_weight=0 (default), two retailers with identical delivered totals rank identically. Even Amazon does not get a thumb on the scale. If the user opts into trust-weighted ranking via find_alternatives, the formula is disclosed in the response.
◆ pledge 03
No personalisation
You see the same ranking your agent sees. No A/B test re-orders results based on who is asking. The only knob is the trust_weight the caller passes explicitly.
01Stage 1 — Product rankinghybrid_search RPC · text + embedding

When a query comes in, the matcher computes a hybrid_score per candidate product using four signals — three text-based (token overlap, trigram, brand similarity) and one semantic (embedding distance). The top-N candidates by hybrid_score become the result list, in score order.

apps/web/src/lib/search/run-search.ts · hybrid_score formula
hybrid_score =
  (emb_dist != null && trgm_sim > 0)
    ? (1.0 - emb_dist / 2.0) * 0.7 + trgm_sim * 0.3
  : (emb_dist != null)
    ? (1.0 - emb_dist / 2.0)
  : trgm_sim
  + token_overlap_pct * 0.30   // plurality-aware (Phase 12.22)
02Stage 2 — Offer rankingcheapest total first, deterministic

Within each matched product, offers are sorted cheapest total ascending where total_aud = price + shipping. The cheapest in-stock offer becomes best_offer. No retailer-specific weighting; no commission-aware re-rank; no “preferred partner” bypass.

apps/web/src/lib/search/run-search.ts:478
// Materialise top-N offers in cheapest-first order. The first is best_offer.
const sortedOffers = [...offers]
  .filter((o) => o.in_stock && !isStale(o.last_seen_at))
  .sort((a, b) => a.total_aud - b.total_aud);

const bestOffer = sortedOffers[0];
03Stage 3 — Alternatives rankingfind_alternatives · ADR-0007 · opt-in trust slider

When an agent calls the find_alternatives MCP tool, we evaluate candidate offers against a baseline product and return ranked alternatives. The ranking is governed by ADR-0007: a user-selectable trust slider that defaults to pure cheapest delivered total. The caller controls the trade-off; we never apply it silently.

apps/web/src/lib/alternatives/find-alternatives.ts · ADR-0007 score
// trust_weight = 0 (default) → pure-cheapest sort by deliveredTotal ascending.
// trust_weight > 0 → linear blend between price_score and trust_score.
const priceScore = 1 - (candidate.deliveredTotal - cheapestDeliveredTotal) / cheapestDeliveredTotal;
const trustScore = candidate.trustScore ?? 0.5;  // 0.5 = neutral when unknown
const weightedScore = (1 - trustWeight) * priceScore + trustWeight * trustScore;

Phase-14.7 disclosure: the trust columns (rating_score, delivery_accuracy_pct, dispute_rate_pct, account_tenure_start) are NULL by default in today’s catalogue. Until they populate, raising trust_weight above 0 reduces every candidate to the neutral default of 0.5 — i.e. it currently tie-breaks at random rather than meaningfully discriminating. We’re shipping the slider as API surface first; the consumer-facing UI on /search waits until the underlying data is real.

04What goes into the rankauditable
inputsourceused?notes
token overlap (query ↔ title/brand/category)pg_trgm SQL◆ yesplurality-aware; weighted 30% of hybrid_score
trigram similarity (full string fuzz)pg_trgm SQL◆ yessurvives typos like "samsong" → Samsung
brand similaritypg_trgm SQL◆ yesprecision floor for brand-explicit queries
embedding distance (Voyage AI · 512-dim)pgvector◆ yes70% of hybrid_score when both lanes hit
price (list, GST/VAT-inclusive) per offerretailer feed (illustrative seed today)◆ yeslist price only — vouchers / promo codes are NEVER read
shipping to buyer postcodefeed + retailer calculator◆ yesoverride per request when live feeds land
cross-border VAT differential (find_alternatives)EU OSS rules + per-country VAT table◆ yesHungarian 27% ≠ German 19%; computed on every cross-border candidate
in-stock flagfeed◆ yesout-of-stock offers are filtered, not penalised
meets-or-beats spec floor (find_alternatives)category schema + Haiku-extracted specs◆ yesstrict — IP67 is not IP69; undeclared candidate specs disqualify
merchant trust_score (find_alternatives only)rating + delivery accuracy + dispute rate + tenureopt-inconsulted only when caller sets trust_weight > 0 — ADR-0007. Default = 0 (pure cheapest). Disclosed formula returned in response.
affiliate commission %CF / Amazon / EPN portals✕ neverwe never read this at rank-time. Tested.
retailer relationshipmanual✕ neverno preferred-partner tier exists
vouchers / promo codes / loyalty pricing✕ neverlist price only; vouchers are user-specific and irrelevant to comparison
user history / agent identity✕ neverwe do not track per-user behaviour or agent identity
05Why we can credibly promise no paid placement
Want to verify? Run the L2 corpus locally: GS_BASE=https://gridscoot.vercel.app python3 scripts/test-protocol/02-recall.py. Today: 54/54 (100%) recall · 17/17 brand-explicit accuracy.