Skip to content

fix(SpacesExtractor): emit inline non-hasAdmin role RIs from gen:Space#108

Merged
tkuhn merged 1 commit into
mainfrom
fix/spaces-inline-role-extraction
May 22, 2026
Merged

fix(SpacesExtractor): emit inline non-hasAdmin role RIs from gen:Space#108
tkuhn merged 1 commit into
mainfrom
fix/spaces-inline-role-extraction

Conversation

@tkuhn
Copy link
Copy Markdown
Contributor

@tkuhn tkuhn commented May 22, 2026

Summary

A gen:Space nanopub may declare multiple role-predicate assignments inline in its assertion — gen:hasAdmin, has-event-facilitator, has-event-organizer, participatedAs*, etc. The extractor was only emitting a gen:RoleInstantiation for the gen:hasAdmin triples; everything else was silently dropped because gen:Space nanopubs aren't auto-typed with back-compat role predicates (only single-triple-assertion nanopubs are).

Symptom: spaces relying on inline role declarations (the 3pff FIP/M4M templates publish all roles in one gen:Space nanopub) end up with admins-only members in consumers. Found while migrating nanodash to query the spaces repo directly (knowledgepixels/nanodash#468) — FIP.38.T.8 has 3 facilitators, 1 assistant, and 1 organizer declared inline; before this fix none of them reach npa:spacesGraph.

Changes

  • SpacesExtractor.emitSpaceEntry now calls a new emitInlineRoleInstantiations(np, ctx, spaceIri, out) helper after the admin-RI emission. It scans the assertion for any back-compat role predicate (excluding gen:hasAdmin, which is the trust seed and handled separately), groups by predicate, and emits one gen:RoleInstantiation per (predicate, direction) pair with multi-valued npa:forAgent — same shape as the admin path.
  • Subject collision avoidance: a new SpacesVocab.forRoleInstantiation(artifactCode, discriminatorHash) overload mints npari:<artifactCode>_<predicateHash>. The admin RI keeps the unhashed npari:<artifactCode> subject (no behavioural change there).
  • BackcompatRolePredicates: adds has-event-organizer (INVERSE). It's actively used by the 3pff FIP templates but was missing from the direction map.
  • Test: extract_spaceWithInlineRoleTriples_emitsAdditionalRoleInstantiations covers admin + INVERSE-inline + REGULAR-inline emission in one gen:Space nanopub.

Test plan

  • mvn test — 214 pass, 0 fail (including the new test)
  • After deploy, FIP.38.T.8 (and other 3pff FIP spaces) will surface facilitators/assistants/organizers through the spaces repo. Verifiable via:
    SELECT (COUNT(?ri) AS ?n) WHERE {
      GRAPH npa:spacesGraph {
        ?ri a gen:RoleInstantiation ;
            npa:forSpace <https://w3id.org/fair/3pff/FIP.38.T.8> .
      }
    }

🤖 Generated with Claude Code

A gen:Space nanopub may declare other roles alongside hasAdmin in the
same assertion — has-event-facilitator, has-event-organizer,
participatedAs* etc. The extractor was only emitting a RoleInstantiation
for the hasAdmin triples; everything else was silently dropped because
gen:Space nanopubs aren't auto-typed with back-compat role predicates
(only single-triple-assertion nanopubs are). Spaces relying on inline
role declarations (the 3pff FIP/M4M templates publish all roles in one
gen:Space nanopub) ended up with admins-only members in consumers.

Each distinct back-compat role predicate found inline gets its own
RoleInstantiation, subject disambiguated by a hash of the predicate IRI
(npari:<artifactCode>_<predicateHash>) so multiple predicates in one
nanopub don't collide with each other or with the unhashed admin RI
(npari:<artifactCode>). Direction comes from BackcompatRolePredicates;
the inline orientation (<space> <pred> <agent> vs <agent> <pred> <space>)
is verified against that.

Also adds has-event-organizer to BackcompatRolePredicates (INVERSE) — it
is actively used by the 3pff FIP templates but was missing from the
direction map.

Closes a gap surfaced while migrating nanodash to query the spaces repo
(knowledgepixels/nanodash#468): FIP.38.T.8 has 3 facilitators, 1
assistant, and 1 organizer declared inline in the root np; with this fix
they round-trip through extraction.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@tkuhn tkuhn merged commit 559f767 into main May 22, 2026
8 checks passed
@github-actions
Copy link
Copy Markdown

🎉 This PR is included in version 1.14.2 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant