From b74268714c2d543f16856c91a1d7938daf7ace49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Ign=C3=A1cio=20Fontoura=20Solla?= Date: Tue, 4 Aug 2026 01:13:44 -0300 Subject: [PATCH] =?UTF-8?q?C86+=20=E2=80=94=20simplify:=20JSDoc=20do=20con?= =?UTF-8?q?trato=20home,=20testes=20de=20borda=20e=20nota=20no=20impl=20pl?= =?UTF-8?q?an?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes do /simplify (3 revisores read-only): JSDoc de normalizePathname/isListPath documentando o invariante (homes nunca são '/' nem terminam em slash), teste de multi-slash e inputs degenerados, comentário de isCampaignHomePath encurtado. Sem mudança de comportamento. --- .../plans/escala-dry-pos-acoes-rapidas-impl.md | 18 ++++++++++++++++++ src/lib/campaignQuickActionMount.ts | 2 +- src/lib/campaignQuickActionPaths.ts | 7 ++++--- tests/unit/campaignQuickAction.unit.spec.ts | 7 +++++++ 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/docs/plans/escala-dry-pos-acoes-rapidas-impl.md b/docs/plans/escala-dry-pos-acoes-rapidas-impl.md index 1f21dfe3..dc58d8b2 100644 --- a/docs/plans/escala-dry-pos-acoes-rapidas-impl.md +++ b/docs/plans/escala-dry-pos-acoes-rapidas-impl.md @@ -107,3 +107,21 @@ N/A — refactor estrutural; nenhuma métrica, série, ranking ou mapa novo. - [ ] Invariantes AGENTS/engineering-standards: client-safe, sem migration, sem access/Consent, identificadores em inglês - [ ] Testes de domínio: specs existentes dos 9 wrappers + describe novo de `isListPath`/`normalizePathname` - [ ] Self-score decision-quality: 5/5 (decisões caras com rejeitadas; appetite respeitado; rabbit holes nomeados; depth check reusa o home existente; outcome preservado) + +## Simplify (2026-08-04) — aplicado e deferido + +3 revisores paralelos (read-only) no diff da sessão; veredito do revisor de corretude: **bordas fechadas, comportamento preservado** (tabela de equivalência borda a borda dos matchers antigo × `isListPath`). Revisor de reuse: **sem duplicação real remanescente** (zero matchers exatos fora do diff; prefix-matches de descendentes deixados de fora por semântica diferente). + +**Aplicados (fixes pontuais que preservam comportamento):** + +- JSDoc de `normalizePathname` documenta o invariante "homes nunca são `/` nem terminam com slash" (S1 quality). +- Wording do JSDoc de `isListPath` corrigido ("equals `home`, optionally with a single trailing slash") (S3 quality). +- Testes novos pinando multi-slash (`/campanha//`) e inputs degenerados (`''`, `'/'` como home, double trailing slash) (S2 quality + S1 correctness). +- Comentário de `isCampaignHomePath` encurtado para o why ("same exact-match rule as the sidebar nav") (S4 quality). + +**Descartados:** + +- `isLeadershipListPath` como wrapper privado com 1 call site — manter (consistência de padrão com os 7 irmãos; inline seria micro-otimização de estilo) (S1 reuse, score 1). +- Contrato `home` sem tipo restrito — JSDoc documenta; gatilho: chamador futuro com home terminando em `/` (S2 correctness, score 1). + +**Defer com gatilho (já registrados na intenção, não reabrir):** derivação de regex numérica de detalhe (3º vertical com `[id]` numérico — hoje 2: advisor + supporter); cache `Map` (4º site com shape compatível); id `register-supporter` sobrecarregado (agregação de catálogos). diff --git a/src/lib/campaignQuickActionMount.ts b/src/lib/campaignQuickActionMount.ts index 756ec7df..cf56febc 100644 --- a/src/lib/campaignQuickActionMount.ts +++ b/src/lib/campaignQuickActionMount.ts @@ -8,7 +8,7 @@ import { type CampaignRole, } from '@/lib/campaignRoles' -/** Início matches only exactly — same rule as sidebar nav. */ +/** Same exact-match rule as the sidebar nav. */ export const isCampaignHomePath = (pathname: string): boolean => isListPath(pathname, CAMPAIGN_HOME) export const isCampaignActionsPath = (pathname: string): boolean => diff --git a/src/lib/campaignQuickActionPaths.ts b/src/lib/campaignQuickActionPaths.ts index 8dd2cb6a..31aff93a 100644 --- a/src/lib/campaignQuickActionPaths.ts +++ b/src/lib/campaignQuickActionPaths.ts @@ -17,13 +17,14 @@ export type OrganizationQuickActionSurface = | { kind: 'detail'; organizationSlug: string } /** - * Strips a single trailing slash for client-side path comparisons, preserving `/`. - * Homes in this codebase are never `/`, so `/campanha/` → `/campanha` while `/` stays `/`. + * Strips a single trailing slash for client-side path comparisons, preserving `/` + * (`/campanha/` → `/campanha`, while `/` stays `/`). Homes in this codebase never + * are `/` nor end with a slash — `isListPath` relies on that contract. */ export const normalizePathname = (pathname: string): string => pathname.length > 1 && pathname.endsWith('/') ? pathname.slice(0, -1) : pathname -/** Whether `pathname` is exactly `home`, with an optional trailing slash (list pages). */ +/** Whether `pathname` equals `home`, optionally with a single trailing slash. */ export const isListPath = (pathname: string, home: string): boolean => normalizePathname(pathname) === home diff --git a/tests/unit/campaignQuickAction.unit.spec.ts b/tests/unit/campaignQuickAction.unit.spec.ts index 6e57e4cc..eee4cf04 100644 --- a/tests/unit/campaignQuickAction.unit.spec.ts +++ b/tests/unit/campaignQuickAction.unit.spec.ts @@ -133,6 +133,13 @@ describe('campaignQuickActionPaths (shared list helpers, C86+)', () => { expect(normalizePathname('/campanha')).toBe('/campanha') expect(normalizePathname('/')).toBe('/') expect(normalizePathname('/campanha/apoiadores/')).toBe('/campanha/apoiadores') + expect(normalizePathname('/campanha//')).toBe('/campanha/') + }) + + it('pins the degenerate inputs the inline matchers used to handle', () => { + expect(isListPath('/campanha/demandas//', '/campanha/demandas')).toBe(false) + expect(isListPath('', '/campanha/demandas')).toBe(false) + expect(isListPath('/', '/')).toBe(true) }) })