# Changelog — Calculadora SOx Scope · V2 Tier 2

**Data:** 2026-05-16
**Versão:** V2 Tier 1 → V2 Tier 1+2 (Should-have)
**Arquivos afetados:** `sox-scope.html` (principal), `sox-demo.html` (Cenário 4 + fórmula).
**Referência:** MD de recomendações `2fe3d47f-calculadorasoxv2recomendacoes.md`, seção 12 (Roadmap), Tier 2 — itens #9 a #18.
**Escopo desta entrega:** 10 itens do Tier 2 (should-have). Tier 1 e hotfix HF-001 documentados em `2026-05-12-changelog-sox-scope-v2-tier1.md`. Tier 3 (10 itens) ainda parqueado aguardando aprovação.

---

## Resumo executivo

O Tier 2 adiciona ao Tier 1: alertas inline de inconsistência Q1↔Q2; Q15 first-year SOx (+2 ao RMM); ponderação Q2 por processo (Receita/Tesouraria/Crédito/Fechamento = +2; demais = +1; cap 5) — calibrada empiricamente nos 5 cenários da demo com **zero drift de veredito**, sem precisar do fallback de thresholds 20/34; sublabels Borderline (provável Key/Limited/Out) refletidos também no Cenário 4 da demo; comentários textuais por pergunta com contagem; co-fill via URL serializada em hash base64 (round-trip validado em 6/6 testes); show your work no banner do resultado (Top 3 positivos + Top 3 redutores + sensitivity por "não sei"); memorando PDF estruturado com jsPDF (cabeçalho navy, veredito colorido, justificativa, pontuação, comentários do respondente, linha de assinatura, paginação); anchoring com 3 cenários no topo do form; decision tree visual SVG com destaque do caminho percorrido em tempo real. O arquivo `sox-scope.html` cresceu de 2427 para ~3300 linhas (+36%).

---

## Mudanças por item

### T2.1 — Co-fill via URL (item #9 do roadmap)

