diff --git a/src/ZB.MOM.WW.MxGateway.Server/Galaxy/GalaxyBrowseProjector.cs b/src/ZB.MOM.WW.MxGateway.Server/Galaxy/GalaxyBrowseProjector.cs
index d6a5135..1768fb3 100644
--- a/src/ZB.MOM.WW.MxGateway.Server/Galaxy/GalaxyBrowseProjector.cs
+++ b/src/ZB.MOM.WW.MxGateway.Server/Galaxy/GalaxyBrowseProjector.cs
@@ -62,7 +62,16 @@ public static class GalaxyBrowseProjector
return new GalaxyBrowseChildrenResult(page, hasChildren, filtered.Children.Count, filterSignature);
}
- private static int ResolveParentId(GalaxyHierarchyCacheEntry entry, BrowseChildrenRequest request)
+ ///
+ /// Resolves the request's parent oneof to a gobject id, throwing
+ /// with when the
+ /// parent does not exist. Public so the gRPC handler can compute the same
+ /// parent id (needed for the page-token signature) without reimplementing the
+ /// resolution rules.
+ ///
+ /// The Galaxy hierarchy cache entry to query.
+ /// The browse-children request.
+ public static int ResolveParentId(GalaxyHierarchyCacheEntry entry, BrowseChildrenRequest request)
{
switch (request.ParentCase)
{
diff --git a/src/ZB.MOM.WW.MxGateway.Server/Grpc/GalaxyRepositoryGrpcService.cs b/src/ZB.MOM.WW.MxGateway.Server/Grpc/GalaxyRepositoryGrpcService.cs
index 8bce0a5..0113b81 100644
--- a/src/ZB.MOM.WW.MxGateway.Server/Grpc/GalaxyRepositoryGrpcService.cs
+++ b/src/ZB.MOM.WW.MxGateway.Server/Grpc/GalaxyRepositoryGrpcService.cs
@@ -128,8 +128,11 @@ public sealed class GalaxyRepositoryGrpcService(
IReadOnlyList browseSubtrees = ResolveBrowseSubtrees();
// Resolve the parent id once so the page-token signature can include it
- // and the projector sees the same resolved id when memoizing.
- int parentId = ResolveParentIdForToken(entry, request);
+ // and the projector sees the same resolved id when memoizing. The projector
+ // re-resolves internally; with the by-name/by-path indexes on
+ // GalaxyHierarchyIndex that second call is O(1), so the redundancy is cheap
+ // and keeps the projector self-contained.
+ int parentId = GalaxyDb.GalaxyBrowseProjector.ResolveParentId(entry, request);
string filterSignature = GalaxyDb.GalaxyBrowseProjector.ComputeFilterSignature(
request, browseSubtrees, parentId);
PageToken pageToken = ParsePageToken(request.PageToken, entry.Sequence, filterSignature);
@@ -283,32 +286,6 @@ public sealed class GalaxyRepositoryGrpcService(
return Math.Min(pageSize, MaxDiscoverPageSize);
}
- // Lightweight parent resolver used only for signature computation. Re-throws
- // NotFound consistently with the projector so the error surface matches.
- private static int ResolveParentIdForToken(
- GalaxyDb.GalaxyHierarchyCacheEntry entry,
- BrowseChildrenRequest request)
- {
- return request.ParentCase switch
- {
- BrowseChildrenRequest.ParentOneofCase.None => 0,
- BrowseChildrenRequest.ParentOneofCase.ParentGobjectId =>
- request.ParentGobjectId == 0 ? 0
- : entry.Index.ObjectViewsById.ContainsKey(request.ParentGobjectId)
- ? request.ParentGobjectId
- : throw new RpcException(new Status(StatusCode.NotFound, "BrowseChildren parent was not found.")),
- BrowseChildrenRequest.ParentOneofCase.ParentTagName =>
- entry.Index.ObjectViews.FirstOrDefault(
- v => string.Equals(v.Object.TagName, request.ParentTagName, StringComparison.OrdinalIgnoreCase))?.Object.GobjectId
- ?? throw new RpcException(new Status(StatusCode.NotFound, "BrowseChildren parent was not found.")),
- BrowseChildrenRequest.ParentOneofCase.ParentContainedPath =>
- entry.Index.ObjectViews.FirstOrDefault(
- v => string.Equals(v.ContainedPath, request.ParentContainedPath, StringComparison.OrdinalIgnoreCase))?.Object.GobjectId
- ?? throw new RpcException(new Status(StatusCode.NotFound, "BrowseChildren parent was not found.")),
- _ => 0,
- };
- }
-
private IReadOnlyList ResolveBrowseSubtrees()
{
ApiKeyConstraints constraints = identityAccessor.Current?.EffectiveConstraints ?? ApiKeyConstraints.Empty;