[
  {
    "chave": "CS-95",
    "territorio": "backend",
    "titulo": "O CURSO PRESENCIAL PASSA A EXISTIR, E E' COISA PROPRIA (⛔ nao uma `Aula` com etiqueta: a aula tem duracao multipla de 20 imutavel, blocos, questoes e link de transmissao): `model Curso` com OS CINCO CAMPOS QUE O DONO NOMEOU — o que e' · quando · onde · LIMITE DE VAGAS · nucleo (regra 52) — mais migracao e `POST`/`GET`/`PATCH /cursos`. SO' A SECRETARIA anuncia (regra 57) e os outros tres levam 403 DO SERVIDOR; 0 VAGAS e DATA NO PASSADO sao RECUSADOS com a frase que diz O QUE ACONTECEU E O QUE FAZER (⛔ nunca «dados invalidos») e ⛔ NADA fica gravado; o medico PENDENTE le' 200 COM LISTA VAZIA e ⛔ nao 403 (regra 46, mesmo gesto de `aula.controlador.ts:80-92`). ⛔ NENHUMA inscricao, ⛔ NENHUM ponto e ⛔ NADA da pergunta 94 neste card (criterios 1, 3 e 6)",
    "escopo_paths": [
      "backend/prisma/schema.prisma",
      "backend/prisma/migrations/",
      "backend/src/modules/curso/",
      "backend/src/app.module.ts",
      "backend/test/curso.e2e-spec.ts"
    ],
    "aceites": [
      "cd backend && npx jest test/curso.e2e-spec.ts --runInBand --ci",
      "cd backend && npx jest test/curso.e2e-spec.ts --runInBand --ci -t 'a secretaria anuncia tres cursos: um em Cardiologia, um em Pediatria e um sem nucleo' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/curso.e2e-spec.ts --runInBand --ci -t 'curso com 0 vagas e recusado com frase que diz o que fazer, e nada fica gravado' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/curso.e2e-spec.ts --runInBand --ci -t 'curso com data no passado e recusado do mesmo modo e a lista continua com tres' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/curso.e2e-spec.ts --runInBand --ci -t 'so a secretaria anuncia: coordenador, medico e especialista levam 403' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/curso.e2e-spec.ts --runInBand --ci -t 'o medico ATIVO ve os tres cursos e o PENDENTE le 200 com lista vazia' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/curso.e2e-spec.ts --runInBand --ci -t 'o curso sem nucleo le-se sem nucleo, sem erro e sem inventar nucleo nenhum' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/curso.e2e-spec.ts --runInBand --ci -t 'o limite de vagas fica gravado tal e qual e um curso nunca nasce com zero' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/curso.e2e-spec.ts --runInBand --ci -t 'editar o curso guarda e o id nao muda' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/curso.e2e-spec.ts --runInBand --ci -t 'o nucleo arquivado nao se oferece num curso novo e continua a ler-se no curso velho' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && grep -q 'model Curso' prisma/schema.prisma",
      "cd backend && ! grep -rniE 'fila|desisten|cancelar|promocao' src/modules/curso/",
      "cd backend && ! grep -rniE 'pontos?_|ranking|somar' src/modules/curso/",
      "cd backend && ! grep -rniE 'maissaude|mais-saude|mais saude' src/modules/curso/",
      "cd backend && npx jest test/aula.e2e-spec.ts test/nucleo.e2e-spec.ts test/parametro.e2e-spec.ts --runInBand --ci",
      "cd backend && npx jest  --runInBand --ci"
    ],
    "depende_de": []
  },
  {
    "chave": "CS-96",
    "territorio": "backend",
    "titulo": "A FOLHA DE PRESENCAS, UM A UM E POSTERIOR AO CURSO (regra 52): a linha de inscricao nasce a CARREGAR A CONFIRMACAO (`compareceu` · `confirmadoPorId` · `confirmadoEm`) e a secretaria marca cada inscrito por `POST /cursos/:cursoId/inscricoes/:id/compareceu` e `.../nao-compareceu` com **200 e ⛔ nao 201** («⛔ nao nasce recurso nenhum, decide-se um que ja' existe», `vinculo.controlador.ts:47`); A LINHA ⛔ NUNCA SE APAGA (`:65`), ⛔ NAO EXISTE rota que marque a lista inteira (sao TRES rotas, contadas), e ⛔ NAO se grava ponto nenhum — o FACTO fica guardado para a demanda 29 o somar (precedente medido: `RespostaQuestao` ⛔ nao tem coluna de pontos, schema:387). ⚠️ A linha nasce SEM estado proprio de inscricao e O ACTO DO MEDICO SE INSCREVER ⛔ NAO E' DESTE CARD (espera a pergunta 94): as linhas da prova semeiam-se pelo `PrismaService`, como o `vinculo.e2e-spec.ts` ja' faz (criterios 4 e 5)",
    "escopo_paths": [
      "backend/prisma/schema.prisma",
      "backend/prisma/migrations/",
      "backend/src/modules/inscricao/",
      "backend/src/app.module.ts",
      "backend/test/presenca.e2e-spec.ts"
    ],
    "aceites": [
      "cd backend && npx jest test/presenca.e2e-spec.ts --runInBand --ci",
      "cd backend && npx jest test/presenca.e2e-spec.ts --runInBand --ci -t 'com tres inscritos a secretaria marca dois COMPARECEU e um NAO COMPARECEU, um a um' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/presenca.e2e-spec.ts --runInBand --ci -t 'cada confirmacao grava quem assinou e quando' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/presenca.e2e-spec.ts --runInBand --ci -t 'confirmar responde 200 e nao 201, como o vinculo ja faz' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/presenca.e2e-spec.ts --runInBand --ci -t 'nenhuma linha e apagada e reabrir a lista mostra os mesmos dois e um' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/presenca.e2e-spec.ts --runInBand --ci -t 'corrigir a marca troca a marca e reescreve quem assinou e quando, sem apagar a linha' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/presenca.e2e-spec.ts --runInBand --ci -t 'so a secretaria confirma: coordenador, medico e especialista levam 403' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/presenca.e2e-spec.ts --runInBand --ci -t 'inscrito por confirmar le-se por confirmar, e nao como falta' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/presenca.e2e-spec.ts --runInBand --ci -t 'a lista de inscritos de um curso que nao existe da 404, e nao lista vazia' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/presenca.e2e-spec.ts --runInBand --ci -t 'a presenca confirmada nao grava ponto nenhum: a linha nao tem numero de pontos' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && grep -q 'model InscricaoCurso' prisma/schema.prisma",
      "cd backend && test $(grep -rE '@(Get|Post|Put|Patch|Delete)\\(' src/modules/inscricao/ | wc -l) -eq 3",
      "cd backend && ! grep -rniE 'pontos?_|ranking|somar' src/modules/inscricao/",
      "cd backend && ! grep -rniE 'fila|desisten|cancelar|promocao' src/modules/inscricao/",
      "cd backend && npx jest test/curso.e2e-spec.ts test/vinculo.e2e-spec.ts --runInBand --ci",
      "cd backend && npx jest  --runInBand --ci"
    ],
    "depende_de": [
      "CS-95"
    ]
  },
  {
    "chave": "CS-97",
    "territorio": "backend",
    "titulo": "NASCE A CHAVE `pontos_curso_presencial` (inteiro >= 0, A MESMA FORMA de `pontos_por_responder`), com a omissao **10 semeada SO' NA MIGRACAO** — ⛔ NENHUM numero em codigo (regra 53). A secretaria muda-a de 10 para 25 por `PUT /parametros/pontos_curso_presencial` SEM DEPLOY, os outros tres papeis levam 403, zero e legitimo, negativo ⛔ nao, e o que ja' esta' gravado ⛔ nao se recalcula. ⚠️ `CHAVES_PARAMETRO` era fechada POR AMBITO DO CS-10 («⛔ nao se criam nem se apagam chaves aqui»), ⛔ nao por proibicao para sempre — e o CS-35 ja' abriu a quinta em `epic/CS-32`. ⟹ ⛔ NENHUM aceite deste card CONTA chaves: medem-se OS NOMES, e as quatro antigas ficam intactas (criterio 5)",
    "escopo_paths": [
      "backend/src/modules/parametro/",
      "backend/prisma/migrations/",
      "backend/test/parametro.e2e-spec.ts"
    ],
    "aceites": [
      "cd backend && npx jest test/parametro.e2e-spec.ts --runInBand --ci",
      "cd backend && npx jest test/parametro.e2e-spec.ts --runInBand --ci -t 'a chave pontos_curso_presencial existe num banco recem-migrado e vale 10' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/parametro.e2e-spec.ts --runInBand --ci -t 'a secretaria muda de 10 para 25 sem deploy e a leitura seguinte da 25' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/parametro.e2e-spec.ts --runInBand --ci -t 'valor negativo e recusado com frase que diz o que fazer e o valor guardado nao muda' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/parametro.e2e-spec.ts --runInBand --ci -t 'valor com casas decimais e recusado: esta chave e inteira, como pontos_por_responder' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/parametro.e2e-spec.ts --runInBand --ci -t 'zero e legitimo e nao e erro: comparecer pode nao valer nada' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/parametro.e2e-spec.ts --runInBand --ci -t 'so a secretaria muda: coordenador, medico e especialista levam 403' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/parametro.e2e-spec.ts --runInBand --ci -t 'as quatro chaves antigas continuam la, com os mesmos nomes e os mesmos limites' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && npx jest test/parametro.e2e-spec.ts --runInBand --ci -t 'correr a migracao duas vezes nao sobrescreve o que a secretaria mudou' 2>&1 | tee /dev/stderr | grep -qE '^Tests:.* [1-9][0-9]* passed'",
      "cd backend && grep -q \"'pontos_curso_presencial'\" src/modules/parametro/chaves.ts",
      "cd backend && grep -q 'pontos_por_responder' src/modules/parametro/chaves.ts && grep -q 'pontos_extra_por_acertar' src/modules/parametro/chaves.ts && grep -q 'dias_gravacao' src/modules/parametro/chaves.ts && grep -q 'multiplicador_gravada' src/modules/parametro/chaves.ts",
      "cd backend && grep -rqE 'pontos_curso_presencial[^0-9]*10' prisma/migrations/*/migration.sql",
      "cd backend && test $(grep -rn 'pontos_curso_presencial' src/ | grep -cE '[0-9]') -eq 0",
      "cd backend && npx jest test/participacao.e2e-spec.ts test/gravacao.e2e-spec.ts --runInBand --ci",
      "cd backend && npx jest  --runInBand --ci"
    ],
    "depende_de": []
  },
  {
    "chave": "CS-98",
    "territorio": "frontend",
    "titulo": "A PORTA «Cursos» ENTRA NA FONTE UNICA E O MEDICO CHEGA A' LISTA PELO MENU (⛔ nao pelo endereco escrito a' mao): `/cursos` mostra o que e' · quando · onde · O LIMITE DE VAGAS (⛔ NAO vagas restantes: isso espera a pergunta 94) · o nucleo, filtra por CHIP DE NUCLEO do M3 com ✓ (regra 83: 1 de 3 · limpar ⟹ 3 de 3; sem nucleo = «Geral») e o VALOR DA PRESENCA CONFIRMADA VEM DO SERVIDOR (`GET /parametros/pontos_curso_presencial`: 10 ⟹ 10, 25 ⟹ 25, ⛔ zero numeros em codigo). Porta para SECRETARIA e MEDICO (regra 112), com `icone: undefined` pelo precedente EXACTO de «UPAs», «Nucleos» e «Sistema» — ⛔ nao ha' nome de icone para cursos no conjunto FECHADO e ⛔ nao se inventa peca num card de ecra. 🩸 AS TRES PROVAS QUE A PORTA NOVA PARTE SAO ACTUALIZADAS, ⛔ nao contornadas: `navegacao.spec.ts` (portas + orfas = TODAS as page.tsx), `alcance.spec.ts` (ESPERADO alcancavel POR CLIQUE + ANCORAS + ESTADOS, cada um com ficheiro:linha) e `botoes.spec.ts` (⛔ zero botao mudo: `add`, `filter_list` e `chevron_right` ja' existem). Os SEIS ESTADOS (regra 84), foco de teclado visivel em todos (criterios 1, 3, 5 e 6)",
    "escopo_paths": [
      "frontend/src/app/cursos/",
      "frontend/src/lib/navegacao.ts",
      "frontend/e2e/cursos.spec.ts",
      "frontend/e2e/navegacao.spec.ts",
      "frontend/e2e/alcance.spec.ts"
    ],
    "aceites": [
      "cd frontend && npx playwright test e2e/cursos.spec.ts --reporter=line",
      "cd frontend && npx playwright test e2e/cursos.spec.ts --reporter=line -g 'o medico chega a Cursos pelo menu e ve 3 de 3'",
      "cd frontend && npx playwright test e2e/cursos.spec.ts --reporter=line -g 'o chip Cardiologia deixa 1 de 3 e limpar o filtro volta a 3 de 3'",
      "cd frontend && npx playwright test e2e/cursos.spec.ts --reporter=line -g 'o curso sem nucleo mostra-se como Geral e tem chip proprio'",
      "cd frontend && npx playwright test e2e/cursos.spec.ts --reporter=line -g 'a lista mostra o limite de vagas e nunca vagas restantes'",
      "cd frontend && npx playwright test e2e/cursos.spec.ts --reporter=line -g 'o medico PENDENTE ve o vazio com a frase do que ali vai estar, e nao um erro'",
      "cd frontend && npx playwright test e2e/cursos.spec.ts --reporter=line -g 'o valor da presenca confirmada vem do servidor: com 10 le-se 10 e com 25 le-se 25'",
      "cd frontend && npx playwright test e2e/cursos.spec.ts --reporter=line -g 'os seis estados da lista de cursos: vazio, a carregar, erro, sem permissao, sucesso e parcial'",
      "cd frontend && npx playwright test e2e/cursos.spec.ts --reporter=line -g 'o 403 do servidor mostra o cadeado e nao deixa ver o dado por baixo'",
      "cd frontend && npx playwright test e2e/cursos.spec.ts --reporter=line -g 'o vazio do filtro diz como se limpa o filtro'",
      "cd frontend && npx playwright test e2e/cursos.spec.ts --reporter=line -g 'o foco de teclado e visivel em cada alvo da lista e o alvo mede 48dp'",
      "cd frontend && npx playwright test e2e/cursos.spec.ts --reporter=line -g 'com prefers-reduced-motion reduce as duracoes sao zero e o estado final e o mesmo pixel'",
      "cd frontend && grep -q \"caminho: '/cursos'\" src/lib/navegacao.ts",
      "cd frontend && ! grep -rqE '#[0-9a-fA-F]{3,8}|shimmer|animate-pulse|<progress' src/app/cursos/",
      "cd frontend && npx playwright test e2e/navegacao.spec.ts e2e/alcance.spec.ts --reporter=line",
      "cd frontend && npx playwright test e2e/botoes.spec.ts e2e/icones.spec.ts e2e/calendario.spec.ts --reporter=line",
      "cd frontend && npx playwright test --reporter=line"
    ],
    "depende_de": [
      "CS-95",
      "CS-97"
    ]
  },
  {
    "chave": "CS-99",
    "territorio": "frontend",
    "titulo": "A SECRETARIA ANUNCIA UM CURSO PELO ECRA: `/cursos/novo` — ORFA DELIBERADA (e' ACTO, letra por letra o motivo de `/secretaria/upas/nova`), chega-se pelo botao em `/cursos` e o botao SO' aparece a' SECRETARIA. Os CINCO campos (o que e' · quando · onde · limite de vagas · nucleo ESCOLHIDO DE UMA LISTA, ⛔ nao texto livre — regra 102); 0 VAGAS e DATA NO PASSADO levam a frase que diz O QUE ACONTECEU E O QUE FAZER (⛔ nunca «campo invalido», regra 85), ⛔ nada fica gravado e a lista continua com 3; o botao A TRABALHAR ⛔ NAO ENCOLHE e o rotulo FICA NO SITIO; e um papel que ⛔ nao cadastra leva o **403 DO SERVIDOR** — ⛔ nao basta o botao escondido. Os SEIS ESTADOS e as tres provas de navegacao ACTUALIZADAS (criterios 1 e 6)",
    "escopo_paths": [
      "frontend/src/app/cursos/",
      "frontend/src/lib/navegacao.ts",
      "frontend/e2e/cursos-anunciar.spec.ts",
      "frontend/e2e/navegacao.spec.ts",
      "frontend/e2e/alcance.spec.ts"
    ],
    "aceites": [
      "cd frontend && npx playwright test e2e/cursos-anunciar.spec.ts --reporter=line",
      "cd frontend && npx playwright test e2e/cursos-anunciar.spec.ts --reporter=line -g 'a secretaria anuncia tres cursos e os tres aparecem na lista: 3 de 3'",
      "cd frontend && npx playwright test e2e/cursos-anunciar.spec.ts --reporter=line -g 'o nucleo escolhe-se de uma lista e nunca se escreve a mao'",
      "cd frontend && npx playwright test e2e/cursos-anunciar.spec.ts --reporter=line -g 'um curso pode ficar sem nucleo e le-se como Geral'",
      "cd frontend && npx playwright test e2e/cursos-anunciar.spec.ts --reporter=line -g '0 vagas leva a frase que diz o que aconteceu e o que fazer, e nada fica gravado'",
      "cd frontend && npx playwright test e2e/cursos-anunciar.spec.ts --reporter=line -g 'data no passado leva a mesma forma de recusa e a lista continua com tres'",
      "cd frontend && npx playwright test e2e/cursos-anunciar.spec.ts --reporter=line -g 'o botao de anunciar mostra-se so a secretaria e o 403 do servidor aparece a quem forca o endereco'",
      "cd frontend && npx playwright test e2e/cursos-anunciar.spec.ts --reporter=line -g 'o botao a trabalhar mantem o rotulo no sitio e nao muda de largura'",
      "cd frontend && npx playwright test e2e/cursos-anunciar.spec.ts --reporter=line -g 'os seis estados do ecra de anunciar: vazio, a carregar, erro, sem permissao, sucesso e parcial'",
      "cd frontend && npx playwright test e2e/cursos-anunciar.spec.ts --reporter=line -g 'o foco de teclado e visivel em cada campo e em cada botao, e o alvo mede 48dp'",
      "cd frontend && npx playwright test e2e/cursos-anunciar.spec.ts --reporter=line -g 'com prefers-reduced-motion reduce as duracoes sao zero e o estado final e o mesmo pixel'",
      "cd frontend && ! grep -rqE '#[0-9a-fA-F]{3,8}|shimmer|animate-pulse' src/app/cursos/",
      "cd frontend && grep -q \"caminho: '/cursos/novo'\" src/lib/navegacao.ts",
      "cd frontend && npx playwright test e2e/cursos.spec.ts e2e/navegacao.spec.ts e2e/alcance.spec.ts --reporter=line",
      "cd frontend && npx playwright test e2e/botoes.spec.ts --reporter=line",
      "cd frontend && npx playwright test --reporter=line"
    ],
    "depende_de": [
      "CS-98"
    ]
  },
  {
    "chave": "CS-100",
    "territorio": "frontend",
    "titulo": "🩸 CONFIRMAR PRESENCA E' PAGINA E ⛔ NAO DIALOGO — regra 86 a' letra («⛔ ACEITAR MEDICO, CONFIRMAR PRESENCA E APROVAR CERTIFICADO ⛔ NAO SAO DIALOGOS: SAO PAGINAS»): `/cursos/[id]/presencas`, orfa deliberada (DETALHE — clica-se o curso em `/cursos`), SO' da SECRETARIA. Lista os INSCRITOS e marca UM A UM COMPARECEU ou ⛔ NAO COMPARECEU — ⛔ NAO EXISTE botao que marque a lista inteira; cada linha diz QUEM ASSINOU E QUANDO, ⛔ nenhuma linha desaparece, reabrir mostra os MESMOS 2 e 1, o «⛔ nao compareceu» conta **0 e ⛔ NUNCA numero negativo** (⛔ sem castigo na cara do produto, regra 84) e o valor do que compareceu vem do PARAMETRO. O PARCIAL — o estado mais importante deste produto — e' a lista com uns confirmados e outros AINDA POR CONFIRMAR, com o total em tabular AO LADO e ⛔ nunca EM VEZ. Os SEIS ESTADOS e as tres provas de navegacao ACTUALIZADAS (criterios 4, 5 e 6)",
    "escopo_paths": [
      "frontend/src/app/cursos/",
      "frontend/src/lib/navegacao.ts",
      "frontend/e2e/presencas.spec.ts",
      "frontend/e2e/navegacao.spec.ts",
      "frontend/e2e/alcance.spec.ts"
    ],
    "aceites": [
      "cd frontend && npx playwright test e2e/presencas.spec.ts --reporter=line",
      "cd frontend && npx playwright test e2e/presencas.spec.ts --reporter=line -g 'com tres inscritos a secretaria marca dois COMPARECEU e um NAO COMPARECEU, um a um'",
      "cd frontend && npx playwright test e2e/presencas.spec.ts --reporter=line -g 'nao existe botao nenhum que marque a lista inteira'",
      "cd frontend && npx playwright test e2e/presencas.spec.ts --reporter=line -g 'confirmar presenca e pagina e nao dialogo: nenhum dialogo no acto'",
      "cd frontend && npx playwright test e2e/presencas.spec.ts --reporter=line -g 'cada linha confirmada diz quem assinou e quando, e nenhuma linha desaparece'",
      "cd frontend && npx playwright test e2e/presencas.spec.ts --reporter=line -g 'reabrir a folha mostra os mesmos dois e um'",
      "cd frontend && npx playwright test e2e/presencas.spec.ts --reporter=line -g 'o marcado como nao compareceu conta 0, nunca um numero negativo e nunca a vermelho'",
      "cd frontend && npx playwright test e2e/presencas.spec.ts --reporter=line -g 'o que compareceu vale o que o parametro diz: com 10 le-se 10 e com 25 le-se 25'",
      "cd frontend && npx playwright test e2e/presencas.spec.ts --reporter=line -g 'o estado PARCIAL: uns confirmados e outros por confirmar, com o total ao lado e nunca em vez'",
      "cd frontend && npx playwright test e2e/presencas.spec.ts --reporter=line -g 'os seis estados da folha de presencas: vazio, a carregar, erro, sem permissao, sucesso e parcial'",
      "cd frontend && npx playwright test e2e/presencas.spec.ts --reporter=line -g 'quem nao confirma leva o cadeado do 403 do servidor e nao ve o dado por baixo'",
      "cd frontend && npx playwright test e2e/presencas.spec.ts --reporter=line -g 'o foco de teclado e visivel em cada botao de confirmacao e o alvo mede 48dp'",
      "cd frontend && npx playwright test e2e/presencas.spec.ts --reporter=line -g 'com prefers-reduced-motion reduce as duracoes sao zero e o estado final e o mesmo pixel'",
      "cd frontend && ! grep -rqiE 'marcar todos|confirmar todos|todos compareceram' src/app/cursos/",
      "cd frontend && ! grep -rqE '#[0-9a-fA-F]{3,8}|shimmer|animate-pulse' src/app/cursos/",
      "cd frontend && npx playwright test e2e/cursos.spec.ts e2e/cursos-anunciar.spec.ts e2e/navegacao.spec.ts e2e/alcance.spec.ts --reporter=line",
      "cd frontend && npx playwright test e2e/botoes.spec.ts --reporter=line",
      "cd frontend && npx playwright test --reporter=line"
    ],
    "depende_de": [
      "CS-96",
      "CS-99"
    ]
  }
]