From 62cdbd1e299a36d9612fdd124127678cd8371356 Mon Sep 17 00:00:00 2001 From: Tom Softreck Date: Mon, 10 Aug 2026 12:50:17 +0200 Subject: [PATCH 1/5] plan(ticket-018): bound post-release version regression Co-authored-by: Koru Agent --- TODO.md | 6 +- project/TICKETS.md | 1 + project/ticket-018/README.md | 56 ++++++++++++++++ project/ticket-018/ai-codex-logs.txt | 6 ++ project/ticket-018/ai-codex.md | 26 ++++++++ project/ticket-018/changelog.md | 7 ++ project/ticket-018/intent.json | 98 ++++++++++++++++++++++++++++ project/ticket-018/preprompt.md | 12 ++++ 8 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 project/ticket-018/README.md create mode 100644 project/ticket-018/ai-codex-logs.txt create mode 100644 project/ticket-018/ai-codex.md create mode 100644 project/ticket-018/changelog.md create mode 100644 project/ticket-018/intent.json create mode 100644 project/ticket-018/preprompt.md diff --git a/TODO.md b/TODO.md index 32b440d..b011270 100644 --- a/TODO.md +++ b/TODO.md @@ -51,6 +51,10 @@ - [x] Deliver [ticket-017](project/ticket-017/README.md): assign the remaining atomic release metadata to integration before ticket 012 publishes. State: `DONE / PUBLICATION`; classification: `SERVICE / governance`. +- [ ] Deliver [ticket-018](project/ticket-018/README.md): infer the synchronized + version transition after a stale tag so post-publication metadata delivery + does not select a duplicate patch. State: `IN_PROGRESS / EDIT`; + classification: `BUG / application`. - [ ] After governance bootstrap, execute the sequential phases defined in [the refactoring plan](docs/GOAL_KORU_SUBACTOR_REFACTORING_PLAN.md), with one narrowly scoped ticket active at a time. @@ -60,7 +64,7 @@ > `ticket-006 DONE`; `ticket-007 DONE`; `ticket-009 DONE`. > `ticket-010 DONE`; `ticket-011 DONE`; `ticket-012 IN_PROGRESS`; > `ticket-013 DONE`; `ticket-014 CANCELLED`; `ticket-015 DONE`; -> `ticket-016 DONE`; `ticket-017 DONE`. +> `ticket-016 DONE`; `ticket-017 DONE`; `ticket-018 IN_PROGRESS`. > **Recently shipped (manual note):** `goal all [PATHS...]` monorepo sweep — > runs `goal -a` in every git repo with uncommitted changes under the given diff --git a/project/TICKETS.md b/project/TICKETS.md index 53f1681..b72f99c 100644 --- a/project/TICKETS.md +++ b/project/TICKETS.md @@ -23,4 +23,5 @@ This file indexes governance tickets without taking ownership of | **ticket-015** | [`README.md`](./ticket-015/README.md) | [`preprompt.md`](./ticket-015/preprompt.md) | - | [`ai-codex.md`](./ticket-015/ai-codex.md) | [`ai-codex-logs.txt`](./ticket-015/ai-codex-logs.txt) | [`changelog.md`](./ticket-015/changelog.md) | | **ticket-016** | [`README.md`](./ticket-016/README.md) | [`preprompt.md`](./ticket-016/preprompt.md) | - | [`ai-codex.md`](./ticket-016/ai-codex.md) | [`ai-codex-logs.txt`](./ticket-016/ai-codex-logs.txt) | [`changelog.md`](./ticket-016/changelog.md) | | **ticket-017** | [`README.md`](./ticket-017/README.md) | [`preprompt.md`](./ticket-017/preprompt.md) | - | [`ai-codex.md`](./ticket-017/ai-codex.md) | [`ai-codex-logs.txt`](./ticket-017/ai-codex-logs.txt) | [`changelog.md`](./ticket-017/changelog.md) | +| **ticket-018** | [`README.md`](./ticket-018/README.md) | [`preprompt.md`](./ticket-018/preprompt.md) | - | [`ai-codex.md`](./ticket-018/ai-codex.md) | [`ai-codex-logs.txt`](./ticket-018/ai-codex-logs.txt) | [`changelog.md`](./ticket-018/changelog.md) | diff --git a/project/ticket-018/README.md b/project/ticket-018/README.md new file mode 100644 index 0000000..f86f43e --- /dev/null +++ b/project/ticket-018/README.md @@ -0,0 +1,56 @@ +# Ticket 018: Stop post-release duplicate version bumps + +- **ID**: ticket-018 +- **Owner**: unresolved:human +- **Status**: IN_PROGRESS +- **Workflow state**: EDIT +- **Created**: 2026-08-10 +- **Work classification**: `BUG / application` + +## Goal and scope + +Prevent a metadata-only Goal run after a publish-only release from selecting +the next patch merely because the remote Git tag still names the prior release. +Committed-source analysis must recognize the commit where every managed version +carrier first reached the current version and inspect only source changes after +that boundary. A complete pre-bump ahead of the registry must continue to +request publication, and real source committed after the boundary must still +request the next release. + +## Acceptance criteria + +- [x] AC-01: Goal 2.1.290 was published from synchronized version metadata, but + a subsequent metadata-only `goal -a` reproduced a false 2.1.291 proposal. +- [ ] AC-02: When all managed carriers reached the current version after the + last tag, source already preceding that transition is not reported again. +- [ ] AC-03: Real package source committed after the transition remains + publishable, and existing pre-bump/version-resolution behavior stays green. +- [ ] AC-04: Focused history/version tests and the full Python suite pass. +- [ ] AC-05: Fresh-base governance and exact-head protected delivery pass. + +## Session authorization + +The user explicitly requested autonomous continuation, testing and publication +of the Goal version-resolution work. This directly reproduced regression is a +bounded prerequisite and proceeds without another confirmation. Trusted merge +approval remains external and exact-head bound. + +## Reproduction evidence + +After PyPI exposed 2.1.290 while the latest reachable Git tag was v2.1.289, +`goal -a --no-publish --delivery-mode pull-request` reported both +`goal/__init__.py` and the already-published `goal/publish/changes.py` as new +source and selected `normal-bump -> 2.1.291`. The generated bump was reverted +before merge in PRs #32 and #33; 2.1.291 was never published. + +## Boundary + +Only version-transition history detection, committed-source classification, +focused regression tests and this ticket's evidence may change. No package +version, dependency, registry artifact, public CLI or governance policy change +is authorized. + +## Participants + +- Human participant: unresolved; no user-* file was created. +- Agent participant: [ai-codex.md](ai-codex.md) diff --git a/project/ticket-018/ai-codex-logs.txt b/project/ticket-018/ai-codex-logs.txt new file mode 100644 index 0000000..e077964 --- /dev/null +++ b/project/ticket-018/ai-codex-logs.txt @@ -0,0 +1,6 @@ +- 2026-08-10: Reproduced false `normal-bump -> 2.1.291` after PyPI already + exposed 2.1.290 and publish-only intentionally left tag v2.1.289 reachable. +- 2026-08-10: Reverted both generated 2.1.291 changes before merge; no invalid + version was published. +- 2026-08-10: Started bounded ticket 018 under the user's autonomous execution + authorization on accepted base `d2523133bc57ef79d8d273a784fe8d97a0b8e89a`. diff --git a/project/ticket-018/ai-codex.md b/project/ticket-018/ai-codex.md new file mode 100644 index 0000000..12c7415 --- /dev/null +++ b/project/ticket-018/ai-codex.md @@ -0,0 +1,26 @@ +--- +participant-id: agent:codex +participant: codex +role: agent +ticket: ticket-018 +--- +# Participant: codex (AI agent) + +## Understanding + +The committed-source detector uses only the last reachable v* tag. In +publish-only mode Goal intentionally does not push a tag, so after PyPI catches +up the detector continues to see source already included in the published +artifact and requests another patch. + +## Execution plan + +1. Infer the synchronized current-version transition after the prior tag. +2. Start committed-source classification at that transition. +3. Cover source before and after the boundary, plus existing pre-bump behavior. +4. Run focused/full validation and deliver through exact-head PR review. + +## Blockers + +- None inside the recorded intent; proceed autonomously. +- Trusted merge approval remains external and exact-head bound. diff --git a/project/ticket-018/changelog.md b/project/ticket-018/changelog.md new file mode 100644 index 0000000..10609f9 --- /dev/null +++ b/project/ticket-018/changelog.md @@ -0,0 +1,7 @@ +# Ticket Changelog (ticket-018) + +## [0.1.0] - 2026-08-10 + +- Initialized a bounded regression ticket from the reproduced post-release + duplicate-bump evidence. +- No human participant identity or content was generated. diff --git a/project/ticket-018/intent.json b/project/ticket-018/intent.json new file mode 100644 index 0000000..b61371f --- /dev/null +++ b/project/ticket-018/intent.json @@ -0,0 +1,98 @@ +{ + "schema": "new-project.intent/v3", + "ticket": "ticket-018", + "summary": "Stop post-release duplicate version bumps", + "workstream": "application", + "classification": { + "kind": "BUG", + "priority": "P1", + "origin": "regression" + }, + "allowedPaths": [ + "goal/publish/changes.py", + "goal/cli/version_state.py", + "tests/test_committed_unreleased.py", + "project/ticket-018/**", + "TODO.md", + "project/TICKETS.md" + ], + "forbiddenPaths": ["project/ticket-*/user-*.md"], + "stacks": ["python"], + "dependsOn": ["ticket-010", "ticket-012", "ticket-016"], + "conflictsWith": [], + "integrationTicket": null, + "delivery": { + "acceptedBaseSha": "d2523133bc57ef79d8d273a784fe8d97a0b8e89a", + "targetBranch": "main", + "outcome": "Post-release metadata delivery stays on the published version while source committed after the synchronized version transition still requests a new release", + "nonGoals": [ + "No package version or registry publication", + "No tag creation or delivery-policy change", + "No dependency, manifest or public CLI change", + "No agent self-approval for merge" + ], + "complexity": "S", + "estimatedMinutes": 30, + "budgets": { + "maxImplementationFiles": 3, + "maxAffectedComponents": 2, + "maxPublicInterfaceChanges": 0, + "maxRuntimeDependencies": 0 + }, + "architecture": { + "status": "accepted", + "decision": "Derive a conservative Git boundary from the first commit after the prior tag where all managed version sources equal the current version, then classify only source after that boundary", + "components": [ + { + "name": "version-transition-evidence", + "paths": ["goal/cli/version_state.py"] + }, + { + "name": "committed-source-classifier", + "paths": [ + "goal/publish/changes.py", + "tests/test_committed_unreleased.py" + ] + } + ], + "responsibilityChanges": false, + "interfaceChanges": [], + "dataChanges": [], + "ui": { + "impact": "none", + "states": [], + "evidence": [] + }, + "rollback": "Remove the inferred transition boundary and return committed-source analysis to the last reachable release tag" + }, + "runtimeDependencies": [], + "validation": [ + { + "criterion": "AC-02", + "commands": [ + ".venv/bin/python -m pytest tests/test_committed_unreleased.py -q" + ], + "evidence": "Already-published source before a synchronized version transition is not emitted after registry catch-up" + }, + { + "criterion": "AC-03", + "commands": [ + ".venv/bin/python -m pytest tests/test_committed_unreleased.py tests/test_version_state.py -q" + ], + "evidence": "Post-transition source and pre-bumped version behavior remain detectable" + }, + { + "criterion": "AC-04", + "commands": [".venv/bin/python -m pytest tests -q"], + "evidence": "The complete Python suite passes" + }, + { + "criterion": "AC-05", + "commands": [ + "./project/governance-check.sh --base d2523133bc57ef79d8d273a784fe8d97a0b8e89a" + ], + "evidence": "Governance reports zero errors and warnings before protected delivery" + } + ] + } +} diff --git a/project/ticket-018/preprompt.md b/project/ticket-018/preprompt.md new file mode 100644 index 0000000..1751692 --- /dev/null +++ b/project/ticket-018/preprompt.md @@ -0,0 +1,12 @@ +# Ticket preprompt + +- **Task ID**: ticket-018 +- **Task title**: Stop post-release duplicate version bumps +- **Created**: 2026-08-10T10:47:00Z + +Keep executable implementation outside this governance/evidence directory. +Read a human-owned user-*.md file only when one exists. +The request to continue creates SESSION_EXECUTION_AUTHORIZATION; proceed within +the recorded intent without a redundant confirmation prompt. Require new +authority for destructive action, secrets, material objective expansion and +trusted merge approval. From 38d55d16b9fb1ffb4508c699ded0a5cb27c03fa8 Mon Sep 17 00:00:00 2001 From: Tom Softreck Date: Mon, 10 Aug 2026 12:55:27 +0200 Subject: [PATCH 2/5] fix(release): bound committed source at version transition Co-authored-by: Koru Agent --- goal/cli/version_state.py | 50 ++++++++++++++++++++++++++++ goal/publish/changes.py | 25 +++++++++++--- project/ticket-018/README.md | 19 ++++++++--- project/ticket-018/ai-codex-logs.txt | 5 +++ project/ticket-018/changelog.md | 6 ++++ tests/test_committed_unreleased.py | 22 ++++++++++++ 6 files changed, 118 insertions(+), 9 deletions(-) diff --git a/goal/cli/version_state.py b/goal/cli/version_state.py index 2ac1420..4ecccbe 100644 --- a/goal/cli/version_state.py +++ b/goal/cli/version_state.py @@ -412,6 +412,56 @@ def _version_at_ref(source: VersionSource, ref: str) -> Optional[str]: return None if contract or value is None else normalize_version(value) +def detect_version_transition_boundary( + sources: Iterable[VersionSource], base_ref: str +) -> Optional[str]: + """Find the first commit where all managed carriers reached HEAD's version. + + A publish-only delivery can leave the latest release tag behind the version + already present in the registry. The synchronized version transition then + provides a safe lower bound for committed-source analysis. Ambiguous or + incomplete history deliberately returns ``None`` so callers can fall back + to the release tag. + """ + managed = tuple( + source for source in sources if source.managed and source.value is not None + ) + current_values = {source.value for source in managed} + if len(current_values) != 1: + return None + current = next(iter(current_values)) + + if all(_version_at_ref(source, base_ref) == current for source in managed): + return None + + paths = tuple(dict.fromkeys(source.path for source in managed)) + try: + result = subprocess.run( + [ + "git", + "rev-list", + "--reverse", + "--topo-order", + f"{base_ref}..HEAD", + "--", + *paths, + ], + capture_output=True, + text=True, + ) + except OSError: + return None + if result.returncode != 0: + return None + + for commit in result.stdout.splitlines(): + if commit and all( + _version_at_ref(source, commit) == current for source in managed + ): + return commit + return None + + def detect_git_history_baseline(sources: Iterable[VersionSource]) -> Optional[str]: """Find a lower HEAD/HEAD^ value that proves a local bump already happened.""" local_values = [source.value for source in sources if source.value is not None] diff --git a/goal/publish/changes.py b/goal/publish/changes.py index 2424e13..9988761 100644 --- a/goal/publish/changes.py +++ b/goal/publish/changes.py @@ -261,14 +261,15 @@ def committed_unreleased_source_files( *, base_ref: str | None = None, ) -> list[str]: - """Package-source files committed since the last release tag. + """Package-source files committed since the newest safe release evidence. Staged-file analysis alone misses source changes that are already committed (an agent or a second `goal -a` run after a manual commit): the tree is clean, so the release is skipped while the registry stays - behind HEAD. This checks ``..HEAD`` with the same - publishable-path classifier. Returns [] when no tag exists or git fails - (callers keep the conservative skip in that case). + behind HEAD. This starts at the last release tag, or at the synchronized + current-version transition when a publish-only release left that tag + behind. Ambiguous history falls back to the tag. Returns [] when no tag + exists or git fails (callers keep the conservative skip in that case). """ registry_types = [t for t in project_types if t in REGISTRY_PROJECT_TYPES] if not registry_types: @@ -276,9 +277,23 @@ def committed_unreleased_source_files( ref = base_ref or _latest_release_tag() if not ref: return [] + effective_ref = ref + try: + from goal.cli.version_state import ( + collect_version_sources, + detect_version_transition_boundary, + ) + + transition = detect_version_transition_boundary( + collect_version_sources(), ref + ) + if transition: + effective_ref = transition + except (OSError, subprocess.SubprocessError, ValueError): + effective_ref = ref try: proc = subprocess.run( - ["git", "diff", "--name-only", f"{ref}..HEAD"], + ["git", "diff", "--name-only", f"{effective_ref}..HEAD"], capture_output=True, text=True, timeout=30, diff --git a/project/ticket-018/README.md b/project/ticket-018/README.md index f86f43e..40a0ee2 100644 --- a/project/ticket-018/README.md +++ b/project/ticket-018/README.md @@ -3,7 +3,7 @@ - **ID**: ticket-018 - **Owner**: unresolved:human - **Status**: IN_PROGRESS -- **Workflow state**: EDIT +- **Workflow state**: REVIEW - **Created**: 2026-08-10 - **Work classification**: `BUG / application` @@ -21,11 +21,11 @@ request the next release. - [x] AC-01: Goal 2.1.290 was published from synchronized version metadata, but a subsequent metadata-only `goal -a` reproduced a false 2.1.291 proposal. -- [ ] AC-02: When all managed carriers reached the current version after the +- [x] AC-02: When all managed carriers reached the current version after the last tag, source already preceding that transition is not reported again. -- [ ] AC-03: Real package source committed after the transition remains +- [x] AC-03: Real package source committed after the transition remains publishable, and existing pre-bump/version-resolution behavior stays green. -- [ ] AC-04: Focused history/version tests and the full Python suite pass. +- [x] AC-04: Focused history/version tests and the full Python suite pass. - [ ] AC-05: Fresh-base governance and exact-head protected delivery pass. ## Session authorization @@ -43,6 +43,17 @@ After PyPI exposed 2.1.290 while the latest reachable Git tag was v2.1.289, source and selected `normal-bump -> 2.1.291`. The generated bump was reverted before merge in PRs #32 and #33; 2.1.291 was never published. +## Implementation evidence + +- Managed carriers with one synchronized current value now identify the first + post-tag commit at which all of them reached that value. +- Committed-source analysis uses that transition as its effective release + boundary and conservatively falls back to the reachable tag when history is + missing or ambiguous. +- Focused regression/version tests: `27 passed`. +- Full Python suite: `510 passed, 2 skipped`. +- Fresh-base governance: `GOV-PASS` with zero errors and warnings. + ## Boundary Only version-transition history detection, committed-source classification, diff --git a/project/ticket-018/ai-codex-logs.txt b/project/ticket-018/ai-codex-logs.txt index e077964..e2fff6c 100644 --- a/project/ticket-018/ai-codex-logs.txt +++ b/project/ticket-018/ai-codex-logs.txt @@ -4,3 +4,8 @@ version was published. - 2026-08-10: Started bounded ticket 018 under the user's autonomous execution authorization on accepted base `d2523133bc57ef79d8d273a784fe8d97a0b8e89a`. +- 2026-08-10: Implemented synchronized version-transition detection and + committed-source boundary selection. +- 2026-08-10: Focused tests passed (27/27); the full Python suite passed + (510 passed, 2 skipped). +- 2026-08-10: Fresh-base governance passed with zero errors and warnings. diff --git a/project/ticket-018/changelog.md b/project/ticket-018/changelog.md index 10609f9..d5d08e2 100644 --- a/project/ticket-018/changelog.md +++ b/project/ticket-018/changelog.md @@ -5,3 +5,9 @@ - Initialized a bounded regression ticket from the reproduced post-release duplicate-bump evidence. - No human participant identity or content was generated. +- Added a conservative synchronized-version transition detector and used it as + the lower bound for committed-source release analysis. +- Added regressions for released source before the transition and new source + after it; focused tests passed 27/27. +- Full Python validation passed with 510 tests and 2 expected skips; fresh-base + governance passed with zero errors and warnings. diff --git a/tests/test_committed_unreleased.py b/tests/test_committed_unreleased.py index b146557..367dd87 100644 --- a/tests/test_committed_unreleased.py +++ b/tests/test_committed_unreleased.py @@ -26,6 +26,7 @@ def git_repo(tmp_path, monkeypatch): (tmp_path / "src").mkdir() (tmp_path / "src" / "pkg.py").write_text("x = 1\n") (tmp_path / "README.md").write_text("readme\n") + (tmp_path / "VERSION").write_text("1.0.0\n") subprocess.run(["git", "add", "-A"], check=True) subprocess.run(["git", "commit", "-qm", "init"], check=True) subprocess.run(["git", "tag", "v1.0.0"], check=True) @@ -76,3 +77,24 @@ def test_latest_release_tag_resolution(self, git_repo): _commit(git_repo, "src/pkg.py", "x = 5\n", "feat") subprocess.run(["git", "tag", "v1.1.0"], check=True) assert _latest_release_tag() == "v1.1.0" + + def test_source_before_synchronized_version_transition_is_released( + self, git_repo + ): + _commit(git_repo, "src/pkg.py", "x = 6\n", "feat: released source") + (git_repo / "VERSION").write_text("1.0.1\n") + package = git_repo / "src" / "pkg" + package.mkdir() + (package / "__init__.py").write_text('__version__ = "1.0.1"\n') + subprocess.run(["git", "add", "-A"], check=True) + subprocess.run(["git", "commit", "-qm", "release: sync 1.0.1"], check=True) + + assert committed_unreleased_source_files(["python"]) == [] + + def test_source_after_synchronized_version_transition_is_detected( + self, git_repo + ): + _commit(git_repo, "VERSION", "1.0.1\n", "release: sync 1.0.1") + _commit(git_repo, "src/pkg.py", "x = 7\n", "feat: next source") + + assert committed_unreleased_source_files(["python"]) == ["src/pkg.py"] From 7d2e9c7d77078f72c9cb83eab640465ad9e8a2db Mon Sep 17 00:00:00 2001 From: Tom Softreck Date: Mon, 10 Aug 2026 12:55:59 +0200 Subject: [PATCH 3/5] docs(ticket-018): keep implementation state through delivery Co-authored-by: Koru Agent --- project/ticket-018/README.md | 2 +- project/ticket-018/ai-codex-logs.txt | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/project/ticket-018/README.md b/project/ticket-018/README.md index 40a0ee2..18edc46 100644 --- a/project/ticket-018/README.md +++ b/project/ticket-018/README.md @@ -3,7 +3,7 @@ - **ID**: ticket-018 - **Owner**: unresolved:human - **Status**: IN_PROGRESS -- **Workflow state**: REVIEW +- **Workflow state**: EDIT - **Created**: 2026-08-10 - **Work classification**: `BUG / application` diff --git a/project/ticket-018/ai-codex-logs.txt b/project/ticket-018/ai-codex-logs.txt index e2fff6c..5ea1168 100644 --- a/project/ticket-018/ai-codex-logs.txt +++ b/project/ticket-018/ai-codex-logs.txt @@ -9,3 +9,5 @@ - 2026-08-10: Focused tests passed (27/27); the full Python suite passed (510 passed, 2 skipped). - 2026-08-10: Fresh-base governance passed with zero errors and warnings. +- 2026-08-10: The first protected-delivery attempt correctly rejected REVIEW + while implementation files were present; restored EDIT for PR delivery. From 497ebcecfec3c321547444b96125f5ecba632b2f Mon Sep 17 00:00:00 2001 From: Tom Softreck Date: Mon, 10 Aug 2026 12:56:52 +0200 Subject: [PATCH 4/5] docs(docs): configuration management system stats: lines: "+3/-3 (net +0)" files: 1 complexity: "Stable complexity" Co-authored-by: Koru Agent --- CHANGELOG.md | 5 +++++ README.md | 10 +++++----- VERSION | 2 +- goal/__init__.py | 2 +- pyproject.toml | 2 +- uv.lock | 2 +- 6 files changed, 14 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 566d5c6..ed4dae5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -173,6 +173,11 @@ sync with the real `[project]` table (e.g. version `2.1.221` vs the actual `2.1.266`) and could mislead anyone editing dependencies there, believing it had any effect. +## [2.1.291] - 2026-08-10 + +### Docs +- Update README.md + ## [2.1.290] - 2026-08-10 ### Docs diff --git a/README.md b/README.md index bc16dcb..78d9cec 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@

