Repository navigation
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Breaking: tag_ids now lists only Containers carrying all the selected Tags, using containerHasAllTags from Container selection (ADR 0011). Pagination and the total stay in SQL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ion. `GET /export/containers` now picks its Containers with `selectContainers` (ADR 0011), so the container type filter runs once, in the selection. A Study whose Containers are all of other types now returns 404 "No containers found for this study" instead of an empty file. `created_from` and `created_to` map to Container created. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The statistics created_from/created_to filter has always matched the Specimen's created date. The filter fields and their chips now say so, in the wording ADR 0011 uses. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
formatContainerExport returned the JSON rows as `json`, but buildPostExportEnvelope reads `jsonData`, so every POST container export in JSON format sent an empty `data` array. New executor tests for multi-study and barcode export pin the rows, the per-Study summary and the barcode summary before those paths move to Container selection. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tion. `POST /export/containers` now builds a subject-list selection from the resolved subject names and their per-subject dates, and selects with `selectContainers` (ADR 0011). Count-only and full export share the one selection, so neither calls `filterContainerIdsByType` any more. The summary is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…election. getDashboardStatistics now asks selectContainers for its Containers and Specimens. created_from/created_to map to Specimen created and specimen_type_id to a one-item list. The inline all-Tags intersection, the unreachable location- and tag-only branch, the statistics location helpers and buildDateFilter are gone. The location filter no longer needs the raw SQLite handle, so the statistics routes drop it. The wire shape is unchanged. A filter that matches no Specimen returns the all-zero statistics, without the storage summary, as an unknown Study or Tag already did. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ainer selection. A multi-study upload is now one subject-list selection instead of one buildContainerQuery call per Study, followed by a container type filter and enrichment per Study. The executor groups the enriched rows by Study for the Export summary. The barcode export selects the found tubes with a micronix barcode selection and applies no other filters; found and not found still come from resolveMicronixBarcodesToContainers, since the selection carries no barcodes. buildMultiStudyContainerQuery, buildContainerQueryByMicronixBarcodes and MultiStudyExportResult had no other callers and are deleted. The multi-visit test moves to the executor tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # packages/api/src/lib/export/container-export.ts
… the old selection code. enrichContainerData now takes only the Containers. Each subject row's study fields come from its Source's Study (ADR 0007) and control rows have none, so the type filter, the unused specimen list, the study argument and the subject-to-Study map are gone, along with loadStudiesBySubject. The MULTI study record is now used only for JSON export metadata, including the barcode export's. buildContainerQuery, filterContainerIdsByType (lib/export/filter.ts) and lib/container-tag-filter.ts had no callers outside their tests and are deleted with them; Container selection's tests cover their cases. query.ts keeps resolveMicronixBarcodesToContainers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every export and statistics path now selects through src/lib/container-selection/, so the rule lists no unmigrated paths. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Container selection now owns the rules its callers re-derived: - containerTypes is typed as ContainerSubtype. containerTypesFilter narrows wire values and drops unrecognised ones, so a list of only unrecognised values still matches nothing; 'unknown' matches Containers with no subtype row, as ADR 0011 now says. - hasContainerLevelFilter replaces dashboard-stats' own rule, which left out Container created. - SpecimenSourceType and specimenSourceType replace the ternary in the database selection and the check in statisticsSelection. Export and statistics look up a Study through identifier-resolution (resolveStudyRecordByShortCode backs resolveStudyByShortCode) instead of their own queries. Export inverts subject name maps with one helper, and multi-study JSON metadata uses MULTI_STUDY_RECORD, as barcode export does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GET /export/available-types picked a Study's Specimens and Containers with unchunked IN lists that grew with the Study, and failed once its Subjects outnumbered SQLite's bound-parameter limit. It now calls selectContainers with a study selection and reads the specimen types and containerTypes from the result. The response is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
createTestStorageContainer takes a created override, createTestSpecimen takes collectionDate and created, and createTestContainerTags links Tags to a Container. The Container selection tests use them instead of raw inserts and updates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
subjectListScopes chunked by Subject, but each dated Subject added a condition per date to one OR, so 500 Subjects with 80 dates each bound 80,500 parameters and the query failed. Each listed date is now its own condition, and a query takes at most SQL_IN_CHUNK_SIZE of them; undated Subjects get their own query. The list is named subjectDateConditions, since it no longer mixes in the undated condition. Scopes can now overlap, so selectContainers collects Containers by id. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The filter table already ran each filter on study, subject-list and whole-database selections. It now also runs them on a whole-database selection narrowed to Subjects, and a subject-list test applies the other filters to a Subject's own dates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
m-murphy
marked this pull request as ready for review
October 23, 2026 00:24
…ed subject_dates. A null subject_dates entry reached Container selection as [null] and the export returned 500. Null means undated again, as before the migration, and the route checks the shape of subject_dates, answering 400 when it is wrong. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… time. resolveMicronixBarcodesToContainers and resolveSubjectNamesByStudy bound every uploaded value in one IN list, so a long enough upload exceeded SQLite's parameter cap. ADR 0011 keeps queries bounded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rror. GET /export/available-types returned its 400 with c.json, which CODING_STANDARDS.md rules out in changed route code (ADR 0004). It throws ValidationError now; the body keeps its error message and gains errorCode. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ule does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GET /export/available-types loaded every Specimen and Container row of the Study to list their types. selectContainerSelectionTypes runs the same selection with SELECT DISTINCT and returns only the type lists. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ed twice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The contract's addSubjectDates now reads one listing of a Subject's dates (a filter, a list, or none) and folds it into the Subject's selection, with an undated listing winning. subjectDateSelections, the subject-list scopes and the single-study POST export use it instead of their own copies. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The GET export repeated the json/csv/xlsx dispatch of formatContainerExport, and three callers passed the MULTI filters and study record pair by hand. formatContainerExport returns the formatted result for both, and defaults its JSON metadata to the multi-study placeholder. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Container selection's CONTAINER_TYPES re-spelled the ContainerSubtype union. container-placement now exports CONTAINER_SUBTYPES and derives the type from it, and the module filters on that list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hasContainerLevelFilter built every Container-level condition just to count them, and dashboard statistics rebuilt the selection filters to call it. The selection result now says whether one was set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s query. dashboard-stats parsed specimen_type_id and location_id from wire strings although parseStatisticsFilters parses the query. StatisticsFilters now carries them as numbers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # CODING_STANDARDS.md # packages/api/src/__tests__/helpers/factories.ts # packages/api/src/routes/__tests__/export.test.ts # packages/api/src/routes/export.ts
…NER_SUBTYPES. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Container export and the statistics dashboard choose Containers through one Container selection module (ADR 0011).
Also:
GET /export/available-typesreads only distinct types throughselectContainerSelectionTypes, not every Specimen and Container row. A missingstudyis a typedValidationError.data: []).buildContainerQuery,lib/export/filter.ts,lib/container-tag-filter.tsandlib/statistics/location-filter.tsare deleted.enrichContainerData(database, containers)reads study fields from the Source.SQL_IN_CHUNK_SIZEat a time, as ADR 0011 requires.addSubjectDates. When a Subject is listed more than once, an undated entry wins, and ADR 0011 now says so.CONTAINER_SUBTYPES. The selection result says whether a Container-level filter was set, andparseStatisticsFiltersparses the statistics id filters.Evidence
expected 14964 values, received 80500.available-typesfor a Study with 70,000 Subjects → 500. A POST export withformat: 'json'→data: [].subject_dates: { "S1": null }→ 500. 70,000 uploaded barcodes or subject names →SQLite query expected 4466 values, received 70002.After: all pass. Container selection, export, statistics, identifier resolution and containers tests: 202 pass against the in-memory database, and the contract's 89 tests pass.
bun run ci:verifypasses: API 1211, web 949, contract 89.Merge Danger
Door: two-way
Revertible per commit; no schema change.
Blast Radius: wire-semantics
GET /containers?tag_idschanges from any-Tag to all-Tags for external clients. GET study export returns 404 when every Container is filtered out by type. The dashboard's "Created" filter is relabelled "Specimen created". POST/export/containersanswers 400VALIDATION_ERRORfor a malformedsubject_dates, which it used to ignore or fail on with a 500. Theavailable-types400 body gainserrorCode.46 files changed, 2493 insertions(+), 2004 deletions(-).
Closes #94
Closes #95
Closes #96
Closes #97
Closes #98
Closes #99
Closes #100
🤖 Generated with Claude Code