Plant Schematics Ingestion
Plant Schematics Ingestion
The Plants page (sidebar → Config → Plants) turns a
plant's PDF diagrams — hydraulic/mechanical P&ID, electrical single-line
schematics — into a structured, IEC 81346-aligned Markdown document that
feeds classification context for that plant via the Plant Schema
selector on the Classify and Classify Bulk pages.
New to this page? Open the ⋯ menu at the top right (the one showing the app version) and choose Guided tour for a walkthrough of the upload form, the review-before-saving step, and the full editing toolbar — the tour briefly shows a sample schema to demonstrate the toolbar and editor, and restores whatever you were looking at once it ends.
Step 1 — Upload
- Type the plant's name (
res_top_node) into the Plant field; existing plant names autocomplete as you type. - Choose a PDF via Unifilar schema (PDF).
- Optionally, also choose the schema's DXF source (optional) — the same drawing exported as a vector CAD file. When present, parsing reads the exact codes and box geometry from the DXF instead of relying on the rendered image, which is more accurate for RDS-PP paths.
- Click Upload. The platform stages the file(s) and shows you the
filename, page count, and size for confirmation before moving them into
that plant's folder (
data/plant_schemas/<PLANT>/).
Step 2 — Parse with LLM
Click Parse with LLM. A dialog opens first: it says what is about to happen — the drawing is read from scratch, whatever is in the editor is replaced by the result, and nothing reaches disk until you press Save — and it gives you a box for context and instructions.
Use that box for what the drawing does not show, and for what it leaves you to decide:
- the unit a detail sheet belongs to, when the sheet does not name it ("this sheet is unit M01");
- a local convention ("valves with no marking are ball valves");
- where to put codes the sheet leaves dangling ("codes with no parent go under MEW10").
What you write is saved with that schema and comes back pre-filled the next time you parse or refine it, so you write it once rather than remembering it every run. Clearing the box and confirming removes it; pressing Cancel changes nothing at all.
Your notes are authoritative for what the drawing does not show, but they never override a code that is legibly drawn. If a note and the page disagree, the code is reported as drawn and the disagreement is flagged — silently "correcting" a legible code would hide a real discrepancy that only you can settle.
Under the hood:
- The PDF's text layer is extracted deterministically to get an authoritative list of every IEC code printed on the page.
- Each page is also rendered to a high-resolution image (200 DPI).
- If a paired DXF was uploaded, its text and box geometry are parsed
deterministically first: every RDS-PP code (
=function,+location,-product) is read as exact text, and its box-nesting (relative vs. absolute path) is resolved from the drawing's real coordinates — no guessing from a rendered image. - A DXF code the geometry pass can't resolve (its enclosing box wasn't detected — e.g. drawn as separate open line segments rather than one closed shape) gets a targeted zoomed crop generated automatically from its DXF coordinates, so the model is shown that exact region of the page directly rather than having to guess where to look.
- A Claude agent receives the code list, the page images, the DXF-resolved candidates, and any targeted crops, and classifies every code by its RDS-PP aspect — reading which codes are drawn inside which bordered boxes when there's no DXF to resolve that geometrically. When a code is too small or unclear to read, the agent can also zoom into any region of the page itself (as many times as needed) instead of guessing; it also reads the platform's wiki through its own tools to ground each code's description, rather than a fixed set of pages chosen in advance.
The result is a Markdown document with two sections:
- Section 1 — Hierarchy: one nested bullet tree per RDS aspect. The
### Function (=)tree is always present;### Location (+)and### Product (-)appear only when the schema actually draws that distinction — a schema with no=/+/-prefixes has every code on the function aspect, which is the normative reading of an unprefixed code. Nesting follows each code's parent to any depth, so a protection-function code such asFE50sits under its bay like any other node. A node marked*[inferred]*was reconstructed from a child's path because the schema named it but never drew it; it starts without a description. Codes whose parent could not be determined at all gather under Orphan codes at the end of the section, and are fixed by dragging the bullet under the right parent — the indentation is what decides a node's parent, not the text of its code. What counts as parentless depends on the drawing. On a plant-wide diagram, which names Main Systems throughout, a Technical System with no Main System above it is a label floating free of its unit, and it is listed as an orphan so you can place it. On a detail sheet of a single subsystem, no Main System is drawn at all — the unit is implied by the document — so the top-level codes there are Technical Systems, and they are treated as roots rather than reported as orphans. In### Product (-)the equipment is grouped under the function it is fitted to: the=line is the function, and the-lines nested beneath it are the physical items on it. The same product label recurs under different functions — a valve type fitted to five lines appears once per line — and each of those is a distinct object, so the grouping is what tells them apart. A product whose function is unknown stays at the top level. - Section 2 — Code Inventory: one table row per code, derived from the tree above rather than written separately, so the two cannot disagree. The function headings in the Product tree are references, not codes of their own, so they get no row — they already have one in the function tree.
Step 3 — Review and refine
The hierarchy in Section 1 opens in an integrated code editor so you can correct it. Refine with LLM opens the same context dialog first, so you can explain the edits you just made — why a code was moved, what a local convention means — and those notes ground the descriptions the model writes. They cannot move anything: the hierarchy is already fixed by then.
Refine then does two things: it fills in the
descriptions that are missing — the *[inferred]* nodes, and any code you
added by hand — and it rebuilds the Code Inventory from your hierarchy.
Refine cannot change your hierarchy. It is not asked to leave it alone: the model's answer has no field in which a hierarchy could be expressed, so whatever you fixed stays fixed.
A description that is already filled in is never overwritten, whoever wrote it. That makes clearing a description the way to ask for it to be looked up again: blank the text after the colon, press Refine, and the model grounds a fresh one in the knowledge base.
The hierarchy is read back from your indentation, not from the text of each
code — so you fix a misplaced code by dragging its bullet under the right
parent, and an orphan you move takes its own children with it. A line that does
not match the bullet format (- **CODE** (BL1): description) cannot be read
back and is dropped. When that happens, Refine's toast reports how many lines
were dropped in place of its usual "descriptions filled" confirmation —
the editor has already reloaded with your other edits applied, so check the
count before saving.
Schemas parsed before this document format stay fully editable — Monaco and Save both keep working — but Refine with LLM is unavailable on them: the editor shows a banner and you re-run Parse with LLM to regenerate the document into the current format before Refine works again.
Click PDF to view the original schema alongside your edits — by default it opens full-screen, but toggling Split first makes it open side by side with the editor (PDF on the right, editor on the left) so you can read the diagram while correcting the hierarchy. If you want to discard everything and start over, Clear empties the editor (after a confirmation prompt); like any other edit, nothing is removed on disk until you click Save.
Step 4 — Normative verification
After parsing, a deterministic check (no LLM involved) runs against IEC
81346/RDS-PP invariants — every code from the PDF's text layer must also
appear in the parsed result, a BL0 code must have no parent, a BL1 code
must have a BL0 parent, two entities resolving to the identical path are
flagged as duplicates, and a product whose linked function is missing from
the result is flagged. This is a debug-level signal for maintainers (logged
server-side), not something rendered into the saved document or shown in
the UI directly — though the product case is visible in the document
anyway: a product whose function is unknown sits at the top level of the
### Product (-) tree instead of under a function heading. This check
is unrelated to the Orphan codes list: a product is never placed there —
it always renders in its own Product tree — and an orphan is a code of any
other aspect whose parent could not be resolved at all, not one whose parent
is merely unusual in shape (an ANSI/IEEE protection number included).
Once saved
A validated, saved schema becomes selectable in the Plant Schema multi-select on both the Classify and Classify Bulk pages, where it's injected as structural context for the LLM — and it's the document that gets updated by the inferred schema suggestions described in Learning from Corrections.