Skip to content

ci: fail the benchmark job on a Devup UI regression and keep a WASM size budget - #746

Open
owjs3901 wants to merge 48 commits into
mainfrom
ci/benchmark-regressions
Open

owjs3901 wants to merge 48 commits into
mainfrom
ci/benchmark-regressions

Conversation

@owjs3901

@owjs3901 owjs3901 commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Refs #683 (NXT-21, INF-16, NXT-22, INF-26, INF-17)

#744(ci/hardening) 위에 쌓인 PR입니다. CI가 main 대상 PR에서만 도므로 base는 main이고, diff에 #744(와 그 아래 #731)의 커밋이 함께 보입니다. 이 PR의 고유 커밋은 8cf1e1a7, 56a37f1d이며 #744가 먼저 병합되어야 합니다. 패키지에 들어가는 파일은 바꾸지 않아 changepack은 없습니다.

요약

  • benchmark 잡이 Devup UI 행의 실제 회귀에서만 실패합니다. 모든 행을 같은 횟수(3회)의 cold build, 순서를 돌려 가며 측정해 중앙값과 범위를 내고, 체크인된 기준값과 비교합니다. 다른 라이브러리 행은 정보용입니다.
  • WASM 패키지 크기(raw, gzip)를 체크인된 예산과 비교해, 예산을 같은 PR에서 올리지 않은 증가는 실패합니다.
  • SemanticBuilder 패스 비용을 격리하는 Rust 벤치를 benchmark 잡이 출력합니다.
  • README 표는 계속 체크인된 결과 파일에서 영어/한국어로 생성되고, 이제 모든 행이 중앙값과 범위를 보여줍니다.

동작

샘플링 정책 (NXT-22) — benchmark-manifest.json이 대상 18개, 그룹(webpack/turbopack/vite), 게이트 대상, 행마다 같은 샘플 수(3)를 정의합니다. benchmark.js는 3라운드를 돌며 라운드마다 목록의 시작 위치를 옮겨(roundOrder) 어떤 대상도 항상 처음이나 마지막에 실행되지 않게 합니다. 각 행은 중앙값, min/max, 중앙값 크기를 benchmark-run.json에 쓰고 benchmark 잡이 benchmark-run 아티팩트로 올립니다. 이전에는 Turbopack 3개 행만 6회였고 나머지는 1회였습니다.

회귀 규칙 (NXT-21, INF-16) — benchmark-gate.js(테스트 가능한 순수 로직), benchmark-check.js(CLI), benchmark-baseline.json:

  • 게이트 대상은 Devup UI 행 9개(gate: true)뿐입니다.
  • 공유 러너는 실행 간 속도가 크게 흔들립니다. 5번의 CI 실행에서 같은 devup-ui 빌드가 10.215.9s였습니다(±25%). 그래서 시간은 같은 실행의 대조 행(같은 번들러의 Tailwind)에 대한 비율로 비교합니다. 같은 실행들에서 비율의 흔들림은 ±16%였습니다.
  • 행은 비율 > 기준 비율 × (1 + 허용치)일 때 실패합니다. 허용치는 max(10%, 2 × 보정 실행들에서 관측한 비율의 상대 범위)이고 행마다 benchmark-baseline.json에 보정 비율과 함께 저장됩니다(현재 10~24%).
  • 크기는 실행 간 0.05% 이내로 결정적입니다(devup-ui/devup-ui-single 총 67,412,690~67,440,333 bytes, CSS는 매번 같은 바이트). 총 크기는 기준 × 1.01을 넘으면, CSS는 기준 + max(5%, 32 bytes)를 넘으면 실패합니다.
  • 의도한 변경은 bun benchmark-check.js --write-baseline(실행을 보정에 추가하고 기준값을 다시 씀)과 --write-results(README 표용 결과)를 CI 아티팩트에 실행해 같은 PR에 커밋합니다. 샘플 정책이 기준값과 다르면 실패합니다.
  • 규칙은 benchmark-gate.js 머리 주석과 README 표 아래 문단에 적혀 있습니다. 한계: 허용치 이하의 느려짐(약 10~24%)은 잡지 못합니다.

