Skip to content

perf: fix +320% regression in CompileComplexWorkflow by eliminating redundant yaml.Unmarshal#40662

Merged
pelikhan merged 5 commits into
mainfrom
copilot/performance-fix-compilecomplexworkflow
Jun 21, 2026
Merged

perf: fix +320% regression in CompileComplexWorkflow by eliminating redundant yaml.Unmarshal#40662
pelikhan merged 5 commits into
mainfrom
copilot/performance-fix-compilecomplexworkflow

Conversation

Copilot AI commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

BenchmarkCompileComplexWorkflow regressed from ~3ms/op to ~12.7ms/op. CPU profiling pinpointed the cause: validateTemplateInjection Path B (active whenever skipValidation=true, the default in NewCompiler()) called hasAnyExpressionInRunContent which matches any ${{ }} expression — including compiler-owned ones like ${{ runner.temp }}. This unconditionally triggered a full yaml.Unmarshal on the ~1200-line compiled YAML on every invocation, even when no violation was possible.

Changes

  • validateTemplateInjection Path B (compiler.go): replace the broad hasAnyExpressionInRunContent pre-check with two targeted text scans that together cover both sub-validators. yaml.Unmarshal is now only called when a scan signals a potential issue:

    1. hasExpressionInRunContent(UnsafeContextPattern) — user-controlled contexts (template injection risk)
    2. hasNonAllowedExpressionInRunContent — expressions not in the compiler-owned allow-list (regression guardrail)
  • template_injection_validation.go: add hasNonAllowedExpressionInRunContent; remove now-unused hasAnyExpressionInRunContent. The new function short-circuits when every ${{ }} expression in a run: block matches allowedRunScriptExpressionRegex (env.*, vars.*, runner.*, etc.).

For well-formed workflows the common case is both scans return false — yaml.Unmarshal is skipped entirely.

Result

before after
ns/op ~6,800,000 ~1,640,000
allocs/op 98,282 10,894

Generated by 👨‍🍳 PR Sous Chef · 53.4 AIC · ⌖ 1.01 AIC · ⊞ 17.3K ·

…formed workflows

Replace broad hasAnyExpressionInRunContent check with two targeted text scans:
1. hasExpressionInRunContent(UnsafeContextPattern) - detects template injection risk
2. hasNonAllowedExpressionInRunContent - detects compiler regression cases

For well-formed workflows (the common case), both scans return false so yaml.Unmarshal
is skipped entirely. This fixes the +320% regression in BenchmarkCompileComplexWorkflow.

Benchmark result: ~1.64ms/op (was ~6.8ms baseline; target ~3ms historical)

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix performance regression in CompileComplexWorkflow perf: fix +320% regression in CompileComplexWorkflow by eliminating redundant yaml.Unmarshal Jun 21, 2026
Copilot AI requested a review from pelikhan June 21, 2026 18:33
@pelikhan pelikhan marked this pull request as ready for review June 21, 2026 18:48
Copilot AI review requested due to automatic review settings June 21, 2026 18:48
@github-actions

github-actions Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

github-actions Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

github-actions Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actions

github-actions Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

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

Improves gh aw workflow compilation performance by preventing unnecessary YAML parsing during template-injection and expression-guardrail validation when schema validation is skipped (the common/default path), while preserving the existing security/regression checks when risk indicators are present.

Changes:

  • Replaced the broad “any ${{ }} in run blocks” pre-check with two targeted text scans to decide whether yaml.Unmarshal is necessary.
  • Added hasNonAllowedExpressionInRunContent to quickly detect run-block expressions that are not in the compiler-owned allow-list.
  • Added focused unit tests for the new scan behavior.
Show a summary per file
File Description
pkg/workflow/template_injection_validation.go Adds a targeted run-block scan to ignore compiler-allowed expressions and reduce unnecessary YAML parsing.
pkg/workflow/template_injection_validation_test.go Adds unit tests covering allowed vs disallowed expressions in run blocks (inline + multiline).
pkg/workflow/compiler.go Updates validateTemplateInjection Path B to use targeted scans and conditionally run the parsed validators.

