Governança — MVP V1 (E1): papéis, corpus e métricas
Data: 2026-09-05 · Aprovação do dono: 2026-09-17 · Revisão da §1: 2026-09-22 (estado do commit
c4d5804::web-search/:terminal/:chatnas roles; acesso a modelo via hot ∪ was-hot) Status: APROVADO PELO DONO (ianffcs) — pendente de contraprova de pcms e da auditoria Origem: auditoria "Manus AI" (2026-09-01), entregável E1 —FINDING-6(DOC_EVIDENCE_ONLY, P1) Referências:DOSSIER-MVP-V1-e2-ambiente-alugado.md§5 (anexo E1) ·DOSSIER-MVP-V1-e10-baseline.md·DOSSIER-MVP-V1-e11-operacao.md·DOSSIER-MVP-V1-rag-access-control.mdFechamento (FINDING-6): matriz de papéis e classificação do corpus promovidas do código a documento; métricas de sucesso propostas na seção 3.
1. Papéis (matriz)
Revisão 2026-09-22 (commit
c4d5804): (a) as roles ganharam:web-search,:terminale:chat; (b) a allowlist estática de modelos (:models) foi removida — o acesso a modelo agora é por hot ∪ was-hot (§1.3); (c) referências de linha atualizadas (::roles-confighoje emconfig.clj:204).
Extraída de apps/small-pine/src/small_pine/config.clj — ::roles-config (linha 204; seed; Datomic é a autoridade em runtime, carregada no boot). Permissões (service/roles.clj): :* (operator, concede tudo), :read (todas as leituras Pathom), :rag-ingest (POST /rag/ingest), :rag-read (POST /rag/query), :web-search (POST /v1/search/web), :terminal (/v1/terminal/{path...}), :chat (/v1/chat/completions com OIDC próprio), :schedule-model (POST /prewarm/<model>), <mutation-name> (gateia uma mutation individual, ex.: :register-user!).
1.1 Role → permissões
| Role | Permissões | RAGs (:rags) | Modelos |
|---|---|---|---|
::operator | #{:* :rag-ingest :rag-read :web-search :chat} | #{"pinha" "dev-machine"} | todo o catálogo (:* + bypass do gate) |
::admin | #{:register-user! :read :schedule-model :ldap-dashboard-read :liveplay-read :web-search :terminal :chat} | #{} | todo o catálogo (role com :schedule-model) |
::user | #{:read :chat :web-search :terminal} | #{} | hot ∪ was-hot |
::teste | #{:read :terminal} | #{} | hot ∪ was-hot |
Notas do seed:
- Fail-closed: allowlist vazia = nenhum acesso (
:ragsvazio nega por
padrão — ::teste/::user não alcançam RAG de projeto).
- Acesso a modelo (novo mecanismo,
c4d5804): operators (ou role com
:schedule-model) roteiam para todo o catálogo; as demais roles roteiam para o conjunto hot ∪ was-hot — o que está quente agora ou já esteve (service/hot_history.clj, store EDN file-backed gravado quando um modelo atinge :ready). Motivação: a allowlist estática antiga dava 403 a operator selecionando qwen3.6-35b-a3b-nvfp4 que o /models já listava.
- Nota de integridade: o store was-hot é *advisory* para a lista de
modelos, não fronteira de autorização (hot_history.clj: "not an authorization boundary"); a fronteira continua no gate do inference_proxy (inference_proxy.clj:1071-1091).
::testeé placeholder paractni.testecarregar um segundo role hoje e ganhar
permissões específicas depois — editando só o seed; a maquinaria multi-role já existe.
- O union de allowlists entre roles de um mesmo usuário é coberto por
service/roles.clj (union-permissions/union-allowlists).
1.2 Usuário → role
| Usuário (SSO) | Role(s) | Efeito prático |
|---|---|---|
ianffcs | ::operator | Acesso total (:*) + RAGs pinha/dev-machine + os 3 modelos |
pcms | ::operator | Idem ianffcs |
ctni.teste | #{::user ::teste} | Autentica no SSO, mas não alcança o RAG do projeto (owner pinha, operator-only) |
1.3 Gates de RAG e de modelos
| Gate | Onde | Regra |
|---|---|---|
:rag-read (POST /rag/query) | core.clj:812 | Role com :rag-read e owner do RAG no :rags da role |
:rag-ingest (POST /rag/ingest) | core.clj:668 (legacy) / core.clj:757 (EQL) | Role com :rag-ingest ou ::rag-ingest-token (token interno service-to-service, mesmo caminho do matrix runner) |
Allowlist por owner (:rags) | ::roles-config | ::operator → {"pinha" "dev-machine"}; demais roles → vazio (fail-closed) |
| Acesso a modelos | inference_proxy.clj:1071-1091 | operator (roles nil ou com :schedule-model) → todo o catálogo; demais roles → hot ∪ was-hot (::config/hot-history, store service/hot_history.clj). *A antiga allowlist estática por role (:models/::model-allowlist) foi removida em c4d5804 (2026-09-22)* |
| Autenticação | Keycloak | Token introspection RFC 7662; sem token → 401 |
Evidência e2e — RAG access (E5), run 20260904T044108Z-da114ad (FINDING-2, resolução TASK-210; driver small-pine.e2e-rag-knowledge-access; plano apps/small-pine/docs/test-plans/done/e2e-34-rag-knowledge-access-control.md; log evidence/20260904T044108Z-da114ad/e2e-rag-knowledge-access.log):
| Ator | POST /rag/query | POST /rag/ingest |
|---|---|---|
pcms (::operator) | 200 | — |
ianffcs (::operator) | 200 | 200 (indexed >= 1) |
ctni.teste (::user + ::teste) | 403 | 403 |
| sem token | 401 | 401 |
2. Classificação do corpus
Fonte: apps/small-pine/scripts/operator/ingest-pinha-corpus.clj + testes e2e (e2e_rag_knowledge_access.clj, e2e_rag_prod_enabled.clj).
2.1 Owners
| Owner | Conteúdo |
|---|---|
pinha | Conhecimento do próprio projeto pinha |
dev-machine | Conhecimento da infraestrutura NeoTek (owner declarado na allowlist :rags de ::operator) |
2.2 O que entra no corpus (owner pinha)
| Origem | O que é |
|---|---|
| Monorepo pinha | docs/, kb/, apps/small-pine/docs/ (ADRs, dossiês, conhecimento) |
Repo dev-machine (externo) | docs/ + código — ansible/, deployer/, services/, scripts/, catalog-cli/, agent-hub/, enverge-sparks-infra/ |
| Extensões | Classe |
|---|---|
.md | Conhecimento |
.clj .cljs .cljc .edn .py .go .yml .yaml .sh .toml .json | Código/config |
Exclusões do dev-machine: .git/, target/, node_modules/, .cpcache/, .clj-kondo/, .mise/, .qwen/ e artefatos de build. Cada arquivo é ingerido com owner_id "pinha" e source = caminho relativo. Idempotência: re-ingest duplica (chunk = UUID próprio no store Datomic) — para popular do zero, limpar o owner pinha antes; o script não apaga nada.
2.3 Scrub de PII e quarantine
| Mecanismo | Detalhe |
|---|---|
| Scrub de PII | Presidio (analyzer/anonymizer via fronteira Python; config ::rag-presidio-*, incluindo perfis pt-BR analyzer-pt.yaml/nlp-pt.yaml/recognizers-pt.yaml) + OpenMed (OpenMed-PII-Portuguese-...-v1, ::rag-openmed-enabled true) |
| Saída do scrub | Entidades redigidas aparecem como <REDACTED> no store e no retrieve |
| Quarantine | ::rag-quarantine-path (default /var/db/small-pine/privacy-quarantine), protegido por ::rag-quarantine-key |
| Evidência | E2E PII (E7): run 20260904T044108Z-da114ad — entities_scrubbed=2, identificadores ausentes no store/retrieve, <REDACTED> presente (evidence/20260904T044108Z-da114ad/e2e-privacy-visibility.log) |
O corpus é PII-free on purpose (constante nos dois drivers e2e de RAG); o scrub existe como barreira estrutural para conteúdo futuro.
3. Métricas de sucesso
✅ aprovadas pelo dono (ianffcs, 2026-09-17) como baseline do MVP V1. Antes do FINDING-6 não havia métricas em documento aprovado; M1–M8 abaixo passam a ser o baseline, com valores-alvo calibráveis por release.
| # | Métrica | Como medir | Ligação | Alvo sugerido | Evidência neste bundle |
|---|---|---|---|---|---|
| M1 | Cobertura e2e dos cenários P0 | runs verdes consolidadas num único commit (docs/mvp-v1/evidence/index.md) | E4/E5/E7/E8 | 4/4 cenários P0 por release do MVP — 4/4 verdes (PII, RAG access, egress stamp: 2026-09-04, run 20260904T044108Z-da114ad; admin E4 browser: 2026-09-06, run 20260906T022327Z-689a252) | Galeria run P0 04/09 · Galeria run admin 06/09 · índice de runs |
| M2 | Integridade da trilha de auditoria | GET /v1/admin/audit/integrity sem divergência de cadeia | E9 | 100% das checagens com cadeia válida | vídeo audit-integrity no index (2026-09-02) + hash-chain atestada no dossiê admin |
| M3 | Scrub de PII sem vazamento | entities_scrubbed > 0 em ingest com PII; zero identificadores no store/retrieve | E7 | 0 vazamentos | run 20260904T044108Z-da114ad: entities_scrubbed=2, <REDACTED> no store/retrieve (e2e-privacy-visibility.log) |
| M4 | TTFT do baseline | caderno ai-factory-task-pack/M5-medicoes-spark02-2026-09.md + catálogo /var/db/small-pine/throughput.tsv | E10 | TTFT p50 ≤ 1 s; throughputs registrados por rodada | caderno M5 · logs bench spark01/spark02 (05/09) (TTFT 0,44 s constante; 32 streams → 30,1 tok/s agregado) · throughput.tsv |
| M5 | Disponibilidade do prod | healthcheck/uptime do Chatsubo + regiões de falha nos findings | E11 | ≥ 99% mensal | healthcheck manual (/health → 200 em 2026-09-22); sem monitor de uptime contínuo — lacuna registrada |
| M6 | Time-to-redeploy do prod | deploy ansible limpo no dev-machine (sem fix manual) | E11 | 1 sessão ≤ 1 dia, sem fix manual | sem run de redeploy cronometrada; lacuna registrada no dossiê E11 (runbook narrativo pendente) |
| M7 | Compliance de acesso ao RAG | 403 uniforme para não-operadores; 0 falso-positivos em operadores | E5 | 100% (gate fail-closed) | run 20260904T044108Z-da114ad: 200×2 operator / 403×2 não-operator / 401×2 sem token · relatório Bruno RAG access boundary (19/09) |
| M8 | Documentos de governança assinados | este doc + dossiês E1/E2 com §assinatura preenchida | E1/E2 | 100% até o aceite final | trilha §4 — dono ✅ 17/09; pcms ⬜; auditoria ⬜ |
4. Trilha de aprovação
| Papel | Nome | Data | Assinatura |
|---|---|---|---|
| Dono (operador protegido, NeoTek) | ianffcs | 2026-09-17 | ✅ Aprovado — Ian Fernandez (ietcd@cryptolab.net), dono/operador protegido. Aprova papéis (§1), classificação do corpus (§2) e as métricas M1–M8 (§3) como baseline do MVP V1. |
| Operador (NeoTek) | pcms | ⬜ Pendente — aguardando assinatura de Patrick Serrano (pcms). | |
| Auditoria ("Manus AI") | ⬜ Pendente — aguardando contraprova da auditoria. |
Espelha o §7 de
docs/archive/mvp-v1/REPORT-MVP-V1-FINAL.md(aceite E1–E11).Nota de integridade: a assinatura do dono foi registrada por ianffcs em 2026-09-17. As linhas de
pcmse da auditoria permanecem deliberadamente em aberto — uma assinatura de terceiro não pode ser preenchida por outra parte. O documento passa de RASCUNHO a APROVADO PELO DONO, mas o aceite final (FINDING-6, M8) só se completa quandopcmse a auditoria assinarem.
5. Mudança necessária para fechar o FINDING-6
- ✅ Matriz de papéis documentada (seção 1) — antes só em
::roles-config. - ✅ Classificação do corpus documentada (seção 2) — antes implícita no script de ingest.
- ✅ Métricas de sucesso (seção 3) — aprovadas pelo dono (ianffcs, 2026-09-17) como
baseline M1–M8; valores-alvo calibráveis por release.
- ✅ Assinatura do dono na trilha (seção 4) — registrada em 2026-09-17; o documento
deixa de ser rascunho e passa a governança aprovada pelo dono.
- ⬜ Contraprova de
pcmse da auditoria (seção 4) — única pendência restante para o
aceite final do FINDING-6 / M8. Não pode ser preenchida por outra parte.