From 34a3f2518c10b7d19ab08b7585dcf938ce1794b5 Mon Sep 17 00:00:00 2001 From: Daniel Petty Date: Wed, 4 Nov 2026 15:57:13 +0000 Subject: [PATCH 1/2] test(roadmap): hold the delivery title guard before the write (#3368) --- .../.openspec.yaml | 0 .../design.md | 2 +- .../proposal.md | 2 +- .../tasks.md | 4 +- tests/roadmap/test_roadmap_implement_job.py | 54 +++++++++++++++++++ 5 files changed, 58 insertions(+), 4 deletions(-) rename openspec/changes/{3368-stop-a-delivery-title-that-the => archive/2026-11-04-3368-stop-a-delivery-title-that-the}/.openspec.yaml (100%) rename openspec/changes/{3368-stop-a-delivery-title-that-the => archive/2026-11-04-3368-stop-a-delivery-title-that-the}/design.md (77%) rename openspec/changes/{3368-stop-a-delivery-title-that-the => archive/2026-11-04-3368-stop-a-delivery-title-that-the}/proposal.md (93%) rename openspec/changes/{3368-stop-a-delivery-title-that-the => archive/2026-11-04-3368-stop-a-delivery-title-that-the}/tasks.md (85%) diff --git a/openspec/changes/3368-stop-a-delivery-title-that-the/.openspec.yaml b/openspec/changes/archive/2026-11-04-3368-stop-a-delivery-title-that-the/.openspec.yaml similarity index 100% rename from openspec/changes/3368-stop-a-delivery-title-that-the/.openspec.yaml rename to openspec/changes/archive/2026-11-04-3368-stop-a-delivery-title-that-the/.openspec.yaml diff --git a/openspec/changes/3368-stop-a-delivery-title-that-the/design.md b/openspec/changes/archive/2026-11-04-3368-stop-a-delivery-title-that-the/design.md similarity index 77% rename from openspec/changes/3368-stop-a-delivery-title-that-the/design.md rename to openspec/changes/archive/2026-11-04-3368-stop-a-delivery-title-that-the/design.md index f70327942..39371916a 100644 --- a/openspec/changes/3368-stop-a-delivery-title-that-the/design.md +++ b/openspec/changes/archive/2026-11-04-3368-stop-a-delivery-title-that-the/design.md @@ -3,7 +3,7 @@ ## Decisions - **Put both tests in `tests/roadmap/test_roadmap_implement_job.py`, beside the #3319 test.** The guard is one function, `_delivery_title`, and its tests belong in the module that already holds the refused-title test, so a reader sees every case together and no new module mirrors one helper. -- **Use `planned_world` for the first-push case and assert that `origin` holds no branch, not that the job deletes one.** `_publish` calls `_delivery_title` before `_push`, so a refused title stops the item before the branch reaches `origin`; a deletion assertion would describe code that no longer exists. +- **Use `planned_world` for the first-push case and edit the target title after the plan.** The plan judge already refuses a Planned item whose issue title has no type (`stage_left_title_type`), so the test keeps a valid title at plan time and replaces the title in the planned target. This holds the `_publish` guard itself: the item stops before the push and `origin` holds no branch, which a deletion assertion would not describe. - **Set `skip_specs: true` and write no spec delta.** The change adds tests for behavior that `openspec/specs/roadmap-implement-job/spec.md` already states in the requirement `The pull request that delivers the code has the type of the issue`, and a test changes no behavior that a consumer observes. ## Rejected alternatives diff --git a/openspec/changes/3368-stop-a-delivery-title-that-the/proposal.md b/openspec/changes/archive/2026-11-04-3368-stop-a-delivery-title-that-the/proposal.md similarity index 93% rename from openspec/changes/3368-stop-a-delivery-title-that-the/proposal.md rename to openspec/changes/archive/2026-11-04-3368-stop-a-delivery-title-that-the/proposal.md index 356403adb..2ab81549b 100644 --- a/openspec/changes/3368-stop-a-delivery-title-that-the/proposal.md +++ b/openspec/changes/archive/2026-11-04-3368-stop-a-delivery-title-that-the/proposal.md @@ -7,7 +7,7 @@ The implement job must stop an item whose delivery title the pull request form r ## What Changes - Add a test to `tests/roadmap/test_roadmap_implement_job.py` for an issue title `wip(cli): add a flag`, whose type `wip` the project does not declare: the job stops the item and writes no pull request title. -- Add a test for a Planned item whose delivery title has no type: the job stops before `_publish` pushes the branch, so `origin` holds no branch and no draft pull request exists. +- Add a test for a Planned item whose delivery title has no type, with the title edited in the planned target because the plan judge already refuses such an issue title: the job stops before `_publish` pushes the branch, so `origin` holds no branch and no draft pull request exists. - The change alters no behavior that a consumer observes, because it adds tests for behavior that `openspec/specs/roadmap-implement-job/spec.md` already states. It has no spec delta and sets `skip_specs: true`. - The change fits one pull request. diff --git a/openspec/changes/3368-stop-a-delivery-title-that-the/tasks.md b/openspec/changes/archive/2026-11-04-3368-stop-a-delivery-title-that-the/tasks.md similarity index 85% rename from openspec/changes/3368-stop-a-delivery-title-that-the/tasks.md rename to openspec/changes/archive/2026-11-04-3368-stop-a-delivery-title-that-the/tasks.md index 3c5a537a6..5f5fc4397 100644 --- a/openspec/changes/3368-stop-a-delivery-title-that-the/tasks.md +++ b/openspec/changes/archive/2026-11-04-3368-stop-a-delivery-title-that-the/tasks.md @@ -4,9 +4,9 @@ Reads: `src/devops_cli/roadmap/implement_run.py`, `src/devops_cli/roadmap/pull_form.py`, `tests/roadmap/test_roadmap_implement_job.py`. Changes: `tests/roadmap/test_roadmap_implement_job.py`. -- [ ] 1.1 Add a test for an issue title `wip(cli): add a flag`, whose type the project does not declare, and assert the job stops the item and writes no pull request title +- [x] 1.1 Add a test for an issue title `wip(cli): add a flag`, whose type the project does not declare, and assert the job stops the item and writes no pull request title - Verification: `uv run devops ci test tests/roadmap/test_roadmap_implement_job.py` -- [ ] 1.2 Add a test for a Planned item whose delivery title has no type, and assert the job stops before `_publish` pushes, so `origin` holds no branch and no draft pull request exists +- [x] 1.2 Add a test for a Planned item whose delivery title has no type, and assert the job stops before `_publish` pushes, so `origin` holds no branch and no draft pull request exists - Verification: `uv run devops ci test tests/roadmap/test_roadmap_implement_job.py` ## Workflow follow-up diff --git a/tests/roadmap/test_roadmap_implement_job.py b/tests/roadmap/test_roadmap_implement_job.py index 01c153b3d..2d7e4c93e 100644 --- a/tests/roadmap/test_roadmap_implement_job.py +++ b/tests/roadmap/test_roadmap_implement_job.py @@ -12,6 +12,7 @@ import shutil import subprocess from collections.abc import Callable +from dataclasses import replace from pathlib import Path import pytest @@ -283,6 +284,59 @@ def test_a_title_that_the_check_refuses_stops_the_item_before_the_job_writes_it( assert "not in the form" in job_world.issue_comments()[0] +def test_a_title_with_a_type_that_the_project_does_not_declare_stops_the_item( + job_world: JobWorld, +) -> None: + """A person may edit the issue title after staging (#3368). The implement job reads the title + again when it publishes, and a type the project does not declare fails the check + `Semantic PR title`, so the job stops before it writes the title.""" + issue = job_world.store._roadmap.issues[1] + job_world.store._roadmap.issues[1] = issue.model_copy(update={"title": "wip(cli): add a flag"}) + + applied = job_world.run(two_groups()) + + status, record = _item(job_world) + assert (applied.stopped, status, record.get("implement.stopped")) == ( + (1,), + "Blocked", + "pull request", + ) + assert job_world.sent("PATCH", f"pulls/{PULL}") == [] + assert "The type `wip` is not a type of the project" in job_world.issue_comments()[0] + + +def test_a_planned_item_with_a_title_that_has_no_type_stops_before_the_first_push( + planned_world: JobWorld, +) -> None: + """A person may edit the issue title after the plan reads it (#3368). The delivery title of a + Planned item must pass the check before the first push, so a title with no Conventional Commit + type stops the item before any branch reaches `origin` and no draft pull request exists.""" + plan = planned_world.plan() + (target,) = plan.selected + edited = replace( + plan, + selected=(replace(target, item=target.item.model_copy(update={"title": "Add a flag"})),), + ) + + applied = apply_implement( + planned_world.store, + edited, + source=planned_world.repo.clone, + model=two_groups().model(), + window=WINDOW, + ) + + status, record = _item(planned_world) + assert (applied.stopped, status, record.get("implement.stopped")) == ( + (1,), + "Blocked", + "push", + ) + assert planned_world.repo.origin_git("branch", "--list", BRANCH) == "" + assert not any(request.method == "POST" for request in planned_world.api.sent) + assert "not in the form" in planned_world.issue_comments()[0] + + def test_the_changes_of_the_archive_and_the_documents_are_in_the_pushed_tree( job_world: JobWorld, ) -> None: From eb5ec8ce0d9ecda8e00e5216bbe78bf7e766eb63 Mon Sep 17 00:00:00 2001 From: Daniel Petty Date: Wed, 4 Nov 2026 16:44:29 +0000 Subject: [PATCH 2/2] test(roadmap): assert the title stop names the refused title (#3368) --- tests/roadmap/test_roadmap_implement_job.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/roadmap/test_roadmap_implement_job.py b/tests/roadmap/test_roadmap_implement_job.py index 2d7e4c93e..32fc0553a 100644 --- a/tests/roadmap/test_roadmap_implement_job.py +++ b/tests/roadmap/test_roadmap_implement_job.py @@ -302,7 +302,9 @@ def test_a_title_with_a_type_that_the_project_does_not_declare_stops_the_item( "pull request", ) assert job_world.sent("PATCH", f"pulls/{PULL}") == [] - assert "The type `wip` is not a type of the project" in job_world.issue_comments()[0] + comment = job_world.issue_comments()[0] + assert "The type `wip` is not a type of the project" in comment + assert "The title is `wip(cli): add a flag`." in comment def test_a_planned_item_with_a_title_that_has_no_type_stops_before_the_first_push( @@ -334,7 +336,9 @@ def test_a_planned_item_with_a_title_that_has_no_type_stops_before_the_first_pus ) assert planned_world.repo.origin_git("branch", "--list", BRANCH) == "" assert not any(request.method == "POST" for request in planned_world.api.sent) - assert "not in the form" in planned_world.issue_comments()[0] + comment = planned_world.issue_comments()[0] + assert "not in the form" in comment + assert "The title is `Add a flag: `." in comment def test_the_changes_of_the_archive_and_the_documents_are_in_the_pushed_tree(