From 0f7a8ad8270c3af312087e4465c2027b7795d496 Mon Sep 17 00:00:00 2001 From: Tobias Kuhn Date: Wed, 27 May 2026 11:50:00 +0200 Subject: [PATCH] fix(spaces): ingest gen:hasGuest / gen:hasHost member RIs (#114) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gen:hasGuest and gen:hasHost were missing from BackcompatRolePredicates, so a single-triple member RI like gen:hasGuest — auto-typed by the predicate via the registry's single-triple-assertion trick — was not in TRIGGER_TYPES. isSpaceRelevant returned false and extract() dropped the nanopub entirely (not even stored), so guest/host members silently vanished while their sibling predicates (hasObserver, hasAdmin, hasProjectLead, hasTeamMember) worked. Add both as Direction.INVERSE (space-centric, matching hasObserver/hasAdmin). A re-materialization then picks up the existing guest/host role instantiations. Co-Authored-By: Claude Opus 4.7 (1M context) --- doc/design-space-repositories.md | 2 ++ .../vocabulary/BackcompatRolePredicates.java | 2 ++ .../query/SpacesExtractorTest.java | 24 +++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/doc/design-space-repositories.md b/doc/design-space-repositories.md index 06e80e1..f1d5313 100644 --- a/doc/design-space-repositories.md +++ b/doc/design-space-repositories.md @@ -53,6 +53,8 @@ Two things in one repo: - `` - `` - `` + - `` + - `` - `` - `` - `` diff --git a/src/main/java/com/knowledgepixels/query/vocabulary/BackcompatRolePredicates.java b/src/main/java/com/knowledgepixels/query/vocabulary/BackcompatRolePredicates.java index fdcf93a..182a5c3 100644 --- a/src/main/java/com/knowledgepixels/query/vocabulary/BackcompatRolePredicates.java +++ b/src/main/java/com/knowledgepixels/query/vocabulary/BackcompatRolePredicates.java @@ -62,6 +62,8 @@ private static IRI iri(String s) { Map.entry(iri("https://w3id.org/fair/3pff/participatedAsTrainerIn"), Direction.REGULAR), // KPXL gen terms Map.entry(iri("https://w3id.org/kpxl/gen/terms/hasAdmin"), Direction.INVERSE), + Map.entry(iri("https://w3id.org/kpxl/gen/terms/hasGuest"), Direction.INVERSE), + Map.entry(iri("https://w3id.org/kpxl/gen/terms/hasHost"), Direction.INVERSE), Map.entry(iri("https://w3id.org/kpxl/gen/terms/hasObserver"), Direction.INVERSE), Map.entry(iri("https://w3id.org/kpxl/gen/terms/hasProjectLead"), Direction.INVERSE), Map.entry(iri("https://w3id.org/kpxl/gen/terms/hasTeamMember"), Direction.INVERSE), diff --git a/src/test/java/com/knowledgepixels/query/SpacesExtractorTest.java b/src/test/java/com/knowledgepixels/query/SpacesExtractorTest.java index b23b7fc..a1cdc90 100644 --- a/src/test/java/com/knowledgepixels/query/SpacesExtractorTest.java +++ b/src/test/java/com/knowledgepixels/query/SpacesExtractorTest.java @@ -347,6 +347,30 @@ void extract_backcompatInverseDirection_emitsRoleInstantiation() throws Exceptio assertDoesNotContain(out, subject, REGULAR_PROPERTY, hasTeamMember); } + @Test + void extract_backcompatHasGuestAndHost_emitsRoleInstantiation_issue114() throws Exception { + // gen:hasGuest / gen:hasHost are space-centric (INVERSE), like hasObserver/hasAdmin. + // They were missing from BackcompatRolePredicates, so the extractor dropped + // guest/host member RIs entirely (issue #114). + for (String pred : new String[] { + "https://w3id.org/kpxl/gen/terms/hasGuest", + "https://w3id.org/kpxl/gen/terms/hasHost" }) { + IRI predicate = vf.createIRI(pred); + // Single-triple assertion → auto-typed by the predicate via NanopubUtils.getTypes. + Nanopub np = creator() + .assertion(SPACE_IRI_1, predicate, MEMBER_AGENT) + .finalizeNanopub(); + + List out = SpacesExtractor.extract(np, defaultContext()); + IRI subject = forRoleInstantiation(ARTIFACT_CODE); + + assertContains(out, subject, RDF.TYPE, GEN.ROLE_INSTANTIATION); + assertContains(out, subject, FOR_SPACE, SPACE_IRI_1); + assertContains(out, subject, INVERSE_PROPERTY, predicate); + assertContains(out, subject, FOR_AGENT, MEMBER_AGENT); + } + } + @Test void extract_backcompatRegularDirection_swapsSpaceAndAgent() throws Exception { // Agent-centric source: . REGULAR under the publisher