Skip to content

refactor: collapse repo cache + push view-display admin gate server-side#473

Merged
tkuhn merged 1 commit into
masterfrom
refactor/collapse-cache-and-server-side-view-display-gate
May 28, 2026
Merged

refactor: collapse repo cache + push view-display admin gate server-side#473
tkuhn merged 1 commit into
masterfrom
refactor/collapse-cache-and-server-side-view-display-gate

Conversation

@tkuhn
Copy link
Copy Markdown
Contributor

@tkuhn tkuhn commented May 28, 2026

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 *Repository caches onto ApiCache

MaintainedResourceRepository and SpaceRepository previously held their own 60s TTL + hand-maintained maps on top of ApiCache (which already has a 60s TTL). They now memoise the derived lookup maps by the ApiResponse object identity returned from ApiCache.retrieveResponseSync, rebuilding only when ApiCache returns a fresh response. ensureLoaded() and the unused refreshAndInvalidate() removed; forceRootRefresh(waitMs) delegates to ApiCache.clearCache(..., waitMs). MaintainedResource / Space classes are unchanged in API.

Phase 2 — push view-display admin gate server-side

New get-view-displays query template (RAIMs6C9gfjqX-TYGd8mrq7MJ7K-DoofW6v4dzFQJTs7Y, supersedes the live RAapc3jbJ3GkDy0ncKx3pok_zEKqwrT6-Z5TkCP1k96II via an intermediate RA3IiHoTcBRg54-... that lacked the no-Space branch). The new query SERVICEs the spaces repo's current state graph, joins through gen: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.triggerDataUpdate
  • DownloadRdfPage.fetchViewDisplays

Space.adminPubkeyMap field and loadAdminPubkeyHashesFromSpacesRepo deleted. Space.isAdminPubkey() kept (still needed by ViewDisplayMenu for UI gating) but now hits the cached GET_SPACE_ADMIN_PUBKEY_HASHES response directly instead of a per-Space pre-loaded map.

Phase 3 — shrink Space to a cache façade

The async data-loading machinery (triggerSpaceDataUpdate, ensureInitialized, spaceDataFuture, shadow dataInitialized/dataNeedsUpdate, plus the four @Override shadow methods) all dropped. SpaceData is now an immutable snapshot value type rebuilt synchronously in currentData(), memoised by the (adminsResp, rolesResp, membersResp) ApiResponse identity tuple. Root-nanopub-derived state (altIds, description, startDate, endDate, defaultProvenance, rootAdmins) lives on the Space instance directly. forceRefresh(waitMs) now also invalidates the four Space-scoped ApiCache entries.

Runtime behaviour notes

  • First call per JVM lifetime to Space.getAdmins() / getUsers() / getMemberRoles() / isMember() / getRoles() / isAdminPubkey() blocks on ApiCache.retrieveResponseSync for 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, SpacePage panels render and call getUsers()/getRoles() synchronously. In practice this is fine because those queries are already warm by the time view-displays have loaded.

Test plan

  • mvn clean compile passes
  • mvn jetty:run + curl smoke-test: /, /spaces, /space?id=https://w3id.org/spaces/knowledgepixels, /resource?id=https://w3id.org/spaces/knowledgepixels/nanodash/r/home all return HTTP 200, no exceptions in logs, expected content rendered
  • v3 query output matches v1 row-for-row for: agent IRI (45), space IRI (3), maintained-resource IRI (5), empty-admin space (0)
  • Manual: load a Space page, confirm Admins / Members / Roles populate after first request
  • Manual: load a User profile page, confirm view-displays render
  • Manual: as a space admin, publish a new view-display and confirm forceRefresh picks it up

🤖 Generated with Claude Code

…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>
@tkuhn tkuhn merged commit 6ce9d21 into master May 28, 2026
8 checks passed
@tkuhn tkuhn deleted the refactor/collapse-cache-and-server-side-view-display-gate branch May 28, 2026 07:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant