Skip to content

Add closed TestPyPI candidate source for release qualify and campaign - #723

Open
jeffhuber wants to merge 1 commit into
mainfrom
claude/v108-testpypi-713
Open

Add closed TestPyPI candidate source for release qualify and campaign#723
jeffhuber wants to merge 1 commit into
mainfrom
claude/v108-testpypi-713

Conversation

@jeffhuber

Copy link
Copy Markdown
Contributor

Summary

Implements the closed TestPyPI candidate source contract from #713 (part of epic #709):

  • New closed package_source vocabulary (pypi default, testpypi) on both code-mower release qualify and code-mower release campaign.
  • testpypi installs from the canonical TestPyPI simple index (https://test.pypi.org/simple/) with production PyPI (https://pypi.org/simple/) as a dependency-only extra index. Never an arbitrary URL or credential.
  • release qualify's built-in runner threads the source into the existing run_package_install_rehearsal pip-install path, reusing its existing bounded retry behavior for package-index propagation.
  • release campaign binds the source into:
    • campaign identity (ReleaseCampaign.package_source, defaults to pypi);
    • each provider's idempotency key computation;
    • local adapter argv construction ({package_source} placeholder, threaded to the maintained codex/claude_audit/antigravity_cli/muse_cli adapter templates and into campaign_adapters.py's CLI, prompt text, and Claude's sandboxed network allowlist);
    • hosted dispatch instructions and the machine-readable dispatch marker, plus binding of a hosted comment reply's declared source against the campaign's expected source;
    • resume/dispatch identity-mismatch checks (_existing_campaign_conflict), matching the existing --qualification-context pattern exactly -- an explicit --package-source that disagrees with a stored campaign's source is rejected as a conflict, not silently advanced.
  • A campaign stored before this field existed reads back as pypi (its documented default); _watch_campaign_validation_error tolerates the missing field the same way.
  • Docs: docs/release-qualification.md gets a new "TestPyPI candidates" subsection plus updated resume-mismatch/placeholder prose; docs/pypi-release.md's propagation-triage section gets the equivalent release qualify/release campaign candidate-first callout next to the existing migration package-install-rehearsal one.

Out of scope (per the issue): private artifact / authenticated GitHub Actions artifact support.

Privacy

Only the closed pypi/testpypi identifier (and the two fixed canonical index URLs it can resolve to) is ever stored, dispatched, or displayed. No credentials, arbitrary URLs, source, diffs, prompts, transcripts, raw stdout/stderr, local paths, or auth output are persisted or uploaded.

Test plan

  • New focused tests: source parsing/validation (tests/test_release_qualify.py::PackageSourceTests), local pip-command construction for both sources, campaign identity binding/idempotency-key binding, resume-mismatch rejection, backward-compatible legacy-campaign default, local adapter argv construction (tests/test_release_campaigns.py), hosted dispatch marker/body content and canonical-URL redaction, hosted-comment result binding, and the maintained-adapter CLI/prompt/sandbox-allowlist surface (tests/test_campaign_adapters.py).
  • python -m unittest discover -s tests (1451 tests, all pass)
  • python -m ruff check .
  • python scripts/privacy_scan.py
  • python -m compileall -q src scripts
  • python scripts/smoke_easy_mode.py --code-mower-bin .venv/bin/code-mower --json
  • git diff --check

Head SHA: f5bc0fd7bc6d8a4f6d56a04d53b981f7cb6601ad

🤖 Generated with Claude Code

…#713)

Support package_source values pypi (default) and testpypi across
`release qualify` and `release campaign`. testpypi installs from the
canonical TestPyPI simple index with production PyPI as a
dependency-only extra index, reusing the existing bounded pip-install
retry behavior. The source is bound into campaign identity
(idempotency key, resume-mismatch checks), local adapter argv
construction, and hosted dispatch instructions/markers; a legacy
campaign missing the field reads back as pypi. Never accepts or
persists an arbitrary URL or credential -- only the closed pypi/
testpypi vocabulary and its two fixed canonical index URLs.

CODE_MOWER_BUILDER:claude
@gitar-bot

gitar-bot Bot commented Sep 5, 2026

Copy link
Copy Markdown
Code Review ✅ Approved

Implements the closed TestPyPI candidate source contract, adding a package_source vocabulary (pypi default, testpypi) to both code-mower release qualify and code-mower release campaign. The feature threads the source through pip-install rehearsal, campaign identity/idempotency binding, dispatch instructions, resume-mismatch validation, and maintained adapter templates while storing only the closed identifier and canonical index URLs—no credentials or arbitrary URLs. Comprehensive test coverage and privacy scanning confirm no issues found.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

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

Labels

builder:claude Code Mower generated label needs-codex-audit

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant