Verified: EtherNet/IP
Each claim the EtherNet/IP page makes, with the tests that
prove it in the last green CI run: 9 of 43 verified, 14 with no test yet.
The claims live in docs/claims/ethernet-ip.yaml.
Last green CI run 16 Oct 2026, 14:48 UTC on c7618d3 · all runtime claims
EIP-001 verified
An `eip` driver without `host:` or without `manifest:` is rejected at project load (so `naut check` fails, not `naut run`).
- pass
TestSchemaRequiresWhatLoaderRequiresininternal/project
EIP-002 partly verified
`New` never dials: it decodes the manifest, rejects bad scan-class configuration and partitions bindings into scan classes offline, so check and build pass with no controller.
- pass
TestScanClassErrorsineip
EIP-003 partly verified
`naut eip browse` prints one line per tag with its name, type name and array dimensions, including program-scope tags as `Program:<prog>.<tag>`.
EIP-004 verified
`naut eip import` always writes `eip_types.st`; with `--format yaml` it also writes `eip_manifest.yaml` and `tags/eip.yaml`, with `--format go` it writes `eip_manifest.go`, and a missing `--out` directory is created.
EIP-005 partly verified
The import selects device tags by `--tags` globs, excludes module I/O such as `Local:1:I` by default, and marks `--writable` matches as writable outputs.
- pass
TestGenerateineip/codegen - pass
TestTagsYAMLDerivesRolesineip/codegen
EIP-006 verified
The generated tag file gives output role to `--writable` matches and input otherwise, names the UDT in `type:` for struct bindings only, and says in its header that it is generated.
- pass
TestTagsYAMLDerivesRolesineip/codegen - pass
TestTagsYAMLEmitsTypeForUDTsOnlyineip/codegen - pass
TestTagsYAMLHeaderineip/codegen
EIP-007 verified
`--tags-skip` leaves hand-declared tags out of the tag file, and a skip pattern that matches nothing is an error rather than a silent regeneration of a hand-written tag.
- pass
TestTagsYAMLSkipineip/codegen - pass
TestTagsYAMLRejectsStaleSkipineip/codegen
EIP-008 partly verified
`naut eip tags` re-derives just the tag file from the committed manifest with no controller.
- pass
TestTagsYAMLDerivesRolesineip/codegen
EIP-009 no test yet
At every connect the driver validates the manifest against the live controller (missing tag, changed template type, lost UDT member) and drift fails the connection listing every problem rather than mis-decoding.
EIP-010 verified
UDTs become real ST `TYPE` structs a program can use, with the controller's member names verbatim and nested UDTs emitted dependencies-first so the block compiles top to bottom.
- pass
TestGenerateineip/codegen
EIP-011 partly verified
A Logix string template (`DINT LEN` plus `SINT[] DATA`) becomes the type `STRING`, not a struct; array members become `ARRAY[0..n-1]`; `STIME`/`DATE`/`TIME_OF_DAY` map to `DINT` and `DATE_AND_TIME` to `LINT`.
- pass
TestGenerateineip/codegen
EIP-013 partly verified
Tag names are sanitized into identifiers (`Program:MainProgram.Motor` becomes `MainProgram_Motor`, other punctuation becomes `_`, runs collapse, a leading digit gets a `Tag_` prefix, a collision gets `_2`) while the device path stays in the manifest's `device:`.
- pass
TestGenerateineip/codegen - pass
TestLogixEmulateBrowseAndImportincmd/naut
EIP-014 no test yet
What cannot be imported (multi-dimensional arrays, members with an undecoded type code, templates that could not be uploaded) is reported as `skipped:` lines with a reason and never reaches the manifest.
EIP-015 partly verified
A binding's scan class comes from the manifest's `scanclass`, overridden by `tag-classes:` globs matched against either the nautilus tag name or the device path; unassigned bindings are the `default` class at `scan-rate`.
- pass
TestScanClassesineip
EIP-016 verified
Naming a scan class without defining its rate is a load error.
- pass
TestScanClassErrorsineip
EIP-017 verified
The reserved class `none` catalogs a tag without polling it: it never appears in the input set or snapshot, and stays a valid write target.
- pass
TestScanClassesineip
EIP-018 verified
Each class polls at its own rate, and every class is polled once immediately on connect so a slow class does not delay the first snapshot.
- pass
TestScanClassesineip
EIP-019 partly verified
Elementary scalars are batched into Multiple Service Packets sized to the negotiated 500-byte connection, so a class of many scalars costs a handful of round trips.
- pass
TestBatchedReadsineip/logix
EIP-020 partly verified
Structs, strings and arrays are read whole with one Read Tag for the root and decoded into the manifest type.
EIP-021 partly verified
When the controller refuses a whole-struct read (privilege violation), that binding drops to leaf mode for the session: members are read individually and the struct is assembled client-side in manifest field order.
- pass
TestDriverLeafModeFallbackineip
EIP-022 no test yet
In leaf mode a member the controller never serves is detected by its CIP status, logged once, dropped from the poll set and assembled as the IEC zero; a member failing for any other reason holds the binding's last good value, so a partial struct is never published.
EIP-023 no test yet
`/api/drivers` counts the bindings in leaf mode as `leaf structs`.
EIP-024 no test yet
The eip driver reports no per-tag quality of its own: before the first successful poll every input reads Stale (read error), and after a connection drops the last snapshot keeps being served as Good.
EIP-025 no test yet
A dotted path resolves to its root tag, since a UDT arrives whole.
EIP-026 partly verified
A `writable` binding is a `role: output` tag; output changes reach the controller, and a scalar goes as one CIP Write Tag with its Logix type code.
EIP-027 partly verified
A struct output is written member by member symbolically (`Device.Member.Sub`), nested structs recursing.
- pass
TestDriverPollAndWriteineip
EIP-028 no test yet
An unchanged output value never reaches the wire twice.
EIP-029 no test yet
Strings and array members inside a struct are not written, and a top-level STRING or array binding is not a writable target.
EIP-030 partly verified
There is no baseline rule: the first scan's output values, including an output's `init:`, are written to the controller.
- pass
TestLogixEmulateDriverRoundTripincmd/naut
EIP-031 no test yet
A write that fails because the connection broke is requeued (latest value per tag) and retried after reconnect; a write the controller refuses on a live connection is logged, dropped for that flush, and goes again when the value changes.
EIP-032 no test yet
A write kicks the poll loop awake rather than waiting out the next interval.
EIP-033 no test yet
The driver has no write gate: nothing inside it suppresses a command (a standby replica instead skips scans).
EIP-034 verified
`/api/drivers` reports Kind `ethernet-ip` with state connected, connecting, error (with `lastError`) or degraded (connected while every poll fails).
- pass
TestEIPStatusStatesininternal/project
EIP-035 no test yet
The status row is named by host with `Detail: "<host> · slot N"`, carries the listed metrics, and reconnects back off from 1s to about 30s, resetting on success.
EIP-036 partly verified
`naut logix emulate` serves a ControlLogix from an L5X export: controller tags become symbols, program tags are served as `Program:<prog>.<tag>`, initial values come from the export, and aliases, multi-dimensional arrays and types without a public shape (`MESSAGE`, `AXIS_*`) are skipped and reported.
EIP-037 partly verified
`--values` seeds values by client-style path (objects seed members, arrays elements, strings a STRING tag), `--surface` serves a hand-written surface, and bad usage (no source, both sources, bad listen address, unknown seed tag, missing file) exits non-zero.
EIP-038 partly verified
`--ramp` drifts every numeric leaf, leaves BOOLs alone, and a leaf a client writes stops drifting and keeps the write.
- pass
TestLogixEmulateRampincmd/naut
EIP-039 partly verified
Client writes land in the emulator, so a project's outputs read back on the next poll, and the whole browse, import, poll, write path runs against it.
EIP-040 partly verified
The emulator serves Forward_Open, symbolic Read/Write Tag (plain and fragmented), Multiple Service Packet batches, tag-list upload, Template services, and the Identity and Program Name objects, which both nautilus's client and pycomm3 speak.
EIP-041 partly verified
The emulator's `DenyStructRoots` switch refuses struct roots the way a real controller refuses an AOI backing tag, which is how leaf mode is tested.
EIP-042 no test yet
`naut test` never opens a socket: whatever `driver:` configures, every acceptance test substitutes the in-memory loopback driver, and `given:` writes struct bindings field by field using the generated `type:`.
EIP-043 no test yet
Non-Logix CIP devices, implicit Class 1 I/O, PCCC/SLC/PLC-5/Micro800, multi-dimensional arrays, and writing strings or arrays are not supported.
EIP-044 partly verified
`WithScanRate`, `WithScanClass` and `WithTagClass` configure polling from Go, and `ScanClasses()` returns the resolved groups.
- pass
TestScanClassesineip