Spaces:
Sleeping
Sleeping
Commit History
-
fix: make consensus capture opt-in so briefs stop archiving wrong labels
agent/tools.py:288 fetches estimates with the LAST REPORTED period, because that is the period the brief is about. fetch_analyst_estimates then reads yfinance's "0q" row, which is the CURRENT, UNREPORTED quarter. Capture was an automatic side effect of every fetch, so every brief run appended a record asserting "consensus for Q1-2027 was X" where X is the street's estimate for Q2-2027. It cannot produce a false comparison today -- those captures post-date the report, so the gate refuses them on no_pre_release_snapshot -- and the 12 committed live records all came from the daily job and are clean. But it is a wrong observation in an archive whose entire asset is being trustworthy years from now, and sub-project E's backtest joins on that label. fetch_analyst_estimates gains an explicit keyword-only snapshot_period. Supply it and the call archives under that label; omit it and it archives nothing. scripts/snapshot_consensus.py supplies it (it derives the correct next-unreported period)…ac0fe57 -
fix: fail the daily job when it archives nothing, and log why
main() returned `0 if ok else 1`, where `ok` counted successful yfinance fetches. The append happens later and elsewhere -- inside record_consensus_snapshot, whose entire body sits in `except Exception: return 0`. So if every append failed the script printed a success line per ticker, exited 0, the workflow committed nothing and GitHub showed green: nothing captured, nothing alerted, and a day of consensus that no public source can give back. - main() now returns non-zero when zero records were written, and says on stderr which of the two causes it was. - record_consensus_snapshot logs the exception it swallows, plus the missing-as_of/target_period early return. Swallowing is correct -- a failed capture must never break a brief -- but the spec says the job logs a failed capture, and a bare `return 0` logs nothing. The module docstring already promised both behaviours; only the code disagreed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>49203e0 -
fix: move filing_staleness to analytics/staleness so the snapshot job avoids Streamlit
scripts/snapshot_consensus.py imported dashboard.provenance.filing_staleness, and dashboard/provenance.py imports streamlit at module level. The daily GitHub Actions job only installs yfinance, so the scheduled run would die on first import with ModuleNotFoundError. filing_staleness is pure date arithmetic with no Streamlit dependency, so it moves verbatim to the stdlib-only analytics package (its __init__ already states that's the package's contract). dashboard/provenance.py re-exports the name so its existing callers (dashboard/verdict.py, tests/test_verdict.py) keep working unchanged. Adds tests/test_staleness.py covering the moved function directly.5f932b3 -
fix: derive target_period for the daily consensus capture
Controller ruling on the gap found while implementing Task 4: the daily job called fetch_analyst_estimates(ticker) with no target_period, so every captured payload carried target_period=None and record_consensus_snapshot's guard silently dropped every record — the archive stayed permanently empty. - analytics/consensus.py: next_unreported_period(ticker) derives the quarter after the most recently reported one from metrics.period labels (Q{n}{YYYY} / FY{YYYY}), taking the max on parsed (year, quarter) rather than lexicographically, since "Q12027" < "Q42026" as strings. Returns None when nothing parses. - scripts/snapshot_consensus.py: calls next_unreported_period first and skips (rather than fetches with a None period) when it returns None. Also warns, per ticker, when the latest reported filing is more than 120 days old (dashboard/provenance.py::filing_staleness's threshold) since the derived period is then probably wrong. - ingestion/analyst.py: every snapshot now car…6bdcc4d -
feat: add daily consensus capture script
Adds storage.metrics_db.list_tickers() (the app's de facto coverage universe, previously duplicated inline in warm_runtime_cache.py and deploy_check.py) and scripts/snapshot_consensus.py, which iterates it and calls ingestion.analyst.fetch_analyst_estimates per ticker. No data/consensus_snapshots.jsonl is included: a live run against all six covered tickers (AAPL, AMD, GOOGL, MSFT, NVDA, TSLA) wrote zero archive records. fetch_analyst_estimates(ticker) is called without target_period, so every captured payload carries target_period=None, and record_consensus_snapshot's `if not target_period: return 0` guard silently drops every record. See task-4-report.md for the full analysis; this needs a decision before the archive can hold real data.a95bfa1