From 7bd3bba6a22c59f1c3f287de9ba873a724d70196 Mon Sep 17 00:00:00 2001 From: Vinh Trinh Date: Tue, 22 Sep 2026 08:54:23 -0400 Subject: [PATCH 1/2] fix(deploy): up says an older release's deployment is still running and billing (BE-16743) A new release gets a new deployment and the old one keeps billing. up already listed those deployments in the JSON supersedes array, but the terminal said nothing. It now warns once per deployment with the stop command to run. --- CHANGELOG.md | 5 ++++ comfy_cli/command/deploy_up.py | 10 +++++++ comfy_cli/skills/comfy-deploy/SKILL.md | 5 ++-- tests/comfy_cli/command/test_deploy_up.py | 36 +++++++++++++++++++++++ 4 files changed, 54 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac43c47b5..8b23d5347 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,11 @@ history. ### Fixed +- `comfy deploy up` on a new release now warns about the Build's older + deployments that are still running and billing, one line each with the + `comfy deploy stop --deployment ` to run. It already listed them in the + JSON `supersedes` array; the terminal said nothing, so the old deployment kept + billing unnoticed. Under `--json` the warning goes to stderr. - `insert_workflow` (`comfy workflow insert-workflow`) now rebases the inserted template beside the target graph's existing nodes instead of leaving its original absolute `pos` values untouched, which could land it thousands of diff --git a/comfy_cli/command/deploy_up.py b/comfy_cli/command/deploy_up.py index 124beeeb3..e619e6709 100644 --- a/comfy_cli/command/deploy_up.py +++ b/comfy_cli/command/deploy_up.py @@ -217,6 +217,16 @@ def _render_result(renderer, result: UpResult, *, watch: bool) -> None: if status == "stop_failed" else f"run `comfy deploy scale --deployment {deployment_id} --min --max ` to change them", ) + # A new release gets a new deployment, so the old one keeps billing. The + # JSON envelope carries `supersedes`; a person reading the terminal needs it + # said, on stderr under --json as with every other warning here. + for row in result.supersedes: + old_id = row["id"] + version = row["release"]["version"] + renderer.warn( + f"Deployment {old_id} (release v{version}, {row['status']}) is still running and billing.", + hint=f"run `comfy deploy stop --deployment {old_id}` if you no longer need it", + ) terminal = status in {"failed", "stopped", "stop_failed", "unhealthy"} renderer.emit( result.payload(), diff --git a/comfy_cli/skills/comfy-deploy/SKILL.md b/comfy_cli/skills/comfy-deploy/SKILL.md index ee9d08e6c..665676866 100644 --- a/comfy_cli/skills/comfy-deploy/SKILL.md +++ b/comfy_cli/skills/comfy-deploy/SKILL.md @@ -73,8 +73,9 @@ running and keeps billing. The CLI tells you this: `up` returns a `supersedes` array naming every other live deployment of this Build still holding compute, with its id, status and -release version. **Read it and act on it.** An empty array means nothing else is -running; a non-empty one is a bill the user has not agreed to. +release version, and prints a "still running and billing" warning for each +(on stderr under `--json`). **Read it and act on it.** An empty array means +nothing else is running; a non-empty one is a bill the user has not agreed to. ```shell comfy deploy up # note `supersedes` in the output diff --git a/tests/comfy_cli/command/test_deploy_up.py b/tests/comfy_cli/command/test_deploy_up.py index 401809afd..17e6e0554 100644 --- a/tests/comfy_cli/command/test_deploy_up.py +++ b/tests/comfy_cli/command/test_deploy_up.py @@ -473,6 +473,42 @@ def test_a_stop_failed_deployment_is_not_pointed_at_a_scale_that_would_bounce(tm assert "comfy deploy stop --deployment" in result.stderr +def test_up_warns_that_an_older_release_deployment_is_still_billing(tmp_path, monkeypatch) -> None: + """A new release gets a new deployment and the old one keeps billing. Only + the JSON `supersedes` array said so; the terminal has to say it too.""" + # Given a ready deployment on release 3 and the live one on release 5 + module = _deploy() + releases = [ + {"id": "release-5", "buildId": "build-1", "version": 5, "deployable": True}, + {"id": "release-3", "buildId": "build-1", "version": 3, "deployable": True}, + ] + client = FakeDeploy([deployment("dep-live"), deployment("dep-old", release_id="release-3", status="ready")]) + monkeypatch.setattr(module, "_command_clients", lambda: (FakeBuilder(releases), client)) + + # When + result = CliRunner().invoke(app, ["--json", "deploy", "up", str(write_spec(tmp_path))]) + + # Then the old deployment is named with the command that stops it + assert result.exit_code == 0, result.stderr + assert "Deployment dep-old (release v3, ready) is still running and billing." in result.stderr + assert "comfy deploy stop --deployment dep-old" in result.stderr + assert [row["id"] for row in _json_envelope(result)["data"]["supersedes"]] == ["dep-old"] + + +def test_up_with_nothing_else_running_prints_no_billing_warning(tmp_path, monkeypatch) -> None: + # Given only the live deployment of this release + module = _deploy() + monkeypatch.setattr(module, "_command_clients", lambda: (FakeBuilder(), FakeDeploy([deployment("dep-live")]))) + + # When + result = CliRunner().invoke(app, ["--json", "deploy", "up", str(write_spec(tmp_path))]) + + # Then + assert result.exit_code == 0, result.stderr + assert "still running and billing" not in result.stderr + assert _json_envelope(result)["data"]["supersedes"] == [] + + def test_reconcile_rejects_an_immutable_gpu_change() -> None: # Given module = _deploy() From fe9209eabda05835d8e17029d3420f5c64fcf409 Mon Sep 17 00:00:00 2001 From: Vinh Trinh Date: Tue, 22 Sep 2026 09:03:17 -0400 Subject: [PATCH 2/2] test(deploy): a person at the terminal sees the billing warning (BE-16743) --- CHANGELOG.md | 11 ++++++----- tests/comfy_cli/command/test_deploy_up.py | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b23d5347..bd47290e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,11 +75,12 @@ history. ### Fixed -- `comfy deploy up` on a new release now warns about the Build's older - deployments that are still running and billing, one line each with the - `comfy deploy stop --deployment ` to run. It already listed them in the - JSON `supersedes` array; the terminal said nothing, so the old deployment kept - billing unnoticed. Under `--json` the warning goes to stderr. +- `comfy deploy up` now warns about each deployment of an older release of the + Build that is still running and billing, with the + `comfy deploy stop --deployment ` to run. `up` on a new release creates a + new deployment and leaves the old one running; the JSON `supersedes` array + already listed it, but the terminal said nothing. Under `--json` the warning + goes to stderr. - `insert_workflow` (`comfy workflow insert-workflow`) now rebases the inserted template beside the target graph's existing nodes instead of leaving its original absolute `pos` values untouched, which could land it thousands of diff --git a/tests/comfy_cli/command/test_deploy_up.py b/tests/comfy_cli/command/test_deploy_up.py index 17e6e0554..10b1dccd6 100644 --- a/tests/comfy_cli/command/test_deploy_up.py +++ b/tests/comfy_cli/command/test_deploy_up.py @@ -495,6 +495,27 @@ def test_up_warns_that_an_older_release_deployment_is_still_billing(tmp_path, mo assert [row["id"] for row in _json_envelope(result)["data"]["supersedes"]] == ["dep-old"] +def test_a_person_at_the_terminal_sees_the_billing_warning(tmp_path, monkeypatch) -> None: + # Given a ready deployment on release 3 and the live one on release 5 + module = _deploy() + releases = [ + {"id": "release-5", "buildId": "build-1", "version": 5, "deployable": True}, + {"id": "release-3", "buildId": "build-1", "version": 3, "deployable": True}, + ] + client = FakeDeploy([deployment("dep-live"), deployment("dep-old", release_id="release-3", status="ready")]) + monkeypatch.setattr(module, "_command_clients", lambda: (FakeBuilder(releases), client)) + + # When run with human output + result = CliRunner().invoke(app, ["deploy", "up", str(write_spec(tmp_path))], env={"COMFY_OUTPUT": "pretty"}) + + # Then the warning is on stdout, after the deployment's own line + assert result.exit_code == 0, result.stderr + assert result.stdout.index("Deployment dep-live: ready") < result.stdout.index( + "Deployment dep-old (release v3, ready) is still running and billing." + ) + assert "comfy deploy stop --deployment dep-old" in result.stdout + + def test_up_with_nothing_else_running_prints_no_billing_warning(tmp_path, monkeypatch) -> None: # Given only the live deployment of this release module = _deploy()