# Entrega — Auditoria e unificação do RH Ponto (ATM-VPS-UP2410)

**Estado:** código e SQL prontos e testados em ambiente isolado. **Nada foi aplicado ao banco real.**
Execução da suíte: `npm test` → **151 testes, 151 aprovados, 0 falhas, 0 pulados** (48 motor · 40 matriz de tolerância · 12 integração · 17 migração/rollback em MariaDB 10.11 descartável · 12 pendências/painel · 5 smoke HTTP/DOM · 8 revisão dos prints · 9 saldo/observação). Ver §9 a §12.

## 1. Diagnóstico — causa raiz de cada problema (todos reproduzidos em teste antes de corrigir)

| # | Problema | Causa raiz | Evidência (código original) |
|---|---|---|---|
| 1 | Dashboard semanal: 0 h trabalhada e todo dia útil = falta | `pontoUtils.js` procura tipos `almoco_saida`/`almoco_retorno`; o ENUM real é `entrada\|almoco\|retorno\|saida` | `calcularHorasTrabalhadas` devolveu `"0.00"` para um dia completo |
| 2 | Atraso compensado por saída posterior | Critério `jornada ± tolerância` sobre o **total** do dia | 08:07→17:55: tudo `00:00` |
| 3 | Tolerância sem regra por marcação nem teto diário | Sem horários previstos; comparação só do saldo | Faltante só se `> tolerância`; sem 5 min/marcação, sem 10 min/dia |
| 4 | Hora noturna contada duas vezes | `processarDia` soma minutos após 22:00 às extras mesmo já contidos no saldo | Saída 23:00: extras `06:12` (correto `05:12`) |
| 5 | Turno que cruza a meia-noite zera/negativa | `calcularMinutos` usa a mesma data; o turno ainda era quebrado por data civil | 22:00→06:00: trabalhado `00:00`, faltante `24:00` |
| 6 | Noturno só olha a saída do 2º período | Ignora jornadas de 2 batidas e entradas noturnas | — |
| 7 | `horasExtrasNoturnas` mistura conceitos | Soma "tempo na faixa noturna" com "extras" | — |
| 8 | 08:48 silencioso | `getJornadaFuncionario` devolvia 528 quando vazio (2 cópias) | `return 528` |
| 9 | Tolerância global possivelmente inoperante | Tela grava a **coluna** `tolerancia_minutos`; o relatório lia **linhas** `chave='tolerancia_minutos'` | **Hipótese — confirmar no banco** (ver §7) |
| 10 | 4 batidas presumidas | Sequência fixa E/A/R/S | Aprendiz de 2 batidas só funcionava por "turno simples" |
| 11 | Dia com marcação faltando virava falta/débito automático | `horasTrabalhadas === 0` ⇒ falta | Só entrada: `faltas = 1`, `08:48` faltantes |
| 12 | Cópias concorrentes do cálculo | 4 implementações (controller, serviço semanal, pontoUtils, admin.js) | ver §2 |
| 13 | Relatório semanal só roda se minuto ≥ 30 | `hora>=18 && minuto>=30` falha às 19:10 | Corrigido de passagem |

## 2. Mapa dos arquivos alterados

**Novos:** `utils/apuracaoPonto.js` (motor único, funções puras) · `services/regrasPonto.js` (leitura das regras globais de sábado/domingo/feriado — único ponto) · `migrations/20261024_ponto_individual.sql` e `…_ROLLBACK.sql` · `tests/*` · este documento.

| Arquivo | Mudança |
|---|---|
| `controllers/relatorioPontoController.js` | `processarDia` **removido**; `processarDados`/`gerarRelatorio` usam o motor; `getConfiguracoes` só lê regras de sáb/dom/feriado (não lê tolerância); `getJornadaFuncionario` sem padrão silencioso; novo `montarLinhaDia` (apresentação). `calcularValeRefeicao`, ajustes/abonos/restauração **intactos** |
| `services/relatorioSemanalService.js` | cálculo próprio removido; usa o motor; `isApos1830` corrigido |
| `routes/registroPonto.js` | resumo semanal do dashboard usa o motor; `findByPk` agora carrega `jornTrabalho` e campos novos (antes não carregava a jornada) |
| `utils/pontoUtils.js` | reduzido a `agruparPorDia` (funções com tipos inexistentes removidas) |
| `routes/admin.js` | rota legada (não montada, template inexistente) → apenas redireciona |
| `models/Funcionario.js` | 8 colunas opcionais |
| `controllers/funcionarioController.js` | valida a seção no servidor (`ponto_secao=1`) |
| `views/cruds/funcionarios/index.ejs` | seção **Jornada e regras de ponto** |
| `views/admin/ponto-calculado.ejs`, `…-pdf.ejs` | jornada não configurada, pendência vinda do motor, avisos |
| `views/admin/gerenciador.ejs` | rótulo da tolerância global: DESCONTINUADA (campo e dado mantidos) |

## 3. Arquitetura do motor (`utils/apuracaoPonto.js`)

1. **Configuração efetiva** — `interpretarJornada`, `resolverConfigFuncionario` (só campos do funcionário), `validarConfigPonto` (servidor: tolerância 0–5, jornada ≤ 10 h, soma dos horários = jornada).
2. **Validação/ordenação** — `normalizarRegistros` (não altera as originais), `montarTurnos` (entrada→saída atravessando meia-noite; turno pertence ao dia da **entrada**).
3. **Tempo trabalhado** — `trechosDoTurno` (só trechos fechados).
4. **Tolerância** — `aplicarTolerancia`: ≤ tolerância por marcação não conta; soma das toleradas > 10 min/dia ⇒ todas contam; marcação acima da tolerância conta **inteira**.
5. **Classificação** — `apurarDia`: atraso, saída antecipada, faltante, crédito/extras (diurnas × noturnas), trabalhado na faixa 22–05, hora noturna reduzida (informativa), falta, pendência.
6. **Consolidação** — `apurarPeriodo`/`totalizar` (única função de soma; HTML, PDF, resumos, dashboard e WhatsApp apenas apresentam).

Modos: `por_marcacao` (exige horários previstos), `por_duracao` (sem horários — **nada é inventado**, aviso explícito), `incompleto`, `configuracao_incompleta`, `dia_especial`, `falta`, `em_andamento`.

## 4. Campos novos em `Funcionario` (todos NULL por padrão) e justificativa

| Coluna | Por quê |
|---|---|
| `tolerancia_ponto_min` TINYINT | Tolerância individual (0–5). Substitui a global |
| `ponto_batidas` TINYINT | 2 ou 4: a duração não permite inferir (04:00 ≠ aprendiz ≠ 2 batidas) |
| `ponto_hora_entrada/almoco/retorno/saida` TIME ×4 | Única forma de aplicar a tolerância **por marcação** sem inventar horário |
| `ponto_perfil` VARCHAR(20) | Informativo (padrão/reduzida/personalizada); não altera cálculo |
| `ponto_regras_desde` DATE | Vigência: avisa que períodos anteriores podem ter tido outra jornada (o sistema não guarda histórico) |

Não criados por não terem fundamento atual: regras de extra individuais (sáb/dom/feriado continuam globais, como já eram) e janela noturna individual (22:00–05:00 fixa, como já era).

## 5. Migração (SQL **não executado em produção**) — v2, revisada

Arquivos: `20261024_ponto_individual.sql` · `…_ROLLBACK.sql` · `…_RESTORE.sql`.
- **Idempotente:** cada coluna só é criada se faltar (via `information_schema`); o único `UPDATE` grava só em `tolerancia_ponto_min IS NULL`. Reexecutar não duplica nem sobrescreve.
- **Conflito bloqueia:** se `configuracoes` tiver mais de um valor válido diferente (ex.: linha `chave`=3 e coluna=4, ou duas linhas diferentes), **nada é gravado** e a prévia mostra `CONFLITO`; o revisor define `@tol_override` (0–5). Sem fontes válidas → 5. Inválidos (negativo, >5, decimal, texto, vazio, NULL) são ignorados explicitamente; `@tol_override` inválido não grava nada.
- **Rollback seguro:** por padrão **só cria backup** (`Funcionario_ponto_cfg_bkp_<data_hora_µs>`) e informa; remove colunas apenas com `SET @confirmo_remover = 'SIM';` (comparação exata) e é **bloqueado** se houver horários/batidas/perfil/vigência configurados, salvo `@forcar_com_config = 'SIM'`. Mesmo removendo, o backup preserva tudo e `…_RESTORE.sql` recupera (só onde NULL).
- **Ordem de deploy:** SQL primeiro, código depois. Código **antigo** continua funcionando no banco migrado (provado com o model original); código **novo** não sobe sem as colunas (provado: erro de coluna inexistente).
- Política após a migração: tolerância `NULL` ⇒ 5 min + aviso; `configuracoes` mantida e ignorada pelos cálculos.

## 6. Antes × depois (motor novo, mesmos cenários do código original)

| Cenário | ANTES (trab / falt / extras / extras not. / faltas) | DEPOIS |
|---|---|---|
| 08:07→17:55 (atraso 7 + saída 7 depois) | 08:48 / 00:00 / 00:00 / 00:00 / 0 | atraso **00:07**, faltante **00:07**, extras **00:07** (separados, sem compensação) |
| 08:04→17:52 (4 e 4 min, dentro da tolerância) | tudo 0 | tolerado 00:08 (soma ≤ 10), nada descontado nem pago |
| Saída 23:00 (08:00/12:00/13:00) | 14:00 / 00:00 / **06:12** / 01:00 / 0 | extras **05:12** = 04:12 diurnas + 01:00 noturnas; noturno trabalhado 01:00 |
| Noturno 22:00→06:00, jornada 08:00 | **00:00 / 24:00** / 0 / 0 / 0 | 08:00 trabalhadas, 07:00 na faixa noturna, extras 00:00, faltante 00:00 |
| Só entrada+almoço | 04:00 / **04:48** / 0 / 0 / 0 | 04:00, **sem débito**, marcado "incompleto — conferir" |
| Só entrada | 00:00 / **08:48** / 0 / 0 / **1 falta** | **sem falta**, marcado "incompleto — conferir" |
| Sem registros em dia útil | 00:00 / 08:48 / 0 / 0 / 1 | idem (falta preservada) |
| Dashboard, dia completo | `0.00` h | 08:48 |

## 7. Preservação de dados — confirmação

- Motor é puro (sem `require`, sem I/O); teste congela as marcações e confirma que nada muda.
- Nas linhas **adicionadas** ao controller, serviço semanal e dashboard: nenhuma ocorrência de `create/update/destroy/bulk*/sync/alter` (verificado por diff contra o original).
- Rotinas de ajuste/abono/exclusão/restauração do controller: **não tocadas** (comparação método a método).
- Migração testada em MariaDB descartável: `RegistroPonto`, jornadas, status e `configuracoes` idênticos antes/depois (comparação byte a byte do conteúdo).
- Nenhum `sync({alter})` existe no projeto. Não há tabelas de fechamento de ponto persistidas: tudo é calculado sob demanda, então reapurar não sobrescreve valor histórico.

## 8. Limitações e decisões que dependem do RH / jurídico