WASM 크기 예산 (INF-26) — verify-wasm-size.js가 pkg/index_bg.wasm과 index.js의 raw/gzip(level 9) 크기를 재서 bindings/devup-ui-wasm/size-budget.json과 비교하고 wasm-size.json을 wasm-size 아티팩트로 올립니다(검증 잡). 예산은 CI에서 잰 값 + 1%를 1 KiB로 올림한 상한입니다(현재 wasm raw 5,479,424 / gzip 1,970,176). 넘으면 실패하고, 의도한 증가는 bun verify-wasm-size.js --write로 예산을 올려 같은 PR에서 리뷰합니다.

SemanticBuilder 비용 (INF-17) — libs/extractor/benches/semantic_pass_benchmark.rs와 benchmark 잡의 cargo bench -p extractor --bench semantic_pass_benchmark -- --quick 단계. 같은 프로그램에서 파싱만, 파싱+SemanticBuilder(바닥), 그리고 패스를 켜는 입력과 끄는 입력 쌍(style_values_pass: css/keyframes import 유무, report_compiled_reads_pass: 컴파일된 이름을 값으로 읽는 오류 경로)을 측정합니다. CI(ubuntu-24.04) 결과: parse 4.2 µs, parse+semantic 6.2 µs(= 패스 한 번의 바닥 약 2.0 µs), 전체 extract는 약 140 µs(패스 off 140.2 / on 143.3, 오류 경로 141.7 / 152.0 µs). 즉 패스 비용은 이 입력에서 추출 전체의 약 1.5% 안팎으로 오차와 구별하기 어렵습니다. 이후 작업이 이 수치를 비교할 수 있습니다(게이트는 아님).

실행 시간

benchmark 잡은 6.9분(단일 샘플 18행 + Turbopack 6회) → 11.4~14.8분(18행 × 3회 + Rust 벤치)입니다. 타임아웃은 60분 그대로입니다. publish 잡 14분대는 그대로입니다.

시연: 회귀가 실제로 실패시킵니다

버려질 PR(draft, 병합하지 말 것)에서 이 브랜치 위에 커밋 하나로 Devup UI 픽스처 빌드(next-devup-ui-single-turbo)에 인위적인 3초 지연을 넣고 WASM 예산을 바이너리보다 작게 낮췄습니다: #748.

  • 정상 실행(이 PR, run 37128462621): benchmark, publish 포함 모든 잡 성공.
  • 시연 실행(run 37128692562):
    • benchmark 실패: FAIL devup-ui-single-turbo: 10.13s (1.453x tailwind-turbo, baseline 0.975x ±10%) / build time is 1.453x tailwind-turbo, over the limit 1.073x. 같은 실행의 다른 8개 Devup UI 행은 ok였습니다. 이 실행의 러너는 이전보다 약 35% 느렸는데(devup-ui 15.15s vs 10.97s) 비율은 0.862x(기준 0.865x)라 오탐이 없었습니다.
    • publish 실패: verify-wasm-size: the package grew beyond its budget: wasm raw is 5,424,552 bytes, 224,552 over the budget of 5,200,000.
  • 크기 증가(+3%)도 같은 규칙으로 검출되는 것을 benchmark-check.js에 CI 아티팩트를 고쳐 먹여 확인했고(output is 37,634,689 bytes, over the limit 36,904,779), 단위 테스트(packages/plugin-utils/src/__tests__/benchmark-gate.test.ts, 게이트 파일 100%)가 지연, 크기, CSS, 누락 행, 정책 불일치, 러너 속도 변화에도 통과하는 정상 실행과 일반 노이즈를 모두 검증합니다.

새로 생기는 오류

빌드 에러는 없습니다. CI 실패 조건이 늘었습니다: Devup UI 행의 시간 비율/크기 회귀, 샘플 정책 불일치, WASM 크기 예산 초과.

남는 한계

  • 허용치(10~24%) 이하의 느려짐은 잡지 못합니다. 보정 실행이 쌓일수록(--write-baseline이 최근 10회를 유지) 허용치를 줄일 수 있습니다.
  • 정보용 행(다른 라이브러리)과 Webpack/Turbopack 사이의 절대 비교는 여전히 러너에 따라 달라집니다.
  • 시연용 draft PR #748은 병합하지 않고 확인 후 닫으면 됩니다(저는 닫지 않았습니다).

검증

  • bun test 100%(게이트 로직 포함), bun lint 오류 0, cargo clippy -D warnings(벤치 포함), tarpaulin 100%는 이 PR의 CI에서 통과했습니다. 이 PR의 CI: run 37128462621 전 잡 성공(release, deploy-pages는 PR이라 건너뜀).
  • README 표와 한국어 README는 bun render-benchmark-readme.js --check로 benchmark-results.json(이 PR의 첫 3샘플 실행 37127187436)과 같음을 검증합니다.

W40 main 반영 (2026-10-06)

  • 2026-10-06: main의 a935315c34b45aeda6dc156e29a5c76df51b76bd까지 병합했습니다 (병합 head: 1936fa362e1548f6d01a5255c7b72e7b7d043111).
  • 충돌 해결: main을 포함한 ci: pin actions and toolchains, scope permissions per event, and generate the benchmark tables from one result #744 head7a81003f를 병합했고 앞선 publish.yml 해결이 그대로 적용되어 추가 수동 충돌은 없었습니다. React18/vinext 두 모드와 SHA·권한·타임아웃을 유지했고 보정된 manifest/baseline/results, 회귀 규칙, SemanticBuilder 벤치와 WASM 예산은 기존 #746과 바이트 단위로 같습니다.
  • 검증: CI37450743141 success; 다섯 검증 작업과 codecov/patch 모두 통과, MERGEABLE/CLEAN. release/deploy는 PR에서 정상 skip. Ubuntu Rust100%(10504/10504), Bun5512 pass/0 fail 및100%, landing 두 모드130개씩 통과. benchmark-check는 측정 잡음을 넘는 회귀 없음으로 통과했고 예산을 올리지 않았습니다. CI WASM raw5424552/gzip1950009, glue raw40680/gzip6896 bytes로 기존 한도 이내입니다. 직렬 빌드/1.99clippy/cargo test workspace/전체 훅, 회귀·ABI 집중 테스트28개와 진입점·README·YAML 구조 검사도 통과했습니다.
  • 새로 생기는 오류: 이번 병합으로 추가되는 오류는 없습니다. 기존 PR의 동작 및 남는 한계는 유지합니다.

2026-10-08 main 11790bef를 병합하여 업데이트했습니다. 갱신된 부모 #744를 충돌 없이 병합했고 모든 CI 작업·단계를 보존했습니다. main의 의도된 Tailwind CSS 증가(530→1491바이트)는 실제 CI 37758611477 산출물로 기존 6회 이력을 유지한 7회 보정 및 결과·README 재생성으로 반영했으며, 게이트 공식과 WASM 예산은 변경하지 않았습니다.

owjs3901 and others added 22 commits October 1, 2026 21:16
…rations

css(a, b) composing classes whose styles the build knows, bound to css() in the file or exported by another module, merges their atoms per property, selector, breakpoint and layer, conditions included, instead of joining classes whose winner the stylesheet order picked. vanilla-extract style([...]) passes each composed style as its own argument, keeping a style composed again later.

Refs #688

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #688

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #688

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #688

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…asurable

Refs #688

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…JSX spreads win

Refs #688

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…led order and JSX element className

Refs #688

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #689

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…uate shouldForwardProp at build time

Refs #689

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…ring

Refs #689

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…APIs

Refs #691

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #691

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #691

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #691

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #691

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #691

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…rate the benchmark tables from one result

Refs #683

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…s against

Refs #683

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…ize budget

Refs #683

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@codecov

codecov Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Files with missing lines Coverage Δ
libs/extractor/benches/semantic_pass_benchmark.rs 100.00% <100.00%> (ø)
libs/extractor/src/composition.rs 100.00% <100.00%> (ø)
...tractor/src/extractor/extract_style_from_styled.rs 100.00% <100.00%> (ø)
libs/extractor/src/imported_constants.rs 100.00% <100.00%> (ø)
libs/extractor/src/lib.rs 100.00% <ø> (ø)
libs/extractor/src/prop_modify_utils.rs 100.00% <100.00%> (ø)
libs/extractor/src/prop_valid.rs 100.00% <100.00%> (ø)
libs/extractor/src/style_values.rs 100.00% <100.00%> (ø)
libs/extractor/src/styled_reads.rs 100.00% <100.00%> (ø)
libs/extractor/src/utils.rs 100.00% <100.00%> (ø)
... and 10 more
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

owjs3901 and others added 4 commits October 3, 2026 23:02
…e first CI run of the new policy

Refs #683

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Resolve .github/workflows/publish.yml by retaining both React 18 and main vinext/RSC CSS acceptance jobs as independent siblings. Keep every main job and step byte-equivalent after YAML parsing, preserve #700 published versions with React peer/dev dependency intent, and regenerate lockfile workspace metadata through bun install.

Refs #691, #683

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Merge #731 head 5644a8a containing main a935315. Resolve .github/workflows/publish.yml by keeping the complete main vinext job and publish validation comment, extending every action SHA/toolchain/cache pin plus timeout30/read-only permissions to vinext. Keep React18 and both CSS modes, original release/deploy needs, #700 published versions and the clean-pkg build script.

Refs #683

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Merge #744 head 7a81003 containing main a935315. No new manual conflict files: .github/workflows/publish.yml cleanly inherits the hardened vinext/React18 job union and read-only validation with action SHA pins/timeouts. Preserve the calibrated benchmark manifest/baseline/results, regression rules, SemanticBuilder bench and WASM budgets byte-for-byte, plus all main published versions and acceptance steps.

Refs #683

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
No conflicted files; preserve composition changes and main ESLint checks.
No conflicted files; combine updated parent and PR changes.
owjs3901 and others added 20 commits October 8, 2026 15:12
No conflicted files; combine updated parent and PR changes.
Merge main history while preserving this PR implementation. No manual conflict resolutions.
Merge main history while preserving this PR implementation. No manual conflict resolutions.
Merge main history while preserving this PR implementation. No manual conflict resolutions.
Merge main history while preserving this PR implementation. No manual conflict resolutions.
Merge main history while preserving this PR implementation. No manual conflict resolutions.
Merge main history while preserving this PR implementation. No manual conflict resolutions.
Merge main history while preserving this PR implementation. No manual conflict resolutions.
Merge main history while preserving this PR implementation. No manual conflict resolutions.
Conflicted file: libs/extractor/src/lib.rs. Retain both composition helper and regression tests from PR 706 and Tailwind per-class regression tests from main 11790be; take rewritten main Tailwind implementation with Rust 1.99 assertions. bun.lock regenerated by bun install; no snapshots were hand-merged.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Merge updated parent PR 706 (30247ba), containing main 11790be. Conflicted file: libs/extractor/src/prop_modify_utils.rs. Preserve PR 707's last-written className/style spread semantics and no spread_props parameter with capacity 2, together with main's per-class Tailwind compiler. No snapshots were hand-merged.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
No conflicted files; retain PR changes and merge updated parent #707, which contains main 11790be.
No conflicted files; retain PR changes and merge updated parent #710, which contains main 11790be.
No conflicted files; retain PR changes and merge updated parent #711, which contains main 11790be.
No conflicted files; retain PR changes and merge updated parent #722, which contains main 11790be.
No conflicted files; retain PR changes and merge updated parent #720, which contains main 11790be.
No conflicted files; retain PR changes and merge updated parent #721, which contains main 11790be.
No conflicted files; retain PR changes and merge updated parent #731, which contains main 11790be.
No conflicted files; retain PR changes and merge updated parent #744, which contains main 11790be.
Main 11790be intentionally emits complete Tailwind v4 font line-height declarations and property registrations, so CI 37758611477 produced 1491 CSS bytes for tailwind-turbo-devup-ui against the former 530-byte baseline. Follow the existing intentional-growth policy using that actual 18-target, three-sample artifact: append each measured seventh control ratio while retaining all six prior entries, regenerate baseline/results and both README benchmark blocks. Keep every gate, threshold formula, workflow step and WASM size budget unchanged; all nine artifact comparisons, provenance/calibration assertions, README renderer check and fresh WASM/root builds pass.

Refs #683

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
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.

1 participant