Copilot's findings

Tip

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

  • Files reviewed: 3/3 changed files
  • Comments generated: 0

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🏗️ Design Decision Gate — ADR Required

This PR makes significant changes to core business logic (208 new lines in pkg/workflow/) but does not have a linked Architecture Decision Record (ADR).

📄 Draft ADR committed: docs/adr/40662-targeted-text-scans-before-yaml-unmarshal.md — review and complete it before merging.

🔒 This PR cannot merge until an ADR is linked in the PR body.

📋 What to do next
  1. Review the draft ADR committed to your branch — it was generated from the PR diff and description.
  2. Complete the missing sections — confirm the decision rationale, refine the alternatives, and verify the benchmark numbers.
  3. Commit the finalized ADR to docs/adr/ on your branch.
  4. Reference the ADR in this PR body by adding a line such as:

    ADR: ADR-40662: Use Targeted Text Scans to Gate yaml.Unmarshal in Template-Injection Validation

Once an ADR is linked in the PR body, this gate will re-run and verify the implementation matches the decision.

❓ Why ADRs Matter

ADRs create a searchable, permanent record of why the codebase looks the way it does. This change makes allowedRunScriptExpressionRegex and the two text-scan gates part of the security-critical fast path — exactly the kind of trade-off (performance vs. validation-coverage surface) that future contributors will want documented.

📋 Michael Nygard ADR Format Reference

An ADR must contain these four sections to be considered complete:

  • Context — What is the problem? What forces are at play?
  • Decision — What did you decide? Why?
  • Alternatives Considered — What else could have been done?
  • Consequences — What are the trade-offs (positive and negative)?

All ADRs are stored in docs/adr/ as Markdown files numbered by PR number (e.g., 40662-...md).

🔒 This gate remains blocking until an ADR is linked in the PR body.

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · 72.3 AIC · ⌖ 10.5 AIC · ⊞ 13.6K ·

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 100/100 — Excellent

Analyzed 1 test function (10 table-driven rows): 1 design, 0 implementation, 0 guideline violations.

📊 Metrics & Test Classification (1 test analyzed)
Metric Value
New/modified tests analyzed 1
✅ Design tests (behavioral contracts) 1 (100%)
⚠️ Implementation tests (low value) 0 (0%)
Tests with error/edge cases 1 (100%)
Duplicate test clusters 0
Test inflation detected No (1.44:1 ratio)
🚨 Coding-guideline violations 0
Test File Classification Issues Detected
TestHasNonAllowedExpressionInRunContent pkg/workflow/template_injection_validation_test.go:1340 ✅ Design

Go: 1 (*_test.go); JavaScript: 0.

Verdict

Check passed. 0% implementation tests (threshold: 30%). The single new table-driven test covers the behavioral contract of hasNonAllowedExpressionInRunContent() with 10 rows: 5 allowed-expression cases, 3 disallowed-expression cases (genuine edge-case coverage), 1 scoping case (env field vs. run block), and 1 multiline run block variant. Build tag //go:build !integration is present, no mock libraries are used, and assertions include descriptive messages.

🧪 Test quality analysis by Test Quality Sentinel · 36.8 AIC · ⌖ 12.9 AIC · ⊞ 8.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.

✅ Test Quality Sentinel: 100/100. Test quality is excellent — 0% of new tests are implementation tests (threshold: 30%).

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot run pr-finisher skill

@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.

Request Changes: validation guardrail regression

The performance win is real and the approach (two targeted scans to avoid yaml.Unmarshal) is sound in principle, but the new pre-check introduces a correctness regression that must be addressed before merge.

Blocking issues

Behavioral regression (compiler.go:344) — Replacing hasAnyExpressionInRunContent (trigger on any expression in any detected run block) with hasNonAllowedExpressionInRunContent (trigger only on disallowed expressions in detected run blocks) changes what causes yaml.Unmarshal to fire. In the old code, an allowed expression like ${{ runner.temp }} in a block-style step was enough to trigger full parsed validation, which then caught disallowed expressions in any run block, including ones the text scanner never detected. In the new code, if every text-detected run block contains only allowed expressions, yaml.Unmarshal is skipped entirely—and disallowed expressions in flow-style or quoted-key steps silently pass. See comment on line 344 for a concrete scenario and a suggested fix.

False negatives in the pre-check (template_injection_validation.go:110)strings.HasPrefix(keyPart, "run:") misses flow-style mappings (- { run: "..." }) and quoted keys ("run":). The parsed validators handle these correctly; the text scanner does not. This is both the root cause of the regression above and a standalone gap in the scanner's coverage.

Non-blocking concerns
  • Code duplication (template_injection_validation.go:72) — The ~45-line run-block detection body is copy-pasted between the two scanners. Extracting a shared walkRunBlockLines callback would eliminate the divergence risk and make the flow-style fix a one-line change.
  • Test coverage gap (template_injection_validation_test.go:1442) — No test covers the mixed scenario (allowed expression in block-style step + disallowed expression in flow-style step). Adding it would immediately surface the regression.

🔎 Code quality review by PR Code Quality Reviewer · 126.8 AIC · ⌖ 7.75 AIC · ⊞ 5.1K

Comment thread pkg/workflow/compiler.go
// appears in run: blocks
// → triggers validateNoGitHubExpressionsInRunScriptsFromParsed
needsUnsafeCheck := hasExpressionInRunContent(yamlContent, UnsafeContextPattern)
needsDisallowedCheck := hasNonAllowedExpressionInRunContent(yamlContent)

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.

Behavioral regression: disallowed expressions in undetected run blocks can now slip through validation entirely.

The old pre-check (hasAnyExpressionInRunContent) triggered yaml.Unmarshal + both validators whenever any ${{ }} appeared in a text-detected run block—including allowed ones like ${{ runner.temp }}. That side-effect also caused validateNoGitHubExpressionsInRunScriptsFromParsed to inspect all run blocks from the parsed YAML, including flow-style steps and quoted-key steps that the text scanner misses.

The new pre-check only fires when a disallowed expression appears in a text-detected run block. If a workflow has only allowed expressions in block-style steps plus a disallowed expression in a step the scanner does not detect, needsDisallowedCheck stays false, no yaml.Unmarshal is performed, and validateNoGitHubExpressionsInRunScriptsFromParsed is silently skipped.

💡 Concrete regression scenario
# flow-style step: text scanner misses it
- { run: "echo ${{ github.actor }}" }  # disallowed, not in allow-list
# block-style step: scanner detects it, but expression is allowed
- run: node ${{ runner.temp }}/foo.cjs

Old code (hasAnyExpressionInRunContent): finds ${{ runner.temp }} in the block-style step → trueyaml.Unmarshal → parsed validator sees both steps → flags ${{ github.actor }}.

New code: hasNonAllowedExpressionInRunContent finds ${{ runner.temp }} (allowed, skip); misses the flow-style step entirely → needsDisallowedCheck = false → no yaml.Unmarshal${{ github.actor }} passes undetected.

Suggested fix: keep InlineExpressionPattern as the yaml.Unmarshal gate (preserving the original trigger), and use the two targeted flags only to decide which validators to call inside the already-parsed block:

if hasExpressionInRunContent(yamlContent, InlineExpressionPattern) {
    var reparsed map[string]any
    if err := yaml.Unmarshal(...); err == nil && reparsed != nil {
        if hasExpressionInRunContent(yamlContent, UnsafeContextPattern) {
            templateErr = validateNoTemplateInjectionFromParsed(reparsed)
        }
        if templateErr == nil && hasNonAllowedExpressionInRunContent(yamlContent) {
            templateErr = validateNoGitHubExpressionsInRunScriptsFromParsed(reparsed)
        }
    }
}

This skips yaml.Unmarshal when there are no expressions at all in detectable run blocks (the dominant fast path) while preserving the original validation safety net.

