Cookwala / SDK and scenarios / 067

The checks a gateway applies to an OFFER before listing it

A gateway must refuse to list offers that fail the cold-chain checks: chilled above 5 °C, frozen above -18 °C, hot-held below 60 °C, or a chilled-class food declared ambient. The parser returns the finding ids.

Audience: food safety officer · Goal: Make people healthier, Help end hunger · Level: beginner

Read first: /docs/HUMANITARIAN-PROFILE/ /humanitarian/

Steps

  1. Chilled yogurt at 7 °C: safety.chilled_max. parseSms

  2. Hot-held rice at 52 °C: safety.hot_hold_min. parseSms

  3. Frozen chicken at -10 °C: safety.frozen_max. parseSms

  4. Chicken declared ambient: the item words imply poultry, so safety.storage_class_mismatch. parseSms

  5. The same rice at 66 °C passes and may be listed. parseSms

Outcome

You know the four block findings and that they fire before a document exists. Next: scenario 070 applies the full rule pack to a recorded offer.

Command line

cookwala sms "OFFER 36KG YOGURT C T7C"
cookwala sms "OFFER 20KG CHICKEN A"
cookwala sms "OFFER 18KG COOKED RICE TRAYS H T66C"

Recorded output

Status: ok

[1] parseSms: {"ok": true, "command": "OFFER", "kg": 36.0, "item": "yogurt", "storage": "chilled", "tempC": 7.0, "foodClasses": ["dairy"], "findings": ["safety.chilled_max"]}
[2] parseSms: {"ok": true, "command": "OFFER", "kg": 18.0, "item": "cooked rice trays", "storage": "hot_held", "tempC": 52.0, "foodClasses": ["cooked_food", "cooked_rice"], "findings": ["safety.hot_hold_min"]}
[3] parseSms: {"ok": true, "command": "OFFER", "kg": 20.0, "item": "chicken", "storage": "frozen", "tempC": -10.0, "foodClasses": ["poultry"], "findings": ["safety.frozen_max"]}
[4] parseSms: {"ok": true, "command": "OFFER", "kg": 20.0, "item": "chicken", "storage": "ambient", "foodClasses": ["poultry"], "findings": ["safety.storage_class_mismatch"]}
[5] parseSms: {"ok": true, "command": "OFFER", "kg": 18.0, "item": "cooked rice trays", "storage": "hot_held", "tempC": 66.0, "foodClasses": ["cooked_food", "cooked_rice"], "findings": []}

Code

Run: python scenarios/out/067-gateway-cold-chain-checks-on-offers/python.py

# Scenario 067: The checks a gateway applies to an OFFER before listing it
# A gateway must refuse to list offers that fail the cold-chain checks: chilled above 5 °C, frozen above -18 °C, hot-held below 60 °C, or a chilled-class food declared ambient. The parser returns the finding ids.
# Run a hub first: python hub/cookwala_hub.py --recipes examples
import json, os
from cookwala.client import CookwalaClient, CookwalaProblem

def load(path):
    with open(path, encoding="utf-8") as f:
        return json.load(f)

def pick(obj, path):
    for part in path.replace("]", "").replace("[", ".").split("."):
        obj = obj[int(part)] if part.isdigit() else (len(obj) if part == "length" else obj.get(part))
    return obj

c = CookwalaClient(os.environ.get("COOKWALA_HUB", "http://localhost:7878"))


# Step 1: Chilled yogurt at 7 °C: safety.chilled_max.
chilled = c.parse_sms("OFFER 36KG YOGURT C T7C")
assert pick(chilled, "ok") == True, pick(chilled, "ok")
print("ok", "ok", "=", True)
assert pick(chilled, "findings") == ["safety.chilled_max"], pick(chilled, "findings")
print("ok", "findings", "=", ["safety.chilled_max"])

# Step 2: Hot-held rice at 52 °C: safety.hot_hold_min.
hot = c.parse_sms("OFFER 18KG COOKED RICE TRAYS H T52C")
assert pick(hot, "findings") == ["safety.hot_hold_min"], pick(hot, "findings")
print("ok", "findings", "=", ["safety.hot_hold_min"])
assert pick(hot, "foodClasses") == ["cooked_food", "cooked_rice"], pick(hot, "foodClasses")
print("ok", "foodClasses", "=", ["cooked_food", "cooked_rice"])

# Step 3: Frozen chicken at -10 °C: safety.frozen_max.
frozen = c.parse_sms("OFFER 20KG CHICKEN F T-10C")
assert pick(frozen, "findings") == ["safety.frozen_max"], pick(frozen, "findings")
print("ok", "findings", "=", ["safety.frozen_max"])
assert pick(frozen, "tempC") == -10.0, pick(frozen, "tempC")
print("ok", "tempC", "=", -10.0)

# Step 4: Chicken declared ambient: the item words imply poultry, so safety.storage_class_mismatch.
ambient = c.parse_sms("OFFER 20KG CHICKEN A")
assert pick(ambient, "findings") == ["safety.storage_class_mismatch"], pick(ambient, "findings")
print("ok", "findings", "=", ["safety.storage_class_mismatch"])
assert pick(ambient, "foodClasses") == ["poultry"], pick(ambient, "foodClasses")
print("ok", "foodClasses", "=", ["poultry"])

# Step 5: The same rice at 66 °C passes and may be listed.
ok = c.parse_sms("OFFER 18KG COOKED RICE TRAYS H T66C")
assert pick(ok, "findings.length") == 0, pick(ok, "findings.length")
print("ok", "findings.length", "=", 0)
assert pick(ok, "storage") == "hot_held", pick(ok, "storage")
print("ok", "storage", "=", "hot_held")

print("scenario complete")

scenarios/067-gateway-cold-chain-checks-on-offers.json

Previous: 066 Next: 068