← Aceite MVP V1 — evidências em vídeo

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/:chat nas 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.md Fechamento (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, :terminal e :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-config hoje em config.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

RolePermissõesRAGs (: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:

padrão — ::teste/::user não alcançam RAG de projeto).

: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.

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).

permissões específicas depois — editando só o seed; a maquinaria multi-role já existe.

service/roles.clj (union-permissions/union-allowlists).

1.2 Usuário → role

Usuário (SSO)Role(s)Efeito prático
ianffcs::operatorAcesso total (:*) + RAGs pinha/dev-machine + os 3 modelos
pcms::operatorIdem 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

GateOndeRegra
:rag-read (POST /rag/query)core.clj:812Role 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 modelosinference_proxy.clj:1071-1091operator (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çãoKeycloakToken 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):

AtorPOST /rag/queryPOST /rag/ingest
pcms (::operator)200
ianffcs (::operator)200200 (indexed >= 1)
ctni.teste (::user + ::teste)403403
sem token401401

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

OwnerConteúdo
pinhaConhecimento do próprio projeto pinha
dev-machineConhecimento da infraestrutura NeoTek (owner declarado na allowlist :rags de ::operator)

2.2 O que entra no corpus (owner pinha)

OrigemO que é
Monorepo pinhadocs/, 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õesClasse
.mdConhecimento
.clj .cljs .cljc .edn .py .go .yml .yaml .sh .toml .jsonCó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

MecanismoDetalhe
Scrub de PIIPresidio (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 scrubEntidades 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ênciaE2E PII (E7): run 20260904T044108Z-da114adentities_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étricaComo medirLigaçãoAlvo sugeridoEvidência neste bundle
M1Cobertura e2e dos cenários P0runs verdes consolidadas num único commit (docs/mvp-v1/evidence/index.md)E4/E5/E7/E84/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
M2Integridade da trilha de auditoriaGET /v1/admin/audit/integrity sem divergência de cadeiaE9100% das checagens com cadeia válidavídeo audit-integrity no index (2026-09-02) + hash-chain atestada no dossiê admin
M3Scrub de PII sem vazamentoentities_scrubbed > 0 em ingest com PII; zero identificadores no store/retrieveE70 vazamentosrun 20260904T044108Z-da114ad: entities_scrubbed=2, <REDACTED> no store/retrieve (e2e-privacy-visibility.log)
M4TTFT do baselinecaderno ai-factory-task-pack/M5-medicoes-spark02-2026-09.md + catálogo /var/db/small-pine/throughput.tsvE10TTFT p50 ≤ 1 s; throughputs registrados por rodadacaderno M5 · logs bench spark01/spark02 (05/09) (TTFT 0,44 s constante; 32 streams → 30,1 tok/s agregado) · throughput.tsv
M5Disponibilidade do prodhealthcheck/uptime do Chatsubo + regiões de falha nos findingsE11≥ 99% mensalhealthcheck manual (/health → 200 em 2026-09-22); sem monitor de uptime contínuo — lacuna registrada
M6Time-to-redeploy do proddeploy ansible limpo no dev-machine (sem fix manual)E111 sessão ≤ 1 dia, sem fix manualsem run de redeploy cronometrada; lacuna registrada no dossiê E11 (runbook narrativo pendente)
M7Compliance de acesso ao RAG403 uniforme para não-operadores; 0 falso-positivos em operadoresE5100% (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)
M8Documentos de governança assinadoseste doc + dossiês E1/E2 com §assinatura preenchidaE1/E2100% até o aceite finaltrilha §4 — dono ✅ 17/09; pcms ⬜; auditoria ⬜

4. Trilha de aprovação

PapelNomeDataAssinatura
Dono (operador protegido, NeoTek)ianffcs2026-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 pcms e 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 quando pcms e a auditoria assinarem.


5. Mudança necessária para fechar o FINDING-6

  1. ✅ Matriz de papéis documentada (seção 1) — antes só em ::roles-config.
  2. ✅ Classificação do corpus documentada (seção 2) — antes implícita no script de ingest.
  3. ✅ Métricas de sucesso (seção 3) — aprovadas pelo dono (ianffcs, 2026-09-17) como

baseline M1–M8; valores-alvo calibráveis por release.

  1. ✅ 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.

  1. ⬜ Contraprova de pcms e 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.