Skip to content

fix(plugin/external): engine disk-manifest fallback + SDK embed helper + STRICT_PROTO _-prefix strip#643

Merged
intel352 merged 19 commits into
mainfrom
fix/strict-contracts-ergonomics-v0.51.3
May 12, 2026
Merged

fix(plugin/external): engine disk-manifest fallback + SDK embed helper + STRICT_PROTO _-prefix strip#643
intel352 merged 19 commits into
mainfrom
fix/strict-contracts-ergonomics-v0.51.3

Conversation

@intel352

Copy link
Copy Markdown
Contributor

Summary

Three surgical fixes for workflow v0.51.3 that unblock BMW deploy + every strict-cutover IaC + STRICT_PROTO plugin:

  1. Engine-side disk-manifest fallback (Bug 1 PRIMARY fix — zero plugin change). manager.go:108 already loads *plugin.PluginManifest via pluginpkg.LoadManifest + Validate. Thread that into NewExternalPluginAdapter as a fallback when gRPC GetManifest returns codes.Unimplemented (strict-cutover IaC plugins served via sdk.ServeIaCPlugin) or an empty Version. DO v1.0.11 registers cleanly via this fallback without re-release.

  2. SDK EmbedManifest helper + WithManifestProvider option (Bug 1 FORWARD-LOOKING). Plugin authors //go:embed plugin.json + call sdk.MustEmbedManifest(json), pass via sdk.WithManifestProvider or IaCServeOptions.ManifestProvider. Parses via canonical *plugin.PluginManifest (camelCase JSON tags), NOT *pb.Manifest (snake_case). Engine-fallback path is the immediate unblock; helper is opt-in defense-in-depth + portability.

  3. Engine _-prefix strip in createTypedConfigRequest (Bug 2). Strips _config_dir (and other engine internals) from cfg before mapToTypedAny for STRICT_PROTO modules whose protojson DiscardUnknown: false rejects unknown fields. Copy-on-clean — legacy *structpb.Struct path retains _config_dir for legacy modules.

Design

See: docs/plans/2026-05-12-strict-contracts-ergonomics-design.md (R2 PASS via 2 adversarial review cycles).

Implementation Plan

See: docs/plans/2026-05-12-strict-contracts-ergonomics.md (R2 PASS via 2 adversarial review cycles + alignment PASS + scope-locked at sha256 4c9a451758fd).

ADR

See: decisions/0031-strict-contracts-ergonomics.md.

Scope Manifest

  • PR Count: 1
  • Tasks: 8
  • Status: Locked 2026-05-12T18:00:00Z
PR # Title Tasks Branch
1 fix(plugin/external): engine disk-manifest fallback + SDK embed helper + STRICT_PROTO _-prefix strip Task 1, Task 2, Task 3, Task 4, Task 5, Task 6, Task 7, Task 8 fix/strict-contracts-ergonomics-v0.51.3

Changes (8 production commits)

Task Commit Description
1 37d3290 Engine disk-manifest fallback — manifestFromDisk helper + NewExternalPluginAdapter 3-arg signature; threaded from manager.go:169 + cmd/wfctl/plugin_conformance.go:327. 3 new tests + 18 updated call sites.
2 61e49a2 Regression test TestEngineManifestValidatesAfterDiskOverlay + precedence-rule comment in adapter.go (single source of truth = Task 1 constructor overlay).
3 f6b2815 stripInternalKeys helper + wire into createTypedConfigRequest. 8 new tests including module + step + legacy + DoesNotMutateInput.
4 92bb87d SDK EmbedManifest + MustEmbedManifest. 10 tests covering happy path + 9 rejection paths (missing Name/Version/Author/Description, malformed JSON, empty bytes, invalid-semver, invalid-name-shape, panic).
5 f16c108 Wire WithManifestProvider into grpcServer.GetManifest. Variadic Serve(...ServeOption) + ServePluginFull(...ServeOption) preserves existing callers.
6 c68826f IaCServeOptions.ManifestProvider + iacPluginServiceBridge.GetManifest override. Extract registerIaCServicesOnly preserving all nil + typed-nil hardening. New internal-test file for unexported bridge access.
7 7ebef77 Audit _-prefix proto fields across workflow engine + 6 wave plugins (66 .proto files). Verdict: PASS — zero collisions.
8 5379b67 + e554183 E2E TestManagerLoadPluginThreadsDiskManifestToAdapter + runtime-launch-validation transcript with pre-tag ritual (v0.51.3-rc1 → DO plugin rebuild → subprocess smoke → promote-or-rollback).

Test Plan

  • GOWORK=off go test ./plugin/external/ ./plugin/external/sdk/ → all PASS (local)
  • go build ./... → exits 0 (verified per task)
  • go build ./cmd/wfctl → exits 0 (F1 conformance caller correctness)
  • copy-on-clean contract locked in by TestStripInternalKeysDoesNotMutateInput
  • All 6 pb.Manifest scalar fields mapped in manifestFromDisk
  • Backward compat verified: 1-arg Serve(p) + 3-arg ServePluginFull(p, cli, hooks) + zero-value IaCServeOptions{} still compile via variadic / optional field
  • R2-3 hardening preserved: registerIaCServicesOnly retains nil-server, nil-provider, typed-nil-reflect checks verbatim
  • Underscore-prefix audit: workflow + 6 wave plugins, 66 .proto files, zero collisions
  • Pre-tag release ritual (required before tagging v0.51.3): see docs/audit/2026-05-12-v0.51.3-smoke-transcript.txt. Tag v0.51.3-rc1 → rebuild DO plugin against rc1 SDK → stage → launch cmd/server against staged DO binary → verify plugin "digitalocean" loaded successfully log line + no validate manifest errors + no proto: unknown field "_config_dir" errors → promote rc1 → v0.51.3.

Review process

  • 2 R cycles adversarial design review → PASS
  • 2 R cycles adversarial plan review → PASS
  • Alignment check (design ↔ plan) → PASS
  • Scope-locked at sha256 4c9a451758fd
  • Per-task spec review (8/8 PASS)
  • Per-task adversarial code review (8/8 PASS — 0 Critical / 0 Important across all 8)

Pre-existing test environment notes (NOT regressions)

  • cmd/wfctl TestInfraMultiEnv_E2E — fails on origin/main with identical wording (no plugin found for IaC provider "digitalocean" in ./data/plugins); env-dependent.
  • example.test/wfctl-ci/pkg TestFallbackRuns — synthetic negative-test fixture injected at cmd/wfctl/ci_run_test.go:178; outer test TestRunCIRunTestFallsBackToGoTestWhenNoConfiguredTests PASSES — inner FAIL line is the test's success signal.

Both reproduce on origin/main; not v0.51.3 regressions.

🤖 Generated with Claude Code

intel352 and others added 18 commits May 12, 2026 01:21
…_-strip)

Two upstream bugs surfaced by BMW v0.51.2 smoke gate:
1. IaC plugins via sdk.ServeIaCPlugin lack GetManifest impl → engine
   synthesized manifest has empty Version → Validate() rejects → registration fails.
2. Engine-injected _config_dir contaminates STRICT_PROTO module configs →
   protojson DiscardUnknown=false rejects unknown field → module init fails.

Fixes (workflow v0.51.3):
1. sdk.EmbedManifest helper + ManifestProvider option on all Serve* helpers.
   Plugins use //go:embed plugin.json to declare manifest at compile time.
2. Engine strips _-prefix keys from cfg before STRICT_PROTO encoding in
   createTypedConfigRequest. _-prefix reserved for engine internals.

ADR-0031 records the design + alternatives + trade-offs.

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

R1 Critical findings:
- C1: EmbedManifest used encoding/json into *pb.Manifest; mismatches camelCase
  plugin.json field names vs snake_case proto JSON tags. Fix: parse via the
  canonical *plugin.PluginManifest type which already has correct tags.
- C2: ServeIaCPlugin uses iacPluginServiceBridge for PluginService, NOT
  grpcServer. GetManifest handler lives on bridge. Fix: wire ManifestProvider
  into IaCServeOptions + bridge.GetManifest override.

R1 reviewer Option 3 adopted (significant pivot):
- manager.go:108 already loads disk plugin.json via pluginpkg.LoadManifest.
- Bug 1 PRIMARY fix moves engine-side: thread disk manifest into adapter as
  fallback when gRPC GetManifest returns empty/Unimplemented. ZERO plugin-side
  change required to unblock BMW.
- SDK helper (EmbedManifest) becomes forward-looking opt-in for plugins that
  want compile-time embedded manifest (defense-in-depth, not strictly required).

R1 Important findings addressed:
- A1 reframing: BMW unblocks the moment v0.51.3 ships; DO v1.0.12 is optional.
- stripInternalKeys clarified as copy-on-clean (fresh map, not in-place).
- ManifestProvider interface removed per YAGNI; concrete *plugin.PluginManifest is the type.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…urce overlay + F3 grep + F4 Validate semantics + F5 step path + F6 panic warning
…valid-shape tests + R2-3/4 task 6 clarity + R2-5 appendix + R2-6 launch step
Copilot AI review requested due to automatic review settings May 12, 2026 11:57

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 delivers three targeted fixes to the external plugin system to unblock strict-cutover IaC plugins and STRICT_PROTO plugins: (1) engine-side fallback to the on-disk plugin.json manifest when gRPC GetManifest is unimplemented/empty, (2) an SDK helper + options to embed and serve a canonical manifest via gRPC, and (3) stripping engine-internal _-prefixed config keys (e.g. _config_dir) before STRICT_PROTO typed config encoding.

Changes:

  • Thread the manager-loaded *plugin.PluginManifest into NewExternalPluginAdapter and use it as the authoritative fallback when gRPC manifest is Unimplemented or has empty Version.
  • Add sdk.EmbedManifest/sdk.MustEmbedManifest and sdk.WithManifestProvider (plus IaC bridge support via IaCServeOptions.ManifestProvider) so plugins can compile-time embed plugin.json and serve it via GetManifest.
  • Strip _-prefixed internal keys before mapToTypedAny to prevent STRICT_PROTO protojson decode failures while preserving the legacy *structpb.Struct path.

Reviewed changes

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

Show a summary per file
File Description
plugin/external/sdk/serve.go Adds ServeOption and WithManifestProvider; makes Serve variadic to apply options.
plugin/external/sdk/serve_full.go Threads ServeOption through ServePluginFull and forwards to Serve.
plugin/external/sdk/manifest.go Adds EmbedManifest/MustEmbedManifest to parse+validate embedded plugin.json into canonical *plugin.PluginManifest.
plugin/external/sdk/manifest_test.go Unit tests for EmbedManifest and MustEmbedManifest (happy path + validation/error cases).
plugin/external/sdk/iacserver.go Threads IaCServeOptions.ManifestProvider into the IaC PluginService bridge and adds bridge GetManifest.
plugin/external/sdk/iacserver_internal_test.go Internal-package tests for IaC bridge GetManifest behavior.
plugin/external/sdk/grpc_server.go Adds diskManifest override and makes GetManifest prefer it over provider.Manifest().
plugin/external/sdk/grpc_server_test.go Tests manifest precedence (disk override vs provider fallback).
plugin/external/manager.go Passes the manager-loaded manifest into the adapter constructor.
plugin/external/integration_test.go In-process e2e test ensuring manager-loaded disk manifest is used when gRPC GetManifest is unimplemented.
plugin/external/convert.go Adds stripInternalKeys helper to remove _-prefixed internal keys from typed-encode input.
plugin/external/convert_test.go Unit tests for stripInternalKeys + copy-on-clean behavior.
plugin/external/adapter.go Adds manifestFromDisk, updates adapter constructor signature/behavior, and strips internal keys before STRICT_PROTO typed encoding.
plugin/external/adapter_test.go Updates constructor call sites and adds regression tests for disk-manifest fallback/overlay and _config_dir stripping.
cmd/wfctl/plugin_conformance.go Updates conformance path to call new adapter signature (passing nil disk manifest).
docs/plans/2026-05-12-strict-contracts-ergonomics.md.scope-lock Adds scope-lock hash artifact.
docs/plans/2026-05-12-strict-contracts-ergonomics.md Adds implementation plan documenting the fixes, tests, and rollout steps.
docs/plans/2026-05-12-strict-contracts-ergonomics-design.md Adds the design document motivating/justifying the three fixes.
docs/audit/2026-05-12-v0.51.3-smoke-transcript.txt Adds runtime-launch-validation transcript and local verification notes.
docs/audit/2026-05-12-underscore-prefix-audit.md Adds audit showing no _-prefixed proto fields in scoped repos.
decisions/0031-strict-contracts-ergonomics.md Adds ADR capturing the rationale/decision and consequences.

Comment thread docs/plans/2026-05-12-strict-contracts-ergonomics.md Outdated
Comment thread plugin/external/sdk/iacserver_internal_test.go
@codecov

codecov Bot commented May 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.35632% with 11 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
plugin/external/sdk/serve.go 0.00% 6 Missing ⚠️
plugin/external/sdk/serve_full.go 0.00% 2 Missing ⚠️
plugin/external/manager.go 0.00% 1 Missing ⚠️
plugin/external/sdk/iacserver.go 95.83% 1 Missing ⚠️
plugin/external/sdk/manifest.go 92.85% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@github-actions

github-actions Bot commented May 12, 2026

Copy link
Copy Markdown

⏱ 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:307109: parsing iteration count: invalid syntax
baseline-bench.txt:645057: parsing iteration count: invalid syntax
baseline-bench.txt:1170946: parsing iteration count: invalid syntax
baseline-bench.txt:1502678: parsing iteration count: invalid syntax
baseline-bench.txt:1834041: parsing iteration count: invalid syntax
benchmark-results.txt:262: parsing iteration count: invalid syntax
benchmark-results.txt:315809: parsing iteration count: invalid syntax
benchmark-results.txt:588312: parsing iteration count: invalid syntax
benchmark-results.txt:870100: parsing iteration count: invalid syntax
benchmark-results.txt:1188290: parsing iteration count: invalid syntax
benchmark-results.txt:1488147: parsing iteration count: invalid syntax
goos: linux
goarch: amd64
pkg: github.com/GoCodeAlone/workflow/dynamic
cpu: AMD EPYC 9V74 80-Core Processor                
                            │ baseline-bench.txt │        benchmark-results.txt        │
                            │       sec/op       │    sec/op      vs base              │
InterpreterCreation-4              3.004m ± 200%   3.412m ± 171%       ~ (p=0.485 n=6)
ComponentLoad-4                    3.467m ±  13%   3.487m ±   1%       ~ (p=0.180 n=6)
ComponentExecute-4                 1.836µ ±   1%   1.840µ ±   1%       ~ (p=0.383 n=6)
PoolContention/workers-1-4         1.010µ ±   1%   1.019µ ±   1%       ~ (p=0.052 n=6)
PoolContention/workers-2-4         1.012µ ±   8%   1.021µ ±   2%       ~ (p=0.331 n=6)
PoolContention/workers-4-4         1.011µ ±   1%   1.022µ ±   2%       ~ (p=0.212 n=6)
PoolContention/workers-8-4         1.022µ ±   2%   1.015µ ±   1%       ~ (p=0.413 n=6)
PoolContention/workers-16-4        1.024µ ±   2%   1.022µ ±   1%       ~ (p=0.331 n=6)
ComponentLifecycle-4               3.540m ±   0%   3.536m ±   1%       ~ (p=0.699 n=6)
SourceValidation-4                 2.106µ ±   1%   2.107µ ±   3%       ~ (p=0.665 n=6)
RegistryConcurrent-4               778.6n ±   4%   751.0n ±   3%       ~ (p=0.093 n=6)
LoaderLoadFromString-4             3.587m ±   2%   3.565m ±   2%       ~ (p=0.240 n=6)
geomean                            16.58µ          16.73µ         +0.94%

                            │ baseline-bench.txt │        benchmark-results.txt         │
                            │        B/op        │     B/op      vs base                │
