Tables that only keep current state
One version per change, with validity start and end
The state of each entity on any date
MRR, commissions, portfolio, funnel and AI agent
What it solves
- A past month's number does not change when a record changes today.
- Each fact is joined to the owner, plan and status that were valid on its date.
- Data the source deletes after a few days is kept.
Business questions it answers
Ask your agent these questions once the case is live.
What you need
- The sources connected to Nekt, with history (SCD Type 2) turned on for state tables
- The stable business key of each entity
- The list of fields whose changes matter to the business
What you get
- A versions table per entity, with validity start and end
- A view with only the current version for day-to-day use
- End-of-day or month-end snapshots for metrics
- An AI agent that answers how something looked on any date
Where to activate
MRR movements, active contracts and listed properties computed from the month-end snapshot.
Each sale joined to the owner, team and rule valid on the win date.
Answers how something looked on any date and says since when history exists.
Turning history on for a source table is configuration. The work is in snapshots of derived tables, which need a notebook with merge, and in rebuilding the period before history from events or invoices. The detailed view has the business rules, the pitfalls and the acceptance test. Or send everything straight to your agent with the Nekt MCP.
Most sources only return the current picture. When a customer changes plan, owner or status, the old value is overwritten and every report about the past starts using the new value. In one real base, changing a company's segment, account executive or monthly value rewrote all of its past sales. Other sources keep only 30 or 45 days, and every full sync shrinks the past.
How it is usually done, and the rule
Each row is a mistake that already happened in practice.
In Nekt, enable SCD Type 2 on the source table. Each change becomes a new row with _available_from (validity start), _available_until (end, null on the current version) and _deleted. History is valid from the day it was turned on: each entity's first version is its state on that day, not at creation.
Each version may get a new surrogate code. In a versioned dimension from a brokerage, the codes changed with every version of the same account. Identify the entity by the stable business key (subscription id, account code, deal id) and use the surrogate code only to tie a fact to the version valid on that date.
The state on a date is the version where _available_from is less than or equal to the date and _available_until is null or greater than it. To join a fact to a dimension (the advisor on a deposit, the owner of a won deal, the plan on an invoice), use the fact's date, not today's version.
For day-to-day use, publish a view with only the current version (_available_until null and _deleted false) and keep the full timeline in a separate table. Querying the versions table without a filter counts each entity several times.
_available_from and _available_until are UTC instants. Convert to the business time zone (America/Sao_Paulo) before cutting by day or month, otherwise changes made at night fall on the next day and the month-end snapshot picks the wrong version.
SCD writes one version per sync that found a change, so the same entity can have several versions on the same day. In the daily snapshot, use each entity's last version of each day. In the month-end snapshot, use the version valid at the last instant of the month, with the same cut-off for every entity.
A new version may only have changed the billing period, the latest invoice or another technical field. To count changes of status, owner or plan, compare the field with the previous version. Control columns such as _nekt_sync_at never enter the comparison, and _available_from says when the sync saw the change, not when it happened at the source.
Some APIs keep only a few days: Stripe events for about 30, email analytics for about 45, database collections with a TTL. A full sync rewrites the table with the current window and deletes the rest. Accumulate into a table of your own by merge, keyed by entity and day, that only grows, and never swap that merge for an overwrite.
A SQL transformation rebuilds the whole table on every run and keeps no past. To snapshot a calculated number (portfolio, balance, daily MRR), use a notebook that reads its own output, keeps previous days and replaces only the current day. That way, running twice on the same day does not duplicate the snapshot.
A closed month's result is read from the frozen snapshot, not recalculated with today's rule or records. Later corrections go in as an adjustment in the month they were found. In one real base, a qualification recalculated on every run made a month's number shrink after it had been presented.
Which kind of table answers the question
Classify the source before answering anything about time.
Definitions
Pitfalls that already happened
A daily snapshot was overwritten by mistake and almost three weeks of history had to be rebuilt.
Add a guard before writing: refuse empty output and abort if any day already written disappears.
A full sync of an analytics source rewrote the table with the current window and deleted more than half of the rows at once.
Accumulate into a table of your own by merge and never use the raw table as an archive.
A versioned dimension from a partner had accounts with no version flagged as current, one of them with dozens of versions.
Test for one current version per entity every day and use the date interval, not the source's current flag.
Commissions joined deals won in past months to the current owner, and people who changed portfolios took credit for sales they did not make.
Join on the owner valid on the win date.
Each entity's first version was the one from the day history was turned on. Read as if it held since creation, it assigned today's segment and plan to old sales.
Record when history starts and rebuild the earlier period from events, invoices or stage history.
A backfill wrote contract attributes with the load date and contaminated the expansion calculation for earlier months.
Flag backfill rows and never use the load date as the business date.
Acceptance test
The case is done when every item passes.
- Each non-deleted entity has exactly one version with a null _available_until.
- Each entity's intervals are continuous: one version's end is the next one's start, with no gaps or overlaps.
- The current view has the same number of entities and the same values as the source's current record.
- Running the pipeline again does not change the snapshot of any closed month.
- Running the daily snapshot twice on the same day does not create a new row.
Agent package
Paste into Claude, ChatGPT or any client with the Nekt MCP connected.
History and dates - Before answering about time, classify the table: current record, versions (SCD Type 2), daily snapshot, monthly snapshot, event history or last known observation. Do not call a current record history. - SCD Type 2 tables have _available_from, _available_until and _deleted. Current version: _available_until null and _deleted false. - State on a date: _available_from <= date and (_available_until null or > date). Convert from UTC to America/Sao_Paulo before cutting by day or month. - Join each fact to the version valid on the fact's date (owner, plan, status, segment), never to today's. - The entity is the business key. Surrogate codes change with every version. - A new version is not a status change: compare the field with the previous version. - _nekt_sync_at and _available_from are not business dates. Use the event date. - History starts at the table's smallest _available_from. Before that, say there is no history or use the event source indicated. - Closed months come from the frozen snapshot. Do not recalculate them with current records. Client exceptions: - <client>: history for <table> turned on <date>; before that, use <event table>. - <client>: month-end snapshot cut off at <time> on the last business day.
Build the "History with SCD Type 2" case in my Nekt workspace following the rules at https://academy.nekt.com/en/casos/scd-type-2.md. 1) Find the source tables and confirm the columns the rules use. 2) Create a transformation at the stated grain applying every rule. 3) Run the acceptance test and show me the result of each item. 4) Create the case's context document in the workspace, leaving my clients' exceptions open for me to fill in.
Variations
When the source keeps history (HubSpot propertieswithhistory, Bitrix24 stage_history, an event log), use it for the period before SCD.
For calculated numbers (bank balance, inventory, portfolio), a daily snapshot by merge, with a defined retention.
For CRMs without stage history, a webhook records each change as an event, with the before and after values.