Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 40 additions & 12 deletions .github/workflows/conformance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ on:
- reopened
- ready_for_review
schedule:
- cron: '43 7 * * *'
- cron: '13 9 * * 1'
- cron: '43 7 1 * *'
workflow_dispatch:
inputs:
shard:
Expand All @@ -28,6 +28,17 @@ on:
- '6'
- '7'
- '8'
suite:
description: First-party correctness or exhaustive competitor comparison
type: choice
default: first-party
options:
- first-party
- comparison
cases:
description: Optional comma-separated case IDs for a targeted run
type: string
default: ''

permissions:
contents: read
Expand All @@ -39,13 +50,15 @@ jobs:
github.event_name == 'schedule' ||
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'pull_request' &&
contains(github.event.pull_request.labels.*.name, 'full-conformance') &&
(github.event.action != 'labeled' || github.event.label.name == 'full-conformance'))
(contains(github.event.pull_request.labels.*.name, 'full-conformance') ||
contains(github.event.pull_request.labels.*.name, 'browser-correctness')) &&
(github.event.action != 'labeled' || github.event.label.name == 'full-conformance' || github.event.label.name == 'browser-correctness'))
runs-on: ubuntu-24.04
timeout-minutes: 2
outputs:
mode: ${{ steps.selection.outputs.mode }}
shards: ${{ steps.selection.outputs.shards }}
suite: ${{ steps.selection.outputs.suite }}

steps:
- id: selection
Expand All @@ -54,17 +67,22 @@ jobs:
EVENT_NAME: ${{ github.event_name }}
EVENT_SCHEDULE: ${{ github.event.schedule }}
REQUESTED_SHARD: ${{ inputs.shard }}
REQUESTED_SUITE: ${{ inputs.suite }}
REQUESTED_CASES: ${{ inputs.cases }}
FULL_LABEL: ${{ contains(github.event.pull_request.labels.*.name, 'full-conformance') }}
run: |
if [ "$EVENT_NAME" = schedule ] && [ "$EVENT_SCHEDULE" = '43 7 * * *' ]; then
epoch_day=$(( $(date -u +%s) / 86400 ))
shard=$(( epoch_day % 8 + 1 ))
mode=nightly
shards="[$shard]"
suite=first-party
if [ "$EVENT_SCHEDULE" = '43 7 1 * *' ] || [ "$FULL_LABEL" = true ] || [ "$REQUESTED_SUITE" = comparison ]; then
suite=comparison
fi
if [ -n "$REQUESTED_CASES" ]; then
mode=targeted
shards='[1]'
elif [ "$EVENT_NAME" = workflow_dispatch ] && [ "$REQUESTED_SHARD" != full ]; then
mode=manual
shards="[$REQUESTED_SHARD]"
elif [ "$EVENT_NAME" = schedule ]; then
mode=weekly
mode=scheduled
shards='[1,2,3,4,5,6,7,8]'
elif [ "$EVENT_NAME" = pull_request ]; then
mode=label
Expand All @@ -76,10 +94,11 @@ jobs:

echo "mode=$mode" >> "$GITHUB_OUTPUT"
echo "shards=$shards" >> "$GITHUB_OUTPUT"
echo "Mode: $mode; shards: $shards; revision: $GITHUB_SHA" >> "$GITHUB_STEP_SUMMARY"
echo "suite=$suite" >> "$GITHUB_OUTPUT"
echo "Suite: $suite; mode: $mode; shards: $shards; revision: $GITHUB_SHA" >> "$GITHUB_STEP_SUMMARY"

conformance:
name: Conformance (${{ matrix.shard }}/8, ${{ needs.select.outputs.mode }})
name: Conformance (${{ matrix.shard }}/8, ${{ needs.select.outputs.suite }}, ${{ needs.select.outputs.mode }})
needs: select
runs-on: ubuntu-24.04
timeout-minutes: 25
Expand All @@ -103,7 +122,16 @@ jobs:
playwright: 'true'

- name: Run standard conformance shard
run: pnpm conformance -- --shard=${{ matrix.shard }}/8
env:
SUITE: ${{ needs.select.outputs.suite }}
CASES: ${{ inputs.cases }}
SHARD: ${{ matrix.shard }}
run: |
args=()
if [ -z "$CASES" ]; then args+=(--shard="$SHARD/8"); fi
if [ "$SUITE" = first-party ]; then args+=(--first-party); fi
if [ -n "$CASES" ]; then args+=(--case="$CASES"); fi
pnpm conformance -- "${args[@]}"

- name: Publish conformance summary
if: success()
Expand Down
13 changes: 13 additions & 0 deletions API-FRICTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -8318,6 +8318,19 @@ Each entry records:
complete standard shard 4/8 passes all 24 cases, including the nine former
failures, with the original geometry, paint, and accessibility gates intact.

- Follow-up from scheduled run 34865024647: active and mixed bars render five
browser data rows, and stacked radial renders two series, but generated
expectations used generic family counts. The interactive line selects one
series at a time, not two simultaneous lines. Correct the source generator and
pinned reference data. The stacked radial example also used 1260 as the
cumulative end of a 570 + 1260 stack; its cumulative end and domain are 1830.
First-party browser checks exposed outside radar labels with no reserved
space, a negative-bar label below the viewport, and dashboard media queries
tied to the host window instead of the embedded panel. Reserve label space
and use dashboard container queries. Its actual scroll viewport is now
identified for the existing offscreen-label rule, not treated as a clipped
static chart. Retain these cases in routine first-party browser coverage.

### F-275 — Preview transparency validation rejected semantic IDs

- Status: resolved
Expand Down
19 changes: 19 additions & 0 deletions benchmarks/conformance/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ pnpm conformance:quick
# Standard 320/640/960, light/dark matrix
pnpm conformance

