# UpdatePipelineLabel

## Permission Scope

label

## Overview

Updates mutable fields of an existing label. Changes propagate immediately to every item the label is attached to (because items reference the label by ID rather than copying its fields).

## Business Rules

- PipelineLabel must exist
- If `name` is supplied, it must be non-empty
- If `name` is supplied, it must remain unique within the pipeline
- `color` and `description` may be explicitly set to `null` to clear them
- `updatedAt` is set on every update
- Consumer extension fields (declared via the `fields` extension point) are passed through to the update; module-managed columns (`id`, `pipelineId`, timestamps) are stripped and cannot be set this way

## Process Flow

```mermaid
flowchart TD
    A[Receive updatePipelineLabel input] --> B{PipelineLabel exists?}
    B -->|No| C[Return LABEL_NOT_FOUND]
    B -->|Yes| D{Name supplied?}
    D -->|No| H[Apply patch]
    D -->|Yes| E{Name non-empty?}
    E -->|No| F[Return INVALID_NAME]
    E -->|Yes| G{Name unique within pipeline?}
    G -->|No| I[Return DUPLICATE_LABEL_NAME]
    G -->|Yes| H
    H --> J[Return updated PipelineLabel]
```

## External Dependencies

- None

## Error Scenarios

- **LABEL_NOT_FOUND**: Specified label ID does not exist
- **INVALID_NAME**: Name is empty or blank
- **DUPLICATE_LABEL_NAME**: A label with the same name already exists on the pipeline

## Test Cases

- updates name, color, and description
- passes extension fields through but strips reserved model columns
- clearing color via null is allowed
- clearing description via null is allowed
- returns error when label does not exist
- returns error when new name is blank
- returns error when renaming to a name that collides on the same pipeline