- Version + Version Python License PyPI @@ -23,11 +23,11 @@ ## AI Cost Tracking -![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-2.1.290-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green) -![AI Cost](https://img.shields.io/badge/AI%20Cost-$8.75-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-141.7h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fx--ai%2Fgrok--code--fast--1-lightgrey) +![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-2.1.291-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green) +![AI Cost](https://img.shields.io/badge/AI%20Cost-$1.61-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-142.3h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fx--ai%2Fgrok--code--fast--1-lightgrey) -- 🤖 **LLM usage:** $8.7470 (397 commits) -- 👤 **Human dev:** ~$14166 (141.7h @ $100/h, 30min dedup) +- 🤖 **LLM usage:** $1.6090 (402 commits) +- 👤 **Human dev:** ~$14233 (142.3h @ $100/h, 30min dedup) Generated on 2026-08-10 using [openrouter/x-ai/grok-code-fast-1](https://openrouter.ai/x-ai/grok-code-fast-1) diff --git a/VERSION b/VERSION index 713c4e6..b6d69f4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.1.290 +2.1.291 diff --git a/goal/__init__.py b/goal/__init__.py index 1916637..96a0067 100644 --- a/goal/__init__.py +++ b/goal/__init__.py @@ -1,3 +1,3 @@ """Goal - Automated git push with smart commit messages, changelog updates, and version tagging.""" -__version__ = "2.1.290" +__version__ = "2.1.291" diff --git a/pyproject.toml b/pyproject.toml index 4862be1..d183c41 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "goal" -version = "2.1.290" +version = "2.1.291" description = "Goal - Automated git push with enterprise-grade commit intelligence, smart conventional commit generation based on deep code analysis, and interactive release workflow management." readme = "README.md" authors = [ diff --git a/uv.lock b/uv.lock index 42aae0a..692c74e 100644 --- a/uv.lock +++ b/uv.lock @@ -771,7 +771,7 @@ wheels = [ [[package]] name = "goal" -version = "2.1.290" +version = "2.1.291" source = { editable = "." } dependencies = [ { name = "click" }, From a96e79f86d7c3194a0a14c5bfca41777e6d4466a Mon Sep 17 00:00:00 2001 From: Tom Softreck Date: Mon, 10 Aug 2026 12:57:44 +0200 Subject: [PATCH 5/5] fix(release): keep ticket 018 pre-release Co-authored-by: Koru Agent --- CHANGELOG.md | 5 ----- README.md | 10 +++++----- VERSION | 2 +- goal/__init__.py | 2 +- pyproject.toml | 2 +- uv.lock | 2 +- 6 files changed, 9 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed4dae5..566d5c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -173,11 +173,6 @@ sync with the real `[project]` table (e.g. version `2.1.221` vs the actual `2.1.266`) and could mislead anyone editing dependencies there, believing it had any effect. -## [2.1.291] - 2026-08-10 - -### Docs -- Update README.md - ## [2.1.290] - 2026-08-10 ### Docs diff --git a/README.md b/README.md index 78d9cec..bc16dcb 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@

