# Client Behavior Fixtures Client behavior fixtures define the shared expectations used by the official .NET, Go, Rust, Python, and Java clients. They keep wrapper behavior aligned while each language exposes idiomatic APIs over the same protobuf contract. ## Fixture Set The fixture manifest is `clients/proto/fixtures/behavior/manifest.json`. `clients/proto/proto-inputs.json` references the fixture root through `behaviorFixtureRoot` so generators and client test projects can discover the same files they use for descriptor inputs. The fixture set contains: - command reply protobuf JSON, - ordered event stream protobuf JSON samples, - `MxValue` conversion case sets, - `MxStatusProxy` conversion case sets, - authentication and authorization error expectations, - timeout and cancellation behavior expectations. Protobuf message fixtures use protobuf JSON field names and enum values. Files that describe client wrapper behavior use explicit JSON fields instead of a proto message because those expectations apply above the generated transport types. ## Command Replies Command reply fixtures live in `clients/proto/fixtures/behavior/command-replies/`. They parse as `mxaccess_gateway.v1.MxCommandReply`. Clients use these fixtures to verify that successful and failed MXAccess commands both carry the full reply details: - `protocolStatus`, - `hresult`, - `returnValue`, - repeated `statuses`, - method-specific reply payloads when MXAccess returns out parameters. MXAccess failures remain command replies when the gateway reached the worker and the worker captured HRESULT or `MXSTATUS_PROXY` details. Client wrappers should map those replies to rich command errors without discarding the raw reply. ### Reply Validation Conformance Four command reply fixtures pin the two reply-validation rules every client applies, because both rules have edges where a naive reading disagrees with the wire contract: | Fixture | Reply | Expected verdict | |---|---|---| | `write.status-category-error-success-set.reply.json` | one status with `success = 1`, `category = MX_STATUS_CATEGORY_COMMUNICATION_ERROR` | failure | | `write.status-category-ok-success-zero.reply.json` | one status with `success = 0`, `category = MX_STATUS_CATEGORY_OK` | success | | `write.hresult-s-false.reply.json` | `hresult = 1` (`S_FALSE`), statuses OK | success | | `write.hresult-e-fail.reply.json` | `hresult = -2147467259` (`E_FAIL`), statuses OK | failure | The rules those fixtures lock in are: - **Status entries.** An `MxStatusProxy` entry is a failure exactly when `category != MX_STATUS_CATEGORY_OK`. `success` mirrors the raw 16-bit COM member and is diagnostics only, so it never participates in the verdict — the proto contract makes `category` authoritative. An absent entry is success (nothing was reported); a present entry with `MX_STATUS_CATEGORY_UNSPECIFIED` is a failure, because the worker always maps a category and an unmapped one is not proven OK. - **HRESULT.** A reply fails on HRESULT exactly when `hresult` is present and negative. Positive COM success codes such as `S_FALSE` pass, matching COM semantics. ## Event Streams Event stream fixtures live in `clients/proto/fixtures/behavior/event-streams/`. Each file contains an ordered `events` array whose entries parse as `mxaccess_gateway.v1.MxEvent`. Clients use these fixtures to verify that stream helpers preserve `workerSequence` order and expose each native event family: - `OnDataChange`, - `OnWriteComplete`, - `OperationComplete`, - `OnBufferedDataChange`. Wrappers must not reorder, coalesce, or drop events while reading the fixture. ## Value And Status Conversion Value fixtures live in `clients/proto/fixtures/behavior/values/`. Each case contains a `value` object that parses as `mxaccess_gateway.v1.MxValue`. Status fixtures live in `clients/proto/fixtures/behavior/statuses/`. Each case contains a `status` object that parses as `mxaccess_gateway.v1.MxStatusProxy`. Clients use these fixtures to verify typed projections and raw fallback behavior. A language helper may expose native booleans, integers, strings, arrays, and timestamps, but it must keep `rawDiagnostic`, raw data type fields, and raw byte payloads accessible when conversion is incomplete. ## Auth, Timeout, And Cancel Behavior Authentication fixtures live in `clients/proto/fixtures/behavior/auth/`. They separate `UNAUTHENTICATED` from `PERMISSION_DENIED` so clients map missing or invalid credentials differently from missing scopes. Expected output strings contain only redacted credentials. Timeout and cancellation fixtures live in `clients/proto/fixtures/behavior/timeout-cancel/`. They document that canceling or timing out a client call stops the client from waiting, but it does not abort an in-flight MXAccess COM call on the worker STA. Clients should follow up with `GetSessionState` or `CloseSession` before reusing handles after an uncertain command timeout. ## Validation Run the fixture validation tests after changing the behavior fixture set: ```bash powershell -ExecutionPolicy Bypass -File scripts/validate-client-behavior-fixtures.ps1 ``` The script runs the focused C# contract tests that parse all protobuf JSON fixtures and validate deterministic wrapper expectation files. ## Related Documentation - [Client Proto Generation](./ClientProtoGeneration.md) - [Client Libraries Detailed Design](./ClientLibrariesDesign.md) - [Protobuf Contracts](./Contracts.md)