Skip to content

[OPIK-8050] [FE] fix: paginate prompt version history and fix version labeling - #8140

Merged
natagh23 merged 9 commits into
mainfrom
nata/OPIK-8050/prompts-versions-check
Sep 4, 2026
Merged

[OPIK-8050] [FE] fix: paginate prompt version history and fix version labeling#8140
natagh23 merged 9 commits into
mainfrom
nata/OPIK-8050/prompts-versions-check

Conversation

@natagh23

@natagh23 natagh23 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Details

Version history on the Prompt tab only ever loaded the first 25 versions (a single useQuery(page=1,size=25)), so older versions were unreachable, and a deep link to one silently fell back to the latest version while still showing a stale vN label. This switches to a paginated usePromptVersionsByIdInfinite hook and wires the lazy-load already built into VersionHistoryTimeline, and replaces client-computed index labels (v${total-idx}) with the backend's persistent version_number (falling back to commit for pre-migration rows that never got backfilled). This also fixes OPIK-8189, where the Compare sheet recomputed labels from whatever was locally loaded instead of the true total, mislabeling versions past the first page.

Along the way, a few related issues surfaced and are fixed in the same diff:

  • A stale/crafted activeVersionId query param (now fetched independently of the current prompt's own list) could render a different prompt's content — guarded so it always falls back to prompt.latest_version instead.
  • The new hook's cache key wasn't matched by the existing mutation-invalidation predicates (create/delete/deploy a version), so the sidebar went stale after writes — aligned the key shape so those predicates pick it up.
  • DeployToEnvironmentMenu received the raw, unguarded activeVersionId instead of the ownership-checked version — could deploy-to-environment against the wrong prompt's version.
  • A race between the mutation's cache-invalidation refetch and the new deep-link auto-pagination effect could duplicate a row in the sidebar — fixed by gating on the broader isFetching flag instead of just isFetchingNextPage.
  • The Diff dropdown's "Compare against" list was capped at whatever page was already loaded (e.g. 24 of 31 options on a 32-version prompt) — it now auto-paginates through every version while open, with a loading indicator.

Change checklist

  • User facing
  • Documentation update

Issues

  • Resolves OPIK-8050
  • Resolves OPIK-8189

AI-WATERMARK

AI-WATERMARK: yes

  • Tools: Claude Code
  • Model(s): Claude Sonnet 5
  • Scope: Full implementation (frontend TypeScript/React changes across prompt version history, deploy menu, compare dialog, diff menu) and regression testing, under human direction and review at each step.
  • Human verification: Reviewed and directed by Natalia across multiple rounds — approved/rejected specific fixes (e.g. reverted an eager-loading approach and a DEP-03 fix attempt after discussion), verified live against a local dev instance for each area of the test plan.

Testing

Verified against a local dev instance (backend :8080, frontend :5174) using Playwright, plus npx tsc --noEmit and npx eslint on all touched files (all clean).

Scenarios validated:

  • Version history pagination: >25 and ≤25 version prompts, scroll-triggered loading, no infinite-loop regressions.
  • Deep-linking: link to an old (unloaded-page) version renders and highlights correctly; nonexistent/deleted version id falls back to latest with no infinite loop; a different prompt's version id never renders foreign content; manually selecting a version while auto-pagination is chasing a deep link doesn't race.
  • Version-create races: creating a new version while a background refetch/auto-pagination effect is in flight no longer duplicates a sidebar row (reproduced pre-fix, confirmed fixed post-fix across repeated trials).
  • Labels: match the backend's version_number (or commit fallback) consistently across the sidebar, main panel, Compare dialog, and Deploy-to "Currently vN" tooltip.
  • Deploy-to-environment: deploy/remove/remove-all update badges immediately; correct label for an environment owned by a version outside the initially-loaded page (once loaded by the Diff-menu fix's shared pagination).
  • Diff/Compare: correct base/diff preselection and labels; chat-structured diff mode and word-level highlighting; dialog state resets correctly across repeated open/close with different starting versions.
  • Diff menu pagination: opens and auto-loads every version (was previously capped at the first page); loading spinner shows only while genuinely fetching another page, not on unrelated background polls; immediate selection before pagination completes works with no console errors.
  • Permissions/edge states: hard refresh with activeVersionId in the URL shows the skeleton then renders correctly with no flash; resizing across the xl breakpoint keeps mobile/desktop selection in sync.

Not run: a read-only/no-permission role (local dev is single-admin with no RBAC configured) and the Playground-load flow's own confirm-dialog/navigation timing (that code is untouched by this diff; the touched code feeding into it was verified via code review instead of fighting flaky dropdown-open timing in automation).

Documentation

N/A — no public API or documented behavior changed beyond the bug fixes described above.

… labeling

Version history on the Prompt tab only ever loaded the first 25 versions
(single page, client-computed vN labels), so older versions were
unreachable and a deep link to one silently fell back to the latest
version while still showing a stale label. Switches to a paginated
usePromptVersionsByIdInfinite hook, wires the lazy-load already built
into VersionHistoryTimeline, and replaces index-derived labels with the
backend's persistent version_number (falling back to commit when a
pre-migration row has none). Also fixes OPIK-8189: the Compare sheet
recomputed labels from whatever was locally loaded instead of the true
total, mislabeling versions past the first page.

Guards a stale/crafted activeVersionId from rendering a different
prompt's content, aligns the new hook's cache key with existing
mutation invalidations so the sidebar refreshes after writes, and
extends the Diff dropdown to auto-paginate so "Compare against" isn't
capped at the first loaded page either.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

⏱️ pre-commit per-hook timing

Hook Description Result Duration
🌐 typecheck — frontend Whole-project tsc type check 31.15s
🌐 eslint — frontend Lint + autofix JS/TS 6.65s
⚙️ actionlint — github workflows Lint GitHub Actions workflows 1.29s
🐍 mypy — python sdk Static type check 1.28s
🌈 zizmor — github workflows security Security-scan GitHub Actions workflows 0.05s
🐍 fix end of files — python sdk Ensure files end in a newline 0.04s
🐍 trim trailing whitespace — python sdk Strip trailing whitespace 0.03s
🐍 ruff-format — python sdk Format Python code (ruff) 0.01s
🐍 ruff — python sdk Lint + autofix Python (ruff) 0.01s
Total (9 ran) 40.51s
⏭️ 35 skipped (no matching files changed)
Hook Description Result
🤖 trim trailing whitespace — optimizer Strip trailing whitespace ⏭️
🤖 fix end of files — optimizer Ensure files end in a newline ⏭️
🤖 check yaml — optimizer Validate YAML syntax ⏭️
🤖 check json — optimizer Validate JSON syntax ⏭️
🤖 check toml — optimizer Validate TOML syntax ⏭️
🤖 check for added large files — optimizer Block large files (>1MB) ⏭️
🔐 detect private key — optimizer Block committed private keys ⏭️
🤖 check for merge conflicts — optimizer Block merge-conflict markers ⏭️
🤖 check for case conflicts — optimizer Block case-only name clashes ⏭️
🤖 pyupgrade — optimizer Modernize Python syntax ⏭️
🤖 ruff — optimizer Lint + autofix Python (ruff) ⏭️
🤖 ruff-format — optimizer Format Python code (ruff) ⏭️
🤖 mypy — optimizer Static type check ⏭️
📓 nbstripout — optimizer notebooks Strip notebook output ⏭️
📝 markdownlint — optimizer Lint Markdown ⏭️
🔤 codespell — optimizer Fix common misspellings ⏭️
📊 radon cc — optimizer Cyclomatic-complexity gate ⏭️
📊 radon raw — optimizer Raw size metrics gate ⏭️
📊 xenon — optimizer Fail on complexity thresholds ⏭️
📊 lizard — optimizer Cyclomatic-complexity gate ⏭️
🧹 vulture — optimizer Find dead code ⏭️
🛡️ trim trailing whitespace — guardrails Strip trailing whitespace ⏭️
🛡️ fix end of files — guardrails Ensure files end in a newline ⏭️
🛡️ ruff — guardrails Lint + autofix Python (ruff) ⏭️
🛡️ ruff-format — guardrails Format Python code (ruff) ⏭️
🛡️ mypy — guardrails Static type check ⏭️
⚓ helm-docs Regenerate Helm chart README ⏭️
block non-public FE plugins Block non-public FE plugins ⏭️
☕ spotless — java backend Format Java code ⏭️
🧪 pre-commit wrapper smoke tests Self-test the wrapper scripts ⏭️
🧪 rebaseline script tests Self-test the changelog re-baseline script ⏭️
📘 eslint — typescript sdk Lint + autofix JS/TS ⏭️
📘 typecheck — typescript sdk Whole-project tsc type check ⏭️
🐳 hadolint — dockerfiles Lint Dockerfiles ⏭️
🛡️ semgrep — java backend sql Block SQL injection-prone string formatting ⏭️

@CometActions

CometActions commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

This change looks worth a test.

Two things here and both land on the same untested screen. The version-history sidebar is now an infinite query (25/page, sentinel auto-load, and the Diff and "Deploy to environment" menus force-load the remaining pages when opened), and every version label switches from the positional v{total - idx} to the backend's version_number. Nothing in the estate ever gets past 4 versions: prompt-library-smoke.spec.ts asserts v1/v2 and prompt-playground-save.spec.ts asserts v4, so no spec loads a second page, opens the Diff or Deploy menu, or looks at the compare dialog — which is where the old labelling was actually visibly wrong, since ComparePromptVersionDialog re-derived vN from versions.length (the 25 loaded) and disagreed with the sidebar on a 30-version prompt. A 30-version prompt is easy to seed through the SDK, so this is testable as-is.

Would target prompts.version-history, prompts.compare-versions.

What it would check
  1. Seed one prompt with ~30 versions via the SDK, open its detail page, and check the sidebar labels the newest as v30 and initially lists only the first page
  2. Scroll the version history to the bottom until it reaches v1 — no duplicated, skipped or out-of-order labels as pages load, and the 30s background refetch does not double-append a row
  3. Open the Diff menu and the "Deploy to environment" menu and confirm both offer versions older than the first page; deploy an old version to an environment and check the menu's "Currently vN" names that version
  4. Open the compare dialog against a version from a later page and confirm both sides carry the same vN the sidebar shows
  5. Deep-link ?activeVersionId=: the sidebar should keep paging until v3 is loaded and highlighted; then substitute a version id belonging to a different prompt and confirm the page falls back to the latest version instead of rendering the other prompt's content

Deploying a test environment for this PR and exploring it — results will follow in a comment.

areas: prompts

Run

Advisory, from the QA test radar. Nothing here blocks this PR, and anything it proposes is a draft for review.

Re-checked after a push on 03 Sep 22:02 UTC.

@CometActions CometActions added the test-environment Deploy Opik adhoc environment label Sep 3, 2026
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

🔄 Test environment deployment process has started

Phase 1: Deploying base version 2.2.50-6530 (from main branch) if environment doesn't exist
Phase 2: Building new images from PR branch nata/OPIK-8050/prompts-versions-check
Phase 3: Will deploy newly built version after build completes

You can monitor the progress here.

Comment thread apps/opik-frontend/src/v2/pages/PromptPage/PromptTab/PromptTab.tsx Outdated
Comment thread apps/opik-frontend/src/v2/pages/PromptPage/PromptTab/PromptTab.tsx Outdated
Comment thread apps/opik-frontend/src/v2/pages/PromptPage/PromptTab/PromptTab.tsx Outdated
Comment thread apps/opik-frontend/src/v2/pages/PromptPage/PromptTab/PromptTab.tsx
Comment thread apps/opik-frontend/src/api/prompts/usePromptVersionsByIdInfinite.ts Outdated
Comment thread apps/opik-frontend/src/api/prompts/usePromptVersionsByIdInfinite.ts
Comment thread apps/opik-frontend/src/api/prompts/usePromptVersionsByIdInfinite.ts
@CometActions

Copy link
Copy Markdown
Collaborator

Test environment is now available!

To configure additional Environment variables for your environment, run [Deploy Opik AdHoc Environment workflow] (https://github.com/comet-ml/comet-deployment/actions/workflows/deploy_opik_adhoc_env.yaml)

Access Information

The deployment has completed successfully and the version has been verified.

@CometActions

CometActions commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Explored this PR on its own test environment.

Worked all 5 ranked items in triage.json. 3 work, 1 suspicious, 1 works-with-a-caveat. Everything is UI-reachable; GET /v1/private/prompts/{id}/versions is unchanged and the paging/labelling is entirely client-side, so the API alone shows nothing — every assertion below is on the page.

Per-item results
# Item Verdict What I saw
1 Sidebar labels newest as v30, lists only the first page works 30-version prompt: header active-version-label = v30, sidebar renders exactly 25 rows (v30v6) off one page=1&size=25 request
2 Scroll to v1 — no dupes/skips/out-of-order; 30s refetch doesn't double-append works Sentinel auto-loaded page 2 → exactly 30 rows, v30…v1, 0 duplicates, order identical to v30..v1. Held the page through two 30s background refetches (7 versions requests total): count stayed 30, dupes [], order unchanged
3 Diff and Deploy menus offer versions past the first page; deploy an old version, check "Currently vN" suspicious (high) Diff menu: correct — 29 items v29…v1, current v30 excluded, forces page 2 within 400 ms. Deploy menu: does not force-load at all. v3 is deployed to development, yet the menu shows no "Currently vN" — and held open 10 s it fires zero page-2 requests. Fixed at head; see below
4 Compare dialog carries the same vN as the sidebar works From v30, Diff → v2 (page 2) ⇒ sheet titled "Compare v2 → v30", both panes showing marker2 / marker30, and the only v\d+ labels in the sheet are v2/v30. From a v3 deep link, Diff → v30 ⇒ "Compare v30 → v3"
5 Deep-link ?activeVersionId=; then a foreign prompt's version id works v3 (page 2) deep link: page keeps paging to 30, v3 active, content marker3, and the v3 row carries ring-primary. A version id belonging to a different prompt falls back to v30 — no foreign content, heading unchanged, v30 highlighted. A syntactically-valid non-existent id behaves the same. Caveat below

3 — Deploy menu never force-loads its remaining pages (suspicious, high confidence)

Reproduced 3×, cleanly, on one page load with the network instrumented:

  1. Load /default/projects/{proj}/prompts/{promptId} (30 versions, v3 deployed to development). Sidebar = 25 rows. One request: …/versions?…&size=25&page=1.
  2. Open Deploy to and hold 10 s → menu reads production / staging / development / Manage environments. No page=2 request. No "Currently vN" on development. (evidence/07-deploy-menu-no-forceload.png)
  3. Escape, open Diff, hold 3 s → page=2 fires immediately, sidebar goes 25 → 30.
  4. Escape, reopen Deploy to → now reads development · **Currently v3**. (evidence/08-deploy-menu-after-diff-forceload.png)

Expected: opening the Deploy menu pages until every version is loaded, so the owner label is right on first open. Observed: it only becomes right if something else happened to load page 2 first. The label logic itself is correct — Currently ${version_number ?? commit} is in the deployed bundle and it printed v3, matching the sidebar. It is only the force-load that is missing.

This is fixed on the PR branch. Commit 60f0e337 adds onOpenChange?/isLoadingMore? to DeployToEnvironmentMenu and changes <DropdownMenu><DropdownMenu onOpenChange={onOpenChange}>, and folds isDeployMenuOpen into the single paging effect in the extracted usePromptVersionHistory. So this is a defect in what is deployed, not an outstanding defect in the PR — but it is exactly the silent-wrongness a reviewer would want a test pinned to, because nothing errors: the menu just quietly omits the owner label, and a user reading it concludes no version is deployed to that environment.

Action for the reader: redeploy pr-8140.dev.comet.com from head (9562adfb) and re-check item 3. Items 3, 4 and 5 all touch code that changed after the deployed commit, so re-running them against head is the only way to confirm head is clean.

3 flows look worth a permanent test:

  • prompts.version-history — Version history sidebar pages through a 30-version prompt without dupes, skips or reordering
  • prompts.compare-versions — Diff menu and compare dialog reach versions past the first page and agree with the sidebar's labels
  • prompts.version-history — Deploy-to-environment menu names the deployed version even when it is on a later page

Writing the spec now; a draft PR will follow.

Test env · Run

Advisory, from the QA test radar. Nothing here blocks this PR, and anything it proposes is a draft for review.

Re-explored after a push on 03 Sep 23:01 UTC.

…ct orchestration hook

- Gate the deep-link, diff-menu, and scroll-sentinel pagination triggers on
  isFetching/isError (not just isFetchingNextPage) to stop a permanently
  failing page fetch from hammering the backend in an infinite retry loop.
- Reject version_type=mask when resolving the active version by id, both for
  rendering and for the playground-load fetch, since the by-id lookup isn't
  scoped the way the paginated list is.
- Fix the mobile version dropdown to highlight the resolved active version
  instead of the raw query param.
- Share one fetcher between usePromptVersionsById and
  usePromptVersionsByIdInfinite instead of duplicating the request logic.
- Reuse an already-loaded version from the paginated list instead of issuing
  a redundant by-id fetch when switching between loaded versions.
- Extract version-history orchestration (pagination, selection, active
  version resolution) out of PromptTab into usePromptVersionHistory.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Comment thread apps/opik-frontend/src/v2/pages/PromptPage/PromptTab/usePromptVersionHistory.ts Outdated
…edupe pagination triggers

- DeployToEnvironmentMenu now auto-paginates while open (mirroring the Diff
  menu) so "Currently vN" resolves for owners on unloaded pages instead of
  silently omitting them.
- Replace remaining positional v{total-idx} labels with the backend's
  version_number/commit in usePromptVersionLabel, usePromptVersionsWithLabels,
  and PromptLibraryMenu, so labels stay correct across Playground, trace
  details, prompt select boxes, Optimizations, and Agent Runner even after
  older versions are deleted.
- Merge the deep-link, Diff-menu, and Deploy-menu pagination triggers into a
  single effect so at most one fetchNextPage() fires per render — two
  separate effects both firing in the same render could cancel each other
  via TanStack Query's default cancelRefetch behavior.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ination

Inject the already-resolved activeVersion into the versions array passed to
ComparePromptVersionDialog when it isn't yet in the paginated list. Without
this, opening Diff while a deep-linked version's page was still loading made
the dialog silently fall back to the newest loaded version instead of the
one actually requested.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@CometActions

CometActions commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Proposed a permanent test for this change.

Test proposal — opik#8140 ([OPIK-8050] [FE] paginate prompt version history and fix version labeling)

No pull request was opened

Not because of the specs — they are written, committed and run. The job's
GitHub token cannot create pull requests: both gh pr create and
POST /repos/comet-ml/opik/pulls answer

403 Resource not accessible by integration
X-Accepted-Github-Permissions: pull_requests=write

for every token in this environment (GH_TOKEN, OVERRIDE_GITHUB_TOKEN,
DEFAULT_WORKFLOW_TOKEN — all resolve to github-actions[bot]). contents:write
is present, so the branch is pushed and complete; only the PR call is blocked.

To open it (as a draft, no reviewers, never ready-for-review), from a context with pull-requests: write:

gh pr create --repo comet-ml/opik --draft \
  --base nata/OPIK-8050/prompts-versions-check \
  --head comet-qa-bot/OPIK-8050/prompt-version-history-pagination-specs \
  --title "[OPIK-8050] [QA] Proposed e2e specs from the #8140 exploration: paginated prompt version history and its version labels" \
  --body-file pr-body.md

Re-running this flow will not detect a prior draft (there is none to detect), so
whoever opens it should keep the marker line in the body.

The specs, and how each verified

All three run against $OPIK_BASE_URL = https://pr-8140.dev.comet.com (OSS, workspace default).
Command: npx playwright test tests/prompts/prompt-version-history-pagination.spec.ts --reporter=list.
Run twice; identical both times.

# Spec (all in tests/prompts/prompt-version-history-pagination.spec.ts) Capability Result
1 Version history pages through all 30 versions once, in order (v30…v1 compared as a whole list), and the 30s background refetch leaves it unchanged @cap:prompts.version-history Passed — 56.7s
2 Diff menu offers 29 items past the page boundary; compare sheet titled Compare v2 → v30 with no third version label anywhere in it @cap:prompts.compare-versions Passed — 9.7s
3 "Deploy to" menu names Currently v3 for development when v3 is on the second page @cap:prompts.version-history Failed on this environment — kept, see below

Also green: tag_lint.py60 specs checked, 1 exempt, 0 problem(s).

Why #3 is kept despite failing

pr-8140.dev.comet.com does not serve the PR head. The served bundle
(App-BXMEnoru.js) renders the Deploy dropdown as jsxs(DropdownMenu,{children:[…]})
with no onOpenChange — commit a7d83e15, the first of the PR's four commits.
The fix (60f0e337) is not deployed there.

Reproduced with the network instrumented: on a fresh load the Deploy menu fires
zero page-2 requests and shows no Currently note; open the Diff menu (which
does force-load) and reopen Deploy, and it reads development · Currently v3
with exactly one Currently note. So the assertion is correct and only the
force-load is missing — which is what the PR's own commit adds.

This is the "failed, and the app is at fault" case: it fails against a build
predating the fix. It is unverified against head 9562adf — no environment
serves that. CI on the target branch settles it; if it still fails there, drop it.

Dropped

0 of 3 candidates dropped. All three in candidates.json were strong and
verified_on_staging: true, and all three became specs.

Deliberately not written (from the exploration's own findings):

  • The positional-vs-version_number labelling divergence itself — unfalsifiable on OSS, which has no delete-prompt-version endpoint, so version_number == position always.
  • The deep-link chase burning every remaining page on an unresolvable activeVersionId — real but wasteful-not-wrong, and unchanged by this PR.
  • PromptLibraryMenu's un-paginated page:1, size:25 version list — pre-existing, out of scope.

Taxonomy

prompts.compare-versionscovered: true (t2-cuj). prompts.version-history
stays covered: true at t1-smoke (the smoke spec covers the shallow case), with
a note recording what the new spec adds. Spec added to the area's specs: list.

Gap worth filing: there is no prompts.deploy-to-environment key. Spec #3
belongs there; it is filed under version-history because inventing a key
silently breaks the coverage map. Deploying a version from that menu remains
untested either way.

Environment note

The backend at pr-8140.dev.comet.com 502'd for roughly 20 minutes during this
run (frontend kept serving). Not a product bug, but any suite pointed at that
host today will look flaky. The suite also needs OPIK_API_KEY set to any
non-empty value there: the pinned Opik TS SDK demands a key for every
*.comet.com hostname, even on this no-auth OSS install.

Run

Advisory, from the QA test radar. Nothing here blocks this PR, and anything it proposes is a draft for review.

@CometActions

Copy link
Copy Markdown
Collaborator

🌙 Nightly cleanup: The test environment for this PR (pr-8140) has been cleaned up to free cluster resources. PVCs are preserved — re-deploy to restore the environment.

@CometActions CometActions removed the test-environment Deploy Opik adhoc environment label Sep 4, 2026

@aadereiko aadereiko left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

  1. version_number is NULL for all pre-existing versions - i don't if you have considered this
  2. Background request load multiplies by the number of loaded pages. useInfiniteQuery stores the loaded pages as { pages: [...], pageParams: [...] }.
    A refetch re-fetches every loaded page, sequentially. Now combine that with what the PR carries over and adds:
  • refetchInterval: 30000 (kept from the old code) — fires every 30 seconds.
  • refetchOnWindowFocus defaults to true — fires on every tab focus.
  • Every version create / delete / deploy invalidates this key.
  • Opening the Diff or Deploy menu auto-pages through every version

useInfiniteQuery refetches every already-loaded page sequentially on any
trigger, and the Diff/Deploy menus can load many pages for large prompts —
so the prior refetchInterval/refetchOnWindowFocus multiplied request volume
by however many pages a session had loaded. Drop those from the infinite
query and instead poll the cheap prompt object (version_count) on the same
interval, invalidating the versions list only when that count actually
changes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@natagh23

natagh23 commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review!

  1. commit is safe as the fallback — DB NOT NULL since the table's first migration, server-generates one if the client omits it. Manually verified too: nulled a real version's version_number in the DB and confirmed the fallback renders correctly (no crash/blank) across sidebar, main panel, Deploy menu, Diff menu, and Compare dialog.

  2. Fixed — dropped refetchInterval/refetchOnWindowFocus from the infinite versions query (which would refetch every loaded page on each trigger) and replaced it with a poll on the already-cheap prompt object's version_count, invalidating the versions list only when that actually changes. Verified: zero periodic versions-list refetches while idle, and exactly one refetch after an externally-created version changed the count.

Comment thread apps/opik-frontend/src/v2/pages/PromptPage/PromptTab/usePromptVersionHistory.ts Outdated
The prior fix's intent comment claimed refetchOnWindowFocus was off, but
never actually set it — the default true still refetched every loaded page
on window focus, defeating the point of bounding refetch cost to actual
version_count changes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…alog resets

- usePromptVersionsByIdInfinite: getNextPageParam now treats an empty page
  as terminal instead of trusting `total`, which could loop forever if the
  two go out of sync (e.g. a concurrent delete between the count and the
  page query). Also gives the infinite-query cache key an explicit
  `view: "infinite"` marker instead of relying on the implicit (and
  breakable) "this hook never has page/size" invariant to stay distinct
  from usePromptVersionsById's key.
- usePromptVersionHistory: memoize isChasingDeepLink so a stale/nonexistent
  activeVersionId doesn't re-scan the whole (growing) version list on every
  unrelated render while it chases pages.
- ComparePromptVersionDialog: the selection-reset effect now fires only on
  the open transition (reading the rest via a ref) instead of on every
  versions/versionOptions change while already open, so a background
  refetch (pagination continuing, a version_count invalidation) no longer
  silently resets the comparison the user is looking at.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ination

ComparePromptVersionDialog previously stored the selected base/diff
PromptVersion objects as state, snapshotted on open. Combined with the
open-only reconciliation effect (added to stop background refetches from
resetting the user's selection), this meant a background refetch could
leave the dialog rendering stale content, or a removed version rendering
content that no longer exists.

Store only the selected version id in state and re-resolve the actual
version live from `versions` on every render instead: a background refetch
now keeps rendered content current, and a version that disappears from the
list resolves to undefined (renders nothing) rather than stale data — while
still not resetting the selection on harmless background changes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
anyMediaChanged alone gated the media section, unlike the Prompt/Metadata
sections which already require both baseVersion and diffVersion. Since
collectMedia falls back to empty media arrays when a version is undefined
(e.g. deleted out from under an open dialog), any media on the surviving
version read as "changed" and rendered — a one-sided comparison against a
version that no longer exists. Add the same baseVersion && diffVersion
guard already used by the other two sections.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

@aadereiko aadereiko left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM! Nice work

@natagh23
natagh23 merged commit 09e6c4e into main Sep 4, 2026
23 checks passed
@natagh23
natagh23 deleted the nata/OPIK-8050/prompts-versions-check branch September 4, 2026 17:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants