BlogProduct

PRODUCT

What did we believe on the day we lost the deal?

Your CRM can tell you the champion left. It cannot tell you whether you knew that in March, which is the only question a post-mortem is actually asking.

SAGARISProduct7 min
What did we believe on the day we lost the deal?

The deal closed lost in July. Someone schedules a post-mortem, and the first thing anybody does is open the account and scroll.

Every field shows you its current value and the date it last changed. Champion: departed. Budget status: reallocated. Competitor: incumbent renewed. Each one carries a last-updated date in June or July, because that is when someone finally typed it in.

None of that answers the question the meeting exists to ask. The question is not whether those facts were true. The question is whether the team was working from them in March, when the deal was still winnable and the decisions that lost it were being made.

Your CRM cannot answer that, and the reason is structural rather than a data hygiene problem you could fix with better rep discipline.

One field, two different dates

Take the champion leaving, as an illustrative example rather than a customer story.

She left in March. Her replacement was announced internally in April. Your account executive found out in May, from an offhand comment on a call. The CRM field was updated in May.

There are two dates here and they mean completely different things. March is when the world changed. May is when you found out. The gap between them, roughly nine weeks, is the entire subject of the post-mortem, because everything the team did in that window was reasonable given what they knew and wrong given what was true.

A single last-updated timestamp collapses both into one number and the number it gives you is May. So the record now asserts, in the only way it can, that the champion left in May. It is wrong about the world, and it has also destroyed the evidence that you were working blind, which is the finding that would have changed how you run the next deal.

This is why post-mortems on CRM data reliably produce the wrong conclusion. They evaluate the team's March decisions against July's field values, because July's field values are the only ones that survived. Every decision looks negligent in hindsight when hindsight is the only tense your database has.

The two questions, kept apart

The clean way to say it is that there are two clocks.

Valid time answers when the fact was true in the world. The champion was in post until March.

Transaction time answers when the system came to believe it. We recorded the departure in May.

Those are not our terms, and they are not new ones. A 1985 SIGMOD paper set out the taxonomy and SQL:2011 standardised both axes: "valid time, the time period during which a row is regarded as correctly reflecting reality by the user of the database" and "transaction time, the time period during which a row is committed to or recorded in the database", carried by application-time periods and system-versioned tables respectively (Kulkarni and Michels, both editors of the standard, SIGMOD Record 41(3), 2012). The distinction is forty-one years old, has been in an ISO standard for fifteen, and your CRM still has one column. Nor are we alone now: TGMS, published in July 2026, is a bi-temporal property graph separating the same two axes (https://arxiv.org/abs/2607.10265).

They are independent. A fact can be old and newly learned, which is the case above. A fact can be new and immediately recorded. A fact can be recorded, then corrected, so that what you believed in June about January differs from what you believe now about January. Collapse the two into one timestamp and you can express none of it.

In our claim store both exist as separate columns. A start and an end bound the interval in which the fact held. A third timestamp, plus an append-only history chain per row, records when the system came to hold it. There are two read methods rather than one: a transaction-time read that filters on when the claim was recorded, and a valid-time read that returns a claim only when the queried instant falls inside its half-open validity interval.

The receipt worth quoting is a single test in the shared contract suite. It sets up one fixture whose fact was true from 2020 and was not recorded until 2026, then asserts that a transaction-time read at 2025-01-01 returns nothing and a valid-time read at 2021-01-01 returns exactly one row. One fact, two axes, opposite answers, on the same row, in a suite shared across every storage adapter. If the two clocks were secretly the same clock, that test could not pass.

Two caveats, which belong in the middle of this article and not at the end

We can travel each axis. We cannot currently travel both at once.

The transaction-time read takes one instant. The valid-time read takes one instant. There is no method on the store interface that accepts both, and the valid-time read is deliberately pinned to current knowledge so the axis stays independent. That means the full bitemporal cell, "what did we believe in March about what was true in June", is not reachable through the seam today. The two axes exist and the query that crosses them does not.

The second caveat is sharper and we would rather publish it than have someone find it. On the shipped Postgres adapter, transaction-time travel reconstructs status and confidence from the history chain, but takes the end of the validity interval from the current row. So a transaction-time read at March, on a claim superseded in June, hands you a status of asserted alongside an interval that ends in June, which is an interval end the system did not know in March. Our Neo4j adapter snapshots the interval end per version and gets this right. Neo4j is a prototype used for evaluation only, and Postgres is the one in production, so the weaker of the two implementations is the shipped one. Nothing binds them either: the shared contract suite contains no assertion about the interval end that a transaction-time read returns, which is why the divergence went unnoticed and could drift further.

Both of those are on the list to fix. Neither is fixed today.

This is also why the copy on our own platform page claims only what the code does. It says contradictions are superseded rather than overwritten and that you can read what the system believed as of any day. That is the transaction axis, which the transaction-time read genuinely delivers, and it stops there.

Why this is worth building rather than tolerating

Because the reconstruction problem is not confined to post-mortems, and practitioners describe it constantly without naming it.

A RevOps post from 4 August 2026 opens with the observation that half the job is knowing which numbers are fake, and describes reconciling a 6.1M CRM figure against the 6.8M the VP of Sales had already given the CEO, then spending two hours finding a 400k deal marked closed-won that was a verbal (https://old.reddit.com/r/revops/comments/1vf8mni/, 26 upvotes, 33 comments, relayed via a research stream rather than personally fetched; small sub, small numbers, treat it as a signal not a groundswell). That is a valid-time problem wearing a reporting costume. The deal was marked closed-won on a date. It was not closed-won on that date. Nothing in the schema can hold both facts.

The same gap shows up wherever a system produces a score that a human is expected to act on. When HackerRank open sourced its applicant tracking system, one author fed it an identical resume and got 90, then 74, then 88, with a 65 percent screening failure rate across runs (https://danunparsed.com/p/hackerrank-open-source-ats, 29 June 2026; 1,032 points on Hacker News). If a resume score is that unstable, so is a lead score. And reps notice: a post on r/sales from 8 August 2026 has a rep reporting that being told to work only the top AI-ranked accounts means "they are losing business that AI doesn't tell us to go after (which we are usually successful with)" (4 upvotes, 40 comments, relayed).

A score that cannot say what it was derived from, and when that evidence was believed, is a score the field routes around. That is a product failure long before it is a trust failure.

Macroeconomists solved this for their own data decades ago and gave it a name. A forecast cannot honestly be tested against today's revised figures, because nobody at the time could see them, so the Federal Reserve Bank of Philadelphia runs a real-time data set whose successive snapshots are called vintages; Croushore and Stark described it in the Journal of Econometrics in November 2001. The post-mortem question in this article is a vintage query. Borrowing the established name costs nothing and beats coining one.

What is on and what is off

The extraction that would fill the store from your email and call transcripts is not generally available yet. The dossier, chat and next-best-action claim reads are behind flags that the deploy config does not set.

So the machinery for answering "what did we believe in March" exists at the storage layer, with each axis exercised by a shared contract test, the query that crosses them unreachable, and the divergence between adapters unbound by any assertion. And the pipeline that would give it March's raw material is switched off. We would rather write those sentences than the one that omits their second halves.

SAGARIS

Written by the SAGARIS team.

See the engine run on your pipeline.

Thirty minutes, your own data, no setup.

Book a demo

Get the next one in your inbox.

SAGARIS opens fully in October 2026. Join the waitlist and we will be in touch before launch.

We use these details to contact you about SAGARIS. See our privacy policy.

Book a demo