Flow
What to do when a step fails
1History window times out
Split it in half and retry each half; stop splitting at one day.
2Error is not retryable
Surface it immediately; never retry validation or authorization errors.
3No receive event found
Mark age unknown and exclude the row from any discount selection.
4Plan hash differs at apply
Return a conflict, record a blocked run and make no upstream calls.
5One write fails mid-run
Record it on that target, continue, and finish as completed with errors.
The bulk markdown tool was hard to misuse before I looked at its age column. When I did, the age turned out to come from the wrong date.
Same count, different packages
The tool shows each package in a store with its age, and lets someone tag a whole age band with a discount in one go. That's a lot of live writes, so I split it into preview and apply.
At first, apply only checked that the count of targets matched the preview. That's not enough. Two packages can sell while two others get old enough, and the count stays the same. Now the preview also returns a hash of the plan: the sorted choices, plus every target with its old tags and new tags. Apply sends the count and hash back. The server rebuilds the plan from fresh data and compares. If anything moved, it refuses, logs the refusal and writes nothing.
Every preview, refusal and apply is logged with its targets. Writes go one package at a time, and one failure doesn't stop the rest. It just marks the run as finished with errors.
The age was on the wrong clock
Age came from the date the producer packed the item. If that was blank, it used the last time anyone edited the record. Neither tells you how long the store has had it. Something packed months ago and delivered last week isn't old stock.
Now age counts from the first time the store received the package, taken from the store's own history. A missing receive record has a consequence downstream.
If a package has no receive record, the line is left out of the markdown run entirely.
Skipping costs a day on the shelf. A wrong discount costs money you don't get back. So don't fill the gap with the label date.
The hard part is matching. The history names packages several different ways. I upper-case every name, store the receive date under each one, and keep the earliest.
Reading the history in pieces
How far back to look still comes from the label, since nothing arrives before it's packed. Add a month of padding and cap it at a few years.
One big request for all of that is fragile, so read it in half-year chunks, one after another. If a chunk times out, split it in half and try each half. Stop splitting at one day and let the error through. Never retry errors that aren't about timeouts or a busy server.
Removing the label date
Last, I took the packed date out of the report so nobody mistakes it for the age.