842b94fb39
The MxValueDetails reader was the root of the false "writeback gap"
diagnosis. Three problems compounded:
1. ReadProperty(attr, "Value") used case-sensitive late-binding via
InvokeMember. The COM-side property is exposed as `value` (lowercase)
on IAttribute, so the lookup silently returned null.
2. Even if the MxValue was retrieved, the accessor probe loop
(Invoke(value, "GetBoolean") -> "GetInteger" -> ... -> "GetString")
relied on IDispatch late-binding. The MxValue interface's accessors
are vtable-only — they aren't reachable through IDispatch — so every
call threw, and the reader reported "no supported scalar accessor
succeeded" even when the typed accessor would have returned the
value cleanly.
3. The probe loop ordering put GetString last, so for any value that
somehow survived the type errors silently, an earlier accessor could
have returned a wrong-typed result.
Fix:
- Add `BindingFlags.IgnoreCase` to ReadProperty + Invoke. COM IDispatch
is case-insensitive at the IDL level; .NET InvokeMember is not unless
explicitly told to be. Comment explains the trap.
- AttributeValueDetails now uses typed `attr.value` (and falls back to
the same lookup via obj.ConfigurableAttributes when the runtime proxy
returns null), bypassing the late-binding gap entirely.
- MxValueDetails casts to IMxValue and dispatches on
GetDataType().ToString(), calling the typed scalar accessor for the
declared type (GetBoolean / GetInteger / GetFloat / GetDouble /
GetString / GetElapsedTime). MxBigString and MxInternationalizedString
share the GetString path. MxTime is left as a follow-up; its
VBFILETIME field layout differs across interop builds.
- Replaced the misleading "Attribute value is not exposed" / "no
scalar accessor succeeded" messages with specific diagnostics that
identify the actual failure (wrong type cast, typed accessor exception,
unhandled MxDataType).
Live verification on $DelmiaReceiver.ProcessRecipe.DeclarationsText:
BEFORE fix: `attribute value get` → Supported: false, Value: null,
"Attribute value is not exposed by this GRAccess attribute."
AFTER fix: `attribute value get` → Supported: true, DataType: MxString,
Value: "// roundtrip-test marker (graccesscli scripts set
--field DeclarationsText)\n"
The reader now correctly surfaces the value graccesscli's writes have
been persisting all along. This is the gap that produced the "writeback
gap" mirage in the previous round of investigation.
Tests still 66/66.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
graccesscli
A .NET Framework 4.8 / x86 CliFx-based CLI for automating AVEVA / Wonderware System Platform Galaxy configuration through the ArchestrA GRAccess COM interop library (ZB.MOM.WW.GRAccess.Cli).
Hard constraints
GRAccess is a 32-bit COM stack. Skipping any of these will fail at load or corrupt Galaxy state:
- Target framework / arch:
net48,x86,[STAThread]. No exceptions. - Cannot be loaded from a .NET 10 / x64 process — see
GRAccess-DLL-and-DotNet10-Notes.md. - AVEVA System Platform must be installed locally (or
ArchestrA.GRAccess.dllregistered in the GAC atC:\Windows\assembly\GAC\Archestra.GRAccess\1.7.0.0_23106a86e706d0ae\). The bundled copy inlib/is for build-time reference only. - In daemon mode, every COM call must be marshalled through
Session/StaComThread.cs; calling GRAccess from any other thread will deadlock or corrupt state. - Keep the root
GRAccessAppalive for the lifetime of any derivedIGalaxy/IgObjecthandle. - Mutation flow is fixed:
CheckOut → modify → Save → CheckIn(comment). SkippingCheckInleaves the object locked in the Galaxy repo. - Build requires Visual Studio / MSBuild with the
x86platform target.
Layout
graccesscli/
ZB.MOM.WW.GRAccess.Cli.slnx # solution
lib/ArchestrA.GRAccess.dll # bundled COM interop assembly (reference only)
src/ZB.MOM.WW.GRAccess.Cli/ # CLI project (net48, x86, CliFx)
tests/ZB.MOM.WW.GRAccess.Cli.Tests # test project
docs/ # CLI workflows, LLM contract, parsing/editing guides
AGENTS.md # coding-agent rules for this tool
CLAUDE.md # detailed agent guide
graccess_documentation.md # full GRAccess API reference
graccess_operations.md # GRAccess operations grouped by functional area
usage.md # compatibility copy of docs/usage.md
GRAccess-DLL-and-DotNet10-Notes.md # platform / 32-bit COM / .NET 10 incident notes
requirements-mutation-typelib-fix.md # active mutation-path defect tracker
Resource index
| Task | Go to |
|---|---|
| Coding-agent rules for working in this folder | AGENTS.md |
| General agent guide (project overview, references) | CLAUDE.md |
| Full GRAccess API surface (types, methods) | graccess_documentation.md |
| GRAccess operations grouped by functional area, with page refs | graccess_operations.md |
| CLI commands, options, session mode, IPC protocol | docs/usage.md |
| LLM-facing operating contract (envelopes, safety, batch) | docs/llm-integration.md |
| Add a new CLI command end-to-end | docs/adding-features.md |
| Inspect / read existing templates (read-only) | docs/template-parsing.md |
| Parse template attributes and setting families | docs/attribute-parsing.md |
| Parse script libraries and object-level scripts | docs/script-parsing.md |
| Edit existing templates safely | docs/template-editing.md |
| Create / edit template instances, areas, engine assignments, I/O | docs/template-instance-editing.md |
| Edit template attributes, UDAs, extensions, setting families | docs/attribute-editing.md |
| Edit script libraries and script-bearing template content | docs/script-editing.md |
Live ZB galaxy reference (read-only capture) |
docs/zb-galaxy.md |
Live ZB $TestMachine template family reference |
docs/zb-testmachine.md |
| CliFx framework reference (commands, options, DI, testing) | docs/clifx_reference.md |
| GRAccess DLL / 32-bit COM / .NET 10 platform notes | GRAccess-DLL-and-DotNet10-Notes.md |
| Active mutation-path COM lifecycle defects | requirements-mutation-typelib-fix.md |
Index for docs/ only |
docs/README.md |
Maintenance
Documentation rules live in ../DOCS-GUIDE.md; the root task → tool index lives in ../CLAUDE.md. When adding, renaming, or removing any doc in this folder, update the resource index above in the same change. When the user-facing CLI surface changes, update docs/usage.md (and keep usage.md aligned).