Skip to content

feat: add classification metadata predicate matrix - #7

Merged
jonathanprozzi merged 3 commits into
mainfrom
feat/classification-metadata-predicate-matrix
Jun 12, 2026
Merged

feat: add classification metadata predicate matrix#7
jonathanprozzi merged 3 commits into
mainfrom
feat/classification-metadata-predicate-matrix

Conversation

@jonathanprozzi

@jonathanprozzi jonathanprozzi commented Jun 9, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds a metadata predicate matrix layer to @0xintuition/classifications.
  • Keeps relationship/object-target semantics out of @0xintuition/predicates; predicates remain reusable vocabulary.
  • Introduces typed expected object targets: classification, schema, primitive, same-classification, and any.
  • Introduces schema mappings with match: exact | semantic | broader | narrower so lossy mappings are explicit.
  • Models every currently promoted (classification, metadataPredicate) pair: 189 promoted pairs, 189 matrix rows, zero missing rows.
  • Adds sameAs matrix entries for every classification that promotes sameAs in metadataPredicates, while preserving the explicit exclusions from feat: add classification metadata predicate refs #6.
  • Seeds concrete examples that exercise the important cases:
    • music-recording:byArtist -> music-group / person
    • music-recording:inAlbum -> music-album
    • music-recording:inPlaylist -> schema.org MusicPlaylist because there is no Intuition music-playlist classification yet
    • music-recording:hasCategory -> defined-term with a broader mapping to schema.org genre
    • music-recording:sameAs -> same-classification for strict identity links like Spotify and Apple Music representations of the same recording

Why This Lives In Classifications

The matrix is keyed by (subjectClassification, predicate), so it belongs with classifications rather than predicates. This preserves the package boundary:

  • @0xintuition/predicates defines predicate vocabulary.
  • @0xintuition/classifications decides which predicates are recommended for each classification and what object targets are expected in that context.
  • @0xintuition/schema-org remains the schema source/provenance layer.

The old predicates-owned entity-type-map remains a compatibility/coarse discovery surface, but generated creation UI should use this classification-owned matrix.

Object Target Policy

The matrix prefers the narrowest honest target:

  • Use classification when Intuition already classifies the object, e.g. movie:director -> person.
  • Use schema when schema.org has the object concept but Intuition has not promoted a matching classification yet, e.g. listedIn -> schema.org Collection.
  • Use primitive for literal values, e.g. url -> primitive:url.
  • Use same-classification for strict identity links.
  • Use any only where the predicate is intentionally broad or still product-dependent, e.g. reference, itemReviewed, contain, linkedAccount, and use.

This intentionally avoids falling back to schema.org Thing as a generic target. Thing would look more precise than any while carrying almost the same runtime behavior, and it would imply schema.org provenance where the intended Intuition object model may still be broader or product-specific. any is more honest for generated UI: builders should show a broad atom picker and can inspect the required reason before narrowing the UX later.

sameAs Decision

sameAs is modeled as strict identity linking, not generic related content. Matrix rows use expectedObjects: [{ kind: 'same-classification' }], which lets builders represent cases like Spotify song atom -> sameAs -> Apple Music song atom without treating reviews, listicles, or adjacent references as the same entity.

This PR covers sameAs for all classifications that intentionally promote it.

Validation

The validator tests check that every matrix entry:

  • References an existing subject classification.
  • References an existing predicate key from @0xintuition/predicates.
  • Uses a predicate already promoted by that subject's metadataPredicates.
  • Resolves classification expected-object slugs.
  • Resolves schema.org expected-object types.
  • Resolves schema.org property mappings through getPropertiesFor(subject.schema.type).
  • Uses an explicit schema mapping match type.
  • Provides a reason for every any object target.

Additional tests assert:

  • Every promoted (classification, metadataPredicate) pair has a matrix row.
  • No matrix row uses schema.org Thing as a catch-all target.
  • Every classification that promotes sameAs has a matrix row.
  • Every sameAs matrix row expects same-classification.
  • Classifications excluded from sameAs promotion do not get stealth matrix rows.
  • Curated Book, Person, Movie, and Software Application rows expose the object-target contracts needed by the generated UI POC.

