docs(audit): AbServer-Test-Fixture.md — accuracy pass
STRUCTURAL: links-report.md row — path MISSING src/tools/ab_server/. ab_server is not in this repo; it lives in the upstream libplctag/libplctag GitHub repo and is cloned + built inside Docker/Dockerfile. Rewrote Binary bullet to describe it as an external upstream source (no local path reference that fails the link checker). STALE-STATUS: Lifecycle TCP-probe host was listed as 127.0.0.1:44818 (AbServer-Test-Fixture.md:21). AbServerFixture.cs:35,72 default is 10.100.0.35:44818 (shared Docker host, migrated 2026-04-28). Fixed. CODE-REALITY: Micro800 profile Notes quoted "ab_server has no --plc micro800 — falls back to controllogix emulation." Incorrect: Docker/docker-compose.yml micro800 service uses --plc=Micro800; AbServerProfile.cs:49 confirms "--plc=Micro800 mode (unconnected-only, empty path)." Updated Notes quote and summary table row to match actual compose behaviour. Verified: python3 .docs-audit/check_links.py — zero rows for this doc.
This commit is contained in:
@@ -10,17 +10,20 @@ quirk. UDT / alarm / quirk behavior is verified only by unit tests with
|
|||||||
|
|
||||||
## What the fixture is
|
## What the fixture is
|
||||||
|
|
||||||
- **Binary**: `ab_server` — a C program in libplctag's
|
- **Binary**: `ab_server` — a C program from the upstream
|
||||||
`src/tools/ab_server/` ([libplctag/libplctag](https://github.com/libplctag/libplctag),
|
[libplctag/libplctag](https://github.com/libplctag/libplctag) repository
|
||||||
MIT).
|
(MIT license). It is **not** part of this repo's source tree; `Docker/Dockerfile`
|
||||||
|
clones libplctag at a pinned tag and builds the `ab_server` CMake target in a
|
||||||
|
multi-stage build.
|
||||||
- **Launcher**: Docker (only supported path). `Docker/Dockerfile`
|
- **Launcher**: Docker (only supported path). `Docker/Dockerfile`
|
||||||
multi-stage-builds `ab_server` from source against a pinned libplctag
|
multi-stage-builds `ab_server` from source by cloning libplctag at a pinned
|
||||||
tag + copies the binary into a slim runtime image.
|
tag + copies the binary into a slim runtime image.
|
||||||
`Docker/docker-compose.yml` has per-family services (`controllogix`
|
`Docker/docker-compose.yml` has per-family services (`controllogix`
|
||||||
/ `compactlogix` / `micro800` / `guardlogix`); all bind `:44818`.
|
/ `compactlogix` / `micro800` / `guardlogix`); all bind `:44818`.
|
||||||
- **Lifecycle**: `AbServerFixture` TCP-probes `127.0.0.1:44818` at
|
- **Lifecycle**: `AbServerFixture` TCP-probes `10.100.0.35:44818` (the shared
|
||||||
collection init + records a skip reason when unreachable. Tests skip
|
Docker host) at collection init + records a skip reason when unreachable.
|
||||||
via `[AbServerFact]` / `[AbServerTheory]` which check the same probe.
|
Tests skip via `[AbServerFact]` / `[AbServerTheory]` which check the same
|
||||||
|
probe.
|
||||||
- **Profiles**: `KnownProfiles.{ControlLogix, CompactLogix, Micro800, GuardLogix}`
|
- **Profiles**: `KnownProfiles.{ControlLogix, CompactLogix, Micro800, GuardLogix}`
|
||||||
in `AbServerProfile.cs` — thin Family + ComposeProfile + Notes records;
|
in `AbServerProfile.cs` — thin Family + ComposeProfile + Notes records;
|
||||||
the compose file is the canonical source of truth for which tags get
|
the compose file is the canonical source of truth for which tags get
|
||||||
@@ -71,12 +74,15 @@ Unit coverage: `AbCipAlarmProjectionTests` — fakes feed `InFaulted` /
|
|||||||
|
|
||||||
### 3. Micro800 unconnected-only path
|
### 3. Micro800 unconnected-only path
|
||||||
|
|
||||||
Micro800 profile `Notes`: *"ab_server has no --plc micro800 — falls back to
|
Micro800 profile `Notes`: *"--plc=Micro800 mode (unconnected-only, empty path).
|
||||||
controllogix emulation."*
|
Driver-side enforcement verified in the unit suite."*
|
||||||
|
|
||||||
The empty routing path + unconnected-session requirement (PR 11) is unit-tested
|
The compose service boots `ab_server --plc=Micro800` with an empty routing path.
|
||||||
but never challenged at the CIP wire level. Real Micro800 (2080-series) on a
|
The unconnected-session requirement (PR 11) is validated at the driver unit-test
|
||||||
lab rig would be the authoritative benchmark.
|
level via `FakeAbCipTagRuntime`; the wire-level contract (what happens when
|
||||||
|
a connected-send arrives at a real Micro800 backplane) is not exercised by the
|
||||||
|
simulator. Real Micro800 (2080-series) on a lab rig would be the authoritative
|
||||||
|
benchmark.
|
||||||
|
|
||||||
### 4. GuardLogix safety subsystem
|
### 4. GuardLogix safety subsystem
|
||||||
|
|
||||||
@@ -177,7 +183,7 @@ project is authored.
|
|||||||
| "Is my atomic read path wired correctly?" | yes | yes | yes | yes |
|
| "Is my atomic read path wired correctly?" | yes | yes | yes | yes |
|
||||||
| "Does whole-UDT grouping work?" | no | yes | **yes** | yes |
|
| "Does whole-UDT grouping work?" | no | yes | **yes** | yes |
|
||||||
| "Do ALMD alarms raise + clear?" | no | yes | **yes** | yes |
|
| "Do ALMD alarms raise + clear?" | no | yes | **yes** | yes |
|
||||||
| "Is Micro800 unconnected-only enforced wire-side?" | no (emulated as CLX) | partial | yes | yes (required) |
|
| "Is Micro800 unconnected-only enforced wire-side?" | partial (--plc=Micro800 boots, but wire rejection untested) | partial | yes | yes (required) |
|
||||||
| "Does GuardLogix reject non-safety writes on safety tags?" | no | no | yes (Emulate 5580) | yes |
|
| "Does GuardLogix reject non-safety writes on safety tags?" | no | no | yes (Emulate 5580) | yes |
|
||||||
| "Does CompactLogix refuse oversized ConnectionSize?" | no | partial | yes (5370 firmware) | yes |
|
| "Does CompactLogix refuse oversized ConnectionSize?" | no | partial | yes (5370 firmware) | yes |
|
||||||
| "Does BOOL-in-DINT RMW race against concurrent writers?" | no | yes | partial | yes (stress) |
|
| "Does BOOL-in-DINT RMW race against concurrent writers?" | no | yes | partial | yes (stress) |
|
||||||
|
|||||||
Reference in New Issue
Block a user