diff --git a/TODO.md b/TODO.md index 7eac6e79..94dae5a3 100644 --- a/TODO.md +++ b/TODO.md @@ -2,6 +2,12 @@ ## Governed architecture roadmap +- [ ] Deliver [ticket-059](project/ticket-059/README.md): align the default + Python strategy and pip/pipenv descriptors with ticket-058's retry-safe + Twine contract. State: `IN_PROGRESS / PUBLICATION`; 618 tests (2 skips), + scoped Ruff and governance pass; classification: + `BUG / P1 / regression`; depends on ticket-058. + - [x] Deliver [ticket-058](project/ticket-058/README.md): make configured Twine publication retries idempotent at runtime and migrate legacy commands through doctor PY013. State: `DONE / DONE`; configuration producers and diff --git a/goal/config/constants.py b/goal/config/constants.py index 25fd1c2a..382abfea 100644 --- a/goal/config/constants.py +++ b/goal/config/constants.py @@ -232,7 +232,7 @@ "python": { "test": "pytest tests/ -v", "build": "python -m build", - "publish": "twine upload dist/{project_name}-{version}*", # placeholder, replaced on init + "publish": "twine upload --skip-existing dist/{project_name}-{version}*", # placeholder, replaced on init "publish_enabled": True, "dependencies": { "file": "requirements.txt", @@ -477,7 +477,7 @@ }, } -from goal.validators.tokens import get_default_token_patterns +from goal.validators.tokens import get_default_token_patterns # noqa: E402 DEFAULT_CONFIG["advanced"]["file_validation"]["token_patterns"] = ( get_default_token_patterns() diff --git a/goal/package_managers.py b/goal/package_managers.py index 06e9aec7..b4d5f855 100644 --- a/goal/package_managers.py +++ b/goal/package_managers.py @@ -83,7 +83,7 @@ def __post_init__(self): update_cmd="pip install --upgrade {package}", test_cmd="pytest", build_cmd="python -m build", - publish_cmd="python -m twine upload dist/*", + publish_cmd="python -m twine upload --skip-existing dist/*", run_cmd="python {command}", version_cmd="python setup.py --version", priority=1, @@ -116,7 +116,7 @@ def __post_init__(self): update_cmd="pipenv update", test_cmd="pipenv run pytest", build_cmd="pipenv run python -m build", - publish_cmd="pipenv run python -m twine upload dist/*", + publish_cmd="pipenv run python -m twine upload --skip-existing dist/*", run_cmd="pipenv run {command}", version_cmd="pipenv --version", priority=6, diff --git a/project/TICKETS.md b/project/TICKETS.md index 8da61dff..35635ff3 100644 --- a/project/TICKETS.md +++ b/project/TICKETS.md @@ -61,4 +61,5 @@ This file indexes governance tickets without taking ownership of | **ticket-056** | [`README.md`](./ticket-056/README.md) | [`preprompt.md`](./ticket-056/preprompt.md) | - | [`ai-codex.md`](./ticket-056/ai-codex.md) | [`ai-codex-logs.txt`](./ticket-056/ai-codex-logs.txt) | [`changelog.md`](./ticket-056/changelog.md) | | **ticket-057** | [`README.md`](./ticket-057/README.md) | [`preprompt.md`](./ticket-057/preprompt.md) | - | [`ai-codex.md`](./ticket-057/ai-codex.md) | [`ai-codex-logs.txt`](./ticket-057/ai-codex-logs.txt) | [`changelog.md`](./ticket-057/changelog.md) | | **ticket-058** | [`README.md`](./ticket-058/README.md) | [`preprompt.md`](./ticket-058/preprompt.md) | - | [`ai-codex.md`](./ticket-058/ai-codex.md) | [`ai-codex-logs.txt`](./ticket-058/ai-codex-logs.txt) | [`changelog.md`](./ticket-058/changelog.md) | +| **ticket-059** | [`README.md`](./ticket-059/README.md) | [`preprompt.md`](./ticket-059/preprompt.md) | - | [`ai-codex.md`](./ticket-059/ai-codex.md) | [`ai-codex-logs.txt`](./ticket-059/ai-codex-logs.txt) | [`changelog.md`](./ticket-059/changelog.md) | diff --git a/project/ticket-059/README.md b/project/ticket-059/README.md new file mode 100644 index 00000000..423eca09 --- /dev/null +++ b/project/ticket-059/README.md @@ -0,0 +1,46 @@ +# Ticket 059: Align built-in Python publish commands + +- **ID**: ticket-059 +- **Owner**: unresolved:human +- **Status**: IN_PROGRESS +- **Workflow state**: PUBLICATION +- **Created**: 2026-08-12 + +## Goal and scope + +Align every built-in Goal configuration producer with the retry-safe Twine +contract delivered by ticket-058. Fresh default configurations and the legacy +`pip` / `pipenv` package-manager descriptors must include exactly one +`--skip-existing`, so newly generated projects are safe before doctor or the +runtime boundary needs to repair them. + +## Acceptance criteria + +- [x] AC-01: The user's instruction to repair and continue records + `SESSION_EXECUTION_AUTHORIZATION` for this bounded regression fix. +- [x] AC-02: The default Python strategy emits the canonical retry-safe Twine + command. +- [x] AC-03: The `pip` and `pipenv` package-manager descriptors emit + retry-safe Twine commands without changing non-Twine managers. +- [x] AC-04: Focused/full tests, Ruff and governance pass before protected + exact-head delivery. + +## Non-goals + +- Do not change runtime normalization or doctor migration from ticket-058. +- Do not edit governance-owned `goal.yaml`; that is a dependent ticket. +- Do not change versions, dependencies or public interfaces. + +## Participants + +- Human participant: unresolved; no user-* file was created by this script. +- Agent participant: [ai-codex.md](ai-codex.md) + +## Validation evidence + +- Three focused regressions prove the default, `pip` and `pipenv` commands + contain the canonical flag exactly where expected. +- The full suite passes 618 tests with 2 existing skips; scoped Ruff, + governance (0 errors/0 warnings) and whitespace checks pass. +- The touched constants module's existing late import is now explicitly marked + `noqa: E402`; import order and runtime behavior are unchanged. diff --git a/project/ticket-059/ai-codex-logs.txt b/project/ticket-059/ai-codex-logs.txt new file mode 100644 index 00000000..0a9645bd --- /dev/null +++ b/project/ticket-059/ai-codex-logs.txt @@ -0,0 +1,5 @@ +2026-08-12T18:08:51Z ticket-059 allocated on clean accepted base d26817b4132d5a110ec0c4c9e3dc3672f94e2508 after ticket-058 closure and workspace cleanup. +2026-08-12T18:08:51Z SESSION_EXECUTION_AUTHORIZATION recorded from the user's repeated instruction to repair and continue. +2026-08-12T18:08:51Z scope: one built-in publish-configuration component containing the default Python strategy, pip/pipenv descriptors and one focused test module; governance-owned goal.yaml deferred to a dependent ticket. +2026-08-12T18:11:08Z implementation: DEFAULT_CONFIG, pip and pipenv now emit exactly one --skip-existing in their Twine upload command; non-Twine descriptors are byte-unchanged. Added three exact regression cases. +2026-08-12T18:11:08Z validation: 3 focused PASS; 618 full PASS/2 SKIP; scoped Ruff PASS; governance GOV-PASS 0 errors/0 warnings; git diff --check PASS. Existing late constants import received an explicit E402 exemption with no runtime change. diff --git a/project/ticket-059/ai-codex.md b/project/ticket-059/ai-codex.md new file mode 100644 index 00000000..0bc9dce7 --- /dev/null +++ b/project/ticket-059/ai-codex.md @@ -0,0 +1,41 @@ +--- +participant-id: agent:codex +participant: codex +role: agent +ticket: ticket-059 +--- +# Participant: codex (AI agent) + +## Understanding + +Ticket-058 guarantees safety at execution and repairs legacy repositories, but +fresh configurations still start stale because three built-in producers omit +`--skip-existing`. This ticket removes that internal inconsistency without +crossing into governance-owned `goal.yaml`. + +## Execution plan + +1. Bind the change to one producer component and three implementation files + allowed by the delivery budget. +2. Add regression assertions for the default strategy and package-manager + descriptors. +3. Run focused/full validation and deliver the exact candidate through + protected CI and Validator Agent review. + +## Actual changes + +- Initialized the bounded ticket and recorded SESSION_EXECUTION_AUTHORIZATION + from the request to execute this work. +- Kept `goal.yaml` in a separate dependent governance ticket so ownership and + implementation budgets remain enforceable. +- Updated the default Python strategy and both Twine package-manager + descriptors, with exact regressions for every producer. +- Passed 3 focused and 618 full tests (2 existing skips), scoped Ruff, + governance and whitespace validation; moved to PUBLICATION for protected + exact-head review. + +## Blockers + +- None inside the recorded intent; proceed without a second confirmation. +- New authority remains required for destructive action, secret access, new + external coordination, material objective expansion and trusted merge. diff --git a/project/ticket-059/changelog.md b/project/ticket-059/changelog.md new file mode 100644 index 00000000..5207e62f --- /dev/null +++ b/project/ticket-059/changelog.md @@ -0,0 +1,10 @@ +# Ticket Changelog (ticket-059) + +## [0.1.0] - 2026-08-12 + +- Initial governance scaffold created. +- No human participant identity or content was generated. +- Bounded the retry-safe producer alignment to default configuration and the + package-manager registry; retained `goal.yaml` as separate governance work. +- Added explicit retry safety to all three built-in Twine command producers and + exact regressions; full tests, Ruff and governance pass. diff --git a/project/ticket-059/intent.json b/project/ticket-059/intent.json new file mode 100644 index 00000000..c6e0f5a5 --- /dev/null +++ b/project/ticket-059/intent.json @@ -0,0 +1,87 @@ +{ + "schema": "new-project.intent/v3", + "ticket": "ticket-059", + "summary": "Align built-in Python publish commands", + "workstream": "application", + "classification": { + "kind": "BUG", + "priority": "P1", + "origin": "regression" + }, + "allowedPaths": [ + "goal/config/constants.py", + "goal/package_managers.py", + "tests/test_package_managers.py", + "project/ticket-059/**", + "TODO.md", + "project/TICKETS.md" + ], + "forbiddenPaths": [ + "project/ticket-*/user-*.md", + "goal.yaml", + "VERSION", + "pyproject.toml", + "uv.lock", + "goal/__init__.py", + ".github/**" + ], + "stacks": ["python"], + "dependsOn": ["ticket-058"], + "conflictsWith": [], + "integrationTicket": null, + "delivery": { + "acceptedBaseSha": "d26817b4132d5a110ec0c4c9e3dc3672f94e2508", + "targetBranch": "main", + "outcome": "Every built-in Goal producer emits retry-safe Twine upload commands", + "nonGoals": [ + "Do not change runtime or doctor behavior", + "Do not edit governance-owned Goal configuration", + "Do not change package versions or dependencies" + ], + "complexity": "S", + "estimatedMinutes": 20, + "budgets": { + "maxImplementationFiles": 3, + "maxAffectedComponents": 2, + "maxPublicInterfaceChanges": 0, + "maxRuntimeDependencies": 0 + }, + "architecture": { + "status": "accepted", + "decision": "Make retry safety explicit at each built-in configuration source while retaining ticket-058 as the final runtime defense", + "components": [ + { + "name": "built-in-publish-configuration", + "paths": [ + "goal/config/constants.py", + "goal/package_managers.py", + "tests/test_package_managers.py" + ] + } + ], + "responsibilityChanges": false, + "interfaceChanges": [], + "dataChanges": [], + "ui": {"impact": "none", "states": [], "evidence": []}, + "rollback": "Revert the bounded implementation PR; ticket-058 runtime normalization still protects execution" + }, + "runtimeDependencies": [], + "validation": [ + { + "criterion": "AC-02", + "commands": ["pytest -q tests/test_package_managers.py"], + "evidence": "project/ticket-059/ai-codex-logs.txt" + }, + { + "criterion": "AC-03", + "commands": ["pytest -q tests/test_package_managers.py"], + "evidence": "project/ticket-059/ai-codex-logs.txt" + }, + { + "criterion": "AC-04", + "commands": ["pytest -q", "ruff check scoped paths", "./project/governance-check.sh"], + "evidence": "project/ticket-059/ai-codex-logs.txt" + } + ] + } +} diff --git a/project/ticket-059/preprompt.md b/project/ticket-059/preprompt.md new file mode 100644 index 00000000..542c212d --- /dev/null +++ b/project/ticket-059/preprompt.md @@ -0,0 +1,12 @@ +# Ticket preprompt + +- **Task ID**: ticket-059 +- **Task title**: Align built-in Python publish commands +- **Created**: 2026-08-12T18:08:39Z + +Keep executable implementation outside this governance/evidence directory. +Read a human-owned user-*.md file only when one exists. +The request to execute this work creates SESSION_EXECUTION_AUTHORIZATION; +proceed within the recorded intent without a redundant confirmation prompt. +Require new authority for destructive action, secrets, external coordination, +material objective expansion and trusted merge approval. diff --git a/tests/test_package_managers.py b/tests/test_package_managers.py new file mode 100644 index 00000000..efb15db6 --- /dev/null +++ b/tests/test_package_managers.py @@ -0,0 +1,26 @@ +"""Regression tests for built-in package publication commands.""" + +import pytest + +from goal.config.constants import DEFAULT_CONFIG +from goal.package_managers import PACKAGE_MANAGERS + + +def test_default_python_publish_command_is_retry_safe(): + assert DEFAULT_CONFIG["strategies"]["python"]["publish"] == ( + "twine upload --skip-existing dist/{project_name}-{version}*" + ) + + +@pytest.mark.parametrize( + ("manager", "expected"), + [ + ("pip", "python -m twine upload --skip-existing dist/*"), + ( + "pipenv", + "pipenv run python -m twine upload --skip-existing dist/*", + ), + ], +) +def test_twine_package_manager_publish_commands_are_retry_safe(manager, expected): + assert PACKAGE_MANAGERS[manager].publish_cmd == expected