Skip to content

fix(migrations): parseMigrationStatus accepts fresh-database output without explicit Dirty line#545

Merged
intel352 merged 3 commits into
mainfrom
copilot/fix-atlas-driver-panics
May 5, 2026
Merged

fix(migrations): parseMigrationStatus accepts fresh-database output without explicit Dirty line#545
intel352 merged 3 commits into
mainfrom
copilot/fix-atlas-driver-panics

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 5, 2026

The atlas driver (via workflow-migrate) omits the "Dirty:" line when outputting "No migrations applied." for a fresh database. parseMigrationStatus required an explicit dirtySeen flag, causing it to reject valid fresh-database status as "incomplete migration status output" — failing baseline-candidate validation even after the atlas executor panic (the primary CI blocker) was fixed in the binary.

Changes

  • cmd/wfctl/migrations_baseline.goparseMigrationStatus: when "No migrations applied." is seen, implicitly set dirtySeen = true with dirty = false. A fresh database cannot be dirty (no migration has been attempted), so the inference is always safe. An explicit subsequent "Dirty: true" line can still override it.
// before: dirtySeen never set → "incomplete migration status output" for fresh DB
case line == "No migrations applied.":
    recognized, pendingSeen, currentSeen = true, true, true

// after: infer dirty=false when no Dirty line precedes this sentinel
case line == "No migrations applied.":
    recognized, pendingSeen, currentSeen = true, true, true
    if !dirtySeen {
        dirtySeen = true // status.Dirty is already false (zero value)
    }
  • cmd/wfctl/migrations_baseline_test.go — adds:
    • TestParseMigrationStatusFreshDatabaseNoMigrationsApplied: unit tests for text-format (with/without explicit Dirty: line) and JSON (pending: [], pending: null)
    • TestRunMigrationsValidateAtlasFreshDatabaseStatusWithoutDirtyLine: integration test for the full baseline-candidate validation flow returning atlas-style fresh-database status

…ne in atlas driver

Agent-Logs-Url: https://github.com/GoCodeAlone/workflow/sessions/53efbe3a-acca-4b90-b019-e60fb1112c6a

Co-authored-by: intel352 <77607+intel352@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot May 5, 2026 08:04
Copilot AI changed the title [WIP] Fix panic on apply for atlas driver fix(migrations): parseMigrationStatus accepts fresh-database output without explicit Dirty line May 5, 2026
Copilot AI requested a review from intel352 May 5, 2026 08:06
@intel352 intel352 marked this pull request as ready for review May 5, 2026 08:16
Copilot AI review requested due to automatic review settings May 5, 2026 08:16
@intel352
Copy link
Copy Markdown
Contributor

intel352 commented May 5, 2026

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

This PR fixes wfctl migrations validate baseline-candidate validation for fresh databases when the atlas migration driver outputs No migrations applied. without an explicit Dirty: line, by inferring dirty=false for that sentinel state so the status output is no longer treated as incomplete.

Changes:

  • Update parseMigrationStatus to treat No migrations applied. as implicitly clean (dirtySeen=true, Dirty=false) when no Dirty: line is present.
  • Add unit tests covering text and JSON fresh-database status parsing (including pending: [] and pending: null).
  • Add an integration-style test covering the baseline-candidate validation flow with atlas-style fresh-database status output.

Reviewed changes

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

File Description
cmd/wfctl/migrations_baseline.go Infers dirty=false for the No migrations applied. sentinel to avoid rejecting fresh-database status output that omits Dirty:.
cmd/wfctl/migrations_baseline_test.go Adds unit + integration coverage to ensure fresh-database status parsing/validation succeeds with and without an explicit Dirty: line.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 5, 2026

@copilot https://github.com/GoCodeAlone/workflow/actions/runs/25364924208/job/74373380701?pr=545 failing

The CI failure was caused by 33 pre-existing lint issues from the golangci-lint v2.12.1 upgrade (tracked in issue #516). Fixed in commit 9093c67:

  • .golangci.yml: exclude ui/node_modules/ (third-party code); add G710 exclusion for intentional OAuth2 redirects
  • reflect.Ptrreflect.Pointer in module/scan_provider_test.go and schema/reflect.go (govet:inline)
  • File permissions: 0o7550o750, 0o6440o600 (gosec G301/G306)
  • Removed 4 unused functions/constants in cmd/iac-codemod/ (unused)
  • Applied De Morgan's law to 3 conditions in refactor_apply.go (staticcheck QF1001)
  • Removed trailing period from JIT error string (staticcheck ST1005)
  • Merged identical if/else branches in infra_bootstrap.go (gocritic dupBranchBody)
  • Fixed range-val-copy in iac/wfctlhelpers/apply.go (gocritic rangeValCopy)
  • Removed embedded-field selector prefix in 5 test files (staticcheck QF1008)

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 5, 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:297945: parsing iteration count: invalid syntax
baseline-bench.txt:602536: parsing iteration count: invalid syntax
baseline-bench.txt:899675: parsing iteration count: invalid syntax
baseline-bench.txt:1189389: parsing iteration count: invalid syntax
baseline-bench.txt:1517254: parsing iteration count: invalid syntax
benchmark-results.txt:260: parsing iteration count: invalid syntax
benchmark-results.txt:413565: parsing iteration count: invalid syntax
benchmark-results.txt:806290: parsing iteration count: invalid syntax
benchmark-results.txt:1488545: parsing iteration count: invalid syntax
benchmark-results.txt:1863414: parsing iteration count: invalid syntax
benchmark-results.txt:2286391: 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.117m ± 254%   2.339m ± 7%  -24.96% (p=0.002 n=6)
ComponentLoad-4                    3.471m ±  12%   2.692m ± 1%  -22.44% (p=0.002 n=6)
ComponentExecute-4                 1.803µ ±   0%   1.417µ ± 3%  -21.41% (p=0.002 n=6)
PoolContention/workers-1-4        1011.5n ±   0%   779.6n ± 1%  -22.93% (p=0.002 n=6)
PoolContention/workers-2-4        1016.0n ±   1%   787.4n ± 1%  -22.50% (p=0.002 n=6)
PoolContention/workers-4-4        1018.0n ±   1%   786.0n ± 1%  -22.79% (p=0.002 n=6)
PoolContention/workers-8-4        1018.0n ±   1%   783.9n ± 1%  -22.99% (p=0.002 n=6)
PoolContention/workers-16-4       1021.0n ±   1%   792.0n ± 2%  -22.43% (p=0.002 n=6)
ComponentLifecycle-4               3.517m ±   0%   2.758m ± 3%  -21.58% (p=0.002 n=6)
SourceValidation-4                 2.076µ ±   2%   1.613µ ± 1%  -22.31% (p=0.002 n=6)
RegistryConcurrent-4               748.2n ±   2%   595.4n ± 5%  -20.42% (p=0.002 n=6)
LoaderLoadFromString-4             3.568m ±   0%   2.740m ± 2%  -23.20% (p=0.002 n=6)
geomean                            16.52µ          12.80µ       -22.50%

                            │ baseline-bench.txt │        benchmark-results.txt         │
                            │        B/op        │     B/op      vs base                │
InterpreterCreation-4               2.027Mi ± 0%   2.027Mi ± 0%       ~ (p=0.608 n=6)
ComponentLoad-4                     2.180Mi ± 0%   2.180Mi ± 0%       ~ (p=0.195 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.515 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.145 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                  295.9n ± 7%   229.4n ± 5%  -22.47% (p=0.002 n=6)
CircuitBreakerExecution_Success-4          22.65n ± 0%   17.58n ± 1%  -22.40% (p=0.002 n=6)
CircuitBreakerExecution_Failure-4          70.98n ± 1%   55.15n ± 0%  -22.30% (p=0.002 n=6)
geomean                                    78.07n        60.59n       -22.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                     831.4n ± 32%   622.8n ± 28%  -25.09% (p=0.002 n=6)
JQTransform_ObjectConstruction-4         1.445µ ±  1%   1.094µ ±  2%  -24.30% (p=0.002 n=6)
JQTransform_ArraySelect-4                3.403µ ±  2%   2.631µ ±  0%  -22.69% (p=0.002 n=6)
JQTransform_Complex-4                    41.23µ ±  2%   31.89µ ±  1%  -22.63% (p=0.002 n=6)
JQTransform_Throughput-4                 1.758µ ±  1%   1.327µ ±  1%  -24.50% (p=0.002 n=6)
SSEPublishDelivery-4                     64.33n ±  1%   50.12n ±  1%  -22.10% (p=0.002 n=6)
geomean                                  1.634µ         1.249µ        -23.56%

                                 │ 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                  1108.5n ± 14%   864.0n ± 1%  -22.06% (p=0.002 n=6)
SchemaValidation_AllFields-4                1.660µ ±  1%   1.279µ ± 1%  -22.96% (p=0.002 n=6)
SchemaValidation_FormatValidation-4         1.593µ ±  1%   1.232µ ± 3%  -22.69% (p=0.002 n=6)
SchemaValidation_ManySchemas-4              1.623µ ±  1%   1.267µ ± 2%  -21.93% (p=0.002 n=6)
geomean                                     1.477µ         1.146µ       -22.41%

                                    │ 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               1129.0n ± 13%   743.4n ±   8%   -34.16% (p=0.002 n=6)
EventStoreAppend_SQLite-4                  1.028m ±  4%   5.306m ± 198%  +416.14% (p=0.002 n=6)
GetTimeline_InMemory/events-10-4          12.312µ ±  3%   9.935µ ±   3%   -19.31% (p=0.002 n=6)
GetTimeline_InMemory/events-50-4           69.65µ ± 24%   47.87µ ±  15%   -31.27% (p=0.015 n=6)
GetTimeline_InMemory/events-100-4         106.61µ ±  0%   82.08µ ±   0%   -23.01% (p=0.002 n=6)
GetTimeline_InMemory/events-500-4          546.5µ ±  1%   420.2µ ±   1%   -23.12% (p=0.002 n=6)
GetTimeline_InMemory/events-1000-4        1108.8µ ±  2%   856.3µ ±   0%   -22.77% (p=0.002 n=6)
GetTimeline_SQLite/events-10-4             85.81µ ±  1%   64.95µ ±   1%   -24.31% (p=0.002 n=6)
GetTimeline_SQLite/events-50-4             221.2µ ±  2%   169.0µ ±   0%   -23.61% (p=0.002 n=6)
GetTimeline_SQLite/events-100-4            383.8µ ±  0%   295.5µ ±   1%   -23.01% (p=0.002 n=6)
GetTimeline_SQLite/events-500-4            1.676m ±  0%   1.291m ±   1%   -22.97% (p=0.002 n=6)
GetTimeline_SQLite/events-1000-4           3.259m ±  0%   2.519m ±   2%   -22.72% (p=0.002 n=6)
geomean                                    192.3µ         170.0µ          -11.58%

                                   │ baseline-bench.txt │         benchmark-results.txt         │
                                   │        B/op        │     B/op       vs base                │
EventStoreAppend_InMemory-4                  775.0 ± 4%     836.5 ± 10%       ~ (p=0.089 n=6)
EventStoreAppend_SQLite-4                  1.983Ki ± 2%   2.016Ki ± 23%  +1.67% (p=0.045 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=1.000 n=6)
GetTimeline_InMemory/events-1000-4         944.3Ki ± 0%   944.3Ki ±  0%       ~ (p=0.697 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.688 n=6)
geomean                                    67.23Ki        67.76Ki        +0.78%
¹ 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%    52.50 ± 1%       ~ (p=0.182 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.161k       -0.08%
¹ 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 6bdacdf into main May 5, 2026
22 of 23 checks passed
@intel352 intel352 deleted the copilot/fix-atlas-driver-panics branch May 5, 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.

workflow-migrate atlas driver: panic on apply (Executor.Execute, index out of range [0] with length 0)

3 participants