Draft
Conversation
Shaped pitch for acs-i3x: a fully i3X-compliant northbound REST/SSE API for ACS that translates i3X queries into Factory+ service calls. Includes data model mapping, architecture, rabbit hole patches, and a TID tracking known spec deviations and limitations.
Covers project structure, dependencies, core components (object tree, value cache, history, subscriptions, mapping, quality), endpoint mapping, response envelope, auth approach, env vars, and test strategy.
13-task TDD implementation plan covering: scaffold, types, mapping, quality, envelope middleware, object tree, value cache, history, subscriptions, API router, entry point, build verification, and end-to-end compliance tests.
… import jest globals in ESM
Wire ObjectTree, ValueCache, History, and SubscriptionManager behind Express routes with i3X envelope middleware. Includes readiness check (503), error handling, bulk query endpoints, and SSE stream delegation. Install express and supertest as runtime and dev dependencies.
…etadata to ObjectTree
- Deployment + Service (Kerberos client+server, MQTT, InfluxDB, HTTP) - Traefik IngressRoute for external HTTPS access - Kerberos principals: sv1i3x (client) and HTTP/i3x (server) - values.yaml: i3x section with enabled flag, image, logLevel - Namespace URI defaults to https://<baseUrl>/i3x
New ServiceRole (I3X.Requirement.ServiceRole) grants: - ConfigDB read for Registration, ConfigSchema, and Info apps - ConfigDB class member and subclass listing - Directory device links, alerts, and relationships - Directory service advertisement for i3X - UNS MQTT read/subscribe (inherited from UNS.Group.Reader) Replaces the incorrect Historian group assignment.
When DEV_NO_AUTH=true, all endpoints are unauthenticated (no Kerberos keytab required). Updated .env.example with local dev defaults.
- Info endpoint now at /info within infoRoute sub-router (was /) - Bulk endpoints bypass envelope middleware to avoid double-wrapping - Added rx-util and preserve-symlinks for local dev - Tests need updating to match (23 failures, will fix next session)
…tions - infoRoute now returns raw JSON (no envelope) per i3X spec - Bulk endpoints bypass envelope via _originalJson - Non-bulk endpoints wrapped once by envelope middleware - All 228 tests pass
Sub-objects from UNS messages use Instance_UUIDs for parent links, but device objects use ConfigDB UUIDs as elementIds. Added lazy auto-detection that maps the device Instance_UUID to its ConfigDB UUID by matching on schema type. Fixes broken parent-child nesting in the i3X Explorer.
Previously the object tree only went as deep as the InstanceUUIDPath (schema containers with Instance_UUIDs). Now every metric path segment becomes an object in the tree, all the way down to the leaf tag. Instance_UUIDs are used where available from the InstanceUUIDPath. For segments without Instance_UUIDs (deeper than the schema containers), deterministic v5 UUIDs are synthesised from parent UUID + segment name. Leaf metrics (final segment) have isComposition: false.
Match any unmatched root device object instead of matching on schema type (ConfigDB class != Sparkplug schema UUID). Fixes broken parent chain where Axes had device Instance_UUID as parent instead of ConfigDB UUID.
The device Instance_UUID to ConfigDB UUID mapping is permanent once learned. Clearing it on refresh caused a race where UNS messages arrived before loadDevices completed, creating orphaned composition objects with broken parent chains.
The reference server at api.i3x.dev uses parentId '/' for root objects, not null. The i3X Explorer builds the Hierarchy tree by looking for objects with parentId '/'. Fixes 'No root objects found' in Explorer.
Logs each init step (ServiceClient, ObjectTree, ValueCache), ConfigDB queries (class members, registration, schemas, device info), and MQTT connection events. Helps diagnose hangs when connecting to different ACS deployments.
Instead of using Registration app class (Sparkplug Device) as typeElementId, now reads DeviceInformation app config for each device at startup: - config.schema → typeElementId (the actual device schema) - config.originMap.Instance_UUID → Instance→ConfigDB UUID mapping - ISA95_Hierarchy (found by searching for Hierarchy-v1 Schema_UUID) → Enterprise/Site/Area/WorkCenter/WorkUnit hierarchy Devices are placed under ISA-95 hierarchy at startup, not just when UNS messages arrive. Devices without ISA-95 Enterprise stay at root.
Recursively walks each device's originMap to create the complete object hierarchy (containers + leaf metrics) at startup. No longer dependent on UNS messages for the structure — offline devices show their full metric tree. - Keys with Sparkplug_Type and no children → leaf objects - Keys with child containers → composition objects - Instance_UUID used where available, v5 synthesised otherwise - Schema_UUIDs collected to create ObjectTypes for all schemas - Plain value fields (no Sparkplug_Type, no children) are skipped
Update test mocks to match the refactored History class which now uses getMetricMeta/getInstanceUuid from ObjectTree instead of elementId string parsing, and getCurrentValue/getCompositionValue instead of valueCache.getValue for current value lookups.
Current values now come from InfluxDB (sparkplug/default bucket) using last() queries instead of the in-memory UNS MQTT cache. This means: - Values available for ALL devices with historian data, not just those publishing to UNS - Consistent data source for both current values and history - MetricMeta stored per leaf object during tree building (topLevelInstance, metricPath, metricName, sparkplugType/typeSuffix) - Composition values assembled from descendant leaf queries UNS MQTT cache retained only for SSE streaming subscriptions (TID L3).
Current value queries now check the UNS MQTT cache first for real-time data. If the cache has a value (device is publishing to UNS), it's returned immediately — no InfluxDB round-trip, no 10s flush delay. If the cache misses (device not on UNS, or no data yet), falls back to InfluxDB last() query from the sparkplug bucket. Same UNS MQTT connection continues to feed SSE streaming subscriptions.
Logs whether current values come from UNS cache (with age) or InfluxDB. Logs subscription registration, stream open/close, and each SSE event write. Logs UNS cache updates and listener notifications.
Return empty array for composition objects instead of querying all child metrics mixed together. Only leaf metrics (with MetricMeta) return history. Matches the reference implementation behaviour.
Shaped pitch for embedding i3X hierarchy browsing, node inspection, relationship graph, history charts, and live monitoring into the acs-admin Vue UI. Big batch, 6-week appetite.
Detailed component architecture, data flow, and implementation design for the Explorer feature in acs-admin. Covers hierarchy tree, relationship graph (Cytoscape.js), history charts (ECharts), current value display, and monitored items with SSE subscriptions.
Detailed step-by-step plan covering: dependency setup, API client, stores, page shell, tree, sidebar, current value, relationship graph, history charts, monitor store, SSE, and navbar integration.
Connect RelationshipGraph, CurrentValue, and HistoryPanel into the Explorer page main panel. Add MonitorButton (navbar, red badge) and MonitorDialog (Sheet with cards, sparklines, unsubscribe). Wire beforeunload cleanup for active subscriptions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the acs-i3x service and an i3X Explorer page to acs-admin. This is ACS's first implementation of the i3X information model interface (spec v0.1.0).
acs-i3x service (
acs-i3x/)New Express/TypeScript service exposing i3X v0.1.0 endpoints at
/v1/:Builds the i3X object hierarchy from ISA-95 structure in DeviceInformation originMaps. Deployed via Helm alongside existing ACS services.
graph TB Client["i3X Client<br/>(Explorer, etc.)"] subgraph acs-i3x["acs-i3x service"] OT["ObjectTree"] VC["ValueCache"] HI["History"] SM["SubscriptionMgr"] end ConfigDB["ConfigDB"] MQTT["MQTT Broker<br/>UNS/v1/#"] InfluxDB["InfluxDB"] Client -->|"REST / SSE"| acs-i3x OT -->|"startup"| ConfigDB VC -->|"runtime"| MQTT HI -->|"on request"| InfluxDB SM -->|"runtime"| MQTTCurrent values use a hybrid strategy: UNS cache (real-time, sub-second) with InfluxDB last() as fallback (~10s delayed). History queries go directly to InfluxDB via Flux.
i3X Explorer in acs-admin (
acs-admin/)New
/explorerpage with a three-panel layout:New packages:
cytoscape,echarts,vue-echarts,@microsoft/fetch-event-source(all lazy-loaded).Still To Do
I3X_DISABLE_REFRESHis set)Test Plan
/#/explorer, verify hierarchy loads from acs-i3x