Skip to content

fix: emit compiler-generated constants as quoted strings - #71803

Merged
pelikhan merged 6 commits into
mainfrom
pelikhan-silver-waffle
Oct 25, 2026
Merged

pelikhan merged 6 commits into
mainfrom
pelikhan-silver-waffle

Conversation

@pelikhan

@pelikhan pelikhan commented Oct 25, 2026 •

Copy link
Copy Markdown
Collaborator

Why

The public workflow corpus produced 15 obfuscation notices for compiler-generated string literals: 14 deferred prompt markers and one unconditional pre-activation output. Authors cannot safely repair generated bindings, so fix code generation rather than suppress the linter.

Changes

  • Explicitly identify generated deferred markers as literal values and emit quoted YAML strings during prompt creation, interpolation, and placeholder substitution.
  • Keep late job output/result bindings as Actions expressions in the agent job, preserving prompt rendering and substitution semantics.
  • Emit unconditional pre_activation.outputs.activated as the string "true", not a YAML boolean or a redundant literal-only expression.
  • Preserve authored expression handling and existing lint rules.
  • Regenerate the four affected workflow lock files after merging main.

ADR: ADR-71803: Quoted compiler-generated constants

Validation

  • make merge-main completed without conflicts, including build, formatting, and successful recompilation of all 348 workflows.
  • Focused compiler and linter regressions passed again after the merge and during review follow-up, covering runtime, inline, and inlined-import prompts; repeated output/result references; compound and conditional expressions; quoted string typing; and zero obfuscation findings in compiled fixtures.
  • All four affected workflows in this repository also compiled with --no-emit and no obfuscation notices. No workflows were executed.
  • The post-merge and review-follow-up make agent-report-progress-no-test gates passed Go lint (zero issues), build, and schema freshness, but remain blocked by pre-existing custom-lint findings in touched files.

The earlier full make agent-report-progress gate also passed impacted tests. A broader test selection encountered unrelated checkout-shell syntax failures and a macOS /var versus /private/var path assertion.

Preserve deferred prompt markers as literal environment values across prompt creation, interpolation, and substitution. Emit unconditional pre-activation output as a quoted string rather than a literal-only Actions expression, without changing authored expressions or lint rules.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@pelikhan
pelikhan marked this pull request as ready for review October 25, 2026 03:52
Copilot AI max review requested due to automatic review settings October 25, 2026 03:52
@github-actions

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

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

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

@github-actions

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

✅ Ponytail Reviewer completed successfully!

Ponytail Reviewer

Outcome: reported_no_action

The agent completed and reported no action. A no-op output alone does not verify that all required work was completed or that publication was possible.

Agent messages are omitted from this comment. The category uses structured run status, not interpretation of agent prose.

Generated from Ponytail Reviewer · gpt56 · ~7 AIC · ⌖ ~6 AIC · ⊞ 14.8K · ◷

Generated by Ponytail Reviewer for #71803

@github-actions

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

✅ PR Code Quality Reviewer completed the code quality review.

🔎 Code quality review by PR Code Quality Reviewer

@github-actions

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

✅ Test Quality Sentinel completed test quality analysis.

Test Quality Sentinel

Outcome: reported_no_action

The agent completed and reported no action. A no-op output alone does not verify that all required work was completed or that publication was possible.

Agent messages are omitted from this comment. The category uses structured run status, not interpretation of agent prose.

Generated from Test Quality Sentinel · sonnet50 · ~16 AIC · ⌖ ~16 AIC · ◇ ~7 AIC · ⊞ 12.7K · ◷

🧪 Test quality analysis by Test Quality Sentinel

@github-actions

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

✅ Design Decision Gate 🏗️ completed the design decision gate check. See the comment below for the result and any generated ADR draft.

Commit pushed: 45c43c8

🏗️ ADR gate enforced by Design Decision Gate 🏗️

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

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

Review summary

No actionable blocking issues found in the changed lines. The deferred-marker quoting and unconditional activation output changes are covered by focused regression tests, and the generated YAML remains correctly typed.

🔎 Code quality review by PR Code Quality Reviewer · copilot · gpt50 · ~3 AIC · ⌖ ~1 AIC · ⊞ 1.6K
Comment /review to run again

@github-actions

Copy link
Copy Markdown
Contributor

🏗️ Design Decision Gate — ADR Required

This PR adds a lot of code to core business logic (165 new lines in pkg/, over the 100-line threshold), but it doesn't link an Architecture Decision Record (ADR).

📄 Draft ADR committed: docs/adr/71803-emit-compiler-generated-constants-as-quoted-yaml-strings.md. Review and finish it before merging.

Inferred decision: add an explicit IsLiteral flag to ExpressionMapping. Compiler-generated constants (deferred prompt markers and the unconditional pre-activation activated output) are then emitted as quoted YAML strings instead of literal-only ${{ }} expressions. The obfuscation lint rule stays unchanged. The draft lists three alternatives that were not chosen: a linter exemption, inferring literals from expression content, and unquoted YAML scalars.

🔒 This PR can't 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.
  2. Complete the missing sections. Add context the AI couldn't infer (such as reviewers, marked [TODO: verify]), refine the rationale, and confirm the alternatives you 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-71803: Emit Compiler-Generated Constants as Quoted YAML Strings

After the PR body links an ADR, this gate runs again and checks that 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 keep a searchable, permanent record of why the codebase looks the way it does, so later contributors can see the reasoning.

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

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · pi · opus55 · ~27 AIC · ⌖ ~41 AIC · ⊞ 1.9K · ◷
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.

Skills-Based Review 🧠

Applied /diagnosing-bugs — approving, no actionable issues found.

