20260723_150_rule_artifact_handoff_state.py 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. """Upgrade artifact handoff from old-140 rows to a durable state machine."""
  2. from alembic import op
  3. revision = "20260723_150"
  4. down_revision = "20260723_140"
  5. branch_labels = None
  6. depends_on = None
  7. def upgrade() -> None:
  8. op.execute(
  9. """
  10. ALTER TABLE public.rule_run_artifacts
  11. ADD COLUMN binding_hash CHAR(64),
  12. ADD COLUMN handoff_status VARCHAR(20) NOT NULL
  13. DEFAULT 'pending'
  14. CHECK (handoff_status IN ('pending','ready','failed')),
  15. ADD COLUMN ready_at TIMESTAMPTZ,
  16. ADD COLUMN failed_at TIMESTAMPTZ,
  17. ADD COLUMN failure_code VARCHAR(100),
  18. ADD COLUMN updated_at TIMESTAMPTZ NOT NULL
  19. DEFAULT CURRENT_TIMESTAMP;
  20. UPDATE public.rule_run_artifacts a
  21. SET binding_hash = (
  22. SELECT binding_hash
  23. FROM public.dataflow_dataset_bindings b
  24. WHERE b.id = a.binding_id
  25. ),
  26. handoff_status = 'ready',
  27. ready_at = a.created_at,
  28. updated_at = a.created_at;
  29. DO $$
  30. BEGIN
  31. IF EXISTS (
  32. SELECT 1
  33. FROM public.rule_run_artifacts
  34. WHERE binding_hash IS NULL
  35. ) THEN
  36. RAISE EXCEPTION
  37. 'artifact handoff migration found unattested bindings';
  38. END IF;
  39. IF EXISTS (
  40. SELECT 1
  41. FROM public.rule_run_artifacts
  42. GROUP BY correlation_id, binding_id, artifact_kind
  43. HAVING COUNT(*) > 1
  44. ) THEN
  45. RAISE EXCEPTION
  46. 'artifact handoff migration found conflicting old rows';
  47. END IF;
  48. END
  49. $$;
  50. ALTER TABLE public.rule_run_artifacts
  51. ALTER COLUMN binding_hash SET NOT NULL;
  52. DO $$
  53. DECLARE
  54. old_constraint TEXT;
  55. BEGIN
  56. SELECT c.conname
  57. INTO old_constraint
  58. FROM pg_constraint c
  59. WHERE c.conrelid = 'public.rule_run_artifacts'::regclass
  60. AND c.contype = 'u'
  61. AND pg_get_constraintdef(c.oid) =
  62. 'UNIQUE (correlation_id, binding_id, artifact_digest)';
  63. IF old_constraint IS NULL THEN
  64. RAISE EXCEPTION
  65. 'old-140 artifact uniqueness constraint was not found';
  66. END IF;
  67. EXECUTE format(
  68. 'ALTER TABLE public.rule_run_artifacts DROP CONSTRAINT %I',
  69. old_constraint
  70. );
  71. END
  72. $$;
  73. ALTER TABLE public.rule_run_artifacts
  74. ADD CONSTRAINT rule_run_artifacts_handoff_key
  75. UNIQUE (correlation_id, binding_id, artifact_kind);
  76. CREATE INDEX idx_rule_run_artifacts_reconcile
  77. ON public.rule_run_artifacts
  78. (handoff_status, updated_at, id);
  79. """
  80. )
  81. def downgrade() -> None:
  82. raise RuntimeError(
  83. "artifact handoff state is forward-only and cannot downgrade "
  84. "without violating durable publication evidence"
  85. )