Skip to content

Fix Goose (and other harness engines) crashing when engine.version is unset - #50849

Merged
pelikhan merged 4 commits into
mainfrom
copilot/fix-goose-engine-crash
Aug 6, 2026
Merged

pelikhan merged 4 commits into
mainfrom
copilot/fix-goose-engine-crash

Conversation

Copilot AI commented Aug 6, 2026 •

Copy link
Copy Markdown
Contributor

Workflows setting engine: { id: goose } without an explicit version: crashed at runtime with Error: GH_AW_ENGINE_VERSION is required, since the shared engine definition's default version (declared in .github/workflows/shared/goose.md) was never merged into the compiled config.

Root cause

  • applyEngineImportDefaults only pulled engine config from an imported/shared definition when the main workflow declared no engine: block at all (engineConfig == nil).
  • Workflows that set engine: { id: goose } directly already had a non-nil engineConfig, so the shared definition's version: "1.45.0" was silently dropped — leaving GH_AW_ENGINE_VERSION unset and the Goose harness script throwing before the agent could start.

Changes

  • EngineDefinition (pkg/workflow/engine_definition.go): added a Version field so shared/imported engine definitions can declare a default version.
  • applyEngineImportDefaults (pkg/workflow/compiler_orchestrator_engine.go): now falls back to the resolved engine definition's default Version (looked up via the engine catalog) whenever EngineConfig.Version is still empty after import processing — mirroring the existing merge pattern for MaxTurns, MCPToolTimeout, etc.
  • Regression test: TestSetupEngineAndImports_ImportedEngineVersionDefault verifies a shared engine definition's version is applied when the main workflow only specifies engine: { id: ... }.
  • Recompiled lock files: this also fixes the same latent gap for other harness-based engines relying on the same shared-definition pattern (Aider, Crush, OpenCode), not just Goose.
# main workflow frontmatter
engine:
  id: goose
imports:
  - shared/goose.md   # declares engine.version: "1.45.0"

now correctly produces GH_AW_ENGINE_VERSION: "1.45.0" in the compiled lock file instead of leaving it empty.


Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 16.9 AIC · ⊞ 5.9K · ◷
Comment /souschef to run again

… unset

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
@pelikhan
pelikhan marked this pull request as ready for review August 6, 2026 12:45
Copilot AI balanced review requested due to automatic review settings August 6, 2026 12:45
Copilot AI changed the title [WIP] Fix Goose engine crashes when version is unset Fix Goose (and other harness engines) crashing when engine.version is unset Aug 6, 2026
Copilot AI requested a review from pelikhan August 6, 2026 12:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes #50731 by applying imported engine-definition versions when workflows omit engine.version.

Changes:

  • Adds default version metadata to EngineDefinition.
  • Applies catalog version defaults while preserving explicit versions.
  • Adds regression coverage and recompiles affected workflows.
Show a summary per file
File Description
pkg/workflow/engine_definition.go Adds engine default version metadata.
pkg/workflow/compiler_orchestrator_engine.go Applies catalog version fallback.
pkg/workflow/compiler_orchestrator_engine_test.go Tests imported version defaults.
.github/workflows/smoke-opencode.lock.yml Pins OpenCode version.
.github/workflows/smoke-goose.lock.yml Pins Goose version.
.github/workflows/smoke-crush.lock.yml Pins Crush version.
.github/workflows/smoke-aider.lock.yml Pins Aider version.
.github/workflows/daily-token-consumption-report.lock.yml Applies Goose version.
.github/workflows/daily-team-evolution-insights.lock.yml Applies Goose version.
.github/workflows/daily-security-red-team.lock.yml Applies OpenCode version.
.github/workflows/daily-reliability-review.lock.yml Applies OpenCode version.
.github/workflows/daily-code-metrics.lock.yml Applies Crush version.
.github/workflows/daily-arxiv-researcher.lock.yml Applies Crush version.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 13/13 changed files
  • Comments generated: 0
  • Review effort level: Balanced

@github-actions

github-actions Bot commented Aug 6, 2026 •

Copy link
Copy Markdown
Contributor

✅ PR Code Quality Reviewer completed the code quality review.

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

@github-actions

github-actions Bot commented Aug 6, 2026 •

Copy link
Copy Markdown
Contributor

✅ Test Quality Sentinel completed test quality analysis.

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

@github-actions

github-actions Bot commented Aug 6, 2026 •

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

@github-actions

github-actions Bot commented Aug 6, 2026 •

Copy link
Copy Markdown
Contributor

✅ Design Decision Gate 🏗️ completed the design decision gate check.

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

No ADR enforcement needed: PR does not have the 'implementation' label and has ≤100 new lines of code in business logic directories (66 additions detected).

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

