Skip to content

fix: add tie-breaker to upsertMany#553

Merged
cameri merged 5 commits intomainfrom
fix/batch-tiebreak
Apr 21, 2026
Merged

fix: add tie-breaker to upsertMany#553
cameri merged 5 commits intomainfrom
fix/batch-tiebreak

Conversation

@Anshumancanrock
Copy link
Copy Markdown
Collaborator

Description

This PR fixes a gap in EventRepository.upsertMany() for replaceable and parameterized-replaceable events.

upsert() already handled the NIP-01 tie-break rule for equal timestamps (lower lexical event_id wins), but upsertMany() only compared strictly newer timestamps. That made batch paths behave differently from single-event ingestion.

Changes in this PR:

  • Updated upsertMany() conflict condition to match upsert() semantics:
    • update when excluded.event_created_at is newer
    • OR when timestamps are equal and existing event_id is lexically greater
  • Added focused unit coverage for upsertMany():
    • returns 0 for empty input
    • applies NIP-01 tie-break logic in batch conflict updates

Related Issue

Fixes #536

Motivation and Context

Nostr replaceable events require deterministic winners when created_at ties occur. Without this fallback in upsertMany(), import/batch flows could keep a different winner than the live websocket path, which creates inconsistent relay state for the same event set.

This aligns batch behavior with existing single-event behavior and preserves protocol-consistent conflict resolution.

How Has This Been Tested?

  • Ran: npm run test:unit -- test/unit/repositories/event-repository.spec.ts
  • Verified new upsertMany tests pass:
    • returns 0 when no events are provided
    • applies NIP-01 tie-breaker in batch conflict condition
  • Confirmed generated SQL condition includes the equal-timestamp event_id fallback.

Screenshots (if appropriate):

N/A

Types of changes

  • Non-functional change (docs, style, minor refactor)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my code changes.
  • I added a changeset, or this is docs-only and I added an empty changeset.
  • All new and existing tests passed.

@coveralls
Copy link
Copy Markdown
Collaborator

coveralls commented Apr 20, 2026

Coverage Status

coverage: 74.55% (+0.07%) from 74.483% — fix/batch-tiebreak into main

@Anshumancanrock Anshumancanrock requested a review from cameri April 20, 2026 11:12
@cameri cameri requested review from Copilot and removed request for cameri April 20, 2026 11:18
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR aligns batch replaceable-event ingestion (EventRepository.upsertMany()) with single-event ingestion (upsert()) by applying NIP-01’s deterministic tie-break rule when created_at timestamps are equal.

Changes:

  • Update upsertMany()’s conflict-update condition to also update on equal timestamps when the incoming event_id is lexically smaller.
  • Add unit tests covering upsertMany([]) === 0 and verifying the generated conflict WHERE condition includes the tie-breaker.
  • Add a Changesets entry documenting the patch fix.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
src/repositories/event-repository.ts Extends upsertMany()’s ON CONFLICT update condition to match NIP-01 tie-break semantics used by upsert().
test/unit/repositories/event-repository.spec.ts Adds focused unit coverage for upsertMany() empty input and tie-breaker conflict condition.
.changeset/fix-upsertmany-tiebreak.md Records the change as a patch release note.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@cameri cameri self-assigned this Apr 21, 2026
@cameri cameri merged commit 3c78e61 into main Apr 21, 2026
14 checks passed
@cameri cameri deleted the fix/batch-tiebreak branch April 21, 2026 01:59
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.

[BUG] upsertMany misses NIP-01 tie-break when timestamps are equal

4 participants