if strings.HasPrefix(keyPart, "-") {
keyPart = strings.TrimSpace(keyPart[1:])
}
if !strings.HasPrefix(keyPart, "run:") {

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.

Pre-check silently misses flow-style step mappings and quoted run keys, producing false negatives for the regression guardrail.

strings.HasPrefix(keyPart, "run:") only recognises a plain scalar run: key. The following valid YAML forms are skipped entirely:

  • Flow-style mapping: - { run: "echo ${{ github.actor }}" }keyPart starts with {, not run:
  • Double-quoted key: "run": echo ${{ github.actor }}keyPart starts with "
  • Single-quoted key: 'run': echo ${{ github.actor }}keyPart starts with '

extractRunBlocks (used by both parsed validators) handles all three forms correctly because it operates on parsed YAML. The text scanner does not, so expressions in those steps never reach validateNoGitHubExpressionsInRunScriptsFromParsed.

💡 How to detect flow-style steps

The minimal surgical fix for flow-style support is to treat a line whose trimmed form contains run: anywhere as a potential match, then extract the value:

// Handle flow-style: - { run: "..." } or { run: "..." }
if idx := strings.Index(keyPart, "run:"); idx >= 0 {
    // make sure it is actually a key boundary, not e.g. "dry-run:"
    if idx == 0 || keyPart[idx-1] == ' ' || keyPart[idx-1] == '{' || keyPart[idx-1] == ',' {
        rest = strings.TrimSpace(keyPart[idx+4:])
        // strip trailing flow-mapping characters, then check for expressions
        ...
    }
}

Alternatively, since quoted/flow-style keys are not emitted by the current compiler, add a comment documenting this known gap and a guard test that will fail if the compiler ever starts emitting them.

// allowedRunScriptExpressionRegex (e.g. ${{ runner.temp }}, ${{ env.FOO }}). It is
// used as a fast pre-check for the regression guardrail inside validateTemplateInjection
// (Path B) to avoid a yaml.Unmarshal when every run-block expression is compiler-owned.
func hasNonAllowedExpressionInRunContent(yamlContent string) bool {

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.

Run-block detection logic is copy-pasted into two independent scanners, creating a silent divergence footgun.

hasNonAllowedExpressionInRunContent and hasExpressionInRunContent share ~45 lines of identical run-block detection code (indentation tracking, - stripping, block-scalar handling). The security correctness of Path B rests on the assumption that both scanners detect the exact same set of run blocks—so that needsUnsafeCheck = true always implies needsDisallowedCheck = true for the same expression.

If the two copies diverge (e.g., a future bug fix for the flow-style gap is applied to one but not the other), the invariant silently breaks: needsUnsafeCheck could be true while needsDisallowedCheck stays false, causing validateNoGitHubExpressionsInRunScriptsFromParsed to be skipped even after yaml.Unmarshal was already paid for.

💡 Suggested refactor

Extract a shared walkRunBlockLines iterator or callback and let both callers plug in their own content-check logic:

// walkRunBlockLines calls visit(line) for each line inside a run: block.
// Returns true as soon as visit returns true (short-circuit).
func walkRunBlockLines(yamlContent string, visit func(line string) bool) bool { ... }

func hasExpressionInRunContent(yamlContent string, re *regexp.Regexp) bool {
    return walkRunBlockLines(yamlContent, func(line string) bool {
        return re.MatchString(line)
    })
}

func hasNonAllowedExpressionInRunContent(yamlContent string) bool {
    return walkRunBlockLines(yamlContent, func(line string) bool {
        for _, expr := range InlineExpressionPattern.FindAllString(line, -1) {
            if !allowedRunScriptExpressionRegex.MatchString(expr) {
                return true
            }
        }
        return false
    })
}

This also makes the flow-style gap easier to fix once: change walkRunBlockLines in one place.

assert.Equal(t, tt.expected, result, "hasNonAllowedExpressionInRunContent() mismatch")
})
}
}

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.

Missing test for the key false-negative scenario that the regression in compiler.go enables.

All new tests exercise straightforward block-style YAML where the text scanner correctly detects every run block. None of them cover the compound case where:

  1. A block-style run step has an allowed expression (${{ runner.temp }}) — triggering hasAnyExpressionInRunContent in the old code but NOT hasNonAllowedExpressionInRunContent in the new code.
  2. A flow-style (or quoted-key) run step in the same workflow has a disallowed expression (${{ github.actor }}).