The fix is surgical and correct. applyEngineImportDefaults now falls back to the engine catalog version only when engineConfig.Version is empty and an ID is set — preserving any explicitly declared version. The new test validates the exact runtime crash scenario. No issues found.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 15.2 AIC · ⊞ 5.3K

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

Skills-Based Review 🧠

Applied /diagnosing-bugs and /tdd — approving with one minor suggestion.

📋 Key Themes & Highlights

Summary

The fix is precise and correct. The root cause (import-path version being silently dropped when engineConfig was already non-nil) is properly addressed in applyEngineImportDefaults, and the new Version field on EngineDefinition is cleanly placed with a clear doc comment.

Positive Highlights

  • ✅ Fix is placed after all import-merge logic, so an explicit engine.version in the main workflow still takes precedence — correct ordering.
  • ✅ Regression test TestSetupEngineAndImports_ImportedEngineVersionDefault is clear and mirrors the real production scenario (shared goose.md pattern).
  • ✅ Lock files for all affected harness engines (Aider, Crush, OpenCode, Goose) are recompiled — good blast-radius awareness.
  • ✅ The debug log line is consistent with the existing pattern in applyEngineImportDefaults.

One Suggestion

  • A counterpart test asserting that an explicit engine.version in the main workflow is not overridden would close the spec gap and prevent accidental removal of the if engineConfig.Version == "" guard (see inline comment).

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • proxy.golang.org

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "proxy.golang.org"

See Network Configuration for more information.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 34.2 AIC · ⊞ 7.1K
Comment /matt to run again

require.NotNil(t, result)
require.NotNil(t, result.engineConfig)
assert.Equal(t, "harness-engine", result.engineSetting)
assert.Equal(t, "1.45.0", result.engineConfig.Version)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] Missing counterpart test: explicit version in the main workflow should NOT be overridden by the catalog default.

💡 Suggested test skeleton
func TestSetupEngineAndImports_ExplicitVersionNotOverriddenByDefault(t *testing.T) {
    // arrange: main workflow sets engine.version: "2.0.0"
    // shared/engine.md also declares version: "1.45.0" for the same engine ID
    // act: compile
    // assert: result.engineConfig.Version == "2.0.0"  // main workflow wins
}

Without this test the guard if engineConfig.Version == "" could be accidentally removed and regressions would go undetected.

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 3bfbb66 by adding TestSetupEngineAndImports_ExplicitVersionNotOverriddenByDefault, which verifies an explicit workflow engine.version is preserved over the imported default.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

🧪 Test Quality Sentinel Report

⚠️ Test Quality Score: 71/100 — Acceptable

Analyzed 24 test(s): 20 design, 4 implementation, 0 violation(s).

📊 Metrics (24 tests)
Metric Value
Analyzed 24 (Go: 24, JS: 0)
✅ Design 20 (83%)
⚠️ Implementation 4 (17%)
Edge/error coverage 10 (42%)
Duplicate clusters 1
Inflation No
🚨 Violations 0
Test File Classification Issues
TestFrontmatterDeclaresImports compiler_orchestrator_engine_test.go:17 design —
TestSetupEngineAndImports_ValidSetup :39 implementation happy-path only
TestSetupEngineAndImports_DefaultEngine :79 design —
TestSetupEngineAndImports_DefaultMaxTurnsFromEnv :106 design —
TestSetupEngineAndImports_ExplicitMaxTurnsOverridesEnvDefault :132 design —
TestSetupEngineAndImports_TopLevelMaxTurnsOverridesEnvDefault :160 design —
TestSetupEngineAndImports_ImportedTopLevelMaxTurns :185 design —
TestSetupEngineAndImports_ImportedTopLevelMaxToolDenials :224 design —
TestSetupEngineAndImports_ImportedTopLevelMaxTurnCacheMisses :264 design —
TestSetupEngineAndImports_ImportedEngineVersionDefault :308 design —
TestSetupEngineAndImports_MainMaxTurnCacheMissesTakesPrecedenceOverImport :357 design —
TestSetupEngineAndImports_ImportedModelPreservedWithTopLevelMaxAICredits :402 design —
TestSetupEngineAndImports_EngineOverride :444 design —
TestSetupEngineAndImports_InvalidEngine :474 design —
TestSetupEngineAndImports_StrictModeHandling :501 design —
TestShouldScanImportedMarkdown :580 design —
TestSetupEngineAndImports_NetworkMerging :622 design —
TestSetupEngineAndImports_DefaultNetworkPermissions :670 design —
TestSetupEngineAndImports_SandboxConfiguration :700 implementation only checks NotNil
TestSetupEngineAndImports_MultipleEngineConflict :733 design —
TestSetupEngineAndImports_FirewallEnablement :775 implementation only checks NotNil
TestSetupEngineAndImports_ImportProcessingError :807 design —
TestSetupEngineAndImports_PermissionsValidation :838 implementation happy-path only
TestSetupEngineAndImports_ExperimentalEngine :866 design —
⚠️ Flagged Tests (4)

