Skip to content

feat(interfaces): IsErrResourceNotFound helper + struct Is method + 11 call-site migrations#788

Merged
intel352 merged 3 commits into
mainfrom
feat/iac-not-found-sentinel-translation-2026-05-27
May 27, 2026
Merged

feat(interfaces): IsErrResourceNotFound helper + struct Is method + 11 call-site migrations#788
intel352 merged 3 commits into
mainfrom
feat/iac-not-found-sentinel-translation-2026-05-27

Conversation

@intel352
Copy link
Copy Markdown
Contributor

Plugs gRPC-boundary gap where errors.Is(err, ErrResourceNotFound) fails on cross-wire stringified errors. Follows ErrImageNotInRegistry load-bearing-string precedent. No SDK changes.

Changes

  • platform.ResourceNotFoundError.Is(target) — makes errors.Is(err, interfaces.ErrResourceNotFound) catch the struct natively
  • interfaces.IsErrResourceNotFound(err) — helper covering sentinel + struct + gRPC-stringified (via strings.Contains fallback on the load-bearing message string)
  • 11 call sites migrated to the helper (1 helper-body collapse + 10 call-site replacements)
  • Stability test pins ErrResourceNotFound message string
  • Unit tests cover sentinel, wrapped, stringified, unrelated-NotFound, empty cases

Call sites migrated

  • cmd/wfctl/infra_apply.go: isIaCNotFound body collapsed to delegation (1) + delete-error paths (2)
  • cmd/wfctl/deploy_providers.go: read + update error paths during deploy (2)
  • platform/differ.go: classifyCreate cascade-retro gap (1)
  • iac/refreshoutputs/refresh.go: refresh-outputs not-found (1)
  • module/tenant_resolver.go: tenant lookup by slug + domain (2)
  • module/tenants.go: tenant fetch + update (2)

Note: deploy_providers.go:389 is a fmt.Errorf("%w: ...") WRAPPING site — not migrated per plan.

Design

docs/plans/2026-05-27-iac-not-found-sentinel-translation-design.md

Test plan

  • GOWORK=off go test ./platform/...TestResourceNotFoundError_IsErrResourceNotFound green
  • GOWORK=off go test ./interfaces/...TestErrResourceNotFound_MessageStringStable + TestIsErrResourceNotFound (6 cases) green
  • GOWORK=off go test ./... — all packages green
  • GOWORK=off golangci-lint run --new-from-rev=origin/main — 0 issues

🤖 Generated with Claude Code

@codecov
Copy link
Copy Markdown

codecov Bot commented May 27, 2026

Codecov Report

❌ Patch coverage is 78.94737% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
module/tenant_resolver.go 0.00% 2 Missing ⚠️
module/tenants.go 50.00% 0 Missing and 1 partial ⚠️
platform/differ.go 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@github-actions
Copy link
Copy Markdown

⏱ Benchmark Results

No significant performance regressions detected.

benchstat comparison (baseline → PR)
## benchstat: baseline → PR
baseline-bench.txt:288: parsing iteration count: invalid syntax
baseline-bench.txt:305761: parsing iteration count: invalid syntax
baseline-bench.txt:616349: parsing iteration count: invalid syntax
baseline-bench.txt:902223: parsing iteration count: invalid syntax
baseline-bench.txt:1198495: parsing iteration count: invalid syntax
baseline-bench.txt:1473368: parsing iteration count: invalid syntax
benchmark-results.txt:288: parsing iteration count: invalid syntax
benchmark-results.txt:310606: parsing iteration count: invalid syntax
benchmark-results.txt:611312: parsing iteration count: invalid syntax
benchmark-results.txt:1133475: parsing iteration count: invalid syntax
benchmark-results.txt:1449916: parsing iteration count: invalid syntax
benchmark-results.txt:1742534: 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 │       benchmark-results.txt        │
                            │       sec/op       │    sec/op     vs base              │