InterpreterCreation-4               2.027Mi ± 0%   2.027Mi ± 0%       ~ (p=0.589 n=6)
ComponentLoad-4                     2.180Mi ± 0%   2.180Mi ± 0%       ~ (p=0.937 n=6)
ComponentExecute-4                  1.203Ki ± 0%   1.203Ki ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-1-4          1.203Ki ± 0%   1.203Ki ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-2-4          1.203Ki ± 0%   1.203Ki ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-4-4          1.203Ki ± 0%   1.203Ki ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-8-4          1.203Ki ± 0%   1.203Ki ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-16-4         1.203Ki ± 0%   1.203Ki ± 0%       ~ (p=1.000 n=6) ¹
ComponentLifecycle-4                2.183Mi ± 0%   2.183Mi ± 0%       ~ (p=0.071 n=6)
SourceValidation-4                  1.984Ki ± 0%   1.984Ki ± 0%       ~ (p=1.000 n=6) ¹
RegistryConcurrent-4                1.133Ki ± 0%   1.133Ki ± 0%       ~ (p=1.000 n=6) ¹
LoaderLoadFromString-4              2.182Mi ± 0%   2.182Mi ± 0%       ~ (p=0.333 n=6)
geomean                             15.25Ki        15.25Ki       +0.00%
¹ all samples are equal

                            │ baseline-bench.txt │        benchmark-results.txt        │
                            │     allocs/op      │  allocs/op   vs base                │
InterpreterCreation-4                15.68k ± 0%   15.68k ± 0%       ~ (p=1.000 n=6) ¹
ComponentLoad-4                      18.02k ± 0%   18.02k ± 0%       ~ (p=1.000 n=6)
ComponentExecute-4                    25.00 ± 0%    25.00 ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-1-4            25.00 ± 0%    25.00 ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-2-4            25.00 ± 0%    25.00 ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-4-4            25.00 ± 0%    25.00 ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-8-4            25.00 ± 0%    25.00 ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-16-4           25.00 ± 0%    25.00 ± 0%       ~ (p=1.000 n=6) ¹
ComponentLifecycle-4                 18.07k ± 0%   18.07k ± 0%       ~ (p=1.000 n=6) ¹
SourceValidation-4                    32.00 ± 0%    32.00 ± 0%       ~ (p=1.000 n=6) ¹
RegistryConcurrent-4                  2.000 ± 0%    2.000 ± 0%       ~ (p=1.000 n=6) ¹
LoaderLoadFromString-4               18.06k ± 0%   18.06k ± 0%       ~ (p=1.000 n=6) ¹
geomean                               183.3         183.3       +0.00%
¹ all samples are equal

pkg: github.com/GoCodeAlone/workflow/middleware
                                  │ baseline-bench.txt │       benchmark-results.txt       │
                                  │       sec/op       │   sec/op     vs base              │
CircuitBreakerDetection-4                 306.7n ± 10%   303.1n ± 3%       ~ (p=0.290 n=6)
CircuitBreakerExecution_Success-4         22.68n ±  0%   22.67n ± 0%       ~ (p=0.840 n=6)
CircuitBreakerExecution_Failure-4         71.16n ±  0%   71.19n ± 0%       ~ (p=0.223 n=6)
geomean                                   79.10n         78.79n       -0.39%

                                  │ baseline-bench.txt │       benchmark-results.txt        │
                                  │        B/op        │    B/op     vs base                │
CircuitBreakerDetection-4                 144.0 ± 0%     144.0 ± 0%       ~ (p=1.000 n=6) ¹
CircuitBreakerExecution_Success-4         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
CircuitBreakerExecution_Failure-4         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
geomean                                              ²               +0.00%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                  │ baseline-bench.txt │       benchmark-results.txt        │
                                  │     allocs/op      │ allocs/op   vs base                │
CircuitBreakerDetection-4                 1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=6) ¹
CircuitBreakerExecution_Success-4         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
CircuitBreakerExecution_Failure-4         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
geomean                                              ²               +0.00%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/module
                                 │ baseline-bench.txt │       benchmark-results.txt        │
                                 │       sec/op       │    sec/op     vs base              │
JQTransform_Simple-4                     857.1n ± 29%   828.9n ± 27%       ~ (p=0.132 n=6)
JQTransform_ObjectConstruction-4         1.433µ ±  2%   1.393µ ±  1%  -2.83% (p=0.002 n=6)
JQTransform_ArraySelect-4                3.475µ ±  1%   3.408µ ±  0%  -1.91% (p=0.002 n=6)
JQTransform_Complex-4                    42.17µ ±  1%   41.74µ ±  0%  -1.02% (p=0.002 n=6)
JQTransform_Throughput-4                 1.781µ ±  2%   1.709µ ±  0%  -4.07% (p=0.002 n=6)
SSEPublishDelivery-4                     64.40n ±  1%   64.73n ±  2%       ~ (p=0.061 n=6)
geomean                                  1.656µ         1.621µ        -2.11%

                                 │ baseline-bench.txt │        benchmark-results.txt         │
                                 │        B/op        │     B/op      vs base                │
JQTransform_Simple-4                   1.273Ki ± 0%     1.273Ki ± 0%       ~ (p=1.000 n=6) ¹
JQTransform_ObjectConstruction-4       1.773Ki ± 0%     1.773Ki ± 0%       ~ (p=1.000 n=6) ¹
JQTransform_ArraySelect-4              2.625Ki ± 0%     2.625Ki ± 0%       ~ (p=1.000 n=6) ¹
JQTransform_Complex-4                  16.22Ki ± 0%     16.22Ki ± 0%       ~ (p=1.000 n=6) ¹
JQTransform_Throughput-4               1.984Ki ± 0%     1.984Ki ± 0%       ~ (p=1.000 n=6) ¹
SSEPublishDelivery-4                     0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=6) ¹
geomean                                             ²                 +0.00%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                 │ baseline-bench.txt │       benchmark-results.txt        │
                                 │     allocs/op      │ allocs/op   vs base                │
JQTransform_Simple-4                     10.00 ± 0%     10.00 ± 0%       ~ (p=1.000 n=6) ¹
JQTransform_ObjectConstruction-4         15.00 ± 0%     15.00 ± 0%       ~ (p=1.000 n=6) ¹
JQTransform_ArraySelect-4                30.00 ± 0%     30.00 ± 0%       ~ (p=1.000 n=6) ¹
JQTransform_Complex-4                    324.0 ± 0%     324.0 ± 0%       ~ (p=1.000 n=6) ¹
JQTransform_Throughput-4                 17.00 ± 0%     17.00 ± 0%       ~ (p=1.000 n=6) ¹
SSEPublishDelivery-4                     0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
geomean                                             ²               +0.00%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/schema
                                    │ baseline-bench.txt │       benchmark-results.txt        │
                                    │       sec/op       │    sec/op     vs base              │
SchemaValidation_Simple-4                   1.091µ ±  3%   1.104µ ±  2%       ~ (p=0.418 n=6)
SchemaValidation_AllFields-4                1.635µ ± 19%   1.670µ ± 19%       ~ (p=0.180 n=6)
SchemaValidation_FormatValidation-4         1.585µ ±  2%   1.601µ ±  3%       ~ (p=0.232 n=6)
SchemaValidation_ManySchemas-4              1.613µ ±  2%   1.599µ ±  2%       ~ (p=0.589 n=6)
geomean                                     1.461µ         1.474µ        +0.86%

                                    │ baseline-bench.txt │       benchmark-results.txt        │
                                    │        B/op        │    B/op     vs base                │
SchemaValidation_Simple-4                   0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SchemaValidation_AllFields-4                0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SchemaValidation_FormatValidation-4         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SchemaValidation_ManySchemas-4              0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
geomean                                                ²               +0.00%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                    │ baseline-bench.txt │       benchmark-results.txt        │
                                    │     allocs/op      │ allocs/op   vs base                │
SchemaValidation_Simple-4                   0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SchemaValidation_AllFields-4                0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SchemaValidation_FormatValidation-4         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SchemaValidation_ManySchemas-4              0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
geomean                                                ²               +0.00%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/store
                                   │ baseline-bench.txt │        benchmark-results.txt        │
                                   │       sec/op       │    sec/op     vs base               │
EventStoreAppend_InMemory-4                1.056µ ±  8%   1.043µ ± 26%        ~ (p=0.589 n=6)
EventStoreAppend_SQLite-4                  1.045m ±  5%   1.087m ±  6%        ~ (p=0.310 n=6)
GetTimeline_InMemory/events-10-4           12.92µ ±  2%   12.37µ ±  2%   -4.20% (p=0.004 n=6)
GetTimeline_InMemory/events-50-4           73.28µ ±  1%   69.68µ ± 21%   -4.91% (p=0.002 n=6)
GetTimeline_InMemory/events-100-4          148.5µ ±  3%   110.0µ ±  2%  -25.93% (p=0.002 n=6)
GetTimeline_InMemory/events-500-4          736.1µ ± 22%   560.4µ ±  0%  -23.87% (p=0.002 n=6)
GetTimeline_InMemory/events-1000-4         1.159m ±  1%   1.138m ±  0%   -1.82% (p=0.002 n=6)
GetTimeline_SQLite/events-10-4             86.22µ ±  1%   84.09µ ±  1%   -2.47% (p=0.002 n=6)
GetTimeline_SQLite/events-50-4             226.4µ ±  1%   219.6µ ±  1%   -3.00% (p=0.002 n=6)
GetTimeline_SQLite/events-100-4            390.7µ ±  2%   382.1µ ±  1%   -2.20% (p=0.002 n=6)
GetTimeline_SQLite/events-500-4            1.698m ±  1%   1.660m ±  1%   -2.26% (p=0.002 n=6)
GetTimeline_SQLite/events-1000-4           3.309m ±  1%   3.233m ±  1%   -2.30% (p=0.002 n=6)
geomean                                    205.5µ         192.5µ         -6.31%

                                   │ baseline-bench.txt │         benchmark-results.txt         │
                                   │        B/op        │     B/op       vs base                │
EventStoreAppend_InMemory-4                  779.5 ± 6%     765.5 ± 11%       ~ (p=0.831 n=6)
EventStoreAppend_SQLite-4                  1.985Ki ± 1%   1.987Ki ±  1%       ~ (p=0.617 n=6)
GetTimeline_InMemory/events-10-4           7.953Ki ± 0%   7.953Ki ±  0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-50-4           46.62Ki ± 0%   46.62Ki ±  0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-100-4          94.48Ki ± 0%   94.48Ki ±  0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-500-4          472.8Ki ± 0%   472.8Ki ±  0%       ~ (p=0.152 n=6)
GetTimeline_InMemory/events-1000-4         944.3Ki ± 0%   944.3Ki ±  0%  +0.00% (p=0.041 n=6)
GetTimeline_SQLite/events-10-4             16.74Ki ± 0%   16.74Ki ±  0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-50-4             87.14Ki ± 0%   87.14Ki ±  0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-100-4            175.4Ki ± 0%   175.4Ki ±  0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-500-4            846.1Ki ± 0%   846.1Ki ±  0%       ~ (p=1.000 n=6)
GetTimeline_SQLite/events-1000-4           1.639Mi ± 0%   1.639Mi ±  0%       ~ (p=0.177 n=6)
geomean                                    67.27Ki        67.18Ki        -0.14%
¹ all samples are equal

                                   │ baseline-bench.txt │        benchmark-results.txt        │
                                   │     allocs/op      │  allocs/op   vs base                │
EventStoreAppend_InMemory-4                  7.000 ± 0%    7.000 ± 0%       ~ (p=1.000 n=6) ¹
EventStoreAppend_SQLite-4                    53.00 ± 0%    53.00 ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-10-4             125.0 ± 0%    125.0 ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-50-4             653.0 ± 0%    653.0 ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-100-4           1.306k ± 0%   1.306k ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-500-4           6.514k ± 0%   6.514k ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-1000-4          13.02k ± 0%   13.02k ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-10-4               382.0 ± 0%    382.0 ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-50-4              1.852k ± 0%   1.852k ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-100-4             3.681k ± 0%   3.681k ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-500-4             18.54k ± 0%   18.54k ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-1000-4            37.29k ± 0%   37.29k ± 0%       ~ (p=1.000 n=6) ¹
geomean                                     1.162k        1.162k       +0.00%
¹ all samples are equal

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

- Plan tech-stack line: Go 1.23 → 1.26.0 (matches go.mod)
- TestIaCBridgeGetManifestUsesProvider: use Validate-passing
  manifest fixture and assert Name/Version/Author/Description
  so any of the four mapped fields regressing fails the test
@intel352 intel352 requested a review from Copilot May 12, 2026 12:27
@intel352 intel352 merged commit 15d34e4 into main May 12, 2026
26 checks passed
@intel352 intel352 deleted the fix/strict-contracts-ergonomics-v0.51.3 branch May 12, 2026 12:31

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

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

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