Compare commits

...
3 Commits
Author SHA1 Message Date
dennisthiessenandClaude Opus 4.8 3df36a9bfb docs(dolt-plan): record A5 gate outcome and hand off remaining work
Deploy / lint (push) Successful in 9s
Deploy / test (push) Successful in 1m39s
Deploy / deploy (push) Successful in 38s
The parity gate has been exercised: nine-pass investigation, fixes, two prod
reparses, and an after-report at 504/511 candidate coverage with agreement
unchanged. What remains of workstream A is the activation itself (step c, the
post-approval fundamental_data refresh — not yet implemented) and A6
decommissioning, both now specified in a handoff section with the caveats the
next implementer must carry (KLAC splits, BRK-B, FITB, the 25% guard, CIK
overrides, reparse-after-parser-changes).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 12:32:53 +02:00
dennisthiessenandClaude Opus 4.8 98793925ef Merge fix/sec-fundamentals-parity-gaps: post-reparse verification docs
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 12:32:12 +02:00
dennisthiessenandClaude Opus 4.8 2e083d3bb9 docs(sec): post-reparse verification and cutover recommendation
Closes the parity investigation: prod reparse runs 6+7 reconciled against the
dry run, the collision check that caught the BEN regression (and its residue --
36 historical 53-week-drift rows, deliberately left), and the 2026-07-24 parity
report diffed against the 2026-07-23 baseline. Candidate coverage 482 -> 504 of
511 with the gap fully explained (PSKY/Q new registrants, FITB guard-tripped
with no revenue), agreement unchanged where both sides exist, and the remaining
deltas are documented definition differences. Includes the after-report and a
correction to the seventh pass (FITB loses its score, not just one input).
Recommends approving the A5 cutover with KLAC as the one carried caveat.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 12:29:13 +02:00
3 changed files with 20742 additions and 2 deletions
+44 -2
View File
@@ -426,8 +426,9 @@ workstream B — Alpaca remains the price source throughout.
API values across the tracked universe, report per-field deltas and resulting API values across the tracked universe, report per-field deltas and resulting
fundamental-score/ranking changes, require explicit approval. Definition fundamental-score/ranking changes, require explicit approval. Definition
changes (e.g. TTM vs provider convention) called out, not averaged away. changes (e.g. TTM vs provider convention) called out, not averaged away.
The read-only report job and Admin summary/download are implemented; production **Status 2026-07-24: the gate has been exercised and the evidence supports
observation and explicit cutover approval remain pending. approval** — see the handoff section below. What remains of A5 is the
activation itself: implementing step (c) and flipping it on.
- A6. Remove FMP/Finnhub/Alpha Vantage; keep monitoring + manual fallback. - A6. Remove FMP/Finnhub/Alpha Vantage; keep monitoring + manual fallback.
**Workstream B (independent, start when wanted):** **Workstream B (independent, start when wanted):**
@@ -479,6 +480,47 @@ workstream B — Alpaca remains the price source throughout.
- Score-parity diff reviewed and approved before `fundamental_data` cutover. - Score-parity diff reviewed and approved before `fundamental_data` cutover.
- Scheduled imports never block the API event loop. - Scheduled imports never block the API event loop.
## Handoff — remaining work after the A5 parity investigation (2026-07-24)
The 2026-07-23 parity report surfaced coverage gaps and wrong values; a nine-pass
investigation traced every one to parser/identity bugs (not source data), fixed them,
and reparsed production twice. Full evidence trail:
`reports/fundamentals-parity-20260723-findings.md` (root causes, decisions, validation)
plus the before/after reports (`fundamentals-parity-20260723T…` / `…20260724T….json`).
Post-fix: candidate scores 504 of 511 vs legacy's 507 (gap = PSKY/Q new registrants +
FITB, all explained); revenue-growth agreement 0.0038 median abs delta where both exist.
Dennis reviewed the evidence 2026-07-24 and directed proceeding to cutover.
**Task 1 — A5 activation (implement step (c) above, ~line 207).** The post-activation
local refresh of `fundamental_data` does not exist yet. Per the spec: `pe_ratio` and
`market_cap` from newest valid snapshots × latest PostgreSQL close, `revenue_growth`
from snapshots, `earnings_surprise`/`next_earnings_date` from `earnings_events`; mark
affected cached fundamental scores stale; must run identically when SEC is unreachable.
Implementation notes from the parity work: consume `fundamentals_derivation.derive()`
outputs, NOT raw snapshot fields — that path carries the split guard (`ttm_diluted_eps`
nulls when contaminated, with `ttm_diluted_eps_caveat`) and the multi-class share
fallback (`shares_outstanding` + `shares_outstanding_estimated`). Activation should be
an explicit switch (SystemSetting, like `sec_cik_overrides`), default off.
**Task 2 — A6 decommissioning.** After a short observation window: remove
FMP/Finnhub/Alpha Vantage providers, config and env keys; keep monitoring + manual
fallback. Gated by the acceptance criteria above — especially forward-calendar
timeliness from `dolt_earnings` (its `source_max_date` ran ~5 weeks ahead as of
2026-07-23, which passes).
**Known caveats to carry (documented in the findings report, not bugs to fix):**
- KLAC-class post-filing splits: P/E wrong until the next 10-Q; undetectable from
snapshots. Workstream B's `corporate_actions` table is the natural future fix.
- BRK-B: no share count exists anywhere in companyfacts → no market cap, correctly.
- FITB: unscored (split guard + no taggable revenue) — the one name that lost its
score relative to legacy; composite renormalises.
- Share-change guard at 25% nulls P/E for stock-funded M&A too (COF, WAT…);
revisit only if the ~3% universe hit-rate proves painful.
- `sec_cik_overrides` SystemSetting pins XOM → 34088 (applied in prod); the
`no_xbrl_filings` SystemEvent says when a new pin is needed.
- After any future parser change, stored rows need `scripts/reparse_fundamentals.py`
(dry-run default; `--apply` rewrites) — snapshots are otherwise immutable.
## Deferred (explicitly, until a concrete need appears) ## Deferred (explicitly, until a concrete need appears)
- Workstream B itself is deferred relative to A and blocks nothing in A. - Workstream B itself is deferred relative to A and blocks nothing in A.
@@ -853,3 +853,73 @@ track the parser's `SnapshotRow`, and only one of them is now enforced by a test
PSKY and Q need nothing — they are new registrants without enough filing history, which is PSKY and Q need nothing — they are new registrants without enough filing history, which is
correct behaviour. correct behaviour.
---
# Closing — post-reparse verification (2026-07-24)
## Production reparse
Two apply runs against prod (`scripts/reparse_fundamentals.py --apply`):
- **Run 6** (all fixes through the seventh pass): 262 inserted, 28,664 rewritten —
99.4% of which was backfilling the new `weighted_avg_diluted_shares` column; the
behavioural churn matched the dry run exactly. The five duration facts clustering at
190234 changed rows each is the 4-4-5 Q3 recovery signature. `accepted_at` changed on
only 76 rows (0.25%), confirming the tz-comparison fix works against real Postgres.
- **Run 7** (after the fiscal-year-end fix below): 3 inserted, 322 rewritten — BEN, DELL,
and boundary-year relabels for 53-week filers whose derived MMDD shifted a few days.
`cik_updates: 1` on run 6 was the XOM pin taking effect; XOM now has 68 snapshot rows,
latest period end 2026-03-31.
## Regression caught by the collision check — and its fix
The before/after key-collision query (~130 rows max 6 → 44 rows all 2) surfaced one real
regression: **BEN**. `submissions.fiscalYearEnd` declares `1231` while every Franklin
Resources 10-K ends 09-30, so `_period_identity` — which trusted the declared value — put
BEN's real fiscal Q1 zero days from the claimed year end (no band matched) and labelled its
fiscal Q2 as Q1. The collision discarded a period and BEN lost TTM EPS and revenue growth it
had before the branch. Fixed in `3d42ca7`: `resolve_fiscal_year_end()` prefers the issuer's
own most recent 10-K reportDate (which *is* the fiscal year end by definition) and treats
the declared field as fallback. Full-universe scan: 2 of 506 issuers mis-declare (BEN 91d,
DELL 29d); both now derive correctly (BEN rg 3.8243 vs legacy 3.82; DELL 38.5735 vs 38.57).
Residual collisions after run 7: 36 rows, all count-2, **latest year 2023** — the 53-week
drift class (AVY/CDNS/RVTY/JNJ/TDY/DPZ at 56-year intervals). Newest-wins degrades one
historical FY row; no current period is affected. Left alone deliberately: eliminating them
means modelling each filer's actual 52/53-week calendar per year, for rows feeding no
current metric.
## The verdict: 2026-07-24 parity report vs the 2026-07-23 baseline
| metric | baseline | after | |
|---|---|---|---|
| candidate scored | 482 | **504** | legacy scores 507; gap = PSKY, Q (new registrants) + FITB |
| revenue_growth candidate available | 442 | **489** | banks, REITs, 4-4-5 recovered |
| pe_ratio candidate available | 432 | **452** | net of the split-guard nulls |
| revenue_growth median abs delta | 0.0038 | **0.0038** | 47 names added at unchanged agreement |
| pe_ratio median / p95 abs delta | 0.5883 / 7.73 | **0.5576 / 6.03** | corrupted outliers gone |
Revenue `material_differences` rose 84 → 96: the newly compared names include the cases
where **legacy is the wrong side** (JPM 108.98% vs 3.34%, PPL 58.81% vs 8.34%, FCX 24.23%
vs +5.44%). Material is symmetric; these flag the provider being corrected.
The split guard is visible in the report: BKNG (1.10), COF, TPL, AMCR, WAT all null P/E now.
**KLAC (6.19) is the one known-wrong value left** — the post-filing split documented as
unfixable without a corporate-actions source.
**Correction to the seventh pass:** the claim that guard-tripped issuers "keep their
fundamental score, losing one of three inputs" fails for **FITB**, the one name that also
lacks revenue growth (its recent filings tag only ASC-606 fee-income fragments, then nothing)
— nulling its contaminated P/E (Comerica merger, 661M → 902M shares) drops it to one metric
and no score. Accepted: the composite renormalises, and legacy's 58% "revenue growth" for a
bank was itself junk.
## Recommendation
The A5 gate evidence now supports approving the cutover: coverage within 3 of legacy with
every gap explained, agreement essentially exact where both sides exist, every corrupted
value either fixed or deliberately nulled with a caveat, and the remaining score deltas are
documented definition differences — called out, not averaged away, as the plan requires.
Carry KLAC as the one known caveat in the approval note.
File diff suppressed because it is too large Load Diff