# Parsing Template Attributes

This guide describes how to parse attributes for an existing GRAccess template such as `TestMachine`, including the settings families normally needed for template analysis: object properties, attribute metadata, history settings, I/O settings, alarm settings, and extension/UDA settings.

Run commands from `graccess_cli`. Examples assume an active session:

```powershell
graccess session start --galaxy ZB --node .
```

Without a session, add `--node .` to each command.

For LLM workflows, start with the stable snapshot envelope:

```powershell
graccess object snapshot --galaxy ZB --name TestMachine --type template --llm-json
```

Then use `object attribute value get --llm-json` for individual scalar value readback. The value command tries direct `IAttribute.Value` first and then the read-only package fallback.

## Attribute Sources

Use all three read paths when building a complete parse:

| Source | Command | Purpose |
|---|---|---|
| Object identity | `object get` | Template tagname, contained name, hierarchy, checkout status |
| All attributes | `object attributes` | Every attribute visible through `IgObject.Attributes` |
| Configurable attributes | `object attributes --configurable` | Attributes visible through `IgObject.ConfigurableAttributes` |
| Extended attributes | `object extended-attributes` | Inherited or hierarchy-expanded attributes from `GetExtendedAttributes` |
| One attribute | `object attribute get` | Metadata for a known attribute |
| One attribute value | `object attribute value get` | Scalar value readback through direct GRAccess or package fallback where supported |

Base commands:

```powershell
graccess object get --galaxy ZB --name TestMachine --type template --json
graccess object attributes --galaxy ZB --name TestMachine --type template --json
graccess object attributes --galaxy ZB --name TestMachine --type template --configurable --json
graccess object extended-attributes --galaxy ZB --name TestMachine --type template --json
```

## Current CLI Coverage

The current CLI exposes the stable `IAttribute` metadata listed below.

| JSON field | GRAccess API member | Notes |
|---|---|---|
| `Name` | `IAttribute.Name` | Attribute name |
| `DataType` | `IAttribute.DataType` | `MxDataType` value |
| `Category` | `IAttribute.AttributeCategory` | Attribute category |
| `SecurityClassification` | `IAttribute.SecurityClassification` | Security classification |
| `Locked` | `IAttribute.Locked` | Lock state |
| `UpperBoundDim1` | `IAttribute.UpperBoundDim1` | First array dimension upper bound |
| `HasBuffer` | `IAttribute.HasBuffer` | Attribute buffer flag |
| `RuntimeSetHandler` | `IAttribute.RtSethandler` | Runtime set handler flag |
| `ConfigSetHandler` | `IAttribute.CfgSethandler` | Configuration set handler flag |

The GRAccess API also exposes `IAttribute.Value`. The CLI serializes scalar values when the local COM object exposes a supported accessor, and falls back to a temporary exported package when direct readback is unavailable. Because many history, I/O, alarm, and script-related settings are stored as attribute values, strict value-level parsing should use these paths:

| Need | Best current path |
|---|---|
| Inventory every setting name and metadata | `object attributes`, `--configurable`, and `object extended-attributes` |
| Read a single setting metadata record | `object attribute get` |
| Read one scalar value | `object attribute value get --llm-json` |
| Preserve full vendor configuration, including values and scripts | `object snapshot --llm-json` package fallback, `objects export`, or `galaxy export-all` |
| Arrays or complex values | Treat as unavailable unless the snapshot/package parser emits a safe scalar representation |

Normal CLI parsing must not query the Galaxy SQL database for attribute values. SQL can be used only in development verification scripts to compare GRAccess/package output against repository facts.

## Parse All Attributes

Capture all attribute lists before classifying them:

```powershell
$name = 'TestMachine'
$out = '.\template-snapshots'
New-Item -ItemType Directory -Force -Path $out | Out-Null

graccess object attributes --galaxy ZB --name $name --type template --json `
  | Set-Content "$out\$name.attributes.json"

graccess object attributes --galaxy ZB --name $name --type template --configurable --json `
  | Set-Content "$out\$name.configurable-attributes.json"

graccess object extended-attributes --galaxy ZB --name $name --type template --json `
  | Set-Content "$out\$name.extended-attributes.json"
```

Load the snapshot in PowerShell:

```powershell
$attrs = Get-Content '.\template-snapshots\TestMachine.attributes.json' -Raw | ConvertFrom-Json
$configurable = Get-Content '.\template-snapshots\TestMachine.configurable-attributes.json' -Raw | ConvertFrom-Json
$extended = Get-Content '.\template-snapshots\TestMachine.extended-attributes.json' -Raw | ConvertFrom-Json
```

Merge and de-duplicate by attribute name:

```powershell
$all = @($attrs) + @($configurable) + @($extended)
$byName = $all | Sort-Object Name -Unique
$byName | Select-Object Name, DataType, Category, Locked, HasBuffer
```

## Parse Object Properties

Object-level properties are not the same as attributes. The current `object get` output gives identity and checkout information:

```powershell
graccess object get --galaxy ZB --name TestMachine --type template --json
```

`graccess_operations.md` lists additional GRAccess object properties that exist on `ITemplate` and `IInstance`, including `DerivedFrom`, `BasedOn`, `Category`, `CategoryGUID`, `Container`, `Area`, `Host`, `Toolset`, `ConfigVersion`, `CheckedOutBy`, `EditStatus`, `ValidationStatus`, `Errors`, and `Warnings`.

The current CLI does not emit every one of those properties in `object get`. If a parse requires all object properties, extend `GRAccessCommandDispatcher.ObjectDetails(...)` to read them defensively with the same `Try(...)` pattern used for current COM-backed fields.

## Parse History Settings

History settings are commonly represented as attributes or extended attributes. To parse them:

1. Capture all attributes and extended attributes.
2. Find setting names related to history or historian configuration.
3. Preserve metadata for each matching attribute.
4. Use object export or a future value-emitting CLI command when actual setting values are required.

PowerShell classification:

```powershell
$history = $byName | Where-Object {
  $_.Name -match '(?i)hist|history|historian|storage|trend'
}

$history | Sort-Object Name | Select-Object Name, DataType, Category, Locked, HasBuffer
```

This is intentionally name-driven because exact attribute names vary by template type, System Platform version, primitive, and extension package.

## Parse I/O Settings

I/O settings can appear as object-level assignment properties, attributes, extension attributes, or exported package content. Parse them in this order:

1. `object get` for identity and hierarchy.
2. `object attributes` and `object extended-attributes` for setting names and metadata.
3. Query relationships such as host, containment, and area when relevant.
4. Use export for full value-level source/destination details.

PowerShell classification:

```powershell
$io = $byName | Where-Object {
  $_.Name -match '(?i)\bio\b|input|output|source|destination|scan|topic|device|address|reference'
}

$io | Sort-Object Name | Select-Object Name, DataType, Category, Locked, RuntimeSetHandler, ConfigSetHandler
```

Relationship queries that often help with I/O context:

```powershell
graccess object query-condition --galaxy ZB --type all --condition containedBy --value TestMachine --json
graccess object query-condition --galaxy ZB --type all --condition assignedTo --value TestMachine --json
graccess object query-condition --galaxy ZB --type all --condition hostEngineIs --value TestMachine --json
```

## Parse Alarm Settings

Alarm settings are usually represented as attributes and extension attributes. Capture all attribute sources, then classify by alarm-related names:

```powershell
$alarm = $byName | Where-Object {
  $_.Name -match '(?i)alarm|alert|limit|priority|severity|deadband|deviation|rate|roc|hihi|lolo|(^|[._])hi($|[._])|(^|[._])lo($|[._])|ack'
}

$alarm | Sort-Object Name | Select-Object Name, DataType, Category, SecurityClassification, Locked
```

For value-level alarm settings, use `objects export` until the CLI emits `IAttribute.Value`.

## Parse UDAs And Extensions

User-defined attributes are included in the attribute collections. Extension primitives normally show up through extended attributes, object export, or extension-specific attributes.

Recommended read-only capture:

```powershell
graccess object attributes --galaxy ZB --name TestMachine --type template --json
graccess object extended-attributes --galaxy ZB --name TestMachine --type template --json
```

The CLI currently has mutation commands for UDA and extension management, but it does not have a dedicated read-only `object uda list` or `object extension list` command. For complete extension parsing, prefer export or add dedicated list commands that call the GRAccess object/extension APIs if available in the local COM assembly.

## Full Attribute Snapshot Script

This script creates a structured local parse folder and classifies likely setting families:

```powershell
$galaxy = 'ZB'
$name = 'TestMachine'
$type = 'template'
$out = ".\template-snapshots\$name"
New-Item -ItemType Directory -Force -Path $out | Out-Null

graccess object get --galaxy $galaxy --name $name --type $type --json `
  | Set-Content "$out\object.json"

graccess object attributes --galaxy $galaxy --name $name --type $type --json `
  | Set-Content "$out\attributes.json"

graccess object attributes --galaxy $galaxy --name $name --type $type --configurable --json `
  | Set-Content "$out\configurable-attributes.json"

graccess object extended-attributes --galaxy $galaxy --name $name --type $type --json `
  | Set-Content "$out\extended-attributes.json"

$all = @(
  Get-Content "$out\attributes.json" -Raw | ConvertFrom-Json
) + @(
  Get-Content "$out\configurable-attributes.json" -Raw | ConvertFrom-Json
) + @(
  Get-Content "$out\extended-attributes.json" -Raw | ConvertFrom-Json
)

$byName = $all | Sort-Object Name -Unique
$byName | ConvertTo-Json -Depth 5 | Set-Content "$out\all-attributes.unique.json"

$groups = [ordered]@{
  history = @($byName | Where-Object { $_.Name -match '(?i)hist|history|historian|storage|trend' })
  io = @($byName | Where-Object { $_.Name -match '(?i)\bio\b|input|output|source|destination|scan|topic|device|address|reference' })
  alarm = @($byName | Where-Object { $_.Name -match '(?i)alarm|alert|limit|priority|severity|deadband|deviation|rate|roc|hihi|lolo|(^|[._])hi($|[._])|(^|[._])lo($|[._])|ack' })
  script = @($byName | Where-Object { $_.Name -match '(?i)script|execute|trigger|expression|declaration|startup|shutdown' })
}

$groups | ConvertTo-Json -Depth 8 | Set-Content "$out\attribute-groups.json"
```

## CLI Gap For Complete Attribute Values

To make `graccess_cli` parse all attribute settings without relying on export files, add a read-only command or extend `object attributes` to include safe value serialization:

| Proposed field | Source |
|---|---|
| `Value` | `IAttribute.Value` converted from `IMxValue` |
| `IsArray` | Derived from bounds and value shape |
| `Dimensions` | `UpperBoundDim1` and any additional dimensions exposed by local API |
| `CommandResult` | `IAttribute.CommandResult` after value reads where relevant |
| `UnavailableReason` | Exception message when a COM-backed field cannot be read |

Keep value reads defensive. Some attributes may throw because storage is unavailable, the value is runtime-only, the datatype is not serializable, or the current login cannot read the field.
