feat: Automation Contract v1 -- outcome restrito, idempotência real, M2M #70

Merged
jhony75 merged 1 commit from feature/automation-contract-v1 into develop 2026-09-11 21:40:56 -03:00
Owner

Formaliza o contrato de automação do QA Cockpit (ingestão, Automation Discovery, Runner Contract) após auditoria completa (estado atual + gaps entregues antes de qualquer mudança de código).

Mudanças confirmadas com o usuário:

  • outcome de ingestão restrito aos 5 valores terminais (PASS/FAIL/ERROR/BLOCKED/SKIPPED) -- PENDING/RUNNING (só fazem sentido pra execução manual em andamento) agora são rejeitados com 422.
  • external_run_id passa a ser obrigatório (era opcional) -- junto com source, é a chave de idempotência. Sem esse campo não havia proteção nenhuma contra reentrega duplicada.
  • Idempotência agora garantida por índice único parcial em test_runs(automation_source, external_run_id) WHERE external_run_id IS NOT NULL, não só checagem em aplicação -- com tratamento de IntegrityError pra corrida entre requisições concorrentes.
  • Runner.secret opcional (M2M Cockpit → Runner via Authorization: Bearer), nunca exposto pela API (RunnerOut só expõe has_secret).
  • M2M automação → Cockpit não precisou de nenhuma mudança de código -- a service account qa-cockpit-automation do Authentik já chega pelos mesmos headers X-authentik-* que services/identity.py lê desde o item 14.
  • Badge de automação (is_automated) em AuditLogEntry, Report.reviewer/approved_by e TestRun.executed_by, calculado a partir do grupo qa-cockpit-automations.

Achado da auditoria que valeu a pena registrar: o Runner Contract (orquestração) já estava correto -- vocabulário QUEUED/RUNNING/COMPLETED/FAILED com a semântica certa (FAILED = erro de infra, não teste reprovado) -- só faltava documentação formal, já que o único ADR próximo do tema (0012) descrevia uma proposta completamente diferente e nunca implementada.

Documentação nova: docs/AUTOMATION_CONTRACT.md (referência externa com exemplos HTTP completos, pra outros projetos consumirem sem ler código) + ADR-0015, com nota de esclarecimento no ADR-0012 e atualizações em API.md/ARCHITECTURE.md/BACKLOG.md/KNOWN_LIMITATIONS.md refletindo que o forward-auth via Authentik já está ativo em prod e dev (PRs #67/#68/#69, aplicadas por fora deste PR).

Verificação: 257 testes de backend (18 novos), 152+ de frontend (2 novos em Runners.test.tsx), typecheck/lint/build/Storybook build OK, migration testada contra banco populado e do zero (restore drill, 37 tabelas).

Formaliza o contrato de automação do QA Cockpit (ingestão, Automation Discovery, Runner Contract) após auditoria completa (estado atual + gaps entregues antes de qualquer mudança de código). **Mudanças confirmadas com o usuário:** - `outcome` de ingestão restrito aos 5 valores terminais (`PASS/FAIL/ERROR/BLOCKED/SKIPPED`) -- `PENDING`/`RUNNING` (só fazem sentido pra execução manual em andamento) agora são rejeitados com `422`. - `external_run_id` passa a ser **obrigatório** (era opcional) -- junto com `source`, é a chave de idempotência. Sem esse campo não havia proteção nenhuma contra reentrega duplicada. - Idempotência agora garantida por **índice único parcial** em `test_runs(automation_source, external_run_id) WHERE external_run_id IS NOT NULL`, não só checagem em aplicação -- com tratamento de `IntegrityError` pra corrida entre requisições concorrentes. - `Runner.secret` opcional (M2M Cockpit → Runner via `Authorization: Bearer`), nunca exposto pela API (`RunnerOut` só expõe `has_secret`). - M2M automação → Cockpit **não precisou de nenhuma mudança de código** -- a service account `qa-cockpit-automation` do Authentik já chega pelos mesmos headers `X-authentik-*` que `services/identity.py` lê desde o item 14. - Badge de automação (`is_automated`) em `AuditLogEntry`, `Report.reviewer`/`approved_by` e `TestRun.executed_by`, calculado a partir do grupo `qa-cockpit-automations`. **Achado da auditoria que valeu a pena registrar**: o Runner Contract (orquestração) já estava correto -- vocabulário `QUEUED/RUNNING/COMPLETED/FAILED` com a semântica certa (FAILED = erro de infra, não teste reprovado) -- só faltava documentação formal, já que o único ADR próximo do tema (0012) descrevia uma proposta completamente diferente e nunca implementada. **Documentação nova**: [`docs/AUTOMATION_CONTRACT.md`](../src/branch/develop/docs/AUTOMATION_CONTRACT.md) (referência externa com exemplos HTTP completos, pra outros projetos consumirem sem ler código) + [ADR-0015](../src/branch/develop/docs/adr/0015-automation-contract-v1.md), com nota de esclarecimento no ADR-0012 e atualizações em `API.md`/`ARCHITECTURE.md`/`BACKLOG.md`/`KNOWN_LIMITATIONS.md` refletindo que o forward-auth via Authentik já está ativo em prod e dev (PRs #67/#68/#69, aplicadas por fora deste PR). **Verificação**: 257 testes de backend (18 novos), 152+ de frontend (2 novos em `Runners.test.tsx`), typecheck/lint/build/Storybook build OK, migration testada contra banco populado e do zero (restore drill, 37 tabelas).
feat: Automation Contract v1 -- outcome restrito, idempotencia real, M2M
All checks were successful
EEG QA CI / Detectar o que mudou (pull_request) Successful in 14s
EEG QA CI / Backend (pull_request) Successful in 1m58s
EEG QA CI / Frontend (pull_request) Successful in 3m38s
EEG QA CI / Build e publicação de imagens (pull_request) Successful in 3m6s
EEG QA CI / Deploy development (pull_request) Has been skipped
EEG QA CI / Deploy production (pull_request) Has been skipped
086ed36850
Formaliza o contrato de automacao do QA Cockpit (ingestao, Automation
Discovery, Runner Contract) com as mudancas confirmadas com o usuario:

- outcome de ingestao restrito aos 5 valores terminais (PASS/FAIL/ERROR/
  BLOCKED/SKIPPED), rejeitando PENDING/RUNNING com 422
- external_run_id passa a ser obrigatorio (era opcional) -- e a chave de
  idempotencia junto com source
- idempotencia agora garantida por indice unico parcial em test_runs
  (nao so checagem em app), com tratamento de IntegrityError pra corrida
  entre requisicoes concorrentes
- Runner.secret opcional (M2M Cockpit -> Runner via Authorization: Bearer),
  nunca exposto pela API (RunnerOut so expoe has_secret)
- M2M automacao -> Cockpit nao precisou de mudanca de codigo -- a service
  account qa-cockpit-automation do Authentik ja chega pelos mesmos headers
  que services/identity.py le desde o item 14
- badge de automacao (is_automated) em AuditLogEntry, Report.reviewer/
  approved_by e TestRun.executed_by, calculado a partir do grupo
  qa-cockpit-automations

Documentacao nova: docs/AUTOMATION_CONTRACT.md (referencia externa com
exemplos HTTP completos) + ADR-0015, com nota de esclarecimento no ADR-0012
(proposta diferente, nao implementada) e atualizacoes em API.md/
ARCHITECTURE.md/BACKLOG.md/KNOWN_LIMITATIONS.md refletindo que o forward-auth
via Authentik ja esta ativo em prod e dev (PRs #67/#68/#69).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
jhony75 merged commit b9f0450d37 into develop 2026-09-11 21:40:56 -03:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jhony75/eeg-qa!70
No description provided.