Skip to content

Withdraw duplicate semantics created by past UUID-generation race condition #213

Description

@knowledge-graphlet

Summary

InferredResultsWriter detects duplicate semantics on the Inferred definition pattern and Inferred Navigation Pattern (and logs a WARN with the canonical and duplicate NIDs), but it currently leaves the duplicates in place. We should provide a one-shot cleanup task that writes a new State.WITHDRAWN version on each duplicate semantic, leaving the canonical NID active.

Background

InferredResultsWriter#findCanonicalSemanticNid (reasoner-service/.../InferredResultsWriter.java#L604-L678) recomputes the deterministic UUID via UuidT5Generator.singleSemanticUuid(pattern, component.publicId()), picks the matching NID as canonical, and lists the rest as duplicates. The trailing log line is:

Found N duplicate semantic(s) ... Canonical UUID: ..., Canonical NID: ..., Duplicate NIDs: [...]. These duplicates were likely created by a past race condition in UUID generation. Consider running a cleanup task to remove the duplicates.

That cleanup task does not yet exist. This issue tracks adding it.

Observed duplicates (from a recent classifier run)

Pattern Component Canonical UUID Canonical NID Duplicate NIDs
Inferred definition pattern Definition b4673aa7-9392-5faf-b862-7337592976cc 945100050 [939524310]
Inferred Navigation Pattern Definition 96a78a7c-4cf2-521b-9829-3cb2c7c84185 1012208926 [1006633174]
Inferred definition pattern Preferred 92ebe328-80a0-55ea-be30-a9327adb8c32 945100051 [939524118]
Inferred Navigation Pattern Preferred 51374140-f539-5e53-a96c-183ed8f7a7d5 1012208927 [1006632982]
Inferred definition pattern Fully qualified name a5c2ba0a-6582-5663-8a5f-fa525bdbac12 945100052 [939524374]

These five rows make a good fixture for verifying the cleanup task end-to-end.

Proposed approach

  1. New cleanup task (e.g. WithdrawDuplicateInferredSemanticsTask) in reasoner-service, runnable both as a TrackingCallable and from a CLI entry point.
  2. Discovery: walk every component referenced by the inferred-definition and inferred-navigation patterns, call the same findCanonicalSemanticNid logic, and collect (canonicalNid, [duplicateNids]) pairs. Factor the existing private method out so the writer and the cleanup task share one implementation.
  3. Withdrawal: for each duplicate NID, open a transaction and write a new SemanticVersion whose STAMP has State.WITHDRAWN, copying field values from the latest version. Do not modify the canonical NID.
  4. Idempotence: if the latest version of a duplicate is already WITHDRAWN, skip it and count it as already-withdrawn — re-running the task must be a no-op.
  5. Reporting: log a single summary line per pattern (withdrew N, skipped M already-withdrawn, K canonical untouched) plus per-NID DEBUG entries; return a structured result the caller can assert against in tests.
  6. Dry-run flag: the task should accept a dryRun parameter that performs discovery and logs the plan without writing.

Acceptance criteria

  • Running the task on a database containing the five duplicates above produces five WITHDRAWN versions, one per duplicate NID, with the canonical NIDs unchanged.
  • A second run of the task is a no-op (logs five "already withdrawn", writes nothing).
  • After the task runs, a subsequent classifier run no longer emits the Found N duplicate semantic(s) warning for these patterns.
  • Unit/integration test covers: canonical-only (no-op), one duplicate (withdraws), already-withdrawn (skips), wrong-pattern semantic (does not touch — that is a separate corruption case the existing code already logs as ERROR).
  • dryRun=true writes nothing and the summary log matches a real run's plan.

Out of scope

  • Any concept-level (as opposed to semantic-level) changes — the duplicates are extra semantic versions; the referenced concepts stay active.
  • The "wrong pattern" corruption case logged at ERROR in the same method — that needs a separate investigation.

Self-Service

I would be willing to fix this issue.

Activity

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

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions