Deduplicate procedural_events with null.* synthetic codes — many true name-duplicates clutter /admin/procedural-events
#144
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Repro
https://paliad.de/admin/procedural-events shows ~20 procedural_events whose names appear 2-6 times each, all with different
null.<8hex>codes minted in mig 136 (B.1) per Q5/Q11 ratification. m: "this needs to be deduped".Worst offenders (sample, from
SELECT name, COUNT(*) FROM procedural_events WHERE code LIKE 'null.%' GROUP BY name HAVING COUNT(*) > 1 ORDER BY COUNT DESC):Root cause
The original
paliad.deadline_ruleshad 78 rows with NULLsubmission_code— cross-cutting orphan concepts (Wiedereinsetzung, Schriftsatznachreichung, etc.) that legitimately spanned multiple proceeding types or weren't bound to one. Mig 136's backfill minted a syntheticnull.<uuid8>code per row, preserving 1:1 mapping. But the same legal concept (e.g. "Mängelbeseitigung / Zahlung") was represented by multiple deadline_rules rows because each rule's anchor / proceeding context differed, even though the user-visible name was identical.Not all
null.*codes are duplicates — only those whosenamecollides. The bulk (~50/78) are unique names referring to genuinely distinct events.Fix
Scope
Migration 151 (or next free at write-time):
Audit-first DO block — for every
namewhosenull.*rows are >1, list the rows (id, name, sequencing_rules-pointing-here count, primary_party_default, concept_id) as aRAISE NOTICE. m can copy that output for the audit trail.Pick canonical per name — the row with the lowest
created_at(oridUUID alphabetic) wins as canonical. Stable, deterministic.Reparent sequencing_rules —
UPDATE sequencing_rules SET procedural_event_id = <canonical_id> WHERE procedural_event_id IN (<duplicate_ids>). Requiresset_config('paliad.audit_reason', 'mig 151: consolidate duplicate null.* procedural_events per m/paliad#144', true)if sequencing_rules carries the deadline_rules audit trigger (verify before mig).Archive duplicates —
UPDATE procedural_events SET is_active = false, lifecycle_state = 'archived', updated_at = now() WHERE id IN (<duplicate_ids>). Keeps the row + audit trail; just removes from UI.Post-check —
RAISE EXCEPTIONif anynamewhosenull.*rows still > 1 ANDis_active = trueANDlifecycle_state = 'published'survives.Hard requirements
mcp__supabase__execute_sql: confirmprocedural_events.updated_atexists (it does per the column list), confirmlifecycle_stateallows'archived'(it should), confirm there's no audit trigger on procedural_events that needsset_config.sequencing_rulesaudit trigger: verify whether mig 140's drop ofdeadline_rulescarried over the audit trigger tosequencing_rules. If yes, addset_config('paliad.audit_reason', ...)at the top.deadline_rules_unifiedview aren't fired by direct sequencing_rules writes (they only fire on view-targeted INSERT/UPDATE).Acceptance
nameinprocedural_eventshas exactly oneis_active=true AND lifecycle_state='published'row.SELECT name, COUNT(*) FROM procedural_events WHERE code LIKE 'null.%' AND is_active = true AND lifecycle_state = 'published' GROUP BY name HAVING COUNT(*) > 1returns 0 rows./admin/procedural-eventspage renders the consolidated list — visible row count drops from ~280+ to ~210 (estimated based on the ~20 collision groups × ~2-3 duplicates per group).sequencing_rulesrow is orphaned — every rule'sprocedural_event_idstill points at a non-archived procedural_event.Anti-patterns
procedural_eventsrows — archive them (is_active=false). Audit-trail safety.null.*rows — they're legitimate orphan concepts, not duplicates.Mig 152 + Proceeding column ready for merge (t-paliad-321)
Branch:
mai/curie/coder-mig152-clone-dedupefeat(db): mig 152 — dedupe identical sequencing_rule clones(4cd28bc)Follow-up to mig 151. The 6 "Mängelbeseitigung / Zahlung" sequencing_rules left active after mig 151 are byte-for-byte clones (proceeding_type_id=NULL, rule_code=NULL, duration 14d, primary_party=NULL). Mig 152 archives 5, keeps the lexicographically-lowest UUID as canonical.
RAISE NOTICEso deploy logs show what's about to be touched (m can spot-check).paliad.sequencing_rules_pre_152in same TX (precedent pre_091/093/095/098/140/151).paliad.deadlines.sequencing_rule_idduplicate → canonical BEFORE archive (live data: 0 affected; defensive).set_config('paliad.audit_reason', …)defensively — sequencing_rules has no audit trigger today (mig 151 §scope), but a future trigger inherits it.Other name-duplicates (Antrag auf Patentänderung×4, Beginn des Hauptsacheverfahrens×2, Berufungsbegründung-R.220.1×2, Berufungsschrift-R.220.1×2) do NOT collapse under the full-signature query — they have distinct (proceeding_type_id, rule_code, duration, primary_party) signatures and are legitimately different rules per proceeding. Mig 152 leaves them alone.
feat(admin): add proceeding-type column to /admin/procedural-events list(6acb116)Surfaces the 3-segment proceeding code (e.g.
upc.inf.cfi) at position 2 of the rule-editor list so the 4 legitimately-distinct same-named groups are visually disambiguated without opening each row.LoadProceedingTypeCodes(ctx, rows)on RuleEditorService — single batch SELECT frompaliad.proceeding_types, returns id → code map. No N+1.proceeding_type_codefield;wrapRuleListResponsepopulates it from the map.Verfahrenstypcolumn (showedcode · name, which duplicated the new content).admin.procedural_events.col.proceeding(DE: "Verfahren", EN: "Proceeding") + i18n-keys.ts union entry.Expected mig 152 outcome on apply: 5 archived. If the deploy log NOTICE shows additional groups, surface to m before merging.
Build + vet clean.
TestMigrations_NoDuplicateSlotpasses.