- Version + Version Python License PyPI @@ -23,11 +23,11 @@ ## AI Cost Tracking -![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-2.1.291-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green) -![AI Cost](https://img.shields.io/badge/AI%20Cost-$1.61-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-142.3h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fx--ai%2Fgrok--code--fast--1-lightgrey) +![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-2.1.290-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green) +![AI Cost](https://img.shields.io/badge/AI%20Cost-$8.75-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-141.7h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fx--ai%2Fgrok--code--fast--1-lightgrey) -- 🤖 **LLM usage:** $1.6090 (402 commits) -- 👤 **Human dev:** ~$14233 (142.3h @ $100/h, 30min dedup) +- 🤖 **LLM usage:** $8.7470 (397 commits) +- 👤 **Human dev:** ~$14166 (141.7h @ $100/h, 30min dedup) Generated on 2026-08-10 using [openrouter/x-ai/grok-code-fast-1](https://openrouter.ai/x-ai/grok-code-fast-1) diff --git a/VERSION b/VERSION index b6d69f4..713c4e6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.1.291 +2.1.290 diff --git a/goal/__init__.py b/goal/__init__.py index 96a0067..1916637 100644 --- a/goal/__init__.py +++ b/goal/__init__.py @@ -1,3 +1,3 @@ """Goal - Automated git push with smart commit messages, changelog updates, and version tagging.""" -__version__ = "2.1.291" +__version__ = "2.1.290" diff --git a/pyproject.toml b/pyproject.toml index d183c41..4862be1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "goal" -version = "2.1.291" +version = "2.1.290" description = "Goal - Automated git push with enterprise-grade commit intelligence, smart conventional commit generation based on deep code analysis, and interactive release workflow management." readme = "README.md" authors = [ diff --git a/uv.lock b/uv.lock index 692c74e..42aae0a 100644 --- a/uv.lock +++ b/uv.lock @@ -771,7 +771,7 @@ wheels = [ [[package]] name = "goal" -version = "2.1.291" +version = "2.1.290" source = { editable = "." } dependencies = [ { name = "click" },