feat(sec): A3 slice 2a — companyfacts -> snapshot parser

Pure parser (no I/O/DB) turning one issuer's companyfacts + submissions filing
metadata into per-accession snapshot rows for the filing's primary period.

- Period identity from end == reportDate, never fy/fp (fy/fp is the filing's
  context; comparatives repeat it).
- Duration facts stored as cumulative YTD: pick the fact whose span matches the
  fiscal-period-to-date length (Q1~3mo..FY~12mo) within tolerance; no YTD-length
  fact -> null (never a discrete masquerading as YTD).
- Balance-sheet instants at end == reportDate; shares_outstanding is the dei
  cover-page fact whose own end (cover date) is stored in shares_outstanding_date.
- Cash and debt composites are aggregate-first and mutually exclusive (each
  source tag counted at most once).
- Carries filing_date through submissions rows (snapshot.filed_date).

Verified on REAL Apple companyfacts: 44 snapshots, 0 skipped, YTD revenue
124.3B->219.7B->313.7B->416.2B across FY2025 (Q4 derives at read time), every
shares_date is the cover date != period_end. Tests: 6 fixture + 1 skip-guarded
live-invariants (monotonic YTD, cover-date shares).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 16:11:22 +02:00
co-authored by Claude Opus 4.8
parent 5939be7b7f
commit 7413de9301
4 changed files with 471 additions and 0 deletions
+2
View File
@@ -31,6 +31,7 @@ SUBMISSIONS_BASE = {
"accessionNumber": ["0000320193-26-000013", "0000320193-26-000006", "0000320193-26-000099"],
"form": ["10-Q", "10-K", "8-K"],
"reportDate": ["2026-03-28", "2025-09-27", "2026-04-01"],
"filingDate": ["2026-05-01", "2026-01-30", "2026-04-02"],
"acceptanceDateTime": ["2026-05-01T10:01:00.000Z", "2025-10-31T10:01:26.000Z", "2026-04-02T09:00:00.000Z"],
"isXBRL": [1, 1, 0],
},
@@ -42,6 +43,7 @@ SUBMISSIONS_SHARD = {
"accessionNumber": ["0000320193-94-000002"],
"form": ["10-Q"],
"reportDate": ["1993-12-31"],
"filingDate": ["1994-01-26"],
"acceptanceDateTime": ["1994-01-26T05:00:00.000Z"],
"isXBRL": [0],
}