A replay can look plausible while using information that had not reached the system when the decision was made.

Consider one fictional event, E-01. It happened at 12:00, became available at 12:03, and received a correction at 12:05. A replay of the 12:02 decision should produce an empty result. Filtering only by observedAt would include information that was still unavailable.

Keep availability separate from event time

For this exercise, observedAt records when the event happened. availableAt records when that particular version became usable by the decision process. The cutoff is inclusive: a version available exactly at the decision time is eligible.

Decision time Eligible version of E-01 Amount
12:02 None —
12:03 Revision 1 20 demo units
12:04 Revision 1 20 demo units
12:05 Revision 2 18 demo units

Every date, tenant and amount below is synthetic. The corrected amount of 18 and the second tenant's amount of 900 are invented for this tutorial.

Retain each version as a separate record. First filter by tenant and availability; then select the highest eligible revision for each event. Selecting the latest revision before checking availability would let the correction erase the earlier view.

This example uses controlled inputs: valid UTC timestamps, numeric amounts, and unique integer revisions within each (tenant, eventId). Higher revision numbers supersede lower ones. Input order does not define which version wins.

Run the example

Save the following as snapshot-at.mjs and run node snapshot-at.mjs. It uses Node's built-in assertion module and needs no installed packages. The exact code below was executed with Node.js 24.13.0; all eight assertions passed.

import assert from 'node:assert/strict'; // Every row, date and amount in this example is fictional. const at = hhmm => `2026-01-01T${hhmm}:00Z`; const original = Object.freeze({ tenant: 'T-A', eventId: 'E-01', revision: 1, observedAt: at('12:00'), availableAt: at('12:03'), amount: 20, }); const correction = Object.freeze({ ...original, revision: 2, availableAt: at('12:05'), amount: 18, }); const otherTenant = Object.freeze({ ...original, tenant: 'T-B', amount: 900 }); const beforeCorrection = Object.freeze([original, otherTenant]); const history = Object.freeze([...beforeCorrection, correction]); function snapshotAt(rows, tenant, decisionAt) { const cutoff = Date.parse(decisionAt); if (!Number.isFinite(cutoff)) throw new TypeError('Invalid decision time'); const byEvent = new Map(); for (const row of rows) { if (row.tenant !== tenant) continue; if (!(Date.parse(row.availableAt) <= cutoff)) continue; const previous = byEvent.get(row.eventId); if (!previous || row.revision > previous.revision) { byEvent.set(row.eventId, row); } } return [...byEvent.values()] .sort((a, b) => a.eventId.localeCompare(b.eventId)) .map(({ eventId, revision, amount }) => ({ eventId, revision, amount })); } const v1 = [{ eventId: 'E-01', revision: 1, amount: 20 }]; const v2 = [{ eventId: 'E-01', revision: 2, amount: 18 }]; const earlySnapshot = snapshotAt(beforeCorrection, 'T-A', at('12:02')); assert.deepEqual(earlySnapshot, []); assert.deepEqual(snapshotAt(history, 'T-A', at('12:02')), earlySnapshot); assert.deepEqual(snapshotAt(history, 'T-A', at('12:03')), v1); assert.deepEqual(snapshotAt(history, 'T-A', at('12:04')), v1); assert.deepEqual(snapshotAt(history, 'T-A', at('12:05')), v2); assert.deepEqual(snapshotAt([...history].reverse(), 'T-A', at('12:05')), v2); assert.deepEqual(snapshotAt(history, 'T-B', at('12:05')), [ { eventId: 'E-01', revision: 1, amount: 900 }, ]); assert.throws(() => snapshotAt(history, 'T-A', 'invalid'), TypeError); for (const time of ['12:02', '12:03', '12:04', '12:05']) { console.log(`${time} T-A: ${JSON.stringify(snapshotAt(history, 'T-A', at(time)))}`); } console.log('8 assertions passed.'); 

Output:

12:02 T-A: [] 12:03 T-A: [{"eventId":"E-01","revision":1,"amount":20}] 12:04 T-A: [{"eventId":"E-01","revision":1,"amount":20}] 12:05 T-A: [{"eventId":"E-01","revision":2,"amount":18}] 8 assertions passed. 

The second assertion matters: the history now contains the correction, but replaying 12:02 still produces the same empty snapshot. The 12:04 assertion also keeps the original amount of 20. A later correction changes a later decision's view; it does not change what was available to an earlier one.

The reversed-input assertion checks that row order does not choose the winner. The T-B assertion uses the same event ID with a different amount, so accidentally combining the two tenants would fail this fixture.

Carry the rule into a review

For a real implementation, record the decision cutoff and retain the original versions needed to replay it. Overwriting revision 1 with revision 2 loses the evidence needed to reconstruct 12:04.

Write down these parts of the contract before comparing results:

  • Which stage makes a record usable, and therefore assigns availableAt? A raw upload may precede validation or approval.
  • Who assigns revision numbers, and how are duplicate or conflicting revisions rejected?
  • Where does the authorized tenant scope come from? The literal T-A in this fixture is only a test input.
  • Which original records and cutoff let a reviewer reproduce a past result?

Keep availableAt faithful to that usability boundary. Backdating a correction to the original event time would defeat the rule even if the filtering code stayed the same.

These assertions establish the outcomes for this small fixture. They do not measure the reliability or performance of a deployed pipeline.

Workbook context

This tutorial expands the fictional E-01 timeline in Nickwang Studio's Data Pipeline Review Workbook. The runnable script above was written separately for this article. The workbook supplies six review worksheets, eight prompts, English and Chinese PDFs, and an offline review editor; its worked example is a written contract-review exercise.

The free English PDF preview shows the review format. The complete workbook is available on Gumroad for readers who want to work through input boundaries, event timing, caching, fallback behavior, failure cases and release evidence.

Disclosure: This article was generated and prepared for publication by an AI agent for Nickwang Studio. The code and output above were executed as recorded.