Skip to content

fix(wfctl): plugin CLI binary path uses dir name twice (matches ensurePluginBinary)#613

Merged
intel352 merged 1 commit into
mainfrom
fix/cli-registry-binary-dirname
May 10, 2026
Merged

fix(wfctl): plugin CLI binary path uses dir name twice (matches ensurePluginBinary)#613
intel352 merged 1 commit into
mainfrom
fix/cli-registry-binary-dirname

Conversation

@intel352

Copy link
Copy Markdown
Contributor

Summary

Second pass on the dispatch binary-path bug. workflow#595 fixed the "manifest.Name twice" failure by joining `dirName + manifest.Name`, but that breaks for the actual install convention:

`ensurePluginBinary(destDir, pluginName)` RENAMES the largest executable in `destDir` to match the (short) plugin name. So the binary post-install lives at `destDir/{shortName}/{shortName}`, not `destDir/{shortName}/{manifestName}`.

Real-world impact

buymywishlist#264 retrigger:

```
error: plugin workflow-plugin-payments command payments:
fork/exec /home/runner/work/buymywishlist/buymywishlist/data/plugins/payments/workflow-plugin-payments:
no such file or directory

$ ls data/plugins/payments
-rwxr-xr-x payments ← actual binary post-rename
plugin.json
```

Fix

`BuildCLIRegistry` now joins `dirName` twice for the binary path. The `manifest.Name` still flows into `PluginName` for log/audit purposes (so error messages like `"plugin workflow-plugin-payments command payments: …"` remain informative), but the executable lookup uses the install convention.

Test fixture `writeCLIPluginNamed` updated to match: stub binary written at `dirName`, not `manifestName`, modeling the post-rename state.

Tests

`TestPluginCLIRegistry_DirVsManifestNameMismatch` rewrites — pins both sides:

  • dir name = binary file name = the install dir name
  • manifest name flows into PluginName

`TestPluginCLIRegistry_EmptyManifestNameUsesDirName` already correct (dirName=anonymous, binary=anonymous).

Verification

  • `GOWORK=off go build ./...` clean
  • `GOWORK=off go vet ./cmd/wfctl/` clean
  • `GOWORK=off go test ./cmd/wfctl/ -count=1 -run "TestPluginCLIRegistry|TestStaticCommand"` green
  • gofmt -l clean

🤖 Generated with Claude Code

…ePluginBinary)

Second pass on the dispatch binary-path bug. workflow#595 fixed the
"manifest.Name twice" failure by joining dirName + manifest.Name, but
that breaks for the actual install convention:

  ensurePluginBinary(destDir, pluginName) RENAMES the largest
  executable in destDir to match `pluginName` (the SHORT install
  name, e.g. "payments"). So the binary post-install lives at
  destDir/{shortName}/{shortName}, not destDir/{shortName}/{manifestName}.

Real-world impact (buymywishlist#264 retrigger):

  error: plugin workflow-plugin-payments command payments:
    fork/exec /home/runner/work/.../data/plugins/payments/workflow-plugin-payments:
    no such file or directory

  $ ls data/plugins/payments
  -rwxr-xr-x payments    ← actual binary post-rename
  plugin.json

Fix: BuildCLIRegistry joins dirName twice for the binary path. The
manifest.Name still flows into PluginName for log/audit purposes (so
"plugin workflow-plugin-payments command payments: …" error messages
remain informative), but the executable lookup uses the install
convention.

Test fixture writeCLIPluginNamed updated to match: stub binary written
at dirName, not manifestName, modeling the post-rename state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@intel352 intel352 requested review from Copilot and removed request for Copilot May 10, 2026 08:52
@github-actions

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:330614: parsing iteration count: invalid syntax
baseline-bench.txt:652176: parsing iteration count: invalid syntax
baseline-bench.txt:932278: parsing iteration count: invalid syntax
baseline-bench.txt:1257632: parsing iteration count: invalid syntax
baseline-bench.txt:1588017: parsing iteration count: invalid syntax
benchmark-results.txt:262: parsing iteration count: invalid syntax
benchmark-results.txt:342578: parsing iteration count: invalid syntax
benchmark-results.txt:605994: parsing iteration count: invalid syntax
benchmark-results.txt:888451: parsing iteration count: invalid syntax
benchmark-results.txt:1370747: parsing iteration count: invalid syntax
benchmark-results.txt:1688679: parsing iteration count: invalid syntax
goos: linux
goarch: amd64
pkg: github.com/GoCodeAlone/workflow/dynamic
cpu: AMD EPYC 7763 64-Core Processor                
                            │ benchmark-results.txt │
                            │        sec/op         │
InterpreterCreation-4                 3.468m ± 198%
ComponentLoad-4                       3.603m ±   1%
ComponentExecute-4                    1.971µ ±   0%
PoolContention/workers-1-4            1.094µ ±   1%
PoolContention/workers-2-4            1.089µ ±   2%
PoolContention/workers-4-4            1.094µ ±   1%
PoolContention/workers-8-4            1.094µ ±   1%
PoolContention/workers-16-4           1.099µ ±   3%
ComponentLifecycle-4                  3.622m ±   1%
SourceValidation-4                    2.347µ ±   0%
RegistryConcurrent-4                  796.1n ±   2%
LoaderLoadFromString-4                3.654m ±   2%
geomean                               17.71µ

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

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

cpu: AMD EPYC 9V74 80-Core Processor                
                            │ baseline-bench.txt │
                            │       sec/op       │
InterpreterCreation-4              3.015m ± 224%
ComponentLoad-4                    3.504m ±  11%
ComponentExecute-4                 1.835µ ±   2%
PoolContention/workers-1-4         1.021µ ±   2%
PoolContention/workers-2-4         1.014µ ±   4%
PoolContention/workers-4-4         1.013µ ±   1%
PoolContention/workers-8-4         1.014µ ±   1%
PoolContention/workers-16-4        1.013µ ±   1%
ComponentLifecycle-4               3.523m ±   1%
SourceValidation-4                 2.085µ ±   1%
RegistryConcurrent-4               754.0n ±   2%
LoaderLoadFromString-4             3.562m ±   1%
geomean                            16.51µ

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

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

pkg: github.com/GoCodeAlone/workflow/middleware
cpu: AMD EPYC 7763 64-Core Processor                
                                  │ benchmark-results.txt │
                                  │        sec/op         │
CircuitBreakerDetection-4                     286.9n ± 2%
CircuitBreakerExecution_Success-4             21.54n ± 0%
CircuitBreakerExecution_Failure-4             66.06n ± 0%
geomean                                       74.18n

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

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

cpu: AMD EPYC 9V74 80-Core Processor                
                                  │ baseline-bench.txt │
                                  │       sec/op       │
CircuitBreakerDetection-4                  295.8n ± 2%
CircuitBreakerExecution_Success-4          22.69n ± 0%
CircuitBreakerExecution_Failure-4          70.95n ± 0%
geomean                                    78.09n

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

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

pkg: github.com/GoCodeAlone/workflow/module
cpu: AMD EPYC 7763 64-Core Processor                
                                 │ benchmark-results.txt │
                                 │        sec/op         │
JQTransform_Simple-4                        1.007µ ± 14%
JQTransform_ObjectConstruction-4            1.470µ ±  1%
JQTransform_ArraySelect-4                   3.372µ ±  2%
JQTransform_Complex-4                       38.19µ ±  2%
JQTransform_Throughput-4                    1.794µ ±  1%
SSEPublishDelivery-4                        64.14n ±  2%
geomean                                     1.673µ

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

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

cpu: AMD EPYC 9V74 80-Core Processor                
                                 │ baseline-bench.txt │
                                 │       sec/op       │
JQTransform_Simple-4                     826.0n ± 29%
JQTransform_ObjectConstruction-4         1.407µ ±  1%
JQTransform_ArraySelect-4                3.405µ ±  1%
JQTransform_Complex-4                    41.67µ ±  1%
JQTransform_Throughput-4                 1.713µ ±  0%
SSEPublishDelivery-4                     64.65n ±  3%
geomean                                  1.623µ

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

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

pkg: github.com/GoCodeAlone/workflow/schema
cpu: AMD EPYC 7763 64-Core Processor                
                                    │ benchmark-results.txt │
                                    │        sec/op         │
SchemaValidation_Simple-4                      1.133µ ± 22%
SchemaValidation_AllFields-4                   1.653µ ±  1%
SchemaValidation_FormatValidation-4            1.584µ ±  2%
SchemaValidation_ManySchemas-4                 1.805µ ±  3%
geomean                                        1.521µ

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

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

cpu: AMD EPYC 9V74 80-Core Processor                
                                    │ baseline-bench.txt │
                                    │       sec/op       │
SchemaValidation_Simple-4                    1.114µ ± 5%
SchemaValidation_AllFields-4                 1.647µ ± 3%
SchemaValidation_FormatValidation-4          1.613µ ± 4%
SchemaValidation_ManySchemas-4               1.588µ ± 1%
geomean                                      1.472µ

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

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

pkg: github.com/GoCodeAlone/workflow/store
cpu: AMD EPYC 7763 64-Core Processor                
                                   │ benchmark-results.txt │
                                   │        sec/op         │
EventStoreAppend_InMemory-4                   1.149µ ± 18%
EventStoreAppend_SQLite-4                     1.388m ±  3%
GetTimeline_InMemory/events-10-4              13.79µ ±  4%
GetTimeline_InMemory/events-50-4              77.68µ ±  2%
GetTimeline_InMemory/events-100-4             153.5µ ± 18%
GetTimeline_InMemory/events-500-4             638.7µ ±  1%
GetTimeline_InMemory/events-1000-4            1.298m ±  1%
GetTimeline_SQLite/events-10-4                107.0µ ±  2%
GetTimeline_SQLite/events-50-4                249.6µ ±  0%
GetTimeline_SQLite/events-100-4               424.0µ ±  1%
GetTimeline_SQLite/events-500-4               1.801m ±  1%
GetTimeline_SQLite/events-1000-4              3.500m ±  0%
geomean                                       223.5µ

                                   │ benchmark-results.txt │
                                   │         B/op          │
EventStoreAppend_InMemory-4                     783.5 ± 5%
EventStoreAppend_SQLite-4                     1.983Ki ± 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.30Ki

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

cpu: AMD EPYC 9V74 80-Core Processor                
                                   │ baseline-bench.txt │
                                   │       sec/op       │
EventStoreAppend_InMemory-4                1.017µ ± 40%
EventStoreAppend_SQLite-4                  1.101m ±  4%
GetTimeline_InMemory/events-10-4           12.68µ ±  2%
GetTimeline_InMemory/events-50-4           73.00µ ±  2%
GetTimeline_InMemory/events-100-4          113.8µ ±  1%
GetTimeline_InMemory/events-500-4          580.1µ ±  1%
GetTimeline_InMemory/events-1000-4         1.186m ±  2%
GetTimeline_SQLite/events-10-4             85.15µ ±  1%
GetTimeline_SQLite/events-50-4             225.7µ ±  1%
GetTimeline_SQLite/events-100-4            394.5µ ±  1%
GetTimeline_SQLite/events-500-4            1.724m ±  1%
GetTimeline_SQLite/events-1000-4           3.330m ±  0%
geomean                                    197.6µ

                                   │ baseline-bench.txt │
                                   │        B/op        │
EventStoreAppend_InMemory-4                 764.5 ± 13%
EventStoreAppend_SQLite-4                 1.983Ki ±  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.16Ki

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

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

@intel352 intel352 merged commit 7fc4778 into main May 10, 2026
18 checks passed
@intel352 intel352 deleted the fix/cli-registry-binary-dirname branch May 10, 2026 09:08
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.

1 participant