TestSetupEngineAndImports_ValidSetup (:39) — implementation_test. Asserts all result fields are non-nil/non-empty but asserts no specific behavioral values beyond engineSetting. Consider asserting parsed engine config fields (e.g., default network permissions) to turn this into a behavioral contract.

TestSetupEngineAndImports_SandboxConfiguration (:700) — implementation_test. Only checks result.sandboxConfig != nil; no assertions on field values (enabled, mounts). Verifying parsed values would make this a genuine design test.

TestSetupEngineAndImports_FirewallEnablement (:775) — implementation_test. Comment says firewall should be enabled by default but no assertion validates it. Add an assertion on the actual firewall-enabled field to test the stated contract.

TestSetupEngineAndImports_PermissionsValidation (:838) — implementation_test. Only asserts NoError + NotNil; does not verify the permissions value was parsed correctly. The name implies validation but the body is a pure smoke test.

Verdict

✅ passed. 17% implementation tests (threshold: 30%). No violations found. Build tag //go:build !integration present on line 1. No Go mock library usage detected.

Score breakdown: design ratio 83% (×40 = 33.3), edge coverage 42% (×30 = 12.6), 1 duplicate cluster (+15), no inflation (+10) = 71/100.

Notable: TestSetupEngineAndImports_ImportedModelPreservedWithTopLevelMaxAICredits and TestSetupEngineAndImports_ImportedEngineVersionDefault are strong regression tests with documented root-cause comments — exactly the behavioral contracts that protect against the Goose version-unset bug class.

🧪 Test quality analysis by Test Quality Sentinel · sonnet46 · 71.4 AIC · ⊞ 7.7K · ◷
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Test Quality Sentinel: 71/100. 17% implementation tests (threshold: 30%). No violations.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

REQUEST_CHANGES — targeted fix is reasonable but has a shared-state leakage bug and a YAML quoting inconsistency that should be fixed before merge.

💡 Themes
  • Correctness (blocking): EngineCatalog is a mutable, per-Compiler map that survives across all files in a batch compile run. The new Get(engineConfig.ID) lookup in applyEngineImportDefaults can silently apply a version registered by an earlier workflow's import to a later, unrelated workflow that never imported that shared definition.
  • Consistency (should fix): Generated GH_AW_ENGINE_VERSION values are unquoted in job-level env: blocks but quoted (%q) elsewhere. This PR is the first time default version strings flow broadly into these files, making the YAML-float-parsing risk (e.g. "1.10" → 1.1) newly relevant.
  • Test coverage (should fix): Only the "version omitted" happy path is tested; no regression test for explicit-version-wins-over-default precedence or for cross-file catalog leakage.

The core mechanism (adding EngineDefinition.Version and applying it as a fallback in applyEngineImportDefaults) is a sound, minimal fix for the reported crash, and the regenerated lock files look consistent with the intent.

🔎 Code quality review by PR Code Quality Reviewer · auto · 138.6 AIC · ⊞ 7.8K
Comment /review to run again