📋 Analysis

The fix addresses the root cause: compiler-generated literal content (deferred prompt placeholders, the unconditional activated output) was previously forced through single-quoted string syntax at the call site, which the obfuscation linter correctly flagged as ambiguous between a literal and an authored expression. The PR introduces an explicit ExpressionMapping.IsLiteral flag and a shared environmentValue() helper that routes literal content through the existing writeYAMLEnv (%q) helper, producing proper double-quoted YAML scalars, while authored expressions keep their ${{ ... }} wrapping unchanged.

Strengths:

  • Root cause fixed in the type/flag, not papered over with linter suppressions.
  • TestExpressionMappingEnvironmentValue round-trips values (including empty string, the literal word true, and a multi-line/quote-containing value) through YAML unmarshal to confirm the emitted scalar decodes back to the exact original content — a solid regression guard against the historical quoting bug.
  • compiler_pre_activation_job_test.go and on_steps_test.go additions assert the activated output decodes as the string "true" (not a YAML boolean), guarding the second part of the fix.
  • New tests invoke workflowlint.ObfuscationRule().Check(...) directly against compiled fixtures to assert zero diagnostics, closing the loop back to the original 15 obfuscation-notice motivation.
  • IsLiteral defaults to false and is only set by the two call sites producing compiler-generated literals, so authored-expression handling (quoted-string heuristics, compound || expressions) is left untouched — verified in TestRewriteDeferredPromptExpressions with explicit assert.False checks on deferred[0].IsLiteral and original.IsLiteral.

I traced all three call sites that write expression-mapping values to YAML (generatePlaceholderEnvironment, template.go's interpolation step, unified_prompt_step.go's prompt-creation step) and confirmed they consistently route through environmentValue()/IsLiteral, so there's no remaining quoting divergence between the prompt-creation, interpolation, and substitution steps.

No blocking issues. This is a clean, well-tested, properly scoped bug fix.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · copilot · sonnet50 · ~63 AIC · ⌖ ~15 AIC · ⊞ 10.2K
Comment /matt to run again

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.

🔵 Needs a closer look

The full validation gate remains incomplete, so human confirmation of validation results is needed before merging the generated-workflow changes.

No open issues 🎉

What changed in this PR

This PR updates gh-aw’s compiler to emit generated constants as quoted YAML strings, avoiding obfuscation notices while preserving authored expressions and deferred runtime bindings.

Changes:

  • Marks deferred prompt placeholders as literals and handles them consistently across prompt-generation steps.
  • Emits unconditional pre-activation output as "true" rather than a literal-only expression.
  • Adds regression coverage for string typing, deferred bindings, and obfuscation diagnostics.
File Description
pkg/​workflow/​unified_prompt_step.go Uses literal-aware serialization for prompt environment values.
pkg/​workflow/​template.go Uses literal-aware serialization during interpolation.
pkg/​workflow/​on_steps_test.go Checks quoted activation output, string typing, and lint diagnostics.
pkg/​workflow/​known_needs_expressions_test.go Updates the deferred-marker quoting assertion.
pkg/​workflow/​expression_extraction.go Adds literal tracking and environment-value serialization.
pkg/​workflow/​compiler_pre_activation_job.go Quotes constant activation output values.
pkg/​workflow/​compiler_pre_activation_job_test.go Covers constant outputs, conditional expressions, and missing checks.
pkg/​workflow/​compiler_github_actions_steps.go Emits literal placeholder bindings directly as YAML strings.
pkg/​workflow/​compiler_deferred_prompt.go Marks generated deferred placeholders as literals.
pkg/​workflow/​compiler_deferred_prompt_test.go Expands prompt-mode, binding, string-typing, and lint regressions.

Review effort: Max

pelikhan and others added 3 commits October 24, 2026 21:10
Regenerate the four affected workflow locks with literal deferred prompt markers.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Record verified literal mapping semantics, alternatives, and consequences while leaving approval pending PR review.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@pelikhan

Copy link
Copy Markdown
Collaborator Author

In response to this review comment:

Accepted the skills review assessment; it reports no actionable issues, so no implementation change is needed.

@pelikhan

Copy link
Copy Markdown
Collaborator Author

In response to this review comment:

Accepted as an informational completion notice, not proof of readiness. Focused compiler and linter regressions pass independently; the existing custom-lint gate failures remain documented in the PR.

@pelikhan

Copy link
Copy Markdown
Collaborator Author

In response to this review comment:

Accepted the code quality review assessment that no actionable blocking issues were found. No implementation change is needed for this completion notice.

@pelikhan

Copy link
Copy Markdown
Collaborator Author

In response to this review comment:

Accepted as an informational no-action report rather than independent evidence of coverage. The focused compiler and linter regression tests were rerun successfully during this follow-up.

@pelikhan

Copy link
Copy Markdown
Collaborator Author

In response to this review comment:

Accepted and reviewed the generated ADR against the implementation, refining the rationale and preserving Proposed status without asserting reviewer approval. The finalized record is committed in 9d88b2c and linked in the PR description.

@pelikhan

Copy link
Copy Markdown
Collaborator Author

In response to this review comment:

Accepted: finalized the ADR in 9d88b2c with verified context, literal-versus-expression handling, alternatives, and consequences, and removed the unverified reviewer placeholder. The PR description now links the ADR; its status remains Proposed pending approval.

@pelikhan
pelikhan merged commit 0ab9cde into main Oct 25, 2026
37 checks passed
@pelikhan
pelikhan deleted the pelikhan-silver-waffle branch October 25, 2026 04:42
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.93.4

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

Labels

None yet

2 participants