{"record":{"id":"bad93ef55a5e4a28","repo":"can1357/oh-my-pi","slug":"refusing-to-rename-non-farm-branch-workspace-bran","errorCode":null,"errorMessage":"refusing to rename non-farm branch {workspace.branch!r}","messagePattern":"refusing to rename non-farm branch (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/robomp/src/sandbox.py","lineNumber":189,"sourceCode":"    (which updates the shared refs in the pool) and mutates\n    ``workspace.branch`` in place.\n\n    Idempotent when the computed branch already matches ``workspace.branch``.\n    Raises ``ValueError`` for syntactically invalid slugs or for a\n    workspace whose branch isn't on the ``farm/<hex>/<slug>`` shape.\n    Raises ``GitCommandError`` if the underlying ``git`` invocation fails\n    (e.g. the target branch name is already taken).\n\n    When ``pr_number`` is provided (non-None), the rename is a no-op: an\n    open PR on origin still tracks ``workspace.branch``, and renaming it\n    locally would orphan the PR by leaving its head on a branch that no\n    longer receives pushes. The slug is still validated so callers see\n    the same input errors as the rename path.\n    \"\"\"\n    validate_branch_slug(new_slug)\n    parts = workspace.branch.split(\"/\", 2)\n    if len(parts) != 3 or parts[0] != \"farm\" or not parts[1]:\n        raise ValueError(f\"refusing to rename non-farm branch {workspace.branch!r}\")\n    new_branch = f\"farm/{parts[1]}/{new_slug}\"\n    if new_branch == workspace.branch:\n        return new_branch\n    if pr_number is not None:\n        log.warning(\n            \"rename_workspace_branch skipped: PR #%d already tracks %r; refusing to rename to %r\",\n            pr_number,\n            workspace.branch,\n            new_branch,\n        )\n        return workspace.branch\n    proc = _safe_run(\n        [\"git\", \"branch\", \"-m\", workspace.branch, new_branch],\n        cwd=workspace.repo_dir,\n        env=_git_env_for_repo(workspace.repo_dir),\n        **_slot_subprocess_kwargs(slot_uid),\n    )\n    if proc.returncode != 0:","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/robomp/src/sandbox.py#L171-L207","documentation":"rename_workspace_branch() only renames branches matching the workspace convention `farm/<8-hex>/<slug>`. Before running git it splits workspace.branch on '/' and refuses any branch that does not have exactly three segments with the literal prefix 'farm' and a non-empty hex part. This guard prevents mangling arbitrary branches (like 'main' or 'feature/x') that were not created by the sandbox worktree pool.","triggerScenarios":"Calling rename_workspace_branch(workspace, new_slug) when workspace.branch is 'main', 'master', a default-branch checkout (e.g. release workspaces on the default branch), a two-segment name like 'feature/x', or any branch not produced by ensure_workspace's farm/<hex>/<slug> scheme. It is also reachable when a caller hand-crafts a Workspace dataclass with a non-farm branch string.","commonSituations":"Attempting to rename the release workspace's branch (it checks out the default branch, not a farm branch); renaming a workspace created manually or by an older robomp version that predates the farm/<hex>/<slug> naming; test fixtures populating Workspace with plain branch names.","solutions":["Only call rename_workspace_branch on issue workspaces created by ensure_workspace (branch always farm/<hex>/<slug>).","Check the shape before calling: workspace.branch.count('/') == 2 and workspace.branch.startswith('farm/').","For release/default-branch workspaces there is nothing to rename — skip the call.","If a legacy workspace must be renamed, create a new ensure_workspace worktree on a proper farm branch instead of renaming in place."],"exampleFix":"// before\nnew = rename_workspace_branch(release_ws, \"hotfix\")  # ValueError: non-farm branch 'main'\n// after\nif release_ws.branch.startswith(\"farm/\"):\n    new = rename_workspace_branch(release_ws, \"hotfix\")\nelse:\n    log.info(\"skip rename: %s is not a farm branch\", release_ws.branch)","handlingStrategy":"validation","validationCode":"def is_farm_branch(branch: str) -> bool:\n    parts = branch.split(\"/\", 2)\n    return len(parts) == 3 and parts[0] == \"farm\" and bool(parts[1])\n\nif not is_farm_branch(workspace.branch):\n    log.info(\"skip rename: %s is not a farm branch\", workspace.branch)\n    return","typeGuard":null,"tryCatchPattern":"try:\n    rename_workspace_branch(ws, slug)\nexcept ValueError as e:\n    log.warning(\"rename refused: %s\", e)  # non-farm branch; skip","preventionTips":["Only rename workspaces produced by ensure_workspace, never release/default-branch workspaces.","Check branch shape with a small predicate before calling.","Treat ValueError from this API as 'not applicable' (skip), not a retryable failure."],"tags":["git","validation","branch-naming"],"backgroundTag":"invalid-branch-name","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}