Skip to content

Procedure Templates

Procedure templates are versioned documents of a calibration workflow. They are managed in the "Templates" tab of the procedure detail page and can be instantiated into calibrations.

Concept

A template carries either an uploaded file (e.g. a calibration instruction as PDF) or a serialized test sequence in the calserver.procedure format (JSON), generated from a calibration's test steps. Every template runs through the lifecycle Draft → Approved → Released.

Template kind and measurement capture

A template's kind decides which measurement capture calServer offers on the calibration. It is not maintained by hand but derived from the file type:

Kind File types Offered capture
Own measurement template json (calserver.procedure) Internal measurement runtime ("Start measurement capture")
MET/CAL procedure pxe "Start in MET/CAL" via the file type's launch command
Excel measurement sheet xlsx, xlsm, xls, csv Open the Excel sheet (launch command), otherwise download
Other template pdf, doc(x), md, everything else Open the instruction; measurements are entered manually

The extension→kind mapping lives in config/procedure.php and can be extended per installation (e.g. an additional MET/CAL extension).

Where the kind shows up

  • The procedure's templates tab has an "Art" column; the raw file type stays available as a hint on the entry.
  • Editing steps is offered only for an own measurement template — MET/CAL procedures, Excel sheets and instructions carry no editable sequence.
  • "Vorlage laden" in the test steps tab likewise offers only own measurement templates. Sending another kind through the API answers 422 and names the kind.

What happens on the calibration

The button in the calibration's header shows one system-determined action, resolved along this chain:

  1. The device's standard procedure; if the device has none, the device type's.
  2. Its governing template: the newest released one, falling back to the newest overall.
  3. That template's kind — which yields the action from the table above.

The tooltip names the procedure, its origin (device or device type), the kind and the version. Alternatives (resume the test run, download the template, enter measurements manually) sit in the adjacent menu.

An action that is not ready stays visible and states its reason on click — for example "not released yet" or "no launch command (file link) configured for this file type". An external launch always requires a released template.

Without an assigned standard procedure only manual entry remains; if the calibration already carries test steps, resuming the run is offered instead.

Switching the procedure for a single calibration

The device/type assignment is a default, not a constraint. Via "Prüfprozedur wechseln …" in the start button's menu, this one calibration runs a different procedure:

  • The picker lists what is assigned to the device and to the device type, including where each assignment comes from.
  • The device's standard procedure stays unchanged — future calibrations are not affected.
  • Existing test steps are left untouched. Switching chooses, it does not load. To adopt the new procedure's steps, use "Vorlage laden" in the test steps tab — that action replaces existing steps explicitly.
  • "Standard wiederherstellen" drops the choice; the calibration follows the device/type default again.

The chain is therefore: calibration → device → device type.

Test steps on start

When an empty calibration starts the internal measurement capture, calServer stages the governing template's test steps — otherwise the run would open on an empty list. A message names the count, template and version.

If the calibration already carries any test step, nothing happens: captured work is never overwritten.

The run records which template version it started from.

The plan and the switch are also available directly:

GET    /api/v2/calibrations/{ctag}/capture-options
PUT    /api/v2/calibrations/{ctag}/procedure     # { "procedure_id": "..." }
DELETE /api/v2/calibrations/{ctag}/procedure     # back to the default

Versioning

Action Effect
Upload New template at version 0.1 (draft)
New version Minor bump (0.1 → 0.2 → …); the previous version loses its "latest" flag
Approve Major bump (e.g. 0.3 → 1.0), status Approved; the approved file is carried over immutably
Release Status Released (only possible for approved versions)

Each template's version history is available via the history icon; every version stays individually downloadable.

Changing name and assignment

A template's name and procedure can be changed after the fact — both in a procedure's templates tab and in the cross-procedure list under Procedures → Test plans:

Icon Action Effect
Tag (Rename) Change the name Applies to every version of the template; the stored files keep their filenames
Link (Assign) Set, switch or clear the procedure The whole version chain moves along; the test steps are untouched

Both apply to every template kind, not just to internal capture templates: an uploaded PDF carries a name too, and otherwise it is taken from the filename without asking.

