Trust layer and grounding indicators

How Conviro keeps the assistant from stating wrong prices, stock or order facts, and how your team can see what an answer was based on. Plan P6.1–P6.2. Code: apps/api/src/modules/temporal/commerce/commerce-grounding.ts (d160e5da), apps/api/src/modules/commerce-trust/ (1a4f55fc), chat pipeline (aa085d1e), inbox indicator (a98996a0). Code and tests only — not deployed, not run against the Magento test stack, the inbox view not yet opened in a browser.

Where facts come from

Every commerce fact handed to the AI carries a source class and provenance (provider, store view, when it was read, how long the read took):

Source classWhat it isAllowed to state
Live store (LIVE_STORE)Read from your Magento store's REST API during the conversationprice, stock, order status and total, tracking, product information
Your policy (MERCHANT_POLICY)Return window (days) and Warranty length (months) from the module's AI Capabilities (and their per-language overrides in Conviro)return window, warranty
Knowledge base (KNOWLEDGE_BASE)Conviro's synced product entries and your own documentsproduct information; return window / warranty only when no policy is set
Inferred (INFERENCE)Conclusions drawn over live state, e.g. "this order can still be cancelled"eligibility

Precedence is fixed: a stronger source always wins; when a weaker source disagrees (say, a knowledge-base price that differs from the live price), it is kept as a recorded conflict and the AI is told to ignore it — it is never promoted. Price, stock and order facts are stated as fact only from the live store.

Checks on the reply

Grounding indicator in the inbox

Under an assistant answer that used store data, your team sees one line, for example:

Expanding it shows the facts given to the AI with their source and when they were read, the store view, the losing side of any conflict ("Conflicting sources (the stronger one was used)"), and price / stock claims in the reply not backed by a live fact, with the reason (no live price, amount differs, currency differs, no live stock, quantity differs). "Only your team sees this."

The record lives in its own staff-only table (chat_message_grounding, one row per answer), not on the chat message the widget reads, so it never reaches the shopper's browser. Access: owners, admins, and agents with sessions: read, with the same conversation scope as the inbox.

Aggregates per day and per source class (grounded answers, ungrounded counts, average latency) are available at GET /api/commerce-grounding/stats?days=1..90 for owners and admins.

In the Magento admin (514d99b0 API, f9e583f6 module): Stores › Configuration › Conviro › AI Chat › AI Answers and Revenue shows, for today and the last 7 days, how many commerce answers there were, how many rested on live store data (LIVE_STORE) versus other sources, and how many ungrounded price / stock claims the post-check flagged — counts only, no conversation content. The config page renders a placeholder and loads the card afterwards (conviro/insights/cards: admin session, URL secret key and Conviro_AiChat::config), so a slow Conviro never delays the page; Service/Insights/ConviroInsights calls GET /v1/api/magento/stats/grounding with the store's API key (3 s connect / 4 s total; cached 5 minutes, 1 minute after a failure; the route has a per-key throttle and takes kb:write, chat:read or the connect-minted magento:module scope). Measured on the local stack (attribution.sh, c3374a58): rendered from the stats endpoint, a failing Conviro gives a message instead of numbers, no admin session gives no card. The same card shows revenue influenced by Conviro (Privacy).

What you control

Limits

Measured (unit tests): precedence over all 120 permutations of the source classes, claim extraction in 10 reply languages with both decimal conventions, no false positives on order-number / quantity replies (commerce-grounding.spec 48/48).