contimp-app / scripts /build_order_world.py
lefft's picture
Add Support Comms (order-comms) task; exclude .claude/ from upload
8691ce5 verified
Raw
History Blame Contribute Delete
8.3 kB
"""Build the committed synthetic e-commerce "world" for the order-comms task.
Deterministic (fixed seed) and re-runnable: produces identical JSONL every time.
No network, no LLM. Everything is invented and generic — safe to commit/world-read.
Writes data/order_world/{customers,products,orders,order_items,shipments,returns}.jsonl,
which back BOTH tools of the task (duckdb SQL + the mock entity search).
uv run python scripts/build_order_world.py
"""
import json
import random
from datetime import datetime, timedelta
from pathlib import Path
OUT = Path(__file__).resolve().parent.parent / "data" / "order_world"
SEED = 7
BASE = datetime(2026, 6, 15, 12, 0, 0) # "today" the world is anchored to
N_CUSTOMERS = 40
N_PRODUCTS = 60
N_ORDERS = 200
BRANDS = [
"Aurelia", "Kettleworth", "Nordhaus", "Brightleaf", "Pinnacle", "Quill & Co",
"Vantage", "Maple & Oak", "Lumio", "Cragmont", "Sundara", "Driftwood",
]
CATALOG = {
"Kitchen": ["Espresso Machine", "Cast Iron Skillet", "Stand Mixer",
"Electric Kettle", "Chef's Knife Set", "Air Fryer"],
"Electronics": ["Wireless Earbuds", "Bluetooth Speaker", "Noise-Canceling Headphones",
"Smart Thermostat", "4K Action Camera", "Mechanical Keyboard"],
"Home": ["Linen Duvet Set", "Area Rug 5x7", "Arc Floor Lamp",
"Ceramic Vase", "Memory Foam Pillow", "Blackout Curtains"],
"Outdoor": ["2-Person Tent", "Camp Stove", "Hiking Backpack",
"Insulated Water Bottle", "Trekking Poles", "Sleeping Bag"],
"Apparel": ["Rain Jacket", "Merino Wool Socks", "Trail Running Shoes",
"Fleece Pullover", "Canvas Tote", "Leather Belt"],
"Toys": ["Building Block Set", "Wooden Train Set", "Plush Bear",
"Remote Control Car", "Strategy Board Game", "1000pc Puzzle"],
}
CARRIERS = ["Northstar Freight", "BluePost", "RapidShip", "Continental Parcel"]
FIRST = ["Avery", "Jordan", "Riley", "Casey", "Morgan", "Quinn", "Reese", "Skyler",
"Devon", "Harper", "Emerson", "Rowan", "Sasha", "Marlo", "Tatum", "Blair",
"Corey", "Dana", "Elliot", "Frankie", "Glen", "Hollis", "Ira", "Jules"]
LAST = ["Mercer", "Holloway", "Vance", "Ashby", "Calderon", "Doyle", "Esposito",
"Farrow", "Grimaldi", "Hatcher", "Ingram", "Jennings", "Keaton", "Larkin",
"Maddox", "Nakamura", "Oviedo", "Pruitt", "Quintero", "Rhodes", "Salazar",
"Thorne", "Underwood", "Vasquez"]
CITIES = [
("Riverton", "OH"), ("Fairview", "TX"), ("Glendale", "AZ"), ("Ashland", "OR"),
("Bellmont", "NC"), ("Crestwood", "IL"), ("Dunmore", "PA"), ("Easton", "MD"),
("Granville", "NY"), ("Hartwell", "GA"), ("Ironwood", "MI"), ("Junction City", "KS"),
]
RETURN_REASONS = ["arrived damaged", "wrong item received", "no longer needed",
"defective on arrival", "not as described", "changed mind"]
def det_uuid(rng: random.Random) -> str:
return "%08x-%04x-%04x-%04x-%012x" % (
rng.getrandbits(32), rng.getrandbits(16), rng.getrandbits(16),
rng.getrandbits(16), rng.getrandbits(48),
)
def iso(dt: datetime) -> str:
return dt.strftime("%Y-%m-%d %H:%M:%S")
def build() -> dict[str, list[dict]]:
rng = random.Random(SEED)
products = []
for _ in range(N_PRODUCTS):
category = rng.choice(list(CATALOG))
base = rng.choice(CATALOG[category])
brand = rng.choice(BRANDS)
products.append({
"sku": f"SKU-{rng.randint(100000, 999999)}",
"product_name": f"{brand} {base}",
"brand": brand,
"category": category,
"price": round(rng.uniform(12, 480), 2),
})
customers = []
used_emails: set[str] = set()
for _ in range(N_CUSTOMERS):
name = f"{rng.choice(FIRST)} {rng.choice(LAST)}"
handle = name.lower().replace(" ", ".")
email = f"{handle}{rng.randint(1, 99)}@mailbox.example.com"
while email in used_emails:
email = f"{handle}{rng.randint(1, 999)}@mailbox.example.com"
used_emails.add(email)
city, state = rng.choice(CITIES)
customers.append({
"customer_id": det_uuid(rng),
"full_name": name,
"email": email,
"phone": "+1" + "".join(str(rng.randint(0, 9)) for _ in range(10)),
"city": city,
"state_code": state,
})
orders, order_items, shipments, returns = [], [], [], []
for _ in range(N_ORDERS):
cust = rng.choice(customers)
placed = BASE - timedelta(days=rng.randint(0, 60),
hours=rng.randint(0, 23), minutes=rng.randint(0, 59))
order_id = det_uuid(rng)
order_number = f"ORD-{placed:%y%m%d}-{rng.randint(1000, 9999)}"
items = rng.sample(products, rng.randint(1, 3))
total = 0.0
for p in items:
qty = rng.randint(1, 2)
total += qty * p["price"]
order_items.append({
"order_id": order_id, "sku": p["sku"],
"quantity": qty, "unit_price": p["price"],
})
age_days = (BASE - placed).days
# status biased by age; recent orders still moving, older ones resolved
if age_days <= 2:
status = rng.choice(["placed", "paid", "paid", "shipped"])
elif age_days <= 10:
status = rng.choice(["shipped", "shipped", "delivered", "cancelled"])
else:
status = rng.choice(["delivered", "delivered", "delivered", "refunded"])
orders.append({
"order_id": order_id,
"order_number": order_number,
"customer_id": cust["customer_id"],
"order_status": status,
"order_total": round(total, 2),
"placed_at": iso(placed),
"ship_to_city": cust["city"],
"ship_to_state": cust["state_code"],
})
if status != "cancelled":
shipped = placed + timedelta(days=rng.randint(1, 3))
est = shipped + timedelta(days=rng.randint(2, 7))
if status in ("delivered", "refunded"):
ship_status, delivered = "delivered", iso(est - timedelta(days=rng.randint(0, 2)))
elif status == "shipped":
ship_status = rng.choice(["in_transit", "in_transit", "out_for_delivery", "exception"])
delivered = ""
else:
ship_status, delivered = "label_created", ""
shipments.append({
"shipment_id": det_uuid(rng),
"shipment_number": f"SHP-{shipped:%y%m%d}-{rng.randint(1000, 9999)}",
"order_id": order_id,
"carrier": rng.choice(CARRIERS),
"ship_status": ship_status,
"tracking_number": "1Z" + "".join(str(rng.randint(0, 9)) for _ in range(12)),
"shipped_at": iso(shipped),
"est_delivery": iso(est),
"delivered_at": delivered,
})
# ~30% of delivered/refunded orders have a return
if status in ("delivered", "refunded") and rng.random() < 0.4:
p = rng.choice(items)
created = placed + timedelta(days=rng.randint(6, 20))
rstatus = "refunded" if status == "refunded" else \
rng.choice(["requested", "approved", "received"])
returns.append({
"return_id": det_uuid(rng),
"rma_number": f"RMA-{created:%y%m%d}-{rng.randint(1000, 9999)}",
"order_id": order_id,
"sku": p["sku"],
"reason": rng.choice(RETURN_REASONS),
"return_status": rstatus,
"created_at": iso(created),
})
return {
"customers": customers, "products": products, "orders": orders,
"order_items": order_items, "shipments": shipments, "returns": returns,
}
def main() -> None:
OUT.mkdir(parents=True, exist_ok=True)
world = build()
for name, rows in world.items():
path = OUT / f"{name}.jsonl"
with path.open("w") as f:
for row in rows:
f.write(json.dumps(row) + "\n")
print(f"wrote {len(rows):>4} rows -> {path.relative_to(OUT.parent.parent)}")
if __name__ == "__main__":
main()