Final code review of the configurable-data-export feature: ExperimentDetail
was forwarding its on-page groupField state (defaults to '__name__') into
ExportDataModal, leaking a clustering default into the default (untouched)
export. Now passes the raw saved localStorage value, defaulting to
'__none__'. The modal also now validates the incoming groupField against
'__none__'/'__name__'/'__id__'/active subjectTemplate fields and coerces to
'__none__' otherwise, guarding against stale/deleted subject_info fields.
Plus a stale module comment fix and optional-chaining consistency fix in
listSubjectMembers.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Client-side CSV export on the experiment page: pick a daily parameter
(session metrics or any daily-record field) and download a date×subject matrix.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replaces "+ New category" with a Note/Numerical type-aware picker, extends
CategoryBucket to render type badges, bulk-add, and custom-bucket remove controls,
and deletes the addCategory() back-compat shim from Task 7.
Implement TDD for new route that accepts CSV configuration with validated buckets.
Route uses auditMiddleware to log config changes and delegates validation to
validateCsvConfig helper from Task 2.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- AnalysisSummaryCard gains an "Edit manually" affordance powered by
the new ManualMetricsForm (add/remove categories, edit counts,
recompute total + success rate).
- New PastAnalysesViewer renders a tab-style selector of saved CSV
analyses with an inline AnalysisResultsView panel.
- Reorganizes the page so the manual-metrics path is reachable when no
analysis_summary exists yet.
- Sync package-lock to the recharts ^2.15.4 already declared in package.json.
12-task TDD plan covering DB backup, schema migration, backend
PATCH endpoint with validator, frontend lib helpers (extractNumber,
computeNumericSeries), CsvAnalysis state refactor, type-aware field
picker, numerical plot rendering, and per-animal config persistence.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Spec for adding a numerical bucket type to CSV analysis that plots
note values (numeric portion) against frame/timestamp, persisted on
the Animal model so subsequent uploads reuse the configuration.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
New file tests/experimentDailyStatuses.test.js — 9 tests covering
GET /api/experiments/:id/daily-statuses:
- 404 on unknown experiment
- all statuses returned when no filter
- analysisOnly=true keeps only non-null analysis_summary records
- analysisOnly=true returns [] when none have analysis_summary
- the exact null/object mix that caused the production 500 now passes
- analysisOnly=false (explicit) returns all records
- ?date= param is forwarded to Prisma correctly
- empty-array response on zero statuses
- returned records include expected fields
Fixed tests/calendar.test.js: existing tests were silently broken by the
cache added in the perf commit. Both test files now mock lib/cache to
always miss, so each test exercises the real route logic in isolation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prisma 5 rejects both null and Prisma.DbNull as WHERE filter values for
Json? fields (no clean IS NOT NULL operator). Filter the result array in
JS after the query — the output is immediately cached so this only runs
once per cache period.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prisma 5 rejects JS null as a where-clause value on Json? fields.
Use Prisma.DbNull (SQL NULL sentinel) so the NOT filter compiles correctly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each chart card now has a "▾ customize" button. Clicking it reveals a
settings bar (only rendered when active — zero cost when collapsed):
Size — S / M / L height selector
Y range — min / max inputs to set the YAxis domain
X zoom — min / max inputs to clip the displayed X domain
X data — per-chart X field override, independent from the shared
global X selector (each chart can use a different field)
Y lines — (counts chart only) toggle individual category lines on/off
↺ Reset — shown only when any setting has been changed from default
The global X-axis selector and tick-step control remain at the component
level as the persistent defaults. Per-chart overrides are session-only
(non-persistent), resetting on page load.
Performance: animalRows computation in ExperimentAnalysisCharts is now
split from the per-chart data step, so a metric/X change only recomputes
the affected chart. Per-chart data only recomputes when that chart's
xFieldOverride changes; shared data is reused otherwise.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>