c2222b16b0
Three NBFX-spec corrections discovered by diffing our wire output against the .NET probe's capture: 1. **EndElement is 0x01, NOT 0x00**. Our F21 had this wrong since the first iteration. Our round-trip tests passed because encode and decode used the same wrong value, but interop with WCF's parser silently failed (TCP RST on every request). Fixed by changing `REC_END_ELEMENT` to 0x01 — all 702 tests pass on the new value. 2. **Single-letter prefix short forms**. WCF uses `PrefixDictionaryElement_<a-z>` (records 0x44-0x5D) and `PrefixDictionaryAttribute_<a-z>` (records 0x0C-0x25) for single-character prefixes. Our F21 always used the long forms (0x43 prefix-string + dict-id, etc.). The encoder now emits the short form when the prefix is a single ASCII lowercase letter; the decoder accepts both. New `prefix_letter_offset(prefix)` helper. 3. **`DictionaryXmlnsAttribute` (0x0B)** for xmlns:prefix declarations whose value is a static-dict id. The long form (0x09 + prefix-string + text-record) is still emitted when the value is an inline string, but for `xmlns:s="...soap-envelope"` (dict id 4) we now emit the short `0b 01 73 04` form WCF uses. 4. **UniqueIdText (0xAC)** added to `NbfxText` enum + encode/decode. WCF emits `<a:MessageID>` as a UniqueIdText carrying the 16 raw UUID bytes (NOT the `urn:uuid:...` text form). Updated `encode_envelope` to use this for MessageID. Combined wire-byte impact: our envelope body section now matches the .NET probe byte-for-byte through `<a:Action>`, `<h:ConnectionValidator>`, `<a:MessageID>` (UniqueId), `<a:ReplyTo>`, `<a:To>`, and `<s:Body>`. The trailing `01 01 01 01` = 4 EndElements is now the correct record byte. Tests pass (702 total). Live status: still TCP RST after the SizedEnvelope. Remaining unknown is in the body section — the .NET capture shows xmlns:xsi / xmlns:xsd declarations on the operation-specific request element (ConnectRequest etc.) that we don't emit, plus possibly different field encoding inside ConnectRequest. Next iteration will re-capture through the relay and diff our body bytes against the new .NET-byte-equivalent we now produce. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>