refactor: collapse repo cache + push view-display admin gate server-side#473
Merged
tkuhn merged 1 commit intoMay 28, 2026
Merged
Conversation
…er-side Two layers of caching (per-Repository 60s TTL + ApiCache 60s TTL) collapsed into one: MaintainedResourceRepository and SpaceRepository now memoise the derived lookup maps by ApiResponse object identity from ApiCache, rebuilding only when ApiCache returns a fresh response. ensureLoaded() and refreshAndInvalidate() removed; forceRootRefresh delegates to ApiCache.clearCache. GET_VIEW_DISPLAYS query template superseded twice to push the admin-pubkey filter server-side: it now joins through the spaces repo's current state graph + npa:AccountState rows to admit only view-displays signed by trust-state-validated admins of the resource's Space (whether the resource IS a Space or is maintained by one). Resources with no Space association (e.g. agent profiles) keep the prior unfiltered behaviour via a UNION branch. Live IRI: RAIMs6C9gfjqX-TYGd8mrq7MJ7K-DoofW6v4dzFQJTs7Y. Client-side filtering in AbstractResourceWithProfile.triggerDataUpdate and DownloadRdfPage.fetchViewDisplays dropped. Space's async data-loading machinery collapsed: triggerSpaceDataUpdate / ensureInitialized / spaceDataFuture / dataInitialized+dataNeedsUpdate shadow fields all dropped. SpaceData is an immutable snapshot rebuilt synchronously in currentData(), memoised by the (admins, roles, members) ApiResponse identity tuple. Space.isAdminPubkey now hits the cached GET_SPACE_ADMIN_PUBKEY_HASHES response directly instead of a per-Space adminPubkeyMap. forceRefresh now also clears the four Space-scoped ApiCache entries. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Summary
Three intertwined simplifications of the space/maintained-resource data layer. Net: -70 LOC, two cache layers collapsed to one, view-display trust now enforced server-side.
Phase 1 — collapse
*Repositorycaches onto ApiCacheMaintainedResourceRepositoryandSpaceRepositorypreviously held their own 60s TTL + hand-maintained maps on top ofApiCache(which already has a 60s TTL). They now memoise the derived lookup maps by theApiResponseobject identity returned fromApiCache.retrieveResponseSync, rebuilding only when ApiCache returns a fresh response.ensureLoaded()and the unusedrefreshAndInvalidate()removed;forceRootRefresh(waitMs)delegates toApiCache.clearCache(..., waitMs).MaintainedResource/Spaceclasses are unchanged in API.Phase 2 — push view-display admin gate server-side
New
get-view-displaysquery template (RAIMs6C9gfjqX-TYGd8mrq7MJ7K-DoofW6v4dzFQJTs7Y, supersedes the liveRAapc3jbJ3GkDy0ncKx3pok_zEKqwrT6-Z5TkCP1k96IIvia an intermediateRA3IiHoTcBRg54-...that lacked the no-Space branch). The new query SERVICEs the spaces repo's current state graph, joins throughgen:RoleInstantiation+npa:AccountState, and admits only view-displays signed by trust-state-validated admins of the resource's Space (whether the resource IS a Space or is maintained by one). A UNION branch keeps the prior unfiltered behaviour for resources with no Space association (agent profiles) — without it,/user/<orcid>profile pages render zero view-displays.Client-side filtering removed from:
AbstractResourceWithProfile.triggerDataUpdateDownloadRdfPage.fetchViewDisplaysSpace.adminPubkeyMapfield andloadAdminPubkeyHashesFromSpacesRepodeleted.Space.isAdminPubkey()kept (still needed byViewDisplayMenufor UI gating) but now hits the cachedGET_SPACE_ADMIN_PUBKEY_HASHESresponse directly instead of a per-Space pre-loaded map.Phase 3 — shrink
Spaceto a cache façadeThe async data-loading machinery (
triggerSpaceDataUpdate,ensureInitialized,spaceDataFuture, shadowdataInitialized/dataNeedsUpdate, plus the four@Overrideshadow methods) all dropped.SpaceDatais now an immutable snapshot value type rebuilt synchronously incurrentData(), memoised by the(adminsResp, rolesResp, membersResp)ApiResponse identity tuple. Root-nanopub-derived state (altIds,description,startDate,endDate,defaultProvenance,rootAdmins) lives on theSpaceinstance directly.forceRefresh(waitMs)now also invalidates the four Space-scoped ApiCache entries.Runtime behaviour notes
Space.getAdmins()/getUsers()/getMemberRoles()/isMember()/getRoles()/isAdminPubkey()blocks onApiCache.retrieveResponseSyncfor the underlying spaces-repo queries; subsequent calls within ApiCache's 60s freshness window are O(map-lookup).Space.isDataInitialized()now reflects only view-display loading (parent's behaviour) — when it flips true,SpacePagepanels render and callgetUsers()/getRoles()synchronously. In practice this is fine because those queries are already warm by the time view-displays have loaded.Test plan
mvn clean compilepassesmvn jetty:run+ curl smoke-test:/,/spaces,/space?id=https://w3id.org/spaces/knowledgepixels,/resource?id=https://w3id.org/spaces/knowledgepixels/nanodash/r/homeall return HTTP 200, no exceptions in logs, expected content renderedforceRefreshpicks it up🤖 Generated with Claude Code