Skip to content

0.26.0 drops the nested id a named Reference Type entry can be the value of: IIIF manifests come out null #844

Description

@ddeboer

Summary

#832 (0.26.0) drops id from every Reference Type entry on the grounds that nothing read it. Linked Open Limburg reads it: a work’s IIIF Presentation manifest is an associatedMedia entry whose node IRI is the manifest URL, and the node states nothing else. With 0.26.0 iiifManifest comes out null on every work that has one.

Observed

limburg/lol#173 (Renovate, @lde/search 0.25.0 → 0.26.0) fails apps/search-indexer/test/iiif-manifest.test.ts:

× is read from the named manifest node among the associated media
AssertionError: expected undefined to be 'https://example.org/iiif/work/manifest'

The test exists for exactly this: it projects through @lde/search rather than hand-building the entry, so that “a projection change that starves the derive fails here rather than at deploy, where it shows as iiifManifest: null on every work”.

What the data looks like, Limburgs Museum dump, one of 518 manifests:

<…/38b5276a…> schema:isBasedOn <…/5a1b6571…/iiif.json> .
<…/5a1b6571…/iiif.json> schema:encodingFormat "application/ld+json;profile='http://iiif.io/api/presentation/3/context.json'" .

SCHEMA-AP-NDE § 4.2.6 has the same shape one hop up: the manifest is an associatedMedia entry with @id the manifest URI and encodingFormat the Presentation context. Neither shape carries contentUrl or any other property naming the URL. MediaObject and IiifService are Reference Types in LOL’s schema – a reproduction has no identity of its own – so after #832 the derive has nothing to read.

Why the #832 argument does not cover this

The PR shows that no engine concern reads a nested entry’s id: the collection does not declare it, welds use the flat companion, no query joins on it. All true. But a derive is a consumer too, and here the IRI is the value: the manifest URL is the payload, not an identity to join on. That is the one case where a named referent’s IRI is data, and it is what the profile prescribes.

Proposed

Keep the default from #832 – an entry of a Reference Type has no id – and let a Reference Type declare that it wants the referent’s IRI, so the projection carries it under a named field. Two shapes that would work from LOL’s side:

  • a field whose path is the node itself, e.g. { name: 'url', kind: 'reference', path: '@id' } (the framing already has @id; only the projection would need to map it), or
  • a type-level flag, keepId: true (or identity: 'iri'), that restores the id for that Reference Type only.

Either keeps the dedupe #832 wanted for role edges, where the IRI really is arbitrary, while a manifest entry stays addressable. I would take the first: it is a declaration on the field that wants the value, it reuses the @id framing already produces, and it adds no second notion of identity to a type that #832 just said has none. Until one exists LOL stays on @lde/search 0.25.x, which also blocks the @lde/search-indexer 0.18 line for it.

Activity

  1. added theissue type on Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions