Skip to content

STZ: market_cap = None on 2026-05-14 cron — shares_outstanding missing from XBRL fact extraction #176

@dackclup

Description

@dackclup

Symptom

frontend/public/data/stocks/STZ.json (Constellation Brands, Consumer Staples, rank 308) has market_cap: null on the 2026-05-14 cron.

{
  "ticker": "STZ",
  "current_price": 151.18,
  "market_cap": null,
  "has_history": true,
  "raw_metrics": {
    "shares_outstanding": null,
    ...
  },
  "data_quality": {
    "missing_metrics": ["eps_basic", "eps_diluted", "shares_outstanding", "research_and_development"],
    "latest_period_end": "2026-02-28",
    "latest_filed_date": "2026-04-22",
    "filing_lag_days": 28
  },
  "risk_flags": []
}

Surfaced by the stock-detail-auditor subagent's Step 2 deterministic prefilter (SCHEMA category — market_cap ≤ 0 or None) on its dry-run during PR #175.

Root cause hypothesis

XBRL fact extraction (compute/ingest/fundamentals.py) failed to pull 4 per-share / count metrics from STZ's 10-Q filed 2026-04-22 (covering period ending 2026-02-28):

  • eps_basic
  • eps_diluted
  • shares_outstanding
  • research_and_development

With shares_outstanding: None, market_cap = current_price × shares_outstanding cannot be computed → null flows to output JSON → frontend /stock/STZ page renders a partial detail.

Related to #10 (shares_outstanding wrong for ~12 tickers), but STZ is a different failure mode — not "wrong value" but "no value at all". Possibly the XBRL fact name STZ uses for shares-outstanding differs from the _FUNDAMENTALS_REQUIRED_ATTRS manifest.

Why data_quality_input_corruption did NOT fire

risk_flags: [] — the Step 7.5 sanity guard in scoring did not flag this, even though data_quality.missing_metrics lists 4 missing fields. The current data_quality_input_corruption threshold appears to require both wrong-value AND mcap drift; missing-value paths are not caught.

This is issue #18 territory (composite scoring doesn't yet respect the data-quality flag) plus a sub-issue: the flag itself isn't being emitted on the "all None" failure mode.

Proposed investigation order

  1. Pull STZ's 10-Q XBRL directly via edgartools and check the fact names for shares-outstanding (dei:EntityCommonStockSharesOutstanding vs us-gaap:CommonStockSharesOutstanding vs share-class–scoped variants — Constellation Brands has Class A / Class B share classes).
  2. If fact name differs, extend the manifest in compute/ingest/fundamentals.py (and bump _FUNDAMENTALS_REQUIRED_ATTRS drift-detector test).
  3. Add fallback: if XBRL doesn't yield shares_outstanding, scrape from 10-Q cover-page text (the SEC requires a count there).
  4. Tighten data_quality_input_corruption to fire on "all None across critical metrics" paths so this is visible without an auditor pass.

Reproduction

python3 -c "
import json
d = json.load(open('frontend/public/data/stocks/STZ.json'))
print('market_cap:', d.get('market_cap'))
print('shares_outstanding:', (d.get('raw_metrics') or {}).get('shares_outstanding'))
print('missing_metrics:', d.get('data_quality',{}).get('missing_metrics'))
"

Tickers to cross-check (audit candidates)

Run the stock-detail-auditor Step 2 prefilter across the full universe — STZ is the only SCHEMA market_cap: null on this cron, but the dual-share-class hypothesis (Class A + Class B) might affect: BRK.B (already special-cased?), GOOG / GOOGL, FOX / FOXA, NWS / NWSA, DISH-class tickers if any. Worth confirming none silently degraded.

Out of scope for this issue

  • Fair-price ensemble extreme estimates on growth-heavy stocks (separate issue — see follow-up filed in same audit)
  • extended_top5 Rule 16 invariant (passed on this cron)

Owner

Unassigned. Pickup ladder: edgar-debugger for fact-name debug → patch in compute/ingest/fundamentals.py + tests/test_ingest/.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions