16ec8c490a9d58228b2fc887266ccca4db355be0
1 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| 75833082fc |
feat(db): mig 136 — additive procedural_events / sequencing_rules / legal_sources tables (Slice B.1, t-paliad-273 / m/paliad#93)
Creates the three new tables that split today's paliad.deadline_rules
into its three latent concepts, plus two nullable link columns on
paliad.deadlines for B.2 dual-write.
ADDITIVE ONLY. paliad.deadline_rules is untouched. deadlines.rule_id
stays in place — it remains the authoritative deadline → rule link
until B.3 cutover flips reads and B.4 drops the legacy table.
* paliad.legal_sources — distinct citations (87 rows backfilled).
pretty_de/pretty_en deferred (Go
legalSourcePretty still computes them
on read; future slice backfills).
* paliad.procedural_events — 153 rows from distinct submission_codes
+ 78 synthetic-code rows for the
NULL-submission_code branch (m's pick
via paliadin 2026-05-26: mint
'null.<8hex>' codes so every rule row
has a procedural event, preserving the
NOT NULL FK on sequencing_rules).
* paliad.sequencing_rules — 1:1 with deadline_rules (231 rows). id
inherited from deadline_rules.id so any
existing deadlines.rule_id FK resolves
transitively to the new sequencing_rule
during the dual-write window.
* paliad.deadlines.procedural_event_id, sequencing_rule_id (nullable,
backfilled by JOIN on the inherited id).
Audit-first pattern (mirrors mig 135): PRE pass counts what we're about
to backfill + refuses to run if multi-row submission_codes have crept
back in (B.0 found zero; the assertion guards against a future
re-archival or rule-editor bug). POST pass asserts the four
invariants — procedural_events count, sequencing_rules 1:1,
legal_sources distinct-citation match, FK integrity — and RAISE
EXCEPTIONs on any mismatch so the transaction rolls back cleanly.
Design deviations from §4.1 (documented in the migration header):
- procedural_events.event_kind is NULLABLE. 89 live rules have NULL
event_type today (structural / parent-only rows in the proceeding
tree). Tightening to NOT NULL with 'other' fallback would lose
semantics; a later slice can do it after reclassification.
- legal_sources.pretty_de / pretty_en are NULLABLE. Materialising them
requires the Go-side legalSourcePretty(); deferred to a Go-driven
slice. Read path keeps computing them from the citation in the
meantime.
- submission_drafts is NOT modified (instruction scope is explicit:
tables + deadlines columns only).
Down migration: drops the two deadlines columns first, then
sequencing_rules → procedural_events → legal_sources in FK-safe
order. No data loss possible (deadline_rules is the source of truth
through B.3).
Test: internal/db/migration_136_test.go restates the four
invariants in Go so they survive PL/pgSQL refactors. Skipped without
TEST_DATABASE_URL.
Verified on live (read-only): 153 distinct codes + 78 distinct
synthetic-code candidates = 231 = deadline_rules row count. 87
distinct legal_sources. Zero 8-hex synthetic-code collisions in the
live UUIDs.
Hard-stop: B.2 dual-write requires explicit m greenlight before
RuleEditorService starts writing to the new tables. B.4 destructive
drop additionally requires m's downtime window + a
paliad.deadline_rules_pre_<N> snapshot in the same migration.
|