From 1cf3f3a9b3ea73556d3dd3e025bf64aedd93b638 Mon Sep 17 00:00:00 2001 From: ZDDC Date: Mon, 1 Jun 2026 13:23:22 -0500 Subject: [PATCH] perf(server): scope /.profile/access?path= to the requested location only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit enumerateAccess always computed the global summary — every project (EnumerateProjects) and every admin subtree (enumerateAdminSubtrees tree walk) — and merely appended the path-scoped fields when ?path= was given. The browse hovercard calls this per folder hovered, so each distinct folder paid a full global enumeration for data it never reads. Split the two: a ?path= query now returns ONLY identity + path_verbs/ path_is_admin/path_can_elevate_grant/path_roles and skips the tree walks; the no-path call still returns the full global view for the profile page. Verified all path-scoped consumers (browse hovercard, form, tables) read only path_* fields; the global consumers (elevation, stage, plan-review, accept-transmittal) all call without ?path=. Co-Authored-By: Claude Opus 4.8 (1M context) --- zddc/internal/handler/profilehandler.go | 21 ++++++++++++++------ zddc/internal/handler/profilehandler_test.go | 6 ++++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/zddc/internal/handler/profilehandler.go b/zddc/internal/handler/profilehandler.go index eed1e08..9421209 100644 --- a/zddc/internal/handler/profilehandler.go +++ b/zddc/internal/handler/profilehandler.go @@ -197,10 +197,22 @@ type AccessView struct { // silently ignored (the global fields still return). func enumerateAccess(ctx context.Context, decider policy.Decider, cfg config.Config, p zddc.Principal, pathQuery string) AccessView { view := AccessView{ - Email: p.Email, - EmailHeader: cfg.EmailHeader, - IsSuperAdmin: zddc.IsAdmin(cfg.Root, p), + Email: p.Email, + EmailHeader: cfg.EmailHeader, } + + // Path-scoped query: return ONLY the access for THIS location. The + // global summary (every project, every admin subtree) requires tree + // walks that are irrelevant to "what can I do here?" — and the + // hovercard calls this per folder, so paying that cost per hover + // would be wasteful. Callers that want the global view omit ?path=. + if pathQuery != "" { + populatePathScopedAccess(ctx, decider, cfg, p, pathQuery, &view) + return view + } + + // Global summary (the profile page). + view.IsSuperAdmin = zddc.IsAdmin(cfg.Root, p) view.Projects, _ = EnumerateProjects(ctx, decider, cfg, p) view.AdminSubtrees = enumerateAdminSubtrees(cfg, p) view.HasAnyAdminScope = view.IsSuperAdmin || len(view.AdminSubtrees) > 0 @@ -216,9 +228,6 @@ func enumerateAccess(ctx context.Context, decider policy.Decider, cfg config.Con allowed, _ := policy.AllowActionFromChainP(ctx, decider, rootChain, p, "/", policy.ActionCreate) view.CanCreateProject = allowed } - if pathQuery != "" { - populatePathScopedAccess(ctx, decider, cfg, p, pathQuery, &view) - } return view } diff --git a/zddc/internal/handler/profilehandler_test.go b/zddc/internal/handler/profilehandler_test.go index 28964e4..612249f 100644 --- a/zddc/internal/handler/profilehandler_test.go +++ b/zddc/internal/handler/profilehandler_test.go @@ -540,6 +540,12 @@ acl: if alice.PathVerbs != "rw" { t.Errorf("alice PathVerbs = %q, want rw", alice.PathVerbs) } + // A path-scoped query returns ONLY the access for this location — the + // global summary (projects + admin-subtree walks) is omitted. + if len(alice.Projects) != 0 || len(alice.AdminSubtrees) != 0 || alice.CanCreateProject { + t.Errorf("path-scoped response leaked global fields: Projects=%d AdminSubtrees=%d CanCreateProject=%v", + len(alice.Projects), len(alice.AdminSubtrees), alice.CanCreateProject) + } if alice.PathIsAdmin { t.Errorf("alice PathIsAdmin = true, want false") }