* feat(campanha): responsive grid and viewport cap for home search results (B54)
Adds HomeSearchResultsLayout with 1/2/3-column breakpoints and allocateHitBudget so Municípios keep priority while total hits stay within per-viewport limits.
Closes#8
* fix(campanha): un-export knip-unused home search budget helpers
CI e2e serves a production build on localhost; Next inlines NODE_ENV so
WebAuthn RP resolution now treats localhost requests as test mode. Saved
filters avoids a racing bare goto. Analytics/SpeedInsights render only on Vercel.
Root cause of the prod-build React #130 on /campanha/municipios: the
md:hidden mobile-cards tree still hydrated ~25 rows x ~5 sheet controls
(~125 eager Drawer/DrawerCloseButton instances) even on wide viewports.
Filtered ?q=... routes failed more often only because they exercise the
list with filters active — the search param itself was not the bug.
CampaignListSheetProvider hosts a single bottom Drawer for the whole
mobile section; CampaignCellEditOverlay sheet cells portal their
body/footer into it while keeping per-cell open state and autosave
scaffolds. Footers with DrawerCloseButton are only created once a sheet
actually opens. Desktop popover path is unchanged; per-cell Drawer
remains the fallback for surfaces without the provider.
Also: DrawerCloseButton (function render prop, avoids base-ui element
render in prod bundles) replaces the DrawerClose render={<Button/>}
pattern across call sites; stale e2e selectors refreshed; e2e affected
script + playwright github/list reporters for CI; use-mobile reverted
(no consumers of the gate remain).
Guardrail filed as issue #52.
- ci-pr.yml: split the serial checks job into parallel lint/format/
typecheck/knip/cycles + unit/int (vitest --changed vs PR base via
scripts/test-affected.mjs, full fallback on high-risk paths) + e2e
(manifest path->spec via scripts/e2e-affected.mjs, blocking) + build;
migration-lock gains checkout + pull-requests:read (fixes the failures
that blocked PR #50)
- ci.yml (main): full safety net — seed:minimal + int full + build + e2e
- package.json: gate:fast / gate:push; .husky/pre-push runs gate:push
- docs: "Dono do PR, dono do CI" policy in AGENT-OPS + work-issue +
engineering-standards; changelog entry; plans for OPS3-OPS7
migration-lock ran `gh pr list --json files` without actions/checkout, so
every PR failed the job in 3s with "not a git repository". The leadership
portfolio spec asserted the exact global hit set with fixed names, which the
minimal seed (Seed Liderança Um/Dois) collides with via word-start 'Lider';
switch to the unique-token pattern already used by the demands spec.
Two-step UX-1 flow on the B59 chassis with URL contract ?signalType= and optional ?entryAction= for embedded skip; reuses createMunicipalityListSignalFormAction.
Unify violation highlights with getWizardVoteViolation, share the expected-votes save error constant, and drop dead parseWizardVoteDraft plus unused municipalitySlug prop.
Organization stays by product decision (political branching, e.g. SindMed);
the leadership gains `exclusive` (default true) with list badge and form
checkbox, and sector/sectorNotes/consentNote leave the collection, zod,
forms, list filters/sort, invite autofill and redemption.
Keep violationEditedScenario when navigating to the inconsistent scenario
so média shows warning immediately after pessimista breaks order; clear
on draft/shortcut edits. Adds regression unit tests and roadmap B76.
Staff can adjust municipality expected votes through média→pessimista→otimista steps with shortcuts, coherence warnings, and a single POST on completion.
Drops signalSource/triangulated from municipalityUpdate (migration
simplify_municipality_signal_fields), rewrites signal-type labels for the
field team, and treats any adversary signal as confirmed in E11 (P1
triage 1). Also fixes the stale post-B43 leader-home e2e and lowers a
drifted bypass pin.
- F1: loadMunicipalityScopeFromDocs evita segunda query em municipalityPageData
- F2: computeAllMunicipalityPotentials memoizado por processo
- F3: TooltipProvider movido para o layout de (app)
- F4: DRY nos filtros multi do mobile em MunicipalityFilters
The B46 flex spacer never filled the scrollport because min-h-full did not propagate; h-full min-h-0 plus home-dock groups the thumb zone above bottom nav.
Staff see role-ranked shortcuts (advisor portfolio by signal age; CG/candidate by alta priority deficit) via POST mode suggest, without treating empty query as search.
B58 hid the scrollbar but dropped mouse drag-to-scroll; pointer-fine
handlers pan past an 8px threshold while coarse touch keeps native pan-x.
Includes simplify pass (imperative data-dragging, coarse-pointer test)
and pin ratchet for municipalityElectoralBaseline bypass count.
Staff get six launchers with uncovered-municipalities linking to the sem_assessor list; leaders get two with contacts wired to the shared route constant.
Unifies Salvador vs RMS subgroup logic for territory rollups, aggregate class slugs, and the intra-TI capture benchmark so the MAUP-sensitive rule cannot drift across call sites.