# Galaxy Driver — Galaxy Repository Requirements > **Revision** — Refreshed 2026-04-19 for the OtOpcUa v2 multi-driver platform (task #205). Scope clarified: this document is **Galaxy-driver-specific**. Galaxy is one of seven drivers in the OtOpcUa platform; the requirements below describe the SQL-side of the Galaxy driver (hierarchy/attribute/change-detection queries against the ZB database) that backs the Galaxy driver's `ITagDiscovery.DiscoverAsync` and `IRediscoverable` implementations. All Galaxy-specific SQL runs inside `OtOpcUa.Galaxy.Host` (.NET 4.8 x86 Windows service); the in-server `Driver.Galaxy.Proxy` calls it over a named pipe. For platform-wide tag discovery requirements see `OpcUaServerReqs.md` OPC-002. For deeper spec see `docs/GalaxyRepository.md` and `docs/v2/driver-specs.md`. Parent: [HLR-002](HighLevelReqs.md#hlr-002-multi-driver-plug-in-model), [HLR-003](HighLevelReqs.md#hlr-003-address-space-composition-per-namespace), [HLR-006](HighLevelReqs.md#hlr-006-change-detection-and-rediscovery) Driver scope: Galaxy only. Namespace kind: `SystemPlatform`. ## GR-001: Hierarchy Extraction The Galaxy driver's `ITagDiscovery.DiscoverAsync` implementation shall query the ZB Galaxy Repository database to extract all deployed objects with their parent-child containment relationships, contained names, and tag names. ### Acceptance Criteria - Executes `queries/hierarchy.sql` against the ZB database from within `OtOpcUa.Galaxy.Host`. - Returns a list of objects with: `gobject_id`, `tag_name`, `contained_name`, `browse_name`, `parent_gobject_id`, `is_area`. - Objects with `parent_gobject_id = 0` become children of the root ZB node inside the `SystemPlatform` namespace. - Only deployed, non-template objects matching the category filter (areas, engines, user-defined objects, etc.) are returned. - Query completes within 10 seconds on a typical Galaxy (hundreds of objects). Log Warning if it takes longer. ### Details - Results are ordered by `parent_gobject_id, tag_name` for deterministic tree building. - Empty result → Warning logged (Galaxy may have no deployed objects, or the DB connection may be misconfigured). - Orphan detection: a row referencing a non-existent `parent_gobject_id` (and not 0) is skipped with a Warning. - Streamed to the core via `IAddressSpaceBuilder.AddFolder` / `AddObject` calls over the Galaxy named pipe; no in-memory full-tree buffering on the Host side. --- ## GR-002: Attribute Extraction The Galaxy driver shall query user-defined (dynamic) attributes for deployed objects, including data type, array flag, and array dimensions. ### Acceptance Criteria - Executes `queries/attributes.sql` using the template chain CTE to resolve inherited attributes. - Returns: `gobject_id`, `tag_name`, `attribute_name`, `full_tag_reference`, `mx_data_type`, `is_array`, `array_dimension`, `security_classification`. - Attributes starting with `_` are filtered out by the query. - `array_dimension` is extracted from the `mx_value` hex bytes (positions 13-16, little-endian uint16). ### Details - CTE recursion depth is limited to 10 levels. - `mx_data_type` not in the known set (1-8, 13-16) defaults to String. - `gobject_id` that doesn't match a hierarchy object is skipped (object may not be deployed). - Each emitted attribute is reported via `DriverAttributeInfo` to the core through `IAddressSpaceBuilder.AddVariable`. --- ## GR-003: Change Detection and IRediscoverable The Galaxy driver shall implement `IRediscoverable` by polling `galaxy.time_of_last_deploy` on a configurable interval to detect when a new deployment has occurred. ### Acceptance Criteria - Polls `SELECT time_of_last_deploy FROM galaxy` at a configurable interval (`Galaxy:ChangeDetectionIntervalSeconds`, default 30 seconds). - Compares the returned timestamp to the last known value stored in memory. - If different, raises the `IRediscoverable.RediscoveryNeeded` signal so the core re-runs `ITagDiscovery.DiscoverAsync` and surgically rebuilds the Galaxy namespace subtree (per OPC-017). - First poll after startup always triggers an initial discovery. - Query failure → Warning logged; no rediscovery triggered; retry at next interval. ### Details - Polling runs on a background `Task` inside `OtOpcUa.Galaxy.Host`, not on the STA message-pump thread. - `time_of_last_deploy` is a `datetime` column; compared using exact equality (not a range). - Signal delivery to the Proxy happens via a server-push message on the Galaxy named pipe. --- ## GR-004: Rediscovery Data Flow On a deployment change, the Galaxy driver shall re-query hierarchy + attributes and stream the updated structure to the core for surgical namespace rebuild. ### Acceptance Criteria - On change signal, re-run `GR-001` (hierarchy) and `GR-002` (attributes) queries. - Stream the new tree to the core via `IAddressSpaceBuilder` over the named pipe. - Log at Information level: `"Galaxy deployment change detected. Rebuilding. ({ObjectCount} objects, {AttributeCount} attributes)"`. - Log total rediscovery duration at Information level. - On re-query failure: Error logged; existing Galaxy subtree is retained. ### Details - Rediscovery is not atomic from the DB perspective — hierarchy and attributes are two separate queries. Acceptable; Galaxy deployment is an infrequent operation. - The core owns the diff/surgical apply per OPC-017; the Galaxy driver only streams the new authoritative tree. --- ## GR-005: Connection Configuration Galaxy DB connection parameters shall be configurable via environment variables passed from the `OtOpcUa.Galaxy.Host` supervisor at spawn time. ### Acceptance Criteria - Connection string via `OTOPCUA_GALAXY_ZB_CONN` environment variable. - Default: `Server=localhost;Database=ZB;Integrated Security=True;TrustServerCertificate=True;Encrypt=False;` (Windows Auth). - ADO.NET `SqlConnection` used for queries (.NET Framework 4.8). - Connection is opened per-query (not kept open). Connection pooling handles efficiency. - If the initial connection test at startup fails, log Error with the connection string sanitized and continue attempting (change-detection polls keep retrying). ### Details - Command timeout: `Galaxy:CommandTimeoutSeconds` in Config DB driver JSON (default 30 seconds). - No ORM. Raw ADO.NET with `SqlCommand` and `SqlDataReader`. SQL text embedded as constants. --- ## GR-006: Query Safety All Galaxy SQL queries shall be static read-only SELECT statements. No writes to the Galaxy Repository database. ### Acceptance Criteria - All queries are hardcoded SQL strings with no string concatenation or user-supplied parameters. - No INSERT, UPDATE, DELETE, or DDL statements are ever executed against the Galaxy database. - Queries use only SELECT with read-only intent. --- ## GR-007: Startup Validation On startup, the Galaxy driver's DB component inside `OtOpcUa.Galaxy.Host` shall validate database connectivity. ### Acceptance Criteria - Execute a simple test query (`SELECT 1`) against the configured Galaxy DB. - If the database is unreachable, log Error but do not prevent Host startup. - The Galaxy driver runs in degraded mode (empty SystemPlatform namespace) until the database becomes available and the next change-detection poll succeeds. - In degraded mode the Galaxy driver instance reports `DriverHealth.Unavailable`, causing its Polly circuit state to be open until the first successful discovery. --- ## GR-008: Capability Wrapping All calls into the Galaxy DB component from the Proxy side shall route through `CapabilityInvoker.InvokeAsync(DriverCapability.Discover, …)`. ### Acceptance Criteria - `Driver.Galaxy.Proxy.DiscoverAsync` is a thin capability-invoker call that sends a MessagePack request over the named pipe to the Host's DB component. - Roslyn analyzer **OTOPCUA0001** validates there are no direct discovery calls bypassing the invoker. - Polly pipeline for `DriverCapability.Discover` on the Galaxy driver instance carries Timeout + Retry + CircuitBreaker.