fix(compile): gate exec-context-pr synth path in bash, not step condition#937
Conversation
…tion ADO rejects `dependencies.<Job>.outputs[...]` in step-level `condition:` fields (only legal in job-level conditions, `variables:` mappings, and step-level `env:` values). The synth-active branch of `PrContextContributor::prepare_step` emitted such a ref, causing every `on.pr.mode: synthetic` pipeline to fail with "Unrecognized value: 'dependencies'" before the Agent job started. Project the synth flag (and `Build.Reason`) through step `env:` and gate in the bash body. Synth-inactive branch unchanged — its `variables[...]` condition is legal at step level. Also adds a YAML-walking regression-trap test that fails for any future extension emitting the same bug class across the synth-default, exec-context-agent, pr-mode-policy, and minimal-agent fixtures. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
🔍 Rust PR ReviewSummary: Looks good — correct diagnosis, minimal surgical fix, thorough test coverage. Findings✅ What Looks Good
|
Summary
Fixes a hard pipeline-validation error that blocked every
on.pr.mode: syntheticpipeline from starting the Agent job:Root cause: The synth-active branch of
PrContextContributor::prepare_stepemitted a cross-jobdependencies.Setup.outputs[...]reference inside a step-levelcondition:field. ADO only allows that syntax in job-levelcondition:, invariables:mappings, and in step-levelenv:values (via$[ ... ]). The expression is rejected at pipeline-expansion time, so the build fails before the Agent job runs.Fix: Project the synth flag through step
env:(legal there) and gate in the bash body. The synth-inactive branch is unchanged — its condition only readsvariables[...], which IS legal at step level.Emitted YAML (synth-active, after fix)
coalesce(..., '')ensures the bash gate sees""(not an unresolved$()literal) whensynthPrskipped itself on a real-PR build. Variables are double-quoted for shellcheck cleanliness andset -usafety.Regression-trap test (bug-class protection)
In addition to fixing the specific bug, this PR adds
test_no_step_condition_references_cross_job_dependencies, which walks compiled YAML across four fixtures (synth-default, exec-context-agent, pr-mode-policy, minimal-agent), distinguishes step vs job/stage mappings, and fails with a pointer to the offending step if any future extension emits a step-levelcondition:containingdependencies.. This protects every extension that emits a step condition, not justexec_context/pr.Why a guard at all
exec-context-pr.jsruns in the Agent job and must be skipped when there is no PR (real or synthetic) — otherwise it writes a misleading "PR context preparation failed" prompt fragment +aw-context/pr/error.txt. The bash guard preserves that semantics; the only difference vs the old (broken) approach is that the step now shows assucceededin the ADO UI with a single skip log line, rather thanskipped.Why bash-guard and not job-level variable promotion
A more ADO-native alternative (project the Setup-output through
variables:on the Agent job, then referencevariables['AW_SYNTHETIC_PR']in the step condition) was considered. It requires a newCompilerExtension::agent_job_variables()trait method plus a new template marker on the Agent job in four base templates (base.yml,1es-base.yml,job-base.yml,stage-base.yml). ~100 LOC of plumbing for one consumer is over-engineering today; the trait abstraction can be added later if a second extension needs Setup-output projection.Test plan
cargo build— cleancargo test --bin ado-aw exec_context::pr— 2/2 pass (updated synth-active test renamed_emits_coalesced_env_and_bash_synth_guard; synth-inactive test unchanged)cargo test --test compiler_tests test_execution_context_pr_emits_prepare_step_and_prompt_supplement test_synthetic_pr_default_emits_full_synth_wiring test_no_step_condition_references_cross_job_dependencies— 3/3 pass (including new regression trap)cargo test --test bash_lint_testswithENFORCE_BASH_LINT=1— shellcheck clean on the new bash guardcargo test— full suite green (1813 + 132 + … tests, 0 failures)pr-reviewer.yml) locally; grep confirms zero step-levelcondition:fields referencedependencies.