Cookwala / SDK and scenarios / 074
Care rules: which food classes are blocked for everyone, which depend on the group
The care pack blocks raw egg, raw meat, raw fish and unpasteurized dairy for all vulnerable groups, warns about raw sprouts, and ties other rules to a named group. Three small test offers written for this scenario show the three cases.
Read first: /docs/HUMANITARIAN-PROFILE/ /humanitarian/
Steps
A test offer of a raw-egg dish, checked with the care pack: a block finding for everyone.
humanitarianCheckThe same offer with the basic pack only: no food-class rules there, no finding.
humanitarianCheckRaw sprouts: a warning, not a block.
humanitarianCheckHigh-mercury fish: the rule names the group pregnant, and an offer names no group, so no finding here. It fires on a handover or distribution that names the group.
humanitarianCheckThe test offer is a valid profile document.
validate
Outcome
You know how a food class on an item meets a rule in a pack, and when the audience matters. Next: scenario 069 shows the school case.
Command line
cookwala humanitarian --pack profiles/humanitarian/care-vulnerable-groups.rulepack.json examples/humanitarian/flows/disaster-kitchen/offer.json
cat profiles/humanitarian/care-vulnerable-groups.rulepack.jsonRecorded output
Status: ok
[1] humanitarianCheck: {"results": [{"id": "of-test-074-egg", "kind": "Offer", "findings": [{"rule": "care.raw_egg", "severity": "block", "detail": "line 1: contains raw_egg"}]}]}
[2] humanitarianCheck: {"results": [{"id": "of-test-074-egg", "kind": "Offer", "findings": []}]}
[3] humanitarianCheck: {"results": [{"id": "of-test-074-sprouts", "kind": "Offer", "findings": [{"rule": "care.raw_sprouts", "severity": "warn", "detail": "line 1: contains raw_sprouts"}]}]}
[4] humanitarianCheck: {"results": [{"id": "of-test-074-fish", "kind": "Offer", "findings": []}]}
[5] validate: {"ok": true, "errors": []}Code
Run: python scenarios/out/074-care-rules-for-vulnerable-groups-on-an-offer/python.py
# Scenario 074: Care rules: which food classes are blocked for everyone, which depend on the group
# The care pack blocks raw egg, raw meat, raw fish and unpasteurized dairy for all vulnerable groups, warns about raw sprouts, and ties other rules to a named group. Three small test offers written for this scenario show the three cases.
# 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: A test offer of a raw-egg dish, checked with the care pack: a block finding for everyone.
egg = c.humanitarian_check([{"profile": "0.2.0", "kind": "Offer", "id": "of-test-074-egg", "donor": "did:web:example.org", "state": "offered", "items": [{"lineId": "1", "name": "Homemade mayonnaise", "kg": 4, "storage": "chilled", "allergens": [], "foodClasses": ["raw_egg"]}], "window": {"from": "2026-11-02T18:00:00+02:00", "to": "2026-11-02T21:00:00+02:00"}, "site": {"country": "EG", "admin1": "Cairo"}}], ["care-vulnerable-groups"])
assert pick(egg, "results[0].findings.length") == 1, pick(egg, "results[0].findings.length")
print("ok", "results[0].findings.length", "=", 1)
assert pick(egg, "results[0].findings[0].rule") == "care.raw_egg", pick(egg, "results[0].findings[0].rule")
print("ok", "results[0].findings[0].rule", "=", "care.raw_egg")
assert pick(egg, "results[0].findings[0].severity") == "block", pick(egg, "results[0].findings[0].severity")
print("ok", "results[0].findings[0].severity", "=", "block")
# Step 2: The same offer with the basic pack only: no food-class rules there, no finding.
eggBasic = c.humanitarian_check([{"profile": "0.2.0", "kind": "Offer", "id": "of-test-074-egg", "donor": "did:web:example.org", "state": "offered", "items": [{"lineId": "1", "name": "Homemade mayonnaise", "kg": 4, "storage": "chilled", "allergens": [], "foodClasses": ["raw_egg"]}], "window": {"from": "2026-11-02T18:00:00+02:00", "to": "2026-11-02T21:00:00+02:00"}, "site": {"country": "EG", "admin1": "Cairo"}}], ["basic-nutrition-food-safety"])
assert pick(eggBasic, "results[0].findings.length") == 0, pick(eggBasic, "results[0].findings.length")
print("ok", "results[0].findings.length", "=", 0)
# Step 3: Raw sprouts: a warning, not a block.
sprouts = c.humanitarian_check([{"profile": "0.2.0", "kind": "Offer", "id": "of-test-074-sprouts", "donor": "did:web:example.org", "state": "offered", "items": [{"lineId": "1", "name": "Bean sprouts", "kg": 6, "storage": "chilled", "allergens": [], "foodClasses": ["raw_sprouts"]}], "window": {"from": "2026-11-02T18:00:00+02:00", "to": "2026-11-02T21:00:00+02:00"}, "site": {"country": "EG", "admin1": "Cairo"}}], ["care-vulnerable-groups"])
assert pick(sprouts, "results[0].findings[0].rule") == "care.raw_sprouts", pick(sprouts, "results[0].findings[0].rule")
print("ok", "results[0].findings[0].rule", "=", "care.raw_sprouts")
assert pick(sprouts, "results[0].findings[0].severity") == "warn", pick(sprouts, "results[0].findings[0].severity")
print("ok", "results[0].findings[0].severity", "=", "warn")
# Step 4: High-mercury fish: the rule names the group pregnant, and an offer names no group, so no finding here. It fires on a handover or distribution that names the group.
fish = c.humanitarian_check([{"profile": "0.2.0", "kind": "Offer", "id": "of-test-074-fish", "donor": "did:web:example.org", "state": "offered", "items": [{"lineId": "1", "name": "Swordfish steaks", "kg": 10, "storage": "frozen", "allergens": [], "foodClasses": ["high_mercury_fish"]}], "window": {"from": "2026-11-02T18:00:00+02:00", "to": "2026-11-02T21:00:00+02:00"}, "site": {"country": "EG", "admin1": "Cairo"}}], ["care-vulnerable-groups"])
assert pick(fish, "results[0].findings.length") == 0, pick(fish, "results[0].findings.length")
print("ok", "results[0].findings.length", "=", 0)
# Step 5: The test offer is a valid profile document.
valid = c.validate("humanitarian", {"profile": "0.2.0", "kind": "Offer", "id": "of-test-074-egg", "donor": "did:web:example.org", "state": "offered", "items": [{"lineId": "1", "name": "Homemade mayonnaise", "kg": 4, "storage": "chilled", "allergens": [], "foodClasses": ["raw_egg"]}], "window": {"from": "2026-11-02T18:00:00+02:00", "to": "2026-11-02T21:00:00+02:00"}, "site": {"country": "EG", "admin1": "Cairo"}})
assert pick(valid, "ok") == True, pick(valid, "ok")
print("ok", "ok", "=", True)
print("scenario complete")
scenarios/074-care-rules-for-vulnerable-groups-on-an-offer.json