1. **Schema real não inspecionado** (sem acesso ao banco). Nomes `Funcionario` / `jorn_trabalho` vêm da configuração Sequelize (`freezeTableName`, `underscored`); confirmar com `SHOW TABLES/COLUMNS` (pré-checagens no SQL). A hipótese #9 só se confirma com `SELECT * FROM configuracoes`.
2. **Dia incompleto não gera falta/débito automático** — decisão do RH já adotada (§9-B): vira pendência visível em todos os relatórios. Falta só existe sem nenhuma marcação (ou após o RH tratar a pendência).
3. **Atraso + saída posterior ficam separados** (§9-A, decisão D1 da matriz). Pela Súmula 366 só é hora extra o que excede a jornada normal; se a empresa compensa, é decisão de política/jurídico. **A matriz ainda não está validada juridicamente.**
4. **Interpretação do teto:** soma das variações ≤ 5 min cada, limite 10 min/dia; marcação > tolerância conta inteira. Validar com jurídico/convenção coletiva.
5. **Sem horários previstos** (todo funcionário até o RH preenchê-los) a apuração é `por_duracao` e **não detecta compensação** entre marcações; o relatório avisa. Para precisão legal, cadastrar os horários.
6. **Jornada ausente/ inválida:** sem extras/faltantes (aviso). Listar quem está assim com a consulta da seção 2.1 do SQL. Jornada legada "8" passou a ser lida como 8 **horas** (antes: 8 minutos) com aviso.
7. **Vale-refeição** continua usando 528 min como divisor quando não há jornada (regra existente de benefício, preservada).
8. **Sábado/domingo/feriado sem a regra de hora extra ligada** continuam zerando horas (preservado; o trabalhado real fica em `trabalhadoRealMin`). Texto "contabilizado como hora extra" em dia abonado foi removido (era enganoso).
9. **Histórico de jornada não existe** no sistema: configuração atual vale para todo o período; `ponto_regras_desde` apenas avisa.
10. **Adicional noturno:** o motor entrega minutos na faixa 22–05 (+ hora reduzida de 52'30" informativa). Valor monetário e reflexos seguem fora do sistema, como antes.
11. **Não verificado em execução real:** PDF via Chromium (o template EJS é renderizado nos testes, o Playwright não), rota do dashboard e formulário no navegador (apenas sintaxe/revisão e testes do motor/controller). Fazer um teste de aceitação manual em homologação.
12. **Painel do RH:** corrigido (§9-D).

## 9. Revisão dos 4 pontos (A–D)

**A. Atraso 7 + saída 7 depois.** Matriz de 39 casos (revisada na §11) com resultados esperados escritos à mão em `tests/matriz_tolerancia.js`, executada em 40 testes e publicada em `docs/MATRIZ_TOLERANCIA_SUMULA_366.md` (gerada da mesma tabela). Mostra a interpretação adotada (R1–R5), as 4 decisões em aberto (D1–D4) com a alternativa de cada uma e uma coluna **"Validado" em branco**. O saldo líquido é exposto (`saldoLiquidoMin`) só como informação. **Pendente:** validação jurídica/folha linha a linha — não considero liberado até isso.

**B. Jornada incompleta.** Segue a recomendação: sem desconto/falta automática. Textos: *"Jornada incompleta — conferir"*, com motivo específico (só entrada · saída p/ intervalo sem retorno · saída final ausente → RH confirma/justifica/corrige · marcação sem entrada · sequência inconsistente · intervalo ausente). A pendência **não some**: lista `apuracao.pendencias`, `diasIncompletos` nos resumos semanal/mensal (“+N pend.”), bloco de alerta no HTML e no PDF, linha no WhatsApp ("NÃO é falta") e nota "VR provisório". Falta confirmada (sem marcação alguma) continua distinta; abono do RH resolve a pendência. Não há tabela de pendências persistida (o sistema apura sob demanda): se o RH quiser fluxo de "resolvido por/quando", é uma etapa nova com tabela própria.

**C. Migração.** Os seis itens do checklist estão cobertos por testes em MariaDB isolado (M01–M12, R01–R05): linha global correta com várias linhas/conflito, individuais intactos (inclusive 0), inválidos/negativos/NULL, reexecução, app antes/depois (model real), rollback sem destruir configurações. A revisão achou e corrigiu 3 defeitos da v1: rollback destrutivo por padrão, UPDATE sem proteção contra conflito, e rollback reexecutado quebrava. Corrigidos mais 2 achados nos testes: colisão de nome do backup no mesmo segundo e confirmação sem diferenciar maiúsculas.

**D. Painel.** `utils/indicadoresPonto.js` centraliza os limites; zero literais `08:05`/`18:00` no `painelController`. Com horários previstos cadastrados usa a jornada e a tolerância **individuais**; sem eles usa o limite genérico e **diz isso**: rótulo "(indicador)" e tooltip na tela, `aviso` na API. Atrasos oficiais continuam só no Relatório de Ponto.

## 10. Checklist de validação (estado real)

| Item | Estado |
|---|---|
| Revisar o código real de `utils/apuracaoPonto.js` | ✅ revisado; correções (intervalo ausente só é pendência em dia útil; pendências estruturadas; saldo líquido informativo) e mutações provando que os testes detectam erros |
| Conferir SQL de migração e rollback | ✅ revisados e testados em MariaDB isolado; **falta a revisão humana do SQL antes de rodar em produção** |
| Tolerância em cenários combinados | ✅ matriz de 31 casos · ⏳ validação jurídica |
| Adicional noturno, extras, meia-noite | ✅ testes 22–24 e integração (turno aparece uma vez, um único VT) |
| Jornada incompleta = pendência | ✅ |
| Cadastro/edição no navegador | 🟡 testado em jsdom (campos, nomes iguais aos da validação, preenchimento na edição) e no servidor (400/update). **Não** em navegador real |
| Dashboard, HTML, PDF, WhatsApp | 🟡 dashboard por HTTP (supertest, relógio congelado), PDF = template EJS renderizado, WhatsApp = mensagem gerada. **PDF via Chromium e envio real não rodaram** (sem Chromium/WhatsApp aqui) → homologação |
| Compatibilidade com schema real e registros antigos | 🟡 provada com os **models do projeto** em MariaDB isolado e com registros sintéticos; **o banco real não foi inspecionado** |
| Regressão da aplicação inteira | 🟡 136 arquivos `.js` sem erro de sintaxe; 84/85 views compilam (a que falha, `sidebar-mensagens-integracao.ejs`, é idêntica ao original — falha pré-existente); 81 módulos de rotas/controllers/serviços/utils: **0 regressões** de carga vs. original (73 carregam, 3 deles novos; os 8 restantes falham igual no original por pacotes ausentes aqui). Rotas não alteradas não foram executadas: o projeto não tinha testes |

Os 68 testes originais foram preservados: os 48 do motor e os 12 de integração permanecem (2 asserções atualizadas para o novo texto e o novo critério de extras diurnas); os 8 de migração foram **substituídos** por 17 mais rígidos porque o SQL mudou.

## 11. Revisão pelos prints (05, 06 e 07/10/2026) — "Rever a lógica"

**O que os prints mostravam.** Os três dias reproduzem-se exatamente com a escala **08:00 / 10:00 / 11:00 / 17:48** cadastrada nesse funcionário (intervalo 10:00–11:00): faltante 01:30 · 01:40 · 01:25 e extra 02:02 · 01:48 · 01:41. **Confirme no cadastro: o intervalo previsto de 1 h parece ter sido digitado errado** (a duração fecha 08:48, por isso a validação não reclamou). O print 1 (sem horários) está correto: 09:20/00:32 · 08:56/00:08 · 09:04/00:16.

**Defeito de lógica (meu), corrigido.** Mesmo com a escala certa (12:00/13:00) o motor antigo apurava a saída e a volta do intervalo **separadamente**: no 07/10 (11:25→12:25, 1 h exata, só adiantada 35 min) mostrava 00:35 faltantes e 00:51 extras, sendo que o tempo trabalhado não mudou. Agora o **intervalo é medido pela duração**: se só se desloca, nada é apurado (provado para deslocamentos de −90 a +90 min). Os 01:25/01:41 do print 2 vinham, em parte, desse defeito e, em parte, do intervalo 10:00–11:00 cadastrado.

**Regra da entrada antecipada (política da empresa, como no seu texto).** Entrada adiantada acima da tolerância **não** vira crédito/hora extra, e os minutos **não são somados** à saída. Não ficam escondidos: aparecem em "não computado" no JSON, na observação do dia e em `apuracao.totais.naoComputadoMin`.

| Dia | Marcações | Trabalhado | Extras (antes, escala certa) | **Extras (agora)** | Não computado | Extras se a política for ligada |
|---|---|---|---|---|---|---|
| 05/10 | 07:50 · 11:30 · 12:30 · 18:10 | 09:20 | 01:02 | **00:22** | 00:10 | 00:32 |
| 06/10 | 08:00 · 11:40 · 12:40 · 17:56 | 08:56 | 00:28 | **00:08** | — | 00:08 |
| 07/10 | 07:50 · 11:25 · 12:25 · 17:54 | 09:04 | 00:51 | **00:06** | 00:10 | 00:16 |

O 9h04 trabalhado e o saldo bruto de 16 min não mudam; os 16 min deixam de virar extra automaticamente: **6 min de saída são extra e 10 min de entrada antecipada ficam não computados**, exatamente como na sua tabela.

**Como ligar/desligar:** padrão = não conta. Para contar: `INSERT INTO configuracoes (chave, valor) VALUES ('entrada_antecipada_hora_extra', 'true');` (mesmo mecanismo de `sabado_hora_extra`; sem alteração de schema nem de tela).

**Sem horários previstos (print 1)** o sistema não consegue separar a entrada antecipada nem o intervalo: o saldo diário inclui esses minutos, e o aviso do relatório passou a dizer isso.

**Risco jurídico (decisão D6 da matriz, em aberto).** Não computar entrada antecipada é política da empresa, mas pela Súmula 366 do TST e pelo art. 4º da CLT (tempo à disposição), minutos antes do horário podem ser exigidos como extra quando o limite de 10 min/dia é ultrapassado e o empregado já está à disposição. Por isso o padrão é rastreável e reversível. **Validar com o jurídico antes de usar na folha.**

## 12. Coluna Saldo e Observação enxuta (relatório HTML e PDF)

**Saldo do dia** (fonte única: `saldoDoDia` em `utils/apuracaoPonto.js`) = tempo computável − jornada = **extras − faltantes**, já com a tolerância e a entrada antecipada não computada aplicadas. Exemplos (prints): 05/10 `+00:22` · 06/10 `+00:08` · 07/10 `+00:06` · dia de falta `-08:48`.
- Dia com jornada incompleta, em andamento ou sem jornada cadastrada: **`—`** (sem saldo; a pendência não vira zero nem débito) e é contado em `apuracao.totais.diasSemSaldo`.
- Dia abonado: `00:00`. Sábado/domingo/feriado trabalhado: o tempo trabalhado.
- Coluna **Saldo** na tabela diária do HTML (verde/vermelho, com **dica ao passar o mouse**: "Extras − Faltantes · Tolerado · Entrada antecipada não computada") e do PDF (com nota de rodapé do cálculo).
- **Resumos semanal e mensal, KPI "Saldo do período" e coluna Saldo do PDF agora somam os saldos diários do servidor.** Antes o navegador calculava `trabalhadas − carga` por conta própria (segunda fórmula, ignorava tolerância/entrada antecipada/pendências) e o campo do servidor perdia o sinal (saldo negativo aparecia como `00:00`). Ambos corrigidos.

**Observação** deixou de receber mensagens longas por linha. O que é lembrete de regra foi para o topo, em dois blocos: **ℹ Informativo** (azul: entrada antecipada não computada com o **total do período**, atraso/saída antecipada apurados separadamente, teto diário de tolerância) e **Avisos da apuração** (amarelo: só o que exige ação, como horários não cadastrados ou jornada ausente). A observação mantém apenas o que é específico do dia (abono/atestado, jornada incompleta, saída no dia seguinte, VR provisório).

Testado: valores no JSON, no PDF renderizado e na tela HTML executada em jsdom (célula, classe de cor, dica, blocos do topo, observação vazia), além de mutações que quebram o cálculo do saldo e que devolvem o texto longo à observação (ambas detectadas).


## Atualização 26/10/2026 — Súmula 366 e resumo do período

- **Entrada antecipada acima da tolerância passa a ser crédito** (padrão). Desligar exige `INSERT INTO configuracoes (chave, valor) VALUES ('entrada_antecipada_hora_extra', 'false');`.
- **Teto de 10 min/dia** soma todas as variações do dia (matriz D2). Exemplo: 07:50 → 17:20 = 30 min extras.
- **Resumo do período** separa: horas trabalhadas · excedente bruto · crédito no banco · saldo (`apuracao.resumo`).


## Atualização 27/10/2026 — dashponto inteligente (por jornada)

- **Serviço único** `services/situacaoPontoService.js`: cruza a jornada cadastrada (2/4 batidas, aprendiz, horários previstos, tolerância) com as batidas e o relógio. Usa o mesmo motor do ponto calculado (2ª batida de jornada de 2 batidas = saída; Súmula 366; apuração do dia encerrado).
- **Situações:** aguardando, atrasado, ausente provável (1 h sem entrada), trabalhando, em intervalo (com alerta de excedido), encerrado, conferir registros, abonado, folga (fim de semana/feriado).
- **Base esperada:** KPIs e gráficos contam quem está *esperado* hoje, não todos os ativos.
- **Alertas:** atraso/ausência, intervalo acima do previsto, intervalo pendente (CLT art. 71), extra em curso, saída esquecida, jornada de ontem sem saída, intervalo curto, cadastro sem horários.
- **Tela:** resumo em frase, KPIs clicáveis, central de atenção, próximos eventos, quadro previsto × realizado por funcionário, gaveta de detalhes, atualização a cada 30 s (pausável), avisos de novos alertas, busca e atalhos (`/`, `R`).
- **API nova:** `GET /painel/dashponto/api/situacao`. As antigas continuam, com os mesmos nomes de campo.
- **Fora do escopo:** o registro de ponto (`utils/jornada.js`) ainda oferece sempre 4 etapas; para jornada de 2 batidas a apuração e o painel já leem a 2ª batida como saída.
