Skip to content

fix: push variant renames and default switches to the platform - #297

Merged
Ruari-Phipps merged 1 commit into
mainfrom
fix/variant-rename
Sep 1, 2026
Merged

fix: push variant renames and default switches to the platform#297
Ruari-Phipps merged 1 commit into
mainfrom
fix/variant-rename

Conversation

@Ruari-Phipps

@Ruari-Phipps Ruari-Phipps commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Summary

Renaming a variant to a name with the same "clean name" (e.g. only the punctuation changes) was silently dropped on push, and a new variant marked is_default never actually became the default. Both are fixed, and set-default command emission moves out of queue_resources into _stage_commands.

Motivation

Variant.file_path is derived from clean_name(), which maps punctuation and whitespace to _. So renaming a variant from My Variant - Prod to My_Variant - Prod keeps the same path: the variant is treated as kept rather than delete+create, and its changed hash puts it in updated_resources. But Variant.build_update_proto returned Variant_SetDefaultVariant, which has no name field, so the rename never reached the platform — while local state and file_structure_info were rewritten as if the push had succeeded, leaving local and remote permanently out of sync with no error.

Separately, Variant_CreateVariant has no is_default field, and the only thing emitting a set-default command was the update path, which new resources never reach. A variant created with is_default: true therefore never became the default.

prepush.filter_nondefault_variant_updates dropped every update for a non-default variant. That was only safe because "update" literally meant "set default"; once updates carry a name it would suppress legitimate renames, so it is removed.

Changes

  • Variant.update_command_type is now variant_update_variant, and build_update_proto returns Variant_UpdateVariant(id, name), so renames reach the platform.
  • attribute_values on that proto is deliberately left unset. The platform only rewrites a variant's attribute values when the field is present, and a present map must cover every non-archived attribute or the command is rejected — sending it would risk wiping values. There is a regression test guarding this.
  • Set-default emission moves out of AgentStudioInterface.queue_resources into queue_set_default_commands in poly/utils/commands.py, called at the end of AgentStudioProject._stage_commands, for both handoffs and variants. It has to run after the creates and updates, because the platform rejects a set-default for a resource that does not exist yet. This is what fixes the new-default-variant case.
  • queue_resources goes back to being purely generic (deletes → creates → updates, duck-typed on *_command_type / build_*_proto) with no per-resource-type knowledge.
  • prepush.filter_nondefault_variant_updates removed, along with its call site and a stale docstring line.
  • New create_command_handoff_set_default / create_command_variant_set_default builders alongside the existing standalone command builders.

Test strategy

  • Added/updated unit tests
  • Manual CLI testing (poly <command>)
  • Tested against a live Agent Studio project
  • N/A (docs, config, or trivial change)

Checklist

  • ruff check . and ruff format --check . pass
  • pytest passes
  • No breaking changes to the poly CLI interface (or migration path documented)
  • Commit messages follow conventional commits

Screenshots / Logs

ruff check .          All checks passed!
ruff format --check . 95 files already formatted
pytest                1445 passed, 117 subtests passed

🤖 Generated with Claude Code

Renaming a variant to a name with the same "clean name" (e.g. only
punctuation changes) never reached the platform. Variant.file_path is
derived from clean_name(), which maps punctuation and whitespace to "_",
so such a rename keeps the same path: the variant is treated as kept
rather than delete+create, and its changed hash puts it in
updated_resources. But build_update_proto returned
Variant_SetDefaultVariant, which has no name field, so the rename was
dropped while local state was rewritten as if the push had succeeded.

Variant updates now send Variant_UpdateVariant(id, name).
attribute_values is deliberately left unset: the platform only rewrites a
variant's attribute values when that field is present, and a present map
must cover every non-archived attribute or the command is rejected.

This also fixes a new variant marked is_default never becoming the
default, since Variant_CreateVariant has no is_default field and only the
update path emitted a set-default command.

Set-default emission moves out of AgentStudioInterface.queue_resources
into queue_set_default_commands, called at the end of _stage_commands, for
both handoffs and variants. It has to run after the creates and updates
because the platform rejects a set-default for a resource that does not
exist yet, and queue_resources goes back to being purely generic.

prepush.filter_nondefault_variant_updates is removed. It dropped every
update for a non-default variant, existed only because "update" used to
mean "set default", and would now suppress legitimate renames.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Ruari-Phipps
Ruari-Phipps requested a review from a team August 28, 2026 15:14
@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report

Base (main) PR Change
76.5% 76.7% +0.2% ✅

Changed file coverage

File Coverage Change
poly/handlers/interface.py 64.3% +1.2% ✅
poly/project.py 76.4% +0.0% ✅
poly/resources/handoff.py 86.4% +3.2% ✅
poly/resources/variant_attributes.py 87.9% +2.3% ✅
poly/utils/prepush.py 95.0% +1.1% ✅
poly/utils/commands.py 96.4% +6.4% ✅

@Ruari-Phipps
Ruari-Phipps merged commit 770440b into main Sep 1, 2026
6 checks passed
@Ruari-Phipps
Ruari-Phipps deleted the fix/variant-rename branch September 1, 2026 11:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants