Skip to content

Add drift fingerprint + incremental mint/supersede publishing - #1

Merged
tkuhn merged 1 commit into
mainfrom
drift-fingerprint-supersede
Jul 6, 2026
Merged

Add drift fingerprint + incremental mint/supersede publishing#1
tkuhn merged 1 commit into
mainfrom
drift-fingerprint-supersede

Conversation

@tkuhn

@tkuhn tkuhn commented Jul 6, 2026

Copy link
Copy Markdown

Problem

Publishing was append-only. mint_publish skipped any term already in the id-map keyed solely on its old id, so a change to an already-published nanopub — whether to its content or to a batch-level wrapper (template, dcterms:isPartOf, nanopub-type, license) — was never detected or re-issued.

What this adds

A semantic drift fingerprint and an incremental publisher that acts on it.

  • fingerprint.py — a key-independent SHA-256 over the identity-defining inputs only: the URDNA2015-canonicalized assertion plus suggester/derived_from/license/introduces/nanopub-type/template. Computed on the placeholder form (subject = …/~~~ARTIFACTCODE~~~) so the thing URI never feeds its own hash. Excludes the build timestamp, signature and blank-node/order noise (no-op tier) and the signing key / toolchain (build-provenance tier), so a key rotation cannot masquerade as content drift.
  • idmap.py — fourth fingerprint column; still reads legacy 3-column files (empty fingerprint).
  • incremental.pypublish_incremental(): per term, mint (new), skip (fingerprint unchanged), or supersede (drifted). A superseded term is re-stated against its existing fixed thing URI in a nanopub that npx:supersedes the recorded one, so the term keeps its identity across versions (only the nanopub URI advances). Legacy rows without a fingerprint are backfilled as a baseline, not mass-superseded.
  • cli/mint_publish.py — builds a matching SupersessionBuilder, drives publish_incremental, writes minted and superseding nanopubs by their own artifact code, and persists fingerprints in the id-map.

Behavior

State Condition Action
new absent from id-map mint defining nanopub, record fingerprint
unchanged fingerprint matches skip
drifted fingerprint differs supersede against fixed thing URI, repoint id-map
legacy fingerprint empty (3-col row) backfill baseline, skip, warn

Tests

test_fingerprint.py, test_incremental.py, and additions to test_idmap.py / test_cli_mint_publish.py cover determinism, cosmetic/no-op invariance, content and each wrapper field moving the fingerprint, key-independence, the mint/skip/supersede/backfill decisions, and the CLI end-to-end (superseding .trig with the right npx:supersedes and a repointed id-map). Full suite: 120 passed.

Not included

  • Downstream biochementity-vocabulary still pins v0.2.1; consuming this needs a release + pin bump there (no Makefile change — same CLI flags).
  • Not proposed to eu-parc yet.

🤖 Generated with Claude Code

Publishing was append-only: mint_publish skipped any term already in the
id-map keyed solely on its old id, so a change to an already-published
term -- whether to its content or to a batch-level wrapper (template,
part-of, nanopub-type, license) -- was never detected or re-issued.

Add a semantic drift fingerprint and an incremental publisher that acts
on it:

- fingerprint.py: a key-independent SHA-256 over the identity-defining
  inputs only (URDNA2015-canonicalized assertion + suggester/derived_from
  + license/introduces/nanopub-type/template), computed on the placeholder
  form so the thing URI never feeds its own hash. Excludes the build
  timestamp, signature and blank-node/order noise (no-op tier) and the
  signing key/toolchain (build-provenance tier), so a key rotation cannot
  read as content drift.
- idmap.py: fourth `fingerprint` column; reads legacy 3-column files.
- incremental.py: publish_incremental() -- per term, mint (new), skip
  (fingerprint unchanged), or supersede (drifted) against the existing
  fixed thing URI so the term keeps its identity across versions. Legacy
  rows without a fingerprint are backfilled as a baseline, not
  mass-superseded.
- cli/mint_publish.py: build a matching SupersessionBuilder, drive
  publish_incremental, write minted and superseding nanopubs by their own
  artifact code, and persist fingerprints in the id-map.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tkuhn
tkuhn merged commit 1d9811a into main Jul 6, 2026
3 checks passed
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