InterpreterCreation-4               6.984m ± 56%   8.950m ± 65%       ~ (p=0.699 n=6)
ComponentLoad-4                     3.579m ±  1%   3.678m ±  8%  +2.77% (p=0.002 n=6)
ComponentExecute-4                  1.938µ ±  1%   1.948µ ±  1%       ~ (p=0.286 n=6)
PoolContention/workers-1-4          1.083µ ±  1%   1.096µ ±  1%       ~ (p=0.078 n=6)
PoolContention/workers-2-4          1.077µ ±  0%   1.086µ ±  2%  +0.84% (p=0.045 n=6)
PoolContention/workers-4-4          1.082µ ±  2%   1.090µ ±  2%       ~ (p=0.675 n=6)
PoolContention/workers-8-4          1.084µ ±  1%   1.088µ ±  1%       ~ (p=0.372 n=6)
PoolContention/workers-16-4         1.091µ ±  2%   1.095µ ±  2%       ~ (p=0.310 n=6)
ComponentLifecycle-4                3.646m ±  1%   3.665m ±  1%       ~ (p=0.485 n=6)
SourceValidation-4                  2.357µ ±  1%   2.325µ ±  1%  -1.36% (p=0.013 n=6)
RegistryConcurrent-4                821.2n ±  1%   782.1n ±  4%  -4.77% (p=0.004 n=6)
LoaderLoadFromString-4              3.633m ±  1%   3.726m ±  2%  +2.56% (p=0.004 n=6)
geomean                             18.72µ         19.17µ        +2.40%

                            │ baseline-bench.txt │        benchmark-results.txt         │
                            │        B/op        │     B/op      vs base                │
InterpreterCreation-4               2.027Mi ± 0%   2.027Mi ± 0%       ~ (p=0.455 n=6)
ComponentLoad-4                     2.180Mi ± 0%   2.180Mi ± 0%       ~ (p=0.132 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.788 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.485 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                  289.2n ± 1%   295.0n ± 6%       ~ (p=0.394 n=6)
CircuitBreakerExecution_Success-4          21.57n ± 1%   21.46n ± 2%       ~ (p=0.361 n=6)
CircuitBreakerExecution_Failure-4          66.23n ± 0%   66.31n ± 0%       ~ (p=0.197 n=6)
geomean                                    74.48n        74.88n       +0.53%

                                  │ 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               │
IaCStateBackend_InProcess-4              317.8n ± 24%   310.3n ± 29%        ~ (p=0.225 n=6)
IaCStateBackend_GRPC-4                   9.549m ±  3%   9.619m ±  2%        ~ (p=0.937 n=6)
JQTransform_Simple-4                     671.5n ± 52%   668.7n ± 35%        ~ (p=1.000 n=6)
JQTransform_ObjectConstruction-4         1.717µ ±  2%   1.493µ ±  0%  -13.05% (p=0.002 n=6)
JQTransform_ArraySelect-4                3.780µ ±  2%   3.445µ ±  1%   -8.85% (p=0.002 n=6)
JQTransform_Complex-4                    42.50µ ±  1%   39.72µ ±  1%   -6.54% (p=0.002 n=6)
JQTransform_Throughput-4                 2.068µ ±  1%   1.853µ ±  4%  -10.40% (p=0.002 n=6)
SSEPublishDelivery-4                     68.20n ±  1%   70.53n ±  2%   +3.42% (p=0.002 n=6)
geomean                                  4.096µ         3.898µ         -4.84%

                                 │ baseline-bench.txt │         benchmark-results.txt         │
                                 │        B/op        │     B/op       vs base                │
IaCStateBackend_InProcess-4             416.0 ±  0%       416.0 ±  0%       ~ (p=1.000 n=6) ¹
IaCStateBackend_GRPC-4                5.737Mi ± 13%     5.798Mi ± 10%       ~ (p=0.818 n=6)
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.31Ki ±  0%     16.31Ki ±  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.13%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                 │ baseline-bench.txt │        benchmark-results.txt        │
                                 │     allocs/op      │  allocs/op   vs base                │
IaCStateBackend_InProcess-4              2.000 ± 0%      2.000 ± 0%       ~ (p=1.000 n=6) ¹
IaCStateBackend_GRPC-4                  6.836k ± 0%     6.838k ± 1%       ~ (p=0.937 n=6)
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                    328.0 ± 0%      328.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.141µ ± 16%   1.113µ ± 17%       ~ (p=0.162 n=6)
SchemaValidation_AllFields-4                1.676µ ±  2%   1.671µ ±  1%       ~ (p=0.738 n=6)
SchemaValidation_FormatValidation-4         1.592µ ±  3%   1.593µ ±  2%       ~ (p=0.848 n=6)
SchemaValidation_ManySchemas-4              1.828µ ±  3%   1.801µ ±  2%  -1.50% (p=0.041 n=6)
geomean                                     1.536µ         1.520µ        -1.07%

                                    │ 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.241µ ± 13%   1.282µ ± 18%        ~ (p=0.288 n=6)
EventStoreAppend_SQLite-4                  1.571m ±  5%   1.332m ±  2%  -15.18% (p=0.002 n=6)
GetTimeline_InMemory/events-10-4           14.45µ ±  2%   14.18µ ±  4%        ~ (p=0.310 n=6)
GetTimeline_InMemory/events-50-4           73.18µ ± 14%   78.65µ ±  3%        ~ (p=1.000 n=6)
GetTimeline_InMemory/events-100-4          130.5µ ±  0%   153.3µ ± 16%        ~ (p=0.394 n=6)
GetTimeline_InMemory/events-500-4          667.1µ ±  4%   656.4µ ±  1%   -1.61% (p=0.009 n=6)
GetTimeline_InMemory/events-1000-4         1.367m ±  1%   1.350m ±  1%   -1.24% (p=0.015 n=6)
GetTimeline_SQLite/events-10-4             112.5µ ±  1%   107.9µ ±  1%   -4.10% (p=0.002 n=6)
GetTimeline_SQLite/events-50-4             267.0µ ±  2%   255.2µ ±  1%   -4.42% (p=0.002 n=6)
GetTimeline_SQLite/events-100-4            449.3µ ±  0%   432.3µ ±  2%   -3.80% (p=0.002 n=6)
GetTimeline_SQLite/events-500-4            1.910m ±  1%   1.844m ±  1%   -3.46% (p=0.002 n=6)
GetTimeline_SQLite/events-1000-4           3.716m ±  1%   3.591m ±  1%   -3.37% (p=0.002 n=6)
geomean                                    231.4µ         228.6µ         -1.18%

                                   │ baseline-bench.txt │         benchmark-results.txt         │
                                   │        B/op        │     B/op       vs base                │
EventStoreAppend_InMemory-4                  796.5 ± 8%     852.0 ± 13%       ~ (p=0.221 n=6)
EventStoreAppend_SQLite-4                  1.986Ki ± 2%   1.987Ki ±  1%       ~ (p=0.768 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.061 n=6)
GetTimeline_InMemory/events-1000-4         944.3Ki ± 0%   944.3Ki ±  0%       ~ (p=1.000 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.448 n=6)
geomean                                    67.40Ki        67.78Ki        +0.56%
¹ 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.

@intel352 intel352 merged commit e8a53e6 into main May 27, 2026
28 checks passed
@intel352 intel352 deleted the feat/iac-not-found-sentinel-translation-2026-05-27 branch May 27, 2026 05:44
intel352 added a commit that referenced this pull request May 27, 2026
…retrospective (#789)

PR #788 merged 2026-05-27. 3 design cycles + 2 plan cycles. All findings prescient or resolved upfront. Skipped brainstorming was the one process miss; identified as Plugin-level follow-up addressable via self-challenge prompt update.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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