[OPIK-7791] [QA] Proposed e2e specs from the 2.2.42 → 2.2.43 release exploration - #8045
Conversation
…sions From the 2.2.42 -> 2.2.43 release exploration on staging. Three specs for flows a human verified there by hand. Two of them are RED against 2.2.43, and that is the finding: once a dataset has been versioned more than once, a filter-scoped delete or batch update does not touch the set the same filter lists. The read paths alias the item-level columns; the mutation paths still filter the raw table, whose snapshot rows get a fresh id and created_at on every version commit. Both directions reproduce - a delete by item id that removes nothing, and a created_at window the page says matches nothing that removes every row. The control test in the same file (a data.<key> filter over the same dataset) passes, which isolates the failure to column binding. The third is green: a regression guard that the experiment-comparison read reports each item authored when the item was, not when its version was cut. - tests/datasets/dataset-items-versioned-filter-scope.spec.ts (API, t3) - tests/datasets/dataset-items-select-all-delete.spec.ts (UI, t2) - tests/experiments/compare-item-timestamps.spec.ts (API, t2) - fixtures/versioned-dataset, fixtures/versioned-comparison: a dataset versioned twice without its items being re-authored, each verifying that precondition server-side before a test reads it - core/backend/client: createdAt on version and item refs, listDatasetItemsPage, commitDatasetItemVersionByTagging, listCompareItems - pom/dataset-items: filtered goto, the select-all banner, the select-all delete - coverage/taxonomy.yaml: the three specs added to their areas' specs lists; no capability flipped Generated by the release QA side flow. Needs review before merge. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
📋 PR Linter Failed❌ Missing Section. The description is missing the ❌ Missing Section. The description is missing the ❌ Missing Section. The description is missing the ❌ Missing Section. The description is missing the ❌ Missing Section. The description is missing the |
⏱️ pre-commit per-hook timing
⏭️ 43 skipped (no matching files changed)
|
| export interface DatasetItemsFilter { | ||
| field: string; | ||
| operator: string; | ||
| value: string; | ||
| type?: string; | ||
| key?: string; | ||
| } |
There was a problem hiding this comment.
Filter popover loses row identity
DatasetItemsFilter omits the required Filter.id, and goto() carries those objects into FiltersContent unchanged, so decoded deep-linked filters have undefined identities and cannot be independently edited or removed — should we serialize complete Filter objects with unique ids and frontend type/operator domains, or normalize URL filters before passing them to the editor?
Want Baz to fix this for you? Activate Fixer
Other fix methods
Prompt for AI Agents
Before applying, verify this suggestion against the current code. In
`tests_end_to_end/e2e/pom/dataset-items.page.ts` around lines 6-12, update
`DatasetItemsFilter` and the `goto()` URL-filter serialization so deep-linked filters
remain valid editor filters. Include a unique `id` and the frontend’s accepted `type`
and `operator` domains, or normalize decoded URL filters before passing them to
`initialFilters`; ensure each filter has a distinct identity so `FiltersContent` can
render, update, and remove rows independently.
| const query = opts.filters?.length | ||
| ? `?filters=${encodeURIComponent(JSON.stringify(opts.filters))}` | ||
| : ''; |
There was a problem hiding this comment.
Persisted page size breaks select-all spec
goto() serializes only filters, so the prior dataset-items-pagination-size=25 remains active when the URL omits size; all 12 matching rows render on page one, countItems() returns 12 instead of PAGE_SIZE 10, and showSelectAllBanner is false because selectedRows.length === totalCount, so selectAllMatching() cannot find the escalation button. Could we include size=10 in the navigation URL or explicitly reset the page-size state so this spec exercises cross-page selection?
Want Baz to fix this for you? Activate Fixer
Other fix methods
Prompt for AI Agents
Before applying, verify this suggestion against the current code. In
`tests_end_to_end/e2e/pom/dataset-items.page.ts` around lines 38-40, update
`DatasetItemsPage.goto()` so navigation explicitly sets the page size to 10 instead of
relying on persisted pagination state. Include `dataset-items-pagination-size=10` in the
URL (or otherwise reset the page-size state) while preserving the optional `filters`
parameter, ensuring the fixture uses multiple pages and the select-all escalation banner
appears.
| const created = await sdkClient.python.createDataset({ | ||
| project_name: project.name, | ||
| name, | ||
| description: 'filter scope across dataset versions', | ||
| items: seededIds.map((id, index) => ({ | ||
| id, | ||
| [VERSION_GROUP_COLUMN]: index % 2 === 0 ? VERSION_TARGET_GROUP : 'alpha', | ||
| input: `question ${index}`, | ||
| expected_output: `answer ${index}`, | ||
| })) as unknown as Array<Record<string, unknown>>, | ||
| }); | ||
|
|
There was a problem hiding this comment.
Setup failures leak remote datasets
tests_end_to_end/e2e/fixtures/versioned-dataset.fixture.ts:124-135 creates the remote dataset, but cleanup in tests_end_to_end/e2e/fixtures/versioned-dataset.fixture.ts:206-214 runs only after await use(ref), so any setup failure before that point leaves the dataset behind — should we register cleanup immediately after creation or wrap setup and use in try/finally, honoring shouldLeaveArtifacts and preserving the original failure if cleanup also fails?
Want Baz to fix this for you? Activate Fixer
Other fix methods
Prompt for AI Agents
Before applying, verify this suggestion against the current code. In
tests_end_to_end/e2e/fixtures/versioned-dataset.fixture.ts around lines 124-135, update
the `versionedDataset` fixture setup so the dataset created by `createDataset` is
cleaned up even if commit, validation, attachment, or `use` fails. Register cleanup
immediately after creation or wrap the entire setup and `await use(ref)` flow in a
`try/finally`, honoring `shouldLeaveArtifacts`; catch and warn on cleanup failures so
they do not replace the original setup or test failure.
Where these came from
The QA release side flow explored the 2.2.42 → 2.2.43 release by hand on
staging.dev.comet.com/opik(workspaceopik-testing). Three of the flows ahuman verified there are worth a permanent test; this PR is those three.
Generated by the release QA side flow, and it needs review before merge.
It is a draft on purpose. Nothing here has been reviewed by a person.
2.2.43(the exploration's ref — the branch iscut from that tag).
mainhas moved on since; please re-run before merging.mainonly because a PR base must be a branch and2.2.43is a tag.Two of these specs are RED, and that is the finding
dataset-items-versioned-filter-scope.spec.tsanddataset-items-select-all-delete.spec.tsfail against 2.2.43, and they fail forthe reason they were written: a filter-scoped dataset-item mutation does not
touch the set the same filter lists, once the dataset has been versioned more
than once.
dataset_item_versionscarries two column sets — the version snapshot row's(
id,created_at,created_by, …) and the item's (dataset_item_id,item_created_at, …). The read paths alias the item-level ones; the delete andbatch-update paths still filter the raw table. A snapshot row gets a fresh id
and a fresh
created_aton every version commit, so from the second version onthe two disagree and the read and the write stop describing the same rows.
Each failing test contains its own proof: the read step passes (the filter lists
exactly what it should) and the write step with the identical filter
contradicts it. No test here asserts which column is the correct one — only that
the two agree.
The control test in the same file passes. It drives the same endpoint over
the same doubly-versioned dataset with a
data.<key>filter and deletes exactlythe right rows, which is what makes the failures a statement about column
binding rather than about the endpoint, the fixture, or the environment.
If the team would rather not carry red specs in the estate, the right move is to
hold this PR against the fix, not to weaken the assertions. None of them are
.skipped.Per spec
1.
tests/datasets/dataset-items-versioned-filter-scope.spec.ts—@t3-nightly@area:datasetsAPI-level, four tests. Extends
dataset-items-filter-scope.spec.ts, whichcovers these endpoints only over
data.<key>on a single-version dataset —both of which keep the two column sets in agreement, so it passes without ever
distinguishing them.
data.<key>filter still deletes exactly the items it lists@cap:datasets.bulk-delete-items@cap:datasets.bulk-delete-itemscreated_atwindow that lists no rows removes no rows@cap:datasets.bulk-delete-items@cap:datasets.filter-scoped-batch-updateWhat the failures actually printed:
GET items?filters=[id = <item>]returns that item.POST /v1/private/datasets/items/deletewith the identical filter answers204and removes nothing — all 15 seeded items are still there, targetincluded.
item was authored and strictly before the version was committed, so
GET items?filters=[created_at > T]returnstotal: 0: the page a user wouldread says the filter matches nothing. The delete with that same filter
removed all 15 items, including the 3 bystanders the filter could not have
matched. Irreversible,
204, no error.PATCH /v1/private/datasets/items/batchfiltered byid = <item>answers204and tags nothing, whileGETwith that filterstill returns the row.
2.
tests/datasets/dataset-items-select-all-delete.spec.ts—@t2-cuj@area:datasetsUI, one test,
@cap:datasets.view-items+@cap:datasets.bulk-delete-items.FAIL, and this is the half that makes the defect user-reachable.
Every existing dataset-items spec ticks rows one at a time, which stages a draft
the user reviews.
DatasetItemsActionsPanelsends an id list unlessisAllItemsSelectedis set, and the only control that sets it is the"Select all N items?" banner — which only renders when the filtered set spans
more than one page. Every other spec in the estate stays under the default
10-row page, so nothing has ever reached this path. Once set, the request is the
filter-scoped one and commits its own version immediately, with no draft to
review.
The run reached the delete with everything before it green: the grid rendered
Showing 1-10 of 12, the banner escalated toAll 12 items are selected, andthe delete request was accepted with
204. Then 10 rows were still onscreen, the API still held all 15 items, and the new version recorded
items_deleted: 0— over a success toast. The spec deliberately does not asserton that toast: rendering a success toast over an unchanged table is the failure.
Three of the fifteen seeded items are outside the filtered prefix, so
"the 12 rows went" cannot be satisfied by a delete that emptied the dataset.
3.
tests/experiments/compare-item-timestamps.spec.ts—@t2-cuj@area:experimentsAPI-level, one test,
@cap:experiments.compare-side-by-side. PASS — aregression guard on behaviour that is correct today, over exactly the column
aliasing that is wrong above.
experiments-compare.spec.tscovers scores, outputs, sort, search, the Feedbackscores tab and the row detail panel, and asserts nothing about timestamps. This
asserts that after a second version the comparison read reports each item
authored when the item was, not when its version was cut.
Deliberately API-level, and this narrows the candidate rather than shortcuts
it. The compare grid renders no created-at column at all — neither
getFilterColumns()nor the dataset/output column builders inExperimentItemsTabdefine one, and the row detail panel does not show iteither. There is no UI proxy for this value to assert on, so asserting the
endpoint the grid reads from is the honest form of the check. If a created-at
column is ever added to the compare view, the UI half belongs here alongside it.
How they were run
From
tests_end_to_end/e2e/, against$OPIK_BASE_URL(
https://staging.dev.comet.com/opik, workspaceopik-testing):npx playwright test \ tests/datasets/dataset-items-versioned-filter-scope.spec.ts \ tests/datasets/dataset-items-select-all-delete.spec.ts \ tests/experiments/compare-item-timestamps.spec.ts \ --reporter=list --retries=0Because this PR touches a shared page object and the backend client, the full
tests/datasets/+tests/experiments/directories were run too: 23 tests,19 passed, 4 failed — and the 4 are exactly the ones described above. No
pre-existing spec broke.
tag_lint.pyreports0 problem(s).npx tsc --noEmitcannot run in this checkout:tsconfig.jsonstill setsbaseUrl, which the pinned TypeScript 7 removed (TS5102), so the commandfails before compiling anything. That is pre-existing on the release ref and not
something this PR touches. Type-checking the same project with TypeScript 5.9
reports only the pre-existing duplicate
deleteDashboardmember incore/backend/client.ts, and nothing from these files.Supporting changes
fixtures/versioned-dataset.fixture.ts(new) — a dataset versioned twicewithout its items being re-authored, which is the only state in which the
two column sets hold different values. The version is committed by a grouped
batch update (the request the UI's select-all "Add tag" sends); an SDK
re-insert would not do, because rewriting an item moves
item_created_atforward with the snapshot and the two agree again. 12 items share an aged
UUIDv7 id prefix, 3 deliberately do not.
fixtures/versioned-comparison.fixture.ts(new) — the same versioncommit chained onto the existing
comparisonseed, so the two experiments,their traces and their teardown stay owned by the fixture that already does
that properly. It creates nothing, so it tears nothing down.
reads them — two versions, every seeded id present, the prefix carried by
exactly the intended items, and the version stamped strictly after the last
item was authored — and throw naming what was wrong. A test asserting on a
divergence its fixture silently failed to create could not fail.
core/backend/client.ts—createdAtonDatasetVersionRefand onDatasetItemWithTagsRef;listDatasetItemsPage(the ids and the reportedtotal, so a response whose total disagrees with the rows it carried fails);commitDatasetItemVersionByTagging;listCompareItems. PlusrequireTimestamp, which throws rather than defaulting an absent timestamp —the generated REST types mark every
createdAtoptional, and a default herewould turn a field the endpoint stopped returning into a comparison that
quietly still passes.
pom/dataset-items.page.ts—goto({ filters }),selectAllOnPage,selectAllMatching,allItemsSelectedBanner,paginationSummary,emptyState,bulkDeleteAllSelected.goto()'s existing no-argument callersare unaffected.
coverage/taxonomy.yaml— the three specs added to their areas'specs:lists. No capability is flipped: all four keys used were already
covered: true, and nothing here claims new coverage.One thing worth a
data-testidThe items grid's Filters trigger is
FiltersButtonwithlayout="icon": anicon-only button with no accessible name and no
data-testid, so the onlyhandle on it today is a structural selector. The POM therefore writes the
filtersquery param directly — the same serialised value the popover writes,read back by the same
useQueryParamthe popover feeds, so the grid takes theidentical code path. This follows the precedent
CompareExperimentsPagealready sets for its own unclickable controls.
A
data-testidon that shared trigger would be worth adding, but adding it herewould not help: these specs run against a deployed environment, which serves
the released frontend bundle, so a new attribute could not reach them.
What was deliberately not written
The exploration offered a fourth candidate, marked
weak:"a filtered dataset items page reports a total that agrees with the rows you
can page to" — the read/paging half, verified healthy on staging. Skipped: it
is a narrow API assertion over behaviour that currently works,
search-itemsand
version-history-viewalready cover the neighbourhood, and reviewerattention is better spent on the three above.
The exploration itself had already set aside three more before proposing
anything: the Dashboards Description filter operators (already covered by
dashboards-list-filters.spec.ts; extending it is a one-line parameterisationfor that spec's author), the list-error-state defect (the frontend fix was
deliberately reverted and deferred, so a test now would either encode the
misleading behaviour as correct or ship red for a reason nobody chose), and
redaction plus the LangChain/Bedrock token extractors (never driven — flag off,
and no provider credentials — and the bar is not to propose a test for a flow
nobody verified).
4 candidates proposed → 3 written, 1 dropped. 0 dropped for being unrunnable.