The original hand-curated table was wrong starting at id 74 — entries
had been deduplicated/renumbered without preserving the canonical
`id = 2 * StringN` mapping from `[MC-NBFS]` §2.2, leaving most of
the SOAP-fault subset at the wrong ids:
ours had Fault at 114, canonical is 134
ours had Code at 122, canonical is 142
ours had Reason at 124, canonical is 144
ours had Text at 126, canonical is 146
ours had Value at 134, canonical is 154
ours had Subcode at 136, canonical is 156
Wire captures from the live AVEVA MxDataProvider use the canonical
ids — verified earlier via `MX_ASB_TRACE_REPLY` showing
`<resultCodeField>` correctly resolved through the F30 post-pass
once the ids matched.
Replaced the entire STATIC_ENTRIES array with a faithful port of the
first 200 entries from `dotnet/wcf`'s
`src/System.ServiceModel.Primitives/src/System/ServiceModel/
ServiceModelStringsVersion1.cs` (sourced via WebFetch — that file is
the canonical [MC-NBFS] §2.2 table mirrored in code). The wire id is
`2 * StringN` for `StringN` at 0-based position N. Coverage now spans
id 0..400, picking up the full SOAP / WS-Addressing / WS-RM /
WS-Security / WS-SecureConversation / WS-Trust / xmldsig+xenc URIs /
SAML / Kerberos / X509 token-type subset. The 436..444 xsi/xsd/nil
extras (used by .NET XmlSerializer for [MessageContract] value-type
bodies) are preserved.
Four new regression tests:
- ids monotonic (was already there);
- ids all even (`[MC-NBFS]` reserves odd ids for the dynamic dict);
- SOAP-fault subset (s, Fault, MustUnderstand, Code, Reason, Text,
Node, Role, Detail, Value, Subcode) resolves to the canonical
strings — pins the fix against accidental regression;
- `position_of_static` round-trips for known strings.
Followups:
- F29 moved to ## Resolved with full audit-trail.
- F18 M5 status block updated to strike F29 from the remaining-work
list. The remaining open M5 items are F32 (live type-matrix beyond
Int32/String/Bool, gated on Galaxy provisioning) and F28 (canonical
XML signing for Read/Write/Subscribe ops, P2 latent).
Workspace: 712 unit tests pass (was 711 + 1 new fault-subset test +
existing tests now matching canonical). Clippy clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Ports the curated subset of the `[MC-NBFS]` §2.2 static dictionary to
`mxaccess-asb-nettcp::nbfs`. Approximately 80 entries covering SOAP 1.2
envelope tokens, WS-Addressing 1.0 tokens, WS-RM, WS-Security,
WS-Trust/SecureConversation, XML Schema Instance primitives, plus the
common XML element / attribute names captured in
`analysis/proxy/mxasbclient-*` traces.
API:
* `STATIC_ENTRIES: &[StaticEntry]` — sorted-by-id table; one-line
extension when wire captures show new IDs.
* `lookup_static(id) -> Option<&'static str>` — binary-search lookup
for the F21 NBFX decoder.
* `position_of_static(value) -> Option<u32>` — `OnceLock`-cached
reverse lookup for the F21 NBFX encoder.
Lookups outside the curated subset return `None`. The NBFX decoder
will surface that as a typed `UnknownStaticDictionaryId` error so the
caller knows to either extend the table or fall through to the
inline-string path. The full 487-entry table is bounded but tedious;
the deliberate subset keeps source size down while remaining
extensible.
ASB-specific contract strings (`http://ASB.IDataV2`,
`http://asb.contracts/20111111`, the IASBIDataV2 operation actions,
etc.) are intentionally **not** in the static dictionary — they live
in the per-session dynamic dictionary that the F21 NBFX codec builds
up via `DictionaryString` records.
6 unit tests cover monotonic-id invariant, known-id lookup,
unknown-id rejection, round-trip lookup consistency, and the
empty-string slot at id=142.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>