# First-party browser correctness, no competitor builds or comparative audits
pnpm conformance -- --first-party

# Target an example while keeping its full browser matrix
pnpm conformance -- --first-party --case=150-shadcn-bar-negative

# Isolated bundle and type audit only
pnpm conformance:size

Expand Down Expand Up @@ -84,6 +90,19 @@ and tooling compatibility even when a run includes Recharts references.
the complete catalog evidence. Long selections use a bounded digest; the JSON
always records the resolved case filter.

First-party reports add `--first-party` to the artifact name. They retain all
case geometry counts, guide assertions, containment, accessible names, and
native interaction scenarios, before and after updates at every profile size
and theme. They do not measure type safety, bundle size, timing, competitor
paint parity, or relative geometry similarity. The ordinary cached checks
still validate types, examples, bundles, and generated assets.

CI runs first-party correctness weekly and the paired comparison monthly.
Ordinary PRs do not run this workflow. Use the `browser-correctness` label for
first-party coverage or `full-conformance` for comparison coverage. Manual
runs accept a suite, shard, or comma-separated case IDs; targeted case runs
use one job rather than launching empty shards.

The [interaction UX audit](./INTERACTION-UX-AUDIT.md) preserves the before-state
review of cases 80–92 and records the implementation follow-through for
discoverability, rendered feedback, keyboard and touch operation, cancellation,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ export function ShadcnDashboard({ ChartRenderer, input }: DashboardProps) {
<div className="sd-viewport">
<DashboardSidebar />
<main className="sd-main">
<div className="sd-main-scroll">
<div className="sd-main-scroll" data-conformance-scroll-viewport>
<DashboardHeader />
<div className="sd-content">
<section className="sd-cards" aria-label="Key metrics">
Expand Down
5 changes: 3 additions & 2 deletions benchmarks/conformance/cases/127-shadcn-dashboard/styles.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export const shadcnDashboardStyles = `
.shadcn-dashboard {
container: dashboard / inline-size;
--sd-background: oklch(1 0 0);
--sd-foreground: oklch(0.145 0 0);
--sd-card: oklch(1 0 0);
Expand Down Expand Up @@ -752,7 +753,7 @@ export const shadcnDashboardStyles = `
}
}
@media (max-width: 767px) {
@container dashboard (max-width: 767px) {
.sd-sidebar {
display: none;
}
Expand Down Expand Up @@ -781,7 +782,7 @@ export const shadcnDashboardStyles = `
}
}
@media (max-width: 480px) {
@container dashboard (max-width: 480px) {
.sd-chart-card {
height: 414px;
}
Expand Down
3 changes: 2 additions & 1 deletion benchmarks/conformance/cases/143-shadcn-bar-active/case.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"geometry": [
{
"role": "bar",
"count": 6
"count": 5,
"maxCount": 5
}
],
"source": {
Expand Down
3 changes: 2 additions & 1 deletion benchmarks/conformance/cases/149-shadcn-bar-mixed/case.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"geometry": [
{
"role": "bar",
"count": 6
"count": 5,
"maxCount": 5
}
],
"source": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export function createExampleChart() {
y: { scale: scaleLinear, grid: true, axis: false },
},

margin: { top: 24, right: 5, bottom: 24, left: 5 },
margin: { top: 24, right: 5, bottom: 36, left: 5 },
theme: shadcnTheme(),
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"geometry": [
{
"role": "line",
"count": 2
"count": 1,
"maxCount": 1
}
],
"source": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,14 @@ export function createExampleChart() {
}),
]
return defineChart(
({ height }) => ({
({ width, height }) => ({
marks: [
polar({
radiusRatio: height < 220 ? 0.64 : 0.76,
// Reserve space for the two outside label rows at every chart size.
radiusRatio: Math.min(
0.76,
Math.max(0.1, 1 - 120 / Math.min(width, height)),
),
scales: {
angle: { scale: scalePoint<string>().domain(months), wrap: true },
radius: { scale: scaleLinear().domain([0, radiusMax]) },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"geometry": [
{
"role": "bar",
"count": 5,
"count": 2,
"maxCount": 2,
"rendererRoles": {
"recharts": "arc",
"tanstack": "arc"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function createExampleChart() {
id: 'desktop',
ring: 'visitors',
start: 570,
end: 1260,
end: 1830,
fill: shadcnColors[0],
},
]
Expand All @@ -36,7 +36,7 @@ export function createExampleChart() {
startAngle: rechartsPolarAngle(0),
endAngle: rechartsPolarAngle(180),
scales: {
angle: { scale: scaleLinear().domain([0, 1260]) },
angle: { scale: scaleLinear().domain([0, 1830]) },
radius: {
scale: scaleBand<string>().domain(['visitors']),
range: [80, 110],
Expand Down
12 changes: 8 additions & 4 deletions benchmarks/conformance/catalog-index.json
Original file line number Diff line number Diff line change
Expand Up @@ -10694,7 +10694,8 @@
"geometry": [
{
"role": "bar",
"count": 6
"count": 5,
"maxCount": 5
}
],
"source": {
Expand Down Expand Up @@ -10880,7 +10881,8 @@
"geometry": [
{
"role": "bar",
"count": 6
"count": 5,
"maxCount": 5
}
],
"source": {
Expand Down Expand Up @@ -11097,7 +11099,8 @@
"geometry": [
{
"role": "line",
"count": 2
"count": 1,
"maxCount": 1
}
],
"source": {
Expand Down Expand Up @@ -12136,7 +12139,8 @@
"geometry": [
{
"role": "bar",
"count": 5,
"count": 2,
"maxCount": 2,
"rendererRoles": {
"recharts": "arc",
"tanstack": "arc"
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading