Skip to content

test(codemod): pin direct-assignment accumulator pattern for AssertDiffSetsNeedsReplaceForForceNew#564

Merged
intel352 merged 3 commits into
mainfrom
copilot/tighten-analyzer-local-accumulator-pattern
May 6, 2026
Merged

test(codemod): pin direct-assignment accumulator pattern for AssertDiffSetsNeedsReplaceForForceNew#564
intel352 merged 3 commits into
mainfrom
copilot/tighten-analyzer-local-accumulator-pattern

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 6, 2026

AssertDiffSetsNeedsReplaceForForceNew was producing false-positives when a driver used the local-accumulator pattern with a direct selector assignment (r.NeedsReplace = needsReplace) rather than assigning true inline. The struct-literal variant (&DiffResult{NeedsReplace: needsReplace}) was already fixed in b0813a2 by adding *ast.KeyValueExpr handling to bodyAssignsField.

Changes

  • New regression test TestAssertDiffSetsNeedsReplaceForForceNew_DirectAccumulatorAssignIsClean — explicitly pins the direct-assignment accumulator form described in the issue:
needsReplace := false
for _, c := range r.Changes {
    if c.ForceNew {
        needsReplace = true
    }
}
r.NeedsReplace = needsReplace  // *ast.AssignStmt, non-false RHS

This form is handled by the existing *ast.AssignStmt branch in bodyAssignsField but had no dedicated test. Adding it prevents a future refactor from silently regressing either accumulator variant without a failing test.

Copilot AI requested review from Copilot and removed request for Copilot May 6, 2026 04:43
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 6, 2026

⏱ Benchmark Results

No significant performance regressions detected.

benchstat comparison (baseline → PR)
## benchstat: baseline → PR
baseline-bench.txt:260: parsing iteration count: invalid syntax
baseline-bench.txt:313335: parsing iteration count: invalid syntax
baseline-bench.txt:563008: parsing iteration count: invalid syntax
baseline-bench.txt:878837: parsing iteration count: invalid syntax
baseline-bench.txt:1176606: parsing iteration count: invalid syntax
baseline-bench.txt:1459183: parsing iteration count: invalid syntax
benchmark-results.txt:260: parsing iteration count: invalid syntax
benchmark-results.txt:314547: parsing iteration count: invalid syntax
benchmark-results.txt:593755: parsing iteration count: invalid syntax
benchmark-results.txt:828023: parsing iteration count: invalid syntax
benchmark-results.txt:1135713: parsing iteration count: invalid syntax
benchmark-results.txt:1458913: 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              3.673m ± 175%   4.675m ± 141%       ~ (p=0.589 n=6)
ComponentLoad-4                    3.554m ±   1%   3.675m ±   3%  +3.41% (p=0.002 n=6)
ComponentExecute-4                 1.931µ ±   1%   1.980µ ±   1%  +2.56% (p=0.002 n=6)
PoolContention/workers-1-4         1.078µ ±   1%   1.119µ ±   1%  +3.76% (p=0.002 n=6)
PoolContention/workers-2-4         1.083µ ±   3%   1.111µ ±   3%  +2.54% (p=0.017 n=6)
PoolContention/workers-4-4         1.085µ ±   1%   1.119µ ±   1%  +3.18% (p=0.002 n=6)
PoolContention/workers-8-4         1.082µ ±   1%   1.129µ ±   4%  +4.39% (p=0.002 n=6)
PoolContention/workers-16-4        1.090µ ±   4%   1.140µ ±   4%  +4.59% (p=0.009 n=6)
ComponentLifecycle-4               3.573m ±   2%   3.811m ±   1%  +6.66% (p=0.002 n=6)
SourceValidation-4                 2.234µ ±   1%   2.442µ ±   1%  +9.29% (p=0.002 n=6)
RegistryConcurrent-4               811.1n ±   2%   877.1n ±   4%  +8.13% (p=0.002 n=6)
LoaderLoadFromString-4             3.617m ±   2%   3.942m ±   2%  +8.98% (p=0.002 n=6)
geomean                            17.60µ          18.81µ         +6.88%

                            │ baseline-bench.txt │        benchmark-results.txt         │
                            │        B/op        │     B/op      vs base                │
InterpreterCreation-4               2.027Mi ± 0%   2.027Mi ± 0%       ~ (p=0.848 n=6)
ComponentLoad-4                     2.180Mi ± 0%   2.180Mi ± 0%       ~ (p=0.732 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%  +0.00% (p=0.050 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.290 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                  284.2n ± 8%   287.0n ± 10%  +0.97% (p=0.037 n=6)
CircuitBreakerExecution_Success-4          21.52n ± 0%   21.61n ±  1%  +0.42% (p=0.011 n=6)
CircuitBreakerExecution_Failure-4          65.80n ± 0%   66.41n ±  1%  +0.93% (p=0.002 n=6)
geomean                                    73.82n        74.39n        +0.77%

                                  │ 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                     884.7n ± 32%   905.1n ± 30%       ~ (p=0.132 n=6)
JQTransform_ObjectConstruction-4         1.469µ ±  1%   1.495µ ±  2%  +1.74% (p=0.002 n=6)
JQTransform_ArraySelect-4                3.337µ ±  2%   3.434µ ±  1%  +2.91% (p=0.004 n=6)
JQTransform_Complex-4                    38.58µ ±  1%   39.34µ ±  2%  +1.97% (p=0.009 n=6)
JQTransform_Throughput-4                 1.780µ ±  1%   1.804µ ±  0%  +1.35% (p=0.002 n=6)
SSEPublishDelivery-4                     71.88n ± 42%   72.76n ±  1%       ~ (p=0.372 n=6)
geomean                                  1.666µ         1.698µ        +1.91%

                                 │ 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.099µ ± 8%   1.134µ ± 16%       ~ (p=0.418 n=6)
SchemaValidation_AllFields-4                 1.661µ ± 1%   1.644µ ±  4%       ~ (p=0.394 n=6)
SchemaValidation_FormatValidation-4          1.573µ ± 1%   1.596µ ±  2%       ~ (p=0.119 n=6)
SchemaValidation_ManySchemas-4               1.801µ ± 2%   1.857µ ±  6%       ~ (p=0.093 n=6)
geomean                                      1.508µ        1.533µ        +1.66%

                                    │ 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.259µ ± 13%   1.296µ ± 19%       ~ (p=0.699 n=6)
EventStoreAppend_SQLite-4                  1.496m ± 10%   1.359m ±  2%  -9.18% (p=0.026 n=6)
GetTimeline_InMemory/events-10-4           13.74µ ±  3%   14.67µ ±  3%  +6.78% (p=0.002 n=6)
GetTimeline_InMemory/events-50-4           68.44µ ± 15%   65.45µ ± 28%       ~ (p=0.394 n=6)
GetTimeline_InMemory/events-100-4          123.7µ ±  2%   131.5µ ±  2%  +6.28% (p=0.002 n=6)
GetTimeline_InMemory/events-500-4          632.1µ ±  1%   676.2µ ±  1%  +6.98% (p=0.002 n=6)
GetTimeline_InMemory/events-1000-4         1.295m ±  1%   1.390m ±  2%  +7.34% (p=0.002 n=6)
GetTimeline_SQLite/events-10-4             107.0µ ±  1%   114.6µ ±  1%  +7.11% (p=0.002 n=6)
GetTimeline_SQLite/events-50-4             248.2µ ±  0%   267.3µ ±  2%  +7.69% (p=0.002 n=6)
GetTimeline_SQLite/events-100-4            417.2µ ±  0%   443.5µ ±  1%  +6.30% (p=0.002 n=6)
GetTimeline_SQLite/events-500-4            1.795m ±  0%   1.904m ±  1%  +6.04% (p=0.002 n=6)
GetTimeline_SQLite/events-1000-4           3.513m ±  1%   3.694m ±  3%  +5.13% (p=0.002 n=6)
geomean                                    219.5µ         228.2µ        +3.95%

                                   │ baseline-bench.txt │        benchmark-results.txt         │
                                   │        B/op        │     B/op      vs base                │
EventStoreAppend_InMemory-4                  810.5 ± 8%     784.5 ± 8%       ~ (p=0.589 n=6)
EventStoreAppend_SQLite-4                  1.987Ki ± 2%   1.983Ki ± 2%       ~ (p=0.606 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.545 n=6)
GetTimeline_InMemory/events-1000-4         944.3Ki ± 0%   944.3Ki ± 0%       ~ (p=0.545 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.675 n=6)
geomean                                    67.50Ki        67.30Ki       -0.29%
¹ 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.

…ffSetsNeedsReplaceForForceNew

Agent-Logs-Url: https://github.com/GoCodeAlone/workflow/sessions/e6d4a1f2-66be-48b7-8e17-964af164c028

Co-authored-by: intel352 <77607+intel352@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot May 6, 2026 05:11
Copilot AI changed the title [WIP] Tighten analyzer to recognize local accumulator pattern for NeedsReplace test(codemod): pin direct-assignment accumulator pattern for AssertDiffSetsNeedsReplaceForForceNew May 6, 2026
Copilot AI requested a review from intel352 May 6, 2026 05:12
@intel352 intel352 marked this pull request as ready for review May 6, 2026 06:00
Copilot AI review requested due to automatic review settings May 6, 2026 06:00
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 regression test to the iac-codemod analyzer test suite to prevent AssertDiffSetsNeedsReplaceForForceNew from reintroducing a known false-positive when NeedsReplace is assigned from a local accumulator variable via a direct selector assignment (r.NeedsReplace = needsReplace).

Changes:

  • Introduces TestAssertDiffSetsNeedsReplaceForForceNew_DirectAccumulatorAssignIsClean to pin the “direct-assignment accumulator” pattern as clean (no diagnostics).
  • Adds a dedicated source fixture (diffDirectAccumulatorSrc) representing the accumulator + post-loop selector assignment shape.

@intel352 intel352 merged commit dc5edbf into main May 6, 2026
18 checks passed
@intel352 intel352 deleted the copilot/tighten-analyzer-local-accumulator-pattern branch May 6, 2026 13:41
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.

iac-codemod AssertDiffSetsNeedsReplaceForForceNew false-positive on accumulator pattern

3 participants