Skip to content

feat: implement ensureReady method for lazy bundle source initialization#500

Merged
frontegg-david merged 5 commits into
release/1.5.xfrom
fix-zod-schema
Jun 22, 2026
Merged

feat: implement ensureReady method for lazy bundle source initialization#500
frontegg-david merged 5 commits into
release/1.5.xfrom
fix-zod-schema

Conversation

@alexmercerpo

@alexmercerpo alexmercerpo commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Bug Fixes

    • Improved bundle synchronization for stateless workers so skill data is guaranteed to be ready before running workflow actions, searching skills, or loading skills.
    • Prevented startup edge cases from causing hangs by making initialization lazy, memoized, and resilient to initial start/emission failures.
  • Tests

    • Added/expanded coverage for worker-safe lazy initialization, readiness memoization, error handling, and non-blocking startup behavior.
    • Updated mocks and expectations to reflect the readiness-waiting flow.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0eeaa831-7801-4631-890c-ab07cddda20c

📥 Commits

Reviewing files that changed from the base of the PR and between 93da97b and 28d49b5.

📒 Files selected for processing (2)
  • plugins/plugin-skilled-openapi/src/__tests__/bundle-sync.service.spec.ts
  • plugins/plugin-skilled-openapi/src/sync/bundle-sync.service.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • plugins/plugin-skilled-openapi/src/tests/bundle-sync.service.spec.ts
  • plugins/plugin-skilled-openapi/src/sync/bundle-sync.service.ts

📝 Walkthrough

Walkthrough

BundleSyncService gains two new public methods—attachSource() and ensureReady()—plus a private bootstrap() that lazily starts the source and memoizes a latch promise for first-bundle readiness. Plugin DI wiring is refactored to use these methods, all three tool execute() paths await ensureReady() before registry access, and all test harnesses are updated to match.

Changes

BundleSyncService worker-safe lazy boot

Layer / File(s) Summary
BundleSyncService: StartableBundleSource + ensureReady/attachSource/bootstrap
plugins/plugin-skilled-openapi/src/sync/bundle-sync.service.ts
Defines internal StartableBundleSource interface; adds instance state for source and memoized readyPromise; implements attachSource(), ensureReady() (memoized latch), and private bootstrap() that starts the source, wires onChange, awaits first apply(), and swallows/logs startup failures.
Plugin DI: replace onChange+start with attachSource+ensureReady
plugins/plugin-skilled-openapi/src/skilled-openapi.plugin.ts
Removes inline source.onChange()/deferred source.start() from dynamicProviders; replaces with sync.attachSource(source) and a conditional setImmediate(sync.ensureReady); adds await ensureReady() in injectSkillCatalogIntoSearchTool; includes minor import reordering.
Tool execute() methods: await ensureReady() before registry access
plugins/plugin-skilled-openapi/src/tools/load-skill.tool.ts, plugins/plugin-skilled-openapi/src/tools/search-skill.tool.ts, plugins/plugin-skilled-openapi/src/tools/run-workflow.tool.ts
All three tool execute() methods now await BundleSyncService.ensureReady() before reading from skill or hidden-op registries; minor multi-line reformatting in run-workflow.tool.ts.
New ensureReady test suite in bundle-sync.service.spec.ts
plugins/plugin-skilled-openapi/src/__tests__/bundle-sync.service.spec.ts
Adds typed loggerMocks handle and makeSource/makeSync helpers; comprehensive test suite covering memoized single-start/apply, no-op with no source, and swallow-on-start()-failure behavior.
Test harness updates across spec files
plugins/plugin-skilled-openapi/src/__tests__/meta-tools.spec.ts, plugins/plugin-skilled-openapi/src/__tests__/run-workflow.tool.spec.ts, plugins/plugin-skilled-openapi/src/__tests__/plugin.spec.ts, plugins/plugin-skilled-openapi/src/__tests__/runtime-deps-injection.spec.ts
Seeds BundleSyncService DI mocks with ensureReady() async no-ops; updates expected error-log pattern to initial bundle sync failed; relocates RunWorkflowTool import after jest.mock; explicitly calls sync.ensureReady() in worker-path integration tests; minor formatting adjustments.

Sequence Diagram(s)

