# 09 — Mapa campo → origem e esquema do "manifesto de cálculo" (módulo Contratos)

Fase 0 do módulo Contratos. Porte do mapa de âncoras de
`~/.claude/skills/fazer-contrato/campos.md` (revisto linha a linha contra os 4 modelos
reais em `/Volumes/Assistente/Modelos contratos`, 22/09/2026 — inalterado desde a
criação da skill) + o esquema JSON que `App\Services\Contratos\Calculadora::calcular()`
devolve (equivalente ao que o relatório de `gerar_contrato.py` mostra hoje ao
utilizador).

## Mapa de âncoras (idêntico à skill, fonte única `campos.md`)

O motor PHP usa exatamente o mesmo mapa — não há diferença de negócio, só de sintaxe
(regex PHP em vez de Python). Reproduzido aqui por completude do documento de Fase 0;
`campos.md` continua a ser a fonte de verdade partilhada com a skill (mudanças de
modelo corrigem-se nos dois lados).

| Âncora no parágrafo | Slots amarelos por ordem | Origem |
|---|---|---|
| `^SEGUNDO:` | nome, morada, ndoc, validade_doc, nif, niss | processo |
| `detentor do cartão de` | cartao_palavra? (só SPR/ARD), mai, validade_cartao | processo.mai + val_&lt;esp&gt; |
| `desempenhar as funções das especialidades de` | especialidades | processo.especialidades por extenso |
| `celebrado a Termo Incerto, com início a` | data_inicio, motivo_texto?, alinea? | processo_contrato (ARD sem motivo/alinea) |
| `celebrado a Termo Certo` | data_inicio, data_fim, duracao_meses, motivo_texto?, alinea? | processo_contrato |
| `nas instalações da` | cliente_nome, cliente_morada | clientes via cliente_equipa (ou flags) |
| `poderá ser renovado` | renovacao | processo_contrato.renov_duracao (parágrafo removido se dias sem renovação) |
| `remuneração mensal ilíquida` | vencimento | calculado |
| `prestar a sua atividade durante` | horas | processo_contrato.nhoras/periodo (fallback processo.nhoras) |
| `horário concentrado` | horas_dia (fixo "12") | constante |
| `exercerá as suas funções na` | cliente_morada | morada_servico do cliente |
| `terá as especialidades de` | especialidades | idem |
| `inicia os seus efeitos a` | data_inicio, data_fim? | processo_contrato |
| `Santo Tirso, ` (com vírgula) | assinatura_extenso | regra do modal |
| `Eu, ` (declaração de fardamento) | nome | processo |
| `Santo Tirso ` (sem vírgula) | assinatura | regra do modal |

Textos proibidos no resultado (`TEXTOS_EXEMPLO`, ver `campos.md`): Rafael Soares
Barbosa, Sequeiros, 13037383, 241414997, 11167393698, 123456, 05/08/2028, 04/04/2028,
Carlos Jorge, `[NOME`, `[MORADA`, `[Nº`, `[NIF]`, `[VALIDADE`, `[DATA`, `[VALOR`, `[X]`,
PREENCHER, ……., 01/01/202, 01 de janeiro de 202, 27/07/2026, 22 de julho, 21 de julho.

Regras de artigo (concordância), motivo do termo por alínea e regras de negócio: ver
`campos.md` secções "Artigos" e `gerar_contrato.py` (`MOTIVO_TEXTO`, `artigo_cliente`,
`artigo_morada`) — portadas tal-e-qual para `App\Services\Contratos\Regras`.

**Confirmação (Fase 0, 22/09/2026)**: as 16 âncoras acima foram confirmadas presentes
nos 4 modelos (`Contrato_Termo_Certo_v2.docx` tem as âncoras de termo certo + comuns;
`Contrato_2026_incerto.docx`/`SPR.docx`/`ARD.docx` têm as de termo incerto + comuns; o
`cartao_palavra?` só existe nos modelos SPR e ARD, como já documentado) — nenhuma âncora
por confirmar.

## Esquema do manifesto de cálculo (`Calculadora::calcular()`)

Estrutura devolvida pelo motor, equivalente ao quíntuplo `(campos, meta, perguntas,
avisos, origem)` de `calcular()` em `gerar_contrato.py`. Consumida por
`contratos:gerar` para preencher o `.docx` e, na Fase 3, pela página do contrato na
webapp (mesmo relatório que a skill hoje imprime em texto).

```json
{
  "campos": {
    "nome": "string", "morada": "string", "doc_tipo": "cc|tr|passaporte|null",
    "doc_texto": "string", "ndoc": "string", "validade_doc": "dd/mm/aaaa|''",
    "nif": "string", "niss": "string",
    "cartao_palavra": "string|''", "mai": "string", "validade_cartao": "dd/mm/aaaa|''",
    "especialidades": "string", "especialidades_n": "int",
    "data_inicio": "dd/mm/aaaa", "data_fim": "dd/mm/aaaa|''",
    "duracao_meses": "string numero|''", "duracao_unidade": "meses|dias|''",
    "renovacao": "string|'(removida)'|''", "renovacao_remover": "bool",
    "cliente_nome": "string|''", "cliente_morada": "string|''",
    "vencimento": "'1015,95 (mil e quinze euros...)'|''",
    "horas": "'40 (quarenta) horas semanais'|''", "horas_dia": "'12'",
    "motivo_texto": "string", "artigo_cliente": "da|do|das|dos",
    "artigo_morada": "na|no", "alinea": "'e)'|''",
    "assinatura_extenso": "'31 de agosto de 2026'", "assinatura": "dd/mm/aaaa"
  },
  "meta": {
    "id_processo": "int", "zona": "string", "admissao": "aaaa-mm-dd",
    "na_fila": "bool", "modalidade": "termo_certo|termo_incerto|sem_termo|null",
    "modelo": "termo_certo|incerto|SPR|ARD|null", "especialidade": "VIG|SPR|ARD|ARE|null",
    "categoria": "string|null", "regime": "Full-Time|Part-Time|''",
    "horas_mensais": "float", "cartoes": {"VIG": "aaaa-mm-dd"},
    "cliente": "objeto ou null", "servicos": "array", "motivo_termo": "string|null",
    "ficheiro": "'<Nome> <dd-mm-aaaa>.docx'"
  },
  "perguntas": [["chave", "texto da pergunta"]],
  "avisos": ["string"],
  "origem": {"campo": "explicação de onde veio o valor"}
}
```

Idêntico campo a campo ao que `gerar_contrato.py` produz (mesmas chaves, mesmos
formatos de string — datas `dd/mm/aaaa`, vencimento com euros por extenso, etc. — para
que o texto final gerado pelo motor PHP seja bit-a-bit comparável ao da skill no teste
de paridade da Fase 2). `perguntas` não vazio ⇒ o motor não gera `.docx` (equivalente ao
exit 2 da skill); `avisos` não bloqueia a geração.

## Flags de entrada (equivalentes às respostas por linha de comandos da skill)

O `Calculadora::calcular()` aceita um array `flags` opcional com as mesmas chaves que a
skill aceita por linha de comandos, usadas para resolver perguntas pendentes numa
segunda chamada (Fase 3 — formulário; Fase 2 — só para os testes de regressão que
precisem de forçar um valor):

`especialidade`, `cliente`, `cliente_nome`, `cliente_morada`, `categoria`, `modalidade`,
`renovacao`, `duracao_meses`, `documento`, `artigo_cliente`, `artigo_morada`,
`data_assinatura`, `data_fim`.
