Changelog¶
Newest first. Short, intentionally incomplete — commits on main are the source of truth, this is the human-readable roll-up.
2026-04 — P5 (UI v2 + quality)¶
Frontend rewrite¶
- React 18 + Vite 5 + Tailwind 3 replaces the original vanilla HTML SPA. Four-tab nav (Dashboard / Watchlist / Claw / Settings), TypeScript throughout, typed API client + adapter layer bridging backend Pydantic shapes to display types.
- Signal card redesign matches the v1 format pixel-for-pixel: headline, per-ticker salience bars (tier-coloured red / gold / blue), bilingual EN/ZH columns, collapsible reasoning broken out per
[AGENT]tag, Impact + Confidence score bars, collapsible agent breakdown, async-hydrated OG preview, compliance disclaimer. - UserMenu dropdown — click the avatar in the header for email, Settings shortcut, and Sign out (no more detour through Settings).
- TelegramWizard — the link flow is now a three-step numbered guide with inline copy-to-clipboard instead of a paragraph of fine print.
- Ask StockClaw page gives the chat transcript ≥55vh and moves Historical Search below so the chat card isn't squeezed by the RAG block.
- OS-adaptive light palette — GitHub-style white cards on pale-grey page, tuned so
text-gray-100headlines render near-black (previously near-white on grey — invisible). - Extended-hours prices — watchlist rows now show a PRE / POST badge + extended price + % change directly beneath the regular price when yfinance reports
marketStatein an extended session. Alignment is CSS-grid so836.92and856.33line up digit-for-digit with the ticker symbol above. - Live status strip — "Last updated 8s ago" is now driven by the hook's real fetch timestamp and ticks every 15s; the gold "What's moving the market" ticker rotates through the top 12 real signal headlines instead of four hardcoded demo lines.
Signal quality¶
- Urgency tiers unambiguous — FLASH / ALERT / NOTE / FYI now render as four distinct badges (red / orange / gold / grey) instead of collapsing FLASH + ALERT into a single overloaded "BREAKING" label. Status strip counts split too: "2 FLASH · 18 ALERT" rather than "20 BREAKING".
- Duplicate signal fix —
RawItem.raw_idnow inherits thecontent_hash(sha256 of source URL + title) so the DB-level dedup inrun_user_pipeline_taskactually fires. Previouslyraw_idwas a fresh UUID4 on every crawl, making the existing dedup a no-op; users were seeing the same Yahoo Finance article pushed every ~20min beat cycle. Also reduces OpenRouter spend (each duplicate article was triggering a fresh 5-agent synthesis run).
Ask Claw (RAG) fixes¶
- BM25 tokeniser —
websearch_to_tsquerywas AND-matching every word in the user's question, which almost never hit. Replaced with a tokeniser that OR-joins content words ("Should I buy NVDA right now?"→"buy | nvda") after dropping English stopwords. - Retrieval diagnostics —
[rag] empty retrievallog line shows visible-signal count + per-retriever hits so RLS vs. query-logic failures are telegraphed clearly.
Deploy / ops¶
- Vercel SPA fallback —
/:path*→/rewrite so/login,/watchlist, etc. serveindex.htmlon direct hits. Without this, Google OAuth's post-sign-in redirect to/login?code=…404'd. - Market quote cache cut from 60s → 30s TTL; pre/post-market prices now surface within ~30s instead of ~1min.
2026-04 — P4 complete¶
- P4.4 Google OAuth with JWKS/ES256 verification (Supabase's current default); Sign in with Google wired end-to-end.
- Web Push: VAPID-authenticated browser notifications with deep-link back to the triggering signal; FLASH gets sticky (requireInteraction) banners.
- Telegram multi-user:
deliver_batchreads per-usertelegram_chat_idfromuser_settingsinstead of a global env var; users must link via Settings. - Per-user chat id + RLS fix:
user_scopenowSET LOCAL ROLE authenticatedso RLS policies actually fire — earlier code silently ran as the Postgres superuser withBYPASSRLS. - Agent breakdown panel: each signal carries per-agent impact / confidence / latency / error in a collapsible table under the card.
- Per-ticker relevance bars + Open Graph preview cards for every signal's source article.
- Signal card redesign to match the Telegram delivery format — bilingual side-by-side summaries, signal id, signal_type pill, expandable reasoning block.
- Email magic link via Supabase (no Google account required to sign up).
- Real Claw chat backed by hybrid dense + BM25 retrieval over your own signals, with every query logged to
rag_query_logs. - Embedding pipeline: each new signal is embedded into ChromaDB (
paraphrase-multilingual-MiniLM-L12-v2) immediately after commit. - Claw rules CRUD with an LLM-based natural-language parser (stored only; triggering is future work).
- OS-driven dark/light theme for the whole SPA.
- Real market data endpoints (
/market/quotes,/market/indices) via yfinance + 60 s Redis cache. - Watchlist auto-bootstrap so new users land on a usable empty list instead of a dead "+ Add ticker" button.
- Logout UI (avatar dropdown in the top bar).
- Legal pages (
/privacy.html,/terms.html) and this documentation site.
2026-04 — P3¶
- Write endpoints:
POST /watchlists/{id}/tickers,DELETE .../{ticker},PUT /settings,POST /integrations/telegram/link,POST /claw/chat(then still an echo stub). user_settingstable.- Adding a ticker fires an immediate crawl.
2026-04 — P2¶
- Read-only FastAPI:
GET /signals,GET /watchlists,GET /health,/ws/signalsWebSocket. - JWT auth + row-level security scaffolding.
- Frontend flipped off mock mode.
2026-04 — P1¶
- Supabase Postgres + Redis via docker-compose.
- Celery + Beat orchestration.
- Signal persistence: pipeline writes each produced SignalCard to the DB.
- SQLite → Supabase watchlist migration.
2026-04 — P0¶
- 5-agent synthesis engine with Reflexion and Pydantic validation.
- RSS / yfinance crawlers.
- Watchlist SQLite DB.
- Frontend SPA (dashboard / watchlist / claw / settings) with PWA manifest.
- Telegram bot delivery (single-user).