refactor(ci): extract wheel smoke into shared script (close PR-time vs publish-time gap) - #2405
Conversation
publish-runtime.yml had a broad smoke (AgentCard call-shape, well-known
mount alignment, new_text_message) inline as a heredoc. runtime-prbuild-
compat.yml had a narrow inline smoke (just `from main import main_sync`).
Result: a PR could introduce SDK shape regressions that pass at PR time
and only fail at publish time, post-merge.
Extract the broad smoke into scripts/wheel_smoke.py and invoke it from
both workflows. PR-time gate now matches publish-time gate — same script,
same assertions. Eliminates the drift hazard of two heredocs that have
to be kept in lockstep manually.
Verified locally:
* Built wheel from workspace/ source, installed in venv, ran smoke → pass
* Simulated AgentCard kwarg-rename regression → smoke catches it as
`ValueError: Protocol message AgentCard has no "supported_interfaces"
field` (the exact failure mode of #2179 / supported_protocols incident)
Path filter for runtime-prbuild-compat extended to include
scripts/wheel_smoke.py so smoke-only edits get PR-validated. publish-
runtime path filter intentionally NOT extended — smoke-only edits should
not auto-trigger a PyPI version bump.
Subset of #131 (the broader "invoke main() against stub config" goal
remains pending — main() needs a config dir + stub platform server).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
626759a to
ef206b5
Compare
HongmingWang-Rabbit
left a comment
There was a problem hiding this comment.
Five-axis pass. Workflow-touching → comment-only per loop policy.
Correctness. The drift class this closes is real: publish-runtime.yml's heredoc smoke caught regressions that runtime-prbuild-compat.yml's narrow from main import main_sync smoke missed, so the gate fired post-merge instead of at PR time. Extracting both into scripts/wheel_smoke.py invoked by both workflows makes the gate symmetric. The four sub-smokes are well-chosen for the actual incident classes: module-imports (#2179 0.1.16 main_sync drop), AgentCard call-shape (state_transition_history + supported_protocols→supported_interfaces), well-known-path alignment (#2193 silent initial_prompt drop), and the message-helper smoke. The "main.py and this block MUST stay in lockstep" comment makes the maintenance contract explicit.
Readability. Top-of-file docstring explains why this exists (heredoc drift) and cites the specific incidents the gate catches. Each function has a focused responsibility with its own rationale comment. The ✓ print lines per sub-smoke keep CI summary logs scannable.
Architecture. Right asymmetry on path filters:
runtime-prbuild-compat.ymladdsscripts/wheel_smoke.pyto its trigger paths — smoke-only edits get PR-validated immediatelypublish-runtime.ymldoes NOT add it — smoke-only edits should not auto-trigger a PyPI version bump
This separation is the right call (matches feedback_runtime_publish_pipeline_gates's spirit — preserve auto-publish trigger semantics).
The "subset of #131" framing is honest about scope — the full "invoke main() against stub config" goal needs a config dir + stub platform server, which is a bigger refactor.
Security.
- No credentials, no auth-bypass;
wheel_smoke.pyruns only against the locally-installed wheel, no network, no secrets touched. - Workflow change is a pure inline → script extraction; no permission/scope expansion.
- No leaked credentials in diff (sk-, gh_, AKIA, sk-ant-, sk-cp- — none).
- No deleted tests; the heredoc test logic is preserved verbatim in the new script (modulo the F401
# noqafor unused import warnings, which is correct for an import-only smoke).
Performance. Identical CI runtime — same Python, same imports, same constructor call. The refactor saves ~30 lines of YAML duplication per workflow without adding any wall-clock cost.
LGTM. CI checks are still queueing on this PR — once runtime-prbuild-compat fires (its path filter is now self-triggering on scripts/wheel_smoke.py edits, which is what the body's verification step contemplates), the meta-test confirms the new flow.
Summary
from main import main_sync)Extract the broad smoke into
scripts/wheel_smoke.pyand have both workflows invoke it. PR-time gate now matches publish-time gate — eliminates the heredoc-drift hazard.Subset of #131. Full "invoke main() against stub config" goal still pending (needs config dir + stub platform server).
Verification
Local:
python scripts/wheel_smoke.py→ pass (all 4 sub-smokes ✓)AgentCardkwarg-rename regression → smoke catches it asValueError: Protocol message AgentCard has no "supported_interfaces" field(exact failure mode of the fix: drop state_transition_history (removed in a2a-sdk 1.x) #2179 / supported_protocols incident class)CI (this PR):
scripts/wheel_smoke.py) and exercise the new path against the PR-built wheelPath filter scope
runtime-prbuild-compat.yml: addedscripts/wheel_smoke.pyso smoke-only edits get PR-validatedpublish-runtime.yml: NOT modified — smoke-only edits should not auto-trigger a PyPI version bumpTest plan
🤖 Generated with Claude Code