Add a test case like:

{
    name: "flow-style step with disallowed expression alongside allowed block-style step",
    yaml: `jobs:
  test:
    steps:
      - { run: "echo ${{ github.actor }}" }
      - run: node ${{ runner.temp }}/foo.cjs`,
    expected: true, // disallowed expression must be detected
},

This test currently fails with the new code (returns false), confirming the regression described in the companion comment on compiler.go:344. Having it in the suite prevents a silent regression if the implementation is changed 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.

Skills-Based Review 🧠

Applied /diagnose and /tdd — the fix is correct and well-measured; commenting on test coverage gaps.

📋 Key Themes & Highlights

Key Themes

  • Test coverage gaps on allow-list boundaries: steps.parse-guard-vars.outputs.*, job.services[...].ports[...], github.run_id, and github.workspace are all explicitly in allowedRunScriptExpressionRegex but have no unit tests — a security boundary that a regex edit could silently widen or narrow.
  • Missing multi-expression edge case: the FindAllString loop covering lines with multiple ${{ }} expressions (some allowed, some not) is untested; a regression to FindString would be invisible.
  • Implicit security invariant: validateNoTemplateInjectionFromParsed is now skipped when needsUnsafeCheck=false, a correct but undocumented change from the old unconditional-call behaviour.
  • No integration-level test for the fast path: the key performance win (both scans return false → zero yaml.Unmarshal) has no end-to-end test through validateTemplateInjection.

