Replace section-level model tags with individual task-level tags.
Haiku for mechanical/config/boilerplate, sonnet for standard feature
work, opus for 2.5 (data migration backfill) and 7.2 (user_id query
permeation across all routes).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Synced 14 capability delta specs to main specs
- Created 6 new main specs: api-authentication, error-boundary, input-validation, security-headers, shared-types
- Updated 8 existing specs with security, validation, and performance requirements
- Archived change to openspec/changes/archive/2026-02-20-code-review-fix/
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
src/types/predictions.ts already existed with PredictionSpan, PredictionState, and ModelInfoResponse interfaces matching actual usage across page.tsx, CandleChart.tsx, and PredictionPanel.tsx.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Creates src/types/annotations.ts with typed interfaces matching actual
usage in CandleChart.tsx, page.tsx, and DB schema. Marks task 9.2 done.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add shared Candle interface with time, open, high, low, close, and
optional volume fields. Volume is optional because the DB schema does
not store volume but the predict/patterns API routes accept it as an
optional field.
Mark task 9.1 as complete in tasks.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the hardcoded 60-second assumption in CandleChart.tsx with
dynamic interval detection: compute interval as candles[1].time -
candles[0].time when at least 2 candles are available, fall back to
60 otherwise. Used for span-to-prediction-time mapping iteration.
Marks task 8.6 as done in tasks.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Before inserting into predictionCacheRef, check if size >= 100
- If so, evict oldest entry via cache.keys().next().value (FIFO)
- Applied at both cache write sites (lines ~549 and ~671 in page.tsx)
- Marks task 8.5 as done in tasks.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Separate the single reconciliation effect into:
1. Full reconciliation effect — runs only when spanAnnotations list,
series, chart, or candles change. Rebuilds all primitives.
2. Selection-only effect — runs only when selectedSpanId changes.
Calls setSelected() on existing primitives instead of detaching
and reattaching all of them.
This avoids tearing down and rebuilding every primitive on each
selection change, which was the main unnecessary overhead.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Move chart.timeScale().fitContent() out of the span annotation reconciliation
effect (which ran on every annotation/selection change) into a dedicated effect
guarded by a hasInitializedRef, so it fires only once when chart and series
first become available.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>