fix(abcip): budget expected reply size in RequestScheduler.TakeBatch (#582); private lock + struct-handle check across read fragments (#567)

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
Joseph Doherty
2026-10-07 22:53:10 -04:00
parent 04b6563286
commit 9641cefe2e
8 changed files with 187 additions and 16 deletions
+14 -1
View File
@@ -157,6 +157,17 @@ The driver has two interchangeable wire transports, selected by one `DriverConfi
- **One CIP connection and one request scheduler per device** (`DeviceSessionPool`), shared by reads,
writes, browse and template reads. The Multiple Service Packet scheduler coalesces requests with one
request in flight; large reads (listing pages, Read Template) are sent unpacked and exclusive.
**Packing budgets the expected reply as well as the request (#582):** each queued request declares an
upper bound on its reply (`expectedReplyBytes`; reads: elements x element width, STRING = 88 bytes per
element, BOOL counted as 4) and a batch is closed when the summed MSP reply (`6 + 2n + sum`) would exceed
the connection size. A read whose size cannot be bounded (structure / unknown authored type) is sent
alone; writes and status-only replies count their 4-byte header. Pinned by
`RequestSchedulerTests.Mixed_scalar_string_and_array_replies_are_packed_within_the_reply_budget`.
⚠️ RESIDUAL: mixed STRING/array packing has not been exercised against a real controller (the real-press
gate predates the budget); the budget is unit-tested against the scheduler and fake channel only.
- **Fragmented-read integrity (#567):** `Read Tag Fragmented` replies are compared against the first reply;
a changed type code *or* structure handle mid-read fails the read with `BadReply` rather than stitching
two types into one value.
- **Forward Open throttle:** at most one attempt in flight, at least 1 s between starts, bounded by the
open budget.
- `ConnectionSize` / `Timeout` / `AllowPacking` are honoured per pooled connection, and the **first**
@@ -194,7 +205,9 @@ The driver has two interchangeable wire transports, selected by one `DriverConfi
(2026-10-08) and nothing else. Results:
[native-ab-transport-gate-results](../plans/2026-10-07-native-ab-transport-gate-results.md).
- **libplctag cannot be deleted** until a bench controller allows write verification.
- Wide-struct fragmented writes (8-byte alignment) are unit-tested only, never proven on a controller (#567).
- ⚠️ RESIDUAL (#567): wide-struct **fragmented writes** (8-byte alignment) are unit-tested only. Production
presses are read-only and there is no bench controller, so this cannot be proven; it stays open until a
bench controller exists.
- Native browse: listing pages are unpaced, and template reads outside an enumeration open a connection per
call (#572).
- Micro800, routed and `logixpccc` paths are covered by `ab_server` only. The Micro800 profile passes