# Host Studio · Contrato do Motor de Análise

> **Este documento é o contrato técnico para IAs que vão editar o motor de geração de relatórios.**
> Compartilhe-o com qualquer IA (Claude, Cursor, GPT) antes de pedir mudanças no motor.

---

## 1. CONTEXTO

O Motor de Análise da Host Studio recebe 4 CSVs + briefing da propriedade e gera um JSON estruturado com 88 campos que alimenta o relatório HTML do cliente. O motor roda como **Edge Function no Supabase**, em TypeScript/Deno.

---

## 2. ARQUITETURA EM 3 CAMADAS

```
┌─── NÍVEL 1: Editável via INTERFACE ───────────────────┐
│  Tabela: engine_config                                │
│  Conteúdo: prompts, regras numéricas, toggles         │
│  Editor: Configurações → Motor de Análise (admin)     │
│  Quem edita: Thales e Regina (sem código)             │
└────────────────────────────────────────────────────────┘

┌─── NÍVEL 2: Editável via CURSOR/IA ───────────────────┐
│  Pasta: supabase/functions/motor-relatorio/           │
│  Conteúdo: parsers, cálculos, integração Claude       │
│  Editor: Cursor com IA seguindo ESTE contrato         │
│  Regras: só código entre marcadores de fronteira      │
└────────────────────────────────────────────────────────┘

┌─── NÍVEL 3: IMUTÁVEL ──────────────────────────────────┐
│  Schema do banco, tipos compartilhados, validador     │
│  Quem edita: ninguém sem revisão consciente           │
└────────────────────────────────────────────────────────┘
```

---

## 3. O QUE A IA PODE ALTERAR

### ✅ Permitido (Nível 2 — código)

Dentro de `supabase/functions/motor-relatorio/`:

- Lógica interna dos parsers em `parsers/`
- Fórmulas dos cálculos em `calculations/`
- Lógica de prompts em `ai/insights_generator.ts`
- Comentários, formatação, refatoração local
- Adicionar **novos** arquivos de teste em `*.test.ts`
- Atualizar fixtures (CSVs de exemplo) em `fixtures/`

### ❌ Proibido (Nível 3 — núcleo)

NUNCA toque em:

- Arquivo `supabase/functions/_shared/types.ts` (tipos compartilhados)
- Schema do Supabase (`hoststudio_schema*.sql`)
- Assinaturas (nome + parâmetros + retorno) de funções públicas exportadas
- Validador `hoststudio_validator.py`
- HTML do relatório (`relatorio_v2.html`) — só admin/IA de UI pode mexer
- Tabela `notification_config` ou central de notificações
- Qualquer arquivo fora de `supabase/functions/motor-relatorio/`

Se a IA achar que precisa alterar algo proibido, **deve parar e perguntar ao humano** antes de prosseguir.

---

## 4. FRONTEIRAS DE EDIÇÃO NO CÓDIGO

Todo arquivo editável tem marcadores explícitos. A IA só edita entre eles:

```typescript
/* ═══════════════════════════════════════════════════════════════
   FRONTEIRA DA EDIÇÃO POR IA — INÍCIO

   Esta função pode ser modificada por IA.
   Pode mudar: lógica interna, variáveis locais, comentários
   Não pode mudar: nome da função, tipo dos parâmetros, tipo do retorno

   Contrato:
     INPUT:  string (CSV bruto)
     OUTPUT: AirbnbParsed (tipo em _shared/types.ts)

   Testes obrigatórios após alteração:
     deno test parsers/airbnb.test.ts
   ═══════════════════════════════════════════════════════════════ */

export function parseAirbnbCSV(csv: string): AirbnbParsed {
  // código editável aqui
}

/* ═══════════════════════════════════════════════════════════════
   FRONTEIRA DA EDIÇÃO POR IA — FIM
   ═══════════════════════════════════════════════════════════════ */
```

**Regras:**
- IA não pode modificar linhas com `FRONTEIRA DA EDIÇÃO POR IA`
- IA não pode adicionar/remover marcadores
- Se precisar ampliar a região editável, deve avisar humano

---

## 5. ESTRUTURA DE PASTAS