sequenceDiagram
  participant Tool as Tool.execute
  participant BSS as BundleSyncService
  participant Source as StartableBundleSource
  participant Registry as HiddenOpRegistry / SkillRegistry

  Tool->>BSS: ensureReady()
  alt source not yet started
    BSS->>Source: start()
    BSS->>Source: onChange(handler)
    Source-->>BSS: emit first bundle
    BSS->>BSS: apply(bundle) → resolve latch
  end
  BSS-->>Tool: void
  Tool->>Registry: read skills / ops
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • agentfront/frontmcp#389: Introduced the original BundleSyncService and bundle-source infrastructure that this PR refactors with the attachSource/ensureReady lifecycle API.

Poem

🐇 A bundle once slept 'til a request said "wake!"
Now ensureReady() fires for all tools' sake.
attachSource() hands off the start to the latch,
The first bundle lands — all registries match!
No more racing for skills on a cold worker day,
The rabbit hops fast on the lazily-boot way. 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 65.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately and specifically describes the main change: implementing an ensureReady method for lazy bundle source initialization, which is the core feature across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-zod-schema

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Performance Test Results

Status: ✅ All tests passed

Summary

Project Tests Passed Warnings Failed Leaks
✅ demo-e2e-agents 4 4 0 0 0
✅ demo-e2e-cache 11 11 0 0 0
✅ demo-e2e-codecall 4 4 0 0 0
✅ demo-e2e-config 4 4 0 0 0
✅ demo-e2e-direct 3 3 0 0 0
✅ demo-e2e-elicitation 1 1 0 0 0
✅ demo-e2e-errors 4 4 0 0 0
✅ demo-e2e-hooks 3 3 0 0 0
✅ demo-e2e-multiapp 4 4 0 0 0
✅ demo-e2e-notifications 3 3 0 0 0
✅ demo-e2e-openapi 2 2 0 0 0
✅ demo-e2e-providers 4 4 0 0 0
✅ demo-e2e-public 4 4 0 0 0
✅ demo-e2e-redis 15 15 0 0 0
✅ demo-e2e-remember 4 4 0 0 0
✅ demo-e2e-remote 5 5 0 0 0
✅ demo-e2e-serverless 2 2 0 0 0
✅ demo-e2e-skills 15 15 0 0 0
✅ demo-e2e-standalone 2 2 0 0 0
✅ demo-e2e-transport-recreation 3 3 0 0 0
✅ demo-e2e-ui 4 4 0 0 0

Total: 101 tests across 21 projects

📊 View full report in workflow run


Generated at: 2026-06-22T17:12:00.764Z
Commit: fc799b31

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 4

🧹 Nitpick comments (1)
plugins/plugin-skilled-openapi/src/sync/bundle-sync.service.ts (1)

139-143: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Remove the non-null assertion from the first-apply latch.

Line 139 violates the repo’s no-! rule; use a checked local before the listener closes over the resolver.

Proposed refactor
-    let resolveFirst!: () => void;
+    let resolveFirst: (() => void) | undefined;
     let firstSettled = false;
     const firstApply = new Promise<void>((resolve) => {
       resolveFirst = resolve;
     });
+    if (!resolveFirst) {
+      throw new Error('[bundle-sync] firstApply resolver was not initialized');
+    }
+    const settleFirst = resolveFirst;
@@
       if (!firstSettled) {
         firstSettled = true;
-        void applied.then(() => resolveFirst());
+        void applied.then(settleFirst);
       }

As per coding guidelines, “Always avoid non-null assertions (!); use proper error handling instead.”

Also applies to: 159-162

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/plugin-skilled-openapi/src/sync/bundle-sync.service.ts` around lines
139 - 143, The variable `resolveFirst` is declared with a non-null assertion
(`!`) on line 139, which violates the repository's no-`!` rule. Remove the
non-null assertion and instead initialize `resolveFirst` with a safe default
value (such as an empty arrow function) so that TypeScript can properly infer
its type without requiring an assertion. Apply the same fix to any similar
declarations around lines 159-162 where this pattern is also used.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/plugin-skilled-openapi/src/__tests__/bundle-sync.service.spec.ts`:
- Around line 154-166: The test for "does not throw (swallows + logs) when the
source fails to start" verifies that ensureReady() resolves successfully when
the source fails, but it does not verify that the error was actually logged. Add
an assertion after the await expect statement that checks fakeLogger.error was
called with an appropriate message pattern (such as a pattern matching the error
message or describing a source startup failure). This ensures the test fully
covers the error-handling contract by confirming both that the error is
swallowed and that it is logged.

In `@plugins/plugin-skilled-openapi/src/__tests__/run-workflow.tool.spec.ts`:
- Around line 328-331: The ctx object literal has a duplicate `get` property
definition which is a syntax error. Locate the ctx object initialization and
identify where the `get` property is defined multiple times. Remove the
duplicate `get` property definition so that the ctx object only has a single
`get` property that returns an object with the ensureReady async method.

In `@plugins/plugin-skilled-openapi/src/sync/bundle-sync.service.ts`:
- Around line 147-163: The source.onChange callback in the bundle-sync service
immediately invokes this.apply(bundle) for each emission, which can cause
concurrent applies to interleave and corrupt shared state (registries, bundle
store, unregister handles). Implement a queue mechanism to serialize bundle
applies so that each apply completes before the next one begins. Modify the
onChange callback to enqueue each bundle apply operation rather than executing
it immediately, ensuring that mutations to shared state are serialized and the
active bundle/handles remain in the correct order.
- Around line 141-166: The SaasPullSource.start() method has an early return
when inFlight is already true that skips emission, causing
BundleSyncService.bootstrap() to hang indefinitely waiting for the onChange
callback to fire. Fix this by modifying the early return logic in
SaasPullSource.start() to ensure emission occurs before the method
resolves—either by awaiting the in-flight pull operation and emitting its
result, or by explicitly rejecting with a descriptive error that makes the race
condition visible, so that start() always triggers at least one onChange event
before completing.

---

Nitpick comments:
In `@plugins/plugin-skilled-openapi/src/sync/bundle-sync.service.ts`:
- Around line 139-143: The variable `resolveFirst` is declared with a non-null
assertion (`!`) on line 139, which violates the repository's no-`!` rule. Remove
the non-null assertion and instead initialize `resolveFirst` with a safe default
value (such as an empty arrow function) so that TypeScript can properly infer
its type without requiring an assertion. Apply the same fix to any similar
declarations around lines 159-162 where this pattern is also used.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 322e6a16-4874-40ba-b96d-12a99973b528

📥 Commits

Reviewing files that changed from the base of the PR and between e6e7123 and 93da97b.

📒 Files selected for processing (10)
  • plugins/plugin-skilled-openapi/src/__tests__/bundle-sync.service.spec.ts
  • plugins/plugin-skilled-openapi/src/__tests__/meta-tools.spec.ts
  • plugins/plugin-skilled-openapi/src/__tests__/plugin.spec.ts
  • plugins/plugin-skilled-openapi/src/__tests__/run-workflow.tool.spec.ts
  • plugins/plugin-skilled-openapi/src/__tests__/runtime-deps-injection.spec.ts
  • plugins/plugin-skilled-openapi/src/skilled-openapi.plugin.ts
  • plugins/plugin-skilled-openapi/src/sync/bundle-sync.service.ts
  • plugins/plugin-skilled-openapi/src/tools/load-skill.tool.ts
  • plugins/plugin-skilled-openapi/src/tools/run-workflow.tool.ts
  • plugins/plugin-skilled-openapi/src/tools/search-skill.tool.ts

Comment thread plugins/plugin-skilled-openapi/src/sync/bundle-sync.service.ts Outdated
Comment thread plugins/plugin-skilled-openapi/src/sync/bundle-sync.service.ts
@frontegg-david frontegg-david merged commit 68154c5 into release/1.5.x Jun 22, 2026
37 checks passed
@frontegg-david frontegg-david deleted the fix-zod-schema branch June 22, 2026 18:43
@github-actions

Copy link
Copy Markdown
Contributor

Cherry-pick Created

A cherry-pick PR to main has been automatically created.

Please review and merge if this change should also be in main.

If the cherry-pick is not needed, close the PR.

frontegg-david pushed a commit that referenced this pull request Jun 22, 2026
…e initialization (#501)

Cherry-picked from #500 (merged to release/1.5.x)
Original commit: 68154c5

Co-authored-by: agentfront[bot] <agentfront[bot]@users.noreply.github.com>
Co-authored-by: alexmercerpo <251740932+alexmercerpo@users.noreply.github.com>
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.

2 participants