Deferred

  • Some broad rows intentionally use kind: 'any' until product examples sharpen enough to split them into narrower contracts.
  • Literal/date object policy remains deferred; date-like schema fields are not represented here yet.
  • MusicPlaylist, CreativeWork, Collection, EducationalOrganization, and schema-only software compatibility targets remain schema-backed until Intuition promotes matching classifications.
  • Broader non-identity relationship rules remain revisit-able as product examples sharpen.

Stack

This branch is stacked on feat/classification-metadata-predicates, which is stacked on feat/predicate-metadata-backfill, which is stacked on feat/schema-org-vocabulary-package.

Validation Run

  • packages/classifications: bun run check
  • packages/classifications: bun run test
  • packages/classifications: bun run typecheck
  • packages/classifications: bun run build
  • root: bun run build
  • root: bun run typecheck
  • root: bun run test
  • root: bun run check

@jonathanprozzi
jonathanprozzi force-pushed the feat/classification-metadata-predicate-matrix branch from 806c593 to b0ab3b1 Compare June 9, 2026 18:29
@jonathanprozzi
jonathanprozzi force-pushed the feat/classification-metadata-predicates branch from f6bcdef to c6ddb76 Compare June 9, 2026 18:34
@jonathanprozzi
jonathanprozzi force-pushed the feat/classification-metadata-predicate-matrix branch from b0ab3b1 to ded03c7 Compare June 9, 2026 18:35
@jonathanprozzi
jonathanprozzi force-pushed the feat/classification-metadata-predicates branch from c6ddb76 to 889b68d Compare June 10, 2026 14:38
@jonathanprozzi
jonathanprozzi force-pushed the feat/classification-metadata-predicate-matrix branch from ded03c7 to 488f81f Compare June 10, 2026 14:38
@jonathanprozzi
jonathanprozzi force-pushed the feat/classification-metadata-predicates branch from 889b68d to 29ae771 Compare June 11, 2026 14:16
@jonathanprozzi
jonathanprozzi force-pushed the feat/classification-metadata-predicate-matrix branch from 488f81f to 69e7b6e Compare June 11, 2026 14:16

Copy link
Copy Markdown
Member Author

Matrix coverage update:

This PR now models every currently promoted (classification, metadataPredicate) pair: 189 promoted pairs, 189 matrix rows, zero missing rows. The matrix is no longer relying on a deferred-row allowlist for current data.

Object-target policy:

  • Prefer concrete classification targets when Intuition already classifies the object, e.g. movie:director -> person.
  • Use schema-backed targets when schema.org has the concept but Intuition has not promoted it yet, e.g. listedIn -> schema.org Collection.
  • Use primitive targets for literal values, e.g. url -> primitive:url.
  • Use kind: 'any' only where the predicate is intentionally broad or still product-dependent, e.g. reference, itemReviewed, contain, linkedAccount, and use.

We intentionally do not fall back to schema.org Thing as a generic target. Thing would look more precise than any while carrying almost the same runtime behavior, and it would imply schema.org provenance where the intended Intuition object model may still be broader or product-specific.

@jonathanprozzi
jonathanprozzi marked this pull request as ready for review June 12, 2026 19:17
@jonathanprozzi
jonathanprozzi force-pushed the feat/classification-metadata-predicates branch from 29ae771 to 606e3b8 Compare June 12, 2026 19:38
@jonathanprozzi
jonathanprozzi force-pushed the feat/classification-metadata-predicate-matrix branch from f56b963 to 84f6c2e Compare June 12, 2026 19:45
@jonathanprozzi
jonathanprozzi changed the base branch from feat/classification-metadata-predicates to main June 12, 2026 19:45
@jonathanprozzi
jonathanprozzi merged commit d116f4a into main Jun 12, 2026
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