Skip to content

The changes tool rounds the record clock to a day #351

Description

@WaylandYang

Found by the temporal benchmark's --chat probe (#306) on a build with #350. The agent now has as_of, and it uses it — and still cannot get behind a correction, because the one tool that tells it when the correction landed rounds that moment to a day.

The trace

Asked "before the payroll correction arrived, what salary did we have on record for Lin Zhao?", the model does the right thing in the right order:

entity  · Lin Zhao        · 1 matches
changes · 2020-01-01 → now · 1 changes            ← "2026-09-05 corrected: Lin Zhao salary 32000 CNY …"
facts   · Lin Zhao        · 0 facts at 2023-06-01, as recorded by 2026-09-04
facts   · Lin Zhao        · 0 facts as recorded by 2026-09-04

It reads the correction's date, subtracts a day, and asks for the base as of the day before — and the base did not exist the day before. The first ingest and the correction are forty seconds apart. Same shape on "before the handover memo arrived, who did we think led Aurora in August 2024": the memo and the charter it corrected were recorded on the same day, and "the day before" is empty.

This is not a benchmark artifact. A memo that corrects the morning's ingest arrives in the afternoon; the question "what did we hold before it" is a same-day question whenever the base is being fed continuously, which is what sources are for.

Where it is

change_line in crates/utopia-server/src/api/tools.rs:

format!("{} {}: {} {} {}{}{}", c.at.format("%Y-%m-%d"), c.kind,)

c.at is recorded_at, a timestamp. The line prints the date. parse_when (#350) already accepts RFC3339 on as_of for exactly this reason — "a record-axis moment is usually a timestamp, which a date cannot hold" — so the reader can take the precision; the writer throws it away one tool earlier.

What to build

  • change_line prints recorded_at as an RFC3339 instant (2026-09-05T02:43:39Z), not a date. The world-axis interval after it stays at day precision — that is how the world was recorded, and mixing the two precisions on one line is itself a hint about which is which.
  • The changes description and the system prompt say the one sentence the model needs: to see the base as it stood before a change, pass that change's instant (or a second earlier) as as_of. The model currently invents "the day before" because that is all a date allows.
  • changes takes since / until at day precision and that is fine — it windows, it does not pin.

One test: a change line carries the time of day, and parse_when reads it back to the same instant.

Not in scope

Time zones in the display. The instant is UTC and says so with the Z; how the UI renders it is the UI's business (#307).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions