Skip to content

test(wftest/bdd): AssertProviderCapabilitiesMatchRegistration belt-and-braces guard (Task 15)#606

Merged
intel352 merged 8 commits into
mainfrom
feat/wftest-bdd-iac-task15
May 10, 2026
Merged

test(wftest/bdd): AssertProviderCapabilitiesMatchRegistration belt-and-braces guard (Task 15)#606
intel352 merged 8 commits into
mainfrom
feat/wftest-bdd-iac-task15

Conversation

@intel352
Copy link
Copy Markdown
Contributor

Summary

Task 15 of the strict-contracts force-cutover plan (docs/plans/2026-05-10-strict-contracts-force-cutover.md, rev5).

Adds wftest/bdd/strict_iac.go with AssertProviderCapabilitiesMatchRegistration(t, provider, grpcSrv) — the cycle 4 belt-and-braces test-time guard.

The canonical registration path is sdk.RegisterAllIaCProviderServices (Task 4, PR #599), which uses Go type-assertion to auto-detect every interface and cannot omit a registration. The per-service Register* helpers are still exposed for advanced use cases (e.g., a plugin that registers a different Go type per optional service); this helper is the test-time guard that catches the manual-registration omission failure mode.

Stacked on PR #602 (Task 5). Base branch is feat/iac-sdk-contracts-task5.

Behavior

The helper does two passes:

  • Pass 1 — every typed IaC interface satisfied by the provider's Go type IS registered on the gRPC server. Missing registrations are reported with the specific service name(s).
  • Pass 2 — no IaC service is registered that the provider's Go type does NOT satisfy. Over-registration (e.g., Enumerator registered but provider is requiredOnlyStub) is reported.

iacServiceChecks lists every typed IaC service the helper knows about (Required + 6 optional + ResourceDriver). New optional services added to iac.proto must be appended here.

Helper takes a strictIaCT interface (Errorf + Fatalf + Helper) rather than *testing.T directly so the failure path itself is unit-testable via a recording double.

Tests (4 cases, all PASS, race-mode included)

  • AutoRegisteredAllOK — silent pass when sdk.RegisterAllIaCProviderServices is used as designed
  • ManuallyRegisteredMissingOptional_Fails — provider satisfies every optional + ResourceDriver but author registered only Required + Enumerator manually → helper names DriftDetector / CredentialRevoker / MigrationRepairer / Validator / DriftConfigDetector / ResourceDriver in the error messages
  • ProviderMissingRequired_Fails — broken test fixture (provider doesn't satisfy IaCProviderRequiredServer) → fatal-class failure naming the missing interface
  • RegisteredButProviderDoesntSatisfy_Fails — server has Enumerator registered but provider is requiredOnlyStub → over-registration named in error

Verification

  • GOWORK=off go test -race ./wftest/... → PASS
  • GOWORK=off go build ./... → clean
  • GOWORK=off go vet ./wftest/... → clean

Rollback

Revert this commit; canonical registration path (sdk.RegisterAllIaCProviderServices) is unaffected.

Test plan

  • All 4 BDD assertion tests pass
  • Race-mode test passes
  • Existing wftest tests unaffected
  • No new lint or vet warnings

🤖 Generated with Claude Code

intel352 added 6 commits May 10, 2026 02:09
…ices + ResourceDriver

Task 3 of the strict-contracts force-cutover plan
(docs/plans/2026-05-10-strict-contracts-force-cutover.md, rev5).

Adds plugin/external/proto/iac.proto defining the typed gRPC contract
that supersedes the legacy InvokeService/structpb dispatch path for
IaCProvider + ResourceDriver:

- service IaCProviderRequired: 11 RPCs every IaC plugin MUST implement
  (Initialize, Name, Version, Capabilities, Plan, Apply, Destroy,
  Status, Import, ResolveSizing, BootstrapStateBackend). Compile-time
  enforced via the SDK type-assert in Task 4.

- 6 optional services — providers register only the ones they support:
  IaCProviderEnumerator (EnumerateAll, EnumerateByTag),
  IaCProviderDriftDetector (DetectDrift, DetectDriftWithSpecs),
  IaCProviderCredentialRevoker (RevokeProviderCredential),
  IaCProviderMigrationRepairer (RepairDirtyMigration),
  IaCProviderValidator (ValidatePlan),
  IaCProviderDriftConfigDetector (DetectDriftConfig).
  Absence of registration IS the negative signal — no NotSupported
  field on any optional response (per design §Optional services).

- service ResourceDriver: 9 RPCs for per-resource-type CRUD dispatch
  (Create, Read, Update, Delete, Diff, Scale, HealthCheck,
  SensitiveKeys, Troubleshoot), each carrying resource_type so a
  single server can route to the per-type driver implementation.

Hard invariants honored:
- NO google.protobuf.Struct, NO google.protobuf.Any anywhere.
- Free-form per-resource Config/Outputs payloads cross the wire as
  bytes <name>_json (the plugin owns json.Marshal/Unmarshal); this
  eliminates the structpb conversion surface that previously dropped
  map[string]bool entries silently (T3.9 finding).
- ResourceOutput.sensitive uses typed map<string, bool> per design.

Generated iac.pb.go + iac_grpc.pb.go via protoc v34.1 +
protoc-gen-go v1.36.11 + protoc-gen-go-grpc v1.6.1.

Failing test (plugin/external/proto/iac_proto_test.go) asserts the
generated server interfaces exist and have the methods the design
requires — drops in iac.proto cause the test file to fail to compile.

Verification: GOWORK=off go test ./plugin/external/proto/... PASSES;
GOWORK=off go build ./plugin/... ./cmd/... ./module/... clean.

Rollback: revert this commit; legacy InvokeService dispatch in
plugin.proto remains functional; the additive-only nature of this PR
means no consumer is affected until subsequent tasks wire callers.
Task 4 of the strict-contracts force-cutover plan
(docs/plans/2026-05-10-strict-contracts-force-cutover.md, rev5).

Adds plugin/external/sdk/iacserver.go: a single helper that uses Go
type-assertion to register every typed IaC gRPC service the provider
satisfies, in one call.

REQUIRED service:
  pb.IaCProviderRequiredServer — surfaced as a clear startup-time error
  if the provider type doesn't satisfy it (rather than failing at the
  first RPC dispatch with a generic "unimplemented" status).

OPTIONAL services (auto-detected): IaCProviderEnumerator,
IaCProviderDriftDetector, IaCProviderCredentialRevoker,
IaCProviderMigrationRepairer, IaCProviderValidator,
IaCProviderDriftConfigDetector. Plus ResourceDriver.

Per cycle 3 I-1 of the design: plugin authors write ONE call; they
cannot omit registration for a capability they implemented. This
removes the registration-omission bug class (the same shape as the
legacy InvokeService case-string-typo bug) by removing the manual
step entirely.

Tests cover four cases:
- required-satisfied → required service registered + advertised by
  grpcSrv.GetServiceInfo().
- enumerator-only → only the optional Enumerator service registered;
  other optionals stay absent (auto-detection precision).
- empty-stub → returns an error naming the unsatisfied required
  interface, with a docs pointer.
- all-capabilities-stub → all 8 typed services (Required + 6 optional
  + ResourceDriver) registered.

Stacked on feat/iac-proto-task3 (Task 3 PR #598 provides the
generated server interfaces this helper consumes).

Verification: GOWORK=off go test -race ./plugin/external/sdk/...
PASS; GOWORK=off go build ./plugin/... ./cmd/... ./module/... clean;
GOWORK=off go vet ./plugin/external/... clean.

Rollback: revert this commit; SDK consumers can still register
services manually via the per-service Register* helpers protoc
generated.
…rver callback

Task 29 of the strict-contracts force-cutover plan
(docs/plans/2026-05-10-strict-contracts-force-cutover.md, rev5).

Adds the high-level plugin-author API on top of Task 4's
RegisterAllIaCProviderServices:

  func main() {
      sdk.ServeIaCPlugin(&doProvider{}, sdk.IaCServeOptions{})
  }

Per cycle 3 I-1 of the design, service registration happens INSIDE
go-plugin's GRPCServer callback (iacGRPCPlugin.GRPCServer) — the
framework owns *grpc.Server lifecycle, so plugin authors cannot
pre-create a server and forget to register a typed service on it.

API surface (all in plugin/external/sdk/iacserver.go):
- IaCServeOptions{ PluginInfo *PluginInfo } — caller-side options.
- PluginInfo{ HandshakeConfig goplugin.HandshakeConfig } — extension
  point for future Name/Version metadata; defaults to ext.Handshake
  (the canonical wfctl<->plugin handshake) when zero-valued.
- iacGRPCPlugin{provider any} — implements goplugin.Plugin
  (GRPCServer + GRPCClient). The GoCodeAlone fork of go-plugin v1.7.0
  is gRPC-only and exposes only the canonical Plugin interface; there
  is no GRPCPlugin alias or NetRPCUnsupportedPlugin embed to use.
- ServeIaCPlugin(provider, opts) — wraps goplugin.Serve with the
  resolved handshake + a single iacGRPCPlugin entry under the "iac"
  key.
- resolveServeHandshake(opts) — extracted helper so the override-vs-
  default rule is unit-testable without invoking the blocking
  goplugin.Serve loop.

Tests (iacserver_serve_test.go) cover six cases via internal-package
tests (so the unexported plugin type is exercisable without a real
subprocess; subprocess-level coverage lands in Task 6's typed-IaC E2E
test):
- iacGRPCPlugin.GRPCServer registers all satisfied services on the
  framework-managed *grpc.Server (Required + Enumerator + ResourceDriver
  for the all-stub).
- iacGRPCPlugin.GRPCServer propagates the auto-register error for an
  empty stub — go-plugin aborts plugin startup with an actionable
  message.
- iacGRPCPlugin.GRPCClient is a no-op (host builds typed clients
  directly).
- iacGRPCPlugin satisfies goplugin.Plugin at compile time (refactor
  guard).
- ServeIaCPlugin defaults to ext.Handshake when PluginInfo is nil.
- ServeIaCPlugin honors a non-zero override handshake when provided.

Stacked on feat/iac-sdk-auto-register-task4 (Task 4 PR #599 provides
RegisterAllIaCProviderServices, which the GRPCServer callback delegates
to).

Verification: GOWORK=off go test -race ./plugin/external/sdk/... PASS;
GOWORK=off go build ./plugin/... ./cmd/... ./module/... clean;
GOWORK=off go vet ./plugin/external/... clean.

Rollback: revert this commit; plugin authors can fall back to
manually constructing goplugin.Serve + Plugins map referencing
RegisterAllIaCProviderServices in their own GRPCServer callback.
Task 5 of the strict-contracts force-cutover plan
(docs/plans/2026-05-10-strict-contracts-force-cutover.md, rev5).

Adds plugin/external/sdk/contracts.go with the BuildContractRegistry
helper that enumerates grpc.Server.GetServiceInfo() and emits a
SERVICE-kind ContractDescriptor for each registered service.
ContractMode is set to STRICT_PROTO so the host can distinguish typed
IaC services from the legacy structpb-mode contracts produced by
Module/Step/Trigger ContractProvider implementations.

Per cycle 3 I-1 of the design: wfctl needs a single mechanism to
discover "is the optional service registered on this plugin handle?".
Reusing the existing ContractRegistry shape keeps Module/Step/Trigger
and IaC capability discovery on the same wire surface — no new gRPC
server-reflection dependency required.

Service descriptors are emitted in deterministic alphabetical order
so callers can rely on stable output for diff/compare operations and
the wftest BDD test in Task 15.

The helper is safe to call with a nil server (returns an empty but
non-nil ContractRegistry) so callers that may construct it before the
gRPC server exists do not panic.

Tests (contracts_iac_test.go) cover three cases — all pass:
- AdvertisesRegisteredIaCServices: a Required + Enumerator +
  DriftDetector stub yields exactly those service descriptors.
- ServiceContractsUseStrictProtoMode: every emitted descriptor is
  Kind=SERVICE + Mode=STRICT_PROTO (host-side discriminator).
- NilServer_ReturnsEmpty: defensive contract for nil input.

Stacked on feat/iac-sdk-serve-task29 (Task 29 PR #600 provides
ServeIaCPlugin which IaC plugins use to register the services this
helper enumerates).

Verification: GOWORK=off go test -race ./plugin/external/sdk/... PASS;
GOWORK=off go build ./plugin/... ./cmd/... ./module/... clean;
GOWORK=off go vet ./plugin/external/... clean.

Rollback: revert this commit; ContractRegistry returns the prior
shape (Module/Step/Trigger only via the existing ContractProvider
hook in grpc_server.go).
…d-braces guard

Task 15 of the strict-contracts force-cutover plan
(docs/plans/2026-05-10-strict-contracts-force-cutover.md, rev5).

Adds wftest/bdd/strict_iac.go with the
AssertProviderCapabilitiesMatchRegistration helper. Given a Go
provider implementation + the gRPC server with the plugin's
service registrations, the helper asserts:

- Pass 1: every typed IaC service interface satisfied by the
  provider's Go type IS registered on the gRPC server.
- Pass 2: no IaC service is registered on the gRPC server that
  the provider's Go type does NOT satisfy (catches the "manual
  Register* call binds a different Go impl" failure mode).

Per cycle 4 belt-and-braces of the design: the canonical
registration path is sdk.RegisterAllIaCProviderServices, which
uses Go type-assertion to auto-detect every interface and cannot
omit a registration. The per-service Register* helpers are still
exposed for advanced use cases; this helper is the test-time
guard that catches the manual-registration omission failure mode.

iacServiceChecks lists every typed IaC service the helper knows
about (Required + 6 optional + ResourceDriver). New optional
services added to iac.proto must be appended here.

Helper takes a strictIaCT interface (Errorf + Fatalf + Helper)
rather than *testing.T directly so the failure path itself is
unit-testable via a recordingT double — the four tests in
strict_iac_test.go cover the four behavior axes:

- AutoRegisteredAllOK: silent pass when sdk.RegisterAllIaCProviderServices
  was used as designed.
- ManuallyRegisteredMissingOptional_Fails: provider satisfies
  every optional + ResourceDriver but author registered only
  Required + Enumerator manually → helper names every missing
  service in the error messages.
- ProviderMissingRequired_Fails: broken test fixture (provider
  doesn't satisfy IaCProviderRequiredServer) → fatal-class
  failure with the missing interface named.
- RegisteredButProviderDoesntSatisfy_Fails: server has Enumerator
  registered but provider passed to assert is requiredOnlyStub
  → over-registration named in error.

Stacked on feat/iac-sdk-contracts-task5 (Task 5 PR #602 provides
the typed proto interfaces this helper inspects via reflection-
free type-assert chain).

Verification: GOWORK=off go test -race ./wftest/... PASS;
GOWORK=off go build ./... clean; GOWORK=off go vet ./wftest/...
clean.

Rollback: revert this commit; canonical registration path
(sdk.RegisterAllIaCProviderServices) is unaffected.
Per cycle 4 code-review PR 606 MINOR-1: iacServiceChecks in
wftest/bdd/strict_iac.go is a manually-maintained list of typed IaC
services. If iac.proto adds a new optional service later without
appending to iacServiceChecks, AssertProviderCapabilitiesMatchRegistration
silently passes for the new service (the satisfies check is never
invoked for unlisted services), leaving a hole in the cycle 4 belt-
and-braces invariant.

Adds wftest/bdd/strict_iac_internal_test.go (package bdd, internal
test so iacServiceChecks is in scope) with
TestIaCServiceChecks_CoversEveryProtoService — walks
pb.File_plugin_external_proto_iac_proto.Services() at runtime and
asserts:

- Forward: every IaC service name in the proto (prefix-matched on
  iacServicePrefix) appears in iacServiceChecks. Missing entries
  produce a test failure naming the service(s) the proto declares
  but the helper doesn't cover.
- Inverse: every iacServiceCheck row names a service the proto
  actually declares. Catches the rename-without-cleanup failure
  mode (proto renames a service; iacServiceChecks still references
  the old name).

Tightens the manual-maintenance surface into a compile-time-
discoverable test failure rather than a silent test-passing
regression.

Verification: GOWORK=off go test ./wftest/bdd/... -run
"TestIaCServiceChecks|TestAssertProviderCapabilities" -count=1 →
PASS (5/5); gofmt clean.

Rollback: revert this commit; the cycle 4 belt-and-braces guard
returns to the manual-maintenance form (still works, just no
test-time coverage check on the helper itself).
Copy link
Copy Markdown
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

Adds a new wftest/BBD helper that cross-checks a provider’s Go-level IaC gRPC capabilities against what’s actually registered on a grpc.Server, to catch manual registration omissions/over-registrations during tests as part of the strict-contracts force-cutover plan.

Changes:

  • Introduces bdd.AssertProviderCapabilitiesMatchRegistration(t, provider, grpcSrv) with a two-pass check for missing vs extra IaC service registrations.
  • Adds external-package tests covering OK, missing optional registrations, missing required interface, and over-registration scenarios.
  • Adds an internal-package guard test that ensures iacServiceChecks stays in sync with the services declared in iac.proto.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
wftest/bdd/strict_iac.go Implements the assertion helper and the known IaC service checklist.
wftest/bdd/strict_iac_test.go Black-box tests validating helper behavior across key failure modes.
wftest/bdd/strict_iac_internal_test.go Ensures the helper’s service checklist matches iac.proto service declarations.

Comment thread wftest/bdd/strict_iac.go
if _, ok := provider.(pb.IaCProviderRequiredServer); !ok {
t.Fatalf(
"provider %T does not satisfy pb.IaCProviderRequiredServer "+
"(broken test fixture); see decisions/0024-iac-typed-force-cutover.md",
@intel352 intel352 force-pushed the feat/iac-sdk-contracts-task5 branch from c03c871 to 8bb6e52 Compare May 10, 2026 11:31
@intel352 intel352 changed the base branch from feat/iac-sdk-contracts-task5 to main May 10, 2026 11:40
intel352 added 2 commits May 10, 2026 07:40
…ask15

# Conflicts:
#	plugin/external/proto/iac.pb.go
#	plugin/external/proto/iac.proto
#	plugin/external/proto/iac_grpc.pb.go
#	plugin/external/proto/iac_proto_test.go
#	plugin/external/sdk/iacserver.go
#	plugin/external/sdk/iacserver_serve_test.go
#	plugin/external/sdk/iacserver_test.go
…e-merge)

Generated proto descriptor variable is File_iac_proto (per iac.proto's
go_package option), not File_plugin_external_proto_iac_proto. Reference
fixed; all 5 BDD strict-IaC tests PASS.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Copilot AI review requested due to automatic review settings May 10, 2026 11:44
Copy link
Copy Markdown
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

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 10, 2026

⏱ Benchmark Results

No significant performance regressions detected.

benchstat comparison (baseline → PR)
## benchstat: baseline → PR
baseline-bench.txt:262: parsing iteration count: invalid syntax
baseline-bench.txt:285353: parsing iteration count: invalid syntax
baseline-bench.txt:577155: parsing iteration count: invalid syntax
baseline-bench.txt:872752: parsing iteration count: invalid syntax
baseline-bench.txt:1176119: parsing iteration count: invalid syntax
baseline-bench.txt:1495584: parsing iteration count: invalid syntax
benchmark-results.txt:262: parsing iteration count: invalid syntax
benchmark-results.txt:368033: parsing iteration count: invalid syntax
benchmark-results.txt:643488: parsing iteration count: invalid syntax
benchmark-results.txt:1007614: parsing iteration count: invalid syntax
benchmark-results.txt:1390469: parsing iteration count: invalid syntax
benchmark-results.txt:1680342: 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               5.620m ± 83%
ComponentLoad-4                     3.647m ± 10%
ComponentExecute-4                  1.931µ ±  0%
PoolContention/workers-1-4          1.099µ ±  1%
PoolContention/workers-2-4          1.092µ ±  4%
PoolContention/workers-4-4          1.100µ ±  1%
PoolContention/workers-8-4          1.101µ ±  3%
PoolContention/workers-16-4         1.101µ ±  1%
ComponentLifecycle-4                3.645m ±  3%
SourceValidation-4                  2.311µ ±  1%
RegistryConcurrent-4                814.0n ±  4%
LoaderLoadFromString-4              3.653m ±  1%
geomean                             18.48µ

                            │ 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

cpu: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
                            │ benchmark-results.txt │
                            │        sec/op         │
InterpreterCreation-4                  9.325m ± 67%
ComponentLoad-4                        3.450m ±  1%
ComponentExecute-4                     1.849µ ±  1%
PoolContention/workers-1-4             1.184µ ±  1%
PoolContention/workers-2-4             1.181µ ±  1%
PoolContention/workers-4-4             1.179µ ±  1%
PoolContention/workers-8-4             1.181µ ±  1%
PoolContention/workers-16-4            1.195µ ±  2%
ComponentLifecycle-4                   3.463m ±  1%
SourceValidation-4                     2.207µ ±  1%
RegistryConcurrent-4                   905.7n ±  6%
LoaderLoadFromString-4                 3.546m ±  1%
geomean                                19.69µ

                            │ 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

pkg: github.com/GoCodeAlone/workflow/middleware
cpu: AMD EPYC 7763 64-Core Processor                
                                  │ baseline-bench.txt │
                                  │       sec/op       │
CircuitBreakerDetection-4                  286.4n ± 7%
CircuitBreakerExecution_Success-4          21.36n ± 0%
CircuitBreakerExecution_Failure-4          66.37n ± 0%
geomean                                    74.05n

                                  │ 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                     450.4n ± 6%
CircuitBreakerExecution_Success-4             59.71n ± 0%
CircuitBreakerExecution_Failure-4             64.79n ± 0%
geomean                                       120.3n

                                  │ 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                     875.8n ± 30%
JQTransform_ObjectConstruction-4         1.460µ ±  9%
JQTransform_ArraySelect-4                3.430µ ±  3%
JQTransform_Complex-4                    38.51µ ±  2%
JQTransform_Throughput-4                 1.805µ ±  1%
SSEPublishDelivery-4                     63.67n ±  1%
geomean                                  1.639µ

                                 │ 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                        950.3n ± 23%
JQTransform_ObjectConstruction-4            1.490µ ±  1%
JQTransform_ArraySelect-4                   3.213µ ±  1%
JQTransform_Complex-4                       35.61µ ±  0%
JQTransform_Throughput-4                    1.800µ ±  0%
SSEPublishDelivery-4                        76.61n ±  0%
geomean                                     1.678µ

                                 │ 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.111µ ± 13%
SchemaValidation_AllFields-4                1.659µ ±  2%
SchemaValidation_FormatValidation-4         1.597µ ±  4%
SchemaValidation_ManySchemas-4              1.818µ ±  4%
geomean                                     1.521µ

                                    │ 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.028µ ±  7%
SchemaValidation_AllFields-4                   1.516µ ± 34%
SchemaValidation_FormatValidation-4            1.494µ ±  1%
SchemaValidation_ManySchemas-4                 1.496µ ±  2%
geomean                                        1.366µ

                                    │ 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.114µ ± 18%
EventStoreAppend_SQLite-4                  1.385m ±  2%
GetTimeline_InMemory/events-10-4           13.56µ ±  2%
GetTimeline_InMemory/events-50-4           75.72µ ±  3%
GetTimeline_InMemory/events-100-4          153.8µ ±  2%
GetTimeline_InMemory/events-500-4          627.1µ ± 27%
GetTimeline_InMemory/events-1000-4         1.277m ±  1%
GetTimeline_SQLite/events-10-4             106.4µ ±  1%
GetTimeline_SQLite/events-50-4             246.5µ ±  1%
GetTimeline_SQLite/events-100-4            417.9µ ±  1%
GetTimeline_SQLite/events-500-4            1.776m ±  0%
GetTimeline_SQLite/events-1000-4           3.459m ±  1%
geomean                                    220.4µ

                                   │ baseline-bench.txt │
                                   │        B/op        │
EventStoreAppend_InMemory-4                  798.0 ± 4%
EventStoreAppend_SQLite-4                  1.989Ki ± 1%
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.41Ki

                                   │ 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.123µ ± 19%
EventStoreAppend_SQLite-4                     951.7µ ±  5%
GetTimeline_InMemory/events-10-4              13.64µ ±  2%
GetTimeline_InMemory/events-50-4              75.23µ ±  3%
GetTimeline_InMemory/events-100-4             147.5µ ± 21%
GetTimeline_InMemory/events-500-4             594.2µ ±  2%
GetTimeline_InMemory/events-1000-4            1.213m ±  0%
GetTimeline_SQLite/events-10-4                81.40µ ±  1%
GetTimeline_SQLite/events-50-4                235.8µ ±  1%
GetTimeline_SQLite/events-100-4               423.9µ ±  1%
GetTimeline_SQLite/events-500-4               1.887m ±  1%
GetTimeline_SQLite/events-1000-4              3.730m ±  1%
geomean                                       208.3µ

                                   │ benchmark-results.txt │
                                   │         B/op          │
EventStoreAppend_InMemory-4                    745.0 ± 12%
EventStoreAppend_SQLite-4                    1.984Ki ±  1%
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.02Ki

                                   │ 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 d4b54a5 into main May 10, 2026
22 checks passed
@intel352 intel352 deleted the feat/wftest-bdd-iac-task15 branch May 10, 2026 11:59
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