feat/sites-1n
needs attentionviewing older commit83fd5a0 · incrementalpre-PRreviewed 2026-07-08 01:37 UTC3H · 8M · 11L · 13I- Purpose
- Stop incorrectly fused RPU sites from the legacy name-based dedup bug (feat/sites-1n) and un-merge existing data — 379 sites holding 1,583 unrelated RPUs.
- Goal
- Make the Site ↔ RPU relationship correct (1:N deliberate, not legacy-automatic) so users can manage it via the new UX.
- Sub-goals
- SG-1: Shared site-resolution decision + rewire both coordinators
- SG-2: Site match/search endpoint
- SG-3: Wizard accepts existingSitePublicId
- SG-4: Drawer with Crear/Usar-existente picker
- SG-5: Site cell pencil → SiteEditModal
- SG-6: Agrupar por sitio toggle
- SG-7: Batch preview grouping
- SG-8: Analytics events + i18n
- What
- Added scripts/split-merged-sites.ts (one-shot remediation for 379 multi-RPU sites); expanded design doc §6 with full prod runbook; updated scope.md to clarify script is authored here but executed post-merge.
- Why
- The code fix (SG-1) stops new merges; this script un-merges existing data before users start creating deliberate groups with the new UX — must run once immediately post-merge.
- Areas
- scripts+271−0docs+324−0apps/platform+1211−173domains/cross-domain+447−131domains/core+33−1domains/utility+61−5packages/analytics+45−0packages/api+18−2.github+31−0
- Blast
- 26 files, +2532/-418 cumulative; this increment: scripts/ + docs/. Prod impact: 379 sites / 1,583 RPUs → ~1,204 new 1:1 sites. Category D orgs (26 sites) need heads-up.
Findings · 15
correctness8
Source sites row not locked during INSERT SELECT — concurrent update race window
scripts/split-merged-sites.ts:163
SUC rows are locked with FOR UPDATE OF suc, but the sites sub-SELECT is unlocked. A concurrent lifecycle/metadata update could commit between lock acquisition and INSERT, causing the new site to be created with stale data.
Source site version not bumped after losing N-1 SUC links
scripts/split-merged-sites.ts:200
SUC version is bumped but sites.version on the source is not. Any shell using OCC on sites will not detect this structural change.
site_locations UNION ALL / LIMIT 1 may silently drop rows for multi-location sources
scripts/split-merged-sites.ts:183
LIMIT 1 applies to the entire UNION result. If source site has multiple site_locations rows, LIMIT 1 picks only one.
Dry-run plan 'keeps rpus[0]' uses contract_number sort — execution uses created_at
scripts/split-merged-sites.ts:234
Plan log can say 'keeps RPU X' while execution keeps RPU Y, undermining pre-run audit.
metric_streams rows not re-pointed to split-off sites
scripts/split-merged-sites.ts:140
Script copies assignees and locations but is silent on metric_streams (may FK to site_id).
Post-verification bounded by --limit — OK message misleading for partial runs
scripts/split-merged-sites.ts:258
findSuspiciousSites reused for verification includes the LIMIT. Drop LIMIT for the verification call.
Failed site IDs not accumulated and re-printed in summary
scripts/split-merged-sites.ts:251
catch block logs and continues. Post-verify shows remaining multi-RPU sites but doesn't list which sites specifically failed.
argValue does not guard against flag-as-value (--org --execute)
scripts/split-merged-sites.ts:79
argValue('--org') returns '--execute' if the user writes --org --execute.
security3
CLI filter values logged to stdout — multi-tenant audit concern
scripts/split-merged-sites.ts:214
ORG_FILTER/SITE_FILTER echoed in console.log. If logs ship to a shared sink, this correlates org public IDs with split activity.
site_assignees copy lacks explicit org_id guard
scripts/split-merged-sites.ts:194
No explicit WHERE m.org_id = s.org_id guard. Defense-in-depth against hypothetical data corruption.
--limit NaN coercion silently drops LIMIT clause
scripts/split-merged-sites.ts:84
Number('foo') is NaN; NaN is falsy so LIMIT drops silently. With --execute this processes far more sites than intended.
conventions1
Duplicate step 5 in prod runbook — verify step hidden
docs/development/site-contract-relationship.md:229
Runbook has two items labeled '5.' The verify step should be step 6.
tests3
splitSite() has no integration test for transaction invariants
scripts/split-merged-sites.ts:140
For a script that will mutate ~1,583 prod rows, at least one integration test against a fixture would verify the transaction before --execute on prod.
categoryOf() has no unit test
scripts/split-merged-sites.ts:101
Pure 4-case function. A 4-assertion unit test eliminates any transcription error.
Dry-run does not exercise the INSERT/UPDATE path
scripts/split-merged-sites.ts:238
Dry-run exits before splitSite(). A staging pilot (--limit 1 --execute on a Supabase branch) would give stronger confidence.
History · 8 commits
- 7b5ff24needs attentionincremental0H · 2M · 3L2026-07-09 00:58
- 6231fe5needs attentionincremental0H · 2M · 4L2026-07-08 22:34
- 8fa38b5needs attentionincremental2H · 4M · 5L2026-07-08 01:45
- 83fd5a0needs attentionincremental3H · 8M · 11L2026-07-08 01:37current
- 23c04fcneeds attentionincremental3H · 3M · 2L2026-07-07 20:30
- e70f9f5blockedincremental6H · 11M · 6L2026-07-07 19:28
- 499b1a5blockedincremental6H · 9M · 5L2026-07-07 18:26
- ff23301needs attentionincremental2H · 6M · 5L2026-07-07 01:05