The character has no clock

A user comes back after three weeks. The character continues the previous exchange as though no time has passed, mid-thought, referring to “earlier” about something from last month. Elsewhere in the same conversation it claims to remember an event as recent when it is a year old.

Nothing in the input said what time it is. A conversation is a sequence of messages, and a sequence has order but no duration. Every temporal statement a character makes is either something you supplied or something it produced from nothing.

Order is free, duration is not

Position in the history tells the model what came before what. It says nothing about the gap, and gaps in a long-running relationship product are enormous and irregular: minutes within a session, days between sessions, months across a lapse and return.

Two distinct failures come out of this.

Absence is invisible. Without an elapsed-time annotation, a resumed conversation is indistinguishable from a continuous one. The character does not acknowledge a gap, because as far as the input is concerned there was none. On a relationship product this is one of the most noticeable continuity failures there is, and it is also one of the cheapest to fix, which is an unusual combination in this subject.

Relative expressions rot. History is full of phrases like “tomorrow”, “next week” and “in a couple of months”, written when they were accurate. They stay in the transcript, and they stay in any summary built from the transcript, long after they have become false. A summary that says the user is starting a new job next month is wrong for the rest of the conversation’s life, and it is wrong in a way that reads as confident recall. This is a specific form of the specifics-loss that summarisation always has: compression preserves the words and destroys the reference point they depended on.

The rule that follows is store absolute, render relative. Anything with a time in it should be stored with an absolute reference, and any relative phrasing should be produced at assembly time from the current clock rather than carried forward from when it was written.

Four ways to supply time, and what each costs

A timestamp per turn. Complete information and the largest addition to the input, on every turn, forever. It also asks the model to do date arithmetic to work out what any of it means, and reliability at that varies by model — which makes it the option that supplies the most data and produces the least dependable temporal behaviour.

A single elapsed-time annotation on the current turn. One short statement of how long since the previous message. Nearly free, and it fixes the invisible-absence failure, which is the one users actually notice. It tells you nothing about the shape of the history: an annotation saying three weeks does not distinguish a user who was here daily for months from one who has sent four messages ever.

Session boundaries in the history. Mark where sessions begin and end with their gaps, rather than timestamping every turn. Middle position, and the useful one for most products: coarse, small, and it makes the structure of the relationship legible — how often, in what bursts, with what pauses.

Timestamps on stored facts, resolved at assembly. Facts need absolute dates because facts outlive their context, and the resolution step is where staleness gets caught. A fact stored with a date can be presented as current or as historical depending on when it is being used, and a fact stored without one is a claim with no expiry. The cost is assembly logic and a schema field, and this is the one worth paying for unconditionally — it also gives you a way to tell a superseded value from a current one.

Time changes what a fact means

Some stored facts have a natural lifetime and the store usually does not know it. A stated job is durable. A stated illness is not. “Working on a deadline this week” is true for a week and misleading after it, and a character that raises it two months later is not remembering, it is misreading its own notes.

You cannot infer these lifetimes reliably, and guessing them wrong is worse than not having them, because a fact silently expired is a fact deleted without a record. The defensible version is a coarse category chosen at write time — durable, situational, or dated-event — with situational facts becoming candidates for demotion rather than deletion after some interval. What it costs is another schema decision at every write and a periodic pass over the store. What it buys is a character that stops bringing up last spring’s temporary circumstance.

The turn

THE TURN — time in state

  · Supply nothing
                    → free, and a three-week absence is
                      indistinguishable from three seconds.

  · Timestamp every turn
                    → complete, largest per-turn addition, and
                      relies on date arithmetic.
                      VARIES BY MODEL.

  · Elapsed time on the current turn
                    → nearly free, fixes the failure users
                      actually see, says nothing about the
                      shape of the history.

  · Session boundaries with gaps
                    → makes the relationship's rhythm legible
                      for a small, bounded addition.

  · Timestamps on stored facts
                    → PAID EVERY TURN in schema and assembly
                      work, and the only thing that stops a
                      dated fact being presented as current.

  · Relative phrases already in history
                    → rot in place. No annotation fixes text
                      that was written when it was true.

Detection

Probe with synthetic gaps. Run the same conversation with an hour, a week and a year inserted before the final turn, and compare the responses. If they are identical, elapsed time is not reaching the model regardless of what you think you are supplying.

Audit summaries for relative expressions. Counting occurrences of relative time words in carried state is a trivial check and a reliable one: every occurrence is a claim that will become false, and the count tells you how much of your continuity state has a decay date. The fix is at summarisation time — resolve dates when writing rather than preserving the original phrasing — and the count is how you verify it.

Log the gap distribution for your traffic. Products differ enormously here, and the right amount of temporal state depends on whether your conversations are continuous sessions or a series of returns weeks apart. If most sessions resume after long gaps, the elapsed-time annotation is the highest-value small change available; if conversations are single long sittings, it barely matters.

Watch for stale-fact complaints specifically. They look like ordinary memory failures in a support queue and they have the opposite cause: not a fact lost, but a fact kept past its meaning.

What this costs and what it doesn’t fix

Temporal state is unusually cheap per unit of benefit — an elapsed-time line and session markers are a small addition against a failure users notice immediately — but they are still an addition to every input from now on, and per-turn timestamps are not small at all. Fact timestamps cost schema and an assembly step rather than input size, which is the better shape of cost.

What none of it fixes is reasoning about time. Supplying accurate absolute times does not make temporal inference reliable, and a character with perfect timestamps will still occasionally get a duration wrong. The practical position is to do the arithmetic yourself at assembly time and hand over a resolved phrase, which turns a reasoning problem into a formatting one — and, like every other piece of continuity here, is state you compute rather than state the model has.