**Técnico.** Conjunto de funções `buildState()`, `encodeState()`, `decodeState()`, `applyState()`, `copyShareLink()`, `getInitialState()`. Estado serializado: `{ v: 2, ans: { q1, q2[], q3a, q3known|q3vol|q3rev, q4..q15, appName, owner }, com: { qN: 'comentário' } }`. Encoding UTF-8-safe via `btoa(unescape(encodeURIComponent(JSON.stringify(state))))`; decode inverso. Hash format: `#state=<base64>`. Fallback de clipboard via `document.execCommand('copy')` em browsers antigos. Detecção de hash no init: se houver `#state=`, prescreen é pulado, `proceedFromPrescreen()` é chamado e `applyState()` aplica respostas + comentários. **Não inclui persona** — o destinatário escolhe a própria persona (decisão #2).

**UX.** Botão "🔗 Copiar link colaborativo" nas actions do form e do banner de resultado. Toast inferior confirma cópia ("Link colaborativo copiado pra clipboard (659 chars)."). Warning amber se URL > 1800 chars. Ao abrir URL com `#state=…`, prescreen é skipped, banner azul "🔗 Avaliação compartilhada carregada" aparece no topo com contagem de campos preenchidos e comentários.

**Decisão Pedro.** Decisões críticas #1 (hash), #2 (não inclui persona), #3 (comentários incluídos), #4 (limite 500 chars por comentário, JSON literal sem abreviação — base64 já comprime suficiente), #21 (label do botão: "Copiar link colaborativo").

### T2.2 — Show your work + sensitivity (item #10 do roadmap)

**Técnico.** Função `getResponseImpacts(r)` retorna `[{ qid, label, detail, pts }]` para todas as perguntas respondidas com peso ≠ 0 (inclui Q14 negativo). Função `buildShowYourWork(r)` separa positivos/negativos, ordena por magnitude decrescente, pega Top 3 de cada. Sensitivity itera `r.unknownFlags` e produz hints para cada "não sei" (ex.: "Q5 marcada como 'não sei' — se mudar para 'high (+3)' varia o total"). Mensagem dedicada para Q3=unknown explicando o gate de Borderline.

**UX.** Nova seção "Por que esse veredito · Show your work" no result-body, entre "Pontuação por bloco" e "Controles esperados". Cada linha: tag azul com QID, label da pergunta, detalhe da resposta em itálico, pontos à direita. Pontos negativos em verde (mesma cor que os redutores). Sensitivity como lista subsequente. Se não há "não sei", mensagem: "Nenhuma resposta marcada como 'não sei' — o veredito tem confiança máxima".

**Decisão Pedro.** Decisão #5 — sensitivity foca apenas em "não sei" (foco didático, sem ruído). Decisão #6 — Q14=yes-strong/yes-weak entra no Top 3 redutores com label dedicado ("Redutor de escopo — redutor forte (reconciliação a jusante documentada)" / "redutor frágil").

### T2.3 — Memorando PDF estruturado (item #11 do roadmap)

**Técnico.** jsPDF 2.5.1 carregado via cdnjs com `defer` no `<head>`. Função `exportPDF()` lê `lastResult` (variável salva por `render()` a cada cálculo) e monta PDF A4 portrait com 12 seções:

1. Cabeçalho navy 90pt com título + timestamp.
2. Identificação (app, owner, persona).
3. Caixa de veredito colorida conforme `verdictKey` (vermelho Key, amber Limited, azul Dependency, cinza Borderline, verde Out).
4. Barra de confiança com fill semafórico (verde ≥80, amber 50-79, vermelho <50).
5. Tabela "Pontuação por bloco" (5 linhas).
6. Justificativa (texto multilinha via `splitTextToSize`).
7. Show your work — Top 3 positivos + Top 3 redutores.
8. Comentários do respondente, agrupados por QID (se houver).
9. Controles esperados + próximos passos.
10. Linha de assinatura ("Aprovado por: ____  Data: ____").
11. Disclaimer (PCAOB AS 2201 / COSO / Big4).
12. Rodapé com paginação em todas as páginas.

Função auxiliar `pageBreakIfNeeded(extra)` injeta `addPage()` quando `y + extra > H - 60`.

**UX.** Botão "📄 Exportar memorando PDF" como primary action no banner do resultado. Substitui "Imprimir / Salvar PDF" como ação principal; "Imprimir página" mantido como secundária. Toast warning se jsPDF ainda não terminou de baixar. Nome do arquivo gerado: `YYYY-MM-DD-sox-scope-<appName>.pdf` (appName sanitizado, max 30 chars).

**Decisão Pedro.** Decisões críticas #7 (jsPDF), #8 (logo do ItGov — implementado como título textual; logo image embutido em dataURL fica pro Tier 3), #9 (linha de assinatura), #22 (sublabel Borderline aparece no PDF via `r.verdict` já formatado).

### T2.4 — Comentários por pergunta (item #12 do roadmap)

**Técnico.** Função `initComments()` percorre `.calc-form [data-wq]` com regex `^qN-label$`, identifica cada pergunta única (15 ao total contando Q15) e injeta dinamicamente:
- um `<button.comment-toggle>💬 comentar</button>` posicionado absolutamente no canto superior direito da `.question`;
- um `<div.comment-box hidden>` com `<textarea maxlength="500">` + contador `<span.comment-chars>`.

Função `getAllComments()` percorre os `<textarea>` e retorna `{ qN: 'texto trimmed' }` apenas para os preenchidos. Função `updateCommentsSummary()` mostra "· X comentário(s)" no header do progress.

**UX.** Botão 💬 discreto no canto de cada uma das 15 perguntas. Click expande textarea (max 500 chars, com contador `0/500` no canto). Botão muda de cor (border navy + bg sky) e label ("1 comentário") quando há conteúdo. Contagem global aparece no progress label.

**Decisão Pedro.** Decisão #10 — ícone discreto + click expande inline (vs sempre visível ou collapsible explícito). Decisão #7 — comentários vão pro PDF (implementado em T2.3, seção "Comentários do respondente").

### T2.5 — Q15 first-year SOx (item #13 do roadmap)

**Técnico.** Nova pergunta no Bloco 3 (RMM), depois de Q9. Pesos: `yes=0, no=2, unknown=1`. Adicionado a `block3Score` em `score()`. `TOTAL_QUESTIONS` 14 → 15. `CONF_WEIGHTS.q15 = 2` (totalWeight 46 → 48). Wordings completos para Tech ("auditoria SOx"), Finanças ("SOx attestation") e GRC ("PCAOB Year 1 / Year 2+"). `unknownFlags.q15` exposto no retorno do score().

**UX.** Nova pergunta inline com 3 opções (Sim/Não/Não sei). Wording adaptado por persona. Quando "Não" (primeira avaliação), rationale do veredito acrescenta linha "é primeira avaliação SOx (first-year), elevando o RMM por imaturidade de controles".

**Decisão Pedro.** Decisão #11 — inserido no Bloco 3 (RMM) conforme MD, não em bloco separado. Decisão #12 — peso 2 em `CONF_WEIGHTS` (consistente com impacto no RMM). Decisão #20 — 3 wordings completos com terminologia adequada por persona.

### T2.6 — Sublabel Borderline + atualização Cenário 4 demo (item #14 do roadmap)

**Técnico.** Em `score()`, quando `verdictKey === 'borderline'`, calcula `borderlineSubKey` com regra:
- `total >= 32 || (b2 >= 8 && itac+ipe >= 4)` → `'key'`
- `total >= 18` → `'limited'`
- caso contrário → `'out'`

Exposto no retorno. `buildControls()` ajustado: quando Borderline com sublabel Key ou Limited, mostra ITGC esperados provisórios + nota explicando como defender o escopo conforme sublabel. Atualizado `sox-demo.html`: Cenário 4 (CreditRisk Suite) agora exibe "Borderline · provável Key System" no header e o `gate-trigger` explica que `total (46) ≥ 32 e B2 ≥ 8 com ITAC+IPE ≥ 4`. Fórmula da demo menciona os sublabels na linha do gate Borderline.

**UX.** Banner do resultado mostra "Borderline · provável Key System" (ou Limited / Out) em vez de só "Borderline — discussão com auditoria". ITGC esperados aparecem mesmo no Borderline (provisórios). Cenário 4 da demo educa: explica que o veredito do form é input pra discussão, não output.

**Decisão Pedro.** Decisão crítica #13 — proposta aprovada exatamente como sugerida (provável Key se Total ≥ 32 ou bypass B2≥8+ITAC+IPE≥4; provável Limited 18-32; provável Out <18).

### T2.7 — Ponderação Q2 + validação empírica thresholds (item #15 do roadmap)

**Técnico.** Substituído `block1Score += Math.min(q2.length, 3) * 1` por iteração sobre `Q2_WEIGHTS = { revenue: 2, treasury: 2, loans: 2, close: 2, purchases: 1, payroll: 1, inventory: 1, tax: 1 }` com cap em 5 (substitui o cap em 3 anterior). **Thresholds 18/32 mantidos** após validação empírica.

**UX.** Sem mudança visual no form (Q2 continua com os mesmos checkboxes). O impacto aparece nos vereditos: aplicações com Receita+Tesouraria+Crédito ganham +2 a +3 no Bloco 1 em relação ao V1; mas validação confirmou que os 5 cenários da demo + 3 cenários de borda mantêm os vereditos esperados.

**Decisão Pedro.** Decisão crítica #14 — **opção C executada** (validação empírica). Resultado dispensou o fallback B (20/34). Detalhes da validação na seção "Validações empíricas" abaixo.

### T2.8 — Alertas inline de inconsistência (item #16 do roadmap)

**Técnico.** Função `checkInconsistency()` registrada no listener `change` do form. Dispara sempre que Q1 ou Q2 mudam. Lógica: `q1 === 'no' && q2.length > 0 && q2.indexOf('none') === -1` → revela `#inconsistencyQ1Q2` (banner amber).

**UX.** Banner amber abaixo de Q2 ("⚠ Possível inconsistência. Q1 indica que a aplicação não tem impacto financeiro, mas Q2 marca processo(s) significativo(s). Reconciliar antes de prosseguir: provavelmente Q1 deveria ser 'Indiretamente — alimenta um sistema em escopo', ou Q2 marcou processo por engano."). Não bloqueia submit; só sinaliza.

**Decisão Pedro.** Decisão #15 — começar conservador, **só a combinação Q1=não × Q2 com processo selecionado**. As outras 2 combinações sugeridas (Q14=forte × Q10/11/12 todos sim; Q9=saas × Q8=custom) ficam pro Tier 3 com base em telemetria.

### T2.9 — Decision tree visual com destaque (item #17 do roadmap)

**Técnico.** Botão collapsible "▶ Ver lógica de classificação" antes do form. Click expande `<svg viewBox="0 0 760 580">` inline com 4 caixas decisórias (Q1, Q13, Q3, threshold Key, threshold Limited) + 5 caixas de veredito coloridas. Edges como `<path>` com IDs estáveis (`edge-q1-q3a`, `edge-q3-border`, etc.). Função `highlightTreePath()` no listener de change: limpa `.active` em todos os `.tree-node` e `.tree-edge`, depois re-aplica conforme respostas atuais. Usa `lastResult` quando disponível; caso contrário tenta `score()` parcial se todos os radios essenciais estiverem preenchidos.

**UX.** Botão discreto no topo do form. Click expande SVG com fluxograma. Cada `.tree-node` é uma decisão; vereditos coloridos no canto direito. Caminho percorrido em azul navy com stroke-width maior; restante em cinza claro. Atualização em tempo real conforme respostas.

**Decisão Pedro.** Decisão #16 — **opção C implementada** (SVG + JS com highlight do caminho atual em tempo real). Decisão #17 — collapsible no topo do form (em vez de overlay). Decisão #23 — só fluxo, sem pesos (pesos ficam na rubrica separada da demo).

### T2.10 — Anchoring com 3 cenários no topo do form (item #18 do roadmap)

**Técnico.** Div `.anchoring` antes do `progress-wrap`, hidden por padrão. Revelado em `applyPersona()` junto com form; escondido em `returnToGate()`. 3 cards estáticos com cores correspondentes aos vereditos (border-left colorido + badge).

**UX.** Antes do form principal, banner com 3 cards: **CoreLedger BR** (Key, vermelho, "Sistema central de contabilidade. Gera lançamentos, alta complexidade, ITAC, IPE. Total 50."), **TaxLake** (Limited, amber, "SaaS de apuração de tributos com SOC 1 e reconciliação forte. Total 25."), **NeoTalk** (Out, verde, "Plataforma de comunicação interna. Sem nexo monetário. Total 3."). Calibra o respondente antes dele projetar percepções.

**Decisão Pedro.** Decisão #18 — CoreLedger/TaxLake/NeoTalk (extremos pra calibração; pula Borderline pra não confundir). Decisão #19 — estático sem auto-fill (Tier 3 considera click=preencher).

---

## Métricas de impacto

| Métrica | V2 Tier 1 | V2 Tier 1+2 | Δ Tier 2 |
|---|---|---|---|
| Linhas em `sox-scope.html` | 2427 | ~3300 | +870 (+36%) |
| Linhas em `sox-demo.html` | 1188 | 1188 (3 linhas alteradas) | 0 |
| Perguntas no form | 14 | 15 | +1 (Q15) |
| Vereditos refinados | 5 | 5 + 3 sublabels Borderline | +3 sub |
| Funções JS novas | 20 | 36 | +16 |
| Slots do dicionário WORDINGS | 30 × 3 personas | 32 × 3 personas | +2 (Q15 label + help) |
| `CONF_WEIGHTS` total | 46 | 48 | +2 (Q15=2) |
| Pesos Q2 | uniforme +1, cap 3 | 8 entradas ponderadas, cap 5 | calibrado |
| Endpoints de export | print | print + PDF + share link | +2 |
| SVG inline (decision tree) | 0 | 1 (4 decisões + 5 vereditos) | +1 |
| Banners de alerta inline | exit-early | exit-early + inconsistência Q1↔Q2 | +1 |
| Anchoring cards | 0 | 3 (CoreLedger/TaxLake/NeoTalk) | +3 |
| Comentários por pergunta | 0 | 15 textareas opcionais (max 500 chars) | +15 |
| Tamanho típico de URL co-fill | n/a | 659 chars (limite 2000) | novo |
| Versionamento de estado serializável | n/a | sim (`STATE_VERSION = 2`) | novo |
| Scripts de validação programática | 1 (`test-prescreen.js`) | 3 (+ Q2 + co-fill) | +2 |
| Libs externas | nenhuma | jsPDF 2.5.1 via CDN cdnjs | +1 |

---

## Validações empíricas executadas

### T2.7 — Ponderação Q2 (`outputs/test-q2-weighting.js`)

Comparou V1 (uniforme +1, cap 3) × V2 (ponderada +2/+1, cap 5, com Q15) em 5 cenários da demo + 3 cenários de borda hipotéticos. Avaliou drift de veredito com thresholds atuais (18/32) e com fallback (20/34).

| Cenário | V1 Total | V2 Total | Δ | V1 Veredito | V2 Veredito (18/32) | V2 Veredito (20/34) | Drift |
|---|---|---|---|---|---|---|---|
| 1 — CoreLedger BR | 48 | 50 | +2 | Key | Key | Key | ✓ |
| 2 — TaxLake | 25 | 25 | 0 | Limited | Limited | Limited | ✓ |
| 3 — CardCore Switch | 27 | 28 | +1 | Dependency | Dependency | Dependency | ✓ |
| 4 — CreditRisk Suite | 46 | 48 | +2 | Borderline | Borderline | Borderline | ✓ |
| 5 — NeoTalk | 3 | 3 | 0 | Out | Out | Out | ✓ |
| Borda A — Out→Limited? | 8 | 9 | +1 | Out | Out | Out | ✓ |
| Borda B — Limited→Key? | 20 | 22 | +2 | Limited | Limited | Limited | ✓ |
| Borda C — first-year+pond. | 24 | 28 | +4 | Limited | Limited | Limited | ✓ |

**Resultado.** Zero drift de veredito. Thresholds 18/32 mantidos. Fallback B (20/34) não foi necessário. Validação confirma decisão #14 opção C.

### T2.1 — Round-trip do estado serializado (`outputs/test-co-fill.js`)

Validou `encodeState()` → `decodeState()` com `deepEqual` em 6 cenários representativos.

| # | Cenário | Tamanho encoded (chars) | Result |
|---|---|---|---|
| 1 | Estado mínimo (só Q1) | 52 | ✓ |
| 2 | Estado completo (CoreLedger com 2 comentários) | 604 | ✓ |
| 3 | Estado com proxy de materialidade (vol+rev) | 444 | ✓ |
| 4 | Caracteres especiais (UTF-8 — acentos PT) | 404 | ✓ |
| 5 | Comentário extremo (500 chars na Q3) | 728 | ✓ |
| 6 | Versão inválida | 36 | ✓ |

URL completa típica (cenário CoreLedger): **659 chars** (origin + path + hash). Limite seguro: 2000 chars. Status: ✓ dentro do limite. Decode de strings inválidas (`"lixo"`, `""`) retornou `null` corretamente.

**Resultado.** 6/6 passaram. Encoding UTF-8-safe funciona com acentos portugueses. URLs típicas bem abaixo do limite. Versão inválida é rejeitada como esperado.

---

## Backups e arquivos auxiliares

**Backups V1 já existentes (do Tier 1):**
- `sox-scope.v1-backup.html`
- `sox-demo.v1-backup.html`

**Nenhum backup novo precisou ser criado** — os V1 protegem o estado pré-Tier-1. Pra desfazer o Tier 2 isoladamente, seria necessário criar agora um backup V2-tier1 — recomendo fazê-lo via cópia manual caso o Pedro queira preservar o snapshot exato pós-Tier-1 antes do QA do Tier 2.

**Scripts de validação programática (fora de produção):**
- `outputs/test-prescreen.js` — validação do hotfix HF-001 do Tier 1.
- `outputs/test-q2-weighting.js` — validação empírica T2.7 (drift = 0).
- `outputs/test-co-fill.js` — round-trip T2.1 (6/6).

---

## Pontos de atenção pra QA do Tier 2

1. **PDF com acentos.** Gerar PDF de um cenário com comentários contendo acentos portugueses (ã, ç, á, é, ó). Verificar que aparecem corretamente. jsPDF usa Helvetica WinANSI por padrão, que cobre Latin-1 — mas vale conferir empiricamente. Se houver falha, considerar adicionar fonte UTF-8 embedded (jsPDF.addFont) pro Tier 3.
2. **Co-fill cross-browser.** Copiar link no Chrome, abrir no Firefox / Safari / Edge. Encoding base64 deve sobreviver. Persona deve ser pedida novamente (decisão #2). Banner azul deve aparecer. Respostas e comentários devem estar restaurados.
3. **Decision tree em mobile.** SVG é responsivo via `max-width: 100%`, mas no viewport estreito (~375px) pode ficar pequeno demais. Avaliar se vale refinar no Tier 3 (T3.10 — mobile review). Possível solução: container scrollável horizontal em viewports < 600px.
4. **Q15 + persona Tech vs GRC.** Trocar entre as 3 personas e verificar se os wordings da Q15 fazem sentido contextualmente (Tech: "auditoria SOx em ano(s) anterior(es)"; Finanças: "SOx attestation em ciclo(s) prévio(s)"; GRC: "PCAOB Year 1 / Year 2+"). Help text também muda.
5. **Ponderação Q2 com aplicação real.** Se você tem alguma aplicação real em mente, rodar pela calculadora e ver se o veredito final ainda faz sentido sob a nova ponderação. Como a validação empírica cobriu 5 cenários canônicos + 3 de borda, casos reais fora dessas regiões podem expor edge cases.

---

## Próximos passos — Tier 3 (Nice-to-have, 10 itens)

| # | Item do MD | Resumo | Dependência crítica |
|---|---|---|---|
| T3.1 | #19 | Recalibração de thresholds 18/32 contra ground truth (20-30 aplicações já classificadas Big4) | **Depende de acesso a aplicações reais classificadas** |
| T3.2 | #20 | Página `/calculadoras/sox-metodologia` com referencial público (PCAOB, COSO, COBIT) | Pode ser feito independentemente |
| T3.3 | #21 | Q16 — fechamento crítico (+1 ao RMM se uso predominante em hard close) | Independente |
| T3.4 | #22 | Revisão do Cenário 3 da demo (CardCore) — reescrever ou adicionar cenário paralelo "promovido pra Key" | Atualização em sox-demo.html |
| T3.5 | #23 | Adicionar cenário co-fill na demo (mostrar workflow Tech→Finanças) | Depende T2.1 (já feito) |
| T3.6 | #24 | Adicionar cenário first-year SOx na demo (Q15=Não elevando RMM) | Depende T2.5 (já feito) |
| T3.7 | #25 | Telemetria anonimizada (qty "não sei" por pergunta, tempo médio) | Plausible / GA / endpoint próprio |
| T3.8 | #26 | Histórico / versionamento de avaliações (IndexedDB ou backend) | Decisão de arquitetura |
| T3.9 | #27 | Botão "discutir com auditoria" no banner Borderline/Key (gera draft de email) | Independente |
| T3.10 | #28 | Mobile-first review + tap-friendly tooltips + decision tree mobile | Depende de testes em devices |

---

## Notas técnicas Tier 2

- **jsPDF via CDN.** Carregado com `defer` no `<head>` (`https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js`). Caso o usuário clique no botão de export antes do load, mostra toast warning "Biblioteca PDF ainda carregando — tente em alguns segundos". Após primeiro acesso, fica em cache do browser e funciona offline.
- **Encoding UTF-8 no base64.** O padrão `btoa(unescape(encodeURIComponent(json)))` é a forma canônica de fazer base64 com UTF-8 em JavaScript (workaround histórico do `btoa` que só aceita Latin-1). Decode inverso: `decodeURIComponent(escape(atob(b64)))`. Validado com acentos portugueses no cenário 4 do test-co-fill.
- **Versionamento do estado.** `STATE_VERSION = 2` (V1 = pré-Q15). `decodeState` rejeita versões diferentes — futura migração precisará de função `migrateState(state)`. Caso queira aceitar URLs antigos no Tier 3, implementar shim.
- **Highlight do decision tree em estado parcial.** Quando faltam respostas pra calcular o total, o tree destaca só até onde dá (Q1 → Q3 conhecida, por exemplo). Quando persona é trocada, o highlight é recalculado automaticamente pelo listener change. Quando `lastResult` está disponível (pós-cálculo), highlight usa o veredito final.
- **Comentários NÃO são incluídos no reset do form.** O `<form reset>` só limpa inputs nativos. Pra limpar comentários explicitamente, usuário precisa esvaziar manualmente cada textarea. **Decisão consciente** — comentários costumam ser custosos de re-escrever e o usuário pode querer manter durante uma rodada de testes de respostas. Documentar isso no QA quando o Pedro testar.
- **Persistência.** localStorage continua só `sox_persona`. Estado completo do form fica no hash da URL (T2.1). Combinar futuramente (Tier 3): lembrar último estado em localStorage também, com TTL.
- **Ponderação Q2 ↔ thresholds.** Validação empírica em 8 cenários (5 demo + 3 borda) confirmou que thresholds 18/32 seguem válidos pós-ponderação. Caso futuro item (T3.x) mude pesos novamente, refazer `outputs/test-q2-weighting.js` adicionando mais cenários de borda do domínio real.
- **Sublabel Borderline na demo.** Apenas o Cenário 4 (CreditRisk) foi atualizado. Os outros 4 cenários da demo não disparam Borderline. Cenário 4 agora explicita o raciocínio do sublabel no `gate-trigger` e na implicação prática.
- **Decision tree e mudanças futuras na rubrica.** O SVG é estático em termos de layout. Coordenadas hardcoded. Caso adicione mais uma decisão (T3.3 — Q16 fechamento crítico, por exemplo), pode ser necessário re-desenhar.
- **Persona não no co-fill.** Decisão consciente (#2): o destinatário escolhe a própria persona. Caso quisermos transferir wording sugerido (não obrigatório) no Tier 3, podemos adicionar `state.suggestedPersona` opcional.
- **PDF e linha de assinatura.** A linha está em "Aprovado por (Controller/CFO): ___ Data: ___" — texto fixo. Pra acomodar persona GRC ou outros aprovadores, pode-se parametrizar pelo `currentPersona` no Tier 3.
- **Show your work — empate de pontos.** Se duas perguntas têm o mesmo peso (ex.: Q10 e Q14 ambas com magnitude 4), a ordem entre elas no Top 3 é definida pela ordem original do `getResponseImpacts()`. Sem critério de desempate explícito. Aceitável pro Tier 2.
- **Custo de jsPDF.** ~360KB minified+gzipped. Carrega só na primeira página acessada por sessão; depois browser cache. Impacto inicial detectável só em first-load com conexão lenta.

---

*Documento gerado durante a entrega do Tier 2 — Calculadora de Escopo SOx · ItGov Insights*
