diff --git a/ZB.MOM.WW.OtOpcUa.slnx b/ZB.MOM.WW.OtOpcUa.slnx
index 6207782..cc7bc01 100644
--- a/ZB.MOM.WW.OtOpcUa.slnx
+++ b/ZB.MOM.WW.OtOpcUa.slnx
@@ -37,6 +37,7 @@
+
diff --git a/docs/drivers/AbLegacy-Test-Fixture.md b/docs/drivers/AbLegacy-Test-Fixture.md
index ee24f14..4dc2ac2 100644
--- a/docs/drivers/AbLegacy-Test-Fixture.md
+++ b/docs/drivers/AbLegacy-Test-Fixture.md
@@ -3,18 +3,34 @@
Coverage map + gap inventory for the AB Legacy (PCCC) driver — SLC 500 /
MicroLogix / PLC-5 / LogixPccc-mode.
-**TL;DR: there is no integration fixture.** Everything runs through a
-`FakeAbLegacyTag` injected via `IAbLegacyTagFactory`. libplctag powers the
-real wire path but ships no in-process fake, and `ab_server` has no PCCC
-emulation either — so PCCC behavior against real hardware is trusted from
-field deployments, not from CI.
+**TL;DR:** Docker integration-test scaffolding lives at
+`tests/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.IntegrationTests/` (task #224),
+reusing the AB CIP `ab_server` image in PCCC mode with per-family
+compose profiles (`slc500` / `micrologix` / `plc5`). Scaffold passes
+the skip-when-absent contract cleanly. **Wire-level round-trip against
+`ab_server` PCCC mode currently fails** with `BadCommunicationError`
+on read/write (verified 2026-04-20) — ab_server's PCCC server-side
+coverage is narrower than libplctag's PCCC client expects. The smoke
+tests target the correct shape for real hardware + should pass when
+`AB_LEGACY_ENDPOINT` points at a real SLC 5/05 / MicroLogix. Unit tests
+via `FakeAbLegacyTag` still carry the contract coverage.
## What the fixture is
-Nothing at the integration layer.
-`tests/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/` is unit-only, all tests
-tagged `[Trait("Category", "Unit")]`. The driver accepts
-`IAbLegacyTagFactory` via ctor DI; every test supplies a `FakeAbLegacyTag`.
+**Integration layer** (task #224, scaffolded with a known ab_server
+gap):
+`tests/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.IntegrationTests/` with
+`AbLegacyServerFixture` (TCP-probes `localhost:44818`) + three smoke
+tests (parametric read across families, SLC500 write-then-read). Reuses
+the AB CIP `otopcua-ab-server:libplctag-release` image via a relative
+`build:` context in `Docker/docker-compose.yml` — one image, different
+`--plc` flags. See `Docker/README.md` §Known limitations for the
+ab_server PCCC round-trip gap + resolution paths.
+
+**Unit layer**: `tests/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/` is
+still the primary coverage. All tests tagged `[Trait("Category", "Unit")]`.
+The driver accepts `IAbLegacyTagFactory` via ctor DI; every test
+supplies a `FakeAbLegacyTag`.
## What it actually covers (unit only)
@@ -77,20 +93,32 @@ cover the common ones but uncommon ones (`R` counters, `S` status files,
## Follow-up candidates
-1. **Nothing open-source** — libplctag's test suite runs against real
- hardware; there is no public PCCC simulator comparable to `pymodbus` or
- `ab_server`.
-2. **Lab rig** — cheapest path is a used SLC 5/05 or MicroLogix 1100 on a
- dedicated network; the parts are end-of-life but still available. PLC-5
- and LogixPccc-mode behavior require those specific controllers.
-3. **libplctag upstream test harness** — the project's own `tests/` folder
- has PCCC cases we could try to adapt, but they assume specific hardware.
-
-AB Legacy is inherently a trust-the-library driver until someone stands up
-a rig.
+1. **Fix ab_server PCCC coverage upstream** — the scaffold lands the
+ Docker infrastructure; the wire-level round-trip gap is in ab_server
+ itself. Filing a patch to `libplctag/libplctag` to expand PCCC
+ server-side opcode coverage would make the scaffolded smoke tests
+ pass without a golden-box tier.
+2. **Rockwell RSEmulate 500 golden-box tier** — Rockwell's real emulator
+ for SLC/MicroLogix/PLC-5. Would close UDT-equivalent (integer-file
+ indirection), timer/counter decomposition, and real ladder execution
+ gaps. Costs: RSLinx OEM license, Windows-only, Hyper-V conflict
+ matching TwinCAT XAR + Logix Emulate, no clean PR-diffable project
+ format (SLC/ML save as binary `.RSS`). Scaffold like the Logix
+ Emulate tier when operationally worth it.
+3. **Lab rig** — used SLC 5/05 or MicroLogix 1100 on a dedicated
+ network; parts are end-of-life but still available. PLC-5 +
+ LogixPccc-mode behaviour + DF1 serial need specific controllers.
## Key fixture / config files
+- `tests/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.IntegrationTests/AbLegacyServerFixture.cs`
+ — TCP probe + skip attributes + env-var parsing
+- `tests/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.IntegrationTests/AbLegacyReadSmokeTests.cs`
+ — three wire-level smoke tests (currently blocked by ab_server PCCC gap)
+- `tests/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.IntegrationTests/Docker/docker-compose.yml`
+ — compose profiles reusing AB CIP Dockerfile
+- `tests/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.IntegrationTests/Docker/README.md`
+ — known-limitations write-up + resolution paths
- `tests/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Tests/FakeAbLegacyTag.cs` —
in-process fake + factory
- `src/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy/AbLegacyDriver.cs` — scope remarks
diff --git a/docs/drivers/README.md b/docs/drivers/README.md
index 4b48c19..7e3c358 100644
--- a/docs/drivers/README.md
+++ b/docs/drivers/README.md
@@ -44,7 +44,7 @@ Each driver has a dedicated fixture doc that lays out what the integration / uni
- [AB CIP](AbServer-Test-Fixture.md) — Dockerized `ab_server` (multi-stage build from libplctag source); atomic-read smoke across 4 families; UDT / ALMD / family quirks unit-only
- [Modbus](Modbus-Test-Fixture.md) — Dockerized `pymodbus` + per-family JSON profiles (4 compose profiles); best-covered driver, gaps are error-path-shaped
- [Siemens S7](S7-Test-Fixture.md) — Dockerized `python-snap7` server; DB/MB read + write round-trip verified end-to-end on `:1102`
-- [AB Legacy](AbLegacy-Test-Fixture.md) — no integration fixture, unit-only via `FakeAbLegacyTag` (libplctag PCCC)
+- [AB Legacy](AbLegacy-Test-Fixture.md) — Docker scaffold via `ab_server` PCCC mode (task #224); wire-level round-trip currently blocked by ab_server's PCCC coverage gap, docs call out RSEmulate 500 + lab-rig resolution paths
- [TwinCAT](TwinCAT-Test-Fixture.md) — XAR-VM integration scaffolding (task #221); three smoke tests skip when VM unreachable. Unit via `FakeTwinCATClient` with native-notification harness
- [FOCAS](FOCAS-Test-Fixture.md) — no integration fixture, unit-only via `FakeFocasClient`; Tier C out-of-process isolation scoped but not shipped
- [OPC UA Client](OpcUaClient-Test-Fixture.md) — no integration fixture, unit-only via mocked `Session`; loopback against this repo's own server is the obvious next step
diff --git a/tests/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.IntegrationTests/AbLegacyReadSmokeTests.cs b/tests/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.IntegrationTests/AbLegacyReadSmokeTests.cs
new file mode 100644
index 0000000..7412902
--- /dev/null
+++ b/tests/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.IntegrationTests/AbLegacyReadSmokeTests.cs
@@ -0,0 +1,93 @@
+using Shouldly;
+using Xunit;
+using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
+using ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.PlcFamilies;
+
+namespace ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.IntegrationTests;
+
+///
+/// End-to-end smoke tests against the ab_server PCCC Docker container.
+/// Promotes the AB Legacy driver from unit-only coverage (FakeAbLegacyTag)
+/// to wire-level: real libplctag PCCC stack over real TCP against the ab_server
+/// simulator. Parametrised over all three families (SLC 500 / MicroLogix / PLC-5)
+/// via [AbLegacyTheory] + [MemberData].
+///
+[Collection(AbLegacyServerCollection.Name)]
+[Trait("Category", "Integration")]
+[Trait("Simulator", "ab_server-PCCC")]
+public sealed class AbLegacyReadSmokeTests(AbLegacyServerFixture sim)
+{
+ public static IEnumerable