dadba2f4c8
The publish job failed on PR #19 with a 409 for version 2026.7.30.2309, but that version is live on the gallery (created 23:10:04) - the push landed and the client still surfaced an error, so the retry collided with the upload that had just succeeded. The run went red over a publish that actually worked. The step now checks the gallery before pushing and skips when the version is already there, and on a publish error it re-checks before failing. This mirrors the release job, which already looks for an existing tag and skips. Version comparison normalizes each segment the way NuGet does, since the manifest carries zero-padded segments (2026.07.30.2309) while the gallery lists the stripped form (2026.7.30.2309); comparing the raw strings would never match and the guard would never fire. Verified: both workflows still parse as YAML with the same three jobs, the normalizer reproduces the gallery form for four published versions, and a live lookup confirms the guard would have exited 0 on the run that failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>