Skip to content

fix(menu): treat items outside their sale hours as unavailable - #63

Merged
mekedron merged 2 commits into
mainfrom
fix/item-sale-hours
Oct 22, 2026
Merged

mekedron merged 2 commits into
mainfrom
fix/item-sale-hours

Conversation

@mekedron

@mekedron mekedron commented Oct 22, 2026 •

Copy link
Copy Markdown
Owner

Summary

The daily live smoke failed because it put a lunch dish into the cart outside lunch hours. Wolt sells that dish only on Mondays from 10:30 to 15:00. The CLI ignored those hours: it listed the dish as available, let cart add put it in the basket and priced it at checkout. Wolt itself marked the basket line unavailable and counted the basket total as 0.

Now the CLI and the MCP server read each dish's sale hours in the restaurant's local time. Outside those hours the dish shows as unavailable with a reason such as "not sold now; available Mon 10:30-15:00 venue time". Adding it to the cart or previewing checkout is refused. wolt cart also warns when Wolt marks a line in the basket unavailable.

Nothing from you: the fix ships as v2.5.3 after CI passes.

Fixes #62

Details

  • Wolt assortment items carry available_times: weekly windows, ISO weekdays (1 = Monday), start and end in milliseconds since venue-local midnight. disabled_info stays null outside the window.
  • The gateway client checks every assortment response (full menu, category, items, search) and writes a disabled_info for items outside their window. Existing availability checks in the CLI and MCP honour it unchanged.
  • The venue's time comes from the venue pages the client already loads. A static page names the IANA zone, and a dynamic page reports the venue's current time with its UTC offset (open_status.now). A menu load and a cart add need no extra request. Otherwise the client asks the dynamic page once, and the static page is the last resort. If neither works, items stay as Wolt returned them.
  • The static page is avoided on purpose. Wolt rate-limits it for GitHub runner IPs (429). An earlier version of this branch fetched it for every menu, and the live smoke's cart add <venue-id> then failed with WOLT_ITEM_AVAILABILITY_UNKNOWN.
  • An offset expires after an hour, so a long-running MCP server picks up a DST switch.
  • time/tzdata is embedded so Windows builds resolve the zone.
  • wolt cart passes Wolt's per-line is_available through and adds a warning for each unavailable line.

Testing

  • Live: Ravintola Trishuli (Espoo) on Thursday 16:00. The Monday lunch dish LAMB METHI shows as unavailable, and cart add fails with WOLT_ITEM_UNAVAILABLE. Before the fix the same add succeeded, and Wolt returned the line with is_available: false and basket_total: 0.
  • Unit tests cover windows in and out of hours, the window end, an overnight window, the UTC clock against a venue-local window, the zone taken from an already loaded page, the dynamic-then-static lookup, the per-venue cache and offset expiry, no lookup for unrestricted menus, an unknown zone, and Wolt's own disabled_info winning.
  • Live smoke on this branch (run 39786680107): 29 passed, 0 failed, 3 skipped (no sell-by-weight item nearby).
  • Full gate: go build, golangci-lint run, go test ./..., go test -race ./....

Wolt assortment items carry available_times: weekly sale windows in the
venue's local time (ISO weekdays, milliseconds since local midnight). A
lunch dish sold only on Mondays 10:30-15:00 keeps disabled_info = null all
week, so the CLI listed it as available, cart add accepted it and checkout
preview priced it. Wolt's basket marked the line is_available=false and
left it out of the basket total, which failed the daily live smoke with
"Wolt basket total 0 != CLI subtotal 2900" (issue #62).

The gateway client now checks available_times on every assortment
response (full menu, category, items, search). For items outside their
window it writes a disabled_info with a reason such as
"not sold now; available Mon 10:30-15:00 Europe/Helsinki", which the menu,
item, cart add and checkout checks in the CLI and MCP already honour. The
venue timezone comes from the static venue page, is fetched only when an
item is restricted at all, and is cached per venue. When it cannot be read,
items stay as Wolt returned them. time/tzdata is embedded so Windows
builds resolve the zone too.

`wolt cart` now passes Wolt's per-line is_available through and warns for
each unavailable line, since Wolt's total then differs from the subtotal.
Looking up the venue timezone on the static venue page added one static
request per venue menu with restricted items. Wolt rate-limits that
endpoint for GitHub runner IPs: after the live smoke's menu crawl, the
static lookup inside `cart add <venue-id>` got 429 and the add failed
with WOLT_ITEM_AVAILABILITY_UNKNOWN.

The client now records each venue's zone from the venue pages it loads
anyway: the IANA zone of a static page (under the requested reference,
its slug and its id) and the UTC offset of open_status.now on a dynamic
page. A menu load and a cart add therefore need no extra request. When no
page was loaded, the client asks the dynamic page, and the static page is
the last resort. An offset expires after an hour so a long-running MCP
server picks up a DST switch. The unavailable reason says "venue time"
instead of the zone name, since an offset has none.
@mekedron
mekedron merged commit 42a19c2 into main Oct 22, 2026
5 checks passed
@mekedron
mekedron deleted the fix/item-sale-hours branch October 22, 2026 13:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Live smoke failing — first observed 2026-10-22

1 participant