Five tools under one repo, all docs organized per DOCS-GUIDE.md: - aalogcli: .NET 4.8 / x86 CliFx CLI for reading System Platform binary logs (*.aaLGX) for LLM debugging, built on aaOpenSource/aaLog. Commands: last, tail, range, unread, fields. Stable JSON envelope under --llm-json. Build template under lib/build/ for rebuilding aaLogReader.dll. - aot: ArchestrA Object Toolkit 2014 v4.0 reference material. Dev guide (Markdown converted from CHM), API reference for the ArchestrA.Toolkit namespace, and the Monitor / Watchdog VS sample solutions. - graccesscli: .NET 4.8 / x86 CliFx CLI that automates Galaxy configuration via the ArchestrA GRAccess COM interop. Includes session daemon, IPC protocol, and llm-json envelope contract. - grdb: SQL/DDL exploration of the Galaxy Repository database. DDL captures, reusable queries, hierarchy / contained-name <-> tag-name translation notes. - histdb: LLM-oriented reference for AVEVA Historian retrieval. INSQL linked-server, extension tables, every wwXxx time-domain extension, every retrieval mode, alarm/event SQL recipes, REST API. Distilled from the 243-page Historian Retrieval Guide. Root contains: - CLAUDE.md: thin index pointing into each tool's README. - DOCS-GUIDE.md: doctrine for organizing docs for LLM consumption. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
13 KiB
Requirements — fix mutation-path COM lifecycle
Authored 2026-04-29; updated 2026-04-30 after retest with the typelib
fix in place. The original TYPE_E_LIBNOTREGISTERED error has been
resolved — objects checkout now succeeds. A second mutation-path
defect has been uncovered in the same retest. This doc covers both;
the typelib regression is preserved as historical context (✅ shipped)
and the new defect is the active blocker.
✅ Already fixed (2026-04-30)
| Command | Mode | Status |
|---|---|---|
objects checkout |
session + one-shot | ✅ CheckOut: True |
objects checkin |
session + one-shot | ✅ CheckIn: True |
object uda add (first call) |
session + one-shot | ✅ Add UDA: OK (but see active defect below) |
The publisher-policy + typed-call fix used for object snapshot is now
applied to the mutation surface. Thank you.
🔴 Active defect — object uda add doesn't Save + CheckIn
Symptom
After a successful object uda add, the template ends up in a
phantom checked-out state that persists across CLI processes and
across helper-process kills:
$cli session start --node localhost --galaxy ZB
$cli template derive --galaxy ZB --name '$UserDefined' --new-name '$X' --confirm --confirm-target '$UserDefined'
# CreateTemplate: OK
$cli objects checkout --galaxy ZB --type template --name '$X' --confirm --confirm-target '$X'
# CheckOut: True
$cli object uda add --galaxy ZB --type template --name '$X' --uda A --data-type MxFloat --category MxCategoryWriteable_USC --security MxSecurityOperate --confirm --confirm-target '$X'
# Add UDA: OK ← lies; nothing persists
$cli object uda add --galaxy ZB --type template --name '$X' --uda B --data-type MxFloat --category MxCategoryWriteable_USC --security MxSecurityTune --confirm --confirm-target '$X'
# Error: Add UDA failed: ID=cmdObjectIsCheckedOutToSomeoneElse (302)
Two consequences
- The "Add UDA: OK" return is a lie. Subsequent
object snapshot --llm-jsonon the same template shows"AttributeValues": []and"CheckoutStatus": "notCheckedOut". The first AddUDA's mutation never persisted in the export-package fallback the snapshot reads from. - The phantom checkout survives process death. Killing all
GRAccessApp.exehelpers (12+ accumulated over an hour of testing) does not release the lock.object snapshotstill saysnotCheckedOutwhile AddUDA still sayscmdObjectIsCheckedOutToSomeoneElse. The two views are inconsistent — likely the GR repo's checkout table holds a row that the AddUDA path checks but the snapshot path doesn't.
Root cause hypothesis
GRAccessCommandDispatcher.cs:507-515 (the case "add": arm of
ExecuteUda) calls obj.AddUDA(...) directly:
case "add":
obj.AddUDA(
Arg(args, "uda"),
EnumValue<MxDataType>(Arg(args, "data-type")),
UdaCategory(Arg(args, "category")),
EnumValue<MxSecurityClassification>(Arg(args, "security")),
BoolArg(args, "is-array"),
IntArg(args, "array-count", 0));
return CommandSummary(obj, "Add UDA");
There is no obj.Save() and no implicit checkin. The GRAccess
mutation lifecycle is:
CheckOut → AddUDA / DeleteUDA / etc. → Save → CheckIn
Skipping Save leaves the change in the helper process's COM-memory
only — when that process dies, the change vanishes. Skipping
CheckIn keeps the GR repo's checkout row alive past the process
death, which is what blocks every subsequent mutation.
The same defect almost certainly affects:
object uda delete,object uda rename,object uda updateobject extension add,object extension delete,object extension renameobject attribute set,object attribute security,object attribute lock,object attribute bufferobject scripts set- Anything else under
ExecuteUda/ExecuteAttribute/ExecuteExtension/ExecuteScriptthat mutates without an explicit Save+CheckIn.
Recommended fix
Two options, in order of preference:
Option A — wrap each mutation in atomic CheckOut + Save + CheckIn
The dispatcher takes responsibility for the lifecycle:
case "add":
obj.CheckOut();
try
{
obj.AddUDA(
Arg(args, "uda"),
EnumValue<MxDataType>(Arg(args, "data-type")),
UdaCategory(Arg(args, "category")),
EnumValue<MxSecurityClassification>(Arg(args, "security")),
BoolArg(args, "is-array"),
IntArg(args, "array-count", 0));
obj.Save();
obj.CheckIn(string.Empty);
}
catch
{
try { obj.UndoCheckOut(); } catch { /* best effort */ }
throw;
}
return CommandSummary(obj, "Add UDA");
This makes each object uda add self-contained — no objects checkout
required from the caller. Mirrors the GUI's Edit→Save→Check-in flow.
Downside: breaks the "do many edits, then one CheckIn" batch
pattern that the existing objects checkout + objects checkin
commands suggest is supported.
Option B — keep the batch model, add Save only
The dispatcher keeps the explicit-CheckOut-and-CheckIn workflow but
calls Save() after each mutation so the change is persisted even
within an open checkout:
case "add":
obj.AddUDA(...);
obj.Save();
return CommandSummary(obj, "Add UDA");
Caller is still expected to do objects checkout once, run all the
mutations, then objects checkin. The phantom-checkout symptom goes
away on process exit because the explicit objects checkin always
runs the CheckIn. Downside: the "first AddUDA OK then second
fails" pattern means obj.Save() mid-checkout might itself release
the checkout — needs verification against the live GRAccess.
I recommend Option A for object uda add and the other
single-shot mutation commands, and keeping the explicit
objects checkout / objects checkin for callers that genuinely want
the batch model. That way graccess object uda add ... "just works"
in a script without a checkout dance.
Acceptance criteria (re-stated)
The script in the original "Acceptance criteria" section below must
run end-to-end without phantom-checkout failures. Repeat-runs (delete
the sandbox, re-derive, re-add UDAs) must produce identical results.
A object snapshot --llm-json after the AddUDA must include the new
UDA in AttributeValues (or wherever the dispatcher surfaces them in
its snapshot).
✅ Default-value fixes (2026-04-30)
The two bad-default complaints from the 2026-04-29 doc are still worth tracking — please verify these in the same fix:
--category default for object uda add
Currently MxCategoryWriteable_C, which is not in the
MxAttributeCategory enum. Valid members:
MxCategoryWriteable_U
MxCategoryWriteable_S
MxCategoryWriteable_US
MxCategoryWriteable_UC
MxCategoryWriteable_USC ← recommended new default
MxCategoryWriteable_UC_Lockable
MxCategoryWriteable_USC_Lockable
MxCategoryWriteable_C_Lockable
--force-option default for template delete
Currently galaxy_DeleteIfNoInstances, which is not in the
EForceDeleteTemplateOption enum. Valid members:
dontForceTemplateDelete ← recommended new default
cascadeDeleteDontUndeploy
🚿 Helper process leak (lower priority)
Each CLI invocation spawns a GRAccessApp.exe helper that survives
the CLI process. After 12+ invocations during a single rig-setup
session there were 12 stale helpers consuming memory. They don't
appear to cause bugs (the phantom checkout persists even after they
are killed), but they do leak.
The CLI should Marshal.ReleaseComObject / Marshal.FinalReleaseComObject
the GRAccess COM root on exit, which should let the helper terminate.
Acceptance script
Repeated from the 2026-04-29 doc — this script must run end-to-end on
this dev box's live ZB galaxy after both the typelib + lifecycle
fixes are in:
$cli = "C:\Users\dohertj2\Desktop\graccess\graccess_cli\src\ZB.MOM.WW.GRAccess.Cli\bin\x86\Debug\net48\ZB.MOM.WW.GRAccess.Cli.exe"
# 1. Derive sandbox template from $UserDefined
& $cli template derive --node localhost --galaxy ZB `
--name '$UserDefined' --new-name '$OtOpcUaParityTest' `
--confirm --confirm-target '$UserDefined'
# 2. Add four UDAs covering the parity matrix's write classifications
# (Option A: each call is self-contained — no separate checkout/checkin)
& $cli object uda add --node localhost --galaxy ZB `
--type template --name '$OtOpcUaParityTest' `
--uda OperateValue --data-type MxFloat `
--category MxCategoryWriteable_USC --security MxSecurityOperate `
--confirm --confirm-target '$OtOpcUaParityTest'
& $cli object uda add --node localhost --galaxy ZB `
--type template --name '$OtOpcUaParityTest' `
--uda TuneValue --data-type MxFloat `
--category MxCategoryWriteable_USC --security MxSecurityTune `
--confirm --confirm-target '$OtOpcUaParityTest'
& $cli object uda add --node localhost --galaxy ZB `
--type template --name '$OtOpcUaParityTest' `
--uda ConfigValue --data-type MxFloat `
--category MxCategoryWriteable_C_Lockable --security MxSecurityConfigure `
--confirm --confirm-target '$OtOpcUaParityTest'
& $cli object uda add --node localhost --galaxy ZB `
--type template --name '$OtOpcUaParityTest' `
--uda Counter --data-type MxInteger `
--category MxCategoryWriteable_USC --security MxSecurityFreeAccess `
--confirm --confirm-target '$OtOpcUaParityTest'
# 3. Add an analog-limit alarm extension on Counter and a history extension
# on OperateValue
& $cli object extension add --node localhost --galaxy ZB `
--type template --name '$OtOpcUaParityTest' `
--extension-type AnalogLimitAlarm --primitive Counter `
--object-extension `
--confirm --confirm-target '$OtOpcUaParityTest'
& $cli object extension add --node localhost --galaxy ZB `
--type template --name '$OtOpcUaParityTest' `
--extension-type HistoryExtension --primitive OperateValue `
--object-extension `
--confirm --confirm-target '$OtOpcUaParityTest'
# 4. Verify state — must show all 4 UDAs and both extensions
& $cli object snapshot --node localhost --galaxy ZB `
--name '$OtOpcUaParityTest' --llm-json
# 5. Instantiate, assign, deploy
& $cli template instantiate --node localhost --galaxy ZB `
--name '$OtOpcUaParityTest' --new-name 'OtOpcUaParityTest_001' `
--confirm --confirm-target '$OtOpcUaParityTest'
& $cli instance assign-area --node localhost --galaxy ZB `
--name 'OtOpcUaParityTest_001' --area 'DEV' `
--confirm --confirm-target 'OtOpcUaParityTest_001'
& $cli instance assign-engine --node localhost --galaxy ZB `
--name 'OtOpcUaParityTest_001' --engine 'DevAppEngine' `
--confirm --confirm-target 'OtOpcUaParityTest_001'
& $cli instance deploy --node localhost --galaxy ZB `
--name 'OtOpcUaParityTest_001' `
--confirm --confirm-target 'OtOpcUaParityTest_001'
# 6. Cleanup (verify the delete path too)
& $cli instance delete --node localhost --galaxy ZB `
--name 'OtOpcUaParityTest_001' `
--confirm --confirm-target 'OtOpcUaParityTest_001'
& $cli template delete --node localhost --galaxy ZB `
--name '$OtOpcUaParityTest' `
--force-option dontForceTemplateDelete `
--confirm --confirm-target '$OtOpcUaParityTest'
Pass criteria:
- Every command exits with status 0.
- Step 4's snapshot shows
OperateValue,TuneValue,ConfigValue,CounterinAttributeValues, and the two extensions inExtensions(or wherever the dispatcher surfaces them). - Step 5's deploy succeeds and the instance is reachable from MxAccess
(verifiable via the lmxopcua parity tests, or a manual
aaWindowViewerbrowse). - Repeat the script — second run after cleanup must produce the same outputs (idempotency).
Verification environment
- Windows 10, dev box
DESKTOP-6JL3KKO - ArchestrA System Platform installed with live
ZBgalaxy (single deployed$WinPlatformnamedDevPlatform, engineDevAppEngine, areaDEV) OtOpcUaGalaxyHostWindows service running. Stop it before deploys if MxAccess sessions hold the platform; otherwise leave it running.- graccess-cli x86 build at the path above.
Consumer of this fix
The lmxopcua repo's parity rig
(docs/v2/Galaxy.ParityRig.md in the lmxopcua repo, branch
v2-mxgw-integration) wants to provision the sandbox from a script so
the seven scenario classes in Driver.Galaxy.ParityTests exercise
real attributes instead of skipping. The 17-test parity matrix is the
gate for retiring the legacy Galaxy.Host backend. Fixing the mutation
lifecycle here unblocks that workflow on every parity rig (dev box +
customer rigs) without requiring GUI clicks.