@@ -1176,6 +1176,19 @@ finance/ nothing is polled unless a browser is viewing it. No futures-hours calendar is modelled (a closed futures market just returns a flat quote), consistent with the no-holiday-calendar decision in `market.rs`.- **2026-05-22: futures pages no longer prompt to seed; SEC job runs on boot.** A future's symbol page showed the generic "no price history, run `make seed`" empty state, which is wrong: a future has no daily history by design (Stooq carries no `=F` data) and seeding cannot change that. The symbol page now hides the daily chart and key-stats sections for any symbol without daily history and shows an honest message: a short "followed with live quotes only" note for a future, a plain "no daily history available" for a historyless index (^RUT, ^VIX). The live quote in the header is unaffected. Separately, the `sec` scheduler job is now brought forward to the first tick on boot, the way the history seed is, so a deploy that introduces new SEC-backed data backfills within a tick instead of waiting out the ~24h interval. That is what populates the Phase 18 ETF profiles on the production box right after a deploy; the job is cheap when nothing is stale.---
modified
src/scheduler.rs
@@ -110,6 +110,13 @@ pub fn spawn(pool: SqlitePool, config: Arc<Config>, hub: Arc<Hub>) -> JoinHandle tracing::warn!( "[scheduler] SEC_CONTACT_EMAIL unset: SEC fundamentals & filings job disabled" ); } else if let Err(e) = schedule_next(&pool, "sec", now_ms()).await { // Bring the SEC job forward to the first tick. The sweep is // resumable and cheap when nothing is stale, so running it on // each boot is harmless — and it means a deploy that introduces // new SEC-backed data (e.g. the Phase 18 ETF profiles) backfills // within a tick instead of waiting out the ~24h interval. tracing::warn!("[scheduler] bring sec job forward: {e}"); } // Prune's last-run time is loop-local: a restart simply re-prunes once,
modified
templates/pages/symbol.html
@@ -56,6 +56,10 @@ {% endif %} </header> {# Chart and key stats need daily history. A future has none by design (live quotes only), and so do the historyless indexes; those fall to the explanatory empty state below instead of an empty chart. #} {% if stats %} <section class="panel chart-panel"> <div class="chart-bar"> <div class="range-bar">
@@ -86,7 +90,6 @@ <div id="chart" data-ticker="{{ symbol.ticker }}"></div> </section> {% if stats %} <h2 class="section-title">Key stats</h2> <section class="keystats">
@@ -184,7 +187,13 @@ </section> {% else %} <section class="empty"> <p>No price history for {{ symbol.ticker }} yet. Run <code>make seed</code> or wait for the next history sync.</p> {% if symbol.kind == 'future' %} <p><strong>{{ symbol.ticker }}</strong> is a futures contract. Finance follows futures with live quotes only, so there is no historical daily chart; the price above updates live while the market is trading.</p> {% else %} <p>No daily price history is available for {{ symbol.ticker }}.</p> {% endif %} </section> {% endif %}