Why it matters: An imported test plan — and one saved off a calibration — arrives without a procedure and shows up as "not assigned". Without an assignment, measurement capture will not find it. The button in the "Procedure" column, or the link icon, gives it one without deleting and recreating it, which would cost the version history.

The reverse route lives in the procedure's templates tab: "Assign existing" lists every test plan that does not belong to this procedure and moves the chosen one here. If it still hangs off another procedure, the list says so beforehand.

Creating a new test plan

Three routes lead to a new test plan:

Where Action Procedure
Procedures → Test plans "Create test plan" Optional in the dialog; leaving it empty is allowed
Procedures → Test plans "Import" None — the plan arrives as "not assigned"
A procedure's templates tab "Create manually" The procedure you are standing in

A test plan does not need a procedure in order to exist. That is deliberate: whoever writes a plan does not always know yet which procedure it belongs to, and an import never knows. A plan without a procedure shows up as "not assigned" and is hooked in later via the link icon.

Running it does require the assignment, though: measurement capture finds a test plan through the device's — or the device type's — standard procedure, and without a procedure the plan is in none of those chains.

Sharing a test plan as a package (ZIP)

Besides exporting the bare test plan file (JSON), internal templates offer a package export: a ZIP in the calserver.procedure-package format carrying everything that belongs to the plan.

manifest.json        manifest: file list with a SHA-256 checksum per entry
README.md            description (existing attachment or a generated skeleton)
procedure.json       the test plan, byte-identical to the exported version
images/…             pictures (connection diagrams, measuring guides), optional
docs/…               documents (manufacturer specifications etc.), optional

Step images: Since document version 3 every step in procedure.json may carry an images field — a list of basenames from the package's images/ folder. Measurement capture shows these pictures right at the step (connection diagram on the group header, measuring guide or test pattern on the step), and the dry run in the test plan editor shows them as well — an imported template can be reviewed with its pictures before it is ever loaded into a calibration. The image files themselves are attachments on the test plan; the step only references them by name.

The manifest is what makes the package tamper-evident: every entry is listed with checksum and size, and the import rejects a package whose content deviates from the manifest — in both directions. The manifest also carries the revision of the exported version (plan: major, minor, release state) and the package format version.

On import (the same "Import" button — the .zip extension decides), a new template at version 0.1 is always created — the source system's release state is never adopted, only surfaced as a note. Pictures and documents from the package are stored as attachments (document management, type "Prüfplan-Anlage") on the new test plan; a subsequent package export picks them up again.

Ready-made sample packages (Fluke 23, caliper 150 mm) are available on the calServer reports download page in the "Prüfpläne" category; the machine-readable manifest schema lives at https://calhelp.github.io/calServer-reports/schema/procedure-package.schema.json.

Step editor

"Create test plan", "Create manually" and the pencil icon on a template all open the step editor. It offers two views, switchable in the top right; the choice is remembered per user:

  • Table (default): one row per measurement point, cells edited in place. Tab commits and moves to the next cell, wrapping into the next row. Rows are reordered by the handle on the left. A click on a row shows its fields in the side panel on the right (tabs Settings and Instruction), as a drawer below about 1280 px. Switched off, the chevron on the right expands a detail row with the operator instruction, range, resolution, uncertainty and the guided tolerance builder. Below the tolerance a limit bar shows band and guard band, the Readings column shows one empty box per reading, and a quick bar on each group header adds a point, yes/no, question, rating, message or series at the end of that group. An empty plan offers three ways to start: first group, MET/CAL import, AI draft.
  • Cards: one collapsible block per step with the full field set.

If a point names a role as source or reference (source cal, ref device dmm), the card Standards of the plan appears above table and cards. There you pick the intended device type per role. From its specification (in its default option) the TAR column then uses the accuracy of the standard (span divided by twice the accuracy, like MET/CAL) and shows the estimated TUR from accuracy and resolution below it. Estimated, because the spread of the repeat readings and the CMC are only known in the test. Without a device type, TAR stays based on the uncertainty of the step. In the script the choice reads standard cal "…", see calScript.

