Commit Graph
8 Commits
Author SHA1 Message Date
Gustavo e11658b4e0 Correct misleading comment about the candidates derived-subquery rationale
Review found the comment claimed a per-row precomputation optimization
that SQLite does not actually perform: the reviewer counted replace()
opcodes in the compiled bytecode and got an identical count (305) for
both the inline and derived-subquery forms of the query, since SQLite
flattens the subquery and re-substitutes the expression text at each
usage site either way. Rewrote the comment to describe the derived
subquery as what it actually is (a readability device), and to state
plainly that the perf investigation did not conclusively isolate the
rare timing outliers to this SQL's shape.
2026-07-31 12:06:25 -03:00
Gustavo e9f585458f Fix perf flakiness in shared-number candidate query by precomputing lead numbers once
The candidate query's lead_number/lead_equivalent forms were being
re-embedded as raw SQL expression text at every usage site (verification
join, opt-out check, shared-number check, inbound-replies check). Each
embedding re-evaluates the same deeply nested replace()/substr()/length()
chain per row; adding the shared-number check as a 5th usage site made
this measurably worse, especially in the worst case where a segment has
zero pre-verified numbers and the scan can't terminate early via LIMIT
(confirmed via reconstructing the pre-Task-3 query on an identical
fixture: that scenario already cost ~3.4s before this feature, and the
5th usage site pushed it to 4.1-9.5s with real variance, including an
outright failure over 5 consecutive runs).

Restructured candidateQuery to compute lead_number/lead_equivalent once
per row in a derived subquery (aliased `candidates`), referenced by
column everywhere else instead of re-embedding the expression text.
SQLite still flattens/uses idx_leads_campaign_order for the segmento
scan and sort (verified via EXPLAIN QUERY PLAN), so the common fast path
is unaffected (~2ms), while the worst-case path dropped to a consistent
~3-5s across 5 consecutive runs of the 1.3M-row perf test.
2026-07-31 11:52:48 -03:00
Gustavo d85fb12991 Exclude leads sharing a WhatsApp number from the automatic campaign queue
candidateQuery now blocks a lead whose WhatsApp number is shared by 2+
leads, unless a shared-number override exists. The inner correlated
subquery compares the bare other.whatsapp column (not normalizedSql())
against the outer row's two computed number forms so SQLite can use
idx_leads_whatsapp instead of a full table scan, keeping the 1.3M-row
perf test within budget.

Also updates the pre-existing 'persiste erro temporario e nao repete
equivalente' test: its two leads use 8/9-digit equivalent numbers,
which the new filter now blocks by default, so an override is added
to keep exercising the intended equivalent-number dedup behavior.
2026-07-31 11:18:41 -03:00
GustavoandClaude Sonnet 5 3d2144eefc Block manual send reservation for unreleased shared numbers
Implement shared-number detection in reserveOutreachSend: reject manual WhatsApp sends with HTTP 409 when the destination number is shared across 2+ leads and hasn't been explicitly released via override.

- Add test: reserveOutreachSend bloqueia numero compartilhado sem override e libera com override
- Add check in reserveOutreachSend right after isOptedOut check
- Uses isNumberSharedAcrossLeads and isSharedNumberOverridden from Task 1

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 11:11:54 -03:00
GustavoandClaude Sonnet 5 40bd8d096e Fix v15 migration test to drop v19 table before replaying migrations
The v15 test pattern (delete migration records >= 15, drop schema, reopen to replay)
was failing because outreach_shared_number_overrides table from v19 migration was not
dropped before replaying. Add DROP TABLE IF EXISTS to the schema cleanup block to
match the same fix applied to v17 test.

This resolves the 'table already exists' error during v19 migration replay.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 11:04:22 -03:00
GustavoandClaude Sonnet 5 fe70436dbb Add shared-number detection and override data layer
- Add migration v19: creates outreach_shared_number_overrides table
- Implement 7 new data-layer functions:
  - leadsSharingNumber: find leads sharing a phone number variant
  - isNumberSharedAcrossLeads: detect if number is shared by 2+ leads
  - getSharedNumberOverride: retrieve override entry for a number
  - isSharedNumberOverridden: check if number has an override
  - addSharedNumberOverride: create or update override with reason
  - removeSharedNumberOverride: delete override record
  - listSharedNumberGroups: group leads by shared numbers, reflect override state
- Add 4 comprehensive tests covering migration, detection, override crud, and grouping
- Update version assertions from 18 to 19
- Fix v17 migration test to properly clean up v19 table for schema reset

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 10:59:29 -03:00
Gustavo d330bb5ff0 Baseline commit of the existing Maquina Comercial Pessoal project
Tracks the app that was already in place (capture, treatment, outreach,
WhatsApp integration, server, frontend, tests, docs) so future feature
work can branch and use isolated worktrees.
2026-07-31 10:54:07 -03:00
Gustavo 6cd336a41e Add design spec for shared-number detection in outreach
Detects when a WhatsApp number is shared by multiple leads (e.g. an
accountant's phone reused across client CNPJs) and blocks automatic
and manual outreach to all of them until an operator reviews and
releases the number.
2026-07-31 10:36:02 -03:00