Commit graph

644 commits

Author SHA1 Message Date
Francisco Solla
34c04d6966 react-audit(família 2): view model mínimo cruza o fio RSC — PetitionForm.tsx:29 deixa de receber o doc Petition inteiro (richText/consent/tracking ficam no server) 2026-08-25 13:40:32 -03:00
Francisco Solla
e562af76d8 feat(audit-p6-m909): deterministic disarm guard for /testing-audit (miss #909) 2026-08-25 11:29:03 -03:00
Francisco Solla
b7d0dba650 fix(audit-p6-2): perfil page uses requireCampaignPageActor; P3-I guard widened to getCampaignUser* variants 2026-08-25 11:29:03 -03:00
Francisco Solla
3fb1a141ba test(audit-p6-1): bypass ratchet — header comment no longer zeroes a file, P6-1 pins 2026-08-25 11:29:03 -03:00
Francisco Solla
b7ed186237 feat(ops98): veto audit/* no safety-net de auto-merge (PR único do audit fica sem automerge) 2026-08-25 08:52:07 -03:00
Francisco Solla
d95f3f575b test(OPS97): parametro nao usado no fetchImpl do teste de convergencia 2026-08-25 02:43:31 -03:00
Francisco Solla
fca5a1c105 refactor(OPS97): fixes do /simplify — fail-closed em PR inexistente, errata do plano, token neutro na skill 2026-08-25 02:43:31 -03:00
Francisco Solla
eec6fd3d49 fix(OPS97): desarme do auto-merge via GraphQL disablePullRequestAutoMerge com laco verificado (licao do dogfood #905) 2026-08-25 02:43:31 -03:00
Francisco Solla
6bb3cfa540 feat(OPS97): disableAutoMerge no github-api + auto_merge normalizado (tests unit) 2026-08-25 02:43:31 -03:00
Francisco Solla
a734bd7372 refactor(ops96): simplify — dedup ms/DEFAULT_TOP no core, exit fail-closed sem relatório, precisão no desarme e pins de fallback 2026-08-25 02:42:40 -03:00
Francisco Solla
71635b8b3b test(ops96-audit): mover 8 specs de artefatos geográficos (readFileSync+hash, sem Payload/DB) de int para unit 2026-08-25 02:42:40 -03:00
Francisco Solla
1bc10f5cd4 test(ops96-audit): mover 4 specs puras com mock/stub de int para unit (formData, supporterListFilters, siteMetadataFallback, eslintConventions) 2026-08-25 02:42:40 -03:00
Francisco Solla
c2f0c44d15 test(ops96-audit): mover 4 specs puros de int para unit (relationship, schemaPrimitives, assertTestDatabase, petition-page-layout) 2026-08-25 02:42:40 -03:00
Francisco Solla
c13174b8aa feat(ops96): motor de métricas baratas + @vitest/coverage-v8 atrás de flag 2026-08-25 02:42:40 -03:00
Francisco Solla
b271d83f6f feat(ops96): tracer — skill testing-audit + comando espelhado + guard de pin 2026-08-25 02:42:40 -03:00
Francisco Solla
019cd456cc feat: S9+ (#771) — integridade de consentimento e alinhamento das ações públicas
- Consent.beforeDelete bloqueia delete com referências (APIError 409 composto
  por coleção), fim do 23502 cru no admin (contagens com overrideAccess).
- submitWhatsapp/submitPetitionSignature delegam o ciclo de transação ao dono
  withPayloadTransaction (rollback no commit-falho, AggregateError, after-commit),
  preservando os contratos { ok: true } / { ok: true, signatureNumber }.
- contactStateSchema exportado + contactCitySchema/contactCityFieldSchema
  consolidados; as 4 fichas usam os exports únicos (fim das cópias inline do
  predicate value in CitiesByState). withMutableConsentFixture purga consent
  via raw SQL para bypassar o hook no harness de teste.

Co-Authored-By: opencode <noreply@opencode.ai>
2026-08-25 00:13:47 -03:00
Francisco Solla
7259193060 S2-FOLLOWUP (#775) — validate do itemId YouTube deixa de ser código morto
O validate de itemId em social-feed-settings lia data.platform (doc inteiro,
sempre undefined) e nunca validava ID de vídeo em produção. Agora lê
siblingData.platform via helper validateExcludedItemId. Stub YouTube ganha
ids de 11 chars e o spec acompanha, destravando o e2e do describe
'Campaign home content section'. Sem migration.
2026-08-24 23:46:57 -03:00
Francisco Solla
d679708c06 fix(worktree): OPS95 — corrige mapa de modelos e remove --variant do launch do TUI (Closes #876) 2026-08-24 23:04:39 -03:00
Francisco Solla
6d962ffd9c fix(campaign): C114-LOCK — hooks do sync do Google Calendar seguram row lock por I/O de rede (Closes #870)
Os afterChange/afterDelete de activity e googleCalendarSync rodavam a reconciliacao completa dentro da transacao do save, segurando row lock + pool por todo o I/O do Google (15s por hop, N RTTs -> 45-75s). Corrige com deadline proprio do hook (GOOGLE_CALENDAR_SYNC_HOOK_TIMEOUT_MS=5s) via AbortSignal.timeout combinado com per-hop 15s no cliente (AbortSignal.any) — manual/webhook mantem 15s sem transacao como fallback confiavel. Fail-closed preservado (abort vira paused). Pin unit hook < per-hop + int hook <=7s com fetch lento.
2026-08-24 22:25:23 -03:00
Francisco Solla
0bb8a96485 feat(campanha): B155+ — migrar quick-edits de célula de lideranças para rota JSON (célula → rota)
F2: POST /campanha/liderancas/state-deputies substitui
setLeadershipStateDeputyMembershipFormAction (chips de /campanha/liderancas B31
e /campanha/dobradinhas B36 — mesma action record).
F3: POST /campanha/liderancas/municipalities substitui
setLeadershipMunicipalitiesFormAction (B34).
Wrappers 'use client' LeadershipStateDeputiesColumnCell /
LeadershipMunicipalitiesColumnCell mantêm o contrato (state, formData) das
shared cells (intocadas); rotas reusam os schemas exportados + allowlists
floor/cap/scope; revalidate herdado das actions record (contrato B34/B31).
F1 (sinal de municípios) não existe mais: C87 o substituiu por form
multi-campo, que por regra B155 permanece em server action — registrado
como já resolvido no plano de intenção.
Guards: whitelist sharedSheetHostConventions (+2 wrappers), prewarm e2e
(+2 rotas), B34 aponta para a rota nova. Sem migration/UI (Impeccable A).

Closes #368
2026-08-24 18:14:56 -03:00
Francisco Solla
5844f026db fix(social-feed): deadline próprio de 5s no hook do save de credenciais encurta a janela de row lock (Closes #762) 2026-08-24 18:03:37 -03:00
Francisco Solla
23a061098a feat(campaign): serializa mutações do editor de relações por célula (Closes #378)
Fila encadeada por instância no MunicipalityRelationEditor: delta otimista
imediato + transporte serializado (próximo elo só dispara quando o anterior
assenta), falha reverte só o delta do próprio elo e a fila segue, busy
derivado da fila (nunca preso), drain aplica o último selectedIDs confirmado
só quando a resposta final o traz (JSON) — sem ele (dobradinhas) confia no
RSC. Substitui requestSeqRef/latestConfirmedRef-seq por fila; tempID de
create em contador próprio. Contratos dos wrappers e call sites intactos.
2026-08-24 18:00:20 -03:00
Francisco Solla
9e1e6e552c fix: prettier format 2026-08-24 17:52:45 -03:00
Francisco Solla
19683a0efb fix(petition): Lead tracking não falha mais assinatura commitada — guarda interna try/catch + spec (Closes #766) 2026-08-24 17:52:45 -03:00
Francisco Solla
facce55eda fix(OPS94): fila de claim não morre mais em issue ready sem frontmatter id (skip + aviso; #659 ganha id B195-F1)
- buildClaimQueue exclui Issues ready sem frontmatter id (não viram worktree
  por construção) e withoutIdReadyIssues() expõe as puladas
- agent:claim / worktree next / pnpm issue next avisam com os números em vez
  de morrer — uma Issue quebrada não trava mais a fila
- pin novo em agentPoolEligibility.unit.spec.ts

Closes #864
2026-08-24 17:23:59 -03:00
Francisco Solla
8951f198ca feat(worktree): flags de modelo --cheap/--pro/--zen/--go/--alibaba com --variant max (OPS93)
Mapa fixo commitado em scripts/lib/worktree.mjs (cheap=cheapestinference/deepseek-v4-flash, pro=opencode-go/qwen3.7-max, zen=opencode-go/ox-alpha-free, go=opencode-go/mimo-v2.5, alibaba=alibaba-token-plan/qwen3.7-max) com WORKTREE_VARIANT=max sempre; resolveWorktreeModel fail-high em múltiplas flags; opencodeLaunchDirective passa a emitir --model <map|preset> --variant max --auto; scripts/worktree.mjs valida at-most-one antes do claim e repassa modelo nos 3 propósitos (next/plan/new) com help/docblock atualizados; .agents/shell/worktree.sh, .opencode/commands/worktree.md, .agents/skills/worktree-next-issue/SKILL.md e local-database skill com contrato remapeado (--go deixa de ser no-op); tests/unit/worktree.unit.spec.ts pina as 5 flags, variant e guardrail.

Closes #859
2026-08-24 17:08:39 -03:00
Francisco Solla
a79d2d3790 fix: prettier format 2026-08-24 16:57:08 -03:00
Francisco Solla
4ee25e31d8 fix(ci): curated result surfaces unmapped risk files before high-risk early-return
Hoist collectUnmappedSrc helper in selectE2eSpecs so unmapped risk-area
files are computed before the high-risk early-return. When high-risk wins
and risk files lack a manifest entry, the curated result now includes
them in unmapped and appends '; curated + risk files without mapping: ...'
to reason — mode stays curated.

Pin: testAffected gains combined case (migration + unmapped risk file →
curated with unmapped in reason). Closes #846.
2026-08-24 16:52:52 -03:00
Francisco Solla
6eb40362d9 review(OPS88): simplify — build surface do reset, contrato high-risk, erros rotulados, docs canônicos 2026-08-24 16:12:44 -03:00
Francisco Solla
7d7fee1619 feat(OPS88): verify do CI/deploy com um Postgres e reset determinístico, um build por run (Closes #834) 2026-08-24 16:12:44 -03:00
Francisco Solla
4d64ad580b chore(worktree): preset model do launcher via OPENCODE_WORKTREE_MODEL — fallback comum deepseek-v4-flash (alinhamento infra-solla/iara-pwa) 2026-08-24 15:43:35 -03:00
Francisco Solla
9c5cd7830b simplify(OPS86): gate fail-fast no unmapped-risk, smoke fallback no manifesto, pins de sync do wrapper, docs AGENT-OPS (Related #846) 2026-08-24 15:19:52 -03:00
Francisco Solla
9af4b92851 ops(OPS86): blast radius dos testes — curated e2e em high-risk, fail-closed para risco sem mapping, unit/int full na seleção vazia (Closes #832) 2026-08-24 15:19:52 -03:00
Francisco Solla
3b32dbc814 fix(OPS83-recurr): cast rotativa do verify #16 — serializar admin atrás do frontend (stub IG compartilhado) + notificação pula recipient sumido em vez de abortar transação 2026-08-24 15:11:39 -03:00
Francisco Solla
ef01b15467 refactor(OPS85): seed + pós-condição do gerador na lib com pin unitário; rest[0] no guard 2026-08-24 14:44:25 -03:00
Francisco Solla
60a71eea4b feat(OPS85): matar o agregado commitado do changelog — registro por-arquivo + HISTORY congelado + leitura sob demanda (Closes #830) 2026-08-24 14:44:25 -03:00
Francisco Solla
a2db543e0c ops(OPS82): preset do launch opencode → DeepSeek V4 Flash 0731 (mais barato) + variantes low/high/max + remoção duplicata cheapest-inference (Closes #817) 2026-08-23 23:20:45 -03:00
Francisco Solla
5b4e5ecf22 ops(OOPS80): cutoff fase 1 — desativar acesso pela URL antiga pt.jorgesolla.com.br (congelar a fonte)
- scripts/check-push-chain.mjs: default --site, usage, erro → canônico; prosa Neon/vercel → homeserver
- tests: fixtures unit (WebAuthn, JsonMutation, aiMarkdownLinks) + int (campaignMultiPhones) → canônico, semântica preservada
- campaignMultiPhones: adiciona ensureLeasedConsent para invite consent fixture (fix pre-existente)
- personas (.opencode/agent/designer, solla-comunicacao, skill): canônico + operação homeserver
- docs: intenção + impl plan + changelog entry; CHANGELOG-AGENTS append-only preservado
- Sem migration, sem schema, sem access/Consent, sem UI
- Closes #796
2026-08-23 20:14:59 -03:00
Francisco Solla
368f138282 feat(campaign): C88 deliberação na atualização — responsável, fio e resolvido (Closes #397)
Migration 20260823_161905_add_municipality_update_deliberation + access por mutationKind + ilha client nas 3 superfícies + specs unit/int/e2e.
2026-08-23 18:58:26 -03:00
Francisco Solla
9467e0f292 fix(campaign): C140 — manual dispatch in 18 forms prevents React 19 form reset on error
Fix manual dispatch em 18 formulários de /campanha que usavam <form action={submitAction}>: campos não controlados voltavam ao defaultValue após qualquer action assentada (sucesso ou erro) do React 19.

- WizardStepFormChrome alterado uma vez (cobre 3 wizard steps)
- 15 forms recebem dispatch manual arquivo a arquivo
- AdvisorPasswordResetButton (2 micro-forms sem campo digitável) ficou como está
- Unit spec novo campaignWizardStepFormChrome.unit.spec.tsx
- CHANGELOG-AGENTS.md cleaned (98 duplicates removed)

Also fixes:
- campaignPageActor writable gate only blocks advisors (was blocking coordinators too)
- campaignLeaderships e2e stability (waitForLoadState before attribute assertion)
2026-08-23 17:54:19 -03:00
Francisco Solla
a97cd56fce fix(campaign): desbloqueia deploy — gate 'writable' libera coordinator/candidate e FAB ganha data-slot do e2e (C142)
Dois bugs do C142 que o e2e full do verify do deploy pegou (o PR rodou só o blast radius):
- requireCampaignPageActor gate 'writable' checava advisorEditingAccess(user)==='none', que retorna 'none' para QUALQUER papel não-advisor — barrava coordinator/candidate de páginas de escrita (municipios/[slug]/editar redirecionava o coordinator pro detalhe).
- CampaignQuickActionsFab não renderizava data-slot='campaign-quick-actions-fab', o locator do e2e campaignPermissionProfile.
Regressões pino: campaignPageActorGate.unit.spec.ts (5 casos) + assert de data-slot no spec do FAB.
Verificado: tsc/lint/format/cycles, unit 2435, int 819, e2e local dos specs afetados (os 3 casos que falhavam no deploy passam).
2026-08-23 16:41:40 -03:00
Francisco Solla
67c213585c ops(OPS78): launch do worktree opencode roteia pelo Vercel AI Gateway com variantes low/high/max (Closes #784) 2026-08-23 16:08:12 -03:00
Francisco Solla
038758eb81 docs(OPS47): alinha plano do agent-pool à política main-based pós-OPS71
- agent-pool-orchestrator.md: PR --base stage + issue-done-on-stage-merge.yml
  + promote stage→main viram --base main + issue-done-on-main-merge.yml
  + sem promote; migration-lock → countOpenSchemaPrs; model-selection →
  agent-pool-models.mjs; agent-github.mjs → agent-forgejo.mjs; workflow
  marcado removido OPS65 (caminho real .forgejo/workflows/agent-pool.yml)
- agent-pool/SKILL.md: L79 sem 'Antes do promote'; L105 agent-pool-github→forgejo
- comentário/label: agent-pool-state.mjs 'merge in stage'→main;
  agentPoolState.unit.spec.ts label 'on stage merge'→main
- changelog 2026-08-23-ops47.md (Closes #735)
2026-08-23 15:23:52 -03:00
Francisco Solla
dddbd920e0 fix(OPS46-S1): hook ESM tenta resolução bare do next/cache antes do remap (Closes #789) 2026-08-23 15:02:16 -03:00
Francisco Solla
a74a2dca9e refactor(OPS46): simplify pós-revisão — release do claim ao fim do cleanup (janela purge segura), gate da hook exige o par de flags, Set→boolean, guard setval/nextval\s*\( e spec de steal invariante-primeiro 2026-08-23 14:24:33 -03:00
Francisco Solla
89bf9d0854 ops(OPS46): e2e local coleta via hook ESM (next/cache + server-only) e allocator de município com registry anti-wrap (Closes #733)
Fase 1: playwright bare (--list, extensão VS Code, runs ad-hoc) quebrava na
coleta — next@15 sem exports não resolve 'next/cache' em ESM nativo e
server-only exige a condição react-server; o script test:e2e carregava ambas
via NODE_OPTIONS (por isso o CI passava). Hook de resolução ESM vitest-free
(e2eEsmResolve.mjs) registrada no main via module.register + propagada aos
workers via NODE_OPTIONS quando invocada bare; path do script intocado.

Fase 2: a sequência persistente campaign_fixture_municipality_alloc nunca é
resetada e um ciclo completo claima ~505 do catálogo de 435 — o wrap em todo
ciclo em DB de worktree fazia dois runs concorrentes receberem o mesmo índice
e purgarem as linhas vivas um do outro. Registry de claims compartilhado
vitest-free (campaignMunicipalityAllocator.ts): INSERT ON CONFLICT DO NOTHING
com skip de slot vivo, steal de claim stale (TTL 2h), release no cleanup dos
dois fixtures, erro claro de exaustão. Guard estático no
testMunicipalityAllocatorConventions + spec int de stress.
2026-08-23 14:02:19 -03:00
Francisco Solla
1c865bd822 refactor(campaign): E1 simplify — pin loading/retry/stale-quirk no spec e tipo local
Review estrutural + qualidade (sem P1): spec ganha 3 pins do contrato mais
sutil (loading em voo, retry pós-falha, quirk gate→not-ready com resposta
stale — comportamento herdado dos 3 originais, preservado); UseAsyncSearchOptionsResult
vira tipo local (export especulativo, knip types:error); docstring documenta
o quirk e o trim; plano registra o ajuste de execução.
2026-08-23 13:16:47 -03:00
Francisco Solla
9a66a23cf6 refactor(campaign): E1 extrai useAsyncSearchOptions (3ª cópia da busca com debounce)
DemandResponsibleMultiSelect (C143), ResponsibleMultiSelect (C90) e
AsyncSearchCombobox trocam o efeito duplicado (requestId/setTimeout 250ms/
loading/failed) pelo hook compartilhado src/hooks/useAsyncSearchOptions.ts,
com isQueryReady opcional preservando a semântica de query vazia de cada
consumidor. Comportamento preservado; unit novo do hook (renderHook +
fake timers); sem schema/server/migration.
2026-08-23 13:16:47 -03:00
Francisco Solla
0d483a08db feat(campaign): C142 UI respects advisor permission profile somente_leitura
- Pure helpers: advisorEditingScope, rowEditingAllowed in campaignAdvisorProfile.ts
- gate: 'writable' in requireCampaignPageActor for route-level enforcement
- Shared cells accept readOnly prop: CampaignInlineEditableCell, MunicipalityRelationEditor, PhonesFieldEditor, DemandDescriptionEditor, etc.
- Municipality pages compute editingScope via resolveMunicipalityWriteScope and thread it to list/detail/edit surfaces
- Home actions, FAB mount rule, quick actions registry accept editingScope parameter
- Demands, activities, supporters, organizations create buttons gated
- E2E spec: campaignPermissionProfile.e2e.spec.ts covering 3 profiles
- Unit tests: campaignAdvisorProfile, accessShared, campaignComponents updated
- gate:fast passed (tsc, lint, format, knip, cycles, unit)
2026-08-21 23:01:35 -03:00
Francisco Solla
c90f70aab4 ops(OPS76): tracker de Issues migra do Forgejo para o GitHub — GitHub como host único
Decisão (2026-08-21): o GitHub passa a ser a fonte única — main, branches,
PRs, CI via Actions E tracker de Issues. O Forgejo deixa de ser canal ativo
(git.e issue tracker congelados pós-convergência).

Data: 17 issues migradas do Forgejo para o GitHub (frontmatter id/depends/
serializes/priority/model preservados, labels mapeados, comment de origem
em cada uma; tabela Forgejo→GitHub registrada).

Tooling: github-api.mjs estendido com a camada de issues/labels/comments/
close/workflow-dispatch/contents (mesmo shape normalizado do forgejo-api);
18 scripts trocam o transporte forgejo-api → github-api; forgejo-api.mjs e
seu teste (961 linhas) removidos; teste githubApi.unit.spec.ts novo (7 casos);
issue-transition-on-merge.mjs renomeado e reapontado.

Flips pós-merge: issue-done e plan-issue-ready agora usam o GITHUB_TOKEN com
issues:write no repo (sem FORGEJO_API_TOKEN) e fecham/flipam Issues no GitHub.

Docs: AGENTS.md, AGENT-OPS.md e skills do fluxo vivo (work-issue, plan-issue,
project-status, capture-review-debts, worktree-next-issue, agent-work-issue)
apontam o tracker para github.com/fsolla/teqo/issues.

Gates: tsc/lint/format/knip/cycles/unit 2416 verdes.
2026-08-21 08:19:06 -03:00