Skip to content

Use aw_context fallbacks for injected GitHub prompt context in centralized slash/workflow-call paths#31820

Merged
pelikhan merged 17 commits into
mainfrom
copilot/fix-github-context-injected-prompt
May 13, 2026
Merged

Use aw_context fallbacks for injected GitHub prompt context in centralized slash/workflow-call paths#31820
pelikhan merged 17 commits into
mainfrom
copilot/fix-github-context-injected-prompt

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 12, 2026

Bug Fix

What was the bug?

Centralized slash-command and workflow_call executions could produce empty/unresolved GitHub context fields in the agent prompt (issue-number, discussion-number, pull-request-number, comment-id) because those runs often lack native github.event.* entity payloads.
As a result, prompts lost key routing context even though the same metadata existed in aw_context.

How did you fix it?

  • Prompt context fallback logic
    • Updated embedded GitHub context prompt expressions to use github.event.* first, then fall back to fromJSON(github.event.inputs.aw_context || '{}').
    • Applied entity-type guards (item_type) for number fields to avoid cross-entity leakage.
  • Regression coverage
    • Added a focused prompt test asserting the aw_context fallback expressions remain present in the embedded GitHub context prompt.
  • Generated fixture alignment
    • Refreshed affected wasm compile goldens to match the updated prompt expression output.

Testing

{{#if ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || '{}').item_number) }} }}
- **pull-request-number**: #${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || '{}').item_number) }}
{{/if}}

Copilot AI and others added 3 commits May 12, 2026 23:50
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title Fix GitHub prompt context fallback from aw_context for centralized slash/workflow_call Use aw_context fallbacks for injected GitHub prompt context in centralized slash/workflow-call paths May 12, 2026
Copilot AI requested a review from pelikhan May 12, 2026 23:57
@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot use built-in syntax sugar and support it in the compiler to reference parsed aw context values.

Copilot AI and others added 2 commits May 13, 2026 00:09
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 13, 2026

@copilot use built-in syntax sugar and support it in the compiler to reference parsed aw context values.

Implemented in 44a6769. I added compiler support for github.aw.context.<field> syntax sugar (rewritten to parsed fromJSON(github.event.inputs.aw_context || '{}').<field> during expression extraction) and updated the embedded GitHub context prompt to use the sugar.

@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot merge main and recompile

@@ -9,17 +9,17 @@ The following GitHub context information is available for this workflow:
{{#if ${{ github.workspace }} }}
- **workspace**: ${{ github.workspace }}
{{/if}}
{{#if ${{ github.event.issue.number }} }}
- **issue-number**: #${{ github.event.issue.number }}
{{#if ${{ github.event.issue.number || (github.aw.context.item_type == 'issue' && github.aw.context.item_number) }} }}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@copilot the nested expression seems unecessary:

{{#if ${{ ... }} }} => {{#if ... }}

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 fee36f4 — I removed the nested ${{ ... }} wrappers in the {{#if ...}} tags and regenerated the affected wasm golden fixtures.

Copilot AI and others added 2 commits May 13, 2026 00:56
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 13, 2026

@copilot merge main and recompile

Done in 733f1ac. I merged origin/main into this branch and recompiled workflows (make recompile).

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
@pelikhan pelikhan marked this pull request as ready for review May 13, 2026 01:14
Copilot AI review requested due to automatic review settings May 13, 2026 01:14
@github-actions
Copy link
Copy Markdown
Contributor

Commit pushed: eaeb048

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions
Copy link
Copy Markdown
Contributor

🏗️ Design Decision Gate — ADR Required

This PR makes significant changes to core business logic (151 new lines in default business directories, above the 100-line threshold) but does not have a linked Architecture Decision Record (ADR).

AI has analyzed the PR diff and generated a draft ADR to help you get started:

📄 Draft ADR: docs/adr/31820-aw-context-fallback-for-injected-github-routing-context.md

What to do next

  1. Review the draft ADR committed to your branch — it was generated from the PR diff (title, body, and changes to pkg/workflow/prompts/github_context_prompt.md plus the regenerated *.lock.yml fixtures).
  2. Complete the missing sections — add context the AI couldn't infer (deciders, any prior incidents that motivated the fallback, links to related issues), refine the decision rationale, and confirm the alternatives reflect what was actually considered.
  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-31820: aw_context Fallback for Injected GitHub Routing Context in Agent Prompt

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

Why ADRs Matter

"AI made me procrastinate on key design decisions. Because refactoring was cheap, I could always say 'I'll deal with this later.' Deferring decisions corroded my ability to think clearly."

ADRs create a searchable, permanent record of why the codebase looks the way it does. Future contributors (and your future self) will thank you.

📋 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., 0042-use-postgresql.md for PR #42).

References:

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

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · ● 6.5M ·

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

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 — this is a bug fix that centralises aw_context fallback logic for slash-command and workflow_call paths.

Key Themes

Critical: {{#if}} conditions are always truthy (regression introduced)

The old pattern was {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__}} — after env-var substitution the condition became the actual value (e.g. 42 or "") which isTruthy evaluates correctly.

The new pattern is:

{{#if github.event.issue.number || (github.aw.context.item_type == 'issue' && github.aw.context.item_number)}}

This raw string is never substitutedisTruthy in is_truthy.cjs receives the full literal string, which is not in the falsy list ("", "false", "0", etc.), so it always returns true. The prompt will always render - **issue-number**: #false even when no issue exists.

Fix: The {{#if}} condition should use the env-var placeholder that IS substituted — i.e. the same ${{ ... }} wrapper approach as the value (which gets compiled to __GH_AW_EXPR_XXXX__). Either restore the {{#if ${{ expr }} }} pattern, or extend isTruthy to evaluate || expressions.

Missing end-to-end regression test

The new github_context_prompt_test.go only checks the source template text. There is no test that runs the full compile→render pipeline with a workflow_call trigger and asserts the prompt contains the right number — meaning the original bug could return undetected.

Positive Highlights

  • github.aw.context.* syntax sugar is a clean abstraction that hides the fromJSON(...) verbosity from template authors
  • ✅ The transformAwContextExpression function is well-isolated and has a doc comment with a clear example
  • ✅ The lock files are consistently regenerated across all affected workflows
  • ✅ The existing expression_extraction_test.go table-driven test was correctly extended

Verdict

Requesting changes on the {{#if}} condition bug before merge — it's a correctness regression that would cause all four conditional context fields to always appear in the prompt with false as their value.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · ● 12.5M

- **workspace**: ${{ github.workspace }}
{{/if}}
{{#if ${{ github.event.issue.number }} }}
- **issue-number**: #${{ github.event.issue.number }}
{{#if github.event.issue.number || (github.aw.context.item_type == 'issue' && github.aw.context.item_number)}}
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] The {{#if ...}} condition here is always truthy at runtime.

interpolate_prompt.cjs only env-var-substitutes __GH_AW_EXPR_XXXX__ tokens inside the body of the block, not inside the {{#if ...}} tag itself. So isTruthy receives the raw literal string "github.event.issue.number || (github.aw.context.item_type == 'issue' && github.aw.context.item_number)" — which is never falsy per the rules in is_truthy.cjs. The section will always render, producing - **issue-number**: #false when no issue context exists.

The correct fix mirrors the old pattern: use the already-computed env-var placeholder as the condition too:

-{{#if github.event.issue.number || (github.aw.context.item_type == 'issue' && github.aw.context.item_number)}}
+{{#if ${{ github.event.issue.number || (github.aw.context.item_type == 'issue' && github.aw.context.item_number) }}}}

This keeps condition and value in sync and the substituted value (false or a number) is correctly evaluated by isTruthy.

}
}

assertContains("github.event.issue.number || (github.aw.context.item_type == 'issue' && github.aw.context.item_number)")
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] This test verifies the source template text contains the right strings, but does not test the rendered output at runtime. The actual bug being fixed — that workflow_call triggers without native event payloads produce empty context fields — has no regression test that would fail if the fix were reverted.

Consider adding an interpolate_prompt.test.cjs test (or a Go integration test) that simulates:

  1. No github.event.* values present
  2. aw_context input set to {"item_type":"issue","item_number":42}
  3. Asserts the rendered prompt contains - **issue-number**: #42

This is the seam closest to the actual bug and would catch regressions in the full compile→render pipeline.

@@ -250,6 +257,16 @@ func transformExperimentsExpression(expr string) string {
return expr
}

// transformAwContextExpression rewrites github.aw.context.<field> references to
// parsed aw_context access expressions.
//
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] transformAwContextExpression applies a regex replacement globally across the entire expression string, but there are no unit tests for edge cases of the regex [a-zA-Z0-9_-]+.

For example: what happens with github.aw.context. (empty field name) or github.aw.context.item-type (hyphen in field)? The regex allows - but fromJSON(...).item-type is not valid JavaScript property access syntax — it would be interpreted as fromJSON(...).item minus type.

Consider adding test cases:

{name: "hyphenated field treated correctly", expr: "github.aw.context.item-type"},
{name: "standalone transform", expr: "github.aw.context.item_number", want: "fromJSON(github.event.inputs.aw_context || '{}').item_number"},

Also: the regex allows - in field names but the only known fields use _. Restricting to [a-zA-Z0-9_]+ would be safer.

@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot review all comments and create an integration test that runders the github prompt template, simulate github action expression substitutaion and runs the javascript renderer

Copilot AI and others added 2 commits May 13, 2026 01:34
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot also applies to workflow_dispatch, repository_dispatch

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 13, 2026

@copilot review all comments

Done in dec0d03. I reviewed the outstanding comments and addressed the remaining actionable one by tightening github.aw.context.<field> matching to underscore-only fields and adding regression coverage for hyphenated fields not being transformed.

@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot merge main and recompile
Review generated lock file and ensure proper escaping

Copilot AI and others added 2 commits May 13, 2026 01:56
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 13, 2026

@copilot review all comments and create an integration test that runders the github prompt template, simulate github action expression substitutaion and runs the javascript renderer

Addressed in 4fbe7e1 (with core additions in dfe3b9f). I added an integration-style JS test in actions/setup/js/interpolate_prompt.test.cjs that loads pkg/workflow/prompts/github_context_prompt.md, simulates GitHub Actions expression substitution, and runs the JS renderer (renderMarkdownTemplate) end-to-end against the rendered prompt output.

@copilot also applies to workflow_dispatch, repository_dispatch

Addressed in 4fbe7e1 (with core logic in dfe3b9f). github.aw.context.<field> now expands to fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').<field>, so aw_context fallbacks cover both workflow_dispatch and repository_dispatch.

Copilot AI and others added 2 commits May 13, 2026 02:05
…ntext-injected-prompt

# Conflicts:
#	.github/workflows/daily-cache-strategy-analyzer.lock.yml
#	.github/workflows/daily-fact.lock.yml
#	.github/workflows/daily-observability-report.lock.yml
#	.github/workflows/duplicate-code-detector.lock.yml
#	.github/workflows/grumpy-reviewer.lock.yml
#	.github/workflows/issue-arborist.lock.yml
#	.github/workflows/necromancer.lock.yml
#	.github/workflows/schema-feature-coverage.lock.yml
#	.github/workflows/smoke-call-workflow.lock.yml
#	.github/workflows/smoke-codex.lock.yml

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 13, 2026

@copilot merge main and recompile
Review generated lock file and ensure proper escaping

Done in 37b2fe3 (after merging main in 443c207). I merged latest main, recompiled lock workflows, and reviewed the regenerated lock output for escaping correctness.

@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot merge main and recompile

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 13, 2026

@copilot merge main and recompile

Done in 7ac6a61 — I merged origin/main into this branch and recompiled workflows (make recompile).

@pelikhan pelikhan merged commit d2399de into main May 13, 2026
@pelikhan pelikhan deleted the copilot/fix-github-context-injected-prompt branch May 13, 2026 02:27
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