Fields that do not apply are hidden rather than offered empty: a Header step only has a description and an instruction, a Rating step carries a grading map instead of a tolerance. Existing values survive a type change.

Fields

Field Meaning
Step no. Number on the certificate (e.g. 1.1). Execution order comes from the row position, not from this field.
Type Manual Test (measurement or yes/no), Rating (1 to 5), Header (section title), Message / Comment (informational).
Description Step heading in the execution wizard and on the certificate.
Instruction Formatted work instruction shown to the operator during execution.
Evaluation Result type and tolerance reference (see below).
Nominal / prefix / unit Nominal value with SI prefix (m, k, µ …) and unit.
Tolerance Permitted deviation, see the legend.
Range Range of the unit under test; reference for tolerance terms with /.
Resolution One digit of the unit under test; reference for terms with D.
Uncertainty Expanded measurement uncertainty; forms the guard band.

Evaluation (config)

The code decides what measurement capture does with the step (MET/CAL heritage, see also the MET/CAL wiki):

  • NUMERIC,NOMINAL or NUMERIC,UUT INDICATED — measurement point: the calculation runs (limits, tolerance usage, guard band). NOMINAL = the nominal value is the reference, UUT INDICATED = the unit's reading.
  • NUMERIC,REFERENCE — measurement point with a standard measuring alongside (calScript ref device|manual|camera <role>): the limits lie around the standard's reading, which capture asks for next to the unit's value; without it there is no verdict.
  • TEXT(Y=PASS) — yes/no confirmation: the operator confirms the step (visual check, functional check), yes counts as pass. TEXT(N=PASS) inverts the direction (no = pass, e.g. "defect visible?").
  • empty — informational only, no interaction.

Caution: A Manual Test without any evaluation is a dead step in measurement capture — neither measurable nor confirmable. The editor warns in that case; a visual check needs TEXT(Y=PASS).

The editor offers these as select fields; a raw MET/CAL value that cannot be mapped onto them stays as text and is stored unchanged.

Tolerance syntax

Several terms separated by spaces are summed. The suffix decides the reference quantity:

Suffix Reference Example
% percent of the measured value 0.5%
/ percent of the range; of the nominal value when the step has no range 0.1/
U absolute amount in the unit 2U
D multiple of the resolution (digits) 3D

So 0.5% 2D means 0.5 % of the measured value plus 2 digits. Without a sign a term applies symmetrically; a leading + limits it to the upper bound, a - to the lower one.

% refers to the measured value and only resolves at measurement time. D reads the resolution from the template, / the range; a step without a range (a source has none, range is optional) calculates / from the nominal value. A term whose reference is missing altogether counts as 0, which is why the editor blocks saving in exactly those cases.

On Rating steps the same field carries a grading map written as 1-2:fail|3-5:pass.

Bulk entry and checks

  • Measurement point series creates several rows at once: evenly spread, as percentages of the range (default 0, 25, 50, 75, 100) or from a value list. The descending leg for devices with hysteresis can be appended. All other fields are inherited from the source row.
  • Duplicate copies a row directly below it.
  • Apply to all rows propagates unit, tolerance, resolution, range or uncertainty from the expanded row to every other row.
  • Renumber assigns step numbers by position.

The editor flags rows with issues: invalid numbers (these block saving), tolerance terms without their reference quantity (they compute as zero), a missing uncertainty (no guard band), and a tolerance-to-uncertainty ratio below 4:1.

AI draft

A test plan for a device that has just been handed in usually follows from two inputs: the device specification and the rule it is to be tested against. The "KI-Entwurf" (AI draft) button in the step editor takes both and produces a draft.

Device handover — four sources, combinable:

Source What it contributes
Device of this calibration test-steps editor of a calibration only; the server resolves device and device type itself
Device from the inventory device master data plus the specifications of the device and its type
Device type type master data plus the type's specifications
Description only anything not (yet) in the master data

The toggle "Hinterlegte Spezifikationen mitgeben" decides whether the specification sheets — ranges, resolutions, accuracies — travel with the request. Without them the model only knows what the dialog says.

