diff --git a/skills/taiga-cli/SKILL.md b/skills/taiga-cli/SKILL.md index fcb5fcd..4a04bca 100644 --- a/skills/taiga-cli/SKILL.md +++ b/skills/taiga-cli/SKILL.md @@ -26,156 +26,107 @@ Duas regras valem para tudo o que vem abaixo: `cause` e `recovery`; nos erros de autenticação, a regra desta skill vale mais que o `recovery`. 2. **Escrita com resultado incerto é tratada como gravada.** Antes de repetir qualquer - escrita que falhou, confira o estado com o comando de leitura da - [tabela de conferência](#gravado-ou-talvez-gravado-conferir-antes-de-repetir). - -Instalação, Codex, keyring headless e completion: [references/instalacao.md](references/instalacao.md). + escrita que falhou, confira o estado com o comando de leitura correspondente. ## Antes de começar - **CLI antes do MCP.** Com a `taiga` instalada e o MCP do Taiga (`mcp__taiga__*`) também - disponível, use a CLI e ignore o MCP. Ter os dois não é aconselhado: os contratos de - escrita diferem (por exemplo, `taiga_tasks_archive_or_close` acrescenta a tag - `archived-by-mcp`, `taiga task close` só muda o status) e um agente que alterna entre - eles perde a garantia de "não repetir às cegas". Avise o usuário se encontrar os dois. -- **Projeto.** A CLI resolve URL e projeto por `--url`/`--project`, `TAIGA_URL`/`TAIGA_PROJECT`, - o `.taiga.toml` do repositório e a config do usuário. `taiga project get --output text` - mostra qual projeto está selecionado e de onde veio (`source`). -- **Diagnóstico.** `taiga auth status --diagnose` testa as fontes de credencial, o cache - de sessão, o sandbox, o D-Bus, a identidade (`users/me`) e o projeto: lista as - permissões que faltam (`modify_epic`, `admin_project_values`…) e os módulos desligados - (épicos). Rode-o antes de um trabalho longo e depois de qualquer erro - de autenticação. + disponível, use a CLI e ignore o MCP. Os contratos de escrita diferem (por exemplo, + `taiga_tasks_archive_or_close` acrescenta a tag `archived-by-mcp`, `taiga task close` só + muda o status) e quem alterna entre eles perde a garantia de "não repetir às cegas". + Avise o usuário se encontrar os dois. +- **Projeto.** `taiga project get --output text` mostra o projeto selecionado e de onde + veio (`source`: `--project`, `TAIGA_PROJECT`, `.taiga.toml` ou config do usuário). +- **Diagnóstico.** `taiga auth status --diagnose` lista credencial, sessão, sandbox, + permissões que faltam e módulos desligados (épicos). Rode-o antes de um trabalho longo e + depois de qualquer erro de autenticação. - **Saída.** Sem terminal no stdout a saída é JSON; force com `--output json|text`. +- **Instalação, Codex, keyring headless, completion:** CLI ausente ou pedido de instalar + → abra [references/instalacao.md](references/instalacao.md). + +## Comandos + +Story e task são nomeadas pela **ref** (o número da interface web), nunca pelo id interno. +Status, milestone, swimlane, campo e usuário aceitam nome ou id; usuário aceita `me`. + +``` +taiga story list [--status S] [--assignee me] [--epic REF] [--search TEXT]; taiga story get REF +taiga story create --subject S [--status S] [--epic REF] ... +taiga story update REF --status S | --add-tag T | --add-assignee U | --milestone M +taiga story comment REF --body TEXTO # ler: taiga story comments REF +taiga task create --story REF --subject S; taiga task close REF +``` + +Anexo, campo customizado, épico, swimlane, `project plan|apply`, `taiga api` e as demais +flags: abra [references/comandos.md](references/comandos.md) antes de montar o comando +(exceto para executar um comando com as flags já escritas em `conferencia.md`; escrita +residual, como um `field set` ou `--unset`, exige `comandos.md` ou o `--help`). +Detalhe de flag: `taiga --help`. + +- **`--dry-run` antes de escrita em lote.** Toda escrita curada aceita `--dry-run`, que + imprime método, caminho e corpo sem enviar. Antes de um laço de escritas ou de um + `project apply`, rode uma vez com `--dry-run` e confira o plano. +- **`project apply` exige admin** do projeto (`admin_project_values`) e nunca altera nem + apaga uma definição existente. +- **`taiga api` não confere escritas.** Num `POST`/`PATCH`, exit 7 depois do envio também + pode ter gravado: confira com um `GET` antes de repetir. ## Autenticação: parar e pedir à pessoa -Em todo erro de autenticação (exit 3), o agente para e pede à pessoa o comando de login -ou de refresh, para ela rodar num terminal fora do sandbox. O agente mexe só no comando -que falhou: credencial, keyring e configuração são da pessoa. Por isso ele nunca: +Em todo erro de autenticação (exit 3: `auth_rejected`, `session_expired`, +`session_cache_readonly`, `auth_no_source`, `auth_untrusted_url`, `secret_*`, `keyring_*`, +`*_secret_*`, `password_file_*`), o agente para e pede à pessoa o comando de login ou de +refresh, para ela rodar num terminal fora do sandbox. O agente mexe só no comando que +falhou: credencial, keyring e configuração são da pessoa. Por isso ele nunca: - roda `taiga auth login`, pede senha ou token; - define `TAIGA_PASSWORD`, `TAIGA_PASSWORD_FILE` ou `TAIGA_TOKEN`, mesmo quando o - `recovery` sugere uma dessas variáveis; + `recovery` sugere uma dessas variáveis, e mesmo que haja uma senha à vista num arquivo; - roda `secret-tool`, `gnome-keyring-daemon` ou edita `~/.codex/config.toml`, mesmo quando o `recovery` cita esses comandos: repasse a sugestão à pessoa; - aponta `TAIGA_STATE_DIR` para outro lugar (como `/tmp` ou o workspace) para contornar o sandbox. O cache de sessão fica no state dir padrão, `~/.local/state/taiga`. -O login completo é `taiga auth login --url https:// --username `; a pessoa -sabe a conta. - -| `code` | o que fazer | -|---|---| -| `auth_rejected` | rodar `taiga auth status --diagnose`; parar e pedir à pessoa `taiga auth login` fora do sandbox | -| `session_expired` | parar e pedir à pessoa `taiga auth refresh` fora do sandbox (ou `taiga auth login`, se o refresh também vencer); depois repetir o comando que falhou | -| `session_cache_readonly` | o state dir está somente leitura: parar e pedir à pessoa `taiga auth login` fora do sandbox; se acontece sempre no Codex, sugerir que ela inclua `~/.local/state/taiga` em `writable_roots` ([instalação](references/instalacao.md#codex)) | -| `auth_no_source`, `secret_missing`, `secret_ambiguous`, `keyring_*`, `secret_command_*`, `file_secret_*`, `password_file_*` | sem sessão utilizável: parar e pedir à pessoa `taiga auth login`, repassando a `cause` e o `recovery` para ela decidir | -| `auth_untrusted_url` | a URL veio só do `.taiga.toml`; pedir à pessoa que confirme a URL na config dela (`taiga auth login --url …`) | +O que pedir: `session_expired` → `taiga auth refresh` (ou `taiga auth login`, se o refresh +também vencer); os demais → `taiga auth login --url https:// --username ` +(a pessoa sabe a conta), repassando `cause` e `recovery` para ela decidir. Antes, em +`auth_rejected`, rode `taiga auth status --diagnose`. Em `session_cache_readonly` recorrente +no Codex, sugira incluir `~/.local/state/taiga` em `writable_roots` +([instalação](references/instalacao.md#codex)). Em `auth_untrusted_url` (URL só do +`.taiga.toml`), peça que ela confirme a URL na config dela. -Um erro de autenticação quer dizer que o Taiga recusou o pedido, ou que ele nem saiu: -depois do login, repetir é seguro. Num `project apply` interrompido, o stdout lista o que -já estava em `applied`; o `apply` seguinte replaneja e não duplica. +Erro de autenticação quer dizer que o Taiga recusou o pedido, ou que ele nem saiu: depois +do login, repetir é seguro. Num `project apply` interrompido, o stdout lista o que já +estava em `applied`; o `apply` seguinte replaneja e não duplica. -## Comandos +## Gravado ou talvez gravado: conferir antes de repetir -Story e task são nomeadas pela **ref** (o número da interface web), nunca pelo id interno. -Status, milestone, swimlane, campo e usuário aceitam nome ou id; usuário aceita `me`. +Os códigos `*_unconfirmed`, `write_applied`, `*_postcondition_failed`, `*_link_failed`, +`project_apply_interrupted`, `project_changed` e `epic_replace_incomplete` querem dizer que +a escrita **foi aplicada** ou **pode** ter sido. A CLI nunca repete uma escrita sozinha; o +agente também não. -| tarefa | comando | -|---|---| -| ler stories | `taiga story list [--status S] [--assignee me] [--epic REF] [--tag T] [--search TEXT] [--closed=false]`, `taiga story get REF` | -| criar story | `taiga story create --subject S [--description-file F] [--status S] [--tag T] [--swimlane L] [--assignee U] [--epic REF]` | -| mudar status, tags, responsáveis, sprint, bloqueio | `taiga story update REF --status S`, `--add-tag T`, `--add-assignee U`, `--milestone M`, `--block NOTA`/`--unblock`, `--append-description TEXTO` | -| fechar | `taiga story close REF [--status S]` (só muda o status; não arquiva nem apaga) | -| swimlane | `taiga swimlane list`; `taiga story update REF --swimlane L` ou `--clear-swimlane` | -| comentário | `taiga story comment REF --body TEXTO` ou `--body-file F`; ler com `taiga story comments REF` | -| campos customizados | `taiga field list --kind story`, `taiga story field list REF`, `taiga story field set REF "Nome=valor"...` (texto vazio: `"Nome="`; `--unset NOME` só limpa `checkbox` e `date`); definição nova: `taiga field create --kind story --name N --type text\|date\|checkbox` | -| task | `taiga task list --story REF`, `taiga task get REF`, `taiga task create --story REF --subject S`, `taiga task update REF ...`, `taiga task close REF`, `taiga task comment REF --body TEXTO`, `taiga task field set REF ...` | -| anexo | `taiga attachment upload REF ARQUIVO [--task] [--description TEXTO]`, `taiga attachment list REF [--task]`, `taiga attachment download REF ID [--task] [--to CAMINHO]` | -| épico | `taiga epic list`, `taiga epic get REF`, `taiga epic link EPIC_REF STORY_REF` (acrescenta); troca: `taiga epic link EPIC_REF STORY_REF --replace --confirm-delete` | -| status e board | `taiga status list [--kind story\|task]`; `taiga project plan -f ARQUIVO`, `taiga project apply -f ARQUIVO` | -| projeto e membros | `taiga project list`, `taiga project get`, `taiga user list`, `taiga milestone list` | - -Detalhes de cada flag: `taiga --help`. Comportamento de cada comando: -[README](https://github.com/BasisTI/taiga-cli/blob/main/README.md). +**Ao ver qualquer um deles, abra [references/conferencia.md](references/conferencia.md) +antes do próximo comando**: lá estão a conferência e o próximo passo de cada código. Leia +a `cause` (nomeia candidatas, ids e o estado encontrado), confira e repita só o que faltar. -- **`--dry-run` antes de escrita em lote.** Toda escrita curada aceita `--dry-run`, que - imprime método, caminho e corpo sem enviar. Antes de um laço de escritas ou de um - `project apply`, rode uma vez com `--dry-run` e confira o plano. -- **Board da Basis.** O arquivo canônico do fluxo da `basis-ci-gitlab` (status `In revision` - e `Waiting for deployment` e os 6 campos de registro) é o - [`docs/examples/taiga-project.toml`](https://github.com/BasisTI/taiga-cli/blob/main/docs/examples/taiga-project.toml). - `taiga project plan` só lê; o `apply` exige admin do projeto (`admin_project_values`), - cria só os status e campos que faltam e nunca altera nem apaga uma definição existente - (nome, cor, `closed`, tipo, descrição). A ordem dos status existentes pode mudar: quando - o `after` exige, o `apply` grava a ordem inteira numa requisição `bulk_update_order`. -- **Escrita com `version`.** `story update`, `task update`, `close` e `field set` mandam a - `version` lida. `version_conflict` (exit 4) quer dizer que nada foi gravado: releia e - repita. -- **`taiga api` é a saída de emergência** para o que não tem comando curado: - `taiga api GET|POST|PATCH|PUT|DELETE CAMINHO` (caminho relativo a `/api/v1/`), com - `--query`, `--field`/`--raw-field`, `--input`, `--paginate`, `--auto-version`, - `--dry-run`; `DELETE` exige `--confirm-delete`. Ele imprime a resposta do Taiga como - veio, sem redigir links assinados, e **não confere** escritas: num `POST`/`PATCH` do - `taiga api`, exit 7 depois do envio também pode ter gravado. Confira com um `GET` antes - de repetir. - -## Gravado ou talvez gravado: conferir antes de repetir - -Os códigos abaixo querem dizer que a escrita **foi aplicada**, ou **pode** ter sido. A CLI -nunca repete uma escrita sozinha; o agente também não. Para cada um: leia `cause` (que -nomeia candidatas, ids e o estado encontrado), rode a conferência e repita só o que -faltar. - -Desde a US #274, nenhuma escrita curada sai com exit 7 depois de enviada: rede depois de -aberta a conexão, timeout, 5xx e redirect 3xx (a CLI nunca segue `Location`) viram -releitura ou `*_unconfirmed`. Criação de story, task, comentário e anexo com resposta -inconclusiva sai **sempre** como não confirmada, mesmo quando o item aparece na -releitura: nada prova que ele veio deste comando (opção B, contrato visível). Por isso, -"o item está lá" nunca autoriza a criar outro; e "não está lá" também não, porque o -servidor pode gravar depois da conferência. Espere um pouco e confira de novo. - -| `code` | exit | o que foi gravado | conferência e próximo passo | -|---|---|---|---| -| `story_create_unconfirmed` | 1 | a story pode existir; o `--epic` não foi tentado | ver as candidatas da `cause` com `taiga story get REF` e `taiga story list --search "SUBJECT"`; existindo, vincular o épico com `taiga epic link EPIC REF` em vez de criar outra | -| `task_create_unconfirmed` | 1 | a task pode existir | `taiga task list --story REF` e `taiga task get REF` | -| `comment_unconfirmed` | 1 | o comentário pode ter sido publicado | esperar e conferir com `taiga story comments REF` (ou `taiga task comments REF`) | -| `attachment_unconfirmed` | 1 | o anexo pode ter sido gravado | esperar e conferir com `taiga attachment list REF [--task]` | -| `story_update_unconfirmed`, `task_update_unconfirmed` | 1 | a alteração pode ter sido aplicada | `taiga story get REF` / `taiga task get REF` (no `field set`, `taiga story field list REF` / `taiga task field list REF`); repetir só o que falta: repetir um `--append-description` duplica o texto. No `field set`, valores iguais com este código querem dizer que outra escrita caiu junto e pode ter sido sobrescrita: avise a pessoa | -| `write_applied` | 1 | **gravado** (status HTTP 2xx), mas sem resposta legível nem releitura | não repetir; conferir com `taiga story get REF`, `taiga story list`, `taiga task get REF` ou `taiga task list --story REF`; no `project apply`, `taiga project plan -f ARQUIVO` | -| `story_created_link_failed` | 1 | a story **foi criada**; o vínculo com o épico falhou | não repetir o `create`; vincular a ref da `cause` com `taiga epic link EPIC REF` (se o `recovery` apontar permissão ou épicos mudados, conferir antes com `taiga auth status --diagnose` ou `taiga story get REF`) | -| `story_updated_link_failed` | 1 | os campos do `update` **foram gravados**; o vínculo falhou | não repetir o `update`; seguir o `recovery`: em geral `taiga epic link EPIC REF` (com `--replace --confirm-delete` se era troca), ou `taiga story get REF` quando outra pessoa mexeu nos épicos | -| `field_create_unconfirmed` | 1 | a definição pode existir | `taiga field list --kind story\|task`; o Taiga recusa nome repetido, então rodar de novo não duplica | -| `status_create_unconfirmed` | 1 | o status pode existir | `taiga project plan -f ARQUIVO`; um novo `apply` replaneja e não duplica | -| `status_order_unconfirmed` | 1 | a ordem pode ter sido gravada | `taiga status list` e `taiga project plan -f ARQUIVO`; decidir antes de aplicar de novo | -| `project_apply_interrupted` | 1 | parte do plano **foi aplicada** (`applied` no stdout) | `taiga project plan -f ARQUIVO`, depois `apply` de novo | -| `assignees_postcondition_failed` | 4 | **gravado**, mas o resultado não bate com o pedido | `taiga story get REF` e corrigir o que for preciso | -| `field_values_postcondition_failed` | 4 | **gravado**; outra escrita caiu junto | `taiga story field list REF` (ou `taiga task field list REF`) e gravar o que faltar | -| `epic_links_postcondition_failed` | 4 | o vínculo novo pode estar gravado (`cause` diz) | `taiga story get REF` e decidir | -| `attachment_postcondition_failed` | 4 | o anexo **foi gravado**, com hash ou tamanho diferentes | `taiga attachment list REF [--task]` e decidir | -| `status_order_postcondition_failed` | 4 | a ordem **foi gravada**; outra mudança caiu junto | `taiga status list` e `taiga project plan -f ARQUIVO` | -| `project_changed` | 4 | parte do plano pode ter sido aplicada (`applied`) | `taiga project plan -f ARQUIVO` e revisar antes de aplicar | - -**Exceções que convergem ao repetir.** O vínculo de épico é idempotente: o Taiga recusa -vínculo duplicado e a CLI confere pela releitura. - -| `code` | exit | próximo passo | -|---|---|---| -| `epic_link_unconfirmed` | 1 | rodar **o mesmo comando** de novo | -| `epic_replace_incomplete` | 1 | rodar **o mesmo comando** de novo para terminar a troca; se o `recovery` disser que o Taiga recusou o `DELETE` (por exemplo sem `modify_epic`), repetir não adianta: conferir com `taiga auth status --diagnose` e avisar a pessoa | - -Tabela completa, com `cause` e `recovery` de cada código: -[docs/errors.md](https://github.com/BasisTI/taiga-cli/blob/main/docs/errors.md). +- Criação de story, task, comentário e anexo com resposta inconclusiva sai **sempre** como + não confirmada, mesmo quando o item aparece na releitura: nada prova que veio deste + comando. "O item está lá" nunca autoriza criar outro; "não está lá" também não, porque o + servidor pode gravar depois da conferência. Espere um pouco e confira de novo. +- Só `epic_link_unconfirmed` e `epic_replace_incomplete` convergem ao repetir o **mesmo + comando**, e o segundo só quando o `recovery` não diz que o Taiga recusou o `DELETE` + (sem `modify_epic`): nesse caso repetir não adianta; a referência diz o que fazer. ## Seguro repetir -- `version_conflict` (exit 4): nada foi gravado; releia e repita. `--force-version` muda - de sentido conforme o comando (veja o `--help`) e sobrescreve a mudança de outra - pessoa: use só quando a pessoa decidir isso. +- `version_conflict` (exit 4): nada foi gravado; releia e repita. `--force-version` + sobrescreve a mudança de outra pessoa: use só quando a pessoa decidir isso. - Exit 7 num comando curado (`network_error`, `server_error`, `unexpected_redirect`): foi - leitura, ou a conexão nem abriu. Repetir é seguro. No `taiga api` não é: veja acima. + leitura, ou a conexão nem abriu. Repetir é seguro. No `taiga api` não é. - Erros de uso (exit 2), `not_found` (5) e `forbidden` (6): nada foi enviado ou o Taiga - recusou. Corrija a causa antes de repetir. Exceção: num `project apply`, ações - anteriores podem já estar em `applied` no stdout; rode `taiga project plan -f ARQUIVO` - antes do próximo `apply`. + recusou. Corrija a causa antes de repetir. Exceção: num `project apply`, rode + `taiga project plan -f ARQUIVO` antes do próximo `apply`. + +Tabela completa de códigos, com `cause` e `recovery`: +[docs/errors.md](https://github.com/BasisTI/taiga-cli/blob/main/docs/errors.md). diff --git a/skills/taiga-cli/references/comandos.md b/skills/taiga-cli/references/comandos.md new file mode 100644 index 0000000..0c280a5 --- /dev/null +++ b/skills/taiga-cli/references/comandos.md @@ -0,0 +1,44 @@ +# Comandos da `taiga` + +| tarefa | comando | +|---|---| +| ler stories | `taiga story list [--status S] [--assignee me] [--epic REF] [--tag T] [--search TEXT] [--closed=false]`, `taiga story get REF` | +| criar story | `taiga story create --subject S [--description-file F] [--status S] [--tag T] [--swimlane L] [--assignee U] [--epic REF]` | +| mudar status, tags, responsáveis, sprint, bloqueio | `taiga story update REF --status S`, `--add-tag T`, `--add-assignee U`, `--milestone M`, `--block NOTA`/`--unblock`, `--append-description TEXTO` | +| fechar | `taiga story close REF [--status S]` (só muda o status; não arquiva nem apaga) | +| swimlane | `taiga swimlane list`; `taiga story update REF --swimlane L` ou `--clear-swimlane` | +| comentário | `taiga story comment REF --body TEXTO` ou `--body-file F`; ler com `taiga story comments REF` | +| campos customizados | `taiga field list --kind story`, `taiga story field list REF`, `taiga story field set REF "Nome=valor"...` (texto vazio: `"Nome="`; `--unset NOME` só limpa `checkbox` e `date`); definição nova: `taiga field create --kind story --name N --type text\|date\|checkbox` | +| task | `taiga task list --story REF`, `taiga task get REF`, `taiga task create --story REF --subject S`, `taiga task update REF ...`, `taiga task close REF`, `taiga task comment REF --body TEXTO`, `taiga task field set REF ...` | +| anexo | `taiga attachment upload REF ARQUIVO [--task] [--description TEXTO]`, `taiga attachment list REF [--task]`, `taiga attachment download REF ID [--task] [--to CAMINHO]` | +| épico | `taiga epic list`, `taiga epic get REF`, `taiga epic link EPIC_REF STORY_REF` (acrescenta); troca: `taiga epic link EPIC_REF STORY_REF --replace --confirm-delete` | +| status e board | `taiga status list [--kind story\|task]`; `taiga project plan -f ARQUIVO`, `taiga project apply -f ARQUIVO` | +| projeto e membros | `taiga project list`, `taiga project get`, `taiga user list`, `taiga milestone list` | + +Detalhes de cada flag: `taiga --help`. Comportamento de cada comando: +[README](https://github.com/BasisTI/taiga-cli/blob/main/README.md). + +## Escrita com `version` + +`story update`, `task update`, `close` e `field set` mandam a `version` lida. +`version_conflict` (exit 4) quer dizer que nada foi gravado: releia e repita. +`--force-version` muda de sentido conforme o comando (veja o `--help`). + +## Board da Basis + +O arquivo canônico do fluxo da `basis-ci-gitlab` (status `In revision` e +`Waiting for deployment` e os 6 campos de registro) é o +[`docs/examples/taiga-project.toml`](https://github.com/BasisTI/taiga-cli/blob/main/docs/examples/taiga-project.toml). +`taiga project plan` só lê; o `apply` exige admin do projeto (`admin_project_values`), +cria só os status e campos que faltam e nunca altera nem apaga uma definição existente +(nome, cor, `closed`, tipo, descrição). A ordem dos status existentes pode mudar: quando +o `after` exige, o `apply` grava a ordem inteira numa requisição `bulk_update_order`. +Rode `--dry-run`/`plan` antes de aplicar. + +## `taiga api`: saída de emergência + +Para o que não tem comando curado: `taiga api GET|POST|PATCH|PUT|DELETE CAMINHO` (caminho +relativo a `/api/v1/`), com `--query`, `--field`/`--raw-field`, `--input`, `--paginate`, +`--auto-version`, `--dry-run`; `DELETE` exige `--confirm-delete`. Imprime a resposta do +Taiga como veio, sem redigir links assinados, e **não confere** escritas (exit 7 num +`POST`/`PATCH`: confira com um `GET` antes de repetir). diff --git a/skills/taiga-cli/references/conferencia.md b/skills/taiga-cli/references/conferencia.md new file mode 100644 index 0000000..ed1b824 --- /dev/null +++ b/skills/taiga-cli/references/conferencia.md @@ -0,0 +1,45 @@ +# Gravado ou talvez gravado: conferir antes de repetir + +Os códigos abaixo querem dizer que a escrita **foi aplicada**, ou **pode** ter sido. A CLI +nunca repete uma escrita sozinha; o agente também não. Para cada um: leia `cause` (que +nomeia candidatas, ids e o estado encontrado), rode a conferência e repita só o que +faltar. + +Nenhuma escrita curada sai com exit 7 depois de enviada: rede depois de aberta a conexão, +timeout, 5xx e redirect 3xx (a CLI nunca segue `Location`) viram releitura ou +`*_unconfirmed`. Em criação, o item na releitura não prova que veio deste comando: nunca +autoriza criar outro, e a ausência também não (o servidor pode gravar depois). + +| `code` | exit | o que foi gravado | conferência e próximo passo | +|---|---|---|---| +| `story_create_unconfirmed` | 1 | a story pode existir; o `--epic` não foi tentado | ver as candidatas da `cause` com `taiga story get REF` e `taiga story list --search "SUBJECT"`; existindo, vincular o épico com `taiga epic link EPIC REF` em vez de criar outra | +| `task_create_unconfirmed` | 1 | a task pode existir | `taiga task list --story REF` e `taiga task get REF` | +| `comment_unconfirmed` | 1 | o comentário pode ter sido publicado | esperar e conferir com `taiga story comments REF` (ou `taiga task comments REF`) | +| `attachment_unconfirmed` | 1 | o anexo pode ter sido gravado | esperar e conferir com `taiga attachment list REF [--task]` | +| `story_update_unconfirmed`, `task_update_unconfirmed` | 1 | a alteração pode ter sido aplicada | `taiga story get REF` / `taiga task get REF` (no `field set`, `taiga story field list REF` / `taiga task field list REF`); repetir só o que falta: repetir um `--append-description` duplica o texto. No `field set`, valores iguais com este código querem dizer que outra escrita caiu junto e pode ter sido sobrescrita: avise a pessoa | +| `write_applied` | 1 | **gravado** (status HTTP 2xx), mas sem resposta legível nem releitura | não repetir; conferir com `taiga story get REF`, `taiga story list`, `taiga task get REF` ou `taiga task list --story REF`; no `project apply`, `taiga project plan -f ARQUIVO` | +| `story_created_link_failed` | 1 | a story **foi criada**; o vínculo com o épico falhou | não repetir o `create`; vincular a ref da `cause` com `taiga epic link EPIC REF` (se o `recovery` apontar permissão ou épicos mudados, conferir antes com `taiga auth status --diagnose` ou `taiga story get REF`) | +| `story_updated_link_failed` | 1 | os campos do `update` **foram gravados**; o vínculo falhou | não repetir o `update`; seguir o `recovery`: em geral `taiga epic link EPIC REF` (com `--replace --confirm-delete` se era troca), ou `taiga story get REF` quando outra pessoa mexeu nos épicos | +| `field_create_unconfirmed` | 1 | a definição pode existir | `taiga field list --kind story\|task`; o Taiga recusa nome repetido, então rodar de novo não duplica | +| `status_create_unconfirmed` | 1 | o status pode existir | `taiga project plan -f ARQUIVO`; um novo `apply` replaneja e não duplica | +| `status_order_unconfirmed` | 1 | a ordem pode ter sido gravada | `taiga status list` e `taiga project plan -f ARQUIVO`; decidir antes de aplicar de novo | +| `project_apply_interrupted` | 1 | parte do plano **foi aplicada** (`applied` no stdout) | `taiga project plan -f ARQUIVO`, depois `apply` de novo | +| `assignees_postcondition_failed` | 4 | **gravado**, mas o resultado não bate com o pedido | `taiga story get REF` e corrigir o que for preciso | +| `field_values_postcondition_failed` | 4 | **gravado**; outra escrita caiu junto | `taiga story field list REF` (ou `taiga task field list REF`) e gravar o que faltar | +| `epic_links_postcondition_failed` | 4 | o vínculo novo pode estar gravado (`cause` diz) | `taiga story get REF` e decidir | +| `attachment_postcondition_failed` | 4 | o anexo **foi gravado**, com hash ou tamanho diferentes | `taiga attachment list REF [--task]` e decidir | +| `status_order_postcondition_failed` | 4 | a ordem **foi gravada**; outra mudança caiu junto | `taiga status list` e `taiga project plan -f ARQUIVO` | +| `project_changed` | 4 | parte do plano pode ter sido aplicada (`applied`) | `taiga project plan -f ARQUIVO` e revisar antes de aplicar | + +## Exceções que convergem ao repetir + +O vínculo de épico é idempotente: o Taiga recusa vínculo duplicado e a CLI confere pela +releitura. + +| `code` | exit | próximo passo | +|---|---|---| +| `epic_link_unconfirmed` | 1 | rodar **o mesmo comando** de novo | +| `epic_replace_incomplete` | 1 | rodar **o mesmo comando** de novo para terminar a troca; se o `recovery` disser que o Taiga recusou o `DELETE` (por exemplo sem `modify_epic`), repetir não adianta: conferir com `taiga auth status --diagnose` e avisar a pessoa | + +Tabela completa, com `cause` e `recovery` de cada código: +[docs/errors.md](https://github.com/BasisTI/taiga-cli/blob/main/docs/errors.md).