orchestratorEngineLog.Printf("Applied model preference from import: %s", model)
}
if engineConfig.Version == "" && engineConfig.ID != "" {
if def := c.engineCatalog.Get(engineConfig.ID); def != nil && def.Version != "" {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Version defaults can leak across unrelated workflows within a single batch compile run: silently applying a wrong version to a workflow that never declared one.

💡 Details

engineCatalog lives on the Compiler struct and is reused for every markdown file processed in compileSpecificFiles/compileAllFilesInDirectory (a single compiler instance is created once via createAndConfigureCompiler and passed through the whole batch loop). Register(def) (engine_definition.go:343) simply does c.definitions[def.ID] = def — it never clears or scopes to the current file.

Given this new lookup:

if def := c.engineCatalog.Get(engineConfig.ID); def != nil && def.Version != "" {
    engineConfig.Version = def.Version
}

Once workflow A imports shared/goose.md (which registers goose with version: "1.45.0"), that definition stays in the catalog for the rest of the batch. If workflow B in the same batch also uses engine: { id: goose } but does not import the shared definition (or imports a different shared file that doesn't set a version), workflow B will incorrectly inherit 1.45.0 from workflow A's registration, because Get("goose") returns the last-registered definition regardless of which file is currently compiling.

Fix: either give EngineCatalog a per-file reset/scratch overlay for imported definitions, or make registerNamedEngineDefinitionFromJSON register on a fresh catalog view per compilation unit instead of mutating shared state.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 3bfbb66 by defaulting from the current workflow's imported engine definitions instead of the compiler-wide catalog, plus regression coverage for no cross-workflow leakage with a reused compiler.

GH_AW_ASSETS_ALLOWED_EXTS: ""
GH_AW_ASSETS_BRANCH: ""
GH_AW_ASSETS_MAX_SIZE_KB: 0
GH_AW_ENGINE_VERSION: 0.88.0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GH_AW_ENGINE_VERSION is emitted unquoted in some lock-file locations (0.88.0) and quoted in others ("0.88.0"), which is a YAML footgun: unquoted version strings like 1.10 would be parsed as a float and truncate/reformat.

💡 Details

Compare the generated lock diffs:

      GH_AW_ENGINE_VERSION: 0.88.0        # unquoted, job-level env (compiler_orchestrator_engine.go path)
...
      GH_AW_ENGINE_VERSION: "0.88.0"      # quoted, step-level env (compiler_safe_outputs_job.go / safe_outputs_env.go path)

safe_outputs_env.go:197 and compiler_safe_outputs_job.go:837 both format the value with %q, but whatever path produces the job-level env: block for the main execution job renders it unquoted. Since this PR is the first time a default (non-user-specified) version string like 1.45.0 or 0.88.0 flows into that env block for engines that previously never had one, this inconsistency is now visible across many workflows. A version such as "1.10" would be silently reinterpreted as 1.1 by strict YAML parsers reading these lock files (e.g. some linters, or manual reconciliation tooling), and 0.10.0 could become 0.1 if ever parsed numerically — a latent correctness bug that this PR's new default-version injection makes far more likely to trigger since defaults are attacker/maintainer-controlled version strings from shared/*.md, not just user frontmatter.

Fix: locate the env template that renders the unquoted GH_AW_ENGINE_VERSION (likely in the job-level env: YAML emission path, distinct from applyEngineVersionEnv) and always quote it, matching the two already-quoted call sites.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 3bfbb66 by quoting job-level GH_AW_ENGINE_VERSION values and regenerating the affected lock files and wasm golden.

require.NotNil(t, result)
require.NotNil(t, result.engineConfig)
assert.Equal(t, "harness-engine", result.engineSetting)
assert.Equal(t, "1.45.0", result.engineConfig.Version)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No test asserts that an explicit engine.version in the main workflow still wins over the shared definition's default — the only new test covers just the "version omitted" happy path.

💡 Details

applyEngineImportDefaults guards the new logic with if engineConfig.Version == "", so precedence should already be correct, but there is no regression test proving it (e.g. main workflow sets engine: { id: goose, version: "1.0.0" } while shared/goose.md declares version: "1.45.0" — expect 1.0.0 to be preserved). Given this PR's stated purpose is fixing a version-defaulting regression, a precedence test guards against a future edit accidentally flipping the condition (e.g. to unconditionally overwrite) and silently breaking users who do pin an explicit version.

Also worth covering: a second file in the same compiler instance/batch that references the same engine ID but without importing the shared definition (see the engineCatalog leakage comment on compiler_orchestrator_engine.go:433) — currently nothing in the test suite exercises multi-workflow compilation with a shared Compiler instance for this code path.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 3bfbb66 with both requested tests: explicit version precedence and no imported-version leakage across workflow compilations using one compiler instance.

@pelikhan

pelikhan commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

@copilot run pr-finisher skill

Copilot AI and others added 2 commits August 6, 2026 13:12
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

@copilot run pr-finisher skill

Ran the pr-finisher pass and pushed 3bfbb66 addressing the in-scope review feedback. Local validation passed except for unrelated environment-sensitive full-test checks noted in the hand-off summary.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

@copilot The PR appears updated after prior review. Please make one final pass on any remaining unresolved review feedback, confirm the prior fixes address the dismissed/stale blocking review concerns, refresh the branch if needed, and then run the pr-finisher skill. Run URL: https://github.com/github/gh-aw/actions/runs/31109158981

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 16.9 AIC · ⊞ 5.9K · ◷
Comment /souschef to run again

@pelikhan
pelikhan merged commit 5befa4c into main Aug 6, 2026
1 check failed
@pelikhan
pelikhan deleted the copilot/fix-goose-engine-crash branch August 6, 2026 14:48
Copilot stopped work on behalf of gh-aw-bot due to an error August 6, 2026 14:49
Copilot AI requested a review from gh-aw-bot August 6, 2026 14:49
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.86.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Code Quality] Goose engine crashes with "GH_AW_ENGINE_VERSION is required" when engine.version is unset in frontmatter

4 participants