1. Desenhar a sequência antes de procurar o erro
Num cenário fictício de suporte L3, a aplicação ainda não recebeu a mudança, mas o gestor vê várias aprovações verdes. Começa por desenhar a sequência: construção do plano, avaliação das condições, acesso aos recursos, execução dos jobs e observação do serviço. Pergunta em que ponto parou o trabalho e que evidência permite afirmá-lo. Um job que nunca começou não tem o mesmo problema de um script que terminou com erro. Uma aprovação humana não demonstra que o agente conseguiu autenticar-se na aplicação. Usa identificadores da execução e do artefacto para não misturar tentativas. Prepara um registo curto com estado, última ação observada, condição pendente, responsável e limite da janela. Esta estrutura ajuda o PM a coordenar infraestrutura, desenvolvimento e produção sem pedir a todas as equipas que repitam a mesma investigação. Antes de reexecutar, identifica efeitos já produzidos e o que uma repetição pode duplicar.
2. Saber quando um valor passa a existir
O inventário do ambiente calcula needsMigration durante Discover. Esse resultado não existia quando o plano foi expandido. Define o consumidor no plano e usa uma condição de runtime depois do produtor, em vez de esperar que um if de template seja reconstruído a meio da execução. Outra diferença aparece dentro de um script: a macro já foi substituída quando o step começou. Um comando de definição de variável não altera retroativamente esse texto. O step seguinte pode consumir o valor atualizado. No exercício, releaseLabel começa como candidate e só depois passa a approved. Pede ao aluno que preveja o valor observado em cada ponto e explique porquê. Não uses uma espera arbitrária para corrigir uma diferença de fase. Regista a origem de cada valor, o momento em que é calculado e o primeiro consumidor que o pode usar. Esta pequena tabela evita diagnósticos baseados apenas na ordem visual do YAML.
3. Tratar outputs como contratos entre produtores e consumidores
Para um output atravessar jobs, identifica o produtor, o step com nome, a variável publicada e a dependência do consumidor. No exemplo normal dentro do mesmo stage, Inspect publica decide.allowRelease e Release depende de Inspect. Entre stages, o contexto do job consumidor inclui stageDependencies, o nome do stage e o job produtor. Não copies o mesmo caminho para deployment jobs sem rever a sintaxe específica. Acrescentar Review entre Build e Deploy também merece atenção: se Deploy precisa do output original de Build, declara essa relação, em vez de depender apenas da posição do ficheiro. O caso usa packageRef para conservar a identidade do pacote avaliado. Recalculá-la a partir do topo atual de main pode indicar outro conteúdo. Num handover, explica qual execução produziu o valor e o que acontece se faltar. Uma string vazia não deve ser convertida silenciosamente em autorização para entregar um pacote diferente.
4. Distinguir condição, alcance e resultado funcional
Uma condição é avaliada antes de iniciar a unidade a que pertence. Um job não pode basear o próprio início num resultado que só o seu primeiro step produziria. Além disso, always no filho não faz arrancar um stage pai que ficou Skipped. No cenário batch, Prepare pausou o consumidor e a reposição ficou dentro desse stage inacessível. O suporte precisa de confirmar o estado externo e executar recuperação autorizada, sem assumir que uma configuração equivale a uma ação realizada. No exercício local, Tests tem de terminar Succeeded, enquanto Docs pode terminar Succeeded ou Skipped. O contrato é deliberadamente estrito e não aceita SucceededWithIssues. Essa escolha pertence ao cenário, não é uma descrição universal de succeeded(). Se uma tarefa usa continueOnError, a continuidade do fluxo também não transforma um teste falhado num teste funcionalmente aprovado. Conserva as duas informações no relatório.
5. Verificar todas as condições de acesso
Um stage pode consumir environment, service connection e outros recursos protegidos. Constrói a lista dos recursos efetivamente usados e dos checks pendentes em cada um. No caso prático, o environment está aprovado, mas a service connection ainda espera por decisão. Repetir o voto no primeiro recurso não resolve o segundo. A autorização da pipeline também é explícita: copiar YAML para uma pipeline nova não lhe transfere automaticamente o acesso da antiga. Outra investigação pode encontrar Branch control a rejeitar a origem do run de um artefacto ligado, apesar de o deployment correr em main. Confirma a referência completa permitida e a execução realmente consumida. Finalmente, não confundas mudança de configuração com atualização de uma avaliação em curso: a lista de aprovadores fica fixada quando os checks começam. Planeia disponibilidade dos responsáveis antes da janela e confirma como uma nova tentativa será avaliada.
6. Separar receção, decisão e janela de execução
Numa integração assíncrona, o HTTP inicial confirma receção; o callback comunica a decisão de acesso. Se o serviço externo terminar o seu trabalho mas não enviar a decisão, a pipeline continua sem essa evidência. Regista a instância e o resultado esperado, sem incluir tokens em relatórios. Uma decisão final de falha não é equivalente a uma espera por sondagem. Corrigir a causa permite preparar uma nova avaliação pelo processo autorizado. Considera também o tempo: uma aprovação diferida só se torna efetiva à hora escolhida e não resolve outros checks. Se Business Hours passou mas o stage continua bloqueado até a janela fechar, a autorização horária pode ser retirada. No cenário, às 23:05 continuam por resolver a decisão externa e o calendário. Explica estes dois bloqueios ao negócio e conserva o artefacto avaliado ao replanear. Reconstruir por conveniência pode invalidar evidência já recolhida.
7. Relacionar capacidade, identidade e limites de execução
Uma demand ajuda a selecionar um agente; não instala a ferramenta em falta. Confirmar software real, descobrir capabilities e ensaiar a tarefa são passos diferentes. Após instalar software num agente self-hosted, reinicia-o em manutenção autorizada para atualizar a descoberta. Distingue ainda a conta de registo da conta que executa o serviço: no exemplo Windows, a partilha é lida por svc-build. Os direitos do administrador que registou o agente não resolvem essa operação. Para concorrência, maxParallel limita a matrix mesmo com agentes suficientes. Para duração, o limite de uma tarefa não prolonga o limite do job. Uma finalização elegível após cancelamento também precisa de caber no cancelTimeoutInMinutes. Pede ao aluno que calcule o tempo restante antes de sugerir mais retries. No final, uma espera ManualValidation pode usar job sem agente, enquanto o ensaio Bash seguinte precisa do seu contexto de agente e dependência.
8. Ensaiar decisões e comunicar o que falta
O código abaixo é um modelo local do contrato fictício, sem chamadas Azure nem interpretação de YAML. Cobre catorze fronteiras e cem combinações de resultados. Prevê primeiro quais as duas combinações que permitem Package e verifica que falha, cancelamento ou pai inacessível não são aceites. Depois compara os minutos 21:59, 22:00 e 23:00 e troca a decisão externa de passed para received. Receção não deve satisfazer o contrato. A janela simples fica dentro do mesmo dia; fusos horários e janelas que atravessam a meia-noite ficam fora deste exercício. O modelo também não calcula capacidade nem executa recuperação de aplicações. Usa os resultados para escrever uma decisão curta com evidência, limitação e próximo responsável. No trabalho real, junta a observação do serviço e o runbook relevante. Termina a aula distinguindo o que passou, o que nunca executou e o que continua a exigir aceitação humana.
# Original fictional acceptance model. No Azure APIs or YAML expression engine.
# Window uses minutes within one day; overnight windows are outside this exercise.
from itertools import product
def can_package(parent_started, cancelled, tests, docs):
return (parent_started and not cancelled
and tests == 'Succeeded'
and docs in {'Succeeded', 'Skipped'})
def ready_to_start(minute, window, checks):
start, end = window
return (start <= minute < end and bool(checks)
and all(value == 'passed' for value in checks.values()))
assert can_package(True, False, 'Succeeded', 'Succeeded')
assert can_package(True, False, 'Succeeded', 'Skipped')
assert not can_package(True, False, 'Skipped', 'Succeeded')
assert not can_package(True, False, 'Failed', 'Skipped')
assert not can_package(True, False, 'Succeeded', 'Failed')
assert not can_package(False, False, 'Succeeded', 'Succeeded')
assert not can_package(True, True, 'Succeeded', 'Succeeded')
assert not can_package(True, False, 'SucceededWithIssues', 'Skipped')
checks = {'environment': 'passed', 'external-decision': 'passed'}
assert not ready_to_start(21 * 60 + 59, (22 * 60, 23 * 60), checks)
assert ready_to_start(22 * 60, (22 * 60, 23 * 60), checks)
assert not ready_to_start(23 * 60, (22 * 60, 23 * 60), checks)
assert not ready_to_start(22 * 60 + 50, (22 * 60, 23 * 60), {**checks, 'external-decision': 'pending'})
assert not ready_to_start(22 * 60 + 50, (22 * 60, 23 * 60), {**checks, 'external-decision': 'received'})
assert not ready_to_start(22 * 60 + 50, (22 * 60, 23 * 60), {})
# Two accepted combinations out of 100 in this deliberately strict contract.
states = ('Succeeded', 'SucceededWithIssues', 'Skipped', 'Failed', 'Canceled')
accepted = {(True, False, 'Succeeded', 'Succeeded'),
(True, False, 'Succeeded', 'Skipped')}
count = 0
for inputs in product((False, True), (False, True), states, states):
assert can_package(*inputs) == (inputs in accepted), inputs
count += 1
print(f'14 boundary checks and {count} policy combinations passed')
Prepare pausa um consumidor; Deploy falha; Recover fica Skipped e Resume não executa. O aluno identifica o caminho inacessível e decide como confirmar e recuperar o serviço sem repetir uma mudança às cegas.
Armadilhas comuns
Usar outputs antes de existirem; confundir posição no YAML com dependência; interpretar always como garantia de execução; tratar HTTP 200 como decisão final; trocar artefactos durante aprovação; assumir que timeout maior numa tarefa prolonga o job.
Tópicos relacionados: Identidade de artefactos · Gestão de mudanças · Resposta a incidentes · Agentes e permissões
Localiza a fase e a condição que faltam. A decisão de release precisa de evidência da combinação, dos recursos e da janela; a recuperação precisa também do estado real do serviço.
Referência: Pipeline conditions · AZ-400 objectives 2026-07-27