The rule that outranks everything
Go back to the Chef’s tart, still sitting in the review queue. Someone with a peanut allergy searches your menu:
no exclusion exclude allergens: ["peanut"] ------------------------ ------------------------------ Tomato soup Tomato soup Peanut satay skewers (left out, has peanut) Garden salad Garden salad Chef's tart (left out, allergens not known)
Nothing says the tart contains peanuts. It is left out because nothing established that it does not. A record is returned only if the field is not marked unknown on it, has a value at all, and that value is none of the excluded ones. Those three conditions are one SQL clause, in the query, not an instruction in a prompt.
This is the difference between a tool and a filter. A filter keeps what it cannot rule out; a missing allergen column reads as “no allergens” and the tart is served to someone who should never have seen it. Fail closed means the opposite: no data is not good news.
A key can pin exclusions of its own. A key that pins allergens: [peanut] applies that to every call made with it, and a caller cannot widen it: their exclusions are merged with the key's, never subtracted. That is how you hand a key to a team whose agent you do not control and still keep the promise.
Every result also carries unknown_safety_fields, so an agent can tell the difference between “no allergens” and “we do not know the allergens” and say so to a person.
The same rule, one level down. When a field's values come from a value set with a hierarchy, excluding cashew also leaves out a dish tagged only “tree nuts”: it isn't known to be free of cashew. See *Long lists: value sets*.
Offer a safe alternative, not just a no. When someone asks for a dish they can't have, an agent can search with similar_to set to that dish and the same exclusion. The dish itself is allowed as the starting point; everything that comes back is known to be clear, by the same rule as any other search.
{
"similar_to": "<id of Paneer tikka>",
"exclude": { "allergens": ["dairy"] }
}