feat(memoria): perfil curado v1.1 — UI no portal + injeção per-account (allowlist)#151
Merged
Conversation
…26-06-19) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pivo de owner-only para per-account: resolveInstructions agora recebe a conta REAL da sessao + a allowlist (PROFILE_INJECT_ACCOUNTS) e so injeta o perfil quando flag on E accountId nao-vazio E na allowlist. Cada conta carrega so os proprios fatos (loadFacts(accountId), nunca DEFAULT). index.ts passa getContext()?.accountId ?? null (sem o fallback 'bruno' de getAccountId), fail-closed por desenho. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
listAccountsWithProfileFacts (SELECT DISTINCT account_id) + runMemoryCuration agora itera todas as contas com fatos, cada uma isolada (loadFacts/upsertFact/ insertAudit sempre com o account_id da conta processada). deps.accountId explicito processa so essa conta (testabilidade); o tick noturno passa listAccounts e processa todas. Sem accountId/listAccounts cai no DEFAULT (compat). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
profile-portal.ts (helpers reusando profile-storage/computeConfidence/
profile-guard) + rotas GET/POST/PATCH/evidence/DELETE em routes.ts, todas
escopadas por res.locals.accountId (sessão, nunca input) e :id validado por
WHERE id=$1 AND account_id=$2 (cross-account → 404). POST recusa segredo
(looks_like_secret) e vazio/>500 chars; evidence recomputa confiança;
memory_audit com trigger portal-{create,edit,evidence,delete}. GET expõe
eligible + injecting (flag + allowlist) + usedChars (renderProfile real).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Nova rota /perfil no portal logado (Next.js) onde o usuário cura os fatos que o Zinom injeta nas sessões dele. - header editorial com badge de status de injeção (ativo / não ativado) - medidor de orçamento usedChars/budgetChars (barra, alerta perto/acima do limite) - form de adicionar fato (select de categoria + textarea), trata 400 looks_like_secret e invalid com mensagem clara - cards de fato: conteúdo, chip de categoria, badge de banda de confiança, star de pinned (toggle), contadores applied/violated, badge 'Injetado agora' quando eligible; ações pin/unpin, 'ainda vale'/'não vale mais', excluir com confirmação - estados loading (skeleton), empty e erro no padrão das outras páginas - hooks React Query (useProfile + mutations) com refetch via invalidação - item 'Perfil' registrado na navegação lateral (lib/nav.ts) + NavId - contratos ProfileFact/ProfileResponse em lib/contracts.ts - testes vitest: hooks (mutations + 400) e componentes (lista + form) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
O quê
Fecha o v1 do perfil curado de memória com UI funcional e pivota de owner-only para per-account governado por allowlist (decisão de produto 2026-06-19: o uso real é via conta friend/portal, não só owner/Claude Code). Atualização registrada no spec.
Mudanças
resolveInstructions): carrega os fatos da conta da sessão (não DEFAULT) e injeta só sePROFILE_INJECT_ENABLEDE a conta está emPROFILE_INJECT_ACCOUNTS. Fail-closed reforçado: cada conta só vê os próprios fatos; accountId ausente/fora do allowlist → base pura; usagetContext()?.accountId(não ogetAccountId()com fallback pra 'bruno').listAccountsWithProfileFacts), isolado por conta, ainda só na tabela nova (fora do eval gate)./portal/profile(per-account, session-authed): GET (lista + budget + injecting), POST (cria, guarda de segredo 400), PATCH (pin/editar), POST/:id/evidence(vale/não-vale → applied/violated + recomputa confiança), DELETE.:idsempreWHERE id AND account_id.web/app/(app)/perfil/): página Perfil com medidor de orçamento, status de injeção, formulário de adicionar fato, cards com banda de confiança/pin/contadores/badge "injetado", ações vale/não-vale/excluir. Item "Perfil" na nav. Reusa o design system (Card/Button/Tag/TextField/EmptyState/Skeleton).Verificação
tsclimpo, 1346 testes (node:test) — inclui injeção allowlist fail-closed, curador multi-conta, 13 testes de rotas.bun run typecheck+bun run build+NEXT_PUBLIC_BASE_PATH=/app bun run buildOK; 244 testes (vitest).Deploy (depois do merge)
Engine: deploy de rotina. Web: build do Next na VPS (
cd web && bun install && NEXT_PUBLIC_BASE_PATH=/app bun run build && rm -rf portal-next && cp -r web/out portal-next) — ver RUNBOOK. Enable:PROFILE_INJECT_ENABLED=true+PROFILE_INJECT_ACCOUNTS=<conta do Bruno>+MEMORY_CURATION_ENABLED=true.🤖 Generated with Claude Code