Skip to content

[BUGFIX] TimeSeriesChart: express palette schema without comprehension - #869

Open
ibakshay wants to merge 3 commits into
mainfrom
ibakshay/timeserieschart-palette-schema
Open

ibakshay wants to merge 3 commits into
mainfrom
ibakshay/timeserieschart-palette-schema

Conversation

@ibakshay

@ibakshay ibakshay commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Description

Part of perses/perses#4574

The TimeSeriesChart palette schema breaks validation against the dashboard CUE schema from Perses: every dashboard with a TimeSeriesChart panel fails. This PR writes the same rule in a form that CUE can resolve. The allowed values don't change.

perses/perses#4577 also fixes this for all plugins in the Perses schema generator.

AI Usage Disclosure

GitHub Copilot was used to investigate the issue and write the change. I reviewed and tested it.

The comprehension 'if mode == "categorical"' on the undefaulted disjunction
of #palette cannot be resolved once the plugin schema is merged into the
complete dashboard schema (/api/v1/schemas/dashboards): 'cue vet' then fails
with 'unresolved disjunction' on every TimeSeriesChart panel.

Use a disjunction of closed structs instead, which keeps the same rules:
'name' is only allowed (and optional) in categorical mode.

Signed-off-by: Akshay Iyyadurai Balasundaram <akshay.iyyadurai.balasundaram@sap.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

The added fixture passes under the old schema and therefore does not protect against the reported merged-schema regression.

1 open finding
What changed in this PR

Rewrites the TimeSeriesChart palette schema to remain resolvable when embedded in Perses dashboard schemas.

Changes:

  • Replaces conditional palette validation with explicit struct variants.
  • Adds an auto-palette schema fixture.
File Description
timeserieschart/​schemas/​time-series.cue Expresses palette modes as a resolvable disjunction.
timeserieschart/​schemas/​tests/​valid/​time-series-palette-auto.json Adds an auto-mode validation fixture.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread timeserieschart/schemas/tests/valid/time-series-palette-auto.json
The plugin schema tests validate the plugin schema alone, where the
previous palette definition was valid. Add a CUE test that embeds the
plugin schema in a panel plugin disjunction, as Perses does when it
builds the dashboard schema, and run it from test-schemas-plugins.

Signed-off-by: Akshay Iyyadurai Balasundaram <akshay.iyyadurai.balasundaram@sap.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Approval recommended

The schema behavior is preserved and the reported integration failure has focused regression coverage.

1 open finding

🧠 Review effort: Balanced

Comment on lines +29 to +31
// dashboardTestDir contains an optional CUE package defining a "#Dashboard" that embeds the plugin schema the way
// Perses does when merging all plugin schemas, along with JSON dashboards that must validate against it.
const dashboardTestDir = "schemas/tests/dashboard"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this makes me wonder why we have this discrepancy. It feels wrong to me to tackle it this way. I think I did a mistake originally in the panel schemas here, e.g TimeSeriesChart is defined as such:

kind: "TimeSeriesChart"
spec: close({
legend?: common.#legendWithValues
tooltip?: #tooltip
yAxis?: #yAxis
thresholds?: common.#thresholds
visual?: #visual
querySettings?: #querySettings
})

the close() call is closing the spec struct only at the level it is used, it doesnt recursively apply to all nested structs, while wrapping the panel in a #Dashboard definition performs a recursive close & that's probably why you got this "valid dashboards fail cue vet against the generated schema, although the same server accepts them". To verify that we should tweak the TimeSeriesChart to this:

kind: "TimeSeriesChart"
spec: #spec

#spec: {
	legend?:        common.#legendWithValues
	tooltip?:       #tooltip
	yAxis?:         #yAxis
	thresholds?:    common.#thresholds
	visual?:        #visual
	querySettings?: #querySettings
})

Could you do this & verify that for the same situation as in perses/perses#4574 this time it makes both cue vet & server validation fail? If yes we should update this schema (and all the other similar ones) to this structure, this would be more accurate in that case & we wouldn't need this dashboardTestDir-related test logic to cover a gap.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thank you for the pointer. @AntoineThebaud

I tried it with the Perses v0.55.0-rc.0. I loaded TimeSeriesChart, BarChart and StatChart, generated the schema with GenerateDashboardSchema(), and ran cue vet -d '#Dashboard'.

Below are the results:

TimeSeriesChart schema server validation cue vet
spec: close({...}) + old #palette (main) OK FAIL: #palette: unresolved disjunction
spec: #spec, without close() + old #palette OK FAIL (same)
spec: {...}, without close() + old #palette OK FAIL (same)
spec: close({...}) + new #palette (this PR) OK OK

So removing close(), with or without your #spec definition, doesn't change the outcome: the #palette error stays.

Your point about close() is a separate issue. With a plain spec: {...} and no close(), the server accepts an unknown field like spec.foo while cue vet rejects it. With close() or #spec, both reject it. A nested unknown field like spec.visual.foo is rejected by both in every variant, because the nested types are definitions.

The difference comes from how the dashboard schema is generated. Each plugin schema, including helper definitions like #palette, is copied into the panel plugin disjunction. Inside that disjunction, CUE can't resolve the if mode == "categorical" check. The server validates each plugin schema on its own, so it never hits this. perses/perses#4577 fixes the generator and adds a regression test for exactly this case.

Given that, I'm happy to remove the test logic from this PR and keep only the schema change. WDYT?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ok indeed I forgot to consider that all the fields within spec are definitions.. I still don't fully understand why this issue occur but let's follow up on perses/perses#4577 side, for this PR yes please keep only the schema change.

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.

3 participants