- 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>
Prevent race conditions by aborting in-flight requests when a new
request is triggered. Each function now:
- Aborts the previous request via a stored AbortController ref
- Passes signal to all fetch() calls
- Silently discards AbortError in catch blocks
Completes task 7.2.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Guard all four fetch() calls in src/app/page.tsx against non-2xx HTTP
responses by throwing before attempting to parse the body as JSON.
Affected functions: fetchCharts, fetchAnnotations, fetchSpanAnnotations,
fetchSpanLabelTypes.
Marks task 4.11 as completed in code-review-fix/tasks.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add sanitizeCsvCell() helper to both export routes that prefixes cell
values starting with =, +, @, or - with a single quote to prevent CSV
formula injection attacks.
Applied to:
- src/app/api/export/route.ts: timestamp and label_type columns
- src/app/api/span-annotations/export/route.ts: start_time, end_time,
label, and outcome columns
Closes task 4.10.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Import spanAnnotations from schema
- Wrap all delete operations in db.transaction() for atomicity
- Delete spanAnnotations first to satisfy FK constraints, then annotations, candles, chart
- Mark task 4.8 as done in tasks.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reject DELETE ?all=true without chartId with HTTP 400 to prevent
accidental deletion of annotations across all charts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Import z from zod
- Add CandleSchema validating time, open, high, low, close (number), volume (optional number)
- Add PatternDetectRequestSchema validating candles array and patterns array of non-empty strings
- Use safeParse() and return HTTP 400 with error details on validation failure
- Forward only validated data to the inference service
- Mark task 4.5 as completed in tasks.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Validates model_type as a non-empty string using .safeParse(); returns
HTTP 400 with error details on invalid input. Marks task 4.4 as done.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Validate run_id in POST /api/model/load using Zod:
- run_id must be a non-empty string matching /^[a-zA-Z0-9_-]+$/
- Returns HTTP 400 with error details if validation fails
- Validated data is forwarded to the inference service
Marks task 4.3 as complete in tasks.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add BatchPredictRequestSchema with Zod to validate pair, timeframe,
start_date, and end_date fields. Returns HTTP 400 with flattened error
details on invalid input. Forward only validated data to the inference
service.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add CandleSchema validating time, open, high, low, close (number) and optional volume
- Add PredictRequestSchema validating pair (non-empty string), timeframe (non-empty string), candles array
- Use safeParse() and return HTTP 400 with error details on invalid input
- Forward only validated data to the inference service
- Mark task 4.1 as done in tasks.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All 12 Next.js API routes that proxy requests to the ML service
(INFERENCE_API_URL / localhost:8001) now include the X-API-Key header
read from process.env.API_KEY. Affected routes:
- /api/predict
- /api/predict/batch
- /api/model/info
- /api/model/load
- /api/training/start
- /api/training/runs
- /api/training/runs/[run_id] (DELETE)
- /api/training/dataset-info
- /api/training/active
- /api/training/build-dataset
- /api/patterns/available
- /api/patterns/detect
Marks task 3.3 as complete in openspec/changes/code-review-fix/tasks.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Validate filename ends with .csv (case-insensitive)
- Validate MIME type is text/* or application/csv or text/csv
- Return HTTP 400 with error message if validation fails
- Mark task 2.4 as complete
- Reject uploads larger than 10MB before reading file content
- Reject CSVs with more than 500,000 data rows after parsing
- Checks placed as early as possible in the handler flow
- Mark task 2.3 as done in tasks.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Validate that run_id matches /^[a-zA-Z0-9_-]+$ regex before interpolating into the API URL.
Returns HTTP 400 with 'Invalid run_id format' error if validation fails.
This prevents potential URL injection attacks and invalid identifier usage.
- Add build_dataset_from_db() that exports candles from DB, runs feature
engineering, and ingests span annotations into labeled CSV
- Call it automatically in _run_training_background before training starts
- Add POST /training/build-dataset endpoint for standalone use
- Add Next.js proxy route /api/training/build-dataset
- Update TrainingPanel: remove dataset-missing block on Start Training,
show informational message that dataset builds automatically
- Fix SpanAnnotationManager price range calculation: use direct candle
filtering by time range instead of dummy Candle objects that fell back
to 0/0 high/low, causing invisible rectangles
- Add handleDeleteAllAnnotations in page.tsx (deletes all span annotations
and regular annotations for current chart)
- Add 'Delete All Annotations' button in sidebar below TA-Lib panel
- TalibPatternPanel: pattern checkboxes, detect button, results summary, clear-all and per-pattern delete
- TrainingPanel: model type selector, dataset info, start training, polling, run history
- ModelSelector: dropdown of completed runs, wired into PredictionPanel for model switching
- page.tsx: integrate all three panels into sidebar, wire callbacks (model load, annotations refresh)
- tasks.md: mark all 39 tasks complete
- Created scripts/migrate-sqlite-to-postgres.py as alternative to TypeScript version
- Handles all type conversions: timestamps, booleans, and JSONB fields
- Successfully migrated all 2,836 rows from SQLite to PostgreSQL
- Verified data integrity: all 6 tables migrated correctly
- Charts: 1, Candles: 2,592, Annotations: 4, Span annotations: 223
- Replace green hacker theme with professional blue-toned design
- Light theme default, manual toggle only (no system detection)
- Compact w-60 sidebar with collapsible sections
- New CSS tokens: sidebar, chart, candle, annotation colors
- Tools displayed as compact grid buttons
- Color swatches as inline bar
- Chart top bar with keyboard shortcut hints
- Inter + JetBrains Mono font pairing
- All components updated for compact styling
- Tailwind config extended with sidebar/chart tokens
- Implement disagreement visual highlighting with distinct colors
- Yellow highlight for 'missed_by_human' predictions
- Orange for 'label_mismatch' disagreements
- Warning icon on disagreement markers
- Add click-to-convert prediction feedback
- Click disagreement predictions to create span annotations
- Auto-fill with predicted label and times
- Set source as 'model_confirmed' or 'model_corrected'
- Add dismiss action for false positive predictions
- Alt+Click or Ctrl+Click to dismiss predictions
- Saves negative annotation with label 'O'
- Records original prediction in model_prediction field
- Filter predictions when 'Show only disagreements' is enabled
- Add GET handler to /api/charts/[id] route to fetch chart metadata
- Fix batch prediction to use regular /predict endpoint with database candles
- Remove /predict/batch usage (was designed for file-based predictions)
- Make volume field optional in CandleData model (database candles don't have volume)
- Convert timestamps to ISO dates for batch requests
Known issue: TA-Lib indicators failing with 'input array type is not double'
- May need to ensure candle data is float64/double type before processing
- Update TypeScript types to match flat backend response structure
- Remove nested model_info and metrics objects
- Remove label_config, use labels array and per_class_metrics array
- Update all component references to use new structure
- Generate default colors for prediction labels in CandleChart
- Fix TypeScript type errors for nullable model_version
- Remove accuracy/F1 metrics display (not in new response)
- Add disagreement detection logic comparing human annotations vs predictions
- Display prediction summary in PredictionPanel (agreements/disagreements)
- Wire up 'Show only disagreements' filter toggle
- Add loading overlay during prediction fetching
- Update docker-compose.yml with healthchecks for all services
- Update DEPLOYMENT.md with comprehensive ML service setup instructions
- Update README.md with ML pipeline overview and architecture diagrams
- Update CLAUDE_DESCRIPTION.md with v3.0.0 ML integration details
Remaining tasks (11.2, 11.4, 11.5) deferred - core functionality complete
- Add histogram series to CandleChart for per-bar prediction colors (15% opacity)
- Add series markers showing label name and confidence % at prediction span starts
- Implement confidence threshold filtering for both histogram and markers
- Implement label type filtering from PredictionPanel checkboxes
- Implement prediction layer visibility toggle (show/hide)
- Add getVisibleCandles method to CandleChartHandle for on-demand prediction fetching
- Pass prediction state props from page.tsx to CandleChart
Tasks 10.1-10.5 complete.
- Create prediction type definitions in src/types/predictions.ts
- Add prediction state management to page.tsx with caching
- Implement PredictionPanel component with:
- Master visibility toggle
- Model info display (name, version, type, metrics)
- Action buttons (Run on Visible, Predict All)
- Confidence threshold slider
- Label filter checkboxes with per-class metrics
- Disagreement filter toggle
- Prediction summary display
- Model server offline banner
- Add on-demand and batch prediction fetching
- Implement prediction caching by chart and model version
- Add health polling for inference API (30s interval when offline)
- Ensure annotation tools work independently of prediction API
Tasks completed: 9.1-9.5, 12.1-12.3 (59/78 total)
- Add GET /api/span-annotations/export endpoint for ML pipeline JSON/CSV export
- Add source and model_prediction fields to span_annotations schema
- Update POST endpoint to accept source (human/model/human_correction) and model_prediction metadata
- Support negative annotations (label 'O' for user corrections to model predictions)
- Create migration 0005 for new schema fields
Completes tasks 8.1-8.4 of candle-backend change
- Add SpanAnnotation and SpanLabelType interfaces to page.tsx
- Add span-related state: spanAnnotations, selectedSpanId, spanLabelTypes
- Add fetchSpanAnnotations() and fetchSpanLabelTypes() data fetching functions
- Load span annotations and label types when chart changes
- Add "Span" tool button to Toolbox component with RectangleHorizontal icon
- Mark Section 5 tasks (5.1-5.5) as complete in tasks.md
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>