Consolidate 13 hand-rolled sync.Once+error caches onto syncutil.OnceLoader - #50934
Conversation
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Consolidates schema and metadata caches onto syncutil.OnceLoader, reducing duplicated synchronization logic.
Changes:
- Migrates parser schema and deprecation caches.
- Migrates workflow schema, tool, output, and alias caches.
- Adds retry handling for the builtin-only alias map.
Show a summary per file
| File | Description |
|---|---|
pkg/parser/schema_compiler.go |
Migrates six schema caches. |
pkg/parser/schema_deprecation.go |
Migrates deprecated-field caches. |
pkg/workflow/schema_validation.go |
Migrates GitHub Actions schema caching. |
pkg/workflow/awf_config.go |
Migrates AWF schema caching. |
pkg/workflow/samples_validation.go |
Migrates tool and sorted-name caches. |
pkg/workflow/imports.go |
Migrates safe-output key caching. |
pkg/workflow/model_aliases.go |
Migrates model-alias caches and recovery handling. |
Review details
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 7/7 changed files
- Comments generated: 2
- Review effort level: Balanced
| if err != nil { | ||
| // Don't permanently cache the failure: leave the loader ready to retry | ||
| // (and builtinOnlyAliasMapID at its zero value) so a caller that recovers | ||
| // from this panic doesn't get stuck with a stale, un-set identity pointer. | ||
| builtinOnlyAliasMapLoader.Reset() |
There was a problem hiding this comment.
Fixed in 716c1b2: restored getBuiltinOnlyAliasMap to the infallible sync.Once cache pattern (builtinOnlyAliasMapOnce + shared map/id), removing the OnceLoader retry/reset behavior from this excluded site.
| names, _ := sortedSafeOutputFieldNamesLoader.Get(func() ([]string, error) { | ||
| return sliceutil.SortedKeys(safeOutputFieldMapping), nil | ||
| }) |
There was a problem hiding this comment.
Fixed in 716c1b2: restored the sorted safe-output field-name cache to infallible sync.Once (sortedSafeOutputFieldNamesOnce) so this site is no longer using OnceLoader and stays out of the 13 error-caching scope.
|
No test files were added or modified in this PR. PR #50934 only modifies production code files (7 Go source files in pkg/parser/ and pkg/workflow/). Test Quality Sentinel found no behavioral tests to analyze. |
|
No ADR enforcement needed: PR does not have the implementation label and has 82 new lines of code in business logic directories (threshold is 100). |
|
|
|
Warning Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding. What happenedThe threat detection engine failed to produce results. Review the workflow run logs for details. |
🧪 Test Quality Sentinel ReportPR #50934: "Consolidate 13 hand-rolled sync.Once+error caches onto syncutil.OnceLoader" Analysis ResultNo test files were added or modified in this PR. This refactoring consolidates 13 hand-rolled Files changed (production code only):
Test files changed: 0 Test Coverage AssessmentSince no behavioral tests were added or modified, existing test suites will validate this refactoring through integration and regression coverage. The consolidation maintains API compatibility and behavioral equivalence with the original scattered caches. Score: N/A — No behavioral tests to analyze Recommendation: ✅ No test quality issues identified. Proceed with existing test coverage validation during CI.
|
There was a problem hiding this comment.
Review: Consolidate 13 hand-rolled sync.Once+error caches onto syncutil.OnceLoader
Clean, mechanical refactoring with consistent application across 7 files.
Observations
Correctness ✅
All converted sites faithfully preserve cache-the-error semantics. OnceLoader.Get holds the mutex for the full loader execution, maintaining the single-invocation guarantee.
builtinOnlyAliasMapID visibility
Line 91 in model_aliases.go sets builtinOnlyAliasMapID = mapHeaderPointer(data) inside the loader closure (under OnceLoader's mutex), but isBuiltinOnlyAliasMap reads it without any lock. The same exposure existed with sync.Once — worth verifying with go test -race that no new race is introduced by the reset-on-panic path.
Infallible sites wrapped in OnceLoader (existing review comment at samples_validation.go:171)
Minor: the sorted-field-names cache discards a synthesized nil error. Not blocking.
No security concerns introduced.
Verdict
No blocking issues. The PR achieves its stated goal cleanly and reduces the error-prone boilerplate surface area significantly.
🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 43.6 AIC · ⊞ 5.4K
There was a problem hiding this comment.
Skills-Based Review 🧠
Applied /codebase-design — requesting one change for a data-safety issue surfaced by the new Reset() path.
📋 Key Themes & Highlights
Key Themes
- Data race introduced by Reset():
builtinOnlyAliasMapIDis a plainuintptrwritten underbuiltinOnlyAliasMapLoader’s internal mutex but read bare inisBuiltinOnlyAliasMap. The originalsync.Onceguaranteed a single write, so unsynchronized readers were safe.OnceLoader.Reset()breaks that guarantee — a concurrentReset+ retry cycle races against readers of the ID. Fix:atomic.Uintptr.
Positive Highlights
- ✅ Clean, consistent mechanical substitution across 7 files — the pattern is easy to audit
- ✅
OnceLoader.Getis simpler and harder to misuse than the three-variable hand-roll - ✅ Error-caching semantics are preserved identically at all 13 sites
- ✅
awf_config.goandschema_validation.gorefactors are textbook-clean - ✅ The
sortedSafeOutputFieldNamesLoaderinfallible closure is a pragmatic choice givenSortedKeyscannot fail
🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 100.9 AIC · ⊞ 7.1K
Comment /matt to run again
Comments that could not be inline-anchored
pkg/workflow/model_aliases.go:112
[/codebase-design] Data race: builtinOnlyAliasMapID is written inside builtinOnlyAliasMapLoader.Get’s mutex (line 91) but read in isBuiltinOnlyAliasMap without any synchronization — and Reset() makes re-runs of the loader possible, turning this into an observable race under the Go memory model.
<details>
<summary>💡 Suggested fix</summary>
Replace the bare uintptr field with atomic.Uintptr:
builtinOnlyAliasMapID atomic.Uintptr // replaces plain uintptrThen use `at…
|
@copilot run pr-finisher skill |
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
|
🎉 This pull request is included in a new release. Release: |
pkg/syncutil.OnceLoader[T]already implements thesync.Once+ cached-value + cached-error contract, but 13 call sites acrosspkg/parserandpkg/workflowhand-rolled the same pattern independently — each a separate chance to get the mutex/visibility semantics wrong, and none withOnceLoader's test-friendlyReset()/Override()escape hatches.Changes
pkg/parser/schema_compiler.go: main workflow, MCP config, repo config, and AW manifest schema loaders, plus the two parsed-schema-doc caches (6 sites → 6OnceLoaderfields)pkg/parser/schema_deprecation.go: shallow and deep deprecated-fields cachespkg/workflow/schema_validation.go/awf_config.go: GitHub Actions schema and AWF config schema loaderspkg/workflow/samples_validation.go: compiled tool schemas + sorted safe-output field namespkg/workflow/imports.go: safe output type keyspkg/workflow/model_aliases.go: builtin model aliases, plus the builtin-only alias map identity cache (retains itsunsafe-derived pointer for map identity comparison, now hardened to reset on load failure so a panic-recover retry can't be stuck with a stale/zeroed pointer)No functional or behavioral change — each site preserves its original cache-the-error semantics.
Every site collapses from 3 package-level vars (
*Once, cached value, cached error) to one: