The governed definitions this build depends on. Read them first if a term is unfamiliar.
- PrimaryFiling RevisionA filing revision is a later official filing or amendment that changes, corrects, or supplements information associated with an earlier filing.
- PrimaryFiling VersionA filing version is one immutable, source-identified representation in the lifecycle of a regulatory filing.
- ImportantAs-Reported DataAs-reported data preserves a value as disclosed in a specific filing version without silently replacing it with a later revision.
- ImportantAvailability TimeAvailability time is the earliest evidenced instant at which information was usable by a specified system or decision process.
- ImportantData LineageData lineage records where data came from, how it was transformed, and which entities, activities, and agents affected it.
- ImportantEffective TimeEffective time is the instant or interval boundary from which a rule, status, or fact applies in its modeled business domain.
- ImportantFiling AmendmentA filing amendment is an official submission that modifies or supplements a previously filed document.
- ImportantPoint-in-Time DatasetA point-in-time dataset can reconstruct what information was valid and available to a specified user or system at a historical decision time.
- ImportantPublication TimePublication time is when a source officially released or disseminated information.
- ImportantRestated DataRestated data is financial information revised through a later filing or authoritative disclosure for a previously reported period.
- ImportantRevision LineageAn ordered chain connecting each correction to the exact earlier record it supersedes.
A point-in-time research system should answer a simple audit question: which filing version had we actually acquired at this historical cutoff? Filing-revision versioning makes that answer reproducible by retaining every accession and separating the reporting period, regulator acceptance, and local ingestion times.
The mistake this prevents
Suppose a company files an annual report and later amends it. If a database overwrites the original values, a backtest run “as of” the earlier date sees facts that arrived months later. Filtering only on the regulator acceptance timestamp is also insufficient when the research system did not ingest the document at that instant.
The SEC says filings often appear on sec.gov one to three minutes after the EDGAR acceptance timestamp, that the lag may increase, and that no timestamp identifies when filing content first became available on the website (SEC webmaster FAQ). That is why a local ingestedAt timestamp is evidence, while an assumed dissemination time is not.
Notice the two distinct boundaries: acceptance orders regulator submissions; ingestion determines what the local system could use.
Three times, three meanings
| Time | What it means | What it does not prove |
|---|---|---|
reportPeriod | Economic period described by the filing | When the information became known |
acceptedAt | EDGAR accepted the submission | Exact public or local availability |
ingestedAt | The local system acquired this version | That parsing or validation was complete unless separately recorded |
For a production system, add parsedAt, validatedAt, provider publication time, source hash, and field-level lineage when those boundaries matter. Do not compress them into one generic date.
The causal selection rule
For entity , period , form family , and cutoff , first build the eligible set:
Then choose:
ingestedAt controls eligibility. The remaining tuple orders versions that were already eligible and resolves ties deterministically. If the eligible set is empty, the correct output is an error—not the first later filing.
The algorithm selects a source version. A fact extractor must still check whether an amendment changes the requested filing item.
Historical case: one fiscal year, two valid versions
Esterline Technologies' fiscal-2017 original Form 10-K is accession 0001564590-17-024189, accepted on 2017-11-21 at 16:32:41 UTC (original filing index). Form 10-K/A Amendment No. 1 is accession 0001564590-18-007244, accepted on 2018-03-30 at 14:43:54 UTC (amendment index).
The amendment states that it restates previously issued financial statements and lists the affected items. Its restatement summary gives fiscal-2017 basic earnings per share (EPS) of 3.75 as restated, while net earnings attributable to Esterline changed from 111.554 million (Form 10-K/A).
Those are sourced event facts. The package makes a separate, explicit teaching assumption:
- original locally ingested at 2017-11-21 16:40 UTC;
- amendment locally ingested at 2018-03-30 15:00 UTC.
The ingestion times are synthetic. They are not claims about SEC dissemination or any vendor.
Three cutoffs expose the value
| Research cutoff | Selected accession | Basic EPS | Explanation |
|---|---|---|---|
| 2018-02-01 00:00 UTC | Original 10-K | $3.94 | The amendment did not yet exist |
| 2018-03-30 14:50 UTC | Original 10-K | $3.94 | Amendment accepted, but not locally ingested under the assumption |
| 2018-03-30 15:05 UTC | 10-K/A | $3.75 | Amendment now locally available and later accepted |
The derived difference is:
This is a revision of the filing's representation of the same fiscal period. It is not a market return, a new fiscal-quarter observation, proof of causality, or an investment signal.
Implementation walkthrough
Both reference implementations follow the same visible stages:
- require a stable entity, report period, form family, and timezone-aware cutoff;
- validate every accession, amendment number, scope, numeric fact, and timestamp;
- reject direct-SEC ingestion earlier than acceptance;
- filter by local ingestion;
- order eligible records by acceptance time, amendment number, and accession;
- return a copy of the selected facts plus eligible/excluded accessions.
The Python and TypeScript code consumes the same shared_fixture.json. The selector does not mutate its input and compares instants rather than timestamp strings, so 15:05Z and 11:05-04:00 resolve identically.
Explore the failure boundary
Open the guided filing-version playground. Choose the cutoff after SEC acceptance but before the synthetic local ingestion. Under the correct policy, the original remains selected. Switch to the deliberately unsafe “acceptance only” comparison and the amendment appears too early.
That comparison is the core lesson: a regulator event and a local knowledge event answer different questions.
Failure modes
- Latest-only storage: destroys the version that was valid at an earlier cutoff.
- Acceptance-only eligibility: can precede local availability.
- Filing-date eligibility: loses intraday ordering and can differ from acceptance behavior.
- Whole-filing overwrite: ignores that an amendment may change only specified items.
- Naive timestamps: make offsets ambiguous and comparisons unreliable.
- Invented provider time: turns an assumption into false evidence.
- Backfill without lineage: makes a corrected value look as if it had always existed.
Retain every accession, local acquisition evidence, source hash, extraction version, and amendment scope. Reject uncertain history rather than manufacturing precision.
What this case does—and does not—show
It shows that a real filing revision can change a historical accounting value and that a bitemporal selector can reproduce which version a local system could use under explicit availability assumptions.
It does not show when a commercial provider revised its field, how a security price reacted, why investors traded, or whether the restatement predicts anything. Those would be separate empirical claims requiring provider evidence, event-study controls, and licensing review.
Summary
Filing-revision versioning preserves both economic truth and knowledge-time truth:
- the report period says what the filing describes;
- the accession and acceptance timestamp identify the regulator version;
- the local ingestion timestamp establishes the research system's evidence boundary;
- amendment scope and field lineage explain what changed.
With those pieces, a historical query can be rerun and defended without rewriting the past.
Asset map
| Asset | Placement | Video scene | Source | Static fallback | Status |
|---|---|---|---|---|---|
| Two-clock overview | Problem | 2 | visuals/static/article-hero.svg | Same SVG | Ready |
| Causal flow | Formula | 3 | visuals/mermaid/calculation-flow.md | Article steps | Ready |
| Three-cutoff case | Worked example | 5 | visuals/static/worked-example.svg | Table above | Ready |
| Failure guard | Failure modes | 7 | visuals/static/failure-guard.svg | Failure list | Ready |
| Guided lab | Exploration | 4–7 | visuals/animated/playground.html | Three-cutoff SVG | Ready |
Primary source roles and limitations are recorded in ../REFERENCES.md.
Rendered from the canonical Mermaid sources linked by this article.
Causal filing-version query
This flow separates local availability from version ordering.
Takeaway: ingestedAt controls local knowability; acceptedAt orders the versions that were already knowable.
Filing-version lifecycle
This state model prevents an accepted amendment from entering a local point-in-time query before acquisition.
Takeaway: superseded does not mean deleted; every accession remains available for historical reconstruction.
References6 primary sources and evidence notesExpand the source trail, evidence role, and limitations behind the engineering choices.
Expand the source trail, evidence role, and limitations behind the engineering choices.
Accessed 2026-07-22. The package stores a small factual case record, not raw filing documents or provider datasets.
R1 — Esterline fiscal-2017 original Form 10-K filing index
- Organization: U.S. Securities and Exchange Commission
- Source type: Primary regulator filing metadata
- Filing date: 2017-11-21
- URL: https://www.sec.gov/Archives/edgar/data/33619/000156459017024189/0001564590-17-024189-index.html
- Jurisdiction: United States
- Supports: CIK, form, report period, accession number, filing date, and acceptance timestamp for the original filing
- Limitations: Acceptance metadata does not establish when a local research system ingested the document
R2 — Esterline fiscal-2017 Form 10-K/A filing index
- Organization: U.S. Securities and Exchange Commission
- Source type: Primary regulator filing metadata
- Filing date: 2018-03-30
- URL: https://www.sec.gov/Archives/edgar/data/33619/000156459018007244/0001564590-18-007244-index.html
- Jurisdiction: United States
- Supports: Form, report period, accession number, filing date, and acceptance timestamp for Amendment No. 1
- Limitations: Acceptance metadata does not establish website or provider availability time
R3 — Esterline fiscal-2017 Form 10-K/A
- Organization: Esterline Technologies Corporation, filed with the SEC
- Source type: Primary issuer filing
- Filing date: 2018-03-30
- URL: https://www.sec.gov/Archives/edgar/data/33619/000156459018007244/esl-10ka_20170929.htm
- Jurisdiction: United States
- Supports: Amendment purpose and scope, categories of errors, and as-reported versus restated fiscal-2017 net earnings and EPS
- Limitations: The filing supports accounting disclosure facts, not market causality or investment significance
R4 — SEC Webmaster Frequently Asked Questions
- Organization: U.S. Securities and Exchange Commission
- Source type: Official regulator technical guidance
- Version: Current page accessed 2026-07-22
- URL: https://www.sec.gov/about/webmaster-frequently-asked-questions
- Jurisdiction: United States
- Supports: Acceptance-to-website lag is variable; no first-availability timestamp exists for filing content on
sec.gov; accession and EDGAR timestamp definitions - Limitations: General operational guidance, not a historical availability timestamp for the Esterline filings
R5 — Accessing EDGAR Data
- Organization: U.S. Securities and Exchange Commission
- Source type: Official regulator developer guidance
- Version: Current page accessed 2026-07-22
- URL: https://www.sec.gov/search-filings/edgar-search-assistance/accessing-edgar-data
- Jurisdiction: United States
- Supports: EDGAR submissions data, filing archives, access practices, and accession-based retrieval
- Limitations: Does not define a research firm's local ingestion or validation boundary
R6 — EDGAR glossary
- Organization: U.S. Securities and Exchange Commission
- Source type: Official regulator terminology
- Version: Current page accessed 2026-07-22
- URL: https://www.sec.gov/submit-filings/filer-support-resources/edgar-glossary
- Jurisdiction: United States
- Supports: Meaning of “accepted,” accession number, and EDGAR dissemination terminology
- Limitations: A generated accession number alone does not prove acceptance or local availability
Full dependency-light reference implementations in both supported languages.
/** Point-in-time filing-version selection for D02-F04-A04. */
const textValue = (value, name) => {
if (typeof value !== "string" || !value.trim()) throw new TypeError(`${name} must be a non-empty string`);
return value;
};
const instant = (value, name) => {
const text = textValue(value, name);
if (!/(?:Z|[+-]\d{2}:\d{2})$/.test(text)) throw new RangeError(`${name} must include a UTC offset`);
const milliseconds = Date.parse(text);
if (!Number.isFinite(milliseconds)) throw new RangeError(`${name} must be a valid ISO 8601 instant`);
return milliseconds;
};
const nonnegativeInteger = (value, name) => {
if (!Number.isInteger(value) || value < 0) throw new TypeError(`${name} must be a non-negative integer`);
return value;
};
const factsValue = (value, name) => {
if (!value || typeof value !== "object" || Array.isArray(value) || !Object.keys(value).length) {
throw new TypeError(`${name} must be a non-empty object`);
}
for (const [key, number] of Object.entries(value)) {
textValue(key, `${name} key`);
if (typeof number !== "number" || !Number.isFinite(number)) throw new TypeError(`${name}.${key} must be finite`);
}
return structuredClone(value);
};
const validateRecord = (record, index, entityId, reportPeriod, formFamily) => {
if (!record || typeof record !== "object" || Array.isArray(record)) throw new TypeError(`records[${index}] must be an object`);
const prefix = `records[${index}]`;
const recordEntity = textValue(record.entityId, `${prefix}.entityId`);
const recordPeriod = textValue(record.reportPeriod, `${prefix}.reportPeriod`);
const form = textValue(record.form, `${prefix}.form`);
const accessionNo = textValue(record.accessionNo, `${prefix}.accessionNo`);
const amendmentNumber = nonnegativeInteger(record.amendmentNumber, `${prefix}.amendmentNumber`);
const acceptedInstant = instant(record.acceptedAt, `${prefix}.acceptedAt`);
const ingestedInstant = instant(record.ingestedAt, `${prefix}.ingestedAt`);
const facts = factsValue(record.facts, `${prefix}.facts`);
if (recordEntity !== entityId || recordPeriod !== reportPeriod) throw new RangeError(`${prefix} does not match the requested entity and report period`);
if (![formFamily, `${formFamily}/A`].includes(form)) throw new RangeError(`${prefix}.form is outside the requested form family`);
if (amendmentNumber === 0 && form !== formFamily) throw new RangeError(`${prefix} marks an amendment as an original filing`);
if (amendmentNumber > 0 && form !== `${formFamily}/A`) throw new RangeError(`${prefix} amendmentNumber requires an amended form`);
if (ingestedInstant < acceptedInstant) throw new RangeError(`${prefix}.ingestedAt cannot precede acceptedAt for direct SEC ingestion`);
if (!Array.isArray(record.amendmentScope) || !record.amendmentScope.length || record.amendmentScope.some(item => typeof item !== "string" || !item)) {
throw new TypeError(`${prefix}.amendmentScope must be a non-empty list of strings`);
}
return { ...record, accessionNo, amendmentNumber, acceptedInstant, ingestedInstant, facts };
};
export function calculate(data) {
if (!data || typeof data !== "object" || Array.isArray(data)) throw new TypeError("data must be an object");
const entityId = textValue(data.entityId, "entityId");
const reportPeriod = textValue(data.reportPeriod, "reportPeriod");
const formFamily = textValue(data.formFamily, "formFamily");
const asOf = textValue(data.asOf, "asOf");
const asOfInstant = instant(asOf, "asOf");
if (!Array.isArray(data.records) || !data.records.length) throw new TypeError("records must be a non-empty list");
const checked = data.records.map((record, index) => validateRecord(record, index, entityId, reportPeriod, formFamily));
const accessions = checked.map(record => record.accessionNo);
if (new Set(accessions).size !== accessions.length) throw new RangeError("accessionNo values must be unique");
const eligible = checked.filter(record => record.ingestedInstant <= asOfInstant);
if (!eligible.length) throw new RangeError("no filing version was locally available by asOf");
const selected = eligible.toSorted((left, right) =>
left.acceptedInstant - right.acceptedInstant ||
left.amendmentNumber - right.amendmentNumber ||
left.accessionNo.localeCompare(right.accessionNo)
).at(-1);
return {
entityId,
reportPeriod,
asOf,
selectionBasis: "latest accepted filing among locally ingested versions",
accessionNo: selected.accessionNo,
form: selected.form,
amendmentNumber: selected.amendmentNumber,
acceptedAt: selected.acceptedAt,
ingestedAt: selected.ingestedAt,
amendmentScope: [...selected.amendmentScope],
facts: structuredClone(selected.facts),
eligibleAccessions: eligible.map(record => record.accessionNo).sort(),
excludedNotYetIngested: checked.filter(record => record.ingestedInstant > asOfInstant).map(record => record.accessionNo).sort(),
};
}
The embedded lab now expands to its full document height, keeping the article as the only scroll surface.