lumnik. / scenarios All scenarios · Français

HPLC report: the impurity over its limit, read from the instrument's export

Goal Read the injection reports an HPLC exports, units glued and decimal commas, and be told when an impurity exceeds its specification.

An HPLC's acquisition software exports one report per injection: UTF-16, a header block, then the peaks.

line
BOM:ff fe
line
Report;Area Percent / External Standard
line
Sample Name;LOT 26-0451 Assay
line
Sample Info;Paracétamol 500 mg, comprimé
line
Injection Date;05/11/2026 09:13:32
line
Instrument;HPLC-02
line
Method;ASSAY-PARA-V3.M
line
Peak;RetTime;Name;Area;Amount
line
1;2,315min;Impurity A;1 231,1mAU*s;0,08%
line
2;4,872min;Paracetamol;1 535 987,4mAU*s;99,81%
line
3;6,103min;Impurity B;1 692,8mAU*s;0,11%

evidence: replay.log, report-0451.txt, peaks-0451.txt, count-read.txt, impurities.txt, inbox-drop.json · transform v1

manifests/10-injection-reports.yaml
apiVersion: connectors.lumnik.io/v1kind: Connectormetadata:  name: scenario-chrom-a  connector_type: csv-file  scopes: [qc-hplc-a]spec:  transport:    kind: local    path: /tmp/lumnik-scenario/chromatograph-report/a/*.csv   # the folder the acquisition software exports to  parser:    lines: true                    # a report, not a table: a header block, then the peaks  after_process: none  mapping:    cell:      - regex-extract: { column: line, pattern: "^([^;]+);", groups: { 1: field } }      # the header block: one key;value per line      - regex-extract: { column: line, pattern: "^Sample Name;(LOT \\S+)", groups: { 1: sample } }      - regex-extract: { column: line, pattern: "^Injection Date;(.+)$", groups: { 1: injected_at } }      - regex-extract: { column: line, pattern: "^Instrument;(.+)$", groups: { 1: instrument } }      - regex-extract: { column: line, pattern: "^Method;(.+)$", groups: { 1: method } }      # a peak: the value and its glued unit, cut apart      - regex-extract:          column: line          pattern: "^(\\d+);([\\d ,]+)(min);([^;]+);([\\d ,]+)(mAU\\*s);([\\d ,]+)(%)$"          groups: { 1: peak, 2: rt, 3: rt_unit, 4: peak_name, 5: area, 6: area_unit, 7: amount_pct, 8: amount_unit }      # the report's header, on each of its peaks; a new report starts empty      - fill-down: { columns: [sample, injected_at, instrument, method], reset-when: { column: field, in: [Report] } }      - parse-number: { column: rt, decimal-separator: "," }      - parse-number: { column: area, decimal-separator: "," }      - parse-number: { column: amount_pct, decimal-separator: "," }      - parse-date: { column: injected_at, formats: ["dd/MM/yyyy HH:mm:ss"] }
manifests/20-impurity-over-limit.yaml
apiVersion: apps.lumnik.io/v1kind: Processmetadata:  name: scenario-chrom-impurity-aspec:  scope: qc-hplc-a  on: { event: data.row.changed, table: connector.t_scenario_chrom_a }  when:    - peak_name~Impurity    - amount_pct>0.15                # the specification's limit for a specified impurity  emit:    type: decision.impurity-over-limit-a    message: "{sample}: {peak_name} at {amount_pct} % (limit 0.15 %), {instrument}, injected {injected_at}"    key: sample
$ lm connector run scenario-chrom-a
run scheduled: 526b41ae-87dd-4e89-adf3-e1cbd5c90596

$ lm run get 526b41ae-87dd-4e89-adf3-e1cbd5c90596
ID        CONNECTOR         ENDPOINT  STATUS     IN  OUT  SKIPPED  DEAD-LETTERS  STARTED           ENDED             EVALUATED
526b41ae  scenario-chrom-a  default   Completed  60  60   0        0             2026-11-06 17:04  2026-11-06 17:04  yes
• 1 file(s) unchanged since they were last read — not read again

$ lm inbox --process scenario-chrom-impurity-a
ID     WHEN      PROCESS                    MESSAGE                                                                                   ENTITY_KEY
24660  just now  scenario-chrom-impurity-a  LOT 26-0459: Impurity B at 0.21 % (limit 0.15 %), HPLC-02, injected 2026-11-06T08:57:32Z  LOT 26-0459

Limits

  • The table keeps every line of the report, header lines included: a rule reads the peaks by their columns.
  • One limit for every impurity: a limit per impurity is one Process per impurity.
  • The regex expects these three units; another unit leaves the line uncut, and the rule does not see it.
  • Synthetic lots, peaks and amounts.

Laboratory · HPLC

The results sit in the instrument's reports.

One file per injection, made to be printed.

UTF-16, 1 532 117,2mAU*s, 0,21%

The problem

LOT 26-0459: impurity B at 0,21 %.

  • The limit is 0,15 %.
  • The report is read by eye, when it is read.

What is not changed

The acquisition software stays as it is.

  • Its own export, in its own folder.
  • No script, no conversion by hand.

What had to be written

pattern: "([\\d ,]+)(%)"
fill-down: { reset-when: Report }

One regex per line kind, one fill-down.

  • The unit in its own column.
  • A Process: impurity above 0.15 %.

The result

One decision, LOT 26-0459.

  • LOT 26-0461 sits on 0,15 %: not above.
  • 36 peaks, 0 cell error.

Try it

The scenario replays locally.

Every step is published with its output.

This scenario runs on lumnik Open, free and open source.

Try lumnik Open →