Skip to content

fix(main): pe_ttm in raw_metrics still used eps_diluted (audit #6 final loose end)#51

Merged
dackclup merged 1 commit into
mainfrom
fix/pe-raw-metrics-missed-consumer
May 14, 2026
Merged

fix(main): pe_ttm in raw_metrics still used eps_diluted (audit #6 final loose end)#51
dackclup merged 1 commit into
mainfrom
fix/pe-raw-metrics-missed-consumer

Conversation

@dackclup
Copy link
Copy Markdown
Owner

Summary

Final-audit follow-up to PR #49. Production median PE was still 77.8 post-PR-#49 (essentially unchanged from 77.5). Root cause: PR #49 fixed 4 consumers of snap.eps_diluted but missed compute/main.py::_build_raw_metrics — the helper that builds the RawMetrics object that surfaces in the public StockSummary / StockDetail JSON. So the inflated PE values kept flowing into the frontend display + downstream consumers.

Fix: route pe_ttm through NI_TTM / shares_outstanding, matching the formula in the other 4 already-fixed consumers (pe_ratio, _build_universe_metrics, multiples_pe_fair_price, graham_number).

Audit findings (post-PR-#49 production)

What WORKED post-PR-#49 + cache key v2 bump:

Fix Result
NVDA revenue $10.9B → $215.9B
AVB / CPT / UDR / ESS revenue $7-12M → $1.7-3.1B
META shares None → 2.564B
WMT shares 3.42B (stale) → 7.97B post-split
BKNG NI None → $6.2B
WFC / GS / DUK / CRWD revenue None → $85B / $60B / $33B / $4.8B
|NI| > |revenue| corruption 17 tickers → 4
Beneish coverage 6.8% → 31.9% ✓ (5× improvement)
Dechow coverage 5.4% → 31.3%
data_quality_input_corruption veto count 20 → 6 ✓ (banks/REITs no longer falsely vetoed)
Fair-price coverage 97.0% → 99.2%
Top-5 rotation invariant symmetric (3 entered = 3 exited) ✓

What was BROKEN:

Metric Production Expected Why
Median PE 77.8 ~26 This PR's bug — _build_raw_metrics missed
AAPL PE 61.6 35.7 same
TSLA PE 3425 432 same
ABBV PE 534 105 same

Files changed

File Change
compute/main.py _build_raw_metrics now derives TTM EPS from NI / shares (was using snapshot.eps_diluted)

11 LOC change, no new dependencies, no schema change.

Verification

  • ruff check . — clean
  • python -m pytest -m "not network" — 646 / 646 pass
  • No regression — eps_diluted field still stored in raw_metrics for display, only the derived pe_ratio_ttm math was fixed

Test plan (post-merge)

  1. CI green
  2. User triggers Compute Rankings workflow_dispatch on main
  3. After bot commit:
    • Median PE drops 77.8 → ~26 (universe-wide)
    • AAPL ~35, NVDA ~46, TSLA ~430 (all in industry range)
    • All 12 critical-ticker fixes from this audit cycle confirmed
  4. If clean → user authorizes Phase 3e.4 v1.0 tag

Phase 3e roadmap

https://claude.ai/code/session_015649aRyi2bvciQYZVNACd2


Generated by Claude Code

…d consumer)

Final audit of post-PR-#49 production output revealed PE distribution
median was 77.8 — virtually unchanged from the pre-fix 77.5. PR #49
fixed `pe_ratio` (Value pillar), `_build_universe_metrics` (peer
median), `multiples_pe_fair_price` (fair-price method), and
`graham_number` — but missed THIS one: `_build_raw_metrics` in
compute/main.py builds the RawMetrics object that surfaces in the
StockSummary / StockDetail JSON output, and it was still computing:

  pe_ttm = current_price / snapshot.eps_diluted  # single-period bug

This is the field that shows up as `raw_metrics.pe_ratio_ttm` in the
public JSON the frontend renders. With this missed consumer, the
production output kept shipping inflated PEs even after PR #49 merged
(AAPL 61.6 vs correct 35.7, TSLA 3425 vs correct 432, ABBV 534 vs
correct 105, ... 88.6% of universe).

Fix: route through `NI_TTM / shares_outstanding`, matching the same
formula in the other 4 already-fixed consumers.

Validation pending workflow_dispatch re-run + audit. Expected:
production median PE drops 77.8 → ~26 (target).

Other corruption fixes already taking effect post-PR-#49 confirmed:
- NVDA $215.9B revenue ✓
- AVB $3.1B (was $7M) ✓
- WMT 7.97B shares post-split ✓
- META 2.564B shares (was None) ✓
- BKNG NI $6.2B (was None) ✓
- WFC $85B / GS $60B / DUK $33B revenue ✓
- Beneish coverage 6.8% → 31.9% ✓ (5x improvement)
- |NI|>|rev| corruption: 17 → 4 tickers ✓

This PR closes the last loose end of the audit-#6 deep-clean cycle.

Full offline suite: 646 / 646 pass.

https://claude.ai/code/session_015649aRyi2bvciQYZVNACd2
@vercel
Copy link
Copy Markdown

vercel Bot commented May 14, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
quantrank Ready Ready Preview, Comment May 14, 2026 4:49am

@dackclup dackclup marked this pull request as ready for review May 14, 2026 04:57
@dackclup dackclup merged commit 48855aa into main May 14, 2026
4 checks passed
@dackclup dackclup deleted the fix/pe-raw-metrics-missed-consumer branch May 14, 2026 04:59
dackclup added a commit that referenced this pull request May 14, 2026
#55)

Workflow run #30 (2026-05-14, 52m 59s) failed at the "Commit JSON
outputs" step:

  [main f409f51] chore: update rankings 2026-05-14
   1006 files changed, 23767 insertions(+), 23767 deletions(-)
  To https://github.com/dackclup/quantrank
   ! [rejected]        main -> main (fetch first)
  error: failed to push some refs to ...
  hint: Updates were rejected because the remote contains work that
  you do not have locally. ...

Root cause: workflow checked out commit 48855aa (PR #51's tip) and
ran for 52 minutes. During that window two docs PRs landed (#52
recommendation-badge, #54 loss-chance + price-chart), advancing main
ahead of the workflow's local HEAD. Push rejected with "fetch first".

Fix: rebase the bot commit on top of remote main before pushing, with
a 3-attempt retry loop. The bot commit only touches
`frontend/public/data/` (502 stock JSONs + rankings.json + metadata),
so rebase against ANY docs/code change is conflict-free —
`--autostash` covers the edge case where the runner's pre-checkout
state had any uncommitted noise.

Without this fix, every workflow run is fragile to "main moved while
compute was running" which becomes more likely as PR velocity
increases (we had 7 PRs land in 24h yesterday). The compute itself
SUCCEEDED — it's purely the commit-and-push step that was racy.

https://claude.ai/code/session_015649aRyi2bvciQYZVNACd2

Co-authored-by: Claude <noreply@anthropic.com>
dackclup added a commit that referenced this pull request May 17, 2026
… UI spot-check requirement (#101)

PHASE_STATUS.md: row 4.5 → ✅ DONE (PRs #89/#90/#91 + #93 + #95 +
  #97 + #100). 4.5f ✅ DONE block added with production verified
  snapshot (run #51, commit e57f09c, warm-cache 5m14s), 5 schema
  field inventory, rank-source contract restatement, and live UI
  Section I spot-check results. Phase 4.5 timeline summary table
  4.5f row flipped ⚪ → ✅; 4.5e marked deferred-until-after-tag.

SKILL.md: schema versions table appended with 0.8.0-phase4.5f row
  covering the minor-bump rationale (5 new fields + new UI surface
  + semver-coupled tag), the FLAG_WEIGHTS additive design, and the
  Rule-16 rank-source contract.

WORKFLOW.md: 4.5f task list [ ] → [x] for all sub-tasks. Captures
  module-location decision (manipulation_index.py kept separate
  from composite.py to keep compute_composite pure-pillar), 4.5e
  reserved-slot weights, and the new Section I spot-check result.
  Tag v1.2.0-phase4.5 is the only [ ] remaining — cut after this
  docs PR merges.

CLAUDE.md: Phase status section refreshed for 4.5f complete. Schema
  0.7.1-phase4g → 0.8.0-phase4.5f; defense layer 16 → 17; next
  deliverable: tag v1.2.0-phase4.5 → then 4.5e. Verification ladder
  amended with the new "after workflow_dispatch green" rule pointing
  at the Section I spot-check (REQUIRED 2026-05-17).

.claude/skills/verify-production-output/SKILL.md: new Section I
  (Live UI visual spot-check via Playwright) added to the A-H
  table + a long-form section covering the 4-ticker matrix (worst-
  case stack, mid-band, boundary, top-clean), per-ticker capture
  template (card-present, headline, band-label, components,
  penalty, screenshot), the design-system regression mode this
  catches (the PR #70 invisible-dark-text-on-forced-light-bg
  class), and the sandbox / browser-version caveats
  (executable_path override + ignore_https_errors=True).

Production verified: commit e57f09c / run #51 (workflow
25983422610) / 502 stocks / 856 offline tests / warm-cache 5m14s.
Phase 4.5 cluster (4.5a-4.5f) complete; 6 sub-PRs landed in
1 calendar day after the cluster kickoff on 2026-05-16.

Tag v1.2.0-phase4.5 is the next action after this merges.

https://claude.ai/code/session_015649aRyi2bvciQYZVNACd2

Co-authored-by: Claude <noreply@anthropic.com>
dackclup added a commit that referenced this pull request May 28, 2026
… open-issues list (#291)

Closes deferred substance items from PR #286 + PR #290 that opted to keep
scope tight under the `pointer-to-CLAUDE.md` delegation pattern.

Changes (1 file, AGENTS.md):

- Line 377 — Production-verified run pointer bumped from cron #51
  (`b1588b2a`, 2026-05-14) → cron #69 (`233117ac`, 13m 16s warm-cache,
  2026-05-28). Cross-tool agents now have the current known-good
  baseline; verified by defense-layer-auditor + stock-detail-auditor
  on schema `0.10.7-phase4.6`.

- Lines 380-382 — "Open Phase 4+ issues" list refreshed from 4 → 11
  entries. Removed stale qualifier on #67 (PR #204 already landed
  data-collection; #67 is Phase 4 follow-up not Phase 5+). Added 7
  missing issues: #115 (JKP license) · #130 (Q3 cohort) · #137
  (9arm-skills license deadline 2026-06-17) · #150 (Phase 2-3 epic) ·
  #287 (FORM4 revert + durable timeout) · #288 (GOOG/GOOGL XBRL) ·
  #289 (NVR DQIC false positive). Added zero-exploitability context
  to #41.

Doc-only PR. No compute / schema / scoring / valuation / frontend /
Python / TS code change. CLAUDE.md substance untouched this PR
(PR #286 + PR #290 already bumped it); this PR closes the AGENTS.md
side of the lockstep. PHASE_STATUS_INFLIGHT.md side-file satisfies
§Conventions lockstep per PR #237 convention.

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants