# Upgrade loop — changing a workflow that already exists

Use this whenever the target workflow is not a fresh build: a live self-built
workflow, a draft mid-iteration, or a workflow the user built in the n8n UI.

## Invariants (violating any of these breaks external callers)

- **Never edit a live workflow directly.** Live changes go draft → test →
  promote. `update_draft` on a live workflow is refused (409, below).
- **Never activate the copy.** A duplicated draft has different webhook URLs;
  activating it instead of promoting strands every external caller.
- **Promote preserves webhookIds** — that is the whole point. The live id and
  its production URLs never change across a promote.
- **Promote only works between self-built (`awm:client-cli`) workflows.**
  UI-built workflows need the duplication path at the bottom.
- **Save the `operationId`** returned by promote — it is the only rollback
  handle.

## Which path

| Situation | Path |
|---|---|
| Iterating on an INACTIVE draft (not yet promoted/activated) | `update_draft` in place — no new workflow ids |
| Changing a LIVE self-built workflow | Duplicate → draft loop → promote (steps below) |
| Changing a workflow built in the n8n UI (no `awm:client-cli` tag) | Duplicate into a CLI draft; coordinated URL cutover |
| Agency-managed workflow (`agency_managed` 403) | Read/explain; may be switched off or on when the user asks; other changes go through Awesomate support |

## Iterating on a draft: `update_draft`

`awesomate_n8n_deploy {action:'update_draft', workflowId,
workflowJson:{name?, nodes, connections, settings?}}`

- **Full JSON replace** — nodes + connections replace the draft's entirely;
  send the complete workflow, not a delta.
- Settings are **whitelisted server-side**: unknown keys and null/undefined
  values are dropped, `saveExecutionProgress` is pinned false (2TB WAL
  incident), `executionOrder` defaults to `v1`. Omit a key to keep the
  draft's current value.
- Refusals: **409 `workflow_active`** — the workflow is live; do NOT
  deactivate it to force the edit, use the promote path below. 403
  `not_self_built` — only `awm:client-cli` workflows. 403 `agency_managed`.
- Validate (`{action:'validate', workflowJson}`) before every update; re-test
  after (the full Phase 5 testing policy from SKILL.md applies).

## Upgrading a LIVE self-built workflow

1. **Duplicate.** Fetch the live workflow's full JSON
   (`awesomate_n8n_workflows {id, detail:'full'}` or
   `GET /api/my-n8n/workflows/:id`), then `create_draft` with the modified
   JSON — new name, e.g. same name; the hub adds `[CLI] ` + fresh test
   webhookIds automatically.
2. **Iterate.** Apply the requested changes; validate. Further revisions go
   through `update_draft` on the draft — no need to delete and recreate.
3. **Test the draft on its own (test) URLs.** Activate the DRAFT (approval
   gate applies), then `awesomate_n8n_test {workflowId:<draft id>, payload}`.
   Full testing policy: inspect node-by-node output, happy path + empty +
   malformed payloads, confirm error branches routed.
4. **Present the diff — mandatory before promote.** Human-readable, covering
   ALL of: nodes added / removed / changed (name + what changed), credential
   changes (added, swapped, removed), and a behavior summary in the user's
   terms (what the workflow will now do differently). **Wait for explicit
   approval.** No diff, no promote.
5. **Promote.** `awesomate_n8n_deploy {action:'promote',
   workflowId:<LIVE id>, draftId:<draft id>}`. The hub snapshots both
   workflows, swaps the draft's body into the live id (preserving its
   webhookIds so external URLs never change), restores activation, and
   archives the draft as `[promoted <date>]`. Save the returned
   `operationId`.
6. **Verify against the ORIGINAL URL.** `awesomate_n8n_test` against the
   LIVE workflow id — the original production URL must still respond, and
   the execution must show the NEW behavior (inspect node output; a 200
   alone proves nothing). On any failure:
   `{action:'rollback', operationId}` restores both workflows to their
   pre-promote state, then investigate — do not iterate on the live body.
7. **Cleanup.** Once the user confirms the promoted version, `delete_draft`
   the archived `[promoted …]` draft (it is deactivated and still
   CLI-tagged), or leave it as a manual fallback if they prefer.

## UI-built workflows (no `awm:client-cli` tag)

Promote refuses these. Instead:

1. Fetch the UI workflow's JSON; `create_draft` a CLI copy with the changes.
2. Test the draft fully (steps 2–3 above).
3. The draft becomes the live workflow going forward — its webhook URL
   DIFFERS from the original. Coordinate the cutover with the user: they
   update every external caller to the new URL, confirm traffic arrives on
   the new workflow, then deactivate the old UI workflow themselves (it is
   theirs — do not delete it).

## Errors you will hit

| Code | Meaning | Do |
|---|---|---|
| 409 `workflow_active` | `update_draft` on a live workflow | Promote path, never deactivate-to-edit |
| 403 `not_self_built` | No `awm:client-cli` tag | UI-built duplication path |
| 403 `agency_managed` | Awesomate-deployed workflow | Explain; offer to switch it off or on if that is what they want; route changes to support |
| 429 `quota_exceeded` | Daily plan cap | Tell the user; never retry-loop |
