Was showing every data point timestamp. Now:
- Recharts generates max 8 evenly-spaced ticks
- Each tick shows 'Apr 29' in bold white + '2 PM' in gray
- All labels at -35° angle to avoid overlap
- Simplified tick component (no hour-boundary filtering needed)
Replaced string-based X-axis with numeric timestamp axis:
- Custom ChartXTick component renders hour marks at -35° angle
- New day boundaries shown in bold (e.g., 'Apr 29')
- Hour marks shown as '9:00 AM', '10:00 AM' etc.
- Tooltip shows full date+time on hover
- Direction timeline uses formatted timestamps
- Bottom margin increased to accommodate angled labels
Two fixes for missing intraday data:
1. Frontend: lifted selectedWindow state to page level so useTrendHistory
passes window param to the API. Previously fetched all windows with
limit=500 which exhausted the limit before reaching recent intraday
data. Now fetches only the selected window's data.
2. Scheduler: removed market-hours-only restriction from periodic
aggregation. Runs every 15 minutes 24/7 so intraday data is always
populated for backtesting regardless of market state.
Intraday was showing only 12h of data (9 sparse points). Widened to
24h to show a full day of intraday trend history. Also widened 1d
from 24h to 48h for better context.
Displays an 'Open Position' card above the trend charts when we hold
a position in that ticker. Shows shares, avg entry price, current
price, market value, and unrealized P&L with green/red coloring.
Card is hidden when no position exists for the ticker.
Replace raw UUID with a linked document title in both the collapsed
row (using the empty space on the right) and the expanded detail view.
Uses useDocument hook to fetch the title, falls back to truncated UUID
while loading. Clicking the link navigates to the document detail page.
The /api/patterns/{ticker}/competitive-signals endpoint returns
{competitive_signals: [...], count: N} but the hook was typed as
returning a raw array. The component called .map() on the object,
causing 'e.map is not a function'. Now extracts the array from the
response wrapper.
Variable was used before declaration (temporal dead zone error).
Moved windowHours/hoursBack/cutoffTs above the filtered const that
references cutoffTs.
The trend history chart was showing all historical data regardless of
which window was selected — only filtering by window name but not by
time range. Now filters both trend data and price data to the time
range matching the selected window (e.g., 7d shows last 7 days only,
30d shows last 30 days).
The TickerFilter triggered a query on every keystroke, causing re-renders
that stole focus from the input. Now uses a local input state with a
300ms debounce before updating the query, keeping focus on the text box
while typing.
- pipelineEnabled: true in beta so all pods run (Kargo happy)
- PIPELINE_DEFAULT_OFF=true in beta config — scheduler initializes
the Redis toggle to OFF on first boot
- Shared Ollama (10.1.1.12:2701) between beta and paper
- Flip pipeline ON from the UI when testing, OFF when done
- Optimistic UI update for the toggle button
- Added pipelineEnabled flag to Helm values (default: true)
- Worker services (scheduler, ingestion, parser, extractor, aggregation,
recommendation, broker-adapter, lake-publisher) scale to 0 when disabled
- API services always run regardless of toggle
- Redis-based runtime toggle: POST /api/ops/pipeline/toggle
- Scheduler checks the flag before each cycle
- Frontend: green/red Pipeline ON/OFF button on the pipeline page
- Beta defaults to pipelineEnabled: false
- Base values.yaml: blanked external URLs (Ollama, Polygon, Alpaca)
so stages only connect to what they explicitly configure
- POST /api/ops/pipeline/retry-failed endpoint resets extraction_failed
docs to parsed, deletes failed intelligence rows, and re-enqueues
them (batch of 200)
- Scheduler now auto-retries extraction_failed docs every ~10 minutes
(100 per cycle, 60-min cooldown per doc)
- Pipeline page shows 'Retry Failed (N)' button when extraction_failed
count > 0, with pending/success/error states
Backend: assemble_trend_with_evidence now deduplicates document IDs
via dict.fromkeys() (the rollup code already did this, but the base
assembly didn't — same doc could appear multiple times from different
intelligence extractions).
Frontend: Trends.tsx deduplicates via Set before rendering as a safety
net for existing data already stored with duplicates.
- EvidenceRef component now fetches document details via useDocument()
hook and displays the title instead of 'doc:43156423…'
- TanStack Query deduplicates and caches lookups for repeated doc IDs
- Pattern IDs still render as before (e.g. 'pattern META other (1d)')
- Override Trade button changed from brand-600 to red-600
The handler for /api/macro/impacts/:ticker was returning the impacts
array directly instead of { exposure_profile, impacts }. The frontend
destructures macroData.impacts which was undefined, falling back to
an empty array — so the Macro tab always showed 'No active macro impacts'
even with mock data present.
- recommendation worker: filter out non-UUID document IDs (synthetic
pattern:* IDs from competitive signals) before inserting into
recommendation_evidence table — the uuid cast was failing and
silently dropping all evidence rows
- wrap executemany in try/except so partial failures don't lose all evidence
- SqlExplorer: wrap Lucide icons in <span title=...> instead of passing
title prop directly (not supported by lucide-react, broke CI build)
- Add GET/PUT /api/admin/trading/approval-config endpoints
- Add POST/DELETE /api/admin/trading/lockouts endpoints
- Add useApprovalConfig, useUpdateApprovalConfig, useCreateLockout, useDeleteLockout hooks
- Add Paper Order Approval toggle card with confirmation dialog
- Add lockout creation form and delete button to Active Lockouts card
- Add MSW handlers for all new endpoints
- Add property-based tests for bug condition exploration and preservation
- Pattern IDs (pattern:META:other:1d) shown as 'pattern META other (1d)'
- Document UUIDs shown as clickable 'doc:43156423…' links to document detail
- Unknown formats shown truncated as fallback
- Trading page: added conservative/moderate/aggressive selector that
updates the trading engine config via PUT /api/trading/config
- Recommendations page: added risk tier dropdown that defaults to the
engine's current tier and filters recs by the tier's min_confidence
- Backend: added min_confidence query param to GET /api/recommendations
- Risk tier thresholds: conservative ≥0.75, moderate ≥0.55, aggressive ≥0.40
- Removed PUT /api/trading/capital (set capital) — only touched in-memory state
- Removed POST /api/trading/capital/adjust (add/withdraw) — same problem
- Reset endpoint now: liquidates Alpaca positions, cancels orders, clears DB,
then queries Alpaca for real portfolio_value to set engine capital
- Frontend: replaced CapitalCard with simple ResetCard (one button)
- Removed useSetTradingCapital and useAdjustCapital hooks
Three distinct capital operations on the Trading Controls page:
- Set Capital: overwrites pool balances to a new amount (existing)
- Add/Withdraw: adjusts active pool by a delta without touching
positions, orders, or history. Validates sufficient balance for
withdrawals. Logged to reserve_pool_ledger as manual_adjustment.
- Reset Everything: nuclear option — deletes all positions, orders,
trading decisions, stop levels, snapshots, backtests, notifications,
and circuit breaker events, then resets capital fresh. Red button
with double-confirmation dialog.
Backend: POST /api/trading/capital/adjust and POST /api/trading/reset
Frontend: CapitalCard rebuilt with three sections and confirmation UIs
New Agents tab in the sidebar (Ops group) for viewing, editing, and
creating AI agent configurations:
Database (migration 026):
- ai_agents table: editable configs for each LLM agent (model, prompts,
temperature, tokens, retries). source='system' for built-in,
source='user' for custom. Seeds 3 system agents (Document Extractor,
Event Classifier, Thesis Rewriter) using WHERE NOT EXISTS to never
overwrite user edits across reinstalls.
- agent_performance_log table: per-invocation metrics (duration,
confidence, retries, tokens, errors) linked to agent config.
API endpoints:
- GET/POST /api/agents — list and create agents
- GET/PUT/DELETE /api/agents/{id} — view, edit, delete (system agents
can be edited but not deleted)
- GET /api/agents/{id}/performance — aggregated metrics (success rate,
avg/p95 latency, confidence, token usage)
- GET /api/agents/{id}/performance/history — hourly time series
Frontend:
- AgentsPage with sidebar list + detail panel
- Agent detail: config display, system prompt viewer, performance
dashboard with metrics cards and time-series chart
- Edit form: all config fields editable including system prompt,
model, temperature, tokens, retries
- Create form: new user-defined agents with auto-slug generation
- System agents show blue badge, user agents show green badge
- New 'intraday_bars' endpoint in PolygonMarketAdapter: fetches hourly
bars for today using range_bars URL with timespan=hour, sort=asc
- Scheduler expands intraday_bars global source into per-ticker jobs
for all active companies (every 15 minutes via polling_interval)
- Migration 025 inserts the intraday source with 900s cadence
- Frontend price matching uses closest-timestamp instead of date-string
matching, with 2h tolerance for intraday and 36h for daily windows
- Bumped market price fetch limit to 200 for intraday granularity
- New GET /api/market/prices/{ticker} endpoint serving OHLCV data from
market_snapshots, deduped by bar_timestamp
- New useMarketPrices hook in frontend
- Trend chart now shows price (purple line) on a right Y axis ($)
alongside trend metrics (%) on the left Y axis
- Custom tooltip formats price as dollars, metrics as percentages
- Price line uses connectNulls for days with missing bar data
Replaced Recharts default Tooltip with formatter prop (broken in
Recharts v3 with explicit type annotations) with a custom
TrendTooltip component matching the SQL Explorer pattern. Shows
each series name, value, and color on hover.
/api/patterns/{ticker} returns {ticker, patterns, count} but
useHistoricalPatterns typed its response as HistoricalPattern[].
The .map() call on the object caused 'e.map is not a function'.
Fixed by unwrapping resp.patterns in the hook's queryFn.
Trend charts blank:
- trend_windows uses upsert (1 row per ticker/window), so charts had
at most 1 data point. Added trend_history table (migration 024) that
appends every snapshot. New /api/trends/history endpoint serves the
time series. Frontend now uses useTrendHistory for charts and
useTrends for the latest summary card.
Competitor GUIDs:
- list_competitors query returned raw company_b_id UUIDs without
joining companies table. Added LEFT JOIN with CASE to resolve the
other company's ticker and legal_name. Updated Pydantic model to
include enriched fields. Frontend fallback changed from truncated
UUID to ticker/legal_name/Unknown.
- ID mismatch: API generated a throwaway UUID while BacktestReplay
generated its own internally. Frontend polled with wrong ID and
never found the DB row. Now pre-generate ID in endpoint and pass
it to BacktestReplay.
- Field name: API returned 'backtest_id' but frontend read 'data.id'.
Unified to 'id' everywhere.
- No polling: useBacktestResult fired once and never refreshed.
Added refetchInterval that polls every 2s while status is running.
- Response shape: GET endpoint nested results under 'result' object
but frontend expected flat fields. Flattened response to match
BacktestResult type.
- Added running/failed/completed status indicators in BacktestPanel.