From 39b3cea27d5c7fb8406367632ce01c1d199e1d8c Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 1 Sep 2026 06:43:22 +0000 Subject: [PATCH 1/2] test(plugin-dashboard): the legacy-retired rows say what they really are, and the fixture claim becomes a read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The two annotated `it.each` rows in DashboardGridLayout.legacyRetired.test.tsx introduced their literals with provenance comments naming `examples/schema-catalog/src/schemas/plugin-dashboard/filtered-dashboard.json`. Both comments are false against that fixture as it stands today, mechanically checked key-for-key. They were true when written. `8640cec19` added this file at 01:05:19Z with a literal byte-for-byte identical to the fixture's `widgets[0]` — same keys, same order, same values — and `e028dfcd8` (objectui#4600, PR #4615) migrated the `filtered-*` catalog entries off the retired shape at 02:11:37Z, 66 minutes later. So this is drift, not an invented fixture. The annotations now state the measured history and say plainly that the rows no longer carry the independent-corpus property. The relationship they assert stops being prose: a derived block reads the same fixture at test time, pins that no shipped catalog widget authors the retired binding, and runs the three real shipped widgets through the surface as corpus-derived negative controls. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012wwHa4aaFybxXrfmfHioDM --- ...DashboardGridLayout.legacyRetired.test.tsx | 101 +++++++++++++++++- 1 file changed, 97 insertions(+), 4 deletions(-) diff --git a/packages/plugin-dashboard/src/__tests__/DashboardGridLayout.legacyRetired.test.tsx b/packages/plugin-dashboard/src/__tests__/DashboardGridLayout.legacyRetired.test.tsx index 224e85930f..7b7dad01ce 100644 --- a/packages/plugin-dashboard/src/__tests__/DashboardGridLayout.legacyRetired.test.tsx +++ b/packages/plugin-dashboard/src/__tests__/DashboardGridLayout.legacyRetired.test.tsx @@ -31,6 +31,9 @@ */ import { describe, it, expect, afterEach } from 'vitest'; +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; import React from 'react'; import { render, screen, cleanup } from '@testing-library/react'; import type { DashboardComponentSchema } from '@object-ui/types'; @@ -46,16 +49,46 @@ afterEach(cleanup); const dash = (widget: Record): DashboardComponentSchema => ({ type: 'dashboard', widgets: [widget] }) as unknown as DashboardComponentSchema; +/** + * The catalog entry the two annotated rows below were transcribed from, named + * once so the prose and the derived block at the bottom cannot drift apart. + */ +const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..', '..'); +const CATALOG_FIXTURE = path.join( + REPO_ROOT, + 'examples/schema-catalog/src/schemas/plugin-dashboard/filtered-dashboard.json', +); +const catalogWidgets = ( + JSON.parse(fs.readFileSync(CATALOG_FIXTURE, 'utf8')) as { widgets: Record[] } +).widgets; + describe('DashboardGridLayout retired legacy widgets (#4612)', () => { it.each([ ['chart', { id: 'w1', type: 'bar', object: 'invoices', categoryField: 'month', valueField: 'amount', aggregate: 'sum' }], - // Byte-for-byte `examples/schema-catalog/src/schemas/plugin-dashboard/ - // filtered-dashboard.json` → `widgets[0]`: the real stored shape, not a - // fixture invented to match the detector. + // Transcribed from `filtered-dashboard.json` → `widgets[0]` as that fixture + // stood at `8640cec19`, the commit that added this file. It was byte-for-byte + // then — same keys, same order, same values — and it is NOT byte-for-byte + // now: `e028dfcd8` (objectui#4600, PR #4615) migrated the `filtered-*` + // entries off the retired shape 66 minutes later, so `widgets[0]` on disk is + // `{ id, title, type, options: { xField, yField, data } }` today. + // + // ⚠️ This row therefore does NOT carry the independent-corpus property the + // original annotation claimed for it. It is a HISTORICAL specimen of stored + // metadata, not a live transcription — which is the right thing to pin (a + // renderer cannot refuse to receive stored metadata) but is worth strictly + // less as evidence, so it is stated rather than left to be re-derived. No + // live specimen can replace it; the derived block at the bottom measures + // that, instead of asserting it here in prose the way this comment once did. ['catalog bar', { id: 'invoices_by_status', title: 'Invoices by Status', type: 'bar', object: 'invoices', categoryField: 'status', aggregate: 'count' }], // The pivot family, whose legacy spelling names `rowField`/`columnField`. ['pivot', { id: 'w1', type: 'pivot', object: 'invoices', rowField: 'region', valueField: 'amount' }], - // `widgets[2]` of the same catalog entry. + // The same fixture's `widgets[2]` at that same commit, and a LOOSER claim + // than the row above ever made: its retired binding verbatim (`type`, + // `object`, `aggregate`), with `id` genericised to `w1` and `title` / + // `filterBindings` dropped. So this row was never byte-for-byte and never + // said it was. `e028dfcd8` retired that widget's shape too — `widgets[2]` is + // `{ id, title, type, options: { value }, filterBindings }` today — so the + // same ⚠️ above applies to it. ['metric', { id: 'w1', type: 'metric', object: 'invoices', aggregate: 'count' }], ])('renders the visible placeholder for a legacy %s widget', (_kind, widget) => { render(); @@ -116,4 +149,64 @@ describe('DashboardGridLayout retired legacy widgets (#4612)', () => { renderOne({ id: 'w1', type: 'pivot', options: { data: [{ region: 'EMEA', amount: 1 }] } }); expect(screen.queryByText(/retired data format/i)).not.toBeInTheDocument(); }); + + /** + * The corpus half — DERIVED from the fixture, not transcribed from it + * (objectui#7151). + * + * Two of the rows above are hand-written literals introduced by comments + * naming a fixture. Those comments were TRUE when written and stopped being + * true 66 minutes later, and nothing noticed for months: a comment cannot + * detect the file it names changing, which is exactly what a test can do. So + * the relationship stops being prose here and becomes a read. + * + * It reads the file off disk rather than importing it because this package's + * `tsconfig.test.json` declares `"types": ["node"]` — the precondition + * `packages/types/src/__tests__/timeline-catalog-fixture-migrated.test.ts` + * could not meet in `packages/plugin-timeline` and had to relocate for. The + * root Vitest config aliases `@object-ui/*` to sibling `src/`, so this file + * needs no built dependency closure to resolve either half. + * + * What this block deliberately does NOT do is restore the independent-corpus + * property the annotations above lost, because that property is no longer + * obtainable. Measured across every JSON document in the repo: 28 dashboard + * widgets, ZERO carrying the retired top-level binding, against live controls + * of 15 `options`-shaped and 2 `dataset`-shaped widgets. That zero is by + * DESIGN, not by accident — the retirement's whole content is that no + * authoring surface emits the shape (`WidgetConfigPanel` scrubs it on save via + * `LEGACY_ANALYTICS_KEYS`), and the catalog is an authoring corpus. A specimen + * reappearing there is therefore a catalog regression, which is the second + * thing this block catches. + */ + describe('the catalog entry those two rows name (objectui#7151)', () => { + it('is on disk, and holds the widgets the derived rows below iterate', () => { + // Asserted before anything consumes `catalogWidgets`: an emptied or + // renamed `widgets` array turns the `it.each` below into ZERO tests and a + // green run — the vacuous pass this whole block exists to end. + expect(fs.existsSync(CATALOG_FIXTURE), `fixture not found at ${CATALOG_FIXTURE}`).toBe(true); + expect(catalogWidgets.length).toBeGreaterThan(0); + }); + + it('carries NO widget in the retired shape — which is why those rows are hand-written', () => { + expect(catalogWidgets.length).toBeGreaterThan(0); + const retired = catalogWidgets.filter( + (w) => 'object' in w || 'categoryField' in w || 'valueField' in w || 'aggregate' in w, + ); + expect( + retired, + 'a shipped catalog widget authors the retired pre-ADR-0021 binding again — either the catalog regressed, or there is finally a live corpus specimen to transcribe into the annotated rows above', + ).toEqual([]); + }); + + // The independent-corpus property, restored on the side where the corpus + // still HAS specimens: these are the real shipped documents, and the + // detector must fire on none of them. + it.each(catalogWidgets.map((w, i) => [`widgets[${i}]`, w] as [string, Record]))( + 'does NOT show the placeholder for shipped catalog %s', + (_where, widget) => { + renderOne(widget); + expect(screen.queryByText(/retired data format/i)).not.toBeInTheDocument(); + }, + ); + }); }); From 81b5da034bce1c2d1ab5136170237f26ee8bf52f Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 1 Sep 2026 06:50:21 +0000 Subject: [PATCH 2/2] chore(changeset): declare the legacy-retired provenance repair as releasing nothing Empty frontmatter: the change is one test file in `plugin-dashboard`, with no published behaviour moving. `check-changeset-presence.mjs` names this as the explicit exemption rather than a workaround. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012wwHa4aaFybxXrfmfHioDM --- .changeset/7151-legacy-retired-provenance.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/7151-legacy-retired-provenance.md diff --git a/.changeset/7151-legacy-retired-provenance.md b/.changeset/7151-legacy-retired-provenance.md new file mode 100644 index 0000000000..6968ead813 --- /dev/null +++ b/.changeset/7151-legacy-retired-provenance.md @@ -0,0 +1,6 @@ +--- +--- + +Test-only change to `plugin-dashboard`'s legacy-retired suite; no published behaviour changes. + +The two annotated `it.each` rows in `DashboardGridLayout.legacyRetired.test.tsx` introduced their literals with provenance comments naming a schema-catalog fixture. Both were true when written and were invalidated 66 minutes later by the catalog migration off the retired shape (objectui#4600). The annotations now state the measured history and say plainly that the rows no longer carry the independent-corpus property, and the relationship they assert is derived at test time from the fixture instead of restated in prose.