Specification rules — the "Regelwerke" picker (DKD-R 6-1, VDI/VDE/DGQ 2622, ILAC-G8 …) names the framework only. The figures of a guideline are not stored in the system and the model must not reconstruct them; what shall apply belongs in the "Prüfvorgaben" field (measurands, points per range, error limits, coverage factor, decision rule).

The toggle "Am Messplatz ablesen" (read at the workstation) makes the draft bind the measurement groups to the workstation roles (read device uut, source cal, function). Which instrument plays which role is set at the workstation, not in the plan; without the toggle the technician reads by hand.

The draft is a calScript: groups with shared defaults, series for similar points (measure 2 10 19 "{value} V"), repeated readings where the requirements ask for them. If the device type carries specifications with test points, for example from a MET/CAL import, the draft takes their points, ranges and accuracies. The preview shows the script and below it the step rows the compiler makes of it.

In the template editor the draft goes to the script view: it replaces the script or is appended to the script (without a second header). From table or cards the editor switches to the script for this. In the test-steps editor of a calibration, which has no script, the step rows are appended to or replace the existing steps. Nothing is stored by itself, only "save as new version" creates a version.

The draft is checked, not adopted

Every script goes through the calScript compiler, with the same rules as on save. If it rejects the script, the model gets the message with its line and corrects it, at most twice and only while the time budget allows. If the script still does not compile, it is returned anyway: the preview names the error, and the script view marks its line. Compiler notes (such as %r without range) and an SI prefix the catalogue does not know (it computes as factor 1) are listed above the preview. Nothing is corrected silently. Nominal values, tolerances and uncertainties are still statements of a language model; review them before release.

Prerequisites: the AI assistant must be configured under Administration → AI assistant with the "Prüfplan-Entwurf aus Gerät und Spezifikationsregeln" feature switched on. The button appears with ai_assistant_edit; the draft itself additionally requires procedure_template_edit. If the configured AI address points outside the installation, the dialog says so — device data leaves the installation in that case.

History and errors

The dialog keeps a history, live while the draft is being produced. It shows how far the server got and is the actual answer when something fails:

Stage What it reports
Request to the server how long the browser waited; if it gives up, the history ends here
Connection checked provider, model, time budget — and whether the address points outside
Device handover read which sources were pulled, how many specification sheets, size of the description
Model queried script lines in the answer, tokens spent, duration
Script checked against the calScript compiler compiled steps and notes, or line and kind of the error
Script corrected one round after a compiler error, at most two

The history carries numbers and configuration names only — no device data, no test requirements, no model output, no part of the script.

When a draft fails, the dialog names the case instead of "please try again":

Case Meaning Whose job
Browser timeout no answer within the client deadline operator: time budget or model
Answer did not get through (502/504) the reverse proxy answered, not the application operator: proxy deadline
AI service unreachable / error status address, key or model is wrong operator: Administration → AI assistant
Answer truncated / empty the model could not finish within its output limit technician: lower "max. steps", or use another model
Answer does not fit the format model too small for structured output operator: larger model
No usable test plan the requirements carry too little technician: name quantities, ranges, limits

Keep the time budget below the deadline of the environment

A draft is one call and takes minutes on local CPU. The server gives up after its time budget (240 s by default) and answers with a diagnosis. If it runs longer than the shortest deadline on the way — nginx fastcgi_read_timeout (60 s by default, and the directive that applies when nginx talks to PHP-FPM directly, as it does in the API image — not proxy_read_timeout, which only covers an upstream proxy layer), PHP-FPM request_terminate_timeout — the proxy answers instead, with an HTML page and no error object. All that is left then is "the answer did not get through".

Either raise those deadlines or put the budget below them:

# API .env — time budget in seconds (30 to 900)
AI_PROCEDURE_PLAN_BUDGET_S=55
docker exec calserver-api-v2 php artisan config:clear

The browser deadline is derived from it (budget + 20 s) — the server should give up first, because only its answer explains what went wrong.

GET  /api/v2/ai/procedure-plan/availability   # incl. budget_s
POST /api/v2/ai/procedure-plan   # { "rules": "...", "standards": [...], "calibration_id"|"inventory_id"|"device_type_id"|"device_text" }

Both outcomes carry the history: data.trace on success, error.trace on failure, next to error.ai_error and error.retryable.

