Skip to content

feat(migrate): id migration with inline cross-reference resolution - #2

Merged
GertjanBisschop merged 1 commit into
eu-parc:mainfrom
knowledgepixels:feat/id-migration
Jun 23, 2026
Merged

feat(migrate): id migration with inline cross-reference resolution#2
GertjanBisschop merged 1 commit into
eu-parc:mainfrom
knowledgepixels:feat/id-migration

Conversation

@tkuhn

@tkuhn tkuhn commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

What

Adds the one-time identifier migration: turn an existing vocabulary whose terms reference each other by their old ids into trusty-artifact-code defining nanopubs, rewriting the inter-term references to the new thing URIs.

This is nanopub-java's np sign -r ("resolve cross-nanopub references") pattern, reimplemented for nanopub-py: a Resource→IRI rewrite over each assertion, plus the ordering that makes it sound.

How

  • references.py — detect inter-term references; cycle-aware topological ordering (order_terms); split_references classifies each reference as resolve-inline / defer (in-batch back-edge) / dangling (target neither minted nor in the batch — kept with its old id and reported).
  • migrate.py (migrate_terms) — mint each term's defining nanopub in dependency order with acyclic references resolved to new thing URIs inline; then publish a superseding nanopub for each held-back cyclic link (e.g. symmetric isIsomerOf). Resumable via the id-map.
  • cli/migrate.pypubmate-migrate. cli/_signing.py — shared signing-material resolution; mint-publish refactored onto it.

A reference can be baked into a defining nanopub only if its target is already minted (fixed artifact code), which topological order guarantees for all acyclic edges; genuine cycles have no single-pass fixed point, so they go through superseding.

Tests & validation

  • Unit tests: ordering (acyclic, 2-/3-cycles, self-ref, determinism), splitting (resolve/defer/dangling), the orchestrator (inline resolution, cycle→supersede, idempotent re-run), and the CLI. Full suite: 81 passed.
  • Validated end-to-end (dry-run) on a real 879-term vocabulary: 879 defining + 21 superseding nanopubs, 879 id-map entries, 0 errors; the 21 deferred edges are exactly the symmetric isIsomerOf cycles, and every other inter-term link resolved to a new RA… URI. (It also flagged 7 dangling isMetaboliteOf references to 3 absent terms — a source-data issue, handled gracefully.)

Add the one-time migration from old self-referential ids to nanopub-based ids,
the np-sign-"-r" pattern reimplemented for nanopub-py:

- references.py: detect inter-term references, cycle-aware topological ordering
  (order_terms), and split_references classifying each reference as resolve-
  inline / defer (in-batch back-edge) / dangling (unknown target, kept + warned).
- migrate.py: orchestrator that mints defining nanopubs in dependency order with
  acyclic references resolved to new thing URIs inline, then publishes
  superseding nanopubs for the deferred cyclic links (e.g. symmetric isIsomerOf).
- cli/migrate.py: pubmate-migrate CLI (resumable via the id-map).
- cli/_signing.py: shared signing-material resolution; mint-publish reuses it.

Tests cover ordering (acyclic, 2-/3-cycles, self-ref, determinism), splitting
(resolve/defer/dangling), the orchestrator (inline resolution, cycle->
supersede, idempotent re-run), and the CLI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@GertjanBisschop GertjanBisschop left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks @tkuhn.

@GertjanBisschop
GertjanBisschop merged commit 6682260 into eu-parc:main Jun 23, 2026
@tkuhn
tkuhn deleted the feat/id-migration branch June 24, 2026 06:54
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.

2 participants