What broke
A start-of-measurement timestamp set 15 hours in the future silenced all evidence
Claude set the timestamp that the stock app's strategy measurements count from about 15 hours into the future. Every counter stayed at zero and nothing raised an error. Claude found it during a fourth full review of its own code, and the fix added a guard, a health check and four tests.
The short version
What went wrongClaude set the strategy epoch about 15 hours in the future, so every measurement quietly showed zero and the go-live gate looked like a strategy that had just started.
How we found itClaude found it during a fourth full review of its own new code.
The rule nowFor every constant that is a point in time, check it is in the past and whether a wrong value gives a wrong or a missing answer; if missing, add a guard, a visible health check and a failing test.
This post documents something Claude got wrong. The claim rests on a commit or a file, not on memory. All of Claude's mistakes
The stock app trades a portfolio by rules. Before a strategy is allowed to go live, it has to build up a record. A go-live gate checks a set of criteria. Every one of those measurements counts from a single timestamp, the strategy epoch.
For a period on 30 July 2026, that timestamp was in the future, and nothing told us.
What Claude got wrong
The epoch had been moved twice in about 24 hours, both times on purpose, because the trading logic had changed. The value written the second time was 20:55 UTC on 30 July.
The commit that fixed it explains the mistake: the value was about 15 hours in the future, because it was set just after midnight with the next day’s date. The commit labels the fix as Claude’s own work, from a fourth round of fully reviewing its own code, with four new findings, all of them Claude’s. Claude wrote the wrong date, and Claude later found it.
The arithmetic holds up. The fix was committed at 07:50 Oslo time on 30 July, which is 05:50 UTC. An epoch of 20:55 UTC that day is about 15 hours later.
What a future epoch does
Nothing crashed and no error was logged. According to the fix commit, every consumer of the epoch quietly produced nothing:
- The expectancy calculation looked for completed sales after the epoch, found none, and kept the round-trip count at 0.
- The track-record day count is the current date minus the epoch. With the epoch in the future that is negative, and the code clamped it to 0.
- The “frozen twin”, a comparison series that shows whether the changes did anything useful, got no data at all.
- The go-live gate showed 0 of 8 criteria met, with 0 % progress on both criterion A (track days) and criterion C (round trips).
The commit concludes that the day’s trading would have produced no documentation at all.
That is the dangerous part. On a freshly reset fleet, 0 of 8 at 0 % looks exactly like a strategy that has only just started. A comment in the new test file makes the same point: an epoch in the future hides all of the documentation, and the measuring apparatus still looks like it works.
How it was found
Claude found it during what the commit calls the fourth round of reviewing all of its own new code. That same round turned up three more problems in a new decision engine:
- It let exchange opening hours skew which stocks it picked.
- It sold a large position to buy a much smaller one while slots were free, and left most of the proceeds in cash.
- It made zero trades without saying why. The commit notes this was the third time the same gap had shown up in Claude’s own work.
The epoch bug ranked worst of the four. A follow-up commit two minutes later calls it the worst finding of the round.
One more time error belongs on the record. The code comments added in the fix date the discovery and correction to 31 July. The commit timestamps say 30 July, in the morning. We go by the commits. Even so, a dated comment in a fix for a date bug is off by a day.
The fix
The epoch was set to 05:00 UTC on 30 July (07:00 in Oslo), when the new logic was deployed. The commit also wrote down what the timestamp means: it marks when the new logic began to run, not when the code was written. Code that has been written but not deployed has not changed anything.
The same comment keeps a standing warning for the owner. The epoch has been moved several times, so the record cannot start until the strategy stops changing.
The guard
The commit states the goal plainly: this error should not be able to go unnoticed again. To make that true it added three things:
- A guard function. It warns when the epoch is in the future, says how many hours ahead it is, and what that breaks: no round trips can count, track time is locked at 0, and the go-live gate shows 0 % without explanation.
- A health check on the app’s status page. When the epoch is valid, it shows the timestamp and says measurement accumulates from that point. When it is in the future, it shows the guard’s message and is flagged as stale.
- Four tests. Two check that the epoch is in the past right now, so a mistyped date fails the next test run. One checks that the guard speaks up when the epoch is in the future and that its message names the consequence, not just that something is wrong. One checks that it stays silent when the epoch is in the past, so it doesn’t raise false alarms.
The test count went from 480 to 491 in that commit. The four epoch tests are part of those 11 new ones.
The broader lesson, written down
The next commit added a document on time mechanics to the repository and a new entry, number 7, to the list of recurring failure classes: time errors. The document lists who reads the epoch and what breaks for each. It also lists other time errors the app has already paid for: a raw date passed into a database query that broke maturation, dividend crediting and decision attribution, three times in total; an external price API whose end date was exclusive and left the whole price series a day behind; and a new rule that would have been applied to price history from before the rule existed.
The core point of that commit, in short: a logic error gives a wrong answer, but a time error gives no answer at all, and no answer looks just like normal waiting. So nobody goes looking.
The rule
For every constant that is a point in time, ask three questions. Is it in the past? Is the window inclusive or exclusive? If it is wrong, will we get a wrong answer, which someone notices, or no answer, which nobody does? If the answer is “no answer”, the value gets a guard, a health check people can see, and a test that fails the next time someone types the wrong date.