Skip to content

[docs] Patterns: a tiered library of tested, installable Workflow patterns - #1858

Open
karthikscale3 wants to merge 48 commits into
mainfrom
karthik/shadcn-registry-2
Open

[docs] Patterns: a tiered library of tested, installable Workflow patterns#1858
karthikscale3 wants to merge 48 commits into
mainfrom
karthik/shadcn-registry-2

Conversation

@karthikscale3

@karthikscale3 karthikscale3 commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Ownership: originally opened by @karthikscale3; @pranaygp has since taken it over and is driving it to merge. Review comments are best directed at @pranaygp.

Summary

Adds a Patterns section to the docs (/patterns) — a tiered library of 30 Workflow patterns, most installable via the shadcn CLI. What began as a flat list of 19 recipes is now organized by what the installed code is worth after adaptation, backed by real, executable, tested source files rather than hand-maintained snippet strings, with a CI pipeline that proves every pattern compiles, runs, and installs.

The taxonomy

Every pattern declares a patternType:

Type The value is… Count Examples
Component the installed code itself — import it and call it, domain-free 9 kill-switch, semaphore, rate-limiter, circuit-breaker, debounce, batch-aggregator, singleton-run, child-workflows, scheduling
Template the structure — keep the skeleton, replace the function bodies 13 saga, batching, idempotency, timeouts, webhooks, polling, dead-letter-queue, recurring-cron, ai-sdk, durable-agent, …
Example the lesson — read it, then mostly rewrite 8 stripe, slack-approval, resend, chat-sdk, sandbox, sequential-and-parallel, workflow-composition, handling-rate-limits

The tier shows as a badge on each card and detail page and is a filter on the listing page. Component is the bar new patterns aim for.

Source of truth: tested files, generated snippets

The core architectural change. Pattern code lives as real .ts files in workbench/vitest/workflows/patterns/ (19 canonical files) — compiled, executed, and tested against the actual runtime. The docs snippet strings are generated from them (docs/scripts/sync-pattern-source.tsdocs/lib/patterns/generated/); a CI check fails if the generated output drifts. This kills the class of bug where snippet strings silently rot as the SDK moves (which this PR hit three times before the inversion).

  • 51 behavioral tests across 17 suites under @workflow/vitest — observed max-concurrency for the semaphore, breaker state transitions, debounce latest-payload, aggregator size/deadline/dedupe flushes, racing KillSwitch.create(), a full continue-as-new cron generation handoff, etc.
  • Replaceable action steps are self-contained runnable demos (real API calls kept as comments) so installs work on first run.

Writing the tests found and fixed three shipped bugs: a recurring-cron stop-hook deadlock (stale channel awaiters swallowed the stop payload), deploymentId: "latest" throwing on non-Vercel worlds in two patterns, and an SWC step-transform bug stripping module consts referenced only from destructuring defaults — filed upstream as #2396 with a verified minimal repro.

shadcn registry + install pipeline

  • GET /r/[name] returns registry-item.json; emits workflows/ files (→ app/workflows/) and lib/ files (→ project root), plus a dependencies array.
  • docs/scripts/validate-registry.ts (CI, every PR): every payload's files parse as TS, files[] metadata matches emissions, npm imports are covered by dependencies, env vars are declared, and DOCS: links resolve. On first run it caught chat-sdk's lib/ files never being emitted (broken install), an undeclared sandbox file, and 9 missing dependency declarations.
  • workbench/install-fixture/: a real Next.js app; patterns are materialized (or CLI-installed) into it, then typechecked and next build-verified with the workflow SWC plugin. Caught real API drift (Sandbox.sandboxId.name).
  • .github/workflows/patterns-checks.yml: registry validation + codegen freshness + fixture build + real shadcn add e2e on PRs.
  • .github/workflows/patterns-nightly.yml: nightly install from the production registry with unpinned shadcn@latest; opens a tracking issue on failure.

Detail-page UX: Usage vs Source

Component pages now separate Usage (the consumer API — "import it and call it") from Source (the full implementation, framed as education — "not a black box; read it, then adapt"). Each pattern also shows version-compatibility badges (v4 / v5), searchable and in the copy-page text.

Idempotency hardening

Reviewed the coordination patterns against the run-idempotency work (#2015 / #2373 / #2376):

  • All six coordinators + the singleton example claim their channel token with getConflict() — a lost start race returns { dedupedTo: winnerRunId } cleanly instead of dying with HookConflictError.
  • kill-switch adopts the registered owner's runId after racing create() calls (a loser handle's .signal would otherwise never fire).
  • batch-aggregator dedupes items by id (sends from retried steps are at-least-once).
  • Analysis + two newly-surfaced gaps (channel close+drain, idempotency keys on resumeHook) posted to Idempotency follow-ups: atomic keyed start(), post-completion dedupe, and attribute-based run lookup #2376.

Semaphore: releases are keyed, so a re-sent release can't mint capacity

The cross-run fan-out test was intermittently reporting max = 4 against
maxConcurrent = 3. Not a flaky assertion — a real over-admission bug in the
recipe.

sendSemaphoreEvent retries semaphoreEvents.resume(...) in a catch-and-retry
loop, and the step wrapping it is itself at-least-once — so a release that
actually landed can look like a failure to its sender and be sent again. The
coordinator applied both copies:

// before — unkeyed, so a duplicate is indistinguishable from a real release
} else {
  inFlight = Math.max(0, inFlight - 1);
}

Each extra copy hands back capacity nobody gave up, and one more holder slips
into the critical section — exactly the maxConcurrent + 1 signature observed.

Both events now carry the holder's grantToken, and the coordinator keeps a
held: Set<string> as an idempotency ledger. inFlight is just its size, and
every mutation is guarded by a membership test, so replaying any event is a
no-op:

} else if (held.delete(ev.grantToken)) {
  // Only a token we actually granted can give capacity back, and only once.
  inFlight = Math.max(0, inFlight - 1);
}

A new deterministic test covers the invariant — it delivers a release for a
token the coordinator never granted while a holder occupies the only permit,
then checks that no second holder gets in. It discriminates: with the
membership guard stubbed out it fails expected 2 to be 1 (the same
maxConcurrent + 1 signature), and passes with the guard in place.

Validated under load, 4 workers, .workflow-data cleared each time:
6/6 iterations clean post-fix (25 files / 82 tests). The same loop on the
pre-fix tree failed 2 of 4 iterations, both on the concurrency bound.

Replay-safety fix in the coordination patterns

Merging main turned the vitest job red — not a flake, a hard failure in ~3s:

Workflow replay diverged 4 times after 3 recovery replays.
Replay could not consume event: eventType=wait_created,
correlationId=wait_01KYKS4PJVB0DZ6992AJDVS740

Three shipped recipes had the same latent bug. withPermit, withRateLimit, and withBreaker each allocated their timeout after awaiting a step:

const grant = createHook<{ granted: true }>();
await sendRequest(key, ...);        // a step
const retryTimer = sleep(TIMEOUT);  // <- allocated after an await

Durable correlation IDs (step_…, wait_…, hook_…) come from a monotonic ULID factory seeded with a fixed timestamp, so the Nth allocation in a run always gets the Nth ID — order is the identity. A sleep() created after an await therefore inherits step-completion order, which isn't stable across replays when several holders run concurrently in one run: replay hands wait_… to a different caller than the one that logged it, and the run dies with CORRUPTED_EVENT_LOG.

Fix: hoist the sleep() into the same synchronous prefix as createHook(), so both IDs are allocated in call order before anything awaits. This also sharpens the semantics — the timeout now bounds the whole acquire (send + wait) rather than just the wait for the verdict.

The underlying runtime gap is separate and tracked upstream: the delivery barrier in packages/core orders hook↔wait deliveries against each other but not against step completions (repro #3137, fix #3139). This PR fixes the recipes, not the runtime.

That runtime gap did surface once in CI on this branch, on the in-run fan-out
test: step_started for step_… belongs to exitCritical, but the current step consumer is holdBriefly — a step/hook interleaving flipping across replays,
which is precisely what #3139 orders and what no barrier covers today
(registerDeliveryBarrier takes only 'hook' and 'wait' participants).

That observation predates the keyed-release fix above, and the two interact:
over-admission puts more chains inside the critical section than
maxConcurrent allows, multiplying the interleavings that can flip. The test
is deliberately left enabled rather than skipped — it is the regression
guard for the allocation-order hoist, and that regression also manifests as
ReplayDivergenceError, so tolerating the signature would gut the guard while
looking like it still worked. If CI diverges again now that admission is
bounded, that's a genuine #3139 sighting and worth quarantining explicitly;
until then it stays honest.

Coordinator start: at most once per sender, with backoff

sendBreakerEvent / sendSemaphoreEvent / sendSlotRequest called start(coordinator, …) on every failed resume. start() resolves on enqueue rather than execution, and the coordinator's hook token isn't claimed until it runs its first instruction — so N callers hitting a cold key spawned N × attempts throwaway runs, all but one immediately deduping. Each sender now starts the coordinator at most once and backs off exponentially, giving a cold coordinator room to boot and claim its token on a busy queue.

The budget is sized per pattern, against the deadline that pattern advertises. The semaphore and limiter retry 250ms → 4s over 10 attempts (~28s), well inside their ACQUIRE_RETRY_TIMEOUT (60s) and SLOT_RETRY_TIMEOUT (120s). The breaker is deliberately tighter — 250ms → 2s over 5 attempts (~6s) — because its send is awaited before the verdict race, so a longer budget would stretch the fail-open path past the CHECK_TIMEOUT (10s) the pattern promises.

Test shapes: cross-run is the contract, in-run is the regression guard

The semaphore and limiter concurrency tests fanned out inside a single run, which isn't the contract these patterns advertise — "at most N concurrent across all runs and machines". Those fan-outs are now separate workflow runs, with the shared counters living in the step bundle's module scope and read back through a small reader workflow. Each holder is then a single linear chain, which is also how you'd really deploy this.

The in-run Promise.all(items.map(i => withPermit(…))) shape is kept as an additional test for both patterns — it's what users will actually write against a documented recipe, and it's precisely the shape the hoist above protects. Both ran 5/5 clean locally.

Driver counters are deduped by stepId now, too: step execution is at-least-once, so a transparent runtime retry would double-count and the assertion would quietly lie.

Navigation, renames & redirects

  • Patterns added to the top nav before Worlds.
  • Renames with redirects (/patterns/* and /r/*): distributed-abort-controllerkill-switch (v5 shipped native AbortController, so the old name collided), rate-limitinghandling-rate-limits (it teaches 429 handling, freeing the name for the real limiter). Old /registry/*/patterns/*.
  • Cookbook pages superseded by a pattern are retired with /cookbook/* and /v5/cookbook/*/patterns/* redirects; the three substantive cookbook fixes that landed on main after this branched (ai-sdk durability, child-workflows hook-resume rewrite, DurableAgent deprecation) were ported into the patterns.
  • Taught the docs link linter about /patterns/<id> routes (mirrors the existing /worlds/<id> handling).

Brought up to date with main

This branch had gone stale, so main was merged in and the conflicts resolved. Notable fallout, all fixed here:

  • @types/react divergence. install-fixture pinned older next / react / @types/react than the workbench apps. pnpm hoists a single copy of a package into node_modules/.pnpm/node_modules/, so a second @types/react put two CSSProperties identities in the graph and broke the turbopack + webpack workbench deployments (CSSProperties not assignable to MotionStyle). Fixed by aligning the fixture's pins and loosening @types/react to ^19.
  • monaco-editor: "latest". Regenerating the lockfile re-resolved it 0.55.1 → 0.56.0, which added an exports map rooted at esm/vs/, so monaco-vim's legacy deep imports resolved to doubled paths and the swc-playground build failed. monaco-vim@0.4.4 is the newest release and has no exports-map-aware version, so monaco-editor is pinned to 0.55.1. Worth noting swc-playground still carries three other "latest" specifiers (@monaco-editor/react, @vercel/analytics, next-themes) — the same landmine.
  • Preview-toolbar feedback addressed. saga's Key APIs listed getWritable() and an optional emit()/SagaEvent streaming note; the pattern source uses neither, so both were corrected to the getStepMetadata() it actually imports (the other six patterns listing getWritable() were checked and do use it). The patterns hero no longer says "for popular providers", and "Submit your recipe" now points at the recipe directory rather than the repo root.
  • The /docs/foundations/workflows-and-steps link flagged as a 404 was real at the time — that page was added to main in docs: split v4/v5 content trees and fix version switcher end-to-end #1948 a day after the comment. The merge brings it in; all 16 Key-API links now resolve.

Known gaps from the geistdocs migration

main's move to @vercel/geistdocs (#2222) removed two things this branch previously had, with no supported replacement in @vercel/geistdocs@1.14.0:

  • The "New" pill on the Patterns nav item — the navbar exposes no badge slot at any layer.
  • The pattern detail page's Feedback and Open in Chat ToC actions — the backing modules were deleted and the package only offers replacements via non-exported internals. Scroll-to-top, Copy page, Ask AI, and Edit on GitHub all survive.

Both are cosmetic and can be restored if/when geistdocs exposes the hooks.

Test plan

  • pnpm dlx shadcn@latest add https://workflow-sdk.dev/r/semaphore installs the component and it typechecks/builds
  • /r/[name] returns valid registry-item.json with correct targets + dependencies
  • patterns-checks CI green: registry validation, codegen freshness, fixture typecheck + build, shadcn install e2e
  • workbench/vitest patterns suites green (52 tests across 17 suites), and the full workbench suite (25 files / 82 tests) clean 6/6 under load
  • Old /cookbook/*, /v5/cookbook/*, /registry/*, and renamed pattern URLs redirect correctly
  • Listing (tier + category filters, search) and detail pages (Usage / Source / version badges) render in light + dark mode

E2E note: the E2E Required Check failures on this branch match known main
flakes rather than anything the merge introduced — main itself was red on all
eight of its most recent tests.yml runs, the failing app rotates run to run,
and the individual tests/timeouts line up with the same failures on main
(webhookWorkflow at ~120s, HMR body-only at ~340s). The one Vercel-prod
failure passed on rerun.

Docs Preview

Base: https://workflow-docs-git-karthik-shadcn-registry-2.vercel.sh

Page Preview
Patterns listing /patterns
Component detail /patterns/semaphore
Template detail /patterns/saga
Example detail /patterns/stripe
Registry payload /r/semaphore
Retired cookbook redirect /v5/cookbook/common-patterns/saga/patterns/saga

Changed docs/content pages:

Page v5
foundations/starting-workflows preview
foundations/versioning preview
api-reference/workflow-api/start preview

The preview sits behind deployment protection, so these require Vercel team access.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
example-nextjs-workflow-turbopack Ready Ready Preview, Comment Jul 28, 2026 1:47pm
example-nextjs-workflow-webpack Ready Ready Preview, Comment Jul 28, 2026 1:47pm
example-workflow Ready Ready Preview, Comment Jul 28, 2026 1:47pm
workbench-astro-workflow Ready Ready Preview, Comment Jul 28, 2026 1:47pm
workbench-express-workflow Ready Ready Preview, Comment Jul 28, 2026 1:47pm
workbench-fastify-workflow Ready Ready Preview, Comment Jul 28, 2026 1:47pm
workbench-hono-workflow Ready Ready Preview, Comment Jul 28, 2026 1:47pm
workbench-nestjs-workflow Ready Ready Preview, Comment Jul 28, 2026 1:47pm
workbench-nitro-workflow Ready Ready Preview, Comment Jul 28, 2026 1:47pm
workbench-nuxt-workflow Ready Ready Preview, Comment Jul 28, 2026 1:47pm
workbench-sveltekit-workflow Ready Ready Preview, Comment Jul 28, 2026 1:47pm
workbench-tanstack-start-workflow Ready Ready Preview, Comment Jul 28, 2026 1:47pm
workbench-vite-workflow Ready Ready Preview, Comment Jul 28, 2026 1:47pm
workflow-docs Ready Ready Preview, 💬 4 unresolved, Open in v0 Jul 28, 2026 1:47pm
workflow-swc-playground Ready Ready Preview, Comment Jul 28, 2026 1:47pm
workflow-tarballs Ready Ready Preview, Comment Jul 28, 2026 1:47pm
workflow-web Ready Ready Preview, Comment Jul 28, 2026 1:47pm

@changeset-bot

changeset-bot Bot commented Apr 27, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 7228352

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

github-actions Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

📊 Workflow Benchmarks

commit 7228352 · Tue, 28 Jul 2026 14:04:40 GMT · run logs

Backend: vercel · app: nextjs-turbopack

Metric Scenario Best (ms) P75 (ms) P90 (ms) P99 (ms) Samples
TTFS step 400 (+57%) 🔻 1396 🔴 (+38%) 🔻 1413 🔴 (+35%) 🔻 1476 🔴 (+29%) 🔻 30
TTFS stream 1238 (+403%) 🔻 1323 🔴 (+29%) 🔻 1368 🔴 (+24%) 🔻 1439 🔴 (+24%) 🔻 30
TTFS hook + stream 1459 (+235%) 🔻 1561 🔴 (+32%) 🔻 1608 🔴 (+28%) 🔻 1710 🔴 (+30%) 🔻 30
STSO 1020 steps (1-20) 165 (-2.4%) 301 🔴 (+16%) 🔻 377 🔴 (+27%) 🔻 388 🔴 (-6.5%) 19
STSO 1020 steps (101-120) 181 (-7.7%) 259 🔴 (-10%) 381 🔴 (+7.9%) 419 🔴 (-17%) 💚 19
STSO 1020 steps (1001-1020) 463 (-4.1%) 530 🔴 (-8.1%) 678 🔴 (+4.6%) 876 🔴 (+21%) 🔻 19
WO 1020 steps 392923 (-5.9%) 392923 (-5.9%) 392923 (-5.9%) 392923 (-5.9%) 1
SL stream latency 87 (-8.4%) 160 🔴 (+3.9%) 192 🔴 (-32%) 💚 219 🔴 (-74%) 💚 30
SO stream overhead (text) 99 (-17%) 💚 129 (-31%) 💚 147 (-36%) 💚 701 (+65%) 🔻 30
SO stream overhead (structured) 94 (-18%) 💚 150 (-56%) 💚 166 (-73%) 💚 225 (-82%) 💚 30
📜 Previous results (2)

b3042f5

Tue, 28 Jul 2026 13:11:39 GMT · run logs

vercel / nextjs-turbopack

Metric Scenario Best (ms) P75 (ms) P90 (ms) P99 (ms) Samples
TTFS step 1231 (+385%) 🔻 1268 🔴 (+26%) 🔻 1289 🔴 (+23%) 🔻 1423 🔴 (+25%) 🔻 30
TTFS stream 342 (+39%) 🔻 1271 🔴 (+24%) 🔻 1278 🔴 (+16%) 🔻 1350 🔴 (+17%) 🔻 30
TTFS hook + stream 1461 (+236%) 🔻 1529 🔴 (+30%) 🔻 1577 🔴 (+26%) 🔻 1644 🔴 (+25%) 🔻 30
STSO 1020 steps (1-20) 163 (-3.6%) 241 🔴 (-6.9%) 298 🔴 (±0%) 502 🔴 (+21%) 🔻 19
STSO 1020 steps (101-120) 181 (-7.7%) 236 🔴 (-18%) 💚 243 🔴 (-31%) 💚 300 🔴 (-40%) 💚 19
STSO 1020 steps (1001-1020) 455 (-5.8%) 520 🔴 (-9.9%) 634 🔴 (-2.2%) 3421 🔴 (+374%) 🔻 19
WO 1020 steps 367573 (-12%) 367573 (-12%) 367573 (-12%) 367573 (-12%) 1
SL stream latency 91 (-4.2%) 144 🔴 (-6.5%) 168 🔴 (-40%) 💚 203 🔴 (-75%) 💚 30
SO stream overhead (text) 102 (-14%) 185 (-1.6%) 217 (-5.2%) 369 (-13%) 30
SO stream overhead (structured) 100 (-13%) 140 (-59%) 💚 150 (-76%) 💚 913 (-28%) 💚 30

9794b81

Tue, 28 Jul 2026 07:29:52 GMT · run logs

vercel / nextjs-turbopack

Metric Scenario Best (ms) P75 (ms) P90 (ms) P99 (ms) Samples
TTFS step 276 (+8.7%) 1294 🔴 (+28%) 🔻 1318 🔴 (+26%) 🔻 1441 🔴 (+26%) 🔻 30
TTFS stream 1235 (+402%) 🔻 1288 🔴 (+25%) 🔻 1303 🔴 (+19%) 🔻 1605 🔴 (+39%) 🔻 30
TTFS hook + stream 454 (+4.4%) 1509 🔴 (+28%) 🔻 1525 🔴 (+22%) 🔻 1563 🔴 (+19%) 🔻 30
STSO 1020 steps (1-20) 171 (+1.2%) 265 🔴 (+2.3%) 291 🔴 (-2.3%) 320 🔴 (-23%) 💚 19
STSO 1020 steps (101-120) 175 (-11%) 239 🔴 (-17%) 💚 266 🔴 (-25%) 💚 369 🔴 (-26%) 💚 19
STSO 1020 steps (1001-1020) 451 (-6.6%) 595 🔴 (+3.1%) 667 🔴 (+2.9%) 3473 🔴 (+382%) 🔻 19
WO 1020 steps 372517 (-11%) 372517 (-11%) 372517 (-11%) 372517 (-11%) 1
SL stream latency 90 (-5.3%) 128 🔴 (-17%) 💚 132 🔴 (-53%) 💚 156 🔴 (-81%) 💚 30
SO stream overhead (text) 99 (-17%) 💚 147 (-22%) 💚 156 (-32%) 💚 195 (-54%) 💚 30
SO stream overhead (structured) 100 (-13%) 148 (-57%) 💚 177 (-72%) 💚 251 (-80%) 💚 30
ℹ️ Metric definitions & methodology

Best/P75/P90/P99 deltas compare against the most recent benchmark run on main at the time of this run. 🔻 flags a delta worse than +15%, 💚 one better than −15%.

Metrics — TTFS: time to first step body (in-deployment start() → first step body, deployment clocks) · STSO: step-to-step overhead (gap between consecutive step bodies) · WO: workflow overhead (whole-run time outside step bodies, in-deployment anchored) · SL: stream latency (in-deployment write → read propagation, readAt - writtenAt) · SO: stream overhead (end-to-end write+consume time beyond the modelled generation window)

Scenarios — step: one trivial no-op step, no stream; no hooks, so the run stays in turbo mode (in-process fast path) · stream: one streaming step; no hooks, so the run stays in turbo mode (in-process fast path) · hook + stream: registers a hook before one step, which exits turbo mode (dispatch path) · 1020 steps: 1020 trivial sequential steps; STSO is measured between consecutive steps in the given step ranges, and WO is the whole-run overhead outside step bodies · stream latency: parallel reader/writer steps on a dedicated stream; SL is the in-deployment write->read propagation (readAt - writtenAt) · stream overhead (text): writer streams 300 variable-length text token deltas paced at 100/s for 3s (a haiku-size LLM's token throughput) while a parallel reader drains the whole stream; SO is the end-to-end write+consume time beyond the 3s generation window (overhead/backpressure) · stream overhead (structured): same workload as stream overhead (text), but each delta is an AI-SDK-style structured object ({ type: 'text-delta', id, text }) instead of a raw string, so the SO gap vs the text scenario is the added serialization cost

🔴 marks a percentile over its target (within target is left unmarked). Targets (p75/p90/p99, ms) — TTFS 200/300/600 · SL 50/60/125 · SO 250/500/1000 · STSO (1-20) 20/30/60 · STSO (101-120) 30/45/90 · STSO (1001-1020) 40/60/120

All metrics are measured from deployment-side timestamps only. Runs are triggered by an in-deployment route that stamps the anchor (clientStart) right before start(), so the CI runner’s request and its path through api.vercel.com sit outside every measured window. TTFS = in-deployment start() → first step body (turbo uses the in-process fast path, non-turbo the dispatch path), and includes the VQS dispatch hop plus any /flow cold start. STSO/WO are measured between step bodies on the deployment. SL is measured inside the workflow (parallel reader/writer steps), so it no longer includes the api.vercel.com read path.

Cold starts are kept in the numbers on purpose — they are part of real bursty-workload latency. The workbench deployment cold-starts the /flow invocation for a large fraction of runs, inflating P75+; the Best column shows the fastest (warm-start) sample for comparison.

@github-actions

github-actions Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

All tests passed

E2E Test Summary

Summary
Passed Failed Skipped Total
✅ ▲ Vercel Production 1455 0 239 1694
✅ 💻 Local Development 1621 0 227 1848
✅ 📦 Local Production 1621 0 227 1848
✅ 🐘 Local Postgres 1621 0 227 1848
✅ 🪟 Windows 154 0 0 154
✅ 📋 Other 1020 0 212 1232
✅ vercel-multi-region 27 0 0 27
Total 7519 0 1132 8651
Details by Category

✅ ▲ Vercel Production

App Passed Failed Skipped
✅ astro 126 0 28
✅ example 126 0 28
✅ express 126 0 28
✅ fastify 126 0 28
✅ hono 126 0 28
✅ nextjs-turbopack 151 0 3
✅ nextjs-webpack 151 0 3
✅ nitro 126 0 28
✅ nuxt 126 0 28
✅ sveltekit 145 0 9
✅ vite 126 0 28

✅ 💻 Local Development

App Passed Failed Skipped
✅ astro-stable 128 0 26
✅ express-stable 128 0 26
✅ fastify-stable 128 0 26
✅ hono-stable 128 0 26
✅ nextjs-turbopack-canary 135 0 19
✅ nextjs-turbopack-stable 154 0 0
✅ nextjs-webpack-canary 135 0 19
✅ nextjs-webpack-stable 154 0 0
✅ nitro-stable 128 0 26
✅ nuxt-stable 128 0 26
✅ sveltekit-stable 147 0 7
✅ vite-stable 128 0 26

✅ 📦 Local Production

App Passed Failed Skipped
✅ astro-stable 128 0 26
✅ express-stable 128 0 26
✅ fastify-stable 128 0 26
✅ hono-stable 128 0 26
✅ nextjs-turbopack-canary 135 0 19
✅ nextjs-turbopack-stable 154 0 0
✅ nextjs-webpack-canary 135 0 19
✅ nextjs-webpack-stable 154 0 0
✅ nitro-stable 128 0 26
✅ nuxt-stable 128 0 26
✅ sveltekit-stable 147 0 7
✅ vite-stable 128 0 26

✅ 🐘 Local Postgres

App Passed Failed Skipped
✅ astro-stable 128 0 26
✅ express-stable 128 0 26
✅ fastify-stable 128 0 26
✅ hono-stable 128 0 26
✅ nextjs-turbopack-canary 135 0 19
✅ nextjs-turbopack-stable 154 0 0
✅ nextjs-webpack-canary 135 0 19
✅ nextjs-webpack-stable 154 0 0
✅ nitro-stable 128 0 26
✅ nuxt-stable 128 0 26
✅ sveltekit-stable 147 0 7
✅ vite-stable 128 0 26

✅ 🪟 Windows

App Passed Failed Skipped
✅ nextjs-turbopack 154 0 0

✅ 📋 Other

App Passed Failed Skipped
✅ e2e-local-dev-nest-stable 128 0 26
✅ e2e-local-dev-tanstack-start- 128 0 26
✅ e2e-local-postgres-nest-stable 128 0 26
✅ e2e-local-postgres-tanstack-start- 128 0 26
✅ e2e-local-prod-nest-stable 128 0 26
✅ e2e-local-prod-tanstack-start- 128 0 26
✅ e2e-vercel-prod-nest 126 0 28
✅ e2e-vercel-prod-tanstack-start 126 0 28

✅ vercel-multi-region

App Passed Failed Skipped
✅ nextjs-turbopack 27 0 0

📋 View full workflow run

@karthikscale3
karthikscale3 changed the base branch from main to karthik/shadcn-registry April 27, 2026 21:03
Base automatically changed from karthik/shadcn-registry to main April 28, 2026 23:52
@karthikscale3
karthikscale3 force-pushed the karthik/shadcn-registry-2 branch from 8ad4dc6 to 36b9eb0 Compare April 29, 2026 23:46
karthikscale3 and others added 9 commits May 5, 2026 15:50
…ry-2

Resolved conflicts from the v4/v5 docs restructure on main:
- v4 cookbook pages kept intact from main (legacy docs unchanged)
- v5 cookbook pattern pages deleted (replaced by the Patterns tab),
  including child-workflows and upgrading-workflows which are now patterns
- v5 cookbook keeps only advanced/serializable-steps and
  advanced/publishing-libraries
- updated v5 links from /cookbook/common-patterns/workflow-composition
  to /patterns/workflow-composition
…terns

Each pattern declares which SDK majors it works with via a new required
`versions` field. Badges render on the listing card and detail hero, are
searchable (e.g. "v5"), and are included in the copy-page text. All 19
current patterns use APIs available in both v4 and v5.
Nav items support an optional badge label, rendered as a blue pill in
both the desktop and mobile menus.
…anch

- ai-sdk (#2099): tools inside the per-turn step are not individually
  durable — remove the misleading "use step" directives and durability
  claims, rewrite when-to-use, add the pitfall and corrected
  streamText-vs-DurableAgent comparison
- child-workflows (#2100): replace spawn-and-poll (getRun().status loop)
  with startAndWait() + withChildCompletionHook() hook resume
- durable-agent + agent-cancellation + human-in-the-loop (#2285):
  DurableAgent is deprecated in v5 — add warn callout and notes pointing
  at AI SDK v7's WorkflowAgent
- ai-sdk: add deployment-pinning versioning callout (#2010)
…-limits, fix resend install, concept-only tutorials

- distributed-abort-controller -> kill-switch: v5 ships native
  AbortController support, so the old name collided. KillSwitch is the
  cross-process, named, durable complement and the copy now explains the
  relationship.
- rate-limiting -> handling-rate-limits: the pattern teaches 429 handling
  with RetryableError, not rate limiting; frees the name for a real
  rate limiter component.
- resend: install paths now follow the workflows/ convention — its /r
  payload previously contained zero files (caption didn't match the
  workflows/ filter).
- sequential-and-parallel + workflow-composition: marked installable:false
  (all-placeholder code); Installation section hidden, /r returns a
  pointer to the readable page.
- redirects for all renamed slugs (incl. /r/*).
…terns

Phase 1: required patternType (component/template/example) with tier
badges on cards + detail hero, a type filter row, search matching, and
copy-page text.

Phase 2: child-workflows ships a reusable component file + worked
example; scheduling exposes cancellableSleep(); both promoted to
component tier.

Phase 3 (components, all on the coordination-workflow + single
event-channel architecture — timeouts injected as timer-child messages,
senders ensure-start coordinators, waiters self-heal with fresh reply
hooks): semaphore (withPermit/withLock), rate-limiter (withRateLimit),
circuit-breaker (withBreaker), debounce (debounceSend), batch-aggregator
(aggregatorSend), singleton-run (getOrStart/sendToSingleton).

Phase 4 (templates): polling, dead-letter-queue, recurring-cron.
Phase 5 (provider examples): stripe (dunning), slack-approval (HITL).

ROADMAP.md updated with implementation status and open items.
pranaygp added 4 commits June 12, 2026 15:03
…ry-2

* origin/main:
  Version Packages (beta) (#2364)
  Animate in-progress segments in the timeline (#2383)
  Render queued span time as a lead-in connector on the trace timeline. (#2381)
  fix(docs): right-align sidebar folder carets consistently (#2377)
  [core] Add wire-level framing for byte streams (#1853)
  docs: move World SDK and getWorld under workflow/runtime, split out workflow/observability (#2375)
  Replace hook.hasConflict with hook.getConflict() returning the conflicting Run (#2373)
  ci: use claude-fable-5 for backport AI model (#2370)
  Add `hook.hasConflict` for early hook conflict detection (#2015)
  [core] V2: unify wait+step queue dispatch in suspension processing (#1925)
  fix(world-local,world-postgres): make duplicate hook_created idempotent (#2295)
  docs(observability): remove MVP implementation detail bullet (#2367)
  fix: settle aborted parallel steps before completing abortParallelWorkflow (#2244)
- Merge origin/main to pick up hook.getConflict() (#2015/#2373 — also
  backported to v4 stable, so version badges are unchanged)
- All six coordinators + the singleton example claim their channel token
  with getConflict() at startup: a lost start race now returns
  { dedupedTo: winnerRunId } cleanly instead of dying with
  HookConflictError, and the early claim shrinks the start->registration
  window the send-with-ensure retry papers over
- kill-switch: fix loser-runId bug — after start(), adopt the REGISTERED
  owner's runId via getHookByToken instead of the started run's (a racing
  create() could previously hand back a handle whose .signal never fires)
- batch-aggregator: optional stable id on aggregatorSend(); coordinator
  dedupes — sends from retried steps are at-least-once
- docs honesty: aggregator/debounce acknowledged-but-dropped flush window,
  child-workflows at-least-once spawns, recurring-cron's generation-keyed
  token doubling as a schedule-fork guard
- ROADMAP: record residual gaps needing SDK support (atomic keyed start,
  native resumeOrStart, channel close+drain) with pointer to #2376
…version)

Pattern workflow code now lives as real, compiled, executable files in
workbench/vitest/workflows/patterns/ (19 files). docs snippet strings are
GENERATED from them by docs/scripts/sync-pattern-source.ts into
docs/lib/patterns/generated/ — the manifest imports display (header-
stripped) and full (install) variants from there; the hand-maintained
template-literal copies are deleted.

First proven test suite: patterns-semaphore (3 behavioral tests green
under @workflow/vitest — max-concurrency bound, release-on-throw, mutex
serialization). TESTING_NOTES.md captures the harness rules learned:
stepId-deduped side-effect counters (step execution is at-least-once),
unique keys per run (world persists across vitest invocations), afterAll
coordinator cancellation, waitForSleep/wakeUp over constant-shrinking.
- docs/scripts/validate-registry.ts: structural validation of every /r
  payload — files parse as TS, files[] metadata matches emissions, npm
  imports covered by the new dependencies field, env vars declared, DOCS
  links resolve. Found and fixed on first run: chat-sdk's lib/ files were
  never installed (the /r route filtered them out — broken install),
  sandbox emitted an undeclared file, 9 patterns missing dependency
  declarations, undeclared env vars.
- /r route now emits lib/-prefixed files (target: project root) and a
  dependencies array (cross-checked by the validator).
- workbench/install-fixture: committed Next.js app fixture; patterns are
  materialized (or CLI-installed) into it, then typechecked and built
  with the workflow SWC plugin. First run caught real API drift: sandbox
  pattern used Sandbox.sandboxId, current @vercel/sandbox identifies by
  .name; plus a stale @/app/workflows/chat-sdk import.
- docs/scripts/materialize-patterns.ts + install-e2e.sh (real shadcn CLI;
  verified locally: 28 patterns, 33 files, typecheck + next build green).
- .github/workflows/patterns-checks.yml: registry validation + codegen
  freshness + fixture typecheck/build + CLI install e2e on PRs.
- .github/workflows/patterns-nightly.yml: nightly prod-registry install
  with unpinned shadcn; failures open/update a tracking issue.
- Detail pages: Usage section (consumer API) now structurally separated
  from Source (full implementation, education-framed); usage snippets
  added for child-workflows and scheduling.
@socket-security

socket-security Bot commented Jun 12, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​@​vercel/​sandbox@​2.2.17210010098100
Addednpm/​@​chat-adapter/​state-redis@​4.30.07310010096100
Addednpm/​@​chat-adapter/​slack@​4.30.07710010096100
Addednpm/​chat@​4.30.0791009597100
Updatednpm/​radix-ui@​1.6.2 ⏵ 1.6.797 +110082 +298 +1100
Addednpm/​stripe@​22.2.08210010096100
Addednpm/​resend@​6.12.498100100100100

View full report

pranaygp added 3 commits June 12, 2026 16:26
… green)

22 suites / 74 tests under @workflow/vitest covering every canonical
pattern: semaphore (concurrency bound, FIFO, release-on-throw, mutex),
rate-limiter (grant spacing), circuit-breaker (threshold trip, instant
open rejection, reset-on-success, half-open recovery), debounce (burst →
one fire with latest payload, fresh burst after exit), batch-aggregator
(size flush, deadline flush, id dedupe), singleton-run (getOrStart
dedupe, mailbox ordering, race → dedupedTo), kill-switch (cross-process
abort, TTL expiry, create() races adopt the winner), child-workflows
(typed results, failure propagation, allSettled isolation), scheduling
(cancel/execute/cancellableSleep), recurring-cron (drift-corrected
ticks, clean stop, full continue-as-new generation handoff), plus
polling, DLQ, saga, batching, idempotency, timeouts, webhooks.

Tests found and fixed three shipped bugs:
- recurring-cron: racing stop.then() per iteration registered stale
  channel awaiters that swallowed the stop payload — any stop after the
  first tick deadlocked. Single shared stop promise now.
- child-workflows + recurring-cron: deploymentId 'latest' throws on
  worlds without resolveLatestDeploymentId (incl. local dev) — removed,
  kept as Vercel-scoped guidance.
- kill-switch: SWC step-mode transform strips module-level consts
  referenced only by the retained class -> ReferenceError on defaults;
  inlined. (Possible upstream swc-plugin issue, noted in ROADMAP.)

Replaceable action steps are now self-contained runnable demos (real
API calls kept as comments) so installed patterns work on first run.
Superseded cookbook copies retired; their unique coverage migrated.
Canonical edits re-synced to docs (sync-pattern-source); registry
validation, fixture typecheck and next build all green.
…enerated/ from biome

lint-staged formats canonical pattern files at commit time, which made
generated output drift from what a pre-commit sync produced. Generated
modules are now biome-ignored (they're codegen output; the clean-check
compares raw generator output) and re-synced against the formatted
canonical files.
Resolved conflicts: the six v5 cookbook pages main touched in #2391 (link
repair) stay deleted on this branch — they're replaced by the Patterns
tab. Audited the patterns against #2391's link fixes and corrected stale
internal doc links the now-working link linter flagged (use-step,
use-workflow, get-step-metadata API-reference moves). Taught the link
linter about /patterns/<id> detail routes (mirrors /worlds/<id>).

Copilot AI left a comment

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

pranaygp added 3 commits July 27, 2026 23:38
…ry-2

* origin/main: (292 commits)
  feat(core): seal forwarded stream writes to the owner's public key (#3098)
  feat(core): seal hook payloads to the target run's public key (#3096)
  [e2e] Rebuild the event-log corruption repro around step-count divergence (#3147)
  feat: decrypt sealed payloads in the dashboard and CLI (#3146)
  Prewarm only appended replay payloads (#3131)
  feat: publish each run's X25519 public key on the run entity (#3095)
  feat(core): route sealed envelopes through the serialization layer (#3094)
  docs: redirect retired migration-guides URLs to comparisons (#3127)
  feat(core): add `encp` sealed-box encryption primitive (#3093)
  chore(core): clarify runtime comments (#3111)
  Remove obsolete world factory aliases (#3112)
  feat(core): deterministic sandbox hardening (#3045)
  Remove retired v1 step route plumbing (#3061)
  [core] Don't count racing invocations' duplicate step_started events toward the maxRetries ceiling (#3069)
  [world-testing] Isolate each spawned test server's data directory (#3055)
  fix: upgrade postcss to >=8.5.18 to address GHSA-r28c-9q8g-f849 (#3102)
  [next] Respect .gitignore in dev watcher to avoid EMFILE on large monorepos (#3085)
  [ci] Backport only stability fixes to `stable`, default to claude-opus-5 (#3092)
  perf(core): immediate leading-edge dispatch for idle streams (flush window default 0) (#3088)
  Optimize `processImportSpecifier` by computing `shouldFollowImportsFromFile` once per file (#3052)
  ...

# Conflicts:
#	docs/components/geistdocs/desktop-menu.tsx
#	docs/components/geistdocs/mobile-menu.tsx
#	docs/content/docs/v5/cookbook/advanced/child-workflows.mdx
#	docs/content/docs/v5/cookbook/advanced/upgrading-workflows.mdx
#	docs/content/docs/v5/cookbook/agent-patterns/agent-cancellation.mdx
#	docs/content/docs/v5/cookbook/agent-patterns/durable-agent.mdx
#	docs/content/docs/v5/cookbook/agent-patterns/human-in-the-loop.mdx
#	docs/content/docs/v5/cookbook/common-patterns/batching.mdx
#	docs/content/docs/v5/cookbook/common-patterns/idempotency.mdx
#	docs/content/docs/v5/cookbook/common-patterns/rate-limiting.mdx
#	docs/content/docs/v5/cookbook/common-patterns/saga.mdx
#	docs/content/docs/v5/cookbook/common-patterns/scheduling.mdx
#	docs/content/docs/v5/cookbook/common-patterns/sequential-and-parallel.mdx
#	docs/content/docs/v5/cookbook/common-patterns/timeouts.mdx
#	docs/content/docs/v5/cookbook/common-patterns/webhooks.mdx
#	docs/content/docs/v5/cookbook/common-patterns/workflow-composition.mdx
#	docs/content/docs/v5/cookbook/index.mdx
#	docs/content/docs/v5/cookbook/integrations/ai-sdk.mdx
#	docs/content/docs/v5/cookbook/integrations/chat-sdk.mdx
#	docs/content/docs/v5/cookbook/integrations/sandbox.mdx
#	docs/next.config.ts
#	docs/proxy.ts
#	docs/scripts/lint.ts
#	pnpm-lock.yaml
#	pnpm-workspace.yaml
Post-merge fixes for main's #2222, which replaced the local geistdocs
chrome with the published @vercel/geistdocs package and deleted the
components the patterns pages imported.

- Point Button/Input/Separator/Mermaid/CodeBlock imports at the package.
- Rebuild RegistryDetailToc against the package: use its AskAIButton,
  inline ScrollTop and CopyPage (their deps survive the migration), and
  drop Feedback + Open-in-Chat, whose entire infrastructure (app actions,
  ai-elements, ui/popover, ui/textarea) was deleted and is only reachable
  through the package's non-exported internals.
- Restore the sitemap link in the llms.mdx route via the package's
  transform hook, keeping agent-discoverable sitemap behavior intact.
- Port #2616's DurableAgent -> WorkflowAgent deprecation notes into the
  pattern manifest prose.
- Fix a validate-registry type error: use the narrowed caption local
  instead of the optional snippet.caption.
@socket-security

socket-security Bot commented Jul 28, 2026

Copy link
Copy Markdown

All alerts resolved. Learn more about Socket for GitHub.

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.

View full report

pranaygp and others added 4 commits July 27, 2026 23:58
The fixture pinned next@16.2.1 / react@19.2.4 / @types/react@19.2.4,
which predate main's bump to next@16.2.11 / react@19.2.7. Because the
lockfile is shared across the workspace, that pulled a second copy of
@types/react into the graph and broke two checks:

  - Patterns Fixture Typecheck: NextConfig from next@16.2.1 was not
    assignable to NextConfig from next@16.2.11 (compiler.define variance).
  - nextjs-turbopack / nextjs-webpack Vercel builds: motion's .d.ts
    resolves react via the hoisted copy under .pnpm/node_modules, which
    diverged from the 19.1.13 those workspaces symlink directly. Two
    CSSProperties identities => "Type 'CSSProperties' is not assignable
    to type 'MotionStyle'" in ai-elements/shimmer.tsx, a file this
    branch never touches.

Pins now match nextjs-turbopack/nextjs-webpack, and @types/react
collapses to a single version (19.1.13) across the lockfile.

Also drops workbench/install-fixture/tsconfig.tsbuildinfo, a TS
incremental cache committed by accident in 671fb1b (the only
tsbuildinfo tracked in the repo), and gitignores it.

Lockfile regeneration incidentally bumped monaco-editor 0.55.1->0.56.0,
@monaco-editor/react 1.6.2->1.6.7 and dompurify 3.2.7->3.4.8:
workbench/swc-playground pins both monaco specifiers as "latest", so
they re-resolve on any install.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…erns hero copy

The lockfile regeneration in 763fd34 re-resolved swc-playground's
"monaco-editor": "latest" from 0.55.1 to 0.56.0, which added an exports map
rooted at esm/vs/ ("./*": "./esm/vs/*.js"). That makes monaco-vim's legacy
deep imports resolve to doubled paths (esm/vs/esm/vs/editor/editor.api.js)
and broke the Turbopack build. monaco-vim@0.4.4 is the newest release and has
no exports-map-aware version, so pin monaco-editor to 0.55.1 — what main
already resolves.

Also addresses preview toolbar feedback on the patterns pages:
- saga listed getWritable() under Key APIs and described optional emit()/
  SagaEvent streaming; the pattern source uses neither. Swapped in the
  getStepMetadata() it actually imports. Verified the other six patterns
  listing getWritable() do use it.
- patterns index said "for popular providers", which misdescribes the library.
- "Submit your recipe" pointed at the repo root instead of the directory
  where recipes live.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…in-run calls

`Vitest Plugin Tests` was failing on the semaphore's in-run fan-out with a
ReplayDivergenceError (`Replay could not consume event: eventType=wait_created`),
not a timeout — the run diverged at 3.2s.

Root cause: durable correlation IDs come from a monotonic ULID factory seeded
with a fixed timestamp, so the Nth allocation in a replay must be the Nth
allocation in the original run. `sleep()` allocates its wait eagerly at call
time, so a `sleep()` written *after* an `await` inherits step-completion order.
When several `withPermit()` / `withRateLimit()` / `withBreaker()` calls run
concurrently inside one run, step completions interleave nondeterministically
and the wait IDs get reassigned on replay.

Fix: allocate the hook and its timer in one synchronous prefix, before the
first await. Allocation then follows call order, which is stable. As a
side effect the timeout budget now covers the request/check step too — that
bounds the whole acquire/admission, which is the behaviour the docs already
describe.

The runtime's delivery barriers order hook deliveries against wait deliveries
but do not include step results, which is why the recipes have to carry this
themselves for now. Upstream: #3137 (repro) / #3139 (fix), both open.

Also in this change:

- Coordinator start is now at-most-once per send, with exponential backoff.
  Previously every failed `resume` fired another `start()`, so N concurrent
  cold callers produced N x attempts throwaway runs — `start()` resolves on
  enqueue, but the token isn't claimed until the run executes.
  The breaker's send budget is deliberately held under its CHECK_TIMEOUT
  (5 attempts, 250ms->2s, ~5.75s < 10s): the send is awaited before the
  verdict race, so a longer budget would stretch the fail-open path past the
  deadline the pattern promises.

- Tests now cover both shapes. Cross-run fan-out is the contract these
  coordinators actually advertise (one permit/slot cluster-wide); in-run
  fan-out is the regression guard for the divergence above. The earlier
  cross-run conversion had dropped the in-run cases entirely — they are
  restored as additional tests, so coverage is strictly better than before.

- Driver counters dedupe by stepId. Step execution is at-least-once, so an
  undeduped counter double-counts on a transparent retry and the assertion
  silently lies.

Generated docs sources re-synced via `pnpm sync-pattern-source`.
… can't mint capacity

sendSemaphoreEvent retries resume() in a catch-and-retry loop, and the step
wrapping it is itself at-least-once, so a release that actually landed can
look like a failure to its sender and be sent again. The coordinator's
release branch was unkeyed:

  } else {
    inFlight = Math.max(0, inFlight - 1);
  }

so it could not tell a duplicate from a real release. Each extra copy handed
back capacity nobody gave up and let one more holder into the critical
section — max = maxConcurrent + 1, the 4 > 3 the fan-out test was
intermittently reporting.

Both events now carry the holder's grantToken and the coordinator keeps a
held Set as an idempotency ledger: inFlight is its size, and every mutation
is guarded by a membership test, so replaying any event is a no-op.

Adds a deterministic regression test that delivers a release for a token the
coordinator never granted while a holder occupies the only permit, then
asserts no second holder gets in. It discriminates — with the membership
guard stubbed out it fails "expected 2 to be 1" (same maxConcurrent + 1
signature) and passes with the guard in place.

Validated with 6 consecutive full-suite runs at --maxWorkers=4 (25 files,
82 tests, all green); the pre-fix baseline failed 2 of 4.
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