AI optimization

An imported plan, for example from a MET/CAL procedure, is technically right but hard to read: copyright and safety texts as dozens of single messages, groups named after subprocedures, the same values on every point. The "KI-Optimierung" (AI optimization) button in the template editor has the plan reworked that is currently in the editor, including unsaved changes.

The dialog asks what should be improved; everything is preselected:

Goal What the AI does
Bundle notes merges consecutive messages, reduces copyright notices to one, turns connection instructions into info on their group, removes MET/CAL leftovers such as [32]; safety warnings keep their content
Name and tidy groups titles by measurand and range, merges groups that only carry notes, lifts shared values to the group
Write series similar consecutive points as one series
Check specifications range, resolution and tolerance per group; anything odd gets a # Prüfen: … comment
Resolve editor hints the table warnings ("40 with hint"), as far as possible without invented numbers

A free field takes further instructions, for example "translate notes into German".

The result is a proposal with a diff: every line that would change, the list of changes, and the number of measuring points, checks and notes before and after. "Apply proposal" puts it into the script view, "Discard" leaves the plan as it is. Nothing is saved until "Save as new version".

Measuring points stay, and the server counts them

The AI may tighten and reorder texts but must not remove or add a measuring point or change a nominal value, tolerance or uncertainty. The server then compares the effective values of every point (group defaults included). If a point is missing, new, or its range or resolution changed, this is shown in red above the diff and applying asks for confirmation. The AI does not fill in a missing uncertainty: it comes from the budget of the standard.

Prerequisites as for the draft: the same function under Administration → AI assistant, the same model, ai_assistant_edit and procedure_template_edit. What is transmitted is the plan as calScript, the editor hints and the instruction; customer and device master data are not. A plan that does not compile is not optimized: fix the error first.

Large plans go section by section. An imported manufacturer plan easily has 50,000 characters and more, which fits neither a request nor the model's answer. Above 12,000 characters the server splits the plan between groups (a group is never split); the dialog sends the sections one after another and shows which one is with the model. It then assembles them, and the server compares the whole proposal with the whole plan, so diff and point count cover the full plan. If the proposal for a section does not compile, that section stays unchanged and the list of changes says so. The time budget applies per section. The whole plan may have up to 400,000 characters.

API

GET    /api/v2/procedure-templates                 # list (filter[procedure_id], latest_only=1)
POST   /api/v2/procedure-templates                 # upload → version 0.1
POST   /api/v2/procedure-templates/manual         # name + steps → version 0.1 (procedure_id optional)
POST   /api/v2/procedure-templates/{id}/new-version
POST   /api/v2/procedure-templates/{id}/approve
POST   /api/v2/procedure-templates/{id}/release
GET    /api/v2/procedure-templates/{id}/versions
GET    /api/v2/procedure-templates/{id}/download
GET    /api/v2/procedure-templates/{id}/export-package  # test plan package (ZIP) of this version
POST   /api/v2/procedure-templates/import-package  # package upload → new template 0.1
PUT    /api/v2/procedure-templates/{id}            # { "name": "..." } and/or { "procedure_id": ... }
POST   /api/v2/procedure-templates/{id}/assign     # { "procedure_id": "..." }
POST   /api/v2/procedure-templates/{id}/unassign
GET    /api/v2/procedures/{id}/unassigned-templates # test plans not belonging to this procedure

Renaming and assigning always write to every version of a test plan (all rows sharing a hash): name and procedure belong to the plan, not to a single version, and every new version inherits both from its predecessor anyway. procedure_id: null on PUT clears the assignment, same as /unassign.

Template ↔ Calibration

In a calibration's test-steps tab:

  • "Save as template" serializes the calibration's test steps into a new template (version 0.1): POST /api/v2/calibrations/{id}/save-as-template
  • "Load template" instantiates a template into the calibration — existing test steps are replaced: POST /api/v2/calibrations/{id}/load-procedure with { "template_id": "..." }

Permissions

Operation Permission
View, download, versions procedure_template_view
Upload, new version, approve, release, rename, assign procedure_template_edit
Delete procedure_template_delete