```
supabase/functions/motor-relatorio/
├── index.ts                     ← entrypoint (NÃO EDITAR sem revisão)
├── README_CONTRATO.md           ← este arquivo localizado
│
├── parsers/                     ← um arquivo por CSV
│   ├── airbnb.ts
│   ├── airbnb.test.ts
│   ├── compset.ts
│   ├── compset.test.ts
│   ├── geral.ts
│   ├── geral.test.ts
│   ├── revenue.ts
│   └── revenue.test.ts
│
├── calculations/                ← cálculos matemáticos puros
│   ├── normalize_period.ts
│   ├── normalize_period.test.ts
│   ├── revenue.ts
│   ├── revenue.test.ts
│   ├── adr_occupation.ts
│   ├── adr_occupation.test.ts
│   ├── deltas.ts
│   └── deltas.test.ts
│
├── ai/
│   ├── client.ts                ← cliente Claude API
│   ├── insights_generator.ts    ← orquestra geração dos 12 insights
│   └── prompt_builder.ts        ← monta prompts a partir de engine_config
│
└── fixtures/                    ← CSVs de exemplo para testes
    ├── airbnb_completo.csv
    ├── compset_24m.csv
    ├── geral_24m.csv
    └── revenue_estimator.csv
```

---

## 6. CONTRATO DE INPUT

O motor recebe um payload do admin:

```typescript
interface MotorInput {
  report_id:         string          // uuid do report no banco
  property_id:       string          // uuid da propriedade
  client_id:         string          // uuid do cliente

  csv_airbnb:        string          // texto do CSV
  csv_compset:       string
  csv_geral:         string
  csv_revenue:       string          // Revenue Estimator do PriceLabs

  briefing:          PropertyBriefing | null  // pode ser null
  is_test:           boolean         // se true, não notifica cliente
}
```

`PropertyBriefing` está definido em `_shared/types.ts`.

---

## 7. CONTRATO DE OUTPUT

O motor produz e salva no Supabase:

```typescript
interface MotorOutput {
  insights: InsightsOutput      // 88 campos — vai em reports.insights (jsonb)
  forecast: ForecastOutput      // dados do Revenue Estimator processados
  warnings: string[]            // avisos não-fatais
  errors:   string[]            // erros fatais (motor não publica)
  metrics: {
    duration_ms:      number
    tokens_input:     number
    tokens_output:    number
    cost_usd:         number
  }
}
```

**Schema completo dos 88 campos** está em `schema_output_motor.md`.

---

## 8. REGRAS DE CÁLCULO OBRIGATÓRIAS

### 8.1 Normalização de período

Antes de qualquer comparativo entre propriedade e compset/geral, o motor DEVE filtrar compset e geral para o mesmo intervalo do Airbnb do cliente.

```typescript
const periodo = detectarPeriodo(airbnb)              // { inicio, fim, meses }
const compsetFiltrado = filtrarPorPeriodo(compset, periodo)
const geralFiltrado = filtrarPorPeriodo(geral, periodo)
```

Sem esse filtro, comparativos ficam distorcidos. Ver `calculations/normalize_period.ts`.

### 8.2 Receita mês a mês

Receita anual é sempre soma mês a mês:

```typescript
const receita = meses.reduce(
  (sum, m) => sum + (m.adr * (m.ocupacao / 100) * m.dias_no_mes),
  0
)
```

NUNCA usar `media_adr * media_ocupacao * 365` — distorce sazonalidade.

### 8.3 Cruzamento ADR×ocupação

Só cruzar valores do MESMO universo:

```
✅ adr_compset × ocupacao_compset    → faturamento histórico do compset
✅ adr_propriedade × ocupacao_propriedade → faturamento real da propriedade
❌ adr_propriedade × ocupacao_compset → projeção falsa
```

### 8.4 Revenue Estimator — cenários

Mapeamento percentil → nome:

| PriceLabs   | Nome no relatório |
|-------------|-------------------|
| P25         | Conservador       |
| P50         | Esperado          |
| P75         | Acima da média    |
| P90         | Top 10%           |

Cálculos derivados:
```typescript
receita_anual_p50  = sum(Revenue_50)         // "Receita Estimada" do PDF
mensal_p50         = receita_anual_p50 / 12
adr_medio_anual    = avg(ADR_50, ignoreZeros=true)
ocupacao_media     = avg(AvgOccupancy)
imoveis_referencia = round(avg(NoListingUsed))
```

---

## 9. REGRAS DE LINGUAGEM

### 9.1 Glossário

| Técnico (NÃO usar) | Acessível (USAR) |
|---|---|
| ADR | Diária média |
| RevPAR | Receita por noite disponível |
| Compset | Imóveis similares · Principais concorrentes |
| Booking window | Antecedência de reserva |
| LOS | Duração da estadia |
| Percentil 75 | Imóveis com melhor desempenho do grupo |
| Mediana | Metade do grupo / valor médio |

### 9.2 Sem projeções

**NUNCA** usar palavras: *projetado, potencial, vai render, garantia, estimativa de receita futura*

**SEMPRE** usar: *histórico, já aconteceu, foi observado, no período X, referência de mercado*

### 9.3 Tom

- Direto, sem floreio
- Conclusões baseadas em dados, nunca em opinião
- Reconhecer limitações ("com base nos 6 meses disponíveis...")
- Nunca afirmar previsão como certeza

### 9.4 Aba Previsão — exceção parcial

Na aba Previsão, é permitido falar de cenários do PriceLabs, mas SEMPRE:
- Citar a fonte: "Segundo o PriceLabs..." / "O Revenue Estimator estima..."
- Falar do compset histórico que atingiu, não da propriedade que vai atingir
- Manter o disclaimer obrigatório

---

## 10. TIPOS COMPARTILHADOS

`_shared/types.ts` é IMUTÁVEL. Define:

```typescript
export interface AirbnbParsed { /* ... */ }
export interface CompsetParsed { /* ... */ }
export interface GeralParsed { /* ... */ }
export interface RevenueParsed { /* ... */ }
export interface PropertyBriefing { /* 50+ campos */ }
export interface InsightsOutput { /* 88 campos */ }
export interface ForecastOutput { /* campos da previsão */ }
```

Qualquer função pública exportada DEVE usar esses tipos. Se a IA achar que precisa de novo tipo, criar localmente; se for compartilhado, **pedir aprovação humana**.

---

## 11. TABELAS DO SUPABASE USADAS

O motor LÊ:
- `properties` (dados da propriedade)
- `property_briefing` (briefing)
- `clients` (cliente alvo)
- `engine_config` (prompts, regras, toggles)

O motor ESCREVE:
- `reports` (campos `insights`, `status`, `data_geracao`, etc)
- `report_revenue_forecast` (dados da previsão)
- `engine_logs` (log da execução)
- `engine_metrics` (métricas agregadas)
- `notifications` (via API `notifyCenter`)

**Acessar TODAS as outras tabelas é proibido** (incluindo `auth.users`, `audit_log`, `notification_config`).

---

## 12. INTEGRAÇÃO COM CLAUDE API

```typescript
// ai/client.ts — assinatura imutável

export async function callClaude(
  prompt: string,
  options: {
    model:        string   // 'claude-sonnet-4-7' (default) ou outro de engine_config
    max_tokens:   number   // default 4096
    temperature:  number   // default 0.3 (baixa = mais determinístico)
  }
): Promise<{ text: string; tokens_input: number; tokens_output: number }>
```

A IA pode editar **como** o prompt é montado, mas não a assinatura do client.

API key vem de `Deno.env.get('ANTHROPIC_API_KEY')` — NUNCA hardcoded.

---

## 13. TESTES OBRIGATÓRIOS

Cada parser e cálculo tem teste com fixtures reais. Após qualquer alteração:

```bash
cd supabase/functions/motor-relatorio
deno test --allow-read
```

Se algum teste falhar, a IA deve:
1. Parar imediatamente
2. Mostrar quais testes falharam
3. Perguntar ao humano se deve corrigir ou reverter

NUNCA fazer commit com testes falhando.

---

## 14. VALIDADOR DO SCHEMA

Após gerar o JSON de output, rodar:

```bash
python3 hoststudio_validator.py
```

Se o JSON não conformar com o schema esperado pelo HTML, a IA deve corrigir antes de commitar.

---

## 15. VERSIONAMENTO

Toda mudança que altere comportamento do motor deve:

1. Atualizar `engine_versions` com novo número (semver: MAJOR.MINOR.PATCH)
2. Documentar mudança em commit message:
   ```
   motor v2.3.5 · ajuste no cálculo de delta de ADR

   - Bug: divisão por zero quando compset tinha 0 imóveis no mês
   - Fix: retornar null em vez de Infinity
   - Testes: adicionado caso de borda em calculations/deltas.test.ts
   ```
