Skip to content

perf(onboarding): optimize onboarding pipeline from ~5min to ~2min#2777

Merged
Marfuen merged 28 commits into
mainfrom
mariano/onboarding-perf
May 7, 2026
Merged

perf(onboarding): optimize onboarding pipeline from ~5min to ~2min#2777
Marfuen merged 28 commits into
mainfrom
mariano/onboarding-perf

Conversation

@Marfuen
Copy link
Copy Markdown
Contributor

@Marfuen Marfuen commented May 7, 2026

Summary

Major performance overhaul of the onboarding pipeline. Sales demos were suffering because prospects stared at a spinner for 4-5 minutes.

Orchestration changes

  • Policies fire first — they only need frameworks + Q&A, no dependency on vendors/risks/linkage
  • Vendor + risk extraction run in parallel — both are independent LLM calls
  • Policies are fire-and-forgetbatchTriggerAndWaittasks.batchTrigger so the main task completes in ~27s instead of blocking for 3-4min
  • Vendor side-effects are non-blocking — risk assessment API + research triggers no longer block vendor creation
  • DB mutations parallelized — owner update + task updateMany merged and run concurrently
  • Vendor research parallelized — serial for await loop → Promise.allSettled

Policy generation rewrite

  • Replaced LLM-based generation with programmatic template processor — walks the TipTap JSON tree, replaces {{COMPANY}} placeholders with Q&A values, evaluates {{#if hipaa}}...{{/if}} conditionals based on framework flags
  • Targeted LLM pass only for cue lines — ~10/28 policies have instruction text ("State that...", "Define...") that needs rewriting. Batches them into a single claude-sonnet-4.6 call per policy instead of regenerating the entire document
  • Result: ~120ms per policy instead of ~30s (28 policies finish in 2-3s total)

Linkage optimization

  • Risk + vendor matching run in parallel — were sequential, now overlap via Promise.all
  • Reranker switched to gemini-3.1-flash-lite — scoring 0-10 relevance doesn't need a heavy model

Model migrations

  • All onboarding LLM calls switched to gemini-3-flash via AI gateway (vendor/risk extraction, mitigations)
  • AI SDK upgraded to v6/v3 across all workspaces
  • Policy concurrency raised from 5 → 15 — original concern about slot starvation no longer applies

UI fixes

  • OnboardingTracker stays visible while background work finishes (policies, mitigations)
  • All useRealtimeRunuseRun with polling — SSE stream closes when parent completes, leaving metadata stale
  • task.batchTriggertasks.batchTrigger for policies, vendors, and risks to preserve parent-child metadata hierarchy
  • Spinner animations synchronized across tracker steps
  • Framework conditional handling expanded (pipeda, gdpr, iso27001, pci, nist, ccpa)

Cleanup

  • Removed caBundleExtension from trigger config (rds-global-bundle.pem no longer exists)
  • Removed ~350 lines of dead LLM policy generation code
  • Fixed convertToModelMessages async change from AI SDK v6

Results

Metric Before After
Main task completion 4-5 min 27s
All work done 5-6 min ~2 min
Policies (28) 3-4 min 2-3s
User sees dashboard After 4-5 min After 27s

Test plan

  • Onboarding creates all 28 policies with correct placeholder replacement
  • Handlebars conditionals evaluate correctly (soc2, hipaa, pipeda, gdpr)
  • Cue lines rewritten to policy language (28/28 clean)
  • Vendor + risk mitigations complete and update tracker metadata
  • Tracker shows live progress for all steps including after main task completes
  • Policies page banner clears when 28/28 done
  • Typecheck passes for apps/app and apps/api

🤖 Generated with Claude Code


Summary by cubic

Cuts onboarding from 5–6 minutes to ~2 minutes and sends users to the dashboard in ~27 seconds by parallelizing the pipeline, replacing slow policy LLMs with a fast TipTap template processor, and keeping the run alive for mitigation tracking while redirecting early. Also fixes tracking edge cases so the progress UI stays accurate during background work.

  • Performance

    • Policies: programmatic TipTap template processor with framework conditionals (soc2, hipaa, pipeda, gdpr, iso27001, pci, nist, ccpa) and a small cue-line rewrite pass; fixed nested {{#if}} leakage and preserved whitespace; ~120ms per policy (28 in 2–3s).
    • Orchestration: policies fire first and use tasks.batchTrigger (fire-and-forget); vendor and risk extraction run in parallel; DB updates parallelized; mitigations use tasks.batchTriggerAndWait with sequential triggerAndWait so metadata stays writable while a readyForDashboard flag redirects users early.
    • Linkage: risk and vendor matching run in parallel; reranker switched to google/gemini-3.1-flash-lite-preview via @ai-sdk/gateway; lowered MATCH_CONCURRENCY to 16.
    • Models/Deps: all onboarding calls use google/gemini-3-flash via @ai-sdk/gateway; upgraded to ai@6 and @ai-sdk/*@3; policy queue concurrency raised to 15; removed caBundleExtension; awaited convertToModelMessages per v6.
  • UI

    • Tracker uses useRun polling, stays visible during background work, and shows live per-step progress after the early redirect.
    • Six steps: Tailoring Policies, Creating Vendors, Creating Risks, Linking to Controls, Assessing Vendors, Assessing Risks; with expandable per-item lists and vendor/risk totals, completed links open the Treatment Plan tab; fixed currentStep label to match “Tailoring Policies…” and treat “assessing” as an active spinner.

Written for commit da3618d. Summary will update on new commits.

Marfuen and others added 21 commits May 7, 2026 11:06
… policies

The onboarding task blocked for ~4 minutes waiting for all 30+ policy
LLM calls to finish before marking completion. Sales demos suffered
because the prospect stared at a spinner the entire time.

Key changes:
- Policy fan-out switched from batchTriggerAndWait to batchTrigger so
  the main task completes in ~35-70s instead of ~4-5min. Per-policy
  progress is already tracked via child metadata.
- Policy fan-out moved before the linkage gate since policies don't
  depend on linkage — they start generating ~30-60s earlier.
- Vendor and risk extraction (both independent LLM calls) now run in
  parallel via Promise.all instead of serially.
- Owner lookup parallelized with frameworkInstances query.
- Two task.updateMany calls (assignee + frequency) merged into one.
- triggerVendorResearch serial for-await loop replaced with
  Promise.allSettled for parallel trigger.dev RPCs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The link-risks-and-vendors-to-work task was taking ~2.5 minutes because
risk matching (11 LLM rerank calls) and vendor matching (10 LLM rerank
calls) ran sequentially. Both phases write to independent DB tables
(Risk.tasks vs Vendor.tasks) and share only a read-only taskById map,
so they can safely overlap.

Wraps the two mapWithConcurrency calls in Promise.all. Expected
wall-time reduction: ~75s (from ~150s to ~75s) since the slower phase
no longer has to wait for the other to finish.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…-flash

The LLM reranker dominates linkage wall time (~7s per entity). Gemini 3
Flash is significantly faster and cheaper while being sufficient for the
scoring task (0-10 relevance rating on compliance task candidates).

Uses the AI SDK gateway so the model swap is a one-line change with no
new API key management needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… gateway

Upgrades ai@6.0.175, @ai-sdk/openai@3.0.62, @ai-sdk/anthropic@3.0.75,
@ai-sdk/gateway@3.0.110, @ai-sdk/google@3.0.68 across all workspaces.

The gateway v3 upgrade resolves the v2 specification compatibility
warning. Reranker now uses google/gemini-3-flash via the AI gateway
for faster, cheaper linkage scoring.

Fixes:
- gateway.ts ModelOptions type: LanguageModelV2 → LanguageModelV3
- policies.controller.ts: await convertToModelMessages (now async in v6)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The inlined RDS CA bundle was dropped in cd5046c in favor of Node's
default trust store. The extension was failing in dev because
rds-global-bundle.pem no longer exists.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Same ai SDK v6 breaking change as policies.controller.ts —
convertToModelMessages is now async.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…get flow

Three issues caused the onboarding tracker to lose step tracking:

1. Merged "Researching Vendors and Risks..." currentStep never matched
   the "Creating Risks" label in the tracker. Fixed by setting
   currentStep to "Researching Vendors..." initially and switching to
   "Creating Risks..." when vendors finish or risks start.

2. policies: true was set immediately after batchTrigger (fire-and-forget)
   before any policy was actually generated. Removed — the tracker
   already derives completion from policiesCompleted >= policiesTotal.

3. The tracker auto-minimized on run.status === COMPLETED, which now
   fires before policies/mitigations finish. Changed to also check
   that all counters (policies, vendors, risks) have reached their
   totals before auto-minimizing.

Also added a hasBackgroundWork branch to the COMPLETED render path so
the tracker shows live per-step progress while child tasks are still
running, instead of prematurely showing "Setup Complete".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…licy templates

Policy templates use {{#if pipeda}}...{{/if}} handlebars syntax but
the prompt only evaluated soc2 and hipaa, defaulting everything else
to false. Added a generic framework matcher that covers pipeda, gdpr,
iso27001, pci, nist, and ccpa so new framework conditionals don't
silently strip content.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ound work

When the main task is COMPLETED but child tasks are still running,
the switch now maps to the EXECUTING render path (which has the full
expandable vendor/risk/policy lists) instead of a simplified flat
view that was missing the expand arrows.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…nt metadata

updatePolicy.batchTrigger() creates independent runs with no parent
relationship, so metadata.parent in the policy tasks was null and
completion counters never reached the onboarding task's metadata.

Switched to tasks.batchTrigger() which creates child runs, restoring
the parent-child relationship needed for per-policy progress tracking.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The concurrencyKey was lost when switching from updatePolicy.batchTrigger
to tasks.batchTrigger. Without it, the queue's concurrencyLimit: 5
applies globally across all orgs instead of per-org, causing policy
runs from different onboarding sessions to block each other.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Each Loader2 spinner computed its own Date.now() offset independently,
causing them to rotate out of phase. Moved the offset into a single
useMemo so all spinners share the same animation delay.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Policies now fire before mitigations (different phase) and mitigations
use their own queues, so the original concern about slot starvation
no longer applies. 15 concurrent cuts policy wall time roughly 3x.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…3-flash

All three LLM calls in update-policies-helpers.ts (content generation,
format reconciliation, format check) now use google/gemini-3-flash via
the AI gateway. Gemini Flash is significantly faster for structured
output tasks like TipTap JSON generation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ing vendor side-effects

Three changes:

1. Policy fan-out now fires BEFORE vendor/risk extraction. Policies
   only need frameworks + Q&A context, so they start draining
   immediately instead of waiting 10-50s for vendor/risk creation.

2. All four LLM calls in onboard-organization-helpers (vendor
   extraction, risk extraction, vendor mitigation, risk mitigation)
   switched from openai gpt-4.1-mini/gpt-5-mini to google/gemini-3-flash
   via the AI gateway.

3. triggerVendorRiskAssessmentsViaApi and triggerVendorResearch are now
   fire-and-forget (void instead of await). These are side effects
   that were adding 2-15s to the vendor creation path without
   contributing to the onboarding flow.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…plate processor

Policy generation was the single slowest step — each of the 28 policies
required a 25-35s LLM call to regenerate the entire TipTap JSON document.

Since the templates already contain the full policy structure with
handlebars placeholders ({{COMPANY}}, {{#if hipaa}}...{{/if}}), the LLM
was doing work that can be done programmatically:

- {{PLACEHOLDER}} replacement with values from the onboarding Q&A
- {{#if framework}}...{{/if}} conditional evaluation based on selected
  frameworks (soc2, hipaa, pipeda, gdpr, iso27001, pci, nist, ccpa)

The new process-policy-template.ts walks the TipTap JSON tree, replaces
placeholders, evaluates conditionals (including nested and multi-node
spans), and returns the processed content. No LLM call needed.

Result: ~10ms per policy instead of ~30s. 28 policies finish in under
1 second total instead of ~60s.

Also removes ~350 lines of dead LLM-based code (generatePolicyContent,
reconcileFormatWithTemplate, aiCheckFormatWithTemplate, and all their
helpers) and the OPENAI_API_KEY requirement from update-policy.ts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…lling

useRealtimeRun's SSE stream closes when the parent run completes,
causing the last few child task metadata updates (counter increments)
to never reach the UI. This left counters stuck at e.g. 25/28.

Switched to useRun with refreshInterval: 1000ms which polls the run
metadata every second. This guarantees the UI eventually reflects all
child completions regardless of when the parent run finishes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Some policy templates contain instruction text ("State that...",
"Define...", "Add a...") that needs to be converted to direct policy
language. The programmatic processor can't handle these since they
require judgment.

Adds a refineCueLines step that:
1. Scans processed content for cue line patterns
2. If found, batches them into a single LLM call (claude-sonnet-4.6)
3. Splices the rewrites back into the TipTap nodes

Only fires for ~10/28 policies that have cue lines. Policies without
cue lines skip the LLM entirely and remain instant. Fails soft —
if the LLM call errors, the original instruction text is preserved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The reranker just scores 0-10 relevance on pre-filtered candidates —
doesn't need a heavy model. Flash lite should cut the per-call latency
that was causing 44s stragglers in the linkage pipeline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Same issue as the policy fix — task.batchTrigger() creates independent
runs with no parent relationship, so metadata.root was null in the
individual mitigation tasks and counter updates never reached the
onboarding run's metadata. The tracker showed 0/N permanently.

Switched both fan-out tasks to tasks.batchTrigger() which preserves
the parent-child hierarchy needed for metadata.root to resolve.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
useRealtimeRun's SSE stream closes when the parent run completes,
leaving metadata stale. This caused the policies page to show
"Tailoring your policies" with a spinner even after 28/28 were done.

Switched to useRun with refreshInterval: 1000ms in all components
that track onboarding run metadata: policies-table, policy onboarding
status hook, risk/vendor onboarding status hook, and ToDoOverview.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 7, 2026

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

Project Deployment Actions Updated (UTC)
app Ready Ready Preview, Comment May 7, 2026 0:17am
comp-framework-editor Ready Ready Preview, Comment May 7, 2026 0:17am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
portal Skipped Skipped May 7, 2026 0:17am

Request Review

… tracking

The tracker now shows granular progress for each phase:

1. Tailoring Policies (28/28) — expandable per-policy list
2. Creating Vendors — simple checkmark when done
3. Creating Risks — simple checkmark when done
4. Linking to Controls — checkmark when linkage completes
5. Assessing Vendors (0/11) — expandable per-vendor mitigation list
6. Assessing Risks (0/12) — expandable per-risk mitigation list

Previously vendor/risk creation and mitigation were conflated into one
step, showing 0/N for a long time during linkage even though vendors
and risks were already created.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

4 issues found across 24 files

Confidence score: 2/5

  • High-confidence logic risk in apps/app/src/trigger/tasks/onboarding/process-policy-template.ts: nested {{#if}} handling may leak content from an outer false branch because openMatch does not short-circuit when skipDepth > 0, which can produce incorrect rendered policy output.
  • apps/app/src/lib/embedding/run-linkage.ts may exceed intended rate-limit-safe throughput: running risk and vendor pipelines in parallel while each uses MATCH_CONCURRENCY can effectively double peak concurrency.
  • A second rendering regression is likely in apps/app/src/trigger/tasks/onboarding/process-policy-template.ts: trimming every text node can remove meaningful spacing between adjacent TipTap nodes and merge words in final policies, so overall merge risk is elevated beyond a minor fix.
  • Pay close attention to apps/app/src/trigger/tasks/onboarding/process-policy-template.ts and apps/app/src/lib/embedding/run-linkage.ts - template correctness and concurrency caps are the main user-impacting risks.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/app/src/lib/embedding/run-linkage.ts">

<violation number="1" location="apps/app/src/lib/embedding/run-linkage.ts:621">
P2: Running risk and vendor pipelines in parallel with `MATCH_CONCURRENCY` on both sides can double peak concurrency and exceed the intended rate-limit-safe cap.</violation>
</file>

<file name="apps/app/src/app/(app)/[orgId]/risk/(overview)/hooks/use-onboarding-status.ts">

<violation number="1" location="apps/app/src/app/(app)/[orgId]/risk/(overview)/hooks/use-onboarding-status.ts:18">
P3: Passing an empty string to useRun triggers an unnecessary HTTP request when onboardingRunId is null/undefined. Consider passing null (with a type assertion) or undefined instead to rely on SWR's built-in conditional-fetch behavior, which skips the request entirely.</violation>
</file>

<file name="apps/app/src/trigger/tasks/onboarding/process-policy-template.ts">

<violation number="1" location="apps/app/src/trigger/tasks/onboarding/process-policy-template.ts:82">
P2: Trimming every text node can remove meaningful spacing between adjacent TipTap nodes, producing merged words in rendered policies.</violation>

<violation number="2" location="apps/app/src/trigger/tasks/onboarding/process-policy-template.ts:130">
P1: Nested `{{#if}}` blocks can leak content from a skipped outer false branch because `openMatch` processing doesn't short-circuit when `skipDepth > 0`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

Comment thread apps/app/src/trigger/tasks/onboarding/process-policy-template.ts
Comment thread apps/app/src/lib/embedding/run-linkage.ts
Comment thread apps/app/src/trigger/tasks/onboarding/process-policy-template.ts Outdated
…ta flag

Trigger.dev silently drops metadata writes to completed runs. Since
the main task completed before mitigations started, all per-entity
status updates (vendor_${id}_status, risksCompleted, etc.) were lost.

Fix: switch mitigations from tasks.trigger (fire-and-forget) to
tasks.triggerAndWait so the main task stays alive and metadata.root
remains writable. The user still redirects early via a readyForDashboard
metadata flag set before mitigations begin.

The redirect page now checks metadata.readyForDashboard instead of
only run.status === COMPLETED, so the user hits the dashboard in ~27s
while the task continues running for another ~90s to complete mitigations
with live progress tracking.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Creating Vendors and Creating Risks steps now show the total count
(e.g. "Creating Vendors  11") so the user sees how many were created.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel vercel Bot temporarily deployed to Preview – portal May 7, 2026 11:53 Inactive
Trigger.dev doesn't support Promise.all with triggerAndWait. Changed to
sequential awaits — vendor mitigations finish first, then risk mitigations.

Both fan-out tasks now use batchTriggerAndWait so they stay alive until
all children complete, keeping the full task hierarchy alive for
metadata.root writes.

Individual mitigations still run with full queue concurrency (50) within
each fan-out. Risk mitigations start queueing while vendor mitigations
drain, so the sequential overhead is minimal.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Vendor and risk links in the tracker now include ?tab=treatment-plan
so clicking a completed assessment goes directly to the generated
mitigation plan.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
P1: Nested {{#if}} inside a false block could leak content. When
skipDepth > 0 (inside a skipped block), any new {{#if}} now always
increments skipDepth without evaluating its condition or processing
content. Previously a true inner condition would emit its content
even though the outer block was false.

P2: Text node trim removed meaningful whitespace between adjacent
TipTap inline nodes, causing merged words. Removed the trim() call
from processTextNode — placeholder replacement and conditional
evaluation don't introduce extra whitespace that needs cleaning.

P2: Parallel risk+vendor matching could double peak LLM concurrency.
Reduced MATCH_CONCURRENCY from 32 to 16 so both sides combined stay
under ~32 concurrent rerank calls.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 7 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/app/src/app/(app)/[orgId]/components/OnboardingTracker.tsx">

<violation number="1" location="apps/app/src/app/(app)/[orgId]/components/OnboardingTracker.tsx:30">
P2: The vendors step label no longer matches one emitted `currentStep` value (`Researching Vendors...`), so active-step mapping returns `null` during that phase.</violation>

<violation number="2" location="apps/app/src/app/(app)/[orgId]/components/OnboardingTracker.tsx:569">
P3: `assessing` is an active status, but item rows only treat `processing` as active, so running mitigations appear queued/idle.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.
Fix all with cubic

Comment thread apps/app/src/app/(app)/[orgId]/components/OnboardingTracker.tsx
Comment thread apps/app/src/app/(app)/[orgId]/components/OnboardingTracker.tsx Outdated
- Initial currentStep was still 'Researching Vendors...' which doesn't
  match any tracker label. Changed to 'Tailoring Policies...' since
  that's the first step now.

- Vendor/risk item rows only treated 'processing' as active (spinner).
  The 'assessing' status (set during creation) is also an active state
  and now shows a spinner instead of a clock.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Marfuen
Copy link
Copy Markdown
Contributor Author

Marfuen commented May 7, 2026

@cubic-dev-ai re-review this

@cubic-dev-ai
Copy link
Copy Markdown
Contributor

cubic-dev-ai Bot commented May 7, 2026

@cubic-dev-ai re-review this

@Marfuen I have started the AI code review. It will take a few minutes to complete.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 25 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

@Marfuen Marfuen merged commit b14db0b into main May 7, 2026
11 checks passed
@Marfuen Marfuen deleted the mariano/onboarding-perf branch May 7, 2026 12:25
@claudfuen
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 3.45.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants