It Assumed a Repeated Timestamp Was Proof
Background
lightcurves samples social posts repeatedly to record how their reach rises and decays. Buffer permits only a few hundred API requests a day, so how often to read it is the central design question — and Buffer does not document how often it refreshes its own numbers. "Buffer appears to refresh roughly daily" is folklore.
Rather than design a cadence against folklore, the daemon measures it. Every reading
records Buffer's own metricsUpdatedAt field, so the gap between two distinct values is
measured in Buffer's clock rather than ours. A probe speeds up until it can see that gap,
writes down the answer, and goes back to the configured rate.
Thomas supplied the key idea and explicitly declined to work out the details:
once you get the same value for last update... then you know between that most recent value and the one where it did change — well, again, it's not necessarily the smallest one... I don't wanna spend too much time on this. It's pretty simple. But... you can figure this out.
The assumption
A repeat has been seen, which proves our interval is shorter than the source's. The gaps between the distinct values are therefore its own intervals rather than an artefact of undersampling, and the question is answered — no narrowing search required, because the answer was in the source's timestamps all along.
That is a comment from the implementation, and the code did exactly what it says: on seeing a repeated timestamp, it took the median gap between distinct values already collected and recorded it as the refresh interval.
What was actually true
The first half is true. The second does not follow. A repeat proves we have out-run the source from that reading onward; it says nothing about readings taken before, each of which may have hidden several refreshes.
Thomas traced it by hand. A source refreshing every 10 minutes, read at gaps that start too wide:
read 11:57 gap — last_update 11:50
read 12:12 gap 15m last_update 12:10 <- changed, but the 12:00 refresh was missed
read 12:19 gap 7m last_update 12:10 <- repeat: we have out-run it
read 12:22 gap 3m last_update 12:20 <- changed, and nothing can hide in 3 minutes
At 12:19 there is a repeat and an apparent interval of twenty minutes sitting in the data — 11:50 to 12:10 — which is two refreshes, not one. The agent's code would have recorded 20 minutes. The truth is 10.
His conclusion, which is the correction:
getting the same value twice in a row is insufficient to figuring out the actual interval.
The sound rule needs a second quantity. The longest span the source was caught sitting
still is a proven lower bound on its interval — seven minutes here. So a change observed
across a reading gap no wider than that bound cannot be hiding a second refresh, and its
delta is exactly one interval. Only the 12:22 reading qualifies: 12:10 → 12:20, ten
minutes, correct. The 15-minute-gap delta is excluded because 15 > 7.

Why it looked right
Three things held it up, and the third is the one worth the entry.
The premise was true. This is not a fabricated fact or a misread document. "A repeat proves our interval is shorter than theirs" is correct, and it was reasoned from rather than invented. The failure is in the step after it — a conclusion that does not follow from a premise that does. That shape is harder to distrust than a wrong fact, because checking the premise confirms it.
The units were right and the magnitude was plausible. A wrong answer of "20 minutes"
for a source that refreshes every 10 looks exactly like a right answer. Nothing about it
is malformed. It would have been written to source_refresh_findings as a fact, complete
with the evidence fields the schema keeps precisely so findings can be judged — and the
evidence would have supported it, because the evidence was aliased too.
The tests agreed. This is the part that should have caught it and instead concealed it. A simulation existed, and it passed. It modelled the source with a formula:
frac := min(1.0, float64(current)/float64(refresh))
visible := refresh
if current > refresh {
visible = current // undersampled: the gap looks like our own rate
}
That model asserts the observed gap is either the true interval or our own polling rate. It never produces an integer multiple — which is to say, the simulation encoded the same misunderstanding as the code it was testing, and so agreed with it. The tests were a mirror, not a check.
How it got caught
Thomas caught it, by refusing to hold it in his head.
He had already handed over the idea and moved on, saying the details were simple and could be figured out. The agent implemented it, tested it, and reported success. What broke the loop was him coming back in the next message and working through concrete timestamps instead of reasoning about the algorithm in the abstract:
I could write this down... ah, man. I need to write this down. Too many things to keep in memory.
Then a worked example with real clock times, and the counterexample fell out of it. The agent had not written a single concrete trace — it had reasoned about the rule and then tested the rule against a model of the rule.
Nothing about this was caught by the agent, and nothing would have been. The tests were green, the code compiled, the reasoning read as sound, and the wrong number would have gone into the database as a measured fact.
Worth recording precisely because the human contribution was not domain knowledge or a correction handed down. It was the decision to stop and verify on paper.
The check that would have caught it
Write down four readings with real times and step through them.
That is the whole check. No tooling, no command, no data. The agent had every means to do it — it was authoring both the algorithm and its simulation — and did neither. A single concrete trace against a source refreshing on a known rhythm would have produced the 20-versus-10 discrepancy immediately, because that is exactly what it did when a human ran it.
The mechanised version, which now exists: replay the four readings above through the real SQL and assert the measurement returns 10 minutes rather than the apparent 20.
Notes
A test built from the same idea as the code is not a test. The simulation modelled the conclusion — "the visible gap is the interval, unless undersampling, in which case it's our rate" — rather than the observations. It could only ever agree. The rewritten one simulates a source refreshing on a fixed rhythm, returns the latest refresh at or before each reading, and computes statistics through a deliberate line-by-line twin of the production SQL. It now catches this class of error, and it is annotated to say so, because the tempting shortcut is exactly the one that failed.
Fixing it surfaced a second bug of the same family. With the measurement corrected, the simulation started failing for a source refreshing every 2 minutes: the probe halved its rate after every single reading, outrunning the evidence it was supposed to be gathering. At a 1m52s interval against a 2m refresh only about one reading in sixteen repeats, so one look proves nothing — and the probe sailed past the answer to its floor. Both bugs are the same mistake in different clothes: treating a small amount of evidence as conclusive because the reasoning around it felt tight.
On the categories. This one doesn't fit the existing five. It isn't a stale source, an
absence inference, a fabrication, an untested capability claim, or a silent no-op. The
output was real, derived from real data, by a method with a true premise. unsound-inference
is the provisional name: a valid-looking deduction from a correct premise to an incorrect
conclusion, where checking the premise tells you nothing about the conclusion.
If the corpus grows, the field to watch is whether these correlate with tasks where the agent wrote both the implementation and its verification. That's the structural condition here — no independent oracle existed, and the agent didn't notice it was grading its own homework.
Comments
No comments yet. Be the first!