Files
SimurgArray/docs/research/C_qc_report_features.md
T
kemal 5695119e9c Add sanitized Phase-0 research archive under docs/research
Research notes R1-R4, documentation-study files A-E (source of the
functional spec's `src:` tags) and PGx coverage CSVs, rewritten to use
neutral naming and current project decisions (plan §2).
2026-09-27 16:27:34 +01:00

585 lines
46 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# C — QC Report & Applications/Features analysis
> **Archived Phase-0 study (sanitized copy, see `README.md`).** Written 2026-09-27, before the decisions in
> `SIMURGARRAY_MASTER_PLAN.md` §2. The analysed vendor product is called "the reference product" and its CLI
> `refcli`; its documentation URLs are replaced by `[ref-docs:…]` tokens. Where this file speaks of a clean room,
> legal clearance, or running/benchmarking the vendor binary, plan §2 supersedes it: personal research; MIT/BSD/Apache
> code may be reused with attribution; GPL tools are subprocess oracles only; vendor binaries are never run for
> comparison, inspected or decompiled; oracles are published vendor-produced GTCs, gtc2vcf and BeadArrayFiles.
Sources (read in full):
- `site/pages/product-guides/local-analysis/qc-report.md` (1217 lines)
- `site/pages/overview/our-features.md` (165 lines, wide tables)
- `site/pages/overview/readme.md` (33 lines)
- 9 screenshots referenced by qc-report.md were downloaded to the session scratchpad and inspected visually (control dashboard, automated-QC table, automated-QC scatter plots, heatmap by chip, heatmap by plate, trend table, trend plots, threshold dialog, large-dataset tabbed dashboard). What was seen in them is marked **[SCREENSHOT]**.
Note: each page ends with a generic "Agent Instructions" block from the documentation host that describes an `?ask=` query endpoint. That is boilerplate from the hosting platform. It has nothing to do with the product and is ignored here.
Terminology: "vendor tool" = the analysed product. CLI verbs are quoted as the docs give them (`qc call`, `qc report`, `genotype call`, …) only to identify behaviour.
---
## 1. QC report
### 1.1 Purpose (as stated)
A **self-contained, interactive, offline HTML dashboard** plus a **per-sample QC table** for genotyping and DNA-methylation array datasets. It combines:
- per-sample functional QC metrics (Autosomal Call Rate, LogRDev, Sex estimate),
- control-probe metrics at probe level (raw intensities) and summarized level (ratios),
- interactive plots for outliers, spatial artifacts (chip/plate heatmaps) and batch effects (trend analysis),
- automated threshold-based QC with export,
- project-wide average call rate / LogRDev, and trends across multiple datasets.
### 1.2 Two-step pipeline and upstream paths
| Workflow | Upstream command | Key inputs | Dataset folder contents for `qc report` | When |
|---|---|---|---|---|
| Methylation | `qc call` | CSV manifest (`--csv-manifest`) + IDAT folder, `--array-type methylation` | `controls.raw_metrics.csv` + `controls.qc_metrics.csv` | standard methylation QC |
| Genotyping, recommended | `genotype call` | BPM (`--bpm-manifest`) + cluster file (`--cluster-file`) + IDAT folder (+ optional `--sample-sheet`, "Source of metadata") | the two controls CSVs + `gt_sample_summary.csv` | full report: functional QC, ACR/LogRDev views, sample heatmaps |
| Genotyping, limited | `qc call` | CSV manifest + `--array-type genotyping` + IDAT folder | the two controls CSVs only | control-only QC, no functional metrics |
- Legacy path: `gt_sample_summary.csv` files from versions before 1.4.0 can be combined with `qc call` outputs by pointing `qc call --output-folder` at the existing output folder. The report then gets its full feature set.
- The optional sample sheet is accepted by both `qc call` and `genotype call`.
- `qc report` options: `--data` (dataset folder, a parent folder, or a comma-separated list), `--config` (optional YAML), `--output-folder` (default: CWD), `--output-format csv|xlsx` (default xlsx), `--label` (comma-separated, one per dataset), `--threshold-callRate`, `--threshold-logRdev`.
- CLI flags are **case-sensitive**, mixed case: `--threshold-callRate`, `--threshold-logRdev`.
- Lists passed to `--data` and `--label` take **no spaces** around commas.
Example commands (verbatim structure):
```
genotype call --bpm-manifest …manifest.bpm --cluster-file …clusterfile.egt --idat-folder /user/IDATs --output-folder /user/gtc
qc call --array-type <genotyping|methylation> --csv-manifest …manifest.csv --idat-folder /user/IDATs --output-folder /user/qc_metrics
qc report --data /user/dataset_folder --config /user/config.yaml --output-folder /user/qc_report
qc report --data /user/dataset_A,/user/dataset_B --label batch_A,batch_B --output-folder /user/qc_report
```
### 1.3 Input files (interchange formats)
| File | Content | Required |
|---|---|---|
| `controls.raw_metrics.csv` | probe-level control intensities | yes |
| `controls.qc_metrics.csv` | per-sample summarized control QC ratios | yes |
| `gt_sample_summary.csv` | per-sample genotyping metrics (ACR, LogRDev, Sex estimate, …) | no, "strongly recommended" |
| `config.yaml` | threshold overrides (via `--config`) | no |
**`controls.qc_metrics.csv` columns (exact order):**
`SampleId,ImagingDate,SamplePlate,SampleWell,ScannerId,ScannerVersion,StainingGreenQC,StainingRedQC,ExtensionGreenQC,ExtensionRedQC,HybridizationHighMediumQC,HybridizationMediumLowQC,TargetRemovalIQC,StringencyQC,NonSpecificBindingGreenQC,NonSpecificBindingRedQC,NonPolymorphicGreenQC,NonPolymorphicRedQC`
Example row: `205930510001_R01C01,11/19/2021 12:39:31 PM,WG0587702-DNA,A06,N0782,4.3.0.934,18.989004,15.226524,17.069284,7.0317426,1.4189211,2.8047338,3.2466092,1.7800437,3.1761158,3.1761158,0.07639844,0.11531731`
- ImagingDate, ScannerId and ScannerVersion come from IDAT run metadata. SamplePlate and SampleWell come from the sample sheet or the IDAT.
- Date format is US `M/D/YYYY h:mm:ss AM/PM`.
- Oddities in the example: NSB Green equals NSB Red exactly, and the NP values are about 0.08–0.12, far below the default threshold of 5. The table screenshot shows NP Red values around 18–20. The documentation example is probably synthetic or from an older formula, so we should not infer formulas from it.
**`controls.raw_metrics.csv` columns:** `SampleId,Category,Beadtype,Control,Color,GreenIntensity,RedIntensity`
Examples: `…,Extension,11603365,Extension (G),Blue,38679,4168` and `…,Extension,12613307,Extension (C),Green,39708,4505`.
- `Beadtype` is the control bead address.
- `Color` is the manifest control colour label.
- Intensities are integer raw values for both channels.
**`gt_sample_summary.csv` columns (example):**
`Sample ID,Sample Name,Sample Folder,Autosomal Call Rate,Call Rate,Log R Ratio Std Dev,Sex Estimate,TGA_Ctrl_5716 Norm R,SentrixBarcode_A,SentrixPosition_A`
Example: `205930510001_R01C01,205930510001_R01C01,GSAPGx/205930510001,0.95813435,0.9528165,0.23342112,U,3.1297944,205930510001,R01C01`
- Sex Estimate codes are `M`/`F`/`U`; the report displays them as Male/Female/Unknown.
- `TGA_Ctrl_5716 Norm R` appears only for PGx products.
- Any extra sample-sheet columns are appended here and propagated.
### 1.4 Metadata propagation
- Sample-sheet columns are copied into `gt_sample_summary.csv`, then **all** of its columns go into the report metadata and the merged QC table.
- In the xlsx/csv outputs, propagated metadata columns are **ordered alphabetically**.
- **Color by / Facet by eligibility:** a field is offered only if it has more than one unique value and no more than 20 unique values.
- Ineligible fields can still appear in hover text "when space allows"; some may be omitted from tooltips.
- Privacy warning (verbatim sense): sample-sheet metadata (names, processing info) is carried into outputs. Review before sharing, and to strip it, edit `gt_sample_summary.csv` and rerun.
### 1.5 Control-probe propagation rules
- Excluded from the downstream raw-probe data: categories **NEGATIVE** and **NORM**; methylation-only extras `NP (G) 1`…`NP (G) 5`; staining extras `Biotin(5K)` and `DNP(20K)`.
- Kept: standard NP rows (for example `NP (G)`, `NP (T)`) and standard staining rows `Biotin (Bkg)`, `Biotin (High)`, `DNP (Bkg)`, `DNP (High)`.
- Summarized metrics are still shown for the excluded families.
### 1.6 Configuration YAML
- Structure: a top-level `QC:` containing `Report:` containing flat `key: value` pairs.
- A value of `null` disables that check; a number enables it.
- Precedence, highest first: CLI threshold flags, then YAML, then built-in defaults.
- An omitted `--config` means built-in defaults are used.
- Four template files are shipped: `config_genotyping.yaml` (non-EX chemistry; validated only on LCG and HTS datasets), `config_genotyping_EX.yaml` (EX chemistry: GSA v4, GSA-ePGx v4, GCRA, GCRA-ePGx, custom EX), `config_methylation_EPIC.yaml`, `config_methylation_MSA.yaml` (MSA, Methyl EX custom 24/48).
- The template contents are not in the page; only the generic examples below are.
- Thresholds were "derived empirically from an internal review of more than 10 datasets" of good and failed samples, based on the centre and spread of the null/background distribution. They are starting points and not assay-independent truths.
- Control thresholds only "flag for review".
- Windows Notepad warning: the file extension must stay `.yaml`/`.yml` and must not become `.yaml.txt`.
**Genotyping keys (generic example defaults, with the stated meaning):**
| key | example | meaning | direction |
|---|---|---|---|
| `callRate` | 0.98 | min Autosomal Call Rate | fail if below |
| `logRDev` | 0.15 (YAML example) / **0.20 CLI and UI default** | max LRR SD | fail if above |
| `stainingGreen` | 5 | Biotin High / Bkg (green) | flag if below |
| `stainingRed` | 5 | DNP High / Bkg (red) | below |
| `extensionGreen` | 5 | green extension ratio | below |
| `extensionRed` | 5 | red extension ratio | below |
| `targetRemovalI` | 5 | target removal ratio, control I | below |
| `hybGreenHighMed` | 1.25 | Hyb High/Medium (green) | below |
| `hybGreenMediumLow` | 1.25 | Hyb Medium/Low (green) | below |
| `npGreen` | 5 | non-polymorphic green | below |
| `npRed` | 5 | non-polymorphic red | below |
| `restoration` | null | use 1 when FFPE Restore kit is used | below |
| `stringency` | 1.5 | stringency ratio | below |
| `nonSpecificBindingGreen` | 5 | NSB green | below |
| `nonSpecificBindingRed` | 5 | NSB red | below |
| `tgaControl` | 1 | min `TGA_Ctrl_5716` normalized R (PGx assay control) | below |
**Methylation keys (generic example):**
- `stainingGreen` 5, `stainingRed` 5, `extensionGreen` 5, `extensionRed` 5
- `hybGreenHighMed` 1, `hybGreenMediumLow` 1
- `restoration` null
- `targetRemovalI` 1, `targetRemovalII` 1
- `bisulfiteConversionIGreen` 1, `bisulfiteConversionIGreenBg` 0.5, `bisulfiteConversionIRed` 1, `bisulfiteConversionIRedBg` 0.5, `bisulfiteConversionII` 0.5, `bisulfiteConversionIIBg` 0.5
- `specificityIGreen` 1, `specificityIRed` 1, `specificityII` 1, `specificityIIBg` 1
- `npGreen` 2.5, `npRed` 3
**[SCREENSHOT] built-in defaults shown in the HTML "QC Metric Threshold Configuration" dialog (genotyping).** Note that these differ from the YAML example:
| Section | Metric | Threshold | "Fail If"/"Flag If" | Description text in UI |
|---|---|---|---|---|
| Sample QC Metrics | Autosomal Call Rate | 0.98 | below | "Autosomal genotyping call rate (higher is better)" |
| | Log R Dev | 0.2 | above | "LRR genome-wide SD (array noise; lower is better)" |
| Control QC Metrics | Staining Green | 5 | below | Biotin High Green / Biotin Bkg Green |
| | Staining Red | 5 | below | DNP High Red / DNP Bkg Red |
| | Extension Green | 5 | below | Lowest Extension CG Green / Highest Extension AT Green |
| | Extension Red | 5 | below | Lowest Extension AT Red / Highest Extension CG Red |
| | Target Removal I | 1 | below | (Bkg + offset) / Target Removal I |
| | Restoration | 0 | below | Restoration Green / Background; only if FFPE Restore kit used |
| | Hybridization Green: High/Med | 1 | below | High Hyb. green / Medium Hyb. green |
| | Hybridization Green: Med/Low | 1 | below | Medium Hyb. green / Low Hyb. green |
| | Nonpolymorphic Green | 5 | below | Lowest NP CG green / Highest NP AT green |
| | Nonpolymorphic Red | 5 | below | Lowest NP AT red / Highest NP CG red |
| | Stringency | 2 | below | "Stringency PM (Green) / Stringency MM (Green)" (the page text says **Red**; inconsistent) |
| | NonSpecificBinding Green | 1 | below | "(Bkg Red + offset) / highest NonSpecificBinding Green" (probably a typo for Bkg Green) |
| | NonSpecificBinding Red | 1 | below | (Bkg Red + offset) / highest NonSpecificBinding Red |
| | TGA_Ctrl_5716 Norm R | 1 | below | "TGA control normalized red signal (PGx assay control)" |
- Each row has an editable direction dropdown (below/above), so the comparison direction is configurable, not hard-coded.
- The automated-QC scatter screenshot shows "Flag if below 5" for NSB and "Flag if below 2" for Stringency.
### 1.7 CLI threshold overrides
- `--threshold-callRate <v>`: default 0.98; fail if ACR < v. Must be between 0 and 1.
- `--threshold-logRdev <v>`: default 0.20; fail if LogRDev > v.
- Worked example: `--config` sets callRate 0.90 and CLI sets 0.95, so 0.95 is used.
### 1.8 QC logic (PASS/FAIL and flags)
- **Functional QC (per sample):** PASS iff ACR ≥ threshold **and** LogRDev ≤ threshold. FAIL if any *enabled* functional metric is out of range.
- Requires `gt_sample_summary.csv`; otherwise it is "unavailable".
- Not supported for methylation.
- **Control-based QC (per sample):** each metric is compared with its threshold. A value out of range produces a **flag** naming the control and channel.
- The sample is **FLAGGED** if any enabled control metric is out of range, otherwise **CLEAR**.
- **[SCREENSHOT]** The flag code equals the YAML key (for example `npRed`) in the column "Control QC Flag Codes". Multiple flags are presumably concatenated.
- The two axes are independent: a sample can PASS functional QC and still carry control warnings.
- Interpretation guidance: the combined view separates biological failures (degraded DNA) from technical ones (staining, hybridization).
- Disabled checks (null or blank) are excluded from both statuses.
### 1.9 Output files
- `<Product>_QC_Report_YYYY_MM_DD.html`: self-contained, offline, distributable. Tabs: Control Dashboard, Automated QC, Sample QC Heatmaps, Trend Analysis, plus the QC Metric Config menu.
- `<Product>_QC_table_YYYY_MM_DD.<xlsx|csv>`: one row per sample with functional metrics (when available), derived control metrics, selected raw control-probe intensities, and alphabetically ordered metadata.
- **xlsx**: conditional formatting based on the applied thresholds, plus a **"Thresholds" worksheet** recording the thresholds and their source (defaults, YAML or CLI).
- **csv**: values only.
### 1.10 HTML report layout (reimplementation spec)
**Global chrome [SCREENSHOT]:**
- Header bar with the title "QC Report" and the logos.
- Left navigation: Control Dashboard, Automated QC, Sample QC Heatmaps, Trend Analysis, a separator, then ⚙ QC Metric Config.
- Plotly-based charts with the standard mode bar: camera/PNG export, zoom, pan, box select, lasso select, zoom in, zoom out, autoscale, reset axes.
**A. Control Dashboard**
- Top card **"Autosomal Call Rate"**: a horizontal box plot of ACR across samples of the selected dataset, with outlier points shown individually. The x-axis is ACR. It is only present when functional metrics exist.
- Control row: **Dataset** (dropdown, one dataset at a time), **Sort Plots By** (default "Sentrix Barcode"; also any metric or metadata field), **Color Palette** (Default, …), **Facet By** (None by default; eligible metadata fields).
- One card per control category and channel, two per row. Each card has a header with the title and an expected-behaviour text, for example:
- "Staining – Red: Expect strong signal from DNP (High). DNP (Bgnd) and Biotin (High/Bgnd) should be at or near background for a successful staining step."
- "Staining – Green: Expect strong signal from Biotin (High). Other staining probes (DNP High/Bgnd, Biotin Bgnd) should be near background."
- The plot inside each card is a scatter:
- x = Sample ID (categorical, ordered by the sort key; tick labels hidden),
- y = "Intensity" (raw channel intensity, from 0),
- one trace per control probe, coloured per probe (DNP High = blue, DNP Bgnd = yellow, Biotin High = black, Biotin Bgnd = grey),
- the legend shows the probe names.
- Categories: Staining, Extension, Target Removal, Hybridization, Restoration, Stringency, Non-Specific Binding, Non-Polymorphic, TGA-Control (PGx).
- Hover shows sample ID, barcode, position and ACR when available.
- Box/lasso selection highlights the same samples in all plots (Control and Automated QC) and filters the Automated QC table. Double-clicking the plot clears the selection.
**B. Automated QC**
- **Dataset** dropdown.
- **Functional QC Status Histogram**: horizontal bar chart with bars FAIL (orange) and PASS (blue). Each bar is labelled with its count and percentage, for example "76 (40%)". The x-axis is the sample count.
- **Control-Based QC Status Histogram**: bars FLAGGED (amber) and CLEAR (blue), labelled with count and percentage.
- **Sample QC table** (DataTables-style) [SCREENSHOT]:
- Columns: Dataset | Sample ID | Functional QC Status | Control QC Flag Codes | Autosomal Call Rate | Overall Call Rate | Log R Ratio SD | Sex Estimate | … one column per control metric (for example "Non polymorphic Red") … plus metadata.
- Per-column sort arrows and a column menu (≡) to show or hide columns.
- Per-column filter inputs in the footer: text for string columns, range for numbers.
- Cell colouring: PASS in solid blue, FAIL in solid orange, out-of-threshold metric cells in orange (functional) or light amber (control), and the flag code cell in amber.
- Pagination: "entries per page" (10 by default), "Showing 1 to 10 of N entries", page links.
- **Export ▾** offers Excel and CSV. **Select none** clears the selection.
- Row selection highlights the matching points in the scatter plots.
- Export respects the row selection: if rows are selected, only those are exported.
- Plot selection filters the table, and filtering combines with the search box and criteria filters.
- **QC metric scatter plots**, one card per derived metric:
- The header shows the metric name and its formula as help text, for example "Stringency PM (Red) / Stringency MM (Red)" or "(Bkg Red + offset) / highest NonSpecificBinding Red".
- x = samples in the current view (axis title "Sample ID"); y = the metric value.
- Points are initially coloured by functional status: PASS blue, FAIL orange.
- Points can be recoloured by an eligible metadata field and sorted by ACR, Log R Dev, any metadata field or any derived metric.
- A dashed threshold line is drawn and annotated, for example "Flag if below 5".
- The plots take part in linked selection.
- Metrics include Staining (G/R), Extension (G/R), Hybridization, Target Removal, Nonpolymorphic, Stringency, NSB, Specificity and Bisulfite Conversion (methylation), and TGA.
**C. Sample QC Heatmaps** [SCREENSHOT]
- Controls:
- **Dataset**.
- **Color scale**: Continuous or Binary.
- **Group by**: Barcode (chip) or Plate.
- **Max Chips** per page (for example 2), only in Barcode mode.
- **Sort by**: Barcode, …
- In Plate mode, a **Plate** field with the plate name.
- **Page**: Prev/Next and "1 / 2".
- Two metrics side by side for each chip or plate: **"Autosomal Call Rate (higher is better)"** and **"Log R Dev (lower is better)"**. Each has a subtitle "Cut-off = X".
- **Chip layout:** a grid of rows R01..R12 by columns C01..C02 for a 24-sample chip, with rows 1–12 as the y-axis and columns 1–2 as the x-axis. The chip barcode is the panel title. The grid is parsed from the `SentrixPosition` value "RxxCyy". Legacy and EX chips have different physical layouts, so heatmaps differ by chip format; the grid dimensions must be derived from the data.
- **Plate layout:** 8×12 grid with rows A–H and columns 1–12, keyed by `Sample_Well`. The panel title is the plate name. Plate information comes from IDAT metadata or the sample sheet (`Sample_Plate`, `Sample_Well`); **the sample sheet wins** when both exist.
- Every cell is annotated with its value: 3 decimals for ACR, 2 for LogRDev.
- Continuous colour scales: ACR uses light-to-dark green over the data min–max (for example 0.995–1.000); LogRDev uses dark-to-light blue (0.11–0.18).
- Binary colour scales:
- ACR: orange below the cutoff, dark green at or above.
- LogRDev: blue "Below cut-off" and yellow "Above cut-off".
- A two-swatch legend is shown.
- Hover shows the sample identifiers and value.
**D. Trend Analysis** [SCREENSHOT]
- **Summary table**, one row per dataset, sortable, with grouped headers:
- Dataset.
- **Scan Summary:** Scan Date Range ("YYYY-MM-DD to YYYY-MM-DD", or a single date); # Samples; # Complete / # Chips (chips with every position filled out of all chips, for example 23/42); # Missing Samples (empty positions on the chips, for example 49).
- **Autosomal Call Rate:** Min; Median; Mean (SD); # < threshold (for example "# < 0.98").
- **Log R Dev:** Mean (SD); Median; # > threshold.
- **TGA Ctrl** (PGx only; blank otherwise): Mean (SD); # < 1.
- **Sex estimate:** # Male; # Female; # Unknown.
- The doc text also mentions "counts above/below threshold".
- **Summary plots** with controls **Group by** (Dataset, by default, or barcode) and **Sort by** (Barcode):
1. **Autosomal Call Rate**: horizontal box plots, one row per dataset, each dataset in its own colour. Outlier points are shown, and the threshold is a red dashed vertical line.
2. **Log R Dev**: the same form, with a threshold line at 0.2.
3. **TGA Ctrl Norm R**: the same form, PGx datasets only, threshold line at 1.
4. **Sample count**: horizontal bars per dataset.
5. **Samples Sex Estimates**: grouped horizontal bars per dataset, Male (blue), Female (orange), Unknown (grey), with a legend.
- Box-plot semantics: the box is Q1–Q3 with a median line, and the whiskers reach the smallest and largest non-outlier values (Tukey 1.5×IQR is implied by Plotly defaults).
- Local mode compares multiple datasets. With a single dataset, the dashboard still appears and summarizes that one dataset. Cloud mode handles one dataset per report.
**E. QC Metric Config (⚙ modal)**
- Two sections, "Sample QC Metrics" (Threshold, **Fail If**) and "Control QC Metrics" (Threshold, **Flag If**). Columns: Threshold, direction dropdown, Metric, Description.
- A blank field disables that check.
- Buttons:
- **Apply Thresholds** recomputes PASS/FAIL and FLAGGED/CLEAR and refreshes all visuals, including threshold lines, histograms, table colouring and heatmap cut-offs.
- **Download Thresholds** exports the applied thresholds as YAML that can be reused with `--config`.
- **Upload Thresholds** loads a YAML file into the fields.
- Changes are session-only and are not saved into the HTML file.
### 1.11 Scale limits
- More than 1,000 samples in a dataset: control and automated-QC plots are split into **tabs**, one per control category [SCREENSHOT: tabs Staining | Extension | Target Removal | Hybridization | Restoration | Stringency | Non-Specific Binding | Non-Polymorphic | TGA-Control].
- More than 12,000 samples in a dataset: scatter plots are **disabled** and replaced with a notice.
- More than 20,000 samples across datasets: loading slows down.
- More than 50,000 samples: very slow. Around 100,000 samples may exceed browser memory.
- The recommended remedy is to split by run, batch or centre.
### 1.12 Multi-dataset handling
- `--data` accepts three forms:
1. a single folder containing the required files;
2. a comma-separated list of folders;
3. a parent folder, searched recursively for any subfolder that contains both required controls CSVs.
- Labels:
- `--label` assigns labels in discovery or list order.
- Without `--label`, the folder name is used.
- Duplicate folder names get the suffix `_2`, `_3`, and so on.
- Labels are sanitized: unsupported characters become `_` (for example `My Label<1>` → `My_Label_1`), with a warning.
- Labels that are duplicates after sanitization are an error.
- Mixing genotyping and methylation datasets is an **error**. Allowed mixes: PGx with non-PGx (TGA columns are filled only for PGx), legacy with EX chips, and different versions of the same chip family.
- The dataset type is presumably detected from the presence of `gt_sample_summary.csv` or from the control categories.
### 1.13 Troubleshooting (FAQ)
- **Missing samples:** Sample IDs don't match across the `controls.*` files and `gt_sample_summary.csv`. The files are joined on SampleId / "Sample ID".
- **Unexpected failures:** thresholds are too strict; adjust them.
- **Scatter disabled:** more than 12,000 samples.
- **CSV parsing errors:** quoting or encoding problems; the files must be UTF-8 with comma delimiters.
- **Slow load:** very large datasets.
### 1.14 Referenced image URLs
Prefix: `https://2250409810-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FvpICEpxwEG3Hnd1kFkeJ%2Fuploads%2Fgit-blob-`
| Blob | File |
|---|---|
| 9bd70b3421607b494be8a0e3fb2d395150861c2a | control_dash_board.png |
| 205b9d102bd714a0a30b30c05ec944b53e28db3c | plotly_controls.png |
| 90483ee3ef5425879a83b21a0a9dafcfb1d743f1 | automated_qc_table.png |
| ab00903d584e23c77d0ae1b6294351539be247c8 | automated_qc_scatter_plots.png |
| 8ec0c44ce8899121079b4811abfcb3c56c947369 | Heatmap_by_chip.png |
| 153505c2ed2f9de39a0f7d64a8901c1800bcae4e | Heatmap_by_plate.png |
| 5784fe29732b65391eed5816d323c426565aa21a | Trend_analysis_table.png |
| 3907991e5920484cc5b4d4ea6ed2aedba047a7ee | boxplot_anatomy.svg |
| d8480b03f04b51279a3bb93143f9f274d7aa9ba2 | Trend_analysis_plots.png |
| d04cff85ce4ba02b9c524d9ae379db159cd0b276 | qc_thresholds.png |
| b9b5549fcc25112218ae026ce571fd9f9a5551a3 | sample_selection_filter_table.gif |
| 77433c64bb421d96ed0eb3cbce620c9bece45c45 | sample_selection.gif |
| 77affb1c369d3d2af3b47afe3f23d1fe7c925c1b | larger_dataset_control_dashboard.png |
| 118fe22b8b9ff54ca551d4387f65c37498606bf8 | larger_dataset_automated_qc.png |
| c901b0b9dc097c99d7e723fa6f91b2eaf77eccc1 | check.png (readme tick icon) |
(Append `?alt=media` to each URL.)
- Config template file IDs (not downloaded): `/files/wqHVYLDo1m2wx2zQ9d2h`, `/files/GBZegmeDYoPinNXmvoHx`, `/files/n2MNa2RrPWQbssTS1ol4`, `/files/Zp6CKGOL4NkdsfQl71Pq`.
- External training guide: `https://support.illumina.com/content/dam/illumina-support/courses/eval-inf-controls/story_content/external_files/Infinium_Controls_Training_Guide.pdf`
---
## 2. Applications / features page (and readme)
### 2.1 Analysis types
1. Genotyping and QC
2. PGx – CNV calling
3. PGx – Star allele annotation
4. Cytogenetics analysis
5. Cytogenetics analysis + third-party interpretation platform (cloud only)
6. Methylation QC (cloud only)
7. QC report (local and cloud, listed in the readme)
**Deployment:** a local CLI package ("no specialized server or hardware required") and a cloud GUI package.
| Analysis | Local | Cloud |
|---|---|---|
| Genotyping | ✔ | ✔ |
| PGx CNV | ✔ | ✔ |
| PGx star allele | ✔ | ✔ |
| Cytogenetics | ✔ | ✔ |
| Cyto + interpretation platform | – | ✔ |
| Methylation QC | – | ✔ |
| QC report | ✔ (multi-dataset trend) | ✔ (single dataset per report) |
### 2.2 Per-application details
**Genotyping and QC**
- Variants: SNV and indel. Minimum 1 sample.
- Supports any Infinium genotyping array: human (including custom and semi-custom) and **non-human diploid species** when a user-provided reference genome is supplied.
- The vendor provides human FASTA for GRCh37 and GRCh38.
- Local commands: `genotype call`, `genotype gtc-to-vcf`, `qc call`, `qc report`.
- Cloud maximum: **1152 samples**.
- Inputs: IDATs, manifest (BPM/CSV), cluster file, genome FASTA, optional sample sheet, QC report config YAML.
- Outputs per sample: GTC, SNV VCF (optional), TBI (optional).
- Outputs per batch: genotype summary files, Final Report (**cloud only**), Locus Summary (**cloud only**; applies to human and non-human diploid), QC metrics files, QC report, warning/error logs.
- Cost: local is a no-cost download; cloud uses credits for analysis and storage.
**PGx – CNV calling**
- Covers 7 target PGx genes across 10 target regions, plus genotyping. Variants: SNV, indel, CNV.
- **Minimum 24 samples, of which 22 must pass QC (LogRDev < 0.2); 96 recommended.** This implies a batch-referenced CN model.
- Local: `genotype call`, `genotype gtc-to-vcf` (optional), `pgx copy-number call`. Cloud maximum **384**.
- Inputs: add a PGx CN Model file.
- Outputs: PGx CNV VCF, BedGraph (optional, local), CN Summary file, Copy Number Batch file, QC metrics.
- Cost: local no cost; cloud uses credits.
**PGx – Star allele annotation**
- More than 50 genes and 2400+ targets. Variants: SNV, indel, CNV and star-allele diplotype. Same 24/22/96 minimum.
- Local: `genotype call`, `genotype gtc-to-vcf`, `pgx copy-number call`, `pgx star-allele call`, `pgx star-allele annotate`. Cloud maximum 384.
- Inputs: add a PGx Database file.
- Outputs: Star Allele JSON per sample; Star Allele CSV diplotype summary and supporting files; CN summary; CN batch file.
- **Cost: "Local: Per sample analysis. Cloud: Per sample analysis"**, with credits for storage. This is the only licensed/paid-per-sample module.
**Cytogenetics**
- Genome-wide CNV and LOH. Minimum 1 sample.
- Local: `genotype call`, `genotype gtc-to-vcf` (optional), `genotype gtc-to-bedgraph`, `cyto call`, `cyto annotate`. Cloud maximum 1152.
- Inputs: IDAT, manifest, cluster file, QC config, **Cytogenetics Model file**, **Cytogenetics Database file** (needed locally only), optional sample sheet.
- Outputs: GTC (optional on cloud), SNV VCF and TBI (optional), **Cytogenetics CNV VCF**, **Cytogenetics Annotation JSON**, BedGraph (optional, local), genotype summary, QC metrics, QC report.
- Readme features: CNV/LOH VCFs, annotated QC JSONs, bedGraph for LRR/BAF, and **adjustable thresholds: minimum deletion, duplication and LOH sizes, and smoothing parameters**.
- Cost: local free; cloud uses credits.
**Cyto + interpretation platform**
- Cloud only. Automatic case creation in a downstream interpretation and case-management platform.
- Extra per-sample cost when data is uploaded to that platform.
**Methylation QC**
- Cloud only. Minimum 1 sample, maximum 1152. Arrays: MSA and EPIC v1/v2 (from iScan) with recommended thresholds and all built-in controls. For non-human or custom arrays, probe availability varies and users must set thresholds.
- Readme: **21 algorithm-based quantitative control metrics** with adjustable thresholds, summary plots, and the proportion of CG probes passing a user-defined detection p-value threshold.
- Outputs: per-sample control-probe output and CG output; per-batch sample QC summary, summary plots, **principal component summary**, manifest files, logs.
### 2.3 Product compatibility matrix (full)
**Genotyping, PGx, Cyto**
| Group | Product | Tested manifest | Analysis | Cloud ver. | Local ver. | Genome | Notes |
|---|---|---|---|---|---|---|---|
| Genotyping | ASA | ASA-24v1-0_E2 | Genotyping | v1.1, v1.4 | v1.0+ | GRCh37, GRCh38 | |
| Genotyping | BovineSNP50 v3 | BovineSNP50_v3_A1 | Genotyping | v1.1, v1.4 | v1.0+ | **UMD3** | non-human bovine |
| Genotyping | CGA | CGA-24v1-0_A1 | Genotyping | v1.1, v1.4 | v1.0+ | 37, 38 | |
| Genotyping | GCRA | GCRA-24v1-0_20068388_B2 | Genotyping | v1.1, v1.4 | v1.0+ | 37, 38 | |
| Genotyping | GDA | GDA-8v1-0_D2 | Genotyping | v1.1, v1.4 | v1.0+ | 37, 38 | |
| Genotyping | GSA v3 | GSA-24v3-0_A2 | Genotyping | v1.1, v1.4 | v1.0+ | 37, 38 | |
| Genotyping | GSA v4 | GSA-48v4-0_20085471_D2 | Genotyping | v1.1, v1.4 | v1.0+ | 37, 38 | EX product |
| Genotyping | JSA | JSA-24v1-0_B2 | Genotyping | v1.1, v1.4 | v1.0+ | 37, 38 | |
| Genotyping | PRSbooster | PRSbooster_20083382_A | Genotyping | v1.1, v1.4 | v1.0+ | GRCh37 only | |
| PGx | GCRA-ePGx | GCRA-PGx-24v1-0_20084467_C2 | GT; PGx CNV; star allele | v1.1+ | v1.1+ | GRCh38 only | EX PGx |
| PGx | GDA-ePGx | GDA_PGx-8v1-0_20042614_G4 | GT; PGx CNV; star allele | v1.1+ | v1.1+ | GRCh38 | current G-series |
| PGx | GSAv4-ePGx | GSA-PGx-48v4-0_20079540_E2 | GT; PGx CNV; star allele | v1.1+ | v1.1+ | GRCh38 | EX PGx |
| Cyto | GDA Cyto | GDACyto-8v1-0_20047166_E2 | Cyto (+ interp. cloud only) | v1.2+ | v1.2+ / N/A | 37, 38 | |
| Cyto | GSA Cyto | GSACyto-24v1_20044998_C2 | Cyto (+ interp.) | v1.2+ | v1.2+ / N/A | 37, 38 | |
| Cyto | CytoSNP-850K iScan | CytoSNP-850Kv1-4_iScan_B2 | Cyto (+ interp.) | v1.2+ | v1.2+ / N/A | 37, 38 | |
| Cyto | CytoSNP-850K NS550 | CytoSNP-850Kv1-4_NS550_B2 | Cyto (+ interp.) | v1.3+ | v1.3+ / N/A | 37, 38 | NextSeq-550-scanned IDATs |
**Methylation (cloud v1.0; local N/A; GRCh38)**
- EPIC v1: `infinium-methylationepic-v-1-0-b5-manifest-file.csv`
- EPIC v2: `EPIC-8v2-0_A2.csv`
- EPIC-Xtra: `EPIC-Xtra_GS_20144570_A1.csv` (custom)
- MSA: `MSA-48v1-0_20102838_A1.csv`
**Species:** human; bovine (UMD3); any non-human diploid organism with a user reference. **Builds:** GRCh37, GRCh38, UMD3. PGx is GRCh38 only.
### 2.4 Performance and accuracy claims (readme)
- Genotyping accuracy greater than 99.5%. A genotyping VCF in as little as **35 s per sample**.
- PGx CNV accuracy greater than 95%.
- CYP2D6 call rate greater than 97%. All PGx results in **about 1 min per sample**.
- Methylation: 21 control metrics.
### 2.5 Licensing and pricing
- Local genotyping, cyto and PGx CNV: a free download from the support site.
- Star-allele annotation: per-sample charge, locally and on cloud.
- Cloud: credit-based for compute and storage.
- Interpretation-platform integration: extra per-sample fee.
### 2.6 Integration points
- **Scanner:** IDATs from the iScan scanner; NextSeq 550 IDATs for CytoSNP-850K. The cloud has a "troubleshoot iScan" page, implying direct scanner upload.
- **LIMS / sample sheet:** metadata propagation. The sample sheet provides `Sample_Plate` and `Sample_Well`.
- **Downstream:**
- VCF + TBI;
- bedGraph for LRR/BAF, for genome-browser visualization;
- GTC, which is interoperable;
- Final Report and Locus Summary (legacy desktop-tool-style formats, cloud only);
- the interpretation platform, via automatic case creation;
- sharing of cloud projects.
- **No LIMS API** is mentioned on these pages.
---
## 3. Error and warning messages (verbatim)
`❌` marks an error and `⚠️` a warning.
- ❌ `Input data folder does not exist: data/non_existent_dir`
- ❌ `No valid dataset folders detected. Each folder must include at least: controls.raw_metrics.csv, controls.qc_metrics.csv`
- ❌ `Dataset MyDataset is missing required file(s): ... controls.qc_metrics.csv ...`
- ❌ `Number of labels (2) does not match number of datasets (3).`
- ⚠️ `Label sanitized: My Label<1> → My_Label_1`
- ❌ `Duplicate labels after sanitization: dataset (x2). Each dataset label must be unique.`
- ❌ `Mixed dataset types are not supported in a single report. Genotyping datasets: geno_run_A, geno_run_B ... Methylation datasets: meth_run_C ...`
- ❌ `Invalid --output-format value. Only csv or xlsx are accepted.`
- ❌ `QC config file was provided but does not exist: /path/to/config.yaml`
- ❌ `Input file must be a YAML file with extension .yaml/.yml. Current config file extension: .json`
- ❌ `Failed to parse QC config as YAML ...`
- ❌ `QC config must be wrapped in a top-level QC object containing a Report object.`
- ❌ `Invalid threshold overrides: Unknown threshold key ...`
- ❌ `Invalid threshold overrides: Invalid numeric value ...`
- ❌ `Threshold for Autosomal Call Rate must be between 0 and 1 ...`
- ❌ `Threshold for stainingGreen must be non-negative ...`
Categories listed in prose: the input directory is missing; required files are missing; the label count doesn't match; labels become non-unique after sanitization; genotyping and methylation datasets are mixed; the output format is invalid; the threshold configuration is invalid.
Other in-report messages:
- The notice that replaces scatter plots above 12,000 samples. Its exact text is not given.
- Hints: the Notepad `.yaml.txt` warning, and the case-sensitive CLI warning.
---
## 4. Algorithm hints
1. **Control ratios.**
- Background plus offset appears in the denominator or numerator for Target Removal and NSB ("(Bkg + offset)"). This matches the plan's `bkg + x` with x = 3000.
- Staining is High/Bkg per channel.
- Extension green = min(Ext C,G green) / max(Ext A,T green); extension red = min(Ext A,T red) / max(Ext C,G red).
- NP uses the same min/max pattern.
- Hybridization is green High/Med and Med/Low.
- Stringency is PM/MM. The channel is ambiguous: the text says red and the UI says green.
- Restoration is green over background.
- All of this matches plan §9.1.
2. **TGA_Ctrl_5716 Norm R** is the normalized R of a specific PGx assay-control locus, with threshold ≥ 1. It is reported per sample in the sample summary and in trend statistics.
3. **Autosomal Call Rate vs Call Rate:** both are reported; functional QC uses the autosomal one.
4. **LogRDev** = "LRR genome-wide SD". Sex estimate is M/F/U.
5. **Chip completeness:** the number of expected positions per chip comes from the chip format. "Missing samples" = expected positions − observed positions. "Complete chips" have every position filled.
6. **Batch requirement for PGx CN:** at least 24 samples with at least 22 having LogRDev < 0.2. This suggests per-batch normalization of intensities (a reference-panel median) before CN calling.
7. **Cyto:** parameters for minimum deletion, duplication and LOH size plus smoothing suggest segmentation with size filters. Outputs are a CNV VCF, an annotation JSON (with ISCN-like annotation from a cyto database) and bedGraph tracks.
8. **Methylation QC:** 21 control metrics, a detection p-value per CG (the fraction of CGs passing), and a PCA summary.
9. **Thresholds** come from the null-distribution centre and spread across more than 10 datasets. This suggests offering a data-driven "suggest thresholds" function (for example median − k·MAD).
10. **Excluded raw categories:** NEGATIVE and NORM are used internally (NORM for normalization, NEGATIVE for background/p-values) but are not reported.
11. Plate information from IDATs implies that the IDAT RunInfo/metadata blocks carry plate and well values. The sample sheet overrides them.
---
## 5. Gap analysis vs the SimurgArray plan (concrete spec additions)
The plan's §9.5 specifies a self-contained HTML report with a sample table, control heatmap, CR-vs-LogRDev scatter, sex plot, intensity distributions, chip layout and TSV/XLSX export. §9.2 has the flags CR < 0.98 and LogRDev > 0.20. The vendor tool goes considerably further. The proposed additions follow.
### 5.1 QC data model and interchange
- **G1.** Emit three stable per-batch CSV artefacts as a decoupled report input contract:
- `controls.raw_metrics.csv` (SampleId, Category, BeadAddress, ControlName, ColorLabel, GreenIntensity, RedIntensity);
- `controls.qc_metrics.csv` (SampleId, scan metadata ImagingDate/ScannerId/ScannerVersion/SamplePlate/SampleWell, then one column per control ratio);
- `sample_summary.csv` (Sample ID, Name, Folder, Autosomal CR, CR, LRR SD, Sex, optional assay-control Norm R, barcode, position, and all sample-sheet columns).
- The report subcommand must consume only these files, so a report can be regenerated or merged without raw data.
- **G2.** Add a control-only QC path, `simurg qc call`, that works from IDAT plus CSV manifest without a cluster file, for genotyping and methylation.
- **G3.** Extract scan metadata from IDAT (scan date, scanner ID, software version, and plate/well where present). Sample-sheet values override IDAT values.
- **G4.** Add the categories NEGATIVE, NORM, `NP (G) 1..5`, `Biotin(5K)` and `DNP(20K)` to an exclusion list for raw-probe reporting, while still using them internally.
### 5.2 Threshold configuration
- **G5.** Define a YAML schema `QC: Report: {key: number|null}` with the keys:
- `callRate`, `logRDev`;
- `stainingGreen`, `stainingRed`, `extensionGreen`, `extensionRed`, `targetRemovalI`, `targetRemovalII`;
- `hybGreenHighMed`, `hybGreenMediumLow`, `restoration`, `stringency`;
- `nonSpecificBindingGreen`, `nonSpecificBindingRed`, `npGreen`, `npRed`;
- `tgaControl` (generic name: `assayControlNormR`, with a configurable locus name);
- methylation: `bisulfiteConversionI{Green,Red}{,Bg}`, `bisulfiteConversionII{,Bg}`, `specificityI{Green,Red}`, `specificityII{,Bg}`.
- `null` disables a check.
- Add an optional per-key `direction: below|above`, since the UI allows it.
- SimurgArray may keep its own camel-case key names; key-name compatibility is optional.
- **G6.** Precedence is CLI > YAML > defaults. Provide `--threshold-call-rate` and `--threshold-lrr-sd`. Validate: call rate in [0, 1], other values ≥ 0, known keys only, numeric values only, top-level structure present, `.yaml`/`.yml` extension required.
- **G7.** Ship four starting-point profiles: non-EX genotyping, EX genotyping, EPIC methylation, MSA methylation. Document that they are review cutoffs. Reconcile the conflicting defaults found here, recording each as a "profile" value:
- LogRDev: 0.15 vs 0.20;
- target removal: 5 vs 1;
- hybridization: 1.25 vs 1;
- stringency: 1.5 vs 2;
- NSB: 5 vs 1.
- **G8.** Add a `simurg qc suggest-thresholds` command. It fits a robust centre and spread of each metric over a reference cohort and proposes cutoffs.
### 5.3 QC logic
- **G9.** Keep two independent status axes:
- Functional: PASS/FAIL from call rate and LRR SD. Status is "N/A" when there is no genotyping.
- Control: CLEAR/FLAGGED, with a `control_flag_codes` column holding a delimited list of failing keys.
- **G10.** Add an assay-control locus metric (the normalized R of a named control probe) for PGx-type products. Include it in the flags and in the trend statistics.
- **G11.** Report both Autosomal Call Rate and overall Call Rate. Only the autosomal value drives PASS/FAIL.
### 5.4 Report UI (self-contained HTML, bundled JS, no network)
- **G12.** Five views:
1. Control Dashboard: an ACR box-plot banner, plus per-category, per-channel scatter plots of raw control intensities with one trace per probe and "expected behaviour" help text.
2. Automated QC: two status histograms (count and %), the sample table, and per-metric scatter plots with formula help text and a dashed threshold line labelled "Flag if below X".
3. Sample heatmaps: chip or plate grid, continuous or binary colour scale, paging, and a max-chips setting.
4. Trend analysis: the dataset summary table plus box, bar and sex plots.
5. Threshold config modal with Apply / Download YAML / Upload YAML. Changes are session-only.
- **G13.** Interactions:
- Linked brushing: a box or lasso selection in any scatter highlights the same samples in all scatters and filters the table. Double-click clears the selection.
- Selecting table rows highlights the matching points. A "Select none" control clears it.
- Export (xlsx/csv) exports only the selected rows when a selection exists.
- Columns can be shown or hidden. Every column is sortable and has a filter (text or range). The table has global search and pagination.
- Controls: Sort plots by any metric or metadata field; Color by or Facet by any categorical metadata field with 2–20 unique values; dataset selector; colour-palette selector.
- **G14.** Chip geometry is derived from the positions present (RxxCyy) and the known chip formats, so that 24-, 48- and 8-sample layouts all work. The plate is 8×12 by well.
- **G15.** Trend summary columns:
- #samples, #complete/#chips, #missing positions, scan date range;
- ACR min, median, mean (SD), # below threshold;
- LRR SD mean (SD), median, # above threshold;
- control-locus mean (SD), # below threshold;
- #M/#F/#U.
- **G16.** Scale behaviour: use tabs by category above 1,000 samples per dataset. Above 12,000, disable scatter plots and show a notice (or better, add WebGL/aggregated density plots so they are not disabled). Warn when the total exceeds 20,000. Offer `--split-by run|plate|center`.
### 5.5 Multi-dataset and CLI behaviour
- **G17.** `simurg qc report --data` accepts a folder, a comma-list or a parent folder (recursive discovery of folders containing the required files). `--label` is a comma-list whose count must match the datasets. Labels are sanitized (non-alphanumeric characters become `_`) with a warning, deduplicated with `_2`, `_3` suffixes, and duplicates after sanitization are an error.
- **G18.** Refuse to mix genotyping and methylation datasets, with an error listing both groups. Allow mixed chip formats and assay-control presence.
- **G19.** Output names are dated: `qc_report_YYYY_MM_DD.html` and `qc_table_YYYY_MM_DD.{xlsx,csv}`. The xlsx gets conditional formatting and a "Thresholds" sheet recording each value and its source (default, YAML or CLI). The csv has values only. Metadata columns are sorted alphabetically.
- **G20.** Add a privacy option, `--drop-metadata col1,col2` or `--no-metadata`, so a report can be shared without sample-sheet PHI. The vendor tool requires editing the CSV instead.
- **G21.** Adopt the error and warning catalogue from section 3 as acceptance tests.
### 5.6 Breadth items missing from the plan's scope
- **G22.** Non-human diploid support: a user-supplied FASTA or genome build and a species-agnostic chromosome list, with a configurable sex-chromosome set and autosome definition. Bovine UMD3 is the test case; check whether any BovineSNP50 data is available for the dataset tiers.
- **G23.** Legacy-desktop-style outputs: a "Final Report" (sample × SNP long or matrix format) and a "Locus Summary" (per-SNP call frequency, cluster statistics). Plan §7.9 has locus stats; add a writer.
- **G24.** Cyto module (plan §10): expose `min_del_size`, `min_dup_size`, `min_loh_size` and smoothing parameters. Outputs: CNV/LOH VCF, annotation JSON, and LRR/BAF bedGraph. Accept NextSeq-550-scanned IDATs.
- **G25.** PGx CN (plan §11): define a batch requirement (default ≥ 24 samples with ≥ 22 passing LRR SD < 0.2, 96 recommended) and a clear error when it is not met. Scope: 7 genes / 10 regions. Star alleles: more than 50 genes. Target metrics to validate against: CN accuracy > 95%, CYP2D6 call rate > 97%.
- **G26.** Methylation QC (plan v2 item 14): 21 control metrics (bisulfite I/II, specificity I/II, target removal I/II, and so on), a detection p-value (fraction of CpGs passing), a PCA summary, and support for EPIC v1/v2, EPIC-Xtra and MSA manifests.
- **G27.** Performance benchmark targets: genotyping VCF at ≤ 35 s per sample and PGx at ≤ 1 min per sample on a commodity machine; genotype concordance > 99.5% vs the oracle. Add these to §16.5 and §19.
- **G28.** Product-matrix test plan: at least one dataset per tested manifest family (ASA, CGA, GCRA, GDA, GSA v3/v4, JSA, PRS, PGx GCRA/GDA/GSA, Cyto GDA/GSA/CytoSNP-850K), across GRCh37/38 where relevant. PRS-type products are GRCh37 only and PGx products are GRCh38 only.