Skip to content

Fix PluginManifest to gracefully parse legacy object-style capabilities in plugin.json#322

Merged
intel352 merged 5 commits intomainfrom
copilot/fix-doc-generation-error-handling
Mar 13, 2026
Merged

Fix PluginManifest to gracefully parse legacy object-style capabilities in plugin.json#322
intel352 merged 5 commits intomainfrom
copilot/fix-doc-generation-error-handling

Conversation

Copy link
Contributor

Copilot AI commented Mar 12, 2026

External plugins (e.g. workflow-plugin-authz) declare capabilities as a flat JSON object with moduleTypes/stepTypes/triggerTypes keys, while PluginManifest.Capabilities expects []CapabilityDecl. This caused LoadManifest to fail, and wfctl docs generate to skip those plugins with a warning.

Changes

  • plugin/manifest.go — Added UnmarshalJSON on PluginManifest that dispatches on the first non-whitespace byte of the raw capabilities JSON:
    • [ → decoded as canonical []CapabilityDecl array
    • { → decoded as legacy object format; moduleTypes/stepTypes/triggerTypes/workflowTypes are promoted into the top-level manifest fields via appendUnique (deduplicating against any already-present values)
    • null/absent → treated as omitted
    • Any other type (string, number, bool) → returns a descriptive error so LoadManifest surfaces it instead of silently accepting a malformed manifest
// Legacy format (now handled gracefully)
"capabilities": {
    "configProvider": false,
    "moduleTypes": ["authz.casbin"],
    "stepTypes": ["step.authz_check_casbin", ...],
    "triggerTypes": []
}
  • Uses type rawManifest PluginManifest + type withRawCaps struct to break the UnmarshalJSON recursion (cleaner than the embedded-alias approach).

  • Added firstNonSpace helper for whitespace-safe peeking and appendUnique helper for deduplicating merged type lists.

  • Added MinEngineVersion field to PluginManifest and moved Dependency struct to immediately follow CapabilityDecl, aligning with upstream main.

  • plugin/manifest_test.go — Added:

    • TestManifestLegacyCapabilitiesObject — verifies the legacy object format is parsed correctly and type lists are promoted to top-level fields
    • TestManifestLegacyCapabilitiesObjectFile — verifies LoadManifest succeeds end-to-end for a plugin.json using the legacy format
    • TestManifestCapabilitiesInvalidFormat — negative cases (string, number, bool) confirming that unsupported capabilities types are rejected with an error

💬 Send tasks to Copilot coding agent from Slack and Teams to turn conversations into code. Copilot posts an update in your thread when it's finished.

…in.json

Co-authored-by: intel352 <77607+intel352@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix doc generation to handle plugin manifest errors gracefully Fix PluginManifest to gracefully parse legacy object-style capabilities in plugin.json Mar 12, 2026
Copilot AI requested a review from intel352 March 12, 2026 23:52
@intel352 intel352 marked this pull request as ready for review March 12, 2026 23:58
Copilot AI review requested due to automatic review settings March 12, 2026 23:58
Copy link
Contributor

Copilot AI left a comment

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 updates plugin manifest parsing to be backward-compatible with external plugins that encode capabilities as a JSON object (with nested moduleTypes/stepTypes/triggerTypes), preventing LoadManifest failures that caused tooling like wfctl docs generate to skip those plugins.

Changes:

  • Added PluginManifest.UnmarshalJSON to support both canonical []CapabilityDecl capabilities and a legacy object format, promoting nested type lists to top-level fields.
  • Introduced legacyCapabilitiesObject and an appendUnique helper to merge/deduplicate promoted type lists.
  • Added tests covering legacy object-style capabilities via both direct json.Unmarshal and LoadManifest.

Reviewed changes

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

File Description
plugin/manifest.go Adds custom JSON unmarshalling to gracefully handle legacy object-style capabilities and promote nested type lists.
plugin/manifest_test.go Adds coverage for parsing/loading manifests that use legacy object-style capabilities.

Comment on lines +434 to +436
func TestManifestLegacyCapabilitiesObject(t *testing.T) {
const legacyJSON = `{
"name": "workflow-plugin-authz",
intel352 added a commit that referenced this pull request Mar 13, 2026
Addresses PRs #321, #322, and issue #316. Covers 13 CLI fixes,
5 registry data fixes, and holistic plugin ecosystem plan including
goreleaser standardization, GitHub URL install, lockfile support,
minEngineVersion checks, and auto-sync CI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
intel352 added a commit that referenced this pull request Mar 13, 2026
* docs: add wfctl audit and plugin ecosystem design

Addresses PRs #321, #322, and issue #316. Covers 13 CLI fixes,
5 registry data fixes, and holistic plugin ecosystem plan including
goreleaser standardization, GitHub URL install, lockfile support,
minEngineVersion checks, and auto-sync CI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add wave 2 integration plugins design + release/validation plan

Wave 2 design: Okta (~130 steps), Datadog (~120), LaunchDarkly (~100),
Permit.io (~80), Salesforce (~75), OpenLMS (~120) — all MIT, community tier.

Release plan: tag untagged plugins, create validation scenarios 51-59
with mock HTTP backends in workflow-scenarios.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add wfctl audit implementation plan (20 tasks)

Phase A: 13 CLI fixes (help exit codes, plugin-dir rename, flag ordering, etc.)
Phase B: 2 registry data fix tasks
Phase C: 5 plugin ecosystem tasks (GitHub URL install, lockfile, goreleaser)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add B5 schema validation gap to Task 14

Alignment check identified missing coverage for design requirement B5.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: move Permit.io into workflow-plugin-authz as provider

Permit.io fits alongside Casbin in the existing authz plugin
rather than a standalone repo. Same multi-provider pattern as
payments (Stripe + PayPal).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: rename -data-dir to -plugin-dir in plugin subcommands

Rename the flag from -data-dir to -plugin-dir across runPluginInstall,
runPluginList, runPluginUpdate, runPluginRemove, and runPluginInfo for
consistency with other wfctl commands. Keep -data-dir as a working
deprecated alias. Update pluginUsage() to document -plugin-dir.

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

* feat(wfctl): add trailing flag detection helper

Add checkTrailingFlags() to detect when flags are passed after
positional arguments, and wire it into runPluginInit,
runRegistryAdd, and runRegistryRemove.

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

* fix: --help exits 0 and suppresses engine error leakage

Add isHelpRequested() helper that detects flag.ErrHelp propagated through
the pipeline engine. In main():
- No-args case now exits 0 (showing help is not an error)
- Help requests in dispatch exit 0 without printing engine error

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

* feat(wfctl): add plugin name normalization to multi-registry

Add normalizePluginName() stripping "workflow-plugin-" prefix so users
can reference plugins by short name (e.g. "authz") or full name
(e.g. "workflow-plugin-authz") interchangeably. Wire into FetchManifest
and SearchPlugins.

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

* feat: validate --dir skips non-workflow YAML files

Add isWorkflowYAML() that checks the first 100 lines of a file for
top-level modules:, workflows:, or pipelines: keys. Files found by
--dir that don't match are skipped with a stderr message, preventing
false validation failures on GitHub Actions CI files and other YAML.

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

* feat: add version check to plugin update command

Before downloading, compare installed plugin.json version against the
registry manifest version. If equal, print "already at latest version"
and skip. If different, print "Updating from X to Y..." and proceed.
Also adds -config flag to plugin update for registry config override.

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

* fix: infra commands show actionable error when no config found

Improve the error message from the generic "no config file found" to a
helpful message that explains what the config needs and how to generate one.

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

* test(wfctl): add TestPluginInstallRespectsPluginDir

Verify that install uses -plugin-dir (custom dir) instead of the
default data/plugins path. This guards the fix from Task 2 that
updated runPluginUpdate to pass --plugin-dir, not --data-dir, when
calling runPluginInstall.

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

* fix: handle missing go.sum in init Dockerfile templates

Replace `COPY go.mod go.sum ./` with `COPY go.mod ./` + `COPY go.sum* ./`
so the generated Dockerfile works whether or not go.sum exists yet.
The glob pattern in the second COPY is a no-op when go.sum is absent.

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

* feat: log resolved imports during validate

Read raw YAML to extract the imports: list before calling
config.LoadFromFile. After loading, print "Resolved N import(s): ..."
to stderr so users can see which files were included. This makes the
validate command transparent about include/import resolution.

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

* feat(wfctl): accept positional config arg in deploy subcommands

Allow users to pass the config file as a positional argument instead of
always requiring -config, e.g. `wfctl deploy cloud myapp.yaml`.

Applied to: runDeployDocker, runK8sGenerate, runK8sApply, runDeployCloud.

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

* feat: PluginManifest UnmarshalJSON handles legacy capabilities object format

Add custom UnmarshalJSON on PluginManifest that detects whether the
capabilities field is an array (new CapabilityDecl format) or an object
(legacy registry format with moduleTypes/stepTypes/triggerTypes).

When the legacy object format is detected, its type lists are merged into
the top-level ModuleTypes, StepTypes, and TriggerTypes fields so callers
always find types in a consistent location regardless of plugin.json format.

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

* fix: plugin info shows absolute binary path

Resolve pluginDir to absolute path before displaying the binary path,
so users see /absolute/path/to/plugin instead of relative data/plugins/foo.

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

* feat: engine warns when plugin minEngineVersion exceeds current version

Add MinEngineVersion field to PluginManifest and checkEngineCompatibility()
to plugin/loader.go. The loader calls this on every plugin load — if the
running engine version is older than the plugin's declared minimum, a WARNING
is printed to stderr. No hard fail to allow testing newer plugins against
older engines.

SetEngineVersion() on PluginLoader threads the engine version through.

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

* feat: add GitHub URL install support to plugin install

Add parseGitHubRef() to detect owner/repo[@Version] references.
Add installFromGitHub() to query GitHub Releases API and download
assets matching {repo}_{os}_{arch}.tar.gz.

In runPluginInstall, when the registry lookup fails and the input
looks like a GitHub ref, fall back to direct GitHub installation.
This allows: wfctl plugin install GoCodeAlone/workflow-plugin-authz@v0.3.1

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

* feat: plugin lockfile support via .wfctl.yaml plugins section

Add PluginLockfile/PluginLockEntry types with load/save that preserve
all other .wfctl.yaml fields (project, git, deploy) on round-trip.

Wire into plugin install:
- `wfctl plugin install` (no args): reads .wfctl.yaml plugins section
  and installs all pinned entries
- `wfctl plugin install <name>@<version>`: after successful install,
  updates/creates the plugins entry in .wfctl.yaml

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

* docs: add plugin goreleaser reference config

Reference .goreleaser.yml for plugin repos documenting required conventions:
- binary using {{ .ProjectName }} template
- archives include plugin.json
- before/after hooks to template plugin.json version from release tag

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

* fix: correct FetchManifest arg and destDir for GitHub installs

Two bugs in Task 16 GitHub install fallback:
1. Pass pluginName (version-stripped) to FetchManifest, not nameArg
   which may carry @Version suffix and cause lookup failures.
2. Compute destDir after normalizing the repo short name so
   owner/repo installs go to data/plugins/<shortname> not the raw input.

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

* fix: lockfile install doesn't re-pin; engine compat uses slog

Task 17: installFromLockfile now passes just the plugin name (no @Version)
to runPluginInstall so updateLockfile doesn't fire and overwrite the pinned
entry in .wfctl.yaml during a lockfile-driven restore.

Task 18: checkEngineCompatibility uses slog.Warn instead of fmt.Fprintf
to stderr, consistent with the rest of the codebase. Remove unused "os"
import from loader.go.

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

* fix: use published @gocodealone/workflow-editor from GitHub Packages

Replace local file path reference with ^0.2.0 from GitHub Packages
registry. Fixes CI failures where the local tarball doesn't exist.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: remove trailing punctuation from infra error string (ST1005)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
@intel352
Copy link
Contributor

@copilot apply changes based on the comments in this thread

Also fix the merge conflict

Co-authored-by: intel352 <77607+intel352@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 13, 2026

@copilot apply changes based on the comments in this thread

Also fix the merge conflict

Done in 5932d16. UnmarshalJSON now peeks at the first non-whitespace byte to route to the correct decoder branch, and returns a descriptive error for any other JSON type (string, number, bool). A negative test TestManifestCapabilitiesInvalidFormat covers the string/number/bool cases.

@intel352
Copy link
Contributor

@copilot Fix the merge conflict

…awCaps pattern, move Dependency

Co-authored-by: intel352 <77607+intel352@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 13, 2026

@copilot Fix the merge conflict

Fixed in 62dfb7f. Incorporated all structural changes from main into manifest.go: added MinEngineVersion field, moved Dependency struct to follow CapabilityDecl, and switched UnmarshalJSON to use the type rawManifest PluginManifest + withRawCaps pattern. Our additions (error on unsupported capability format, firstNonSpace, appendUnique, WorkflowTypes in legacy caps) are preserved.

@github-actions
Copy link

⏱ Benchmark Results

No significant performance regressions detected.

benchstat comparison (baseline → PR)
## benchstat: baseline → PR
baseline-bench.txt:244: parsing iteration count: invalid syntax
baseline-bench.txt:291221: parsing iteration count: invalid syntax
baseline-bench.txt:587877: parsing iteration count: invalid syntax
baseline-bench.txt:876670: parsing iteration count: invalid syntax
baseline-bench.txt:1174781: parsing iteration count: invalid syntax
baseline-bench.txt:1475958: parsing iteration count: invalid syntax
benchmark-results.txt:244: parsing iteration count: invalid syntax
benchmark-results.txt:333272: parsing iteration count: invalid syntax
benchmark-results.txt:679029: parsing iteration count: invalid syntax
benchmark-results.txt:1033174: parsing iteration count: invalid syntax
benchmark-results.txt:1430309: parsing iteration count: invalid syntax
benchmark-results.txt:1751604: parsing iteration count: invalid syntax
goos: linux
goarch: amd64
pkg: github.com/GoCodeAlone/workflow/dynamic
cpu: AMD EPYC 7763 64-Core Processor                
                            │ baseline-bench.txt │
                            │       sec/op       │
InterpreterCreation-4               7.718m ± 60%
ComponentLoad-4                     3.570m ±  1%
ComponentExecute-4                  2.037µ ±  3%
PoolContention/workers-1-4          1.109µ ±  4%
PoolContention/workers-2-4          1.109µ ±  1%
PoolContention/workers-4-4          1.109µ ±  1%
PoolContention/workers-8-4          1.107µ ±  2%
PoolContention/workers-16-4         1.118µ ±  4%
ComponentLifecycle-4                3.605m ±  1%
SourceValidation-4                  2.403µ ±  1%
RegistryConcurrent-4                804.9n ±  6%
LoaderLoadFromString-4              3.707m ±  2%
geomean                             19.16µ

                            │ baseline-bench.txt │
                            │        B/op        │
InterpreterCreation-4               1.944Mi ± 0%
ComponentLoad-4                     2.097Mi ± 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.099Mi ± 0%
SourceValidation-4                  1.984Ki ± 0%
RegistryConcurrent-4                1.133Ki ± 0%
LoaderLoadFromString-4              2.099Mi ± 0%
geomean                             15.05Ki

                            │ baseline-bench.txt │
                            │     allocs/op      │
InterpreterCreation-4                15.09k ± 0%
ComponentLoad-4                      17.43k ± 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                 17.48k ± 0%
SourceValidation-4                    32.00 ± 0%
RegistryConcurrent-4                  2.000 ± 0%
LoaderLoadFromString-4               17.47k ± 0%
geomean                               181.2

cpu: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
                            │ benchmark-results.txt │
                            │        sec/op         │
InterpreterCreation-4                  6.289m ± 58%
ComponentLoad-4                        3.292m ±  1%
ComponentExecute-4                     1.946µ ±  1%
PoolContention/workers-1-4             1.190µ ±  2%
PoolContention/workers-2-4             1.192µ ±  1%
PoolContention/workers-4-4             1.194µ ±  5%
PoolContention/workers-8-4             1.191µ ±  1%
PoolContention/workers-16-4            1.208µ ±  2%
ComponentLifecycle-4                   3.380m ±  2%
SourceValidation-4                     2.236µ ±  1%
RegistryConcurrent-4                   896.4n ±  4%
LoaderLoadFromString-4                 3.351m ±  1%
geomean                                19.01µ

                            │ benchmark-results.txt │
                            │         B/op          │
InterpreterCreation-4                  1.944Mi ± 0%
ComponentLoad-4                        2.097Mi ± 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.099Mi ± 0%
SourceValidation-4                     1.984Ki ± 0%
RegistryConcurrent-4                   1.133Ki ± 0%
LoaderLoadFromString-4                 2.099Mi ± 0%
geomean                                15.05Ki

                            │ benchmark-results.txt │
                            │       allocs/op       │
InterpreterCreation-4                   15.09k ± 0%
ComponentLoad-4                         17.43k ± 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                    17.48k ± 0%
SourceValidation-4                       32.00 ± 0%
RegistryConcurrent-4                     2.000 ± 0%
LoaderLoadFromString-4                  17.47k ± 0%
geomean                                  181.2

pkg: github.com/GoCodeAlone/workflow/middleware
cpu: AMD EPYC 7763 64-Core Processor                
                                  │ baseline-bench.txt │
                                  │       sec/op       │
CircuitBreakerDetection-4                  309.8n ± 4%
CircuitBreakerExecution_Success-4          22.54n ± 0%
CircuitBreakerExecution_Failure-4          64.41n ± 0%
geomean                                    76.62n

                                  │ 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

cpu: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
                                  │ benchmark-results.txt │
                                  │        sec/op         │
CircuitBreakerDetection-4                     456.2n ± 6%
CircuitBreakerExecution_Success-4             59.78n ± 0%
CircuitBreakerExecution_Failure-4             64.65n ± 0%
geomean                                       120.8n

                                  │ 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

pkg: github.com/GoCodeAlone/workflow/module
cpu: AMD EPYC 7763 64-Core Processor                
                                 │ baseline-bench.txt │
                                 │       sec/op       │
JQTransform_Simple-4                     945.8n ± 21%
JQTransform_ObjectConstruction-4         1.495µ ±  1%
JQTransform_ArraySelect-4                3.465µ ±  2%
JQTransform_Complex-4                    39.24µ ±  1%
JQTransform_Throughput-4                 1.826µ ±  1%
SSEPublishDelivery-4                     67.34n ±  1%
geomean                                  1.694µ

                                 │ 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

cpu: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
                                 │ benchmark-results.txt │
                                 │        sec/op         │
JQTransform_Simple-4                        894.2n ± 26%
JQTransform_ObjectConstruction-4            1.527µ ±  3%
JQTransform_ArraySelect-4                   3.319µ ±  3%
JQTransform_Complex-4                       36.18µ ±  4%
JQTransform_Throughput-4                    1.816µ ±  2%
SSEPublishDelivery-4                        72.89n ±  7%
geomean                                     1.670µ

                                 │ 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

pkg: github.com/GoCodeAlone/workflow/schema
cpu: AMD EPYC 7763 64-Core Processor                
                                    │ baseline-bench.txt │
                                    │       sec/op       │
SchemaValidation_Simple-4                   1.123µ ± 12%
SchemaValidation_AllFields-4                1.726µ ±  4%
SchemaValidation_FormatValidation-4         1.629µ ±  2%
SchemaValidation_ManySchemas-4              1.842µ ±  4%
geomean                                     1.553µ

                                    │ 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

cpu: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
                                    │ benchmark-results.txt │
                                    │        sec/op         │
SchemaValidation_Simple-4                       1.027µ ± 4%
SchemaValidation_AllFields-4                    1.517µ ± 6%
SchemaValidation_FormatValidation-4             1.469µ ± 1%
SchemaValidation_ManySchemas-4                  1.505µ ± 1%
geomean                                         1.362µ

                                    │ 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

pkg: github.com/GoCodeAlone/workflow/store
cpu: AMD EPYC 7763 64-Core Processor                
                                   │ baseline-bench.txt │
                                   │       sec/op       │
EventStoreAppend_InMemory-4                1.254µ ± 12%
EventStoreAppend_SQLite-4                  1.390m ±  5%
GetTimeline_InMemory/events-10-4           14.50µ ±  2%
GetTimeline_InMemory/events-50-4           64.29µ ± 25%
GetTimeline_InMemory/events-100-4          129.0µ ±  1%
GetTimeline_InMemory/events-500-4          661.0µ ±  2%
GetTimeline_InMemory/events-1000-4         1.370m ±  0%
GetTimeline_SQLite/events-10-4             111.5µ ±  1%
GetTimeline_SQLite/events-50-4             261.4µ ±  2%
GetTimeline_SQLite/events-100-4            448.1µ ±  2%
GetTimeline_SQLite/events-500-4            1.890m ±  1%
GetTimeline_SQLite/events-1000-4           3.661m ±  1%
geomean                                    225.3µ

                                   │ baseline-bench.txt │
                                   │        B/op        │
EventStoreAppend_InMemory-4                  828.5 ± 7%
EventStoreAppend_SQLite-4                  1.982Ki ± 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.60Ki

                                   │ 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

cpu: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
                                   │ benchmark-results.txt │
                                   │        sec/op         │
EventStoreAppend_InMemory-4                   1.129µ ± 16%
EventStoreAppend_SQLite-4                     1.459m ± 10%
GetTimeline_InMemory/events-10-4              13.89µ ±  3%
GetTimeline_InMemory/events-50-4              78.42µ ±  5%
GetTimeline_InMemory/events-100-4             148.1µ ± 18%
GetTimeline_InMemory/events-500-4             615.2µ ±  1%
GetTimeline_InMemory/events-1000-4            1.252m ±  2%
GetTimeline_SQLite/events-10-4                84.12µ ±  1%
GetTimeline_SQLite/events-50-4                241.7µ ±  3%
GetTimeline_SQLite/events-100-4               439.6µ ±  3%
GetTimeline_SQLite/events-500-4               1.937m ±  1%
GetTimeline_SQLite/events-1000-4              3.782m ±  2%
geomean                                       220.8µ

                                   │ benchmark-results.txt │
                                   │         B/op          │
EventStoreAppend_InMemory-4                    768.5 ± 10%
EventStoreAppend_SQLite-4                    1.983Ki ±  0%
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.19Ki

                                   │ 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

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

@intel352 intel352 merged commit e4cf1aa into main Mar 13, 2026
11 checks passed
@intel352 intel352 deleted the copilot/fix-doc-generation-error-handling branch March 13, 2026 03:18
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