Compare commits

...

4 commits

Author SHA1 Message Date
a2fdaae6ac Record phase 6 progress and issues ISS-025 to ISS-029
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 17:49:49 +10:00
f99490378c Extend class-object-engineering skill: language, Java, reset, opcdbg tasks
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 17:49:49 +10:00
e6911796f7 Add template item, Traditional and Java classes and objects to CI-Eng-Sample
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 17:49:49 +10:00
f9f6bf59db Add phase 6 PROCESS Service manual summaries (L10, P10, P11)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 17:49:49 +10:00
20 changed files with 900 additions and 40 deletions

View file

@ -1,20 +1,38 @@
---
name: class-object-engineering
description: >-
CI Server R1.03 PROCESS Service classes, objects and trigger groups. Use when the user wants
to create a trigger group, write or compile a class (traditional language), create objects
from a class, or load classes and objects with quick load files. Sources IM 36K10G10-01EN
(Tutorial) and IM 36K10J10-01EN; to be extended with IM 36K10L10, P10 and P11 in phase 6.
CI Server R1.03 PROCESS Service: trigger groups, classes and objects. Use when the user wants
to create a trigger group, write, compile or change a class (Traditional PROCESS language or
Java), use signals, attributes, prompts, timers or template items in a class, create objects
from a class (with prompt answers), let an object create its own items, reset a class after a
change, read or change object attribute values, see which item a signal uses, load or remove
classes and objects with quick load files, or check PROCESS Service with opcdbg (database
check, object status, executor statistics). Sources IM 36K10L10-01EN, IM 36K10P10-01EN,
IM 36K10P11-01EN, IM 36K10G10-01EN (Tutorial).
---
# Class and object engineering (R1.03)
Background: `knowledge/manuals/IM36K10G10-01EN.md` (chapter 5) and
`knowledge/manuals/IM36K10J10-01EN.md` (sections 2.4 and 5.3). Known issues for PROCESS
Service: `knowledge/manuals/IM36K01A50-01EN.md`.
Background: `knowledge/manuals/IM36K10L10-01EN.md` (processes, `opc.sup`, `opcdbg`, data
store), `IM36K10P10-01EN.md` (Traditional language), `IM36K10P11-01EN.md` (Java),
`IM36K10G10-01EN.md` chapter 5 (Tutorial). Known issues for PROCESS Service:
`knowledge/manuals/IM36K01A50-01EN.md` (PROCESS 1.10).
Rules: run `system-check` first; creating classes and objects changes the running system.
Rules:
- Run `system-check` first; follow the user's chosen way of working.
- Creating, changing or resetting classes and objects changes the running system; objects can
write to items (and through them to devices). Test on a test system or with the user's
approval.
- Deleting an object deletes the items it created (and their history links).
- `opcdbg`: read-only actions only, unless the user approves (task `opcdbg-checks.md`).
| Task | File | Status |
|---|---|---|
| Trigger group, class (compiled on load) and object via quick load | `tasks/load-class-object.md` | verified |
| Trigger group, class (compiled on load) and object via quick load; compile errors; remove | `tasks/load-class-object.md` | verified |
| Traditional class with prompts/attributes, signals from the object's section, items created from a template, input check; change an attribute at runtime | `tasks/traditional-class.md` | verified |
| Java class: attach and create items, signal trigger, system log message | `tasks/java-class.md` | verified |
| Change a class that has objects: compile, reset with `opcdbg` | `tasks/change-reset-class.md` | verified (`dssqld` reset does not work, ISS-028) |
| `opcdbg` checks: database check, class/object details, object status, executor statistics, dumps | `tasks/opcdbg-checks.md` | verified |
| Language reference (statements, operators, built-ins, DSS routines; Java API) | P10 / P11 summaries | from docs, main parts verified |
| `opc.sup` settings (executors, priorities, statistics, PRINT) | L10 summary §2 | read-only check; changing not practiced |
| Containment, inheritance, timers, alarms, STEP state machines, DSS routines | P10 / P11 summaries | from docs |

View file

@ -0,0 +1,64 @@
---
task: Change a class that already has objects (compile and reset)
version: R1.03
source: IM 36K10L10-01EN §4 (Reset class); IM 36K10P11-01EN §2.3, §10.4; practiced with CI-Eng-Sample class CIENG_TANK 2026-09-30
status: verified
---
# Change a class that has objects
Objects keep running the **old** compiled code until their class is reset (verified). A reset
restarts every object of the class; by the manual, `ONCE` trigger groups fire again. Items the
objects created were kept, with their values (verified).
## 1. New source and compile
`dssqld -m` with the class name, `COMPILE` 1 and the new `METHOD`:
```
@FIELDS
NAME,COMPILE,METHOD
@CLASS_DF
"CIENG_TANK",1,@"
CLASS CIENG_TANK;
…
ENDCLASS CIENG_TANK;
"@
```
`Errors` 0 = compiled. On a compile error the old code stays; see `load-class-object.md` for
reading the error listing.
Export the class (`load-class-object.md` §2): after the compile `RESET_REQUIRED` = 1 and
`OBJECTS_RESET` = 0 of `OBJECTS` n. Verified: the object still printed the old text.
## 2. Reset the class
**Works** — `opcdbg`, Classes, action 8 *Reset class*: class name, node (0 = this node), file
for a reset report (empty = none; this prompt is not in the manual):
```
printf '2\n8\n<CLASS>\n0\n\n-1\n-1\n' | timeout 30 opcdbg 0
```
(Bash. Interactively, type the same answers.) Keep the time-out: `opcdbg` repeats its last
prompt forever when the input runs out.
Afterwards `RESET_REQUIRED` = 0 and the object used the new code at once (verified).
The Engineering Module also resets classes (class properties); not practiced.
**Does not work** (verified 2026-09-30, ISS-028):
- `dssqld -m` with `NAME,RESET` = `"<class>",1` (also with `RESET_NODE` = the host node name):
accepted with 0 errors but nothing happens.
- `dssqld -m` on `OBJECT_DF` with `RESET` 1: refused with `OPC-E-OBJ_RSTREQ, The class needs to
be reset first`.
- `CLASS_RESET_COMMAND` (system-wide reset used by the Engineering Module) was not tried.
## 3. Changing prompts or signals
Only a change in the method bodies was practiced. When the class **prolog** changes (new
signals, prompts, attributes, created items), check `EXTENDED_RESET_REQUIRED` in `CLASS_DF`
after compiling; what an extended reset does was not tested. The safe way is to recreate the
objects (remove, load) — note that removing an object deletes the items it created, with their
history links.

View file

@ -0,0 +1,87 @@
---
task: Write and load a Java PROCESS Service class
version: R1.03
source: IM 36K10P11-01EN §1–§5, §10; IM 36K10L10-01EN §1; practiced with CI-Eng-Sample class CIENG_JFLOW 2026-09-30
status: verified
---
# Java class
Worked example: class `CIENG_JFLOW`, object `CI-Eng-Sample.TANK1.JFLOW`
(`examples/CI-Eng-Sample/06_class_df.qli`, `07_object_df.qli`). Language reference:
`knowledge/manuals/IM36K10P11-01EN.md`. Loading and removing: `load-class-object.md`.
Choose Java when you need loops, arrays of signals, inheritance, libraries, or signals that may
stay unattached; otherwise the Traditional language is simpler.
## 1. Class record
Same as a Traditional class but `PF_LANGUAGE` = `"Java"` (cannot be changed later) and Java
source in `METHOD`. The Java class name must equal the `CLASS_DF` name exactly.
```
@FIELDS
NAME,DESCRIPTION,PF_LANGUAGE,TRIGGER_1,COMPILE,LISTING_WANTED,METHOD
@CLASS_DF
"CIENG_JFLOW","Inflow per minute (Java)","Java","",1,0,@"
import fasttools.processfast.*;
public class CIENG_JFLOW extends ProcessClass {
Signal sInflow = defineDoubleSignal(Signal.Trigger.VALUE);
Signal sPerMin = defineDoubleSignal();
public void create() {
attachItemToSignal(sInflow, getSectionsPath() + ".INFLOW");
createItemForSignal(sPerMin, "CI-Eng-Sample.TEMPLATES.TPL_REAL",
"DESCRIPTION", "Tank inflow (m3/min), class CIENG_JFLOW");
}
public void signalEvent(Signal signal) {
double mInflow = sInflow.getValueAsDouble();
sPerMin.setValue(mInflow / 60.0);
systemMessage("CIENG_JFLOW " + getTag() + ": inflow " + mInflow);
}
}
"@
```
`OPCMAN` starts the Java compiler `OPCJCOM` on demand; allow ~15 s, then export the class and
check `VALID_METHOD` = 1 (as in `load-class-object.md`).
## 2. Object
```
@FIELDS
NAME,DESCRIPTION,CLASS
@OBJECT_DF
"CI-Eng-Sample.TANK1.JFLOW","Tank 1 inflow per minute (Java)","CIENG_JFLOW"
```
Prompts: `Attribute aX = defineStringAttributeForPrompt("…");` → answer in `ATTR_VALUE_n`;
refuse bad answers with `cancel("text")` in `create()`.
## 3. Results on the test system
- Signals: `sInflow` → `CI-Eng-Sample.TANK1.INFLOW`; `sPerMin` → created item
**`CI-Eng-Sample.TANK1.JFLOW.sPerMin`** — automatic names keep the identifier's case, and
`itmval` needs that exact case (`…SPERMIN` is not found). Give a `"NAME"` if you want
upper-case item names.
- `INFLOW` 120 → `sPerMin` 2; 90 → 1.5.
- `systemMessage()` appears in `umhlog.log` from `OPCJEXE` as
`UMH-I-INFO, (<object>: <text>)`.
- The first object ran without resetting the new class, although the manual asks for a reset
(ISS-029). After changing a Java class that has objects, compile **and reset** it
(`change-reset-class.md`).
- Deleting the object deleted `…JFLOW.sPerMin` and section `…TANK1.JFLOW`; `INFLOW` stayed.
## 4. Pitfalls (manual)
- Definitions (`define…()`) only at class level, without `public`/`private`.
- `create()`/`destroy()` run in a different process than the trigger methods: only attributes
keep values between them; no timers or signal values in `create()`.
- Never sleep or loop long in a trigger method: it blocks all objects of the same priority.
- No anonymous listener classes (fail at object start with `NoClassDefFoundError`).
- Dataset access: get the session with `getDssSession()` and never close it (release notes).

View file

@ -1,16 +1,18 @@
---
task: Create a trigger group, class and object with quick load files
task: Create trigger groups, classes and objects with quick load files
version: R1.03
source: IM 36K10G10-01EN §5.1–5.3; IM 36K10J10-01EN §5.6; practiced with CI-Eng-Sample 2026-09-30
source: IM 36K10G10-01EN §5.1–5.3; IM 36K10L10-01EN §3; IM 36K10J10-01EN §5.6; practiced with CI-Eng-Sample 2026-09-30 (full remove/reload with three classes and objects)
status: verified
---
# Trigger group, class and object via quick load
# Trigger groups, classes and objects via quick load
Load in this order (each with `dssqld -i <file>.qli -l <file>.qlo`, check `Errors` = 0);
remove in reverse (object, class, trigger group) with `NAME`-only files and `dssqld -r`.
Load in this order, each with `dssqld -i <file>.qli -l <file>.qlo` and check `Errors` = 0:
items the classes need (template items, attached items) → trigger groups → classes → objects.
Remove in reverse (objects, classes, trigger groups) with `NAME`-only files and `dssqld -r`.
Run `dssqld` from the folder that holds the files and use short relative names (ISS-020).
**1. Trigger group** (`TRIGGER_DF`, name max 16 characters):
## 1. Trigger group (`TRIGGER_DF`, name max 16 characters)
```
@FIELDS
@ -20,17 +22,23 @@ NAME,DESCRIPTION,TRIGGER_INTERVAL
"CIENG_1S","CI-Eng-Sample one second trigger","1 seconds"
```
**2. Class** (`CLASS_DF`, name max 16 characters). The source goes in the `METHOD` memo field,
between `@"` and `"@` on their own lines; `COMPILE` 1 compiles it on load; `TRIGGER_1`
attaches a trigger group:
Other fields: `ACTIVATION_TIME`, `DEACTIVATION_TIME`, `TRIGGER_ONCE` (1 = run once when an
object is activated), `CORRECT_DAYLIGHT`. A class or object without a trigger group only runs
on signal triggers, timers and `TRIGGER` statements.
## 2. Class (`CLASS_DF`, name max 16 characters; the language allows 15)
The source goes in the `METHOD` memo field between `@"` and `"@` on their own lines.
`COMPILE` 1 compiles it on load; `PF_LANGUAGE` is `Traditional` (default) or `Java` and cannot
be changed later; `TRIGGER_1`…`TRIGGER_8` attach trigger groups; `PRIORITY` 0–999 picks the
executor (installed: `OPCEXE1` 0–249 … `OPCEXE4` 750–999).
```
@FIELDS
NAME,DESCRIPTION,PF_LANGUAGE,TRIGGER_1,COMPILE,LISTING_WANTED,METHOD
@CLASS_DF
"CIENG_INCR","Count CI-Eng-Sample.DEMO.COUNTER 1..100","Traditional","CIENG_1S",1,1,\
@"
"CIENG_INCR","Count CI-Eng-Sample.DEMO.COUNTER 1..100","Traditional","CIENG_1S",1,1,@"
CLASS CIENG_INCR;
PROLOG
SIGNAL INPUT := "CI-Eng-Sample.DEMO.COUNTER";
@ -46,23 +54,70 @@ ENDCLASS CIENG_INCR;
"@
```
The item a `SIGNAL` names must exist first (or be created by the class with `FROM … MAKE`).
Several classes (also mixed languages) can share one file and one `@FIELDS` line; leave unused
fields as `""`. See `examples/CI-Eng-Sample/06_class_df.qli`.
**3. Object** (`OBJECT_DF`): full name in its section, and the class:
**Check the compile**: export the class with a filter file and read the flags after the source:
`VALID_METHOD` = 1 means compiled; `ATTR_PROMPT_n` shows the class's prompts;
`RESET_REQUIRED`, `OBJECTS`, `OBJECTS_RESET` matter when changing a class (`change-reset-class.md`).
```
@SELECT
'NAME = "CIENG_TANK"'
@CLASS_DF
```
`dssqld -e cls.qli filter.qli -l cls.lst`
**Compile errors** (verified, Traditional): with `COMPILE` 1 on insert, a class that does not
compile is **not inserted at all** — the `.qlo` only says `DSI-E-OPCCOMERR, Compilation failed
with n error(s)`. To see the errors, insert the class with `COMPILE` 0, then update it with
`dssqld -m` and `NAME,COMPILE,LISTING_WANTED` = `"<class>",1,1`: the update fails the same way
but the class's `LISTING` field (export as above) now shows the numbered source with
`**** ERROR: …` after the faulty line. Fix the `METHOD` field and compile again.
Class language: `traditional-class.md` and `java-class.md`.
## 3. Object (`OBJECT_DF`)
Full name (its section must exist), class, and `ATTR_VALUE_n` = answer to the class's n-th
prompt:
```
@FIELDS
NAME,DESCRIPTION,CLASS
NAME,DESCRIPTION,CLASS,ATTR_VALUE_1
@OBJECT_DF
"CI-Eng-Sample.DEMO.INCR1","Counts DEMO.COUNTER every second","CIENG_INCR"
"CI-Eng-Sample.DEMO.INCR1","Counts DEMO.COUNTER every second","CIENG_INCR",""
"CI-Eng-Sample.TANK1.CALC","Tank 1 volume (capacity 200 m3)","CIENG_TANK","200"
```
Other fields: `TRIGGER_1`…`8` (object's own trigger groups), `PRIORITY`, `CONTROL_ITEM`
(item whose status blocks/stops the object and whose value is `STEP`), `ITEMS_MAY_EXIST`
(allow linking to items that already exist instead of creating them), `LEAVE_ITEMS` (keep
created items when the object is deleted), `DEBUG`.
The item a plain `SIGNAL` names must exist. If the class refuses the object (`ERROR` in the
prolog, Java `cancel()`, missing item) the row counts as an error and the `.qlo` shows the
reason (e.g. `OPC-E-INFO, <text>`); nothing is left behind.
## Check
Run `itmval -g -n CI-Eng-Sample.DEMO.COUNTER` a few seconds apart: the value rises by one per
second. To inspect a class, export it with a filter file (`@SELECT`, then
`'NAME = "<class>"'`, then `@CLASS_DF`).
- Items the object writes: `itmval -g -n <item>` a few seconds apart (sample: `DEMO.COUNTER`
rises by one per second).
- Which item each signal got: export `OBJECT_SIGNAL_DF` with filter
`'OBJECT = "<object>"'`; attribute values: `OBJECT_ATTR_VAL` (same filter).
- Run state: `opcdbg` (task `opcdbg-checks.md`).
Example files: `examples/CI-Eng-Sample/05_trigger_df.qli`, `06_class_df.qli`, `07_object_df.qli`,
`86_` to `88_remove_*.qli`.
## Remove
```
@FIELDS
NAME
@OBJECT_DF
"CI-Eng-Sample.TANK1.CALC"
```
Then `CLASS_DF`, then `TRIGGER_DF`. Deleting an object also deletes the items and sections it
created (verified); items it only attached stay.
Example files: `examples/CI-Eng-Sample/05_trigger_df.qli`, `06_class_df.qli`,
`07_object_df.qli`, `86_` to `88_remove_*.qli`.

View file

@ -0,0 +1,47 @@
---
task: Check PROCESS Service with opcdbg (database check, classes, objects, performance)
version: R1.03
source: IM 36K10L10-01EN §4; practiced on the test system with CI-Eng-Sample 2026-09-30
status: verified (read-only actions and Reset class)
---
# PROCESS Service checks with `opcdbg`
`opcdbg` is interactive. Answers can be piped in, one per line, in Bash; always add a time-out
and end with `-1` lines, because on end of input it repeats the last prompt forever. `opcdbg 0
<menu>` starts in a menu on node 0 (this node). Times are printed in **GMT**.
Only the actions below are read-only. Do not use insert/modify/delete, *Database repair*,
*Reset* (utilities) or *Modify attribute value* without the user's approval.
| Check | Command (Bash) | Output |
|---|---|---|
| Database consistency | `printf '5\n-1\n-1\n' \| timeout 60 opcdbg 0 5` | Counts per store (trigger groups, classes, sources, code, objects, signals, attributes), then checks; warnings such as `No compiled code found for class (cls_id = …)` |
| Class details | `printf '2\n5\nN\n<CLASS>\n-1\n-1\n' \| timeout 20 opcdbg 0` | Language, priority, modified/compiled times, cls_id, objects derived / reset, hidden |
| Class by id (from a warning) | `printf '2\n5\nI\n<sec>\n<seq>\n-1\n-1\n' \| timeout 20 opcdbg 0` | Same; `Compiled at : 0` = never compiled |
| Object details | `printf '3\n4\nN\n<object>\n-1\n-1\n' \| timeout 20 opcdbg 0` | Priority, control item id, times, cls_id/obj_id |
| Object status | `printf '3\n18\n<object>\n-1\n-1\n' \| timeout 20 opcdbg 0` | Total runs, executor (`Running in : 1, OPCEXE1`) |
| Object signals / attributes | `3` then `14` / `12`, object name | Signal → item id; attribute → type (LOCAL/GLOBAL) |
| Executor statistics | `printf '0\nOPCEXE1\n1\n-1\n-1\n' \| timeout 20 opcdbg 0 4` | Active classes/objects/trigger groups/items, number of executions; times stay 0 unless `STATISTICS = YES` in `opc.sup` |
Executor names on R1.03: `OPCEXE1`…`OPCEXE4` (Traditional, priority ranges 0–249 … 750–999)
and `OPCJEXE` (Java). The prompt's default `OPCEXE` does not exist.
Easier for names: the datasets `OBJECT_SIGNAL_DF` (object:signal → item name) and
`OBJECT_ATTR_VAL` / `CLASS_ATTR_VAL` (attribute values) via `dssqld -e` with a filter — see
`traditional-class.md` §3.
## Dumps
*Utilities* 3 / 4 (`printf '3\nclasses.qli\n4\nobjects.qli\n-1\n-1\n' | timeout 30 opcdbg 0 5`)
write all class sources / objects to files in the current folder. The format is an old one
(`NAME,"description",priority` then source lines starting with `- `) and **`dssqld -i` rejects
it** (`DSS-E-UNK_DS_NM`, ISS-027). To move classes and objects to another system, export
`CLASS_DF` and `OBJECT_DF` with `dssqld -e` instead (task `load-class-object.md`; migration in
`knowledge/manuals/IM36K10J10-01EN.md` §5.6).
## Observed on the test system
The database check reported one warning for a class `SINUS` (not from this repo) that was
never compiled; everything else was consistent. A class like that is harmless but can be
compiled or removed by its owner.

View file

@ -0,0 +1,91 @@
---
task: Write a Traditional class with prompts, signals built from the object name, and items created from a template
version: R1.03
source: IM 36K10P10-01EN §1–§5, §8, §10, §11.2.8; IM 36K10L10-01EN; practiced with CI-Eng-Sample class CIENG_TANK 2026-09-30
status: verified
---
# Traditional class: prompts, signals, created items
Worked example: class `CIENG_TANK` and object `CI-Eng-Sample.TANK1.CALC`
(`examples/CI-Eng-Sample/06_class_df.qli`, `07_object_df.qli`). Loading and removing: task
`load-class-object.md`. Language reference: `knowledge/manuals/IM36K10P10-01EN.md`.
## 1. Design
One class = one kind of equipment; one object per piece of equipment. Put the variable parts
(which items, which settings) in the **class prolog** so they are fixed when each object is
created:
| Need | Use |
|---|---|
| Setting per object, asked at creation | `ATTRIBUTE x OBJECT FLOAT;` + `PROMPT x QUERY "…";` → `ATTR_VALUE_n` in `OBJECT_DF` |
| Setting shared by all objects | `ATTRIBUTE x CLASS …;` |
| Existing item next to the object | `SIGNAL s := SECTION || ".<TAG>" TRIGGER VALUE;` |
| New item per object | `SIGNAL s := FROM "<template item>" MAKE "FIELD" EQUAL value …;` |
| Refuse bad input | `IF … THEN ERROR "text"; ENDIF;` in the class prolog |
| Periodic run | trigger group on the class (`TRIGGER_1`) or object |
| Run on a change | `TRIGGER VALUE` (or STATUS, UPDATE …) on the signal |
Template items: keep them in their own section (sample: `CI-Eng-Sample.TEMPLATES.TPL_REAL`)
and load them before the class.
## 2. Example
```
CLASS CIENG_TANK;
PROLOG
ATTRIBUTE CAPACITY OBJECT FLOAT;
PROMPT CAPACITY QUERY "Tank capacity (m3)";
SIGNAL LEVEL := SECTION || ".LEVEL" TRIGGER VALUE;
SIGNAL VOLUME := FROM "CI-Eng-Sample.TEMPLATES.TPL_REAL" MAKE
"DESCRIPTION" EQUAL "Tank volume (m3), class CIENG_TANK";
IF CAPACITY <= 0 THEN
ERROR "CIENG_TANK: capacity must be > 0";
ENDIF;
BODY
METHOD CALC;
BODY
VOLUME := LEVEL * CAPACITY / 100.0;
IF LEVEL >=: 80.0 THEN
PRINT "CIENG_TANK ", SECTION, ": level reached 80 pct, volume ", VOLUME;
ENDIF;
ENDMETHOD CALC;
ENDCLASS CIENG_TANK;
```
Object `CI-Eng-Sample.TANK1.CALC` with `ATTR_VALUE_1` = `"200"`:
- `SECTION` = `CI-Eng-Sample.TANK1`, so `LEVEL` → `CI-Eng-Sample.TANK1.LEVEL`.
- `VOLUME` has no `"NAME"`, so the item is `CI-Eng-Sample.TANK1.CALC.VOLUME`; the section
`TANK1.CALC` is created too. Both are deleted with the object.
- `LEVEL` 50 → `VOLUME` 100; 82 → 164.
- `>=:` prints once when the level **crosses** 80 (message in `umhlog.log`, sender `OPCEXE1`).
Rules learned on the test system:
- Do not put `%` in `PRINT` text: the message is cut at that point (ISS-025).
- An object at root level has an empty `SECTION`; build names with an `IF` then (release notes).
- Item names in `SIGNAL` strings must match exactly; an item that does not exist makes the
object creation fail.
## 3. Check and operate
- Signals → items: export `OBJECT_SIGNAL_DF` with filter `'OBJECT = "<object>"'`
(sample: `…CALC:LEVEL` → `CI-Eng-Sample.TANK1.LEVEL`, `…CALC:VOLUME` → `…CALC.VOLUME`).
- Attribute values: export `OBJECT_ATTR_VAL` (same filter); record name
`<object>:<attribute>`, field `ATTR_VALUE`.
- **Change an attribute of a running object** (verified): `dssqld -m` on `OBJECT_ATTR_VAL`:
```
@FIELDS
NAME,ATTR_VALUE
@OBJECT_ATTR_VAL
"CI-Eng-Sample.TANK1.CALC:CAPACITY","400"
```
The new value is used from the next run (level 50 → volume 200). Do not change attributes
that were used to build signal names: the signal keeps its old item (P10 §8.3).
- Class-wide attributes: `CLASS_ATTR_VAL` (`<class>:<attribute>`), not practiced.
- Refused object: loading `ATTR_VALUE_1` = `"0"` gave `Errors 1` with
`OPC-E-INFO, CIENG_TANK: capacity must be > 0` in the `.qlo`; nothing was created.
Changing the class source later: task `change-reset-class.md`.

View file

@ -10,6 +10,7 @@ NAME,SECTION_PATH,SECTION_NAME,DESCRIPTION
@SECTION_DF
"CI-Eng-Sample","","CI-Eng-Sample","CI-Eng-Sample project"
"CI-Eng-Sample.TEMPLATES","CI-Eng-Sample","TEMPLATES","Template items for classes"
"CI-Eng-Sample.TANK1","CI-Eng-Sample","TANK1","Sample tank 1"
"CI-Eng-Sample.PUMP1","CI-Eng-Sample","PUMP1","Sample pump 1"
"CI-Eng-Sample.SYSTEM","CI-Eng-Sample","SYSTEM","Sample system monitoring"

View file

@ -10,6 +10,7 @@ NAME,DESCRIPTION,ITEM_REP,VALUE_FORMAT
LOW_LOW_LIMIT,LOW_LIMIT,HIGH_LIMIT,HIGH_HIGH_LIMIT,SCALE_LOW_LIMIT,SCALE_HIGH_LIMIT
@ITEM_DF
"CI-Eng-Sample.TEMPLATES.TPL_REAL","Template: internal real item","Real","9999.9",0,0,0,0,0,1000
"CI-Eng-Sample.TANK1.LEVEL","Tank 1 level (%)","Real","999.9",10,20,80,90,0,100
"CI-Eng-Sample.TANK1.INFLOW","Tank 1 inflow (m3/h)","Real","9999.9",0,0,0,0,0,500
"CI-Eng-Sample.PUMP1.RUNNING","Pump 1 running","Boolean","",0,0,0,0,0,0

View file

@ -4,8 +4,12 @@ ENGLISH
@VERSION
1.03.00
! CI-Eng-Sample class (traditional language), compiled on load (COMPILE = 1)
! Based on the INCREMENT example in the CI Server Tutorial (IM 36K10G10-01EN 5.2)
! CI-Eng-Sample classes, compiled on load (COMPILE = 1), CI Server R1.03.00
! CIENG_INCR : traditional, based on the INCREMENT example of the Tutorial (IM 36K10G10-01EN 5.2)
! CIENG_TANK : traditional; prompt/attribute, signal to <object section>.LEVEL, item created from
! the template TEMPLATES.TPL_REAL (automatic name <object>.VOLUME), ERROR in the prolog
! CIENG_JFLOW: Java; attaches <object section>.INFLOW, creates <object>.sPerMin (automatic name)
! Changing a class that has objects: compile, then reset the class (see skill class-object-engineering).
@FIELDS
NAME,DESCRIPTION,PF_LANGUAGE,TRIGGER_1,COMPILE,LISTING_WANTED,METHOD
@ -24,3 +28,45 @@ CLASS CIENG_INCR;
ENDMETHOD UP_AND_DOWN;
ENDCLASS CIENG_INCR;
"@
"CIENG_TANK","Tank volume from level x capacity","Traditional","",1,1,@"
CLASS CIENG_TANK;
PROLOG
ATTRIBUTE CAPACITY OBJECT FLOAT;
PROMPT CAPACITY QUERY "Tank capacity (m3)";
SIGNAL LEVEL := SECTION || ".LEVEL" TRIGGER VALUE;
SIGNAL VOLUME := FROM "CI-Eng-Sample.TEMPLATES.TPL_REAL" MAKE
"DESCRIPTION" EQUAL "Tank volume (m3), class CIENG_TANK";
IF CAPACITY <= 0 THEN
ERROR "CIENG_TANK: capacity must be > 0";
ENDIF;
BODY
METHOD CALC;
BODY
VOLUME := LEVEL * CAPACITY / 100.0;
IF LEVEL >=: 80.0 THEN
PRINT "CIENG_TANK ", SECTION, ": level reached 80 pct, volume ", VOLUME;
ENDIF;
ENDMETHOD CALC;
ENDCLASS CIENG_TANK;
"@
"CIENG_JFLOW","Inflow per minute (Java)","Java","",1,0,@"
import fasttools.processfast.*;
public class CIENG_JFLOW extends ProcessClass {
Signal sInflow = defineDoubleSignal(Signal.Trigger.VALUE);
Signal sPerMin = defineDoubleSignal();
public void create() {
attachItemToSignal(sInflow, getSectionsPath() + ".INFLOW");
createItemForSignal(sPerMin, "CI-Eng-Sample.TEMPLATES.TPL_REAL",
"DESCRIPTION", "Tank inflow (m3/min), class CIENG_JFLOW");
}
public void signalEvent(Signal signal) {
double mInflow = sInflow.getValueAsDouble();
sPerMin.setValue(mInflow / 60.0);
systemMessage("CIENG_JFLOW " + getTag() + ": inflow " + mInflow);
}
}
"@

View file

@ -4,9 +4,12 @@ ENGLISH
@VERSION
1.03.00
! CI-Eng-Sample object created from class CIENG_INCR
! CI-Eng-Sample objects, CI Server R1.03.00
! ATTR_VALUE_n answers the class's n-th PROMPT (CIENG_TANK: capacity in m3).
@FIELDS
NAME,DESCRIPTION,CLASS
NAME,DESCRIPTION,CLASS,ATTR_VALUE_1
@OBJECT_DF
"CI-Eng-Sample.DEMO.INCR1","Counts DEMO.COUNTER every second","CIENG_INCR"
"CI-Eng-Sample.DEMO.INCR1","Counts DEMO.COUNTER every second","CIENG_INCR",""
"CI-Eng-Sample.TANK1.CALC","Tank 1 volume (capacity 200 m3)","CIENG_TANK","200"
"CI-Eng-Sample.TANK1.JFLOW","Tank 1 inflow per minute (Java)","CIENG_JFLOW",""

View file

@ -10,3 +10,5 @@ NAME
@OBJECT_DF
"CI-Eng-Sample.DEMO.INCR1"
"CI-Eng-Sample.TANK1.CALC"
"CI-Eng-Sample.TANK1.JFLOW"

View file

@ -10,3 +10,5 @@ NAME
@CLASS_DF
"CIENG_INCR"
"CIENG_TANK"
"CIENG_JFLOW"

View file

@ -19,3 +19,4 @@ NAME
"CI-Eng-Sample.SYSTEM.PROC_ALM"
"CI-Eng-Sample.DEMO.COUNTER"
"CI-Eng-Sample.PLC1.COMM_OK"
"CI-Eng-Sample.TEMPLATES.TPL_REAL"

View file

@ -14,4 +14,5 @@ NAME
"CI-Eng-Sample.SYSTEM"
"CI-Eng-Sample.PLC1"
"CI-Eng-Sample.DEMO"
"CI-Eng-Sample.TEMPLATES"
"CI-Eng-Sample"

View file

@ -46,6 +46,12 @@ cmd /c "<repo>\examples\CI-Eng-Sample\remove.cmd"
| `CIENG_1S` | Trigger group | Every second |
| `CIENG_INCR` | Class (traditional) | Increments `DEMO.COUNTER`, wraps at 100; compiled on load |
| `CI-Eng-Sample.DEMO.INCR1` | Object | Instance of `CIENG_INCR` |
| `CI-Eng-Sample.TEMPLATES` | Section | Template items for classes |
| `CI-Eng-Sample.TEMPLATES.TPL_REAL` | Item, Real | Template for items that objects create (format `9999.9`, scale 0–1000) |
| `CIENG_TANK` | Class (traditional) | Prompt *Tank capacity (m3)*; signal `LEVEL` = `<object section>.LEVEL` (trigger on value); creates `<object>.VOLUME` from `TPL_REAL`; volume = level × capacity / 100; logs when the level crosses 80; refuses capacity ≤ 0 |
| `CI-Eng-Sample.TANK1.CALC` | Object | `CIENG_TANK`, capacity 200; creates section `TANK1.CALC` and item `TANK1.CALC.VOLUME` |
| `CIENG_JFLOW` | Class (Java) | Attaches `<object section>.INFLOW`; creates `<object>.sPerMin` = inflow / 60; logs each change |
| `CI-Eng-Sample.TANK1.JFLOW` | Object | `CIENG_JFLOW`; creates item `TANK1.JFLOW.sPerMin` (mixed case, as the Java identifier) |
| `CIENG_EVENT` | Item storage group | Event/Item, lifetime 1 week, rollover 1 day |
| `CI-Eng-Sample.PLC1` | Section | Modbus loopback station |
| `CI-Eng-Sample.PLC1.COMM_OK` | Item, Boolean | Status item of station `CIENG_PLC` (1 = communicating, status 22 when off-scan) |
@ -56,6 +62,9 @@ cmd /c "<repo>\examples\CI-Eng-Sample\remove.cmd"
| `CIENG_SCAN1S` | Modbus scan type | 1000 ms |
| `CIENG_VIEWER` | Authorization group | Read-only: `ITEM_READ`, `SECTION_READ`, `ALARM_CURRENT_READ`, `ALARM_CHRONO_READ`. No users are created by the sample. |
Items created by objects (`TANK1.CALC.VOLUME`, `TANK1.JFLOW.sPerMin`) and their sections are
deleted with the objects; they are not in `02_item_df.qli`.
All items except `PLC1.*` are internal (no station). The `PLC1` station talks to CI Server's own Modbus slave mirror (see below), so no PLC is needed either.
New items start with status 13 (`NOT INIT`) until a value is written.
@ -68,7 +77,7 @@ New items start with status 13 (`NOT INIT`) until a value is written.
| `02b_sub_item_df.qli` | Sub-items (`SUB_ITEM_DF`) |
| `03_his_group_df.qli` | Item storage group (`HIS_GROUP_DF`) |
| `04_item_his_df.qli` | Items in the storage group (`ITEM_HIS_DF`, name `<group>:<item>`) |
| `05_trigger_df.qli`, `06_class_df.qli`, `07_object_df.qli` | Trigger group, class (source in the `METHOD` memo, `@"` … `"@`, `COMPILE` 1), object |
| `05_trigger_df.qli`, `06_class_df.qli`, `07_object_df.qli` | Trigger group; classes (source in the `METHOD` memo, `@"` … `"@`, `COMPILE` 1; Traditional and Java); objects (`ATTR_VALUE_1` = prompt answer) |
| `08_auth_group_df.qli` | Authorization group (`AUTH_GROUP_DF`) |
| `09_modbus_line_df.qli`, `10_modbus_station_df.qli`, `11_item_eqp_df.qli` | Modbus line; station, scan type, points; items connected to points |
| `equipment/eqpciengslv_start.cmd`, `_stop.cmd` | Start/stop the Modbus slave mirror (copy to `tls\com`) |
@ -103,7 +112,6 @@ testing. See the `system-management` skill, task `monitoring-processes.md`.
| Phase | Adds |
|---|---|
| 6 | Template items, a class with attributes/prompts, objects that create items |
| 8 | Alarm settings on sample items |
| 9 | More storage groups (scan/time, aggregation) |
| 10 | A display and symbol |

View file

@ -44,3 +44,8 @@ development system (see "Test system" in `progress.md`); they do not exist on ot
| ISS-022 | 2026-09-30 | ITEM (`itmval -f`) | `itmval -f <file> vs -n CI-Eng-Sample.TANK1.LEVEL` (IM 36K10L36 §1.4, write a restore command) crashes with a segmentation fault (bash) / access violation 0xC0000005 (PowerShell) and writes no file; also with `-l`. The manual's space-separated form `-n <inst> <unit> <tag>` is rejected with `FSL-E-NARG_ALL`. `itmval -g`/`-p` work. | open | Workaround: build restore lines from `itmval -g` output. Report to Yokogawa support if needed. | `knowledge/manuals/IM36K10L36-01EN.md` §3; `.claude/skills/system-management/tasks/read-write-item.md` |
| ISS-023 | 2026-09-30 | ITEM / ITH (manual vs install) | Installed ITEM Service differs from IM 36K10L35/L36: `item_start.cmd` starts `itheix` (EVENT/ITEM storage, not described), aggregation `ithsag`/`ithrag`, two instances of each retrieve process, and `itmtim 100 1000 1 200 1` (five arguments, three documented); `itm.sup` item pool is 650000 KB (manual default 50000) and has `not_regained` (not described); `itheix.sup` has `max_sample_delay`, `max_samples_queued`, `max_open_files`. | closed | Closed 2026-09-30 (user decision: the installed software is the reference). Summaries describe the installed values. | `knowledge/manuals/IM36K10L35-01EN.md`; `knowledge/manuals/IM36K10L36-01EN.md` |
| ISS-024 | 2026-09-30 | EQUIPMENT (Modbus slave) | IM 36K10L41 §3.7 says `EQPMDCSLVTCP` waits for "MODBUS RTU requests via TCP/IP" and the CI Server master should use "MODBUS RTU via TCP/IP". A Modbus master station with `PROTOCOL = RTU` to `eqpmdcslvtcp` (port 5020) got no answer (`EQP-E-TCPRCVTMO`, 4 requests, 0 valid); with `Open Modbus/TCP` it worked at once. | closed | Closed 2026-09-30 (user decision: installed software is the reference). Use `Open Modbus/TCP` towards `eqpmdcslvtcp`. | `knowledge/manuals/IM36K10L41-01EN.md` §3.7; `.claude/skills/equipment/tasks/modbus-station.md` |
| ISS-025 | 2026-09-30 | PROCESS (PRINT) | A Traditional `PRINT "… 80 %, volume ", VOLUME;` logged `OPC-I-INFO, UMH Message Text Error: Message number 083A001B (… level reached 80 )`: the text is cut at the `%` and the rest is lost. Without `%` the full text is logged. | open | Avoid `%` in PRINT/ERROR text (sample uses "pct"). Check whether `%%` or `\%` gives a literal percent sign. | `knowledge/manuals/IM36K10P10-01EN.md` §4; `.claude/skills/class-object-engineering/tasks/traditional-class.md` |
| ISS-026 | 2026-09-30 | PROCESS (`opc.sup`) | Installed PROCESS setup differs from IM 36K10L10 §2: `IMMED-EVENTS = NO` (manual: default on); `FLOW-CONTROL = 30,60` (manual 300/360 s); four executors `OPCEXE1`–`4` with fixed priority ranges (manual examples `OPCEXE01`…) and `opcdbg` still defaults to `OPCEXE`; keyword `VARTAB-SIZE` (manual `VARITAB-SIZE`); hidden keywords `FLDSEP`, `IGNEXI` not described; `ALARM-ITEMS` not set; class source file `opc_clssrc.dat` (manual `opc_clasrc.dat`); `opcini.sup` (licence line) not described. | open | Installed software is the reference (standing user decision); summary written from the installed files. Close when the user confirms. | `knowledge/manuals/IM36K10L10-01EN.md` §2, §5 |
| ISS-027 | 2026-09-30 | PROCESS (`opcdbg`) | IM 36K10L10 §4 says the `opcdbg` *Dump classes/objects* files can be read by `dssqld`. The files have no `@LANGUAGE`/`@FIELDS`/`@<dataset>` headers (`NAME,"desc",prio` + source lines prefixed `- `); `dssqld -i` on the object dump gave `DSS-E-UNK_DS_NM, Unknown data set name`. | open | Use `dssqld -e CLASS_DF` / `OBJECT_DF` for transfers. Maybe an old tool reads the dump format; not found. | `knowledge/manuals/IM36K10L10-01EN.md` §4; `.claude/skills/class-object-engineering/tasks/opcdbg-checks.md` |
| ISS-028 | 2026-09-30 | PROCESS (class reset) | After recompiling a class with objects (`RESET_REQUIRED` 1), `dssqld -m` with `CLASS_DF` `RESET` = 1 (also with `RESET_NODE` = host node name) is accepted with 0 errors but does not reset; `OBJECT_DF` `RESET` = 1 is refused (`OPC-E-OBJ_RSTREQ`). `opcdbg` Classes → 8 *Reset class* works; it asks for a reset report file, which the manual does not list. | open | Use `opcdbg`. Still to try: `CLASS_RESET_COMMAND` (system-wide) and the Engineering Module's reset. | `.claude/skills/class-object-engineering/tasks/change-reset-class.md`; `knowledge/manuals/IM36K10L10-01EN.md` §4 |
| ISS-029 | 2026-09-30 | PROCESS (Java) | IM 36K10P11 §10.4 says a new Java class must be reset before objects are added, otherwise the code does not take effect. A Java class inserted with `COMPILE` 1 by `dssqld` ran its first object correctly without any reset (twice, including a full sample reload). | open | Installed behaviour is the reference; keep "reset after changing a class that has objects". Check whether the Engineering Module path (compile without quick load) behaves differently. | `knowledge/manuals/IM36K10P11-01EN.md` §7; `.claude/skills/class-object-engineering/tasks/java-class.md` |

View file

@ -0,0 +1,118 @@
---
manual: IM 36K10L10-01EN
title: Class/Object Engineering
edition: 3rd Edition, Sep. 2023
version: R1.03
status: from docs; opc.sup, process_start.cmd, the PROCESS data files and opcdbg (database check, get class/object, signals, attributes, reset class, dump, performance main info) checked on the test system 2026-09-30
---
# Class/Object Engineering (R1.03)
PROCESS Service runs **objects**: instances of **classes** (programs written in the
Traditional or Java PROCESS Service language) that link a set of items through **signals** and
are run by **trigger groups**, signal changes or timers. Internally all its process names start
with `OPC` ("Object oriented Process Control") — nothing to do with the OPC Foundation
standard. Section numbers refer to the manual. Language details: `IM36K10P10-01EN.md`
(Traditional) and `IM36K10P11-01EN.md` (Java).
## 1. Processes (§1)
| Process | Role |
|---|---|
| `OPCMAN` | Manager: keeps the configuration (trigger groups, classes, objects); every client request goes through it |
| `OPCCOM` / `OPCJCOM` | Compiler for Traditional / Java classes |
| `OPCACT` / `OPCJACT` | Activator: creates/deletes objects (runs the class prolog / `create()`), creates and deletes the items an object makes |
| `OPCLOA` | Loader: passes run information to the executors; keeps a private copy of the data store on a front-end node |
| `OPCEXE` / `OPCJEXE` | Executor: runs the objects (Traditional / Java); creates the ALARM-statement items |
| `opcdbg` | Command-line debugger (see §4) |
Rules for distributed systems: `OPCMAN`, the compilers and activators run together on the host
node, one of each. Loader/executor pairs may run on other nodes; several executors per node
are allowed, each serving its own **priority range** (0–999).
**Installed (R1.03 test system)**: `process_start.cmd` starts `opcloa`; on the host node also
`opcman`, `opcact`, `opccom`; then **four** Traditional executors `opcexe1`…`opcexe4` and one
Java executor `opcjexe` (a `javaw` process). `OPCJCOM`/`OPCJACT` are not started by the script;
`OPCMAN` starts them on demand (`process_jcom_start.cmd`, `process_jact_start.cmd`) and they exit
after an idle time. Java process logging is configured in
`%TLS_WAP_PATH%\cfg\properties\opcj{act,com,exe}logging.properties`.
## 2. Setup files (§2)
`opc.sup` holds settings for all PROCESS processes; a file named after one process's BUS queue
(e.g. `opcman.sup`) overrides it for that process only. The Java processes read only `opc.sup`.
Change it with the Setup File Editor (skill `portal-setup`); a restart is needed.
Main keywords and the **installed** values (differences from the manual: ISS-026):
| Keyword | Meaning | Installed |
|---|---|---|
| `CLASS-TEMPLATE`, `JCLASS-TEMPLATE` | Source template for new classes | not set → `%TLS_DAT_PATH%\opc_src_tpl.asc` / `opc_jsrc_tpl.asc` |
| `EVENT-BUFFER = node, size, time-out` | ITEM Service buffers item events for PROCESS | `-1, 1000, 0.1` (all nodes) |
| `IMMED-EVENTS` | One extra update per item when an executor starts | `NO` (manual: default YES) |
| `COLD-START` | Front-end loads everything from the host at start (legacy) | `NO` |
| `AUDIT` | Audit trail for configuration and value changes | `NO` |
| `FLOW-CONTROL = interval, timeout` (s) | Heartbeat from ITEM Service; `0,0` disables | `30,60` (manual default 300/360) |
| `TRIGGER-QUEUE-SIZE` | Queued triggers per object; at 90 % a "Loosing real-time" warning | `100` |
| `ALARM-ITEMS`, `ALARM-PRIORITY` | Items and priorities for the language's ALARM statement | not set |
| `HOST-NODE` | PROCESS host node | `-1` (the system host) |
| `ALM-PROC`, `ADT-PROC`, `ITM-PROC` | Queue names of ALARM, AUDIT, ITEM Service | `ITM-PROC = ITM` |
| `PROC-TIME = wait s, jact min, jcom min` | Start wait and idle time-outs of `OPCJACT`/`OPCJCOM`; 0 = 30 min | `20,0,0` |
| `QUEUE-SIZE = process, kB` | BUS queue sizes | `OPCEXE1`–`4` 300, `OPCMAN` 400, `OPCLOA` 252 |
| `PRIORITY-RANGE = executor, from, to` | Priority range per executor; must not overlap | `OPCEXE1` 0–249, `OPCEXE2` 250–499, `OPCEXE3` 500–749, `OPCEXE4` 750–999 |
| `LOCK-CHECK` (s) | Manager housekeeping interval | `10` |
| `SCHEDULER-INTERVAL` (ms) | Finest run resolution for Traditional objects | `500` |
| `TRACE` | Debug output of `OPCEXE` to stdout | `NO` |
| `STATISTICS` | Performance statistics for `opcdbg` (Traditional; Java always on) | `NO` |
| `PRINT` | `PRINT` statement output goes to the message log | `YES` |
| `SYMTAB-SIZE`, `INCTAB-SIZE`, `ALARMTAB-SIZE`, `TIMERTAB-SIZE`, `ATTRIBTAB-SIZE`, `SIGTAB-SIZE`, `LABELTAB-SIZE`, `VARTAB-SIZE`, `FNCTAB-SIZE`, `STRPOOL-SIZE`, `CODE-SIZE` | Compiler table sizes (Traditional) | 4000, 100, 40, 40, 1000, 1000, 100, 4000, 200, 32 kB, 1000 kB |
Also in the file: hidden keywords `FLDSEP = ","` and `IGNEXI = 1` (not described). `opcini.sup`
holds only a licence line; leave it alone.
The object's priority decides which executor runs it: sample objects with priority 0 run in
`OPCEXE1` (seen with `opcdbg`, "Running in : 1, OPCEXE1").
## 3. Ways to create classes and objects (§3)
1. Engineering Module (normal GUI way).
2. `opcdbg` (repair situations).
3. An application using the PROCESS routine interface.
4. **Quick load** with `dssqld` (`CLASS_DF`, `OBJECT_DF`, `TRIGGER_DF`) — used by this repo;
see skill `class-object-engineering`.
## 4. Debugger `opcdbg` (§4)
Interactive; first asks the OPC host node (0 = this node), then the action:
`1` trigger groups, `2` classes, `3` objects, `4` performance, `5` utilities, `-1` exit.
`opcdbg 0 <action>` skips the first two questions. Answers can be piped in (one per line); end
with `-1` lines so it exits, and keep a time-out: on end of input it repeats the last prompt
forever.
| Menu | Useful actions |
|---|---|
| Classes (2) | 5 get class (by **N**ame or **I**d — asked first), 7 compile, 8 **reset class** (all its objects on a node), 12 triggers, 16 all attributes, 18 all signals, 19/20 get/modify attribute value, 21 hide/unhide code |
| Objects (3) | 4 get object (N/I first), 6 reset, 7 trigger, 12 all attributes, 14 all signals (with item ids), 15 debug on/off (writes a trace file), 16/17 get/modify attribute value, 18 object status (runs, executor) |
| Performance (4) | Asks front-end node and **executor name** (default `OPCEXE`, installed names are `OPCEXE1`…`4`); 1 main info, 5 class info, 7 object info, 8 reset statistics, 9 statistics on/off, 10/11 top-10 classes/objects |
| Utilities (5) | 1 reset host/front-end, 2 pending front-end updates, 3/4 dump classes/objects, **5 database check** (read-only), 6 database repair (deletes incomplete data; back up first), 7 disassemble class, 8 clean up "item used" marks, 9 memory dump |
Verified 2026-09-30: *Reset class* asks class name, node **and a file for a reset report**
(not in the manual; empty line = none). Times are printed in GMT. The dump files (3/4) are
**not** in quick load format and `dssqld -i` rejects them (ISS-027); export `CLASS_DF` /
`OBJECT_DF` with `dssqld -e` instead. *Cleanup item used file* fixes items that cannot be
deleted because a removed object still marks them as used.
## 5. Data store (Appendix 1)
Owned by PROCESS Service, in `%TLS_DAT_PATH%`: `opc_clsdef` (class definitions), class source
(installed name `opc_clssrc`, manual `opc_clasrc`), `opc_clsobj` (compiled code), `opc_objdef`,
`opc_attrib` (attribute values of classes and objects), `opc_signal` (item per signal, with
storage info), `opc_trgdef`, `opc_trgact` (trigger group ↔ class/object links), `opc_msgovf`
(pending updates to front-ends). They depend on each other: losing one corrupts the whole
store; check with `opcdbg` utilities 5, repair with 6. Back them up together (they are part of
the `tls\dat` backup).
Related datasets (read with `dssqld -e`, see `IM36K10J10-01EN.md`): `CLASS_DF`, `OBJECT_DF`,
`TRIGGER_DF`, `CLASS_SIGNAL_DF`, `OBJECT_SIGNAL_DF` (object:signal → item), `CLASS_ATTR_VAL`,
`OBJECT_ATTR_VAL` (attribute values, writable with `dssqld -m`), `CLASS_INCLUDED_DF`,
`CLASS_RESET_COMMAND` (system-wide reset command used by the Engineering Module; not practiced).

View file

@ -0,0 +1,167 @@
---
manual: IM 36K10P10-01EN
title: Class Description Language - Traditional
edition: 3rd Edition, Sep. 2023
version: R1.03
status: from docs; PROLOG/ATTRIBUTE/PROMPT/ERROR, SIGNAL to an existing item and SIGNAL … FROM … MAKE, TRIGGER VALUE, the SECTION constant, transitional >=:, PRINT and runtime attribute change verified with CI-Eng-Sample class CIENG_TANK on 2026-09-30; everything else from docs
---
# Traditional PROCESS Service language (R1.03)
Summary in own words; section numbers refer to the manual. Engineering of classes and objects:
`IM36K10L10-01EN.md` and skill `class-object-engineering`.
## 1. Structure (§1, §11.1)
```
CLASS <name>; { name max 15 characters }
PROLOG { optional class prolog: runs when an object is CREATED }
<local declarations, CONTAINS, ATTRIBUTE, PROMPT, SIGNAL, statements>
BODY { needed only when there is a class prolog }
<global declarations: CONSTANT, VAR, TIMER, ALARM, ITEM, FOR>
METHOD <name>; { method name max 50 characters }
ENTRYCONDITION <cond>; { optional guard }
<local declarations>
PROLOG <statements> { optional: first run / after going on-line }
BODY <statements>
EPILOG <statements> { optional: when deactivated }
ENDMETHOD <name>;
ENDCLASS <name>;
```
- Comments: `{ … }`, may span lines.
- All methods of an active object run "simultaneously" (like tasks), not in order.
- Method parts by state: becoming active → prolog + body; staying active → body; becoming
inactive (entry condition false or object off-line) → epilog (Table 1.3-1).
- **Control item** (optional, per object): blocked = methods suspended; off-line = stopped,
on-line again = start as new. Its value is `STEP` (below).
- `SEQUENCE`/`SUBSEQUENCE` are old synonyms of `CLASS`/`METHOD`; do not use.
- Enterprise classes (Enterprise Engineering Module): extra `MAKE` fields `CREATE_ITEM`,
`PUT_IN_HISTORY`, `ALARM_DETECTION` = `MASTER_ONLY` / `DELEGATE_ONLY` / `MASTER_AND_DELEGATE`;
ignored in local classes (§1.6).
## 2. Declarations (§2, §11.2)
| Declaration | Syntax (short) | Notes |
|---|---|---|
| Constant | `CONSTANT a := 1, b := 2.5;` | Type from the expression |
| Variable | `VAR x [INTEGER\|FLOAT\|STRING];` | Default FLOAT; numbers convert, strings and numbers do not mix |
| Timer | `TIMER t [TRIGGER];` | Value = seconds left; `t'status` STOPPED / RUNNING / EXPIRED (initial EXPIRED). Assign seconds to start; 0 → EXPIRED. `TRIGGER` runs the object on expiry |
| Alarm | `ALARM a [TRIGGER];` | Value = alarm text, `a'status` NORMAL/A1/A2/A3 (OR `ACKNOWLEDGE`), `a'priority`. Needs `ALARM-ITEMS` in `opc.sup` (not set on the installed system) |
| Attribute | `ATTRIBUTE n [OBJECT\|CLASS] [INTEGER\|FLOAT\|STRING];` | In class prolog only. OBJECT (default) = per object; CLASS = one value for all objects. Kept across restarts. Name max 15 |
| Prompt | `PROMPT n QUERY "text";` / `NOPROMPT path;` | Asks the value of an OBJECT attribute when an object is created. Declaration, not a statement |
| Containment | `CONTAINS alias := other_class;` | Include another class; access `alias.signal`, nest `a.b.signal` |
| Signal | see §3 | In class prolog only |
| Item / For | `FOR [node:]inst[.unit]; ITEM tag [TRIGGER type];` | Fixed item names (first two section levels only); prefer SIGNAL |
Limits: identifiers 50 characters (class, attribute, signal, function names 15); string values
max 255 characters.
## 3. Signals (§2.3, §11.2.8)
A signal links the object to an item whose name is computed **when the object is created**,
so each object can use different items.
```
SIGNAL LEVEL := SECTION || ".LEVEL" TRIGGER VALUE; { existing item }
SIGNAL VOLUME := FROM "<template item>[;<station>:<template point>]" MAKE
"DESCRIPTION" EQUAL "text" "NAME" EQUAL "<new item name>" … ; { create the item }
```
- Types `INTEGER`, `FLOAT` (default), `STRING` after the signal name.
- `FROM … MAKE`: copies the template item (and point) and overrides the listed fields; any field
of `ITEM_DF`, `SUB_ITEM_DF`, `ITEM_HIS_DF` and the station's `POINT_DF` may be used (e.g.
`"STATION"`, `"POINT"`, `"IO_ADDRESS"`, `"ALARMING" EQUAL ON`, `"PROCESS_LIST" EQUAL "1,3"`).
Storage: `"GROUP_NAME" EQUAL "<group>"` followed by its storage fields (`"STORE_VALUE"`,
`"ON_VALUE_CHANGE"` …); up to 4 groups; order matters. A template's own history membership is
**not** copied.
- Without `"NAME"` the item is named `<object>.[<containment path>.]<signal>` and missing
sections are created (verified: object `CI-Eng-Sample.TANK1.CALC`, signal `VOLUME` →
item `CI-Eng-Sample.TANK1.CALC.VOLUME`). Sub-items always need a name.
- Items and sections the object created are **deleted with the object** (verified), unless the
object has `LEAVE_ITEMS`; existing items are only unlinked.
- An empty template name creates nothing: the signal stays unattached (`sig'attached` false).
- Creating a point that already exists fails the object creation.
- Use `||` to build names; a comma in a SIGNAL statement is read as a list separator.
- Release notes: if the object sits at root level `SECTION` is empty — build names as
`IF SECTION = "" THEN tag ELSE SECTION || "." || tag`; prefer automatic naming.
**Trigger types** (combine with `|`): `VALUE`, `STATUS`, `OPTION`, `UPDATE`, `FIRST`, `PIT`,
`LIMIT`, `QUALITY`.
**Signal attributes** (`sig'attr`; plain `sig` = value): `VALUE`, `OLD_VALUE`, `STATUS`,
`CONTROL_STATUS`, `OPTION_STATUS` (`OPT_BLOCKED`, `OPT_OFF_LINE`, … with bitwise operators),
`MERGED_STATUS`, `ALARM_TYPE`, `ACKNOWLEDGED`, the four limits, `DEADBAND`, `QUALITY`,
`UPDATE_TIME`, `ID_*`, `SECTION`, `TAG`, `SUB`, `APPLICATION_INFO[i]`/`_SIZE`/`_FLAG`,
`LOCKED`, `ATTACHED`. Which are writable differs between the manual's two tables (§2.3 vs
§11.2.8); value and limits are writable in both. To set value and status together use
`SIG_UPDATE`.
**Object constants**: `NOW` (GMT, float seconds), `NODE`, `INSTALLATION`, `UNIT`, `SECTION`
(object's section path — verified), `TAG` (object's tag), `CLASS`.
## 4. Statements and expressions (§3–5, §11.4–11.5, §11.7)
| Statement | Example | Notes |
|---|---|---|
| Assignment | `x := 12;` | To variable, signal (writes the item), attribute, timer, alarm |
| Add | `x :+ 5;` / `x :+ -5;` | |
| IF | `IF c THEN … [ELSE …] ENDIF;` | Nestable |
| TRIGGER | `TRIGGER 60;` / `TRIGGER CLASS alias;` | Run again after n s (last one wins); trigger a contained class |
| PRINT | `PRINT "text ", x;` | To the message log when `PRINT = YES` (installed). A `%` in the text cuts the message (ISS-025) |
| ERROR | `ERROR "text";` | In a method: logs and stops this run. In the class prolog: **object creation is refused** and the text is returned (verified: `dssqld` `.qlo` shows `OPC-E-INFO, <text>`) |
| STEP | `ENTRYCONDITION STEP = 2; … STEP := 3;` | Value of the control item; state machine between methods |
Operators, highest first: unary `+ -`; `NOT ~`; `* /`; `+ -`; string `||` and `,` (comma also
joins numbers); `= <> =: <>:`; `< > <= >= <: >: <=: >=:`; `&`; `^`; `|`; `AND`; `XOR`; `OR`.
**Transitional** operators (`=:`, `>=:` …) are true only on the evaluation where the comparison
**becomes** true (edge detection) — verified: `LEVEL >=: 80.0` fired for 85 and again for 81
after 70, not for 90 after 85. `TRUE`/`ON` and `FALSE`/`OFF` are the same.
`IF TRIGGERED BY GROUP|SIGNAL|TIMER|TRIGGER|ALARM|ONCE` tells why the object ran;
`TRGSIG(sig)`, `TRGTIM(t)`, `TRGALM(a)` name the exact source. A trigger group with interval
**ONCE** runs the object once when it is created, reset, its class reset, or PROCESS starts —
good for initialisation (`ENTRYCONDITION TRIGGERED BY ONCE;`).
Format strings for `STRING(x, "fmt")` (§11.7.4): `9` digits, `0` leading zeros, `+` sign,
`.` decimal point, `EEEE` exponent; dates (seconds since 1970) `D DD DDD M MM MMM Y YY YYYY
Hh Mm Ss P`; `\` escapes; `%…` C-style (`%5.2f`); empty = `%g`.
## 5. Built-in functions (§6.2, §11.6)
- Maths: `ABS`, `TRUNC`, `SQRT`, `POWER`, `EXP`, `LOG`, `LOG10`, `SIN`/`COS`/`TAN`,
`ARC…`, `…HYP`, `RANDOM`.
- Time: `NOW`, `GMT`, `LCT` (local time), `ADDMONTH`, `DAYS`.
- Strings/conversion: `LENGTH`, `LEFT`, `MIDDLE`, `RIGHT`, `STRING`, `INTEGER`, `FLOAT`.
- Trigger info at trigger time: `TRGSIG_VALUE`, `TRGSIG_OLD_VALUE`, `TRGSIG_STATUS`,
`TRGSIG_QUALITY`, `TRGSIG_UPDATE_TIME`, limits, `…_STR_VALUE` etc.
- Signal functions: `SIG_UPDATE(sig, value, status, add)`, `SIG_UPDATE_TIME(…, time)` (sends
time to ITM; size its queue), `SIG_OFFLINE(sig, on)`, `SIG_LOCK`, `SIG_FORCE_ALARM_STATE`,
`SIG_GETSUB(sig, avg, reset)` (read and reset a sub-item in one step), `SIG_GET_…`/`SIG_SET_…`
by attribute id (ids from Yokogawa).
**User functions** (§7): class named `FUNCTIONS` (no objects from it) with
`FUNCTION [INTEGER|FLOAT|STRING|VOID] name; ARG a FLOAT, …; <CONSTANT/VAR>; <statements>;
RETURN v; ENDFUNCTION name;`. Max 10 arguments, passed by reference; a user function with a
built-in's name overrides it.
## 6. Datasets from a class (§12)
- Basic: `DSS_READ_STRING|INTEGER|FLOAT(dataset, record NAME, field, result)` and
`DSS_UPDATE_STRING|INTEGER|FLOAT(…)`; `result` 1 = OK.
- Advanced: `id := DSS_OPEN(dataset, "F1, F2", "rudi", result)` or `DSS_OPEN_ALL`;
`DSS_READ_EQUAL(id, name)`, `DSS_READ_NEXT`, `DSS_SET_FILTER` / `DSS_REMOVE_FILTER`,
`DSS_GET_…` / `DSS_PUT_…` on the field buffer, then `DSS_UPDATE`, `DSS_INSERT`,
`DSS_DELETE`; always `DSS_CLOSE(id)` (otherwise memory leaks). `DSS_ERROR_LOG(on)`.
- Only STRING, INTEGER, FLOAT data types are supported.
## 7. AGA gas calculations (§13)
`AGA_INIT`, `AGA_COMP` (composition), `AGA_CALC`, `AGA_3_METER`, `AGA_CONE`, `AGA_PULSE`,
`AGA_8_GROSS`, `AGA_9_…` (ultrasonic), `AGA_R_…` result getters, `AGA_ERROR`. Not practiced;
see the manual's §13.2 example if needed.
## 8. Examples in the manual (Appendix 1)
`TWIN_UNIT_CONTR` (STEP state machine with timers, transitional operators and limit changes)
and `SENSOR`/`FLUID_VESSEL` (containment). Reserved words: Appendix 2.

View file

@ -0,0 +1,139 @@
---
manual: IM 36K10P11-01EN
title: Class Description Language - Java
edition: 3rd Edition, Sep. 2023
version: R1.03
status: from docs; a Java class (attachItemToSignal, createItemForSignal with automatic name, Signal.Trigger.VALUE, signalEvent, systemMessage) compiled on quick load and run on the test system with CI-Eng-Sample class CIENG_JFLOW on 2026-09-30; everything else from docs
---
# Java PROCESS Service language (R1.03)
Summary in own words; section numbers refer to the manual. Engineering: `IM36K10L10-01EN.md`,
skill `class-object-engineering`. The full API reference is only in the Engineering Module
class editor (F1).
## 1. What Java adds (§1)
Arrays of signals/attributes, loops, inheritance (`extends` another PROCESS class), any Java
library (TCP/IP, files, web services), and signals that need not be attached. Java and
Traditional classes cannot contain each other. Compiled by `OPCJCOM`, created by `OPCJACT`, run
by `OPCJEXE` (see L10 summary).
## 2. Class layout (§1.1, §3)
```java
import fasttools.processfast.*; // the framework; import other packages as usual
public class CIENG_JFLOW extends ProcessClass { // name = class name in CLASS_DF, exactly
// definitions: class level only, no public/protected modifiers
Signal sInflow = defineDoubleSignal(Signal.Trigger.VALUE);
Signal sPerMin = defineDoubleSignal();
Attribute aCapacity = defineDoubleAttribute(Attribute.Scope.OBJECT);
Timer tCheck = defineTimer();
public void create() { /* object created: attach or create items */ }
public void destroy() { /* object deleted (items are detached automatically) */ }
public void start() { /* object starts: after create and at every CI Server start */ }
public void stop() { /* CI Server stops (not guaranteed, e.g. HA switch) */ }
public void signalEvent(Signal signal) { }
public void timerEvent(Timer timer) { }
public void triggerGroupEvent(TriggerGroup triggerGroup) { }
}
```
Naming advice: `s…` signals, `a…` attributes, `t…` timers, `c…` containments, `m…` locals;
identifiers max 15 characters. Omit methods you do not need.
**Two environments** (§3.4, important): `create()`/`destroy()` run in the *creation*
environment (`OPCJACT`), everything else in the *runtime* environment (`OPCJEXE`). Signals have
items only at runtime; timers only at runtime; plain Java fields and objects set in `create()`
are gone at runtime — only **attributes** carry values across. Static fields are not shared
between objects of different priorities. Share data through class-scope attributes or items.
## 3. Signals (§4)
- `defineIntegerSignal()`, `defineDoubleSignal()`, `defineStringSignal()` (string max 79
characters); `…SignalArray(n)` or `…SignalArray(trigger, n)`; max 4095 signals per class.
- Triggers: `Signal.Trigger.VALUE | STATUS | OPTION | UPDATE | FIRST | PIT | LIMIT | QUALITY`
as argument of `define…Signal()`. Without it the signal never triggers.
- In `create()`:
- `attachItemToSignal(sig, "<item>")` — the item must exist, else creation is cancelled and
rolled back.
- `createItemForSignal(sig, "<template>[;<station>:<template point>]", "FIELD", value, …)` —
any `ITEM_DF` field; `"STORAGE_GROUP", "<group>"` followed by `ITEM_HIS_DF` fields (order
matters, max 4 groups); with a point, prefix shared names: `"ITEM'DESCRIPTION"`,
`"POINT'DESCRIPTION"`, and use the station's point dataset fields (`STATION`,
`IO_ADDRESS` …). Sub-items: template must be a sub-item, main item must exist, name required.
- Without `"NAME"` the framework names the item `<object>.<signal identifier>` and creates
the sections; **the identifier's case is kept** (verified: `CI-Eng-Sample.TANK1.JFLOW.sPerMin`;
item names are case-sensitive for `itmval`). Framework-created items and sections are
deleted with the object (verified) unless *Leave items* is set.
- `createSection(path, description, process areas, blocked, opcVisible)` creates sections
you name yourself; the framework cannot always undo these — prefer automatic names.
- Name helpers: `getTag()`, `getSectionsPath()`, `getSections()`, `getFullIdentifierPath(x)`,
`getContainerIdentifierName()`, `getContainerIdentifierPath()`, `getNode()`.
- Unattached signals: `sig.isAttached()`; most methods throw on an unattached signal.
- Handling: override `signalEvent(Signal signal)` and compare with `==`, or add a named inner
class implementing `SignalListener` in `start()` (`addSignalListener`); **anonymous listeners
compile but fail at start** (`NoClassDefFoundError` in the log).
- The signal passed to the handler holds the attribute values of the moment of the trigger.
- Common methods: `getValueAsDouble/Integer/String()`, `getOldValueAs…()`, `setValue(x)`,
`setValueAndStatus(x, Signal.Status.MANUAL)`, `setStatusNumber(Signal.Status.FAILED)`,
limits `get/setHighLimit()` … (throw when the item has no such limit — catch it),
`isOffline()`, `setOffline()`, `isBlocked()`, `getQuality()`, `getUpdateTime()`,
`getValueAsDoubleAndReset()` (sub-items), `setValueAndTime()`.
- Control item: `hasControlSignal()`, `getControlSignal()`; blocked control item = triggers
ignored.
## 4. Attributes (§5)
`defineIntegerAttribute(scope)`, `defineDoubleAttribute(scope)`, `defineStringAttribute(scope)`
(string max 255), `…AttributeArray(scope, n)`; scope `Attribute.Scope.OBJECT` or `.CLASS`.
Prompts: `defineStringAttributeForPrompt("Question:")` (always OBJECT scope; max 100 prompts);
read it in `create()` and call `cancel("message")` to refuse the object (rolls back). Attributes
survive restarts and are visible in the Engineering Module, but writing them is heavy (disk,
and for CLASS scope every runtime) — use them for settings, not process values.
## 5. Timers and trigger groups (§6, §7)
- `defineTimer()` (no arrays; not usable in `create()`/`destroy()`); `t.start(10)` or
`setTime(10)` + `start()`; `setRepeat(true)`; `cancel()`; resolution 1 s. Handle in
`timerEvent()` or with a named `TimerListener`.
- Trigger groups are assigned in engineering (class or object), not in code; handled in
`triggerGroupEvent(tg)` (`tg.getName()`, `tg.getInterval()`, `TriggerGroup.Interval.…`).
Use a trigger group for periodic work, a timer for "check again after a while". ONCE groups
are unnecessary: use `start()`.
## 6. Containment and inheritance (§8, §9)
- `VALVE cGas = (VALVE)defineContainment("VALVE");` — never `new VALVE()`. Prompts of a
contained class become normal attributes: set them in the container's `create()`
(`cGas.aStation.setValue(…)`).
- `create()`/`destroy()` of contained classes are called automatically after the container's
(`call(cX).create()` to force order); `start()`/`stop()` and the `…Event()` methods are **not**
— call or forward them yourself, or use listeners in the contained class.
- Inheritance: `public class BOILER_MIXER extends BOILER`; call `super.create()`,
`super.signalEvent(signal)` etc.; prompts of the super class are kept. A shared base class
(e.g. `BASE_CLASS extends ProcessClass`) holds helper methods; each subclass loads its own
copy (no shared statics). Plain Java code can go in a jar in `%TLS_ROOT_PATH%\tls\exe`; its
classes must have a package name.
## 7. Runtime behaviour (§10)
- Keep trigger methods short, never sleep: one object holds up all objects **of the same
priority** (one thread per priority). Give slow objects their own priority, or extra
executors per priority range.
- Exceptions in `create()` cancel the creation; in a trigger method they abort that trigger and
are logged. Use `try/catch`.
- `systemMessage("text")` writes to the message log (`umhlog.log`, sender `OPCJEXE`, prefixed
with the object name — verified); `cancel("text")` also stops the current trigger.
- `getStatistics()` → processed/lost/queued events, execution times.
- The manual says a changed class must be compiled **and reset**, and a new class reset before
its first object. On the test system a new class compiled by quick load ran its first object
without a reset (ISS-029); after changing a class with objects, reset it (skill task
`change-reset-class.md`).
- Release notes (IM 36K01A50): Java classes that use datasets must get the session with
`getDssSession()` and never close it.
## 8. Examples in the manual (Appendix 1)
Valve, boiler (containment), twin boiler, mixer boiler (inheritance), city temperature.

View file

@ -41,9 +41,9 @@ AID is not needed.
| 5 | IM 36K10L41 | EQUIPMENT Service - Configuration | summarized ([notes](manuals/IM36K10L41-01EN.md)); general + Modbus in detail, other drivers as a table |
| 5 | IM 36K10L35 | ITEM Service - ITH | summarized ([notes](manuals/IM36K10L35-01EN.md)); installed processes and setup files checked |
| 5 | IM 36K10L36 | ITEM Service - ITM | summarized ([notes](manuals/IM36K10L36-01EN.md)); `itmdbg` statistics run; `itmval -f` crashes (ISS-022) |
| 6 | IM 36K10L10 | Class/Object Engineering | not started |
| 6 | IM 36K10P10 | Class Description Language - Traditional | not started |
| 6 | IM 36K10P11 | Class Description Language - Java | not started |
| 6 | IM 36K10L10 | Class/Object Engineering | done; `opc.sup` read-only, `opcdbg` read-only actions and Reset class practiced ([notes](manuals/IM36K10L10-01EN.md)); skill `class-object-engineering` |
| 6 | IM 36K10P10 | Class Description Language - Traditional | done for prompts, signals, created items, transitional operators, PRINT/ERROR; timers, alarms, containment, STEP, DSS routines, AGA from docs ([notes](manuals/IM36K10P10-01EN.md)) |
| 6 | IM 36K10P11 | Class Description Language - Java | done for a basic class (attach/create items, signal trigger, systemMessage); timers, containment, inheritance from docs ([notes](manuals/IM36K10P11-01EN.md)) |
| 7 | IM 36K10L55 | Exchange Tool Engineering | not started |
| 7 | IM 36K10L30 | BUS Service | not started |
| 7 | IM 36K10L45 | Data Access Engineering | not started |
@ -99,7 +99,11 @@ now come before classes and objects (phase 6), and the other interfaces follow a
| C30 | IT Security Tool, Domain Link Management, account utilities | not practiced | n/a | Not installed and not supported on Windows 10 Pro. |
| G10 | Sub-items: Integrator, Min-Max (`SUB_ITEM_DF`) ([task](../.claude/skills/item-engineering/tasks/sub-items.md)) | passed | passed | Integrator adds value × seconds; `TIME_UNIT` ignored. |
| G10 | Block / unblock an item (`ITEM_DF.BLOCKED` via `dssqld -m`); write with `itmval -o` ([task](../.claude/skills/item-engineering/tasks/block-item.md)) | passed | passed | `blk` flag, writes without `-o` silently ignored; `ublk` (*updated blocked*) after unblock ([ISS-001](issues.md), closed). |
| G10 | Trigger group, class (compile on load), object via quick load ([task](../.claude/skills/class-object-engineering/tasks/load-class-object.md)) | passed | passed | `DEMO.COUNTER` counts every second; full remove/load cycle clean. |
| G10 | Trigger group, class (compile on load), object via quick load ([task](../.claude/skills/class-object-engineering/tasks/load-class-object.md)) | passed | passed | `DEMO.COUNTER` counts every second; full remove/load cycle clean. Phase 6: three classes and objects in one remove/load cycle, 0 errors. A class that fails to compile is not inserted (`DSI-E-OPCCOMERR`); error lines appear in `LISTING` after insert with `COMPILE` 0 and a compile update (test class removed). |
| P10/L10 | Traditional class with prompt/attribute, signal from `SECTION`, item created from a template, `ERROR` check, `>=:`, PRINT; attribute change via `OBJECT_ATTR_VAL` ([task](../.claude/skills/class-object-engineering/tasks/traditional-class.md)) | passed | passed | `CIENG_TANK` / `TANK1.CALC`: volume 50→100, 82→164; capacity 0 refused; capacity 200→400 took effect on next run; created item and section deleted with the object. `%` in PRINT cuts the message (ISS-025). |
| P11 | Java class ([task](../.claude/skills/class-object-engineering/tasks/java-class.md)) | passed | passed | `CIENG_JFLOW` / `TANK1.JFLOW`: inflow 120→2, 90→1.5, `systemMessage` in `umhlog.log` from `OPCJEXE`. Created item keeps the identifier's case (`…JFLOW.sPerMin`). Worked without a class reset (ISS-029). |
| L10 | Change a class with objects: compile + reset ([task](../.claude/skills/class-object-engineering/tasks/change-reset-class.md)) | passed | passed | Old code runs until reset (`RESET_REQUIRED` 1). `opcdbg` Reset class works (extra prompt for a report file); `dssqld` `CLASS_DF.RESET` does nothing, `OBJECT_DF.RESET` refused (ISS-028). |
| L10 | `opcdbg` read-only checks ([task](../.claude/skills/class-object-engineering/tasks/opcdbg-checks.md)) | passed | passed | Database check (one never-compiled foreign class `SINUS`), get class/object, object status/signals/attributes, executor main info. Dumps are not `dssqld`-readable (ISS-027). |
| G10/C10 | Authorization group and user creation ([task](../.claude/skills/authorization/tasks/users-groups.md)) | passed | passed | Group `CIENG_VIEWER` (sample file `08_auth_group_df.qli`) loaded/removed by Claude; test user `CIENG_TEST` (no password) loaded by the user, checked and removed. The sample creates no users. |
| C10 | String items: length 1–200, holds length − 1 characters ([task](../.claude/skills/item-engineering/tasks/string-items.md)) | passed | passed | Tested with temporary `CI-Eng-Sample.DEMO.STR*` items (removed): 201 rejected; too-long writes cut, status 12 OVERRANGED ([ISS-019](issues.md)). |
| C10 | Integrator time unit: integration granule `itm_int_secs` in `itm.sup` ([task](../.claude/skills/item-engineering/tasks/sub-items.md)) | passed | passed | 60 → `RUN_SECONDS` +1 per minute; restored to 1 (file identical to backup), +1 per second again ([ISS-010](issues.md)). Elevated restarts run by the user. |