From 208d4168e5a02b994905e94d648599d06b4afbd2 Mon Sep 17 00:00:00 2001 From: Matthew Berman <748450+mberman84@users.noreply.github.com> Date: Sun, 21 Jun 2026 19:25:16 -0700 Subject: [PATCH 1/2] Prevent recursive nested integration promotion --- .../claude-code/.claude-plugin/plugin.json | 2 +- .../.codex-plugin/plugin.json | 2 +- docs/reference.md | 2 +- pyproject.toml | 2 +- src/agent_merge_queue/__init__.py | 2 +- src/agent_merge_queue/cli.py | 6 ++++ tests/test_cli.py | 36 +++++++++++++++++++ 7 files changed, 47 insertions(+), 5 deletions(-) diff --git a/adapters/claude-code/.claude-plugin/plugin.json b/adapters/claude-code/.claude-plugin/plugin.json index d8a8dc6..c89b1fc 100644 --- a/adapters/claude-code/.claude-plugin/plugin.json +++ b/adapters/claude-code/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "deploybot", - "version": "0.2.17", + "version": "0.2.18", "description": "DeployBot: a provider-neutral GitHub merge queue for coding agents", "author": { "name": "DeployBot contributors" diff --git a/adapters/codex/agent-merge-queue/.codex-plugin/plugin.json b/adapters/codex/agent-merge-queue/.codex-plugin/plugin.json index 38b3a6c..8073367 100644 --- a/adapters/codex/agent-merge-queue/.codex-plugin/plugin.json +++ b/adapters/codex/agent-merge-queue/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "deploybot", - "version": "0.2.17", + "version": "0.2.18", "description": "Coordinate exact-head pull requests through verified deployment and thread notification", "author": { "name": "DeployBot contributors" diff --git a/docs/reference.md b/docs/reference.md index 7b8d89e..d92b6e9 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1,7 +1,7 @@ # DeployBot reference This reference describes the CLI, MCP server, policy file, and GitHub Action in -DeployBot v0.2.17. GitHub labels and authenticated comments are the durable state; +DeployBot v0.2.18. GitHub labels and authenticated comments are the durable state; the CLI and MCP tools are two interfaces to the same operations. ## CLI diff --git a/pyproject.toml b/pyproject.toml index b40f7a1..f4b247d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "deploybot-merge-queue" -version = "0.2.17" +version = "0.2.18" description = "DeployBot: a provider-neutral GitHub merge queue for coding agents" readme = "README.md" license = "MIT" diff --git a/src/agent_merge_queue/__init__.py b/src/agent_merge_queue/__init__.py index 357d8e5..ef0b3b1 100644 --- a/src/agent_merge_queue/__init__.py +++ b/src/agent_merge_queue/__init__.py @@ -1,3 +1,3 @@ """DeployBot: a provider-neutral GitHub merge queue for coding agents.""" -__version__ = "0.2.17" +__version__ = "0.2.18" diff --git a/src/agent_merge_queue/cli.py b/src/agent_merge_queue/cli.py index 04e567e..27e4575 100755 --- a/src/agent_merge_queue/cli.py +++ b/src/agent_merge_queue/cli.py @@ -3290,7 +3290,13 @@ def promote_integrations( known_checks_by_number: dict[int, dict[str, str]] | None = None, ) -> list[int]: promoted: list[int] = [] + delegated_integrations = client.active_integration_sources() for number in client.integration_pull_request_numbers(): + # A newer cumulative PR owns any integration PR listed among its + # sources. Re-promoting that nested source would recursively integrate + # the same frozen work into another cumulative PR. + if number in delegated_integrations: + continue comments = client.comments(number) integration = latest_payload( comments, diff --git a/tests/test_cli.py b/tests/test_cli.py index 0ece816..bb065c7 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -4706,6 +4706,7 @@ def test_integration_promotion_reuses_owned_exact_checks(self) -> None: client.config = CONFIG client.coordinator_logins = {"coordinator"} client.integration_pull_request_numbers.return_value = [number] + client.active_integration_sources.return_value = set() client.comments.return_value = [ { "created_at": "2026-06-20T00:00:00Z", @@ -4732,6 +4733,41 @@ def test_integration_promotion_reuses_owned_exact_checks(self) -> None: known_checks={"CI": "passed"}, ) + def test_integration_promotion_skips_nested_source_integrations(self) -> None: + nested = 38 + canonical = 39 + marker = { + "batch_id": "batch", + "conflict": None, + "heads": {str(nested): "a" * 40}, + "pull_requests": [nested], + } + client = Mock() + client.config = CONFIG + client.coordinator_logins = {"coordinator"} + client.integration_pull_request_numbers.return_value = [nested, canonical] + client.active_integration_sources.return_value = {nested} + client.comments.return_value = [ + { + "created_at": "2026-06-20T00:00:00Z", + "user": {"login": "coordinator"}, + "body": integration_body(marker), + } + ] + client.labels.return_value = set() + ready = entry(canonical, "combined.py") + client.snapshot.return_value = ready + + promoted = promote_integrations(client) + + self.assertEqual(promoted, [canonical]) + client.snapshot.assert_called_once_with( + canonical, + require_marker=False, + allow_blocked_label=True, + known_checks=None, + ) + def test_reactor_pauses_when_post_merge_ci_dispatch_fails(self) -> None: client = Mock() client.config = CONFIG From 706dee5ac3f4ea536c1ddd97392394f571ed4559 Mon Sep 17 00:00:00 2001 From: Matthew Berman <748450+mberman84@users.noreply.github.com> Date: Sun, 21 Jun 2026 19:25:42 -0700 Subject: [PATCH 2/2] Pin DeployBot v0.2.18 runtime --- README.md | 6 +++--- adapters/claude-code/.mcp.json | 2 +- adapters/cursor/.cursor/mcp.json | 2 +- examples/github-workflow.yml | 4 ++-- tests/test_skill.py | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b3d44f7..5936d00 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,11 @@ integration PRs, follows `main` through production, and pauses after failures. ## Install -Install the reviewed `v0.2.17` source commit directly from GitHub: +Install the reviewed `v0.2.18` source commit directly from GitHub: ```bash python3 -m pip install \ - 'deploybot-merge-queue[mcp] @ git+https://github.com/Forward-Future/DeployBot.git@7842edbd5fe75cdb68324e98c2a7244aed3009f6' + 'deploybot-merge-queue[mcp] @ git+https://github.com/Forward-Future/DeployBot.git@208d4168e5a02b994905e94d648599d06b4afbd2' deploybot init ``` @@ -95,7 +95,7 @@ worker can dispatch deployment when GitHub suppresses the `workflow_run` event for token-dispatched CI. Pin the Action to the full reviewed release commit: ```yaml -- uses: Forward-Future/DeployBot@7842edbd5fe75cdb68324e98c2a7244aed3009f6 +- uses: Forward-Future/DeployBot@208d4168e5a02b994905e94d648599d06b4afbd2 ``` The Action uses GitHub's built-in workflow token. GitHub intentionally does not diff --git a/adapters/claude-code/.mcp.json b/adapters/claude-code/.mcp.json index b270d6c..458d69e 100644 --- a/adapters/claude-code/.mcp.json +++ b/adapters/claude-code/.mcp.json @@ -4,7 +4,7 @@ "command": "uvx", "args": [ "--from", - "deploybot-merge-queue[mcp] @ git+https://github.com/Forward-Future/DeployBot.git@7842edbd5fe75cdb68324e98c2a7244aed3009f6", + "deploybot-merge-queue[mcp] @ git+https://github.com/Forward-Future/DeployBot.git@208d4168e5a02b994905e94d648599d06b4afbd2", "deploybot-mcp" ] } diff --git a/adapters/cursor/.cursor/mcp.json b/adapters/cursor/.cursor/mcp.json index b270d6c..458d69e 100644 --- a/adapters/cursor/.cursor/mcp.json +++ b/adapters/cursor/.cursor/mcp.json @@ -4,7 +4,7 @@ "command": "uvx", "args": [ "--from", - "deploybot-merge-queue[mcp] @ git+https://github.com/Forward-Future/DeployBot.git@7842edbd5fe75cdb68324e98c2a7244aed3009f6", + "deploybot-merge-queue[mcp] @ git+https://github.com/Forward-Future/DeployBot.git@208d4168e5a02b994905e94d648599d06b4afbd2", "deploybot-mcp" ] } diff --git a/examples/github-workflow.yml b/examples/github-workflow.yml index fa34934..bb44ae7 100644 --- a/examples/github-workflow.yml +++ b/examples/github-workflow.yml @@ -59,5 +59,5 @@ jobs: with: ref: ${{ github.event.repository.default_branch }} persist-credentials: false - # v0.2.17 implementation; keep the full commit for privileged workflows. - - uses: Forward-Future/DeployBot@7842edbd5fe75cdb68324e98c2a7244aed3009f6 + # v0.2.18 implementation; keep the full commit for privileged workflows. + - uses: Forward-Future/DeployBot@208d4168e5a02b994905e94d648599d06b4afbd2 diff --git a/tests/test_skill.py b/tests/test_skill.py index 051b31b..f517d2a 100644 --- a/tests/test_skill.py +++ b/tests/test_skill.py @@ -8,7 +8,7 @@ ROOT = Path(__file__).resolve().parents[1] CANONICAL = ROOT / "skills" / "deploybot" / "SKILL.md" -RELEASE_COMMIT = "7842edbd5fe75cdb68324e98c2a7244aed3009f6" +RELEASE_COMMIT = "208d4168e5a02b994905e94d648599d06b4afbd2" CHECKOUT_COMMIT = "9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0"