Files
mxaccessgw/docs/audit/fragments/08-galaxy.md
T

24 KiB
Raw Blame History

Cluster 08 — Galaxy Repository

Audited doc: docs/GalaxyRepository.md Verified against: src/ZB.MOM.WW.MxGateway.Server/Galaxy/**, src/ZB.MOM.WW.MxGateway.Contracts/Protos/galaxy_repository.proto Date: 2026-06-03


DOC: docs/GalaxyRepository.md LINES: 34 CLAIM: The SQL Server database is named ZB. CLAIM_TYPE: config-key VERDICT: accurate EVIDENCE: GalaxyRepositoryOptions.cs:17 (DefaultConnectionString = "Server=localhost;Database=ZB;...") CODE_AREA: gr.conn SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 34 CLAIM: The database is a SQL Server database. CLAIM_TYPE: config-key VERDICT: accurate EVIDENCE: GalaxyRepository.cs:1 (using Microsoft.Data.SqlClient;); GalaxyRepositoryOptions.cs:17 CODE_AREA: gr.conn SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 3031 CLAIM: The service is defined in src/ZB.MOM.WW.MxGateway.Contracts/Protos/galaxy_repository.proto under package galaxy_repository.v1. CLAIM_TYPE: path VERDICT: accurate EVIDENCE: galaxy_repository.proto:3 (package galaxy_repository.v1;) CODE_AREA: gr.proto SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 3539 CLAIM: TestConnection returns { ok: bool } after a SELECT 1. Does not throw on SQL failure — returns ok = false. CLAIM_TYPE: behavior-rule VERDICT: accurate EVIDENCE: GalaxyRepository.cs:2032 (catches SqlException and InvalidOperationException, returns false); galaxy_repository.proto:4345 (TestConnectionReply { bool ok = 1; }) CODE_AREA: gr.proto SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 36 CLAIM: GetLastDeployTime returns the cached galaxy.time_of_last_deploy. Served from the shared hierarchy cache; refreshed in the background. CLAIM_TYPE: behavior-rule VERDICT: wrong EVIDENCE: GalaxyRepositoryGrpcService.cs:4262 — GetLastDeployTime calls WaitForCacheBootstrap then reads cache.Current, not repository directly. The underlying SQL is SELECT time_of_last_deploy FROM galaxy (GalaxyRepository.cs:40) but it is served from cache, not direct SQL. The doc correctly says "served from cache" in the inline column. However the inline description says "Served from the shared hierarchy cache; refreshed in the background" which is accurate for the RPC handler — but the SQL column itself (galaxy.time_of_last_deploy) is an internal SQL column name, not a table.column phrasing. No actual error; accurate. CODE_AREA: gr.sql SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 3839 CLAIM: WatchDeployEvents is server-streaming. The server emits the current state immediately on subscribe. CLAIM_TYPE: behavior-rule VERDICT: accurate EVIDENCE: galaxy_repository.proto:33 (rpc WatchDeployEvents ... returns (stream DeployEvent)); GalaxyDeployNotifier.cs:5863 (bootstrap emit on subscribe) CODE_AREA: gr.proto SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 39 CLAIM: BrowseChildren returns the direct children of one parent object (or root objects when parent is unset). Includes a per-child has_children hint so UIs can draw expand triangles without an extra round trip. Served from cache. CLAIM_TYPE: behavior-rule VERDICT: accurate EVIDENCE: galaxy_repository.proto:175190 (BrowseChildrenReply with child_has_children repeated bool); GalaxyRepositoryGrpcService.cs:112168 CODE_AREA: gr.proto SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 4243 CLAIM: The server defaults omitted page size to 1000 objects and caps every page at 5000 objects (for DiscoverHierarchy). CLAIM_TYPE: behavior-rule VERDICT: accurate EVIDENCE: GalaxyRepositoryGrpcService.cs:2728 (DefaultDiscoverPageSize = 1000, MaxDiscoverPageSize = 5000) CODE_AREA: gr.proto SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 8386 CLAIM: BrowseChildren default page size is 500; the server caps any requested size at 5000. Page tokens encode (cache_sequence, parent_id, filter_signature, offset). CLAIM_TYPE: behavior-rule VERDICT: wrong EVIDENCE: GalaxyRepositoryGrpcService.cs:29 (DefaultBrowsePageSize = 500) — default is accurate. Cap of 5000 is accurate (comment "MaxBrowsePageSize reuses MaxDiscoverPageSize (5000)"). However the token encoding claim is inaccurate: the actual token format is sequence:filterSignature:offset (GalaxyRepositoryGrpcService.cs:295302, FormatPageToken). parent_id is embedded inside filterSignature as a component (GalaxyBrowseProjector.cs:266 builder.Append("parent=").Append(parentId...)) — it is NOT a separate named field in the token. Describing it as (cache_sequence, parent_id, filter_signature, offset) implies four independent fields; the wire encoding has three fields with parent_id folded into the signature hash. CODE_AREA: gr.proto SEVERITY: medium PROPOSED_FIX: Change "Page tokens encode (cache_sequence, parent_id, filter_signature, offset)" to "Page tokens encode sequence:filterSignature:offset; parent_id is incorporated into filterSignature along with the other filter parameters."


DOC: docs/GalaxyRepository.md LINES: 9798 CLAIM: Missing metadata:read scope returns PermissionDenied. CLAIM_TYPE: behavior-rule VERDICT: accurate EVIDENCE: GatewayGrpcScopeResolver.cs:2327 (all five Galaxy request types map to GatewayScopes.MetadataRead); GatewayScopes.cs:11 CODE_AREA: gr.proto SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 118119 CLAIM: GalaxyHierarchyRefreshService ticks every MxGateway:Galaxy:DashboardRefreshIntervalSeconds seconds (default 30). CLAIM_TYPE: config-key VERDICT: accurate EVIDENCE: GalaxyRepositoryOptions.cs:2829 (DashboardRefreshIntervalSeconds { get; init; } = 30); GalaxyHierarchyRefreshService.cs:18 (TimeSpan.FromSeconds(Math.Max(1, options.Value.DashboardRefreshIntervalSeconds))) CODE_AREA: gr.conn SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 120 CLAIM: Each tick queries the cheap SELECT time_of_last_deploy FROM galaxy first. CLAIM_TYPE: behavior-rule VERDICT: accurate EVIDENCE: GalaxyRepository.cs:40 ("SELECT time_of_last_deploy FROM galaxy"); GalaxyHierarchyCache.cs:117 (GetLastDeployTimeAsync called first before deciding whether to run heavy queries) CODE_AREA: gr.sql SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 150152 CLAIM: The snapshot file is written atomically — a temp file plus rename — so a crash mid-write cannot corrupt the snapshot. CLAIM_TYPE: behavior-rule VERDICT: accurate EVIDENCE: GalaxyHierarchySnapshotStore.cs:7481 (writes to _path + ".tmp" then File.Move(..., overwrite: true)) CODE_AREA: gr.conn SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 178179 CLAIM: GalaxyDeployNotifier maintains a private bounded channel per subscriber. The bound is 16 events with DropOldest. CLAIM_TYPE: behavior-rule VERDICT: accurate EVIDENCE: GalaxyDeployNotifier.cs:18 (SubscriberQueueCapacity = 16); GalaxyDeployNotifier.cs:4953 (BoundedChannelOptions with FullMode = BoundedChannelFullMode.DropOldest) CODE_AREA: gr.proto SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 386387 CLAIM: Default connection string is Server=localhost;Database=ZB;Integrated Security=True;TrustServerCertificate=True;Encrypt=False; CLAIM_TYPE: config-key VERDICT: accurate EVIDENCE: GalaxyRepositoryOptions.cs:17 (exact match) CODE_AREA: gr.conn SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 387 CLAIM: MxGateway:Galaxy:CommandTimeoutSeconds default is 60. Applies to all three RPCs. CLAIM_TYPE: config-key VERDICT: wrong EVIDENCE: GalaxyRepositoryOptions.cs:22 (CommandTimeoutSeconds { get; init; } = 60) — default is accurate. However "Applies to all three RPCs" is stale: there are five RPCs (TestConnection, GetLastDeployTime, DiscoverHierarchy, WatchDeployEvents, BrowseChildren), not three. CommandTimeoutSeconds applies to the SQL commands in GalaxyRepository.cs which backs TestConnection, GetLastDeployTime, GetHierarchyAsync, and GetAttributesAsync. The doc says "all three RPCs" presumably counting only the original three before BrowseChildren was added. CODE_AREA: gr.conn SEVERITY: medium PROPOSED_FIX: Change "Applies to all three RPCs" to "Applies to all SQL commands issued by the repository (used by TestConnection, GetLastDeployTime, and the hierarchy/attributes queries backing DiscoverHierarchy and BrowseChildren)."


DOC: docs/GalaxyRepository.md LINES: 388389 CLAIM: MxGateway:Galaxy:PersistSnapshot default is true. CLAIM_TYPE: config-key VERDICT: accurate EVIDENCE: GalaxyRepositoryOptions.cs:40 (PersistSnapshot { get; init; } = true) CODE_AREA: gr.conn SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 389390 CLAIM: MxGateway:Galaxy:SnapshotCachePath default is C:\ProgramData\MxGateway\galaxy-snapshot.json. CLAIM_TYPE: config-key VERDICT: accurate EVIDENCE: GalaxyRepositoryOptions.cs:3233 (DefaultSnapshotCachePath = @"C:\ProgramData\MxGateway\galaxy-snapshot.json") CODE_AREA: gr.conn SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 403404 CLAIM: "All four Galaxy RPCs (including WatchDeployEvents) require the metadata:read API-key scope." CLAIM_TYPE: rpc/proto VERDICT: wrong EVIDENCE: GatewayGrpcScopeResolver.cs:2327 — all five Galaxy RPCs require metadata:read: TestConnectionRequest, GetLastDeployTimeRequest, DiscoverHierarchyRequest, WatchDeployEventsRequest, and BrowseChildrenRequest. The service has five RPCs (galaxy_repository.proto:2139), not four. BrowseChildren was added after the original four but the authorization section was not updated. CODE_AREA: gr.proto SEVERITY: high PROPOSED_FIX: Change "All four Galaxy RPCs" to "All five Galaxy RPCs" (or explicitly list all five: TestConnection, GetLastDeployTime, DiscoverHierarchy, WatchDeployEvents, BrowseChildren).


DOC: docs/GalaxyRepository.md LINES: 378 CLAIM: "GalaxyRepositoryGrpcService (src/ZB.MOM.WW.MxGateway.Server/Grpc/GalaxyRepositoryGrpcService.cs) implements the five RPCs." CLAIM_TYPE: path VERDICT: accurate EVIDENCE: GalaxyRepositoryGrpcService.cs (file exists at that path); implements all five overrides: TestConnection, GetLastDeployTime, DiscoverHierarchy, WatchDeployEvents, BrowseChildren CODE_AREA: gr.proto SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 327 CLAIM: Architecture diagram shows DiscoverHierarchy, GetLastDeployTime, BrowseChildren -> IGalaxyHierarchyCache.Current (WatchDeployEvents -> IGalaxyDeployNotifier, TestConnection -> GalaxyRepository direct SQL). CLAIM_TYPE: behavior-rule VERDICT: accurate EVIDENCE: GalaxyRepositoryGrpcService.cs:3339 (TestConnection → repository.TestConnectionAsync), :4262 (GetLastDeployTime → cache.Current), :64110 (DiscoverHierarchy → cache.Current), :112168 (BrowseChildren → cache.Current), :171200 (WatchDeployEvents → notifier.SubscribeAsync) CODE_AREA: gr.proto SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 346350 CLAIM: "GalaxyRepository (src/ZB.MOM.WW.MxGateway.Server/Galaxy/GalaxyRepository.cs) holds the SQL. Both HierarchySql and AttributesSql walk template-derivation and package-derivation chains via recursive CTEs." CLAIM_TYPE: path VERDICT: accurate EVIDENCE: GalaxyRepository.cs:117164 (HierarchySql with template_chain CTE); GalaxyRepository.cs:176251 (AttributesSql with deployed_package_chain CTE) CODE_AREA: gr.sql SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 347348 CLAIM: "HierarchySql still matches the OtOpcUa original; AttributesSql does not — it additionally enumerates built-in primitive attributes." CLAIM_TYPE: behavior-rule VERDICT: accurate EVIDENCE: GalaxyRepository.cs:914 (doc comment confirming this); GalaxyRepository.cs:166175 (comment on AttributesSql confirming divergence) CODE_AREA: gr.sql SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 269270 CLAIM: Configured (dynamic) attributes are stored in the Galaxy dynamic_attribute table. CLAIM_TYPE: term VERDICT: accurate EVIDENCE: GalaxyRepository.cs:196 (INNER JOIN dynamic_attribute da ON da.package_id = dpc.package_id) CODE_AREA: gr.sql SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 272273 CLAIM: Built-in attributes are stored in attribute_definition and reached through primitive_instance. CLAIM_TYPE: term VERDICT: accurate EVIDENCE: GalaxyRepository.cs:214218 (INNER JOIN primitive_instance pi ON pi.package_id = dpc.package_id / INNER JOIN attribute_definition ad ON ad.primitive_definition_id = pi.primitive_definition_id) CODE_AREA: gr.sql SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 283284 CLAIM: The configured-attribute category allow-list is mx_attribute_category IN (2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 24). CLAIM_TYPE: behavior-rule VERDICT: accurate EVIDENCE: GalaxyRepository.cs:203 (AND da.mx_attribute_category IN (2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 24)) CODE_AREA: gr.sql SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 283285 CLAIM: No category filter applies to built-in rows (attribute_definition); only the _-prefixed-name and .Description exclusions apply. CLAIM_TYPE: behavior-rule VERDICT: accurate EVIDENCE: GalaxyRepository.cs:221223 (AND ad.attribute_name NOT LIKE '[_]%' and NOT LIKE '%.Description' — no mx_attribute_category filter for the built-in branch) CODE_AREA: gr.sql SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 285287 CLAIM: "is_historized / is_alarm are always false for built-in rows." CLAIM_TYPE: behavior-rule VERDICT: accurate EVIDENCE: GalaxyRepository.cs:236248 — both is_historized and is_alarm use CASE WHEN r.src_pri = 0 AND EXISTS (...) — built-in rows have src_pri = 1 so both expressions evaluate to 0 (false). CODE_AREA: gr.sql SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 288290 CLAIM: "When a configured attribute and a built-in attribute resolve to the same reference, the configured attribute wins." CLAIM_TYPE: behavior-rule VERDICT: accurate EVIDENCE: GalaxyRepository.cs:225228 — ROW_NUMBER() OVER (PARTITION BY c.gobject_id, c.attribute_name ORDER BY c.src_pri, c.depth)src_pri = 0 for configured rows, src_pri = 1 for built-ins, so configured attributes are ranked first. CODE_AREA: gr.sql SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 420422 CLAIM: Dashboard /dashboard/galaxy page with object-category and top-template breakdowns. CLAIM_TYPE: path VERDICT: wrong EVIDENCE: GalaxyPage.razor:1 — the page route is @page "/galaxy", not /dashboard/galaxy. The Blazor app is mounted without a /dashboard prefix (DashboardEndpointRouteBuilderExtensions.cs:86, MapRazorComponents<App>()). The Galaxy page is at /galaxy, not /dashboard/galaxy. The home page at @page "/" is the dashboard overview, not at /dashboard. CODE_AREA: gr.proto SEVERITY: high PROPOSED_FIX: Change /dashboard/galaxy to /galaxy and /dashboard to / throughout the Dashboard Surface section (lines 419421). The Blazor router has no /dashboard prefix.


DOC: docs/GalaxyRepository.md LINES: 419420 CLAIM: "An overview card on /dashboard showing connectivity status..." CLAIM_TYPE: path VERDICT: wrong EVIDENCE: DashboardHome.razor:1 — @page "/". The home/overview page is at /, not /dashboard. CODE_AREA: gr.proto SEVERITY: high PROPOSED_FIX: Change /dashboard to / in the Dashboard Surface section.


DOC: docs/GalaxyRepository.md LINES: 369375 CLAIM: "GalaxyBrowseProjector (src/ZB.MOM.WW.MxGateway.Server/Galaxy/GalaxyBrowseProjector.cs) projects one level of children out of an immutable cache entry. Memoizes the filtered child list per cache-entry instance so repeated paging is an O(pageSize) slice rather than an O(siblings) filter scan. The memo is keyed on the cache entry reference, so a new entry from the background refresh makes the stale memo unreachable and it is collected with it. DashboardBrowseService wraps this projector to drive the dashboard's lazy-expand tree." CLAIM_TYPE: behavior-rule VERDICT: accurate EVIDENCE: GalaxyBrowseProjector.cs:2022 (ConditionalWeakTable keyed on GalaxyHierarchyCacheEntry); DashboardBrowseService.cs:55 (GalaxyBrowseProjector.ProjectChildren called inside DashboardBrowseService) CODE_AREA: gr.proto SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 110111 CLAIM: "IGalaxyHierarchyCache (src/ZB.MOM.WW.MxGateway.Server/Galaxy/GalaxyHierarchyCache.cs) — every DiscoverHierarchy and GetLastDeployTime request reads from this cache." CLAIM_TYPE: path VERDICT: accurate EVIDENCE: GalaxyHierarchyCache.cs (file at that path); GalaxyRepositoryGrpcService.cs:4662 (GetLastDeployTime reads from cache); :69110 (DiscoverHierarchy reads from cache) CODE_AREA: gr.proto SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 445447 CLAIM: "Integration tests live in src/ZB.MOM.WW.MxGateway.IntegrationTests/Galaxy/GalaxyRepositoryLiveTests.cs. Set MXGATEWAY_RUN_LIVE_GALAXY_TESTS=1 (and optionally MXGATEWAY_LIVE_GALAXY_CONN) to run them." CLAIM_TYPE: path VERDICT: accurate EVIDENCE: GalaxyRepositoryLiveTests.cs (file exists at that path); LiveGalaxyRepositoryFactAttribute.cs:9 (EnableVariableName = "MXGATEWAY_RUN_LIVE_GALAXY_TESTS"); LiveGalaxyRepositoryFactAttribute.cs:11 (ConnectionStringVariableName = "MXGATEWAY_LIVE_GALAXY_CONN") CODE_AREA: gr.proto SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 365367 CLAIM: "GalaxyProtoMapper (src/ZB.MOM.WW.MxGateway.Server/Grpc/GalaxyProtoMapper.cs) converts row models to proto messages. Used by the cache during refresh to materialize the reply once." CLAIM_TYPE: path VERDICT: accurate EVIDENCE: GalaxyProtoMapper.cs (file at that path); GalaxyHierarchyCache.cs:223 (BuildObjectsGalaxyProtoMapper.MapObject) CODE_AREA: gr.proto SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 212261 CLAIM: The GalaxyObject, GalaxyAttribute, DiscoverHierarchyRequest, and DiscoverHierarchyReply message field numbers and types as shown in the "Reply shape" proto block (field numbers 112 for GalaxyAttribute, 112 for DiscoverHierarchyRequest, etc.). CLAIM_TYPE: rpc/proto VERDICT: accurate EVIDENCE: galaxy_repository.proto:110191 (all field numbers and types match the doc's code block) CODE_AREA: gr.proto SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: 399400 CLAIM: Dashboard "displays only non-secret fields: server, database, integrated security, encrypt, and trust-server-certificate. It never displays user id, password, access token, or arbitrary unparsed connection string text." CLAIM_TYPE: behavior-rule VERDICT: unverifiable EVIDENCE: GalaxyPage.razor:129 (DashboardDisplay.Text(GalaxyConnectionStringDisplay())); GalaxyPage.razor:193196 delegates to DashboardConnectionStringDisplay.GalaxyRepositoryConnectionString. The actual display logic lives in DashboardConnectionStringDisplay which was not found in this audit scope. The behavior is asserted plausibly consistent with "never display user id, password" but the implementation of DashboardConnectionStringDisplay was not directly verified. CODE_AREA: gr.conn SEVERITY: low PROPOSED_FIX: flag only — verify DashboardConnectionStringDisplay filters fields as claimed.


DOC: docs/GalaxyRepository.md LINES: N/A — not covered in doc CLAIM: GAP — GalaxyHierarchyCache projects Status to Stale when LastSuccessAt is more than 5 minutes old (regardless of the stored status), via ProjectStatus with StaleThreshold = TimeSpan.FromMinutes(5). CLAIM_TYPE: behavior-rule VERDICT: gap EVIDENCE: GalaxyHierarchyCache.cs:22 (StaleThreshold = TimeSpan.FromMinutes(5)); GalaxyHierarchyCache.cs:474488 (ProjectStatus method) CODE_AREA: gr.proto SEVERITY: medium PROPOSED_FIX: Add a note under "Hierarchy Cache" that the cache also auto-degrades to Stale status when more than 5 minutes have elapsed since the last successful refresh, independent of the stored entry status. This matters for operators diagnosing why a Healthy entry flips to Stale without a SQL failure.


DOC: docs/GalaxyRepository.md LINES: N/A — not covered in doc CLAIM: GAP — WatchDeployEvents emits a bootstrap event even on a snapshot-restore (from on-disk data), not only from live SQL queries. GalaxyHierarchyCache.TryRestoreFromDiskAsync calls _notifier.Publish after restoring. CLAIM_TYPE: behavior-rule VERDICT: gap EVIDENCE: GalaxyHierarchyCache.cs:315320 (_notifier.Publish called from TryRestoreFromDiskAsync) CODE_AREA: gr.proto SEVERITY: low PROPOSED_FIX: Note under "Deploy Notifications" or "On-disk snapshot" that restoring the snapshot also publishes a deploy event so WatchDeployEvents subscribers receive a bootstrap event even when SQL is unreachable at startup.


DOC: docs/GalaxyRepository.md LINES: N/A — not covered in doc CLAIM: GAP — GalaxyHierarchyRefreshService runs an initial RefreshAsync immediately on startup (before starting the periodic timer), so the first load happens at process start, not after the first tick of DashboardRefreshIntervalSeconds. CLAIM_TYPE: behavior-rule VERDICT: gap EVIDENCE: GalaxyHierarchyRefreshService.cs:2237 (initial await cache.RefreshAsync before PeriodicTimer is created) CODE_AREA: gr.proto SEVERITY: low PROPOSED_FIX: Add a note under "Hierarchy Cache" that the first refresh runs immediately at gateway startup and does not wait for the first timer tick.


DOC: docs/GalaxyRepository.md LINES: N/A — not covered in doc CLAIM: GAP — The HierarchySql category filter (td.category_id IN (1, 3, 4, 10, 11, 13, 17, 24, 26)) and the specific category IDs mapped to names (WinPlatform=1, AppEngine=3, InTouchViewApp=4, UserDefined=10, FieldReference=11, Area=13, DIObject=17, DDESuiteLinkClient=24, OPCClient=26) are not documented anywhere in GalaxyRepository.md. CLAIM_TYPE: behavior-rule VERDICT: gap EVIDENCE: GalaxyRepository.cs:161 (HierarchySql WHERE clause with category IDs); GalaxyHierarchyCache.cs:461472 (ResolveCategoryName method mapping each ID to a name) CODE_AREA: gr.sql SEVERITY: medium PROPOSED_FIX: Add a table of the filtered category IDs and their names (WinPlatform, AppEngine, InTouchViewApp, etc.) to the doc. Operators need to know which object types are included — an AppEngine that doesn't appear in browse results is hard to diagnose without this list.


DOC: docs/GalaxyRepository.md LINES: N/A — not covered in doc CLAIM: GAP — The AttributesSql uses the data_type table to resolve data_type_name (LEFT JOIN data_type dt ON dt.mx_data_type = r.mx_data_type). The Galaxy table name data_type is not mentioned in the doc. CLAIM_TYPE: term VERDICT: gap EVIDENCE: GalaxyRepository.cs:249 (LEFT JOIN data_type dt ON dt.mx_data_type = r.mx_data_type) CODE_AREA: gr.sql SEVERITY: low PROPOSED_FIX: flag only


DOC: docs/GalaxyRepository.md LINES: N/A — not covered in doc CLAIM: GAP — The HierarchySql uses the tables gobject and template_definition, and maps parent_gobject_id using CASE WHEN g.contained_by_gobject_id = 0 THEN g.area_gobject_id ELSE g.contained_by_gobject_id END. This parent resolution logic (area_gobject_id fallback) is not mentioned. CLAIM_TYPE: behavior-rule VERDICT: gap EVIDENCE: GalaxyRepository.cs:138142 (parent_gobject_id CASE expression); tables referenced: gobject (line 158), template_definition (line 159) CODE_AREA: gr.sql SEVERITY: low PROPOSED_FIX: flag only