Positive Highlights

  • ✅ Clear, reproducible benchmark data (4.1× ns/op, 9× allocs/op) pinpoints the exact regression — textbook /diagnose approach.
  • ✅ Root cause correctly identified: hasAnyExpressionInRunContent matching compiler-owned expressions was the false-positive driving unnecessary yaml.Unmarshal calls.
  • ✅ The two independent flags (needsUnsafeCheck / needsDisallowedCheck) are a clean decomposition — each validator is gated by exactly the pre-check relevant to it.
  • ✅ The new function's inline-run and multiline-run paths both apply FindAllString, which is correct.
  • ✅ Excellent inline documentation on Path B — future readers will understand the design without having to trace through the old code.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 163.5 AIC · ⌖ 10.3 AIC · ⊞ 6.9K

} else {
// Inside run block content — check each expression on this line.
if InlineExpressionPattern.MatchString(line) {
for _, expr := range InlineExpressionPattern.FindAllString(line, -1) {

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] The FindAllString loop correctly iterates all expressions on a line, but no test exercises a line containing both an allowed and a disallowed expression (e.g. ${{ env.FOO }} ${{ github.event.issue.title }}). A future accidental replacement with FindString (first-match only) would be invisible to the test suite.

💡 Suggested test case
{
    name: "mixed allowed and disallowed expressions on same line",
    yaml: `jobs:
  test:
    steps:
      - run: echo ${{ env.FOO }} ${{ github.event.issue.title }}`,
    expected: true,
},

echo "${{ github.event.issue.title }}"`,
expected: true,
},
}

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] The allow-list regex covers steps.parse-guard-vars.outputs.(approval_labels|blocked_users|trusted_users), job.services[...].ports[...], github.run_id, and github.workspace, but none of these patterns have a test case. They are security boundaries — a regex change that narrows or widens them would be undetected by the test suite.

💡 Suggested test cases
{
    name: "allowed steps.parse-guard-vars output in run block",
    yaml: `jobs:
  test:
    steps:
      - run: echo ${{ steps.parse-guard-vars.outputs.approval_labels }}`,
    expected: false,
},
{
    name: "disallowed output from non-allow-listed step",
    yaml: `jobs:
  test:
    steps:
      - run: echo ${{ steps.other-step.outputs.value }}`,
    expected: true,
},
{
    name: "allowed github.run_id in run block",
    yaml: `jobs:
  test:
    steps:
      - run: echo ${{ github.run_id }}`,
    expected: false,
},

Comment thread pkg/workflow/compiler.go
if reparsed != nil {
templateErr = validateNoTemplateInjectionFromParsed(reparsed)
if templateErr == nil {
if needsUnsafeCheck {

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.

[/diagnose] validateNoTemplateInjectionFromParsed is now conditionally skipped when needsUnsafeCheck=false, which is a behaviour change from the old code (which called both validators whenever any expression existed). The reasoning is sound — the injection validator only catches user-controlled contexts, and if UnsafeContextPattern found nothing there's nothing to inject — but this invariant is implicit. A short comment would help future reviewers confirm no security check was accidentally dropped.

💡 Suggested comment
// validateNoTemplateInjectionFromParsed is intentionally skipped when
// needsUnsafeCheck=false: the validator only catches user-controlled contexts,
// and the UnsafeContextPattern scan above has already confirmed none are present.
if needsUnsafeCheck {
    templateErr = validateNoTemplateInjectionFromParsed(reparsed)
}

Comment thread pkg/workflow/compiler.go
// needsDisallowedCheck: true when any expression outside the compiler allow-list
// appears in run: blocks
// → triggers validateNoGitHubExpressionsInRunScriptsFromParsed
needsUnsafeCheck := hasExpressionInRunContent(yamlContent, UnsafeContextPattern)

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] The new Path B logic (both-scans-false → skip yaml.Unmarshal) is the core of this performance fix, but there is no compiler-level integration test that exercises this fast path end-to-end. The new unit tests cover hasNonAllowedExpressionInRunContent in isolation; a test at the validateTemplateInjection or Compile level that feeds a workflow containing only ${{ runner.temp }} and asserts no error would anchor the behaviour and catch future regressions at the seam.

💡 Sketch
// Verify that a compiled workflow with only compiler-owned expressions
// in run blocks does not trigger a yaml.Unmarshal error path.
func TestValidateTemplateInjection_AllowedExpressionsOnly(t *testing.T) {
    yamlWithAllowed := `on: push
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - run: node ${{ runner.temp }}/foo.cjs
`
    c := NewCompiler()
    err := c.validateTemplateInjection(yamlWithAllowed, "", "test.md", nil)
    assert.NoError(t, err)
}

Copilot AI and others added 2 commits June 21, 2026 19:25
@github-actions

Copy link
Copy Markdown
Contributor

@copilot review all comments and address unresolved review feedback.

Generated by 👨‍🍳 PR Sous Chef · 53.4 AIC · ⌖ 1.01 AIC · ⊞ 17.3K ·

@github-actions

Copy link
Copy Markdown
Contributor

@copilot refresh the branch and rerun checks.

Generated by 👨‍🍳 PR Sous Chef · 53.4 AIC · ⌖ 1.01 AIC · ⊞ 17.3K ·

@github-actions

Copy link
Copy Markdown
Contributor

``
@copilot re-run checks after the recompile and summarize any remaining blockers.

Generated by 👨‍🍳 PR Sous Chef · 30.3 AIC · ⌖ 1.01 AIC · ⊞ 17.3K ·

@github-actions

Copy link
Copy Markdown
Contributor

``
@copilot review all comments and address unresolved review feedback.

Generated by 👨‍🍳 PR Sous Chef · 30.3 AIC · ⌖ 1.01 AIC · ⊞ 17.3K ·

@pelikhan pelikhan merged commit c9a3de7 into main Jun 21, 2026
29 checks passed
@pelikhan pelikhan deleted the copilot/performance-fix-compilecomplexworkflow branch June 21, 2026 23:45
github-actions Bot added a commit that referenced this pull request Jun 22, 2026
Weekly update covering the week of June 15–22, 2026:
- Compiler +320% performance regression fix (#40662)
- New deferinloop Go linter (#40679)
- gh-aw-detection rollout to 50% of workflows (#40698)
- JSON-RPC error handling fix (#40715)
- Skillet sparse checkout path fix (#40684)
- FNV-1a heredoc delimiter generation (#40696)
- Agent of the Week: delight ✨

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.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.

3 participants