Releases: sidxz/cellar
Releases · sidxz/cellar
Release list
Frontend v1.2.0
Bug Fixes
- Address whole-branch review findings (frontend) (campaigns)
- Keep the stage criterion readout select inside its column (screen-campaign)
- Top-align the stage criterion row labels (screen-campaign)
- Surface domain error messages in toasts; verdict chip on its own line (frontend)
- Filter-bar separator, compound column width, dead source DTOs (screen-campaign)
- Compound activity tab shows reported endpoints for curve-less dose-response readouts (activity)
- Colliding stage_name is an advisory, not a block (screen-campaign)
- Bulk gestures act only on rows the chip filter shows (screen-campaign)
- StageKind aliases the generated enum (screen-campaign)
- Depict renders again, and every campaign write answers 204 (api)
- Reopening the delete dialog refetches, and blocked deletes stay accessible (admin)
- Unique wells in the plate trace, no filter, warm surface (login)
- Library rows use the 14px list size like every other list (protocols)
- Clear every fixable high and critical Trivy finding (security)
Features
- Structure role in the summary wizard; both import wizards render the shared result vocabulary (frontend)
- Regenerate FE types for hit stages, drop retired hit/signature/publish fields (campaigns)
- Hit stages section and stage editor (frontend) (campaigns)
- Stage lens — outcome chips, cell verdicts, Stage column, override popover (campaigns)
- Close/reopen dialogs, header, stages preview, save-as-stage (screen-campaign)
- Compact readout chips, funnel stage tiles, per-protocol colors (screen-campaign)
- Tags as a compact chip row under the description (screen-campaign)
- Colored sidebar icons carried into page headers; persist sidebar collapse (nav)
- Refuse direct entry onto calculated readouts across summary, plate and bulk paths (screening)
- Compound page and search fall back to reported endpoints for dose-response columns; reported markers (activity)
- Manual stages, pending outcome, bulk promote/demote and bulk remove (screen-campaign)
- Summary-driven campaign list with status filter, stage parent on import dialogs, readout reorder (screen-campaign)
- Per-readout "resolve from all runs" opt-out (screen-campaign)
- Page and filter a campaign's results server-side (campaigns)
- Offer the maximum common substructure as a core, never pick it (sar)
- Let the results filter take several outcomes (campaigns)
- Show a campaign's libraries and what it left unread (campaigns)
- Show hits per stage under each library's coverage bar (campaigns)
- Hold back the per-library stage lines in cellar's UI (campaigns)
- Hide the Libraries section itself, not just its stage lines (campaigns)
- A draft's creator may delete it, and no delete while anything still uses it (protocols)
- Force-delete dialog lists what blocks or changes, and won't submit a blocked delete (admin)
- Lime accent from the product site, flat logo mark (theme)
- Live screening plate with a glowing dose-response hit (login)
Refactor
- Drop decision UI; notes column; stage picker for add-from-campaign (screen-campaign)
- Export isReportedEndpoint so the grid's own line is tested (campaigns)
- Render the shared chart core, drop the local copy (dose-response)
Backend v1.2.0
Bug Fixes
- Import result counts are required on the wire (screening)
- Report the compound ref too when both refs miss (both importers) (screening)
- Structure fallback applies to compound-only rows; import total_rows regression test (screening)
- Serialize number minting per workspace; surface constraint violations as 409 (registration)
- Enforce one live molecule per InChIKey per workspace in the database (registration)
- Remove per-cell hit call and per-readout hit threshold (campaigns)
- Address whole-branch review findings (backend) (campaigns)
- Require notes key on PATCH, normalise blank notes to NULL (campaigns)
- Single-row readout create follows the run's shape (screening)
- Curve-class filter on add-from-runs applies to curves only, not endpoint fallbacks (campaigns)
- Compound activity tab shows reported endpoints for curve-less dose-response readouts (activity)
- Reported-endpoint fallback reads well-less rows only (activity)
- Add-from-runs preview and commit share one candidate resolver (campaigns)
- Drc reported-endpoint fallback only fires on unscoped columns (search)
- Refuse the summary header preview onto a welled run (screening)
- Empty result_ids on bulk-remove is a 422 (campaigns)
- Break display_order ties on id; tighten stage/bulk-remove DTOs (campaigns)
- Campaign records its seed runs; resolution scope is per channel protocol (campaigns)
- Depict renders again, and every campaign write answers 204 (api)
- An ND that came off a curve is a miss, not untested (campaigns)
- A reported endpoint keeps its qualifier and fills only its own intercept (campaigns)
- A censored value that can't prove a criterion is a miss (campaigns)
- A reported ">=40" stays censored instead of reading as 40 (campaigns)
- Apply every null before any delete so id-only references stay FK-safe (admin)
- Clear every fixable high and critical Trivy finding (security)
Documentation
- Correct rule-module docstrings and record final-review findings (admin)
Features
- STRUCTURE role on the summary-import mapping + SMILES header inference (screening)
- Summary planner falls back to SMILES when the identifier misses; per-row unmatched_compounds (screening)
- Summary preview/import resolve by structure on identifier miss; import result carries the shared vocabulary (screening)
- One result vocabulary for import preview/import responses; structure on the summary mapping (screening)
- Plate preview/import speak the shared result vocabulary; rows_skipped on the plate preview (screening)
- Add hit-stage value objects and shared compare() (campaign)
- Wire hit stages and overrides into the Campaign aggregate (campaign)
- Pure stage evaluator (evaluate_stages, tally_stage_counts) (campaigns)
- ORM models, repository mapping, and migration 074 for hit stages (campaigns)
- Soft close — drop signature/collection, add reopen (campaigns)
- Migration 075 — drop retired hit/publish columns (campaigns)
- Published JSON gains stages and per-result stage outcomes (campaigns)
- Stage use cases, routes, and DTOs (campaigns)
- Stage_name on run import and mirror protocol (campaigns)
- Stage override use case, DTOs, and API routes (campaigns)
- Refuse direct entry onto calculated readouts across summary, plate and bulk paths (screening)
- One run, one shape — refuse summary import onto welled runs and plate paths onto well-less runs (screening)
- Dose-response channels fall back to reported endpoint rows when no curve survives QC (campaigns)
- Compound page and search fall back to reported endpoints for dose-response columns; reported markers (activity)
- Manual stage kind with a pending outcome (campaigns)
- Bulk stage overrides and bulk row removal (campaigns)
- Parent_stage_id and get-or-create on the stage_name paths (campaigns)
- Stage counts on the draft read, summary endpoint, list summaries with status filter; viewer gate, channel reorder, stable result order (campaigns)
- Resolution honours the campaign's source runs, with a per-readout opt-out (campaigns)
- Maximum common substructure over a supplied molecule set (sar)
- Page and filter a campaign's results server-side (campaigns)
- Offer the maximum common substructure as a core, never pick it (sar)
- Let the results filter take several outcomes (campaigns)
- Name the libraries a campaign screened, and how much it read (campaigns)
- Count each library's compounds through the campaign's stages (campaigns)
- A draft's creator may delete it, and no delete while anything still uses it (protocols)
- Cascade rules express references with or without a column (admin)
- One exhaustive plan walk behind force-delete preview and execute (admin)
- Tier-1 hard delete refuses on cascade-rule references too (admin)
- Force delete refuses on campaigns and import templates, removes flags and attachments (admin)
- Molecule force delete refuses while its data or open work remains (admin)
- Export/import a full local environment as a bundle (replication)
Refactor
- Remove per-result decisions; notes-only edit; add-from-campaign filters by stage (campaigns)
Tests
- Reformat API test helpers after merge (campaigns)
- Drop stale CV- registration-prefix assertion (molecules)
- Bulk upsert writes a well-bound row on a welled run (screening)
- Cover the bulk routes' reason and closed-campaign guards (campaigns)
- Guard that every id reference says what a force delete does to it (admin)
- Guard tests only count rules that actually stop an FK violation (admin)
Frontend v1.1.0
Bug Fixes
- Unit affordance, stale seed shape, and null-sort fixes on the any-protocol UI (search)
- Pre-merge review follow-ups on preview, wizard forecast, and storage probe
Build & CI
- Duar SDKs 1.0.0 -> 1.3.0; refresh all in-range Python and npm deps (deps)
Features
- "Any protocol" activity criterion — curve class + potency cutoff across all protocols (search)
- Derive the any-protocol where-picker from every protocol's measurements (search)
- Any-protocol rows use the derived measurement catalog (search)
- 'Active in' results column for any-protocol searches; matched protocols expand in the detail sheet (search)
- Surface summary-import attachment and molecule provenance (frontend)
- Bulk-registration preview forecasts what each row will do (frontend)
Backend v1.1.0
Bug Fixes
- Tenant-scope + normalization-layer fixes on the any-protocol activity query (search)
- Review follow-ups on the declared disclosure date (disclosure)
- Every file write hangs off STORAGE_ROOT; refuse to boot prod off a volume (storage)
- Pre-merge review follow-ups on preview, wizard forecast, and storage probe
Build & CI
- Duar SDKs 1.0.0 -> 1.3.0; refresh all in-range Python and npm deps (deps)
Features
- "Any protocol" activity criterion — curve class + potency cutoff across all protocols (search)
- Any-protocol dr_curve conditions accept an intercept_key (IC50/EC90 across protocols, µM) (search)
- Any-protocol readout_data conditions match readout-defs by normalized name + unit (search)
- 'any' activity column — per-protocol DR entries, native units, best first (search)
- 'any' column adds readout entries for readout groups named in the criterion (search)
- 'any' activity column exports as one 'Active in' text column (export)
- Attach the raw upload to the run on summary import (screening)
- Scientist_name on POST /molecules, persisted on the molecule (registration)
- Settable disclosure_date on POST /disclosures (disclosure)
- Declared disclosure_date through POST /molecules (registration)
- Shared classifier + advisory POST /molecules/preview-registration (registration)
- Refuse to start against a database that is not at this image's migration head (ops)
Tests
- Any-protocol intercept-key and readout-name searches against Postgres (api)
Frontend v1.0.0
Bug Fixes
- Close frontend-backend gap — all APIs now have UI coverage
- Review fixes — remove ghost operator field, guard log10(0), fix retire reason type (S31-S32)
- Replace UUID text inputs with compound/batch selectors (GF04)
- Add CSV template downloads and use human-readable columns in imports
- Serve RDKit WASM from public/ — fixes streaming compile error (GF02)
- Show error states instead of infinite skeletons when backend is down
- Dynamic CSV templates — protocol-aware readout, multi-ID compounds
- Show multiple custom_id columns in CSV template
- Readout data table shows compound names and measurement names, not UUIDs
- Pivot readout data table — definitions as columns, one row per compound
- Root-cause fixes — server-side identifier resolution, search-based selector
- Replace window.location.href/history.back with Next.js router
- Add storage location dropdown to create sample dialog
- Replace raw UUID inputs with entity selectors (S26)
- Replace empty-string SelectItem values with sentinel strings
- Replace UUID displays with entity names + fix assign 401
- Eliminate all UUID displays from new inventory UI
- Add link to manage synthesis routes from Start dialog
- Redesign shipment creation with compound-first workflow
- Widen dialogs globally — default max-w-2xl (672px)
- Search results — emerald colors + structure depiction cards
- Stringify nested objects in Excel export to prevent [object Object] (export)
- Reset editorOpen state in form reset functions, remove redundant cast
- Enlarge structure thumbnails in compound list (40px → 80px)
- Replace empty string SelectItem values with sentinel in plate components
- Enlarge well mapping dialog + add import template management UI
- Well mapping dialog — 80vw/85vh, CSV paste/upload, download template
- Resolve UUID displays to human-readable names in plate UI
- Well mapping dialog — ResizeObserver-based square cell grid
- CustomInstance FormData support + clarify import wizard purpose
- Import wizard end-to-end — type alignment, UoW, FormData upload
- Move useCallback above early returns in CollectionDetail
- Remove stray 's' from API endpoint URLs (attachment)
- Replace UUID input with MemberSelector search-by-name (project-scoping)
- Vault mapper field names, pagination, dialog scroll, and caching
- Map external description/category, fix 204 JSON parse, pagination
- Ontology annotation PUT sends 'slot' not 'slot_name'
- Ontology_annotations is a dict not array on Protocol type
- Add cascade selection guidance to inventory dashboard (ui)
- Use Zustand store for breadcrumb overrides instead of context (ui)
- Only make breadcrumb segments clickable if page exists (ui)
- Restore Saved Searches to sidebar navigation (ui)
- Show compound names in dose-response chart legend and cards (ui)
- Add Edit Points toggle, compound names on constraints, round IC50 values (ui)
- Guard against undefined plateMap.wells in run data panel (ui)
- Make readout_data molecule_id/batch_id nullable in API + frontend
- Validate batch amount required when include batch is toggled on
- Resolve chemist UUID to display name on batch detail page
- Review fixes — zero-value data points, shared helper, actual top/bottom, sorted query key
- Excel export now uses getCellValue to respect valueGetter columns
- Readout data table shows per-well rows for dose-response data
- Excel export — plain headers, CV ID in Compound, custom-only synonyms
- Excel export fills existing Structure/Curve columns with images
- Marker toggle label uses actual curve type (IC50/EC50/Ki/etc)
- Restore integration client naming — only docs/commits are sanitized
- Clean up collection criterion types and unused imports in search form
- Search revamp frontend bugs — protocol columns, 4PL div-by-zero, config safety, cursor jumps
- Code review fixes — updated_at propagation, null visibility, grid selection sync, hook lift
- Replace hardcoded colors with semantic design tokens
- Simplify ProtocolSection — remove dead dropdowns, unify readout/curve selector
- Wire protocol and/or conjunctions to actual search query
- DR chart not rendering — raw_data keys were concentration/response, not x/y
- Persist protocol conjunctions in saved searches + support mixed AND/OR
- Remove placeholder tabs, fix scroll, open detail in new tab
- Saved search loading stuck on skeleton — remove handleSearch from useEffect deps
- Derive protocol curve types from readout definitions instead of hardcoding
- Restore lost backend changes + commit all pending work
- Restore DR curve plots in search results grid
- Breadcrumb trail system — fix duplicate Protocols and missing protocol on runs
- Remove AG Grid Enterprise rowGroup from collection list
- Disclosure mode uses disclosure endpoint, not registration
- Add disclosure provenance fields + confirmation before submit
- Remove explicit Content-Type for FormData + fix status poll URL
- Saved-search load stuck on skeleton — inline mutation (search)
- Infinite loop from mutation deps in reset() (run-import-wizard)
- Upgrade confidence to High when header exactly matches a readout-def name (import-wizard)
- Widen dialog so the mapping table fits without horizontal scroll (import-wizard)
- Widen all protocol-related dialogs to remove horizontal scroll (protocol-ui)
- Accept signal + nullable params in customInstance (frontend)
- Reliably pre-load SMILES into Ketcher edit dialog (chemistry)
- Re-resolve preview when chemist refines column mapping (screening)
- Readable amber text on light mode for run import panels (ui)
- Disclosure path sets batch_skipped=false (types)
- Place campaigns route under existing [id] segment (fe)
- Persist result notes from decision panel
- Show registration_number in compound-list pane (fe)
- Use backend enum values for source_kind (fe)
- Align all campaign enums with backend StrEnum values (fe)
- Never display UUIDs to users — breadcrumbs, sources, fallbacks (fe)
- Edit-channel popover — add hit threshold, hide non-editable fields, tidy QC (fe/campaign)
- Radix Select rejects empty-string item values — use "none" sentinel (fe/campaign)
- Require projectId on add-dialogs (spec contract) (fe/campaign)
- SourcesSection empty-state + SourceEntry + remove callback (fe/campaign)
- MeasurementToActivity readout uses replicate_count for point count (fe/campaign)
- Re-export useCampaignCurves + tighten enabled guard (fe/campaign)
- Final review polish + Phase 5 handoff update (fe/campaign)
- +Channel popover pre-fills hit criteria from protocol recommendations (fe/campaign)
- Friendly run label in Sources — protocol name + run date instead of UUID prefix (campaign)
- Show channel unit on hit threshold + spell out the comparison (campaign/import)
- Explicit Save / Cancel buttons on the description editor (campaign)
- Description itself is the edit target — drop the corner-floating pencil (campaign)
- Decision popover only saves on Save — no more auto-save mid-edit (campaign)
- Published collection uses campaign name + sign-time publish toggle (campaign/close)
- Closed-meta line resolves user name and hides signature UUID (campaign)
- Fold "N results" into the filter bar, drop the empty toolbar row (campaign)
- Drop TautomerEnumerator + populate stereo classification; rename chem_vault → cellar (registration)
- Address Phase 1 code review feedback (shared)
- Address Phase 2 review — migrate inventory-dashboard tabs, fix lifecycle variant (frontend)
- Drop redundant server-state sync into Zustand store (registration)
- Replace state-sync effects with derived values (frontend)
- Replace imperative DOM/window APIs with proper React patterns (frontend)
- Handle PageResult shape in bespoke list hooks + regen api (frontend)
- IC90/EC90 marker Y position needs level/100 (screening)
- Detail drawer Selected Protocols card missing on DR rows (search)
- Multi-intercept channels — proper cells, hits, labels (campaign)
- Closed view defaults filter to Selected only (campaign)
- ND / >max cells sort to where a chemist expects them (screening)
- Grid value cell renders ND uppercase, tooltip + sort honest (campaign)
- Download via authed fetch — drops the bearer token (export)
- Ready toast — Download action + close icon, no stale Cancel (export)
- V1 smoke — card grid ref timing + dup heading + table density (collections)
- Expose is_frozen + derived_from_campaign_id on API (collections)
- Split-pane layout — string sizes (percent) + explicit height (scaffold-tree)
- Drop SMILES text + bump thumbnail to 80px (scaffold-tree)
- See the FULL collection, not just the visible page (scaffold-tree)
- Relax pagination cap for {type:'collection'} queries (search)
- Split handoffs into prepare + fire effects to fix soft-nav stale-mutation bug (search)
- Cluster-map sends collectionId XOR moleculeIds (was sending both) (sar)
- Cluster scatter hover shows reg_number/name, not UUID (sar)
- Picker/N/threshold changes wait for Diversify, no auto-refetch (sar)
- Lasso uses Plotly's selected points directly + lasso wins over reps (sar)
- Lasso resolves IDs via pointNumber index; SVG trace ≤5K (scattergl selection unreliable) (sar)
- Star markers use amber fill (SVG scatter ignored the transparent fill) (sar)
- Star fill = cluster color (per-rep chemotype palette + dark outline) (sar)
- Star size 18→12 (closer to base dot size; thinner outline) (sar)
- Polling reads {result,job} shape from GET (was treating it as flat UmapJobDto, never recognized ready) (sar)
- NO_SCAFFOLD bucket falls back to in-memory filter (not exact_match_in) (sar)
- DR point counter reflects all exclusion sources (screening)
- Align FE/BE idx domain for DR point editing (screening)
- Collection-import wizard UX — loading state + breadcrumb + row input + top commit button (frontend)
- Stop UMAP cluster poll storm + bound selection pane (sar_analysis)
- Bulk-registration summary renders its results (chemical_registration)
- Lasso resolves ids via data-space polygon (scatter + scattergl) (sar_analysis)
- Keep 'Diversify...
Frontend v0.1.0
Bug Fixes
- Close frontend-backend gap — all APIs now have UI coverage
- Review fixes — remove ghost operator field, guard log10(0), fix retire reason type (S31-S32)
- Replace UUID text inputs with compound/batch selectors (GF04)
- Add CSV template downloads and use human-readable columns in imports
- Serve RDKit WASM from public/ — fixes streaming compile error (GF02)
- Show error states instead of infinite skeletons when backend is down
- Dynamic CSV templates — protocol-aware readout, multi-ID compounds
- Show multiple custom_id columns in CSV template
- Readout data table shows compound names and measurement names, not UUIDs
- Pivot readout data table — definitions as columns, one row per compound
- Root-cause fixes — server-side identifier resolution, search-based selector
- Replace window.location.href/history.back with Next.js router
- Add storage location dropdown to create sample dialog
- Replace raw UUID inputs with entity selectors (S26)
- Replace empty-string SelectItem values with sentinel strings
- Replace UUID displays with entity names + fix assign 401
- Eliminate all UUID displays from new inventory UI
- Add link to manage synthesis routes from Start dialog
- Redesign shipment creation with compound-first workflow
- Widen dialogs globally — default max-w-2xl (672px)
- Search results — emerald colors + structure depiction cards
- Stringify nested objects in Excel export to prevent [object Object] (export)
- Reset editorOpen state in form reset functions, remove redundant cast
- Enlarge structure thumbnails in compound list (40px → 80px)
- Replace empty string SelectItem values with sentinel in plate components
- Enlarge well mapping dialog + add import template management UI
- Well mapping dialog — 80vw/85vh, CSV paste/upload, download template
- Resolve UUID displays to human-readable names in plate UI
- Well mapping dialog — ResizeObserver-based square cell grid
- CustomInstance FormData support + clarify import wizard purpose
- Import wizard end-to-end — type alignment, UoW, FormData upload
- Move useCallback above early returns in CollectionDetail
- Remove stray 's' from API endpoint URLs (attachment)
- Replace UUID input with MemberSelector search-by-name (project-scoping)
- Vault mapper field names, pagination, dialog scroll, and caching
- Map external description/category, fix 204 JSON parse, pagination
- Ontology annotation PUT sends 'slot' not 'slot_name'
- Ontology_annotations is a dict not array on Protocol type
- Add cascade selection guidance to inventory dashboard (ui)
- Use Zustand store for breadcrumb overrides instead of context (ui)
- Only make breadcrumb segments clickable if page exists (ui)
- Restore Saved Searches to sidebar navigation (ui)
- Show compound names in dose-response chart legend and cards (ui)
- Add Edit Points toggle, compound names on constraints, round IC50 values (ui)
- Guard against undefined plateMap.wells in run data panel (ui)
- Make readout_data molecule_id/batch_id nullable in API + frontend
- Validate batch amount required when include batch is toggled on
- Resolve chemist UUID to display name on batch detail page
- Review fixes — zero-value data points, shared helper, actual top/bottom, sorted query key
- Excel export now uses getCellValue to respect valueGetter columns
- Readout data table shows per-well rows for dose-response data
- Excel export — plain headers, CV ID in Compound, custom-only synonyms
- Excel export fills existing Structure/Curve columns with images
- Marker toggle label uses actual curve type (IC50/EC50/Ki/etc)
- Restore integration client naming — only docs/commits are sanitized
- Clean up collection criterion types and unused imports in search form
- Search revamp frontend bugs — protocol columns, 4PL div-by-zero, config safety, cursor jumps
- Code review fixes — updated_at propagation, null visibility, grid selection sync, hook lift
- Replace hardcoded colors with semantic design tokens
- Simplify ProtocolSection — remove dead dropdowns, unify readout/curve selector
- Wire protocol and/or conjunctions to actual search query
- DR chart not rendering — raw_data keys were concentration/response, not x/y
- Persist protocol conjunctions in saved searches + support mixed AND/OR
- Remove placeholder tabs, fix scroll, open detail in new tab
- Saved search loading stuck on skeleton — remove handleSearch from useEffect deps
- Derive protocol curve types from readout definitions instead of hardcoding
- Restore lost backend changes + commit all pending work
- Restore DR curve plots in search results grid
- Breadcrumb trail system — fix duplicate Protocols and missing protocol on runs
- Remove AG Grid Enterprise rowGroup from collection list
- Disclosure mode uses disclosure endpoint, not registration
- Add disclosure provenance fields + confirmation before submit
- Remove explicit Content-Type for FormData + fix status poll URL
- Saved-search load stuck on skeleton — inline mutation (search)
- Infinite loop from mutation deps in reset() (run-import-wizard)
- Upgrade confidence to High when header exactly matches a readout-def name (import-wizard)
- Widen dialog so the mapping table fits without horizontal scroll (import-wizard)
- Widen all protocol-related dialogs to remove horizontal scroll (protocol-ui)
- Accept signal + nullable params in customInstance (frontend)
- Reliably pre-load SMILES into Ketcher edit dialog (chemistry)
- Re-resolve preview when chemist refines column mapping (screening)
- Readable amber text on light mode for run import panels (ui)
- Disclosure path sets batch_skipped=false (types)
- Place campaigns route under existing [id] segment (fe)
- Persist result notes from decision panel
- Show registration_number in compound-list pane (fe)
- Use backend enum values for source_kind (fe)
- Align all campaign enums with backend StrEnum values (fe)
- Never display UUIDs to users — breadcrumbs, sources, fallbacks (fe)
- Edit-channel popover — add hit threshold, hide non-editable fields, tidy QC (fe/campaign)
- Radix Select rejects empty-string item values — use "none" sentinel (fe/campaign)
- Require projectId on add-dialogs (spec contract) (fe/campaign)
- SourcesSection empty-state + SourceEntry + remove callback (fe/campaign)
- MeasurementToActivity readout uses replicate_count for point count (fe/campaign)
- Re-export useCampaignCurves + tighten enabled guard (fe/campaign)
- Final review polish + Phase 5 handoff update (fe/campaign)
- +Channel popover pre-fills hit criteria from protocol recommendations (fe/campaign)
- Friendly run label in Sources — protocol name + run date instead of UUID prefix (campaign)
- Show channel unit on hit threshold + spell out the comparison (campaign/import)
- Explicit Save / Cancel buttons on the description editor (campaign)
- Description itself is the edit target — drop the corner-floating pencil (campaign)
- Decision popover only saves on Save — no more auto-save mid-edit (campaign)
- Published collection uses campaign name + sign-time publish toggle (campaign/close)
- Closed-meta line resolves user name and hides signature UUID (campaign)
- Fold "N results" into the filter bar, drop the empty toolbar row (campaign)
- Drop TautomerEnumerator + populate stereo classification; rename chem_vault → cellar (registration)
- Address Phase 1 code review feedback (shared)
- Address Phase 2 review — migrate inventory-dashboard tabs, fix lifecycle variant (frontend)
- Drop redundant server-state sync into Zustand store (registration)
- Replace state-sync effects with derived values (frontend)
- Replace imperative DOM/window APIs with proper React patterns (frontend)
- Handle PageResult shape in bespoke list hooks + regen api (frontend)
- IC90/EC90 marker Y position needs level/100 (screening)
- Detail drawer Selected Protocols card missing on DR rows (search)
- Multi-intercept channels — proper cells, hits, labels (campaign)
- Closed view defaults filter to Selected only (campaign)
- ND / >max cells sort to where a chemist expects them (screening)
- Grid value cell renders ND uppercase, tooltip + sort honest (campaign)
- Download via authed fetch — drops the bearer token (export)
- Ready toast — Download action + close icon, no stale Cancel (export)
- V1 smoke — card grid ref timing + dup heading + table density (collections)
- Expose is_frozen + derived_from_campaign_id on API (collections)
- Split-pane layout — string sizes (percent) + explicit height (scaffold-tree)
- Drop SMILES text + bump thumbnail to 80px (scaffold-tree)
- See the FULL collection, not just the visible page (scaffold-tree)
- Relax pagination cap for {type:'collection'} queries (search)
- Split handoffs into prepare + fire effects to fix soft-nav stale-mutation bug (search)
- Cluster-map sends collectionId XOR moleculeIds (was sending both) (sar)
- Cluster scatter hover shows reg_number/name, not UUID (sar)
- Picker/N/threshold changes wait for Diversify, no auto-refetch (sar)
- Lasso uses Plotly's selected points directly + lasso wins over reps (sar)
- Lasso resolves IDs via pointNumber index; SVG trace ≤5K (scattergl selection unreliable) (sar)
- Star markers use amber fill (SVG scatter ignored the transparent fill) (sar)
- Star fill = cluster color (per-rep chemotype palette + dark outline) (sar)
- Star size 18→12 (closer to base dot size; thinner outline) (sar)
- Polling reads {result,job} shape from GET (was treating it as flat UmapJobDto, never recognized ready) (sar)
- NO_SCAFFOLD bucket falls back to in-memory filter (not exact_match_in) (sar)
- DR point counter reflects all exclusion sources (screening)
- Align FE/BE idx domain for DR point editing (screening)
- Collection-import wizard UX — loading state + breadcrumb + row input + top commit button (frontend)
- Stop UMAP cluster poll storm + bound selection pane (sar_analysis)
- Bulk-registration summary renders its results (chemical_registration)
- Lasso resolves ids via data-space polygon (scatter + scattergl) (sar_analysis)
- Keep 'Diversify...
Backend v1.0.0
Bug Fixes
- Green up backend lint, unit, and integration jobs (ci)
Tests
- Remove tautological tests that only echo source literals
Bug Fixes
- User preferences — proper DDD layers, no architecture violations
- Security + architecture review — 8 findings resolved
- Architectural review — 7 findings resolved
- Architectural review — 3 findings resolved
- Architectural review — workspace isolation, DDD, security (11 findings)
- Protocol versioning — parent stays active until new version published
- Root-cause fixes — server-side identifier resolution, search-based selector
- Correct model import paths in dashboard route and disclosure repo
- Schema hardening + disclosure/merge atomicity
- Skip name-to-identifier promotion for auto-generated names
- Add missing guard checks across use cases
- Lazy Sentinel init so interface layer imports don't crash
- Replace None auth fallback with reject-all stub
- Replace UUID displays with entity names + fix assign 401
- Architectural review — workspace isolation + persistence gaps
- Columns type to dict[str, Any], add_molecules/remove_molecules return int (research-org)
- Clean architecture fix — move query composer to infra, add repo method (search)
- Find_collections_containing returns Collection objects per Protocol
- Rename protocol_id/run_id to project_id/template_id on RegisteredPlate
- Add batch validation on MapWells + PlateTemplate delete guard
- MapWells accepts batch numbers (CV-00001-001), not just UUIDs
- Import wizard end-to-end — type alignment, UoW, FormData upload
- Rename AddMoleculesBody.refs → references to match frontend contract
- Add UoW to list use cases — missing async context manager (t10)
- Clean architecture violations in vault import — move errors to app layer, catch timeout
- Correct WorkspaceSettings types and vault import use case UoW handling
- Handle legacy {} values in workspace_settings columns
- Vault mapper field names, pagination, dialog scroll, and caching
- Map external description/category, fix 204 JSON parse, pagination
- Filter external calculation outputs, map description/category, fix 204
- Move PlateFormat to shared kernel to fix bounded context independence
- Show compound names in dose-response chart legend and cards (ui)
- Clamp R² to [0, 1] in both fitting passes (infra)
- Make readout_data molecule_id/batch_id nullable in API + frontend
- Batch numbering uses molecule reg number prefix (CV-00001-001)
- Serialize recommended_hit_criteria in ProtocolResponse
- Remove is_computed filter + add n/sd to numeric readout aggregation
- Review fixes — zero-value data points, shared helper, actual top/bottom, sorted query key
- Fit-curves endpoint calls FitDoseResponseCurves directly
- Activity summary includes compounds with DR curves but no readout data
- Normalize top > bottom in curve fitter output
- Compute R² and classify before top/bottom swap in curve fitter
- Commit UoW after fitting curves in standalone mode
- Excel export — plain headers, CV ID in Compound, custom-only synonyms
- Restore integration client naming — only docs/commits are sanitized
- Code review fixes — updated_at propagation, null visibility, grid selection sync, hook lift
- DR chart not rendering — raw_data keys were concentration/response, not x/y
- Restore lost backend changes + commit all pending work
- Wire GetMoleculeActivityDetail in DI container and dependencies
- Update CDD client docstring, add param validation, fix type hint
- Register get_sync_watermark activity in Temporal worker
- Register ListCddMoleculeImports and ForceFailCddMoleculeImport in DI container
- Parse cdd_modified_at ISO string to datetime before DB insert
- Correct Mapped type hints for DateTime columns on CddMoleculeImportModel
- Detect crashed workflows in status endpoint, graceful cancel for terminated
- Sync crashed workflow status to DB to prevent UI infinite loop
- Disclosure FK violation + add missing merge side effects
- Mark_conflict keyword arg + add find_by_id_in_workspace to Protocol
- Restore saved-search write-back on first page (execute-search)
- Add missing updated_at column to compound_flags (db)
- Wrap PreviewRunFile in UoW context (import-run-file)
- Unwrap RegistrationNumber + case-insensitive identifier match (import)
- Write readouts for control wells; unblocks plate normalization (import)
- Hydration regression + invariant boundaries + drop legacy normalization kwarg (protocols)
- FitOverrides + versioning carry-forward all DR config fields (screening)
- Scope inbound-ref and cascade engine queries by workspace_id (cascade)
- Write audit operation inside the deletion transaction (admin)
- Morgan similarity must pass Python-computed bytes via bfp_from_binary_text (persistence)
- Drop mol_adjust_query_properties from substructure path (persistence)
- Drop typed bindparam on SMARTS/SMILES query strings (persistence)
- SQL-level CAST to cstring + execute-tier regression tests (search)
- Apply professional mode descriptions to MODE_DEFAULTS (domain)
- Re-resolve preview when chemist refines column mapping (screening)
- Preserve config writes when patching create_batch_on_duplicate together (data-sources)
- Correct NotFoundError signature in Collection guards (persistence)
- Tighten close-campaign tests and import hygiene (application)
- Tidy get_published_campaign dead paths (application)
- Preserve measurement id on re-resolve (application)
- Persist result notes from decision panel
- Handle nested per-plate z_prime shape in qc_metrics JSONB (campaign)
- Match find_by_ids signature convention + drop fixture commit (be/screening)
- Rely on Pydantic for batch cap + document non-enrichment (be/dose-response)
- Condense raw_data to {x,y} in curves:batch (be/dose-response)
- Include curve_class in DR candidates so the curve-class chip filter actually works (campaign/import)
- Published collection uses campaign name + sign-time publish toggle (campaign/close)
- Drop TautomerEnumerator + populate stereo classification; rename chem_vault → cellar (registration)
- Multi-intercept channels — proper cells, hits, labels (campaign)
- Tighten ExportJob state-machine guards + Protocol typing (domain)
- Commit UoW transactions in RenderExport state transitions (export)
- Replace inline container access in download route with PrepareExportDownload use case (export)
- Build columns in total_count() so the renderer sees them (export)
- Use parent drc token for activity lookups (cell values + sparklines) (export)
- Expose is_frozen + derived_from_campaign_id on API (collections)
- Backfill script must eagerly import sibling model modules (scaffold-tree)
- Emit clean ring-only scaffolds, parent=simpler (scaffold-tree)
- See the FULL collection, not just the visible page (scaffold-tree)
- Relax pagination cap for {type:'collection'} queries (search)
- UmapJobRepository takes UoW + alembic env.py imports for sar_analysis models (sar)
- Test_find_cached_misses_past_ttl — use unique ids_hash to avoid cross-test cache collision (sar)
- Morgan FP decode uses CreateFromBitString (was passing bytes to CreateFromBinaryText) (sar)
- Refit endpoint honors disable_auto_outliers flag (screening)
- Migration 041 preserves concentration+response payload (screening)
- Refit audit reason + audit-rollback atomicity test (screening)
- Next_batch_number uses MAX-tail regex, accepts width (inventory)
- Backfill script — use database_url + pool_pre_ping (matches sibling) (scripts)
- Immutable candidates tuple + has_identifier/empty-outcomes tests (research_org)
- Guard uow.commit + tests for not-found + TTL (research_org)
- BulkAddToCollection populates molecule_name on resolved outcomes (research_org)
- Dedup summary-import items by key (last-wins) + normalize errors (screening)
- Return 422 for malformed summary-import mapping (api)
- Summary import resolves compound_ref by identifier (mirrors plate path) (screening)
- Resolve code-review findings on kvt branch (tagging,screening)
- Move tag-browse read protocol to the application layer (arch)
- 422 on explicit-null type in collection PATCH (research-org)
- 404 on unknown target links + audit events + light guards (screening)
- Block deleting in-use targets (RESTRICT + 409) (screening)
- Resolve targets in the same transaction as reads + scope link queries (screening)
- Mutation responses carry targets like GET (screening)
- Forbid unknown fields on protocol create/update bodies (screening)
- Enforce workspace tenant guard in every application use case (security)
- Workspace-scope tag-link repoint (defence-in-depth) (security)
- Single workspace-first unique index on favorites (personalization)
- Require_same_user guard on favorite use cases (personalization)
- Idempotent favorite insert + drop dead dispatcher wiring (personalization)
- Per-project SQL cap on scope-stats member ids (projects)
- Owner-side workspace scope on target filter subquery (campaigns)
- Serialize curve excluded_points to dicts in activity-detail (screening)
- Guard decomposer translate loop + cover multi-Rgroup and mid-sequence unmatched (sar)
- Surface no-SMILES molecules as unmatched; ruff format (sar)
- Install cellar project in backend image so it boots (docker)
- Fan out synonym mirrors on batches created during import (inventory)
- Scope activity-projection find_cached by workspace_id (defense-in-depth) (sar)
- Validate projection ownership in /rows (defense-in-depth) (sar)
- Resolve design-7 code-review findings (lifecycle, heatmap, grid, efficiency) (sar)
- Log status_code=None (not 0) on pre-response crash; +health/client_ip tests (logging)
- Source environment from APP_ENV to match deployment (version)
- Conservative is_run_candidate + immutable VO fields + remove name_floor knob (screening)
- Unify free-text facet normalization + canonical type labels in name suggestion + seam tests (screening)
- Persist protocol facets atomically at create + type ontology-term boundary (screening)
- _AuthShim satisfies widened AuthContext (org_id/org_slug) (b...
Backend v0.1.0
Bug Fixes
- User preferences — proper DDD layers, no architecture violations
- Security + architecture review — 8 findings resolved
- Architectural review — 7 findings resolved
- Architectural review — 3 findings resolved
- Architectural review — workspace isolation, DDD, security (11 findings)
- Protocol versioning — parent stays active until new version published
- Root-cause fixes — server-side identifier resolution, search-based selector
- Correct model import paths in dashboard route and disclosure repo
- Schema hardening + disclosure/merge atomicity
- Skip name-to-identifier promotion for auto-generated names
- Add missing guard checks across use cases
- Lazy Sentinel init so interface layer imports don't crash
- Replace None auth fallback with reject-all stub
- Replace UUID displays with entity names + fix assign 401
- Architectural review — workspace isolation + persistence gaps
- Columns type to dict[str, Any], add_molecules/remove_molecules return int (research-org)
- Clean architecture fix — move query composer to infra, add repo method (search)
- Find_collections_containing returns Collection objects per Protocol
- Rename protocol_id/run_id to project_id/template_id on RegisteredPlate
- Add batch validation on MapWells + PlateTemplate delete guard
- MapWells accepts batch numbers (CV-00001-001), not just UUIDs
- Import wizard end-to-end — type alignment, UoW, FormData upload
- Rename AddMoleculesBody.refs → references to match frontend contract
- Add UoW to list use cases — missing async context manager (t10)
- Clean architecture violations in vault import — move errors to app layer, catch timeout
- Correct WorkspaceSettings types and vault import use case UoW handling
- Handle legacy {} values in workspace_settings columns
- Vault mapper field names, pagination, dialog scroll, and caching
- Map external description/category, fix 204 JSON parse, pagination
- Filter external calculation outputs, map description/category, fix 204
- Move PlateFormat to shared kernel to fix bounded context independence
- Show compound names in dose-response chart legend and cards (ui)
- Clamp R² to [0, 1] in both fitting passes (infra)
- Make readout_data molecule_id/batch_id nullable in API + frontend
- Batch numbering uses molecule reg number prefix (CV-00001-001)
- Serialize recommended_hit_criteria in ProtocolResponse
- Remove is_computed filter + add n/sd to numeric readout aggregation
- Review fixes — zero-value data points, shared helper, actual top/bottom, sorted query key
- Fit-curves endpoint calls FitDoseResponseCurves directly
- Activity summary includes compounds with DR curves but no readout data
- Normalize top > bottom in curve fitter output
- Compute R² and classify before top/bottom swap in curve fitter
- Commit UoW after fitting curves in standalone mode
- Excel export — plain headers, CV ID in Compound, custom-only synonyms
- Restore integration client naming — only docs/commits are sanitized
- Code review fixes — updated_at propagation, null visibility, grid selection sync, hook lift
- DR chart not rendering — raw_data keys were concentration/response, not x/y
- Restore lost backend changes + commit all pending work
- Wire GetMoleculeActivityDetail in DI container and dependencies
- Update CDD client docstring, add param validation, fix type hint
- Register get_sync_watermark activity in Temporal worker
- Register ListCddMoleculeImports and ForceFailCddMoleculeImport in DI container
- Parse cdd_modified_at ISO string to datetime before DB insert
- Correct Mapped type hints for DateTime columns on CddMoleculeImportModel
- Detect crashed workflows in status endpoint, graceful cancel for terminated
- Sync crashed workflow status to DB to prevent UI infinite loop
- Disclosure FK violation + add missing merge side effects
- Mark_conflict keyword arg + add find_by_id_in_workspace to Protocol
- Restore saved-search write-back on first page (execute-search)
- Add missing updated_at column to compound_flags (db)
- Wrap PreviewRunFile in UoW context (import-run-file)
- Unwrap RegistrationNumber + case-insensitive identifier match (import)
- Write readouts for control wells; unblocks plate normalization (import)
- Hydration regression + invariant boundaries + drop legacy normalization kwarg (protocols)
- FitOverrides + versioning carry-forward all DR config fields (screening)
- Scope inbound-ref and cascade engine queries by workspace_id (cascade)
- Write audit operation inside the deletion transaction (admin)
- Morgan similarity must pass Python-computed bytes via bfp_from_binary_text (persistence)
- Drop mol_adjust_query_properties from substructure path (persistence)
- Drop typed bindparam on SMARTS/SMILES query strings (persistence)
- SQL-level CAST to cstring + execute-tier regression tests (search)
- Apply professional mode descriptions to MODE_DEFAULTS (domain)
- Re-resolve preview when chemist refines column mapping (screening)
- Preserve config writes when patching create_batch_on_duplicate together (data-sources)
- Correct NotFoundError signature in Collection guards (persistence)
- Tighten close-campaign tests and import hygiene (application)
- Tidy get_published_campaign dead paths (application)
- Preserve measurement id on re-resolve (application)
- Persist result notes from decision panel
- Handle nested per-plate z_prime shape in qc_metrics JSONB (campaign)
- Match find_by_ids signature convention + drop fixture commit (be/screening)
- Rely on Pydantic for batch cap + document non-enrichment (be/dose-response)
- Condense raw_data to {x,y} in curves:batch (be/dose-response)
- Include curve_class in DR candidates so the curve-class chip filter actually works (campaign/import)
- Published collection uses campaign name + sign-time publish toggle (campaign/close)
- Drop TautomerEnumerator + populate stereo classification; rename chem_vault → cellar (registration)
- Multi-intercept channels — proper cells, hits, labels (campaign)
- Tighten ExportJob state-machine guards + Protocol typing (domain)
- Commit UoW transactions in RenderExport state transitions (export)
- Replace inline container access in download route with PrepareExportDownload use case (export)
- Build columns in total_count() so the renderer sees them (export)
- Use parent drc token for activity lookups (cell values + sparklines) (export)
- Expose is_frozen + derived_from_campaign_id on API (collections)
- Backfill script must eagerly import sibling model modules (scaffold-tree)
- Emit clean ring-only scaffolds, parent=simpler (scaffold-tree)
- See the FULL collection, not just the visible page (scaffold-tree)
- Relax pagination cap for {type:'collection'} queries (search)
- UmapJobRepository takes UoW + alembic env.py imports for sar_analysis models (sar)
- Test_find_cached_misses_past_ttl — use unique ids_hash to avoid cross-test cache collision (sar)
- Morgan FP decode uses CreateFromBitString (was passing bytes to CreateFromBinaryText) (sar)
- Refit endpoint honors disable_auto_outliers flag (screening)
- Migration 041 preserves concentration+response payload (screening)
- Refit audit reason + audit-rollback atomicity test (screening)
- Next_batch_number uses MAX-tail regex, accepts width (inventory)
- Backfill script — use database_url + pool_pre_ping (matches sibling) (scripts)
- Immutable candidates tuple + has_identifier/empty-outcomes tests (research_org)
- Guard uow.commit + tests for not-found + TTL (research_org)
- BulkAddToCollection populates molecule_name on resolved outcomes (research_org)
- Dedup summary-import items by key (last-wins) + normalize errors (screening)
- Return 422 for malformed summary-import mapping (api)
- Summary import resolves compound_ref by identifier (mirrors plate path) (screening)
- Resolve code-review findings on kvt branch (tagging,screening)
- Move tag-browse read protocol to the application layer (arch)
- 422 on explicit-null type in collection PATCH (research-org)
- 404 on unknown target links + audit events + light guards (screening)
- Block deleting in-use targets (RESTRICT + 409) (screening)
- Resolve targets in the same transaction as reads + scope link queries (screening)
- Mutation responses carry targets like GET (screening)
- Forbid unknown fields on protocol create/update bodies (screening)
- Enforce workspace tenant guard in every application use case (security)
- Workspace-scope tag-link repoint (defence-in-depth) (security)
- Single workspace-first unique index on favorites (personalization)
- Require_same_user guard on favorite use cases (personalization)
- Idempotent favorite insert + drop dead dispatcher wiring (personalization)
- Per-project SQL cap on scope-stats member ids (projects)
- Owner-side workspace scope on target filter subquery (campaigns)
- Serialize curve excluded_points to dicts in activity-detail (screening)
- Guard decomposer translate loop + cover multi-Rgroup and mid-sequence unmatched (sar)
- Surface no-SMILES molecules as unmatched; ruff format (sar)
- Install cellar project in backend image so it boots (docker)
- Fan out synonym mirrors on batches created during import (inventory)
- Scope activity-projection find_cached by workspace_id (defense-in-depth) (sar)
- Validate projection ownership in /rows (defense-in-depth) (sar)
- Resolve design-7 code-review findings (lifecycle, heatmap, grid, efficiency) (sar)
- Log status_code=None (not 0) on pre-response crash; +health/client_ip tests (logging)
- Source environment from APP_ENV to match deployment (version)
- Conservative is_run_candidate + immutable VO fields + remove name_floor knob (screening)
- Unify free-text facet normalization + canonical type labels in name suggestion + seam tests (screening)
- Persist protocol facets atomically at create + type ontology-term boundary (screening)
- _AuthShim satisfies widened AuthContext (org_id/org_slug) (backend)
- Only own org (or admin) may set plate owner_org_id (backend)
- Enforce private-org visibility on children/export/read-model/writes (ba...