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.

Audience: food safety officer · Goal: Make people healthier · Level: beginner

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

Steps

  1. A test offer of a raw-egg dish, checked with the care pack: a block finding for everyone. humanitarianCheck

  2. The same offer with the basic pack only: no food-class rules there, no finding. humanitarianCheck

  3. Raw sprouts: a warning, not a block. humanitarianCheck

  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. humanitarianCheck

  5. The 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.json

Recorded 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

Previous: 073 Next: 075