Bake-off: 15 January vs. 2027-01-15
Every retailer is about to paste a Christmas returns window into its support prompt, and most will write the deadline the way the marketing email does. We wrote one holiday returns section twice, once with dates as a person writes them and once in ISO format, gave both the same January edit, and let the checker referee. One of them was reading the date as a number of things.
TL;DR The checker reads until 15 January as a count of fifteen and until 2027-01-15 as a date, so two clashing return deadlines written the first way check clean and written the second way block the build: put ISO dates in the prompt, one format throughout, and let a tool own each order's last day.
Tallis Toys accepts returns within 30 days. Every November it stretches that for Christmas, because a train set bought on 3 December is a present that will not be opened until the 25th. Pip, the returns chat assistant, needs the extension in its prompt by the first of the month. Two people draft the line. One writes the date the way the customer email does: until 15 January. The other writes it the way a database does: until 2027-01-15. Both drafts say the same thing. The checker does not hear the same thing.
§1Two drafts, one Christmas
Draft A writes the dates day first, as most of the world does outside the United States.
# Role @@ role: one sentence names the speaker, so every later "you" is the agent You are Pip, the returns assistant for Tallis Toys. # Returns @@ standard_window: the returns policy for the rest of the year - MUST accept a return within 30 days. @@ christmas_window: gifts bought early must survive until after the day, so the window runs into January - WHEN a customer bought an item between 1 November and 24 December THEN MUST accept the return until 15 January.
Draft B is the same section with every date in ISO 8601: year, month, day, hyphens.
# Role @@ role: one sentence names the speaker, so every later "you" is the agent You are Pip, the returns assistant for Tallis Toys. # Returns @@ standard_window: the returns policy for the rest of the year - MUST accept a return within 30 days. @@ christmas_window: gifts bought early must survive until after the day, so the window runs into January - WHEN a customer bought an item between 2026-11-01 and 2026-12-24 THEN MUST accept the return until 2027-01-15.
$ npx typeglish score day-first.tg day-first.tg — A (96/100) proven errors: none tiers: base+z3 planes runtime 95 (what the model reads) · hygiene 100 (source only) rules 2 of 2 rule-shaped lines read · 1 not provable $ npx typeglish score iso.tg iso.tg — A (96/100) proven errors: none tiers: base+z3 planes runtime 95 (what the model reads) · hygiene 100 (source only) rules 2 of 2 rule-shaped lines read · 1 not provable
WHEN and the 30-day default does not, and a deadline beside a duration draws nothing either way.§2Round two: the courier strike
Say a courier strike in early January slows every return in the country. Ops extends the Christmas window by a month and appends one line to the returns section. They do not delete the old line, because the CX lead wrote it and they are not sure it is theirs to delete, and they write the date the way the draft already writes dates.
@@ courier_delay: the courier strike slowed returns, so ops extended the window - WHEN a customer bought an item between 1 November and 24 December THEN MUST accept the return until 15 February. @@ courier_delay: the courier strike slowed returns, so ops extended the window - WHEN a customer bought an item between 2026-11-01 and 2026-12-24 THEN MUST accept the return until 2027-02-15.
Both drafts now hold two deadlines for the same return under the same condition. Pip will pick one per conversation, and a customer told 15 January on Monday and 15 February on Tuesday will screenshot both.
$ npx typeglish check iso-edit.tg
iso-edit.tg:9:1 error logic/time Conflicts with line 11. Time conflict — "2027-01-15" and "2027-02-15" put two times on one "you accept the · return" slot; a slot holds one time per scope. Guard one with IF (different days or conditions) or remove one.
↳ line 11: - WHEN a customer bought an item between 2026-11-01 and 2026-12-24 THEN MUST accept the return until 2027-02-15.
iso-edit.tg:11:1 error logic/time Conflicts with line 9. Time conflict — "2027-01-15" and "2027-02-15" put two times on one "you accept the · return" slot; a slot holds one time per scope. Guard one with IF (different days or conditions) or remove one.
↳ line 9: - WHEN a customer bought an item between 2026-11-01 and 2026-12-24 THEN MUST accept the return until 2027-01-15.
✗ 1 file — 2 error, 0 warning, 0 info
$ npx typeglish score iso-edit.tg
iso-edit.tg — F (79/100) proven errors — grade capped at F tiers: base+z3
$ npx typeglish check day-first-edit.tg
✓ 1 file — 0 error, 0 warning, 0 info
$ npx typeglish score day-first-edit.tg
day-first-edit.tg — A (95/100) proven errors: none tiers: base+z3
§3Why 15 January is a count
Ask the checker what each edited line is connected to and the difference is stark.
$ npx typeglish statements day-first-edit.tg --line 9 day-first-edit.tg Snapshot tg1-e24a23e7-951f3363 [tg1-e24a23e7-951f3363:statement:354] line 9 - WHEN a customer bought an item between 1 November and 24 December THEN MUST accept the return until 15 January. When a customer bought an item between 1 November and 24 December: Requires Pip to accept the return until 15 January. partial coverage; ~28 tokens; 0 diagnostics; 0 relations $ npx typeglish statements iso-edit.tg --line 9 iso-edit.tg Snapshot tg1-14c9356c-6a7d8cd6 [tg1-14c9356c-6a7d8cd6:statement:354] line 9 - WHEN a customer bought an item between 2026-11-01 and 2026-12-24 THEN MUST accept the return until 2027-01-15. When a customer bought an item between 2026-11-01 and 2026-12-24: Requires Pip to accept the return until 2027-01-15. partial coverage; ~24 tokens; 1 diagnostics; 2 relations
--json form of the same command says why: the 15 in 15 January is read as a cardinal numeral and January as the noun it counts, the same reading as 15 tickets.So in draft A the deadline is not a time at all. It is fifteen of something called January. That reading is visible when it happens to fire: change the edit to until 31 January and the day-first draft does block, with a message that gives the game away.
$ npx typeglish check day-first-31.tg
day-first-31.tg:9:1 error logic/contradiction Conflicts with line 11. Counted rule — "accept the return until 15 January." vs "accept the return until 31 January." is bound to exactly 15 but exactly 31. The counts cannot both hold.
↳ line 11: - WHEN a customer bought an item between 1 November and 24 December THEN MUST accept the return until 31 January.
day-first-31.tg:11:1 error logic/contradiction Conflicts with line 9. Counted rule — "accept the return until 15 January." vs "accept the return until 31 January." is bound to exactly 15 but exactly 31. The counts cannot both hold.
↳ line 9: - WHEN a customer bought an item between 1 November and 24 December THEN MUST accept the return until 15 January.
✗ 1 file — 2 error, 0 warning, 0 info
We ran the other spellings a returns team might reach for, two clashing deadlines each, on the same slot:
January 15besideFebruary 15, month first: blocked,logic/time, read as two times. So areJan 31,January 31standJanuary 31, 2027.2027-01-15beside2027-02-15: blocked,logic/time, as round two showed.15 January 2027beside31 January 2027: clean. Adding the year to a day-first date takes away even the accidental count conflict.15/01/2027beside31/01/2027, and01/15/2027beside01/31/2027: clean. Slashed numbers are not read as dates in either order.January 31beside2027-01-15: clean. Two formats the checker does read as times are still not compared with each other.
That last line is the one to remember. The format you choose matters less than choosing one. This is the lesson of Bake-off: 5 business days vs. 7 days and of $40 and 40 dollars are not the same rule, moved from durations and money to the calendar: the spelling of a quantity decides whether it is a quantity at all.
§4Round three: the other readers
The checker is one reader. The model and the customer are the others, and the date formats do not treat them equally either.
A date with no year expires silently. Until 15 January was right when it was written in November 2026. If nobody removes it, it reads just as confidently in November 2027, when it means a date that has passed or a date a year away, and the model has to guess which. ISO forces the year onto the page, which is also the property that lets the checker order two of them.
A slashed date is ambiguous by construction. 01/02 is the first of February in London and the second of January in Chicago, and a prompt read by customers in both cities, or written by colleagues from both, carries the ambiguity into every reply. ISO has one reading everywhere.
What ISO is not is customer-facing. Nobody wants to be told their return is accepted until 2027-01-15. That is fine: the prompt is not the reply. Keep the machine format in the file, ask for the human format in the reply, and let a $TEST check the reply, as the one below does.
And one reader should not be doing date arithmetic at all. Bought between 2026-11-01 and 2026-12-24 asks the model to know the purchase date and compare it with two others. The order system already knows the purchase date and whichever extension is live this week. As in Why your agent gets the time zone wrong, the date-shaped question belongs to the system that holds the calendar.
§5The verdict: ISO in the prompt, the order system for the order
The final draft keeps the policy dates in ISO, so the checker defends them, hands the per-order answer to a tool, and pins the reply format with a deterministic assert.
$TOOL check_return_window - description:: Returns the last day an order can be returned, with the Christmas extension applied. - input:: - order_id:: string # Role @@ role: one sentence names the speaker, so every later "you" is the agent You are Pip, the returns assistant for Tallis Toys. # Returns @@ standard_window: the returns policy for the rest of the year - MUST accept a return within 30 days. @@ christmas_window: gifts bought early must survive until after the day, so the window runs into January - WHEN a customer bought an item between 2026-11-01 and 2026-12-24 THEN MUST accept the return until 2027-01-15. @@ exact_day: the order system knows the purchase date and applies the extension, the model does not - WHEN a customer asks for the last day to return an order THEN MUST call @[check_return_window]. $TEST christmas_gift - input:: I bought a train set on 3 December as a present. Can it still come back after Christmas? - expect:: - tells the customer the return is accepted until 15 January 2027 - matches /^(?![\s\S]*\d{1,2}\/\d{1,2})/ $TEST ordinary_return - input:: The puzzle I ordered last week is missing pieces, can I send it back? - expect:: - tells the customer a return is accepted within 30 days $TEST last_day - input:: What is the last day I can return order TT-48213? - expect:: - calls check_return_window
$ npx typeglish score final.tg final.tg — A (97/100) proven errors: none tiers: base+z3 planes runtime 96 (what the model reads) · hygiene 100 (source only) rules 3 of 3 rule-shaped lines read · 1 not provable · 3/3 covered by $TEST $ npx typeglish test final.tg --dry ✓ final.tg coverage: 3/3 rules exercised · christmas_gift — "I bought a train set on 3 December as a present. Can it stil" (not run) ✓ matches /^(?![\s\S]*\d{1,2}\/\d{1,2})/ · rubric — 1 prose expectation, judged on a live run (needs ANTHROPIC_API_KEY) · ordinary_return — "The puzzle I ordered last week is missing pieces, can I send" (not run) · rubric — 1 prose expectation, judged on a live run (needs ANTHROPIC_API_KEY) · last_day — "What is the last day I can return order TT-48213?" (not run) · rubric — 1 prose expectation, judged on a live run (needs ANTHROPIC_API_KEY) ✓ 1 prompt — 0 failed
christmas_gift is a deterministic assert: if Pip ever answers with a slashed date such as 15/01, the case fails without a judge. The prose expectation asks for the date in words, with its year.Then the January edit, appended to the final draft in its own format.
$ npx typeglish check final-edit.tg
final-edit.tg:14:1 error logic/time Conflicts with line 19. Time conflict — "2027-01-15" and "2027-02-15" put two times on one "you accept the · return" slot; a slot holds one time per scope. Guard one with IF (different days or conditions) or remove one.
↳ line 19: - WHEN a customer bought an item between 2026-11-01 and 2026-12-24 THEN MUST accept the return until 2027-02-15.
final-edit.tg:19:1 error logic/time Conflicts with line 14. Time conflict — "2027-01-15" and "2027-02-15" put two times on one "you accept the · return" slot; a slot holds one time per scope. Guard one with IF (different days or conditions) or remove one.
↳ line 14: - WHEN a customer bought an item between 2026-11-01 and 2026-12-24 THEN MUST accept the return until 2027-01-15.
✗ 1 file — 2 error, 0 warning, 0 info
check_return_window, every per-order answer moves the same afternoon, and the one policy line gets edited, not appended to.One honest limit. The checker compares ISO dates on the same slot; it does not check that a date makes sense. A Christmas window that closes before it opens, or a deadline set in 2026 when you meant 2027, is a clean line. A second pair of eyes on the year is still the cheapest test you can run.
§6Common questions
- How should I write dates in my AI agent's system prompt?
- As ISO dates with the year, such as 2027-01-15, in one format across the whole prompt. In this bake-off the checker proved two conflicting return deadlines written that way and passed the same pair written as 15 January and 15 February. Let the model turn the date into words for the customer.
- Why did my holiday returns extension not conflict with the old deadline?
- If both deadlines are written day first, such as 15 January and 15 February, the checker reads each as a count of 15 and finds nothing to compare. Write them as 2027-01-15 and 2027-02-15 and the second line is a blocking logic/time error until you delete or guard one of them.
- Does adding the year to 15 January help?
- No. In this bake-off 15 January 2027 beside 31 January 2027 checked clean, while 15 January beside 31 January without the year blocked as a count conflict. Slashed dates such as 15/01/2027 also compared with nothing. Only ISO dates and month-first dates such as January 15 were compared as times.
- Should my support agent work out a customer's return deadline itself?
- No. The deadline depends on the purchase date and whatever extension is live, and the order system knows both. Keep the policy dates in the prompt so the checker can defend them, and give the agent a tool such as check_return_window that returns the last day for one order.
A two-minute audit before peak season: search your prompts for month names and for slashes between digits. Every hit that is a deadline is a promise the checker may be reading as a count, or not reading at all. Rewrite each as an ISO date with its year, run typeglish statements <file> --line <n> on one of them, and look for relations above zero once a second deadline shares its slot. For where the number itself should live, Bake-off: the number in the prompt vs. the number at runtime runs the same kind of referee on a refund SLA.