Background
The Customer Messaging team at a large online retailer sends each customer one evening message that sums up the day's updates on their orders, instead of a notification for every scan. A small C++ library turns the day's order event feed and the customers' message preferences into those digests. Since the last release, customers have been complaining about what the evening message says.
How the system works
Event feed
One event per line: timestamp | customer | order | kind | detail.
- Fields are separated by
|and trimmed. Thedetailfield is optional, so a line has 4 or 5 fields; anything else is an error. timestampisYYYY-MM-DDTHH:MM(e.g.2026-09-14T08:15): month 01–12, day 01–31, hour 00–23, minute 00–59.customerandordermust not be empty.kindis one ofPLACED,SHIPPED,DELAYED,DELIVERED,CANCELLED,REFUNDED, in any case. Customers see it asPlaced,Shipped,Delayed,Delivered,Cancelled,Refunded.- Blank lines and lines starting with
#are skipped. - A malformed line throws
ParseErrorwith a message startingline N:(N counts every line from 1).
Urgent updates
An update needs the customer's attention when it is a delay (DELAYED), a cancellation
(CANCELLED), or its detail contains the words action needed anywhere, in any case
(Action needed: collect from the depot and refund held - ACTION NEEDED both count).
Preferences
One customer per line: customer: settings, where settings are separated by ; and trimmed
(empty settings are ignored, so C-305: is valid and changes nothing).
mute=<kinds>: a comma-separated list of kinds (any case; empty items ignored) the customer doesn't want. Cancellations are always sent, even when muted.urgent-only: the customer only wants urgent updates.- Settings are read in any case. Both settings may be combined; an update must pass both.
- Blank lines and lines starting with
#are skipped. A line without:, an empty customer id, an unknown setting or kind, or a customer listed twice throwsParseError. - Customers without a line get every update.
Building digests
buildDigests(events, preferences, day) builds the digests for one day (YYYY-MM-DD):
- Only events whose timestamp falls on
dayare used. - Carrier retries: when the same order has the same kind more than once that day, only the latest one (by timestamp) is kept. On equal timestamps, the one later in the feed wins.
- Updates the customer doesn't want (see Preferences) are left out. A customer with no updates left gets no digest at all.
- A digest's lines are ordered by timestamp, then order id (A to Z), then kind in the order listed
above (
PLACEDfirst,REFUNDEDlast). urgentis true when any of the customer's remaining updates is urgent.- A digest shows at most 8 lines: when there are more, only the 8 newest are kept and
earlierNotShownsays how many older ones were left out (they still count forurgent). - Digests are returned in customer id order (A to Z).
Message text
renderDigest joins these lines with \n (no trailing newline):
Order updates for <customer> on <day>Some of these updates need your attention.(only whenurgent)1 earlier update not shown/N earlier updates not shown(only whenearlierNotShown> 0)- One line per update (
renderLine):HH:MM <order> <Kind>, plus- <detail>when the detail isn't empty, e.g.08:15 ORD-5521 Shipped - via parcel locker. The parts are separated by two spaces.
Project structure
include/ and src/
util.h / util.cpp trim, split, case helpers, timestamp check, ParseError
event.h / event.cpp the event feed, kinds and urgent updates
preferences.h / preferences.cpp the preferences file and who wants which update
digest.h / digest.cpp building the day's digests
render.h / render.cpp the message text
tests/
fixtures.h shared test data
test_util.cpp helpers
test_event.cpp feed parsing and urgency
test_preferences.cpp preferences
test_digest.cpp building digests
test_render.cpp message text
testlib.h, runner.cpp the test framework
Your task
Customers report these problems with the evening message:
- Almost every message now opens by saying something needs their attention.
- Some messages show out-of-date delivery information.
- Some customers say the evening message arrives even on days it has nothing to tell them.
Find and fix the defects so that all tests pass.
- Do not modify
tests/. - Keep your changes minimal. Fix the defects; don't rewrite modules.
- Additional hidden tests check the behaviour described in this README.