Skip to content

feat(deploy): wire real plugin loader into resolveIaCProvider#428

Merged
intel352 merged 2 commits into
mainfrom
feat/deploy-plugin-loader
Apr 21, 2026
Merged

feat(deploy): wire real plugin loader into resolveIaCProvider#428
intel352 merged 2 commits into
mainfrom
feat/deploy-plugin-loader

Conversation

@intel352

@intel352 intel352 commented Apr 21, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Replace the `resolveIaCProvider` no-op stub with `discoverAndLoadIaCProvider`, which:
    • Scans `WFCTL_PLUGIN_DIR` subdirectories for `plugin.json` files declaring `capabilities.iacProvider.name`
    • On match: loads the plugin via `ExternalPluginManager`, asserts the `iac.provider` module factory result to `interfaces.IaCProvider`
    • Each failure mode returns an actionable error (no plugin dir → `wfctl plugin install`; binary missing → same; no module type → `wfctl plugin update`)
  • Refactor `pluginDeployProvider` to resolve lazily via `ensureProvider(ctx)` — the real request context is now threaded through to `Initialize` instead of `context.Background()`
  • Derive `resourceType` from the matched infra module's `Type` field instead of hardcoding `"infra.container_service"`
  • Add `--plugin-dir` flag to `wfctl ci run` (also honoured via `WFCTL_PLUGIN_DIR` env var)

Option A vs Option B

Option A (engine build + module walk) was skipped because `iac.provider` has no registered factory in the engine — `workflow.NewEngineBuilder().BuildFromConfig(cfg)` would skip the module rather than instantiate it, so there is nothing to extract. Option B (direct `ExternalPluginManager` + raw JSON manifest scan) is the only path that can discover and load the plugin without requiring engine-side changes.

Known gap: workflow-plugin-digitalocean

`workflow-plugin-digitalocean` v0.1.0 declares `capabilities.iacProvider.name = "digitalocean"` in `plugin.json` but does not expose an `iac.provider` module type or any `ServiceInvoker` handlers. Deploying through it currently returns:

```
plugin "workflow-plugin-digitalocean" does not expose an iac.provider module type — upgrade with: wfctl plugin update workflow-plugin-digitalocean
```

The follow-up work in `workflow-plugin-digitalocean` is to:

  1. Register `iac.provider` in `moduleTypes` in `plugin.json`
  2. Implement `sdk.ModuleProvider.CreateModule("iac.provider", ...)` returning a module that implements `interfaces.IaCProvider`
  3. Wire `ResourceDriver.Update` and `ResourceDriver.HealthCheck` through `sdk.ServiceInvoker.InvokeMethod`

Integration check (manual)

Steps run against `/Users/jon/workspace/buymywishlist`:

Step 1 — check plugin registry manifest exists:
```
wfctl plugin search workflow-plugin-digitalocean
```
Result: manifest exists in workflow-registry (added in PR #12).

Step 2 — install plugin binary:
```
wfctl plugin install workflow-plugin-digitalocean --plugin-dir ./data/plugins
```
Result: binary installed to `data/plugins/workflow-plugin-digitalocean/workflow-plugin-digitalocean`.

Step 3 — attempt deploy:
```
DIGITALOCEAN_TOKEN=... SPACES_access_key=... SPACES_secret_key=...
wfctl ci run --phase deploy --env staging --config infra.yaml
--plugin-dir ./data/plugins
```
Actual outcome (expected given known gap above):
```
plugin "workflow-plugin-digitalocean" does not expose an iac.provider module type — upgrade with: wfctl plugin update workflow-plugin-digitalocean
```
Plugin discovery and loading succeeds (ExternalPluginManager log lines appear on stderr); the error is returned at the `ModuleFactories()["iac.provider"]` assertion step — confirming the wiring is correct and the remaining work is entirely in the DO plugin.

Test plan

  • `TestDefaultResolveIaCProvider_IsNotPlaceholder` — default no longer returns old stub message
  • `TestDefaultResolveIaCProvider_NoPluginDir` — missing dir → hint to `wfctl plugin install`
  • `TestDefaultResolveIaCProvider_NoMatchingPlugin` — unmatched provider → hint to `wfctl plugin install`
  • `TestDefaultResolveIaCProvider_MatchingPlugin_NotLoaded` — manifest found, binary absent → error names the plugin
  • `TestPluginDeployProvider_LazyResolution` — `resolveIaCProvider` not called at construction; called once on first `Deploy`; not called again on subsequent `Deploy`
  • `TestPluginDeployProvider_ResourceTypeFromModule` — `resourceType` matches the infra module's declared type
  • All pre-existing `cmd/wfctl/...` tests pass

🤖 Generated with Claude Code

- Replace the no-op stub with discoverAndLoadIaCProvider, which scans
  plugin.json files for capabilities.iacProvider.name, loads the matching
  plugin via ExternalPluginManager, and type-asserts the iac.provider
  module factory result to interfaces.IaCProvider.
- Each failure mode (no plugin dir, no matching plugin, binary absent,
  no iac.provider module type, wrong type) returns an actionable error
  pointing at the fix command.
- Refactor pluginDeployProvider to resolve lazily in ensureProvider(ctx)
  so the real request context is threaded through to Initialize.
- Derive resourceType from the matched module's Type field instead of
  hardcoding "infra.container_service".
- Add --plugin-dir flag to wfctl ci run (sets WFCTL_PLUGIN_DIR).

Note: workflow-plugin-digitalocean v0.1.0 does not yet expose an
iac.provider module type or ServiceInvoker handlers. Until it does,
deploying via that plugin returns a clear "upgrade with wfctl plugin
update" error rather than a silent no-op.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 21, 2026 00:14

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.

Pull request overview

This PR wires wfctl deploy’s plugin-based IaC provider resolution to the real external plugin loader, enabling ci run deployments to discover/load an IaC provider from installed plugins (via WFCTL_PLUGIN_DIR / --plugin-dir) and initialize it with the calling context.

Changes:

  • Implement plugin discovery + loading for IaC providers by scanning plugin.json for capabilities.iacProvider.name and loading via external.ExternalPluginManager.
  • Refactor pluginDeployProvider to lazily resolve the IaC provider on first Deploy/HealthCheck, threading through the real context.Context.
  • Add --plugin-dir to wfctl ci run (also honoring WFCTL_PLUGIN_DIR) and add unit tests for loader behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
cmd/wfctl/deploy_providers.go Replaces the IaC provider resolver stub with real plugin discovery/loading and adds lazy provider resolution; derives resourceType from the selected module.
cmd/wfctl/deploy_plugin_loader_test.go Adds tests covering default IaC provider resolution error modes and lazy resolution behavior.
cmd/wfctl/ci_run.go Adds --plugin-dir flag and applies it to WFCTL_PLUGIN_DIR during deploy phase.

Comment on lines +110 to +111
_, statErr := os.Stat(binaryPath)
return pluginName, statErr == nil, nil

Copilot AI Apr 21, 2026

Copy link

Choose a reason for hiding this comment

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

findIaCPluginDir treats any os.Stat error on the plugin binary as “binary missing” (hasBinary=false). If Stat fails for reasons other than non-existence (e.g., permission denied, I/O error), the caller will surface an incorrect install hint. Consider distinguishing os.IsNotExist(statErr) from other errors and returning a wrapped error for the non-NotExist cases.

Suggested change
_, statErr := os.Stat(binaryPath)
return pluginName, statErr == nil, nil
if _, statErr := os.Stat(binaryPath); statErr != nil {
if os.IsNotExist(statErr) {
return pluginName, false, nil
}
return "", false, fmt.Errorf("stat plugin binary %q: %w", binaryPath, statErr)
}
return pluginName, true, nil

Copilot uses AI. Check for mistakes.
Comment thread cmd/wfctl/deploy_plugin_loader_test.go Outdated
Comment on lines +19 to +25
_, err := resolveIaCProvider(context.Background(), "any-provider", nil)
if err == nil {
t.Skip("resolveIaCProvider succeeded unexpectedly")
}
if strings.Contains(err.Error(), "no in-process provider loader") {
t.Errorf("default resolveIaCProvider still returns old placeholder message: %v", err)
}

Copilot AI Apr 21, 2026

Copy link

Choose a reason for hiding this comment

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

TestDefaultResolveIaCProvider_IsNotPlaceholder uses t.Skip when resolveIaCProvider unexpectedly succeeds. A success here indicates a regression in the test setup/expectations and should fail the test (e.g., t.Fatalf) rather than being skipped, otherwise the test suite could hide real behavior changes.

Copilot uses AI. Check for mistakes.
Comment thread cmd/wfctl/ci_run.go
return fmt.Errorf("--env is required for deploy phase")
}
if *pluginDir != "" {
os.Setenv("WFCTL_PLUGIN_DIR", *pluginDir) //nolint:errcheck

Copilot AI Apr 21, 2026

Copy link

Choose a reason for hiding this comment

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

runCIRun ignores the error return from os.Setenv when applying --plugin-dir. Since Setenv can fail on some platforms/environments, it’s better to check and return a wrapped error so the deploy phase doesn’t proceed with an unexpected plugin directory.

Suggested change
os.Setenv("WFCTL_PLUGIN_DIR", *pluginDir) //nolint:errcheck
if err := os.Setenv("WFCTL_PLUGIN_DIR", *pluginDir); err != nil {
return fmt.Errorf("set WFCTL_PLUGIN_DIR: %w", err)
}

Copilot uses AI. Check for mistakes.
Comment on lines +190 to 201
// Find the first infra resource module referencing this provider.
var resourceName, resourceType string
var resourceCfg map[string]any
for _, m := range wfCfg.Modules {
if m.Type != "infra.container_service" {
if m.Type == "iac.provider" || m.Type == "" {
continue
}
if p, _ := m.Config["provider"].(string); p == providerModName {
resourceName = m.Name
resourceType = m.Type
resourceCfg = m.Config
break

Copilot AI Apr 21, 2026

Copy link

Choose a reason for hiding this comment

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

newPluginDeployProvider now selects the first non-empty module whose config.provider matches the iac.provider module name. In configs with multiple infra.* resources (e.g., VPC/firewall/database + container_service), this can pick the wrong resource (like infra.vpc) and then attempt to deploy by injecting an "image" key into that resource’s config, leading to incorrect updates or failures. Consider restricting selection to the intended deployable resource type (likely infra.container_service), or introduce an explicit config option to choose which infra resource to deploy (e.g., by module name), rather than taking the first match.

Copilot uses AI. Check for mistakes.
… resolution

- resolveIaCProvider now returns (IaCProvider, io.Closer, error); the
  Closer wraps mgr.Shutdown() via closerFunc so callers can reap the
  plugin subprocess when done.
- discoverAndLoadIaCProvider calls mgr.Shutdown() on every early-exit
  error path so no subprocess is leaked when loading fails.
- runDeployPhaseWithConfig defers Close() on any provider that
  implements io.Closer, ensuring the subprocess is reaped after deploy.
- pluginDeployProvider.ensureProvider is guarded by sync.Once (safe for
  concurrent Deploy/HealthCheck) and short-circuits when provider is
  already set (preserves test injection pattern).
- Update all resolveIaCProvider test overrides to the new 3-return
  signature with nil closer.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Apr 21, 2026

Copy link
Copy Markdown

⏱ Benchmark Results

No significant performance regressions detected.

benchstat comparison (baseline → PR)
## benchstat: baseline → PR
baseline-bench.txt:245: parsing iteration count: invalid syntax
baseline-bench.txt:391737: parsing iteration count: invalid syntax
baseline-bench.txt:773419: parsing iteration count: invalid syntax
baseline-bench.txt:1092833: parsing iteration count: invalid syntax
baseline-bench.txt:1391529: parsing iteration count: invalid syntax
baseline-bench.txt:1735882: parsing iteration count: invalid syntax
benchmark-results.txt:245: parsing iteration count: invalid syntax
benchmark-results.txt:313992: parsing iteration count: invalid syntax
benchmark-results.txt:601468: parsing iteration count: invalid syntax
benchmark-results.txt:929495: parsing iteration count: invalid syntax
benchmark-results.txt:1227876: parsing iteration count: invalid syntax
benchmark-results.txt:1543291: parsing iteration count: invalid syntax
goos: linux
goarch: amd64
pkg: github.com/GoCodeAlone/workflow/dynamic
cpu: AMD EPYC 7763 64-Core Processor                
                            │ benchmark-results.txt │
                            │        sec/op         │
InterpreterCreation-4                 3.167m ± 186%
ComponentLoad-4                       3.560m ±   9%
ComponentExecute-4                    1.970µ ±   3%
PoolContention/workers-1-4            1.098µ ±   2%
PoolContention/workers-2-4            1.089µ ±   2%
PoolContention/workers-4-4            1.094µ ±   1%
PoolContention/workers-8-4            1.093µ ±   1%
PoolContention/workers-16-4           1.095µ ±   1%
ComponentLifecycle-4                  3.597m ±   0%
SourceValidation-4                    2.285µ ±   1%
RegistryConcurrent-4                  813.3n ±   4%
LoaderLoadFromString-4                3.604m ±   1%
geomean                               17.52µ

                            │ benchmark-results.txt │
                            │         B/op          │
InterpreterCreation-4                  2.027Mi ± 0%
ComponentLoad-4                        2.180Mi ± 0%
ComponentExecute-4                     1.203Ki ± 0%
PoolContention/workers-1-4             1.203Ki ± 0%
PoolContention/workers-2-4             1.203Ki ± 0%
PoolContention/workers-4-4             1.203Ki ± 0%
PoolContention/workers-8-4             1.203Ki ± 0%
PoolContention/workers-16-4            1.203Ki ± 0%
ComponentLifecycle-4                   2.183Mi ± 0%
SourceValidation-4                     1.984Ki ± 0%
RegistryConcurrent-4                   1.133Ki ± 0%
LoaderLoadFromString-4                 2.182Mi ± 0%
geomean                                15.25Ki

                            │ benchmark-results.txt │
                            │       allocs/op       │
InterpreterCreation-4                   15.68k ± 0%
ComponentLoad-4                         18.02k ± 0%
ComponentExecute-4                       25.00 ± 0%
PoolContention/workers-1-4               25.00 ± 0%
PoolContention/workers-2-4               25.00 ± 0%
PoolContention/workers-4-4               25.00 ± 0%
PoolContention/workers-8-4               25.00 ± 0%
PoolContention/workers-16-4              25.00 ± 0%
ComponentLifecycle-4                    18.07k ± 0%
SourceValidation-4                       32.00 ± 0%
RegistryConcurrent-4                     2.000 ± 0%
LoaderLoadFromString-4                  18.06k ± 0%
geomean                                  183.3

cpu: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
                            │ baseline-bench.txt │
                            │       sec/op       │
InterpreterCreation-4              3.533m ± 199%
ComponentLoad-4                    3.443m ±  12%
ComponentExecute-4                 1.872µ ±   2%
PoolContention/workers-1-4         1.193µ ±   3%
PoolContention/workers-2-4         1.186µ ±   1%
PoolContention/workers-4-4         1.187µ ±   1%
PoolContention/workers-8-4         1.183µ ±   1%
PoolContention/workers-16-4        1.190µ ±   1%
ComponentLifecycle-4               3.481m ±   1%
SourceValidation-4                 2.226µ ±   1%
RegistryConcurrent-4               887.6n ±   7%
LoaderLoadFromString-4             3.522m ±   1%
geomean                            18.18µ

                            │ baseline-bench.txt │
                            │        B/op        │
InterpreterCreation-4               2.027Mi ± 0%
ComponentLoad-4                     2.180Mi ± 0%
ComponentExecute-4                  1.203Ki ± 0%
PoolContention/workers-1-4          1.203Ki ± 0%
PoolContention/workers-2-4          1.203Ki ± 0%
PoolContention/workers-4-4          1.203Ki ± 0%
PoolContention/workers-8-4          1.203Ki ± 0%
PoolContention/workers-16-4         1.203Ki ± 0%
ComponentLifecycle-4                2.183Mi ± 0%
SourceValidation-4                  1.984Ki ± 0%
RegistryConcurrent-4                1.133Ki ± 0%
LoaderLoadFromString-4              2.182Mi ± 0%
geomean                             15.25Ki

                            │ baseline-bench.txt │
                            │     allocs/op      │
InterpreterCreation-4                15.68k ± 0%
ComponentLoad-4                      18.02k ± 0%
ComponentExecute-4                    25.00 ± 0%
PoolContention/workers-1-4            25.00 ± 0%
PoolContention/workers-2-4            25.00 ± 0%
PoolContention/workers-4-4            25.00 ± 0%
PoolContention/workers-8-4            25.00 ± 0%
PoolContention/workers-16-4           25.00 ± 0%
ComponentLifecycle-4                 18.07k ± 0%
SourceValidation-4                    32.00 ± 0%
RegistryConcurrent-4                  2.000 ± 0%
LoaderLoadFromString-4               18.06k ± 0%
geomean                               183.3

pkg: github.com/GoCodeAlone/workflow/middleware
cpu: AMD EPYC 7763 64-Core Processor                
                                  │ benchmark-results.txt │
                                  │        sec/op         │
CircuitBreakerDetection-4                     286.6n ± 7%
CircuitBreakerExecution_Success-4             21.54n ± 0%
CircuitBreakerExecution_Failure-4             66.04n ± 1%
geomean                                       74.14n

                                  │ benchmark-results.txt │
                                  │         B/op          │
CircuitBreakerDetection-4                    144.0 ± 0%
CircuitBreakerExecution_Success-4            0.000 ± 0%
CircuitBreakerExecution_Failure-4            0.000 ± 0%
geomean                                                 ¹
¹ summaries must be >0 to compute geomean

                                  │ benchmark-results.txt │
                                  │       allocs/op       │
CircuitBreakerDetection-4                    1.000 ± 0%
CircuitBreakerExecution_Success-4            0.000 ± 0%
CircuitBreakerExecution_Failure-4            0.000 ± 0%
geomean                                                 ¹
¹ summaries must be >0 to compute geomean

cpu: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
                                  │ baseline-bench.txt │
                                  │       sec/op       │
CircuitBreakerDetection-4                  452.3n ± 2%
CircuitBreakerExecution_Success-4          59.71n ± 0%
CircuitBreakerExecution_Failure-4          65.40n ± 0%
geomean                                    120.9n

                                  │ baseline-bench.txt │
                                  │        B/op        │
CircuitBreakerDetection-4                 144.0 ± 0%
CircuitBreakerExecution_Success-4         0.000 ± 0%
CircuitBreakerExecution_Failure-4         0.000 ± 0%
geomean                                              ¹
¹ summaries must be >0 to compute geomean

                                  │ baseline-bench.txt │
                                  │     allocs/op      │
CircuitBreakerDetection-4                 1.000 ± 0%
CircuitBreakerExecution_Success-4         0.000 ± 0%
CircuitBreakerExecution_Failure-4         0.000 ± 0%
geomean                                              ¹
¹ summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/module
cpu: AMD EPYC 7763 64-Core Processor                
                                 │ benchmark-results.txt │
                                 │        sec/op         │
JQTransform_Simple-4                        868.2n ± 27%
JQTransform_ObjectConstruction-4            1.451µ ±  0%
JQTransform_ArraySelect-4                   3.309µ ±  1%
JQTransform_Complex-4                       37.96µ ±  2%
JQTransform_Throughput-4                    1.774µ ±  1%
SSEPublishDelivery-4                        72.61n ±  1%
geomean                                     1.653µ

                                 │ benchmark-results.txt │
                                 │         B/op          │
JQTransform_Simple-4                      1.273Ki ± 0%
JQTransform_ObjectConstruction-4          1.773Ki ± 0%
JQTransform_ArraySelect-4                 2.625Ki ± 0%
JQTransform_Complex-4                     16.22Ki ± 0%
JQTransform_Throughput-4                  1.984Ki ± 0%
SSEPublishDelivery-4                        0.000 ± 0%
geomean                                                ¹
¹ summaries must be >0 to compute geomean

                                 │ benchmark-results.txt │
                                 │       allocs/op       │
JQTransform_Simple-4                        10.00 ± 0%
JQTransform_ObjectConstruction-4            15.00 ± 0%
JQTransform_ArraySelect-4                   30.00 ± 0%
JQTransform_Complex-4                       324.0 ± 0%
JQTransform_Throughput-4                    17.00 ± 0%
SSEPublishDelivery-4                        0.000 ± 0%
geomean                                                ¹
¹ summaries must be >0 to compute geomean

cpu: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
                                 │ baseline-bench.txt │
                                 │       sec/op       │
JQTransform_Simple-4                     886.8n ± 29%
JQTransform_ObjectConstruction-4         1.479µ ±  1%
JQTransform_ArraySelect-4                3.188µ ±  0%
JQTransform_Complex-4                    35.66µ ±  1%
JQTransform_Throughput-4                 1.774µ ±  1%
SSEPublishDelivery-4                     76.65n ±  1%
geomean                                  1.651µ

                                 │ baseline-bench.txt │
                                 │        B/op        │
JQTransform_Simple-4                   1.273Ki ± 0%
JQTransform_ObjectConstruction-4       1.773Ki ± 0%
JQTransform_ArraySelect-4              2.625Ki ± 0%
JQTransform_Complex-4                  16.22Ki ± 0%
JQTransform_Throughput-4               1.984Ki ± 0%
SSEPublishDelivery-4                     0.000 ± 0%
geomean                                             ¹
¹ summaries must be >0 to compute geomean

                                 │ baseline-bench.txt │
                                 │     allocs/op      │
JQTransform_Simple-4                     10.00 ± 0%
JQTransform_ObjectConstruction-4         15.00 ± 0%
JQTransform_ArraySelect-4                30.00 ± 0%
JQTransform_Complex-4                    324.0 ± 0%
JQTransform_Throughput-4                 17.00 ± 0%
SSEPublishDelivery-4                     0.000 ± 0%
geomean                                             ¹
¹ summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/schema
cpu: AMD EPYC 7763 64-Core Processor                
                                    │ benchmark-results.txt │
                                    │        sec/op         │
SchemaValidation_Simple-4                       1.128µ ± 7%
SchemaValidation_AllFields-4                    1.676µ ± 7%
SchemaValidation_FormatValidation-4             1.598µ ± 1%
SchemaValidation_ManySchemas-4                  1.804µ ± 3%
geomean                                         1.528µ

                                    │ benchmark-results.txt │
                                    │         B/op          │
SchemaValidation_Simple-4                      0.000 ± 0%
SchemaValidation_AllFields-4                   0.000 ± 0%
SchemaValidation_FormatValidation-4            0.000 ± 0%
SchemaValidation_ManySchemas-4                 0.000 ± 0%
geomean                                                   ¹
¹ summaries must be >0 to compute geomean

                                    │ benchmark-results.txt │
                                    │       allocs/op       │
SchemaValidation_Simple-4                      0.000 ± 0%
SchemaValidation_AllFields-4                   0.000 ± 0%
SchemaValidation_FormatValidation-4            0.000 ± 0%
SchemaValidation_ManySchemas-4                 0.000 ± 0%
geomean                                                   ¹
¹ summaries must be >0 to compute geomean

cpu: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
                                    │ baseline-bench.txt │
                                    │       sec/op       │
SchemaValidation_Simple-4                   1.020µ ± 17%
SchemaValidation_AllFields-4                1.499µ ±  7%
SchemaValidation_FormatValidation-4         1.460µ ±  2%
SchemaValidation_ManySchemas-4              1.473µ ±  2%
geomean                                     1.347µ

                                    │ baseline-bench.txt │
                                    │        B/op        │
SchemaValidation_Simple-4                   0.000 ± 0%
SchemaValidation_AllFields-4                0.000 ± 0%
SchemaValidation_FormatValidation-4         0.000 ± 0%
SchemaValidation_ManySchemas-4              0.000 ± 0%
geomean                                                ¹
¹ summaries must be >0 to compute geomean

                                    │ baseline-bench.txt │
                                    │     allocs/op      │
SchemaValidation_Simple-4                   0.000 ± 0%
SchemaValidation_AllFields-4                0.000 ± 0%
SchemaValidation_FormatValidation-4         0.000 ± 0%
SchemaValidation_ManySchemas-4              0.000 ± 0%
geomean                                                ¹
¹ summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/store
cpu: AMD EPYC 7763 64-Core Processor                
                                   │ benchmark-results.txt │
                                   │        sec/op         │
EventStoreAppend_InMemory-4                   1.216µ ± 10%
EventStoreAppend_SQLite-4                     1.409m ±  5%
GetTimeline_InMemory/events-10-4              13.62µ ±  3%
GetTimeline_InMemory/events-50-4              68.22µ ± 13%
GetTimeline_InMemory/events-100-4             122.1µ ±  0%
GetTimeline_InMemory/events-500-4             628.0µ ±  1%
GetTimeline_InMemory/events-1000-4            1.282m ±  1%
GetTimeline_SQLite/events-10-4                108.0µ ±  1%
GetTimeline_SQLite/events-50-4                248.3µ ±  0%
GetTimeline_SQLite/events-100-4               419.3µ ±  1%
GetTimeline_SQLite/events-500-4               1.795m ±  1%
GetTimeline_SQLite/events-1000-4              3.486m ±  2%
geomean                                       217.2µ

                                   │ benchmark-results.txt │
                                   │         B/op          │
EventStoreAppend_InMemory-4                     786.0 ± 9%
EventStoreAppend_SQLite-4                     1.985Ki ± 2%
GetTimeline_InMemory/events-10-4              7.953Ki ± 0%
GetTimeline_InMemory/events-50-4              46.62Ki ± 0%
GetTimeline_InMemory/events-100-4             94.48Ki ± 0%
GetTimeline_InMemory/events-500-4             472.8Ki ± 0%
GetTimeline_InMemory/events-1000-4            944.3Ki ± 0%
GetTimeline_SQLite/events-10-4                16.74Ki ± 0%
GetTimeline_SQLite/events-50-4                87.14Ki ± 0%
GetTimeline_SQLite/events-100-4               175.4Ki ± 0%
GetTimeline_SQLite/events-500-4               846.1Ki ± 0%
GetTimeline_SQLite/events-1000-4              1.639Mi ± 0%
geomean                                       67.32Ki

                                   │ benchmark-results.txt │
                                   │       allocs/op       │
EventStoreAppend_InMemory-4                     7.000 ± 0%
EventStoreAppend_SQLite-4                       53.00 ± 0%
GetTimeline_InMemory/events-10-4                125.0 ± 0%
GetTimeline_InMemory/events-50-4                653.0 ± 0%
GetTimeline_InMemory/events-100-4              1.306k ± 0%
GetTimeline_InMemory/events-500-4              6.514k ± 0%
GetTimeline_InMemory/events-1000-4             13.02k ± 0%
GetTimeline_SQLite/events-10-4                  382.0 ± 0%
GetTimeline_SQLite/events-50-4                 1.852k ± 0%
GetTimeline_SQLite/events-100-4                3.681k ± 0%
GetTimeline_SQLite/events-500-4                18.54k ± 0%
GetTimeline_SQLite/events-1000-4               37.29k ± 0%
geomean                                        1.162k

cpu: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
                                   │ baseline-bench.txt │
                                   │       sec/op       │
EventStoreAppend_InMemory-4                1.112µ ±  4%
EventStoreAppend_SQLite-4                  971.2µ ±  6%
GetTimeline_InMemory/events-10-4           13.27µ ±  4%
GetTimeline_InMemory/events-50-4           74.07µ ±  2%
GetTimeline_InMemory/events-100-4          147.0µ ± 20%
GetTimeline_InMemory/events-500-4          593.4µ ±  1%
GetTimeline_InMemory/events-1000-4         1.213m ±  1%
GetTimeline_SQLite/events-10-4             82.02µ ±  4%
GetTimeline_SQLite/events-50-4             236.4µ ±  1%
GetTimeline_SQLite/events-100-4            427.5µ ±  2%
GetTimeline_SQLite/events-500-4            1.903m ±  1%
GetTimeline_SQLite/events-1000-4           3.707m ±  3%
geomean                                    208.0µ

                                   │ baseline-bench.txt │
                                   │        B/op        │
EventStoreAppend_InMemory-4                  775.0 ± 7%
EventStoreAppend_SQLite-4                  1.985Ki ± 2%
GetTimeline_InMemory/events-10-4           7.953Ki ± 0%
GetTimeline_InMemory/events-50-4           46.62Ki ± 0%
GetTimeline_InMemory/events-100-4          94.48Ki ± 0%
GetTimeline_InMemory/events-500-4          472.8Ki ± 0%
GetTimeline_InMemory/events-1000-4         944.3Ki ± 0%
GetTimeline_SQLite/events-10-4             16.74Ki ± 0%
GetTimeline_SQLite/events-50-4             87.14Ki ± 0%
GetTimeline_SQLite/events-100-4            175.4Ki ± 0%
GetTimeline_SQLite/events-500-4            846.1Ki ± 0%
GetTimeline_SQLite/events-1000-4           1.639Mi ± 0%
geomean                                    67.24Ki

                                   │ baseline-bench.txt │
                                   │     allocs/op      │
EventStoreAppend_InMemory-4                  7.000 ± 0%
EventStoreAppend_SQLite-4                    53.00 ± 0%
GetTimeline_InMemory/events-10-4             125.0 ± 0%
GetTimeline_InMemory/events-50-4             653.0 ± 0%
GetTimeline_InMemory/events-100-4           1.306k ± 0%
GetTimeline_InMemory/events-500-4           6.514k ± 0%
GetTimeline_InMemory/events-1000-4          13.02k ± 0%
GetTimeline_SQLite/events-10-4               382.0 ± 0%
GetTimeline_SQLite/events-50-4              1.852k ± 0%
GetTimeline_SQLite/events-100-4             3.681k ± 0%
GetTimeline_SQLite/events-500-4             18.54k ± 0%
GetTimeline_SQLite/events-1000-4            37.29k ± 0%
geomean                                     1.162k

Benchmarks run with go test -bench=. -benchmem -count=6.
Regressions ≥ 20% are flagged. Results compared via benchstat.

@intel352
intel352 merged commit 7675de4 into main Apr 21, 2026
17 of 18 checks passed
@intel352
intel352 deleted the feat/deploy-plugin-loader branch April 21, 2026 00:38
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