Skip to content

fix(prompts): restore soft-deleted prompts on upsert match instead of skipping#2583

Open
byteclimber wants to merge 1 commit into
mainfrom
fix/prompts-upsert-restore-soft-deleted
Open

fix(prompts): restore soft-deleted prompts on upsert match instead of skipping#2583
byteclimber wants to merge 1 commit into
mainfrom
fix/prompts-upsert-restore-soft-deleted

Conversation

@byteclimber

Copy link
Copy Markdown
Contributor

Problem

upsertPrompts (src/support/prompts-storage.js) built its existence lookup without a status filter, so it matched soft-deleted rows — then dropped any soft-deleted match entirely:

if (match && match.status !== 'active') {
  continue; // no insert, no update, no restore
}

Re-importing an identical prompt silently no-oped while the API still returned 201 with created:0 / skipped:N. A brand left with only soft-deleted prompts could never re-create identical prompts — the import dedup matched the deleted ghosts and skipped.

Observed in production

Brand 019e92a2-…40 (ZEE): GET /promptstotal:0, GET /prompts?status=deletedtotal:817. Every re-import returned 201 but wrote nothing. (The 817 rows were restored out-of-band; this PR fixes the cause.)

Fix

Replace skip-on-deleted-match with restore-on-match: a matched row now flows into the update path, which sets status back to 'active' (via row.status, default 'active') and refreshes its fields. Genuinely new prompts still insert. This makes re-import idempotent and self-healing for soft-deleted rows.

Tests

  • Flipped the two unit tests that previously asserted the silent-skip behavior to assert restore-on-match (update back to active, targeting the existing row by uuid, no insert).
  • Full prompts-storage suite passes (124 tests).

Risk

Low. Behavior change is confined to the deleted-match branch; the active-match and new-insert paths are unchanged. Restoring updates existing rows rather than inserting, so it cannot create duplicates.

🤖 Generated with Claude Code

… skipping

upsertPrompts built its existence lookup without a status filter, so it
matched soft-deleted rows, then dropped any soft-deleted match entirely
(no insert, no update, no restore). Re-importing an identical prompt
silently no-oped while the API still returned 201 with created:0/skipped:N.
A brand left with only soft-deleted prompts (e.g. ZEE: 0 active / 817
deleted) could never re-create identical prompts.

Replace the skip-on-deleted-match with restore-on-match: a matched row is
now updated, which sets status back to 'active' (via row.status, default
'active'), restoring the prompt and refreshing its fields. Inserts still
happen only for genuinely new prompts.

Updated the two unit tests that previously asserted the silent-skip
behavior to assert restore-on-match (update back to active, no insert).

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

codecov Bot commented Jun 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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