| name | heater-appb-known-non-bugs |
| description | Use when auditing HEATER App B, triaging a suspected bug, or about to "fix" one of these: FanGraphs 403, partial/skipped refresh_log statuses, season_stats coverage gaps, name-collision warnings, empty Yahoo tables locally, zero-value FA/lineup numbers on live, a thin Sell/Breakout lens, missing Stripe/CORS env, Yahoo writes 401, or known-flaky tests. Check here BEFORE filing or fixing. |
Known Non-Bugs — do not re-flag, do not "fix"
Every item below has been investigated to root cause at least once and ruled a design choice, an external limitation, or an accepted degradation. Re-fixing them has burned whole sessions. Protocol: confirm the match → cite this entry → move on. If it does NOT match, treat as real; note it as a follow-up in your report (or spawn a task) rather than fixing mid-audit.
External limitations (unfixable from our side)
| Observation | Reality |
|---|
| FanGraphs 403 (worse: ALWAYS from Railway's IP) | Anti-scrape policy. Tiered fallbacks exist; on App B the Marcel fallback generates projections ("Marcel fallback: wrote N projection rows"). Projections differing from FanGraphs on live is EXPECTED. |
| Yahoo lineup writes 401 on live | Yahoo's console offers no self-serve fspt-w write scope. HEATER is a read-only advisor; the write endpoints correctly return graceful failures. Do not re-attempt scope acquisition. |
| Yahoo token refresh fails from Railway | Datacenter-IP block — that's WHY the token relay exists. Token staleness = relay task on the owner's PC, not App B code. |
| bat_speed phase skipped; catcher-framing CSV parse failure | Upstream pybaseball limitations; waterfalls handle them. |
Design choices that look like bugs
| Observation | Reality |
|---|
STRIPE_* unset on live App B; everything free; require_pro inert | Intentional: friends beta is free; billing is built + dormant (billing_env_configured() false). |
HEATER_API_CORS_ORIGINS unset | CORS is moot — the Vercel server-side proxy makes all calls same-origin. |
refresh_log partial / cached / skipped / no_data | Honest statuses honoring TTL, not failures. season_stats: partial ~2497/7498 = curated ~1100-player scope vs MLB's full 40-man+ dump — intentional. pitcher_positions: 0 rows = idempotent no-op success. |
| "canonical-name collision … keeping first" warnings | Real duplicate human names; keep-first is the documented accepted behavior for news. |
| ATH Max Muncy row (player_id=71) still exists | Deliberate — other teams may roster him; the fix was mlb_id-aware dedup, not row deletion. |
| Sell/Breakout lenses thin or quiet | Honest by design: xwOBA arrives only via the Statcast relay; NaN (not fabricated 0) until it loads. Breakout is bounded to top-500 relevant (an O(n²) engine — the bound fixed a >12s hang). |
| League scoreboard per-team scores (0,0) locally | Scores come from the cached Yahoo matchups; env-dependent degradation, real on Railway. |
Streaming replay proxy_caveat=True; raw engine status/confidence strings | Replay uses CURRENT projections (no snapshots exist); the API intentionally emits raw engine values (frontend adapts). |
| Grace periods / floors in FA math (30-day playing-time grace, 0.20× ROS floor, punt weight 0.05 not 0, L14 gates 20 PA/5 IP) | Calibrated engine choices with registry citations — not missing edge cases. |
| Empty rosters/matchup/FA locally | Local Yahoo tables are empty; App B on Railway has the live sync. See heater-appb-debugging. |
Known test rednesses (pre-existing; don't chase in unrelated PRs)
- Shard-1 xdist flake
test_draft_service_recommend_engine_failure_logs (passes in isolation; owner deferred).
- Date/env-sensitive failures in
test_ai_keys / test_usage_analytics (noted 2026-06-27; not caused by feature work).
- Full-suite runs after a local bootstrap may diverge because the identity-repair phase MUTATED your DB — rerun against a clean DB before blaming the code.
Deliberately dormant / deferred (not dead code)
B2.0/B2.1 Postgres seams (src/db/engine.py, alembic) — get_connection() raising NotImplementedError on non-SQLite DATABASE_URL is the designed guard until owner-gated B2.2. M2 billing UI, tenancy stores, require_login — active only when env flips. The Statcast relay is the opposite: live now but MUST DIE before monetization (commercial-use-prohibited source).
When NOT to apply
If the observation matches an entry only partially (new symptom, new surface, different root), it's NOT covered — investigate as a real bug via heater-appb-debugging. This list is a shield against re-litigating settled findings, not against new ones.