3. Adicionar warning em `engine_logs` se mudança quebrar compatibilidade

---

## 16. ROLLBACK

Se o motor v2.3.5 começar a falhar em 3 execuções consecutivas:

1. Sistema notifica admin por email
2. Admin acessa Configurações → Motor → Histórico
3. Pode clicar em "Restaurar v2.3.4"
4. Próximas execuções usam v2.3.4 automaticamente

A IA NÃO faz rollback automático — só o admin.

---

## 17. LOGS E MÉTRICAS

Toda execução grava em `engine_logs`:

```typescript
{
  report_id:    string
  version:      string         // ex: '2.3.5'
  started_at:   timestamp
  duration_ms:  number
  status:       'success' | 'warning' | 'error'

  inputs_hash:  string         // hash SHA256 dos inputs (privacidade)
  inputs_summary: {
    csv_airbnb_lines:  number
    csv_compset_lines: number
    // ...
  }

  prompts_used:  jsonb         // prompts efetivamente enviados ao Claude
  ai_response:   jsonb         // resposta bruta do Claude (truncada)

  warnings:      string[]
  errors:        string[]

  output_hash:   string        // hash do JSON gerado
  tokens_input:  number
  tokens_output: number
  cost_usd:      number
}
```

Retenção: **90 dias** detalhado, agregado em `engine_metrics` para sempre.

---

## 18. AUDITORIA — KIT QUE A IA RECEBE

Quando o admin gerar "Kit de auditoria" no painel, vai gerar um ZIP:

```
auditoria_motor_2026-05-16.zip
├── 00_instrucoes_auditoria.md        ← guia da auditoria
├── 01_motor_contrato.md              ← este arquivo
├── 02_schema_output.md               ← schema do JSON
├── 03_glossario_linguagem.md         ← regras de tom
├── inputs/
│   ├── airbnb.csv
│   ├── compset.csv
│   ├── geral.csv
│   └── revenue_estimator.csv
├── motor_output/
│   ├── relatorio.html
│   ├── insights.json
│   └── logs_execucao.txt
└── host_studio_output/
    ├── entrega_manual.pdf            ← adicionar manualmente
    └── observacoes_equipe.md         ← adicionar manualmente
```

A IA que receber esse ZIP retorna **laudo de auditoria** classificando cada divergência:

```
[ Motor ]              → editar prompt/regras na interface
[ Motor + Código ]     → ajustar prompt E lógica
[ Código ]             → bug puro
```

---

## 19. CHECKLIST PARA IA ANTES DE COMMITAR

```
[ ] Mudei só código entre marcadores de fronteira
[ ] Não alterei tipos compartilhados
[ ] Não alterei schema do banco
[ ] Rodei `deno test` e passou
[ ] Rodei `python3 hoststudio_validator.py` e passou
[ ] Atualizei engine_versions com novo número
[ ] Commit message segue padrão "motor v#.#.# · descrição"
[ ] Se mudei prompt, atualizei engine_config também
[ ] Se mudei comportamento, documentei em CHANGELOG.md
```

---

## 20. EM CASO DE DÚVIDA

Se a IA encontrar uma situação não coberta neste contrato:

**PARAR. PERGUNTAR. NUNCA IMPROVISAR.**

Exemplo:
```
"Encontrei um padrão que não está no contrato:
o CSV do PriceLabs veio com coluna nova chamada 'X'.
Devo:
(a) Ignorar a coluna nova
(b) Adicionar parsing dela
(c) Falhar com erro
Qual é a abordagem correta?"
```

Aguardar resposta humana antes de prosseguir.

---

## RESUMO ULTRA RÁPIDO

1. **Edite só entre marcadores** `FRONTEIRA DA EDIÇÃO POR IA`
2. **Não toque em tipos compartilhados** (`_shared/types.ts`)
3. **Não toque no schema do banco**
4. **Rode testes** antes de commitar
5. **Use linguagem honesta** (sem "projetado", "potencial")
6. **Cruze dados do mesmo universo** (ADR e ocupação do mesmo lugar)
7. **Filtre período** antes de comparar
8. **Pergunte ao humano** se houver dúvida

Bom trabalho.
