{
  "schema": "pg36-ch29-migration-contract-v1",
  "hypothesis": "A logical migration is acceptable only when initial copy, incremental catch-up, slot retention, conflict handling, semantic reconciliation, sequence synchronization, cutover fencing, rollback, and exact cleanup are independently evidenced.",
  "state_machine": [
    "preflight",
    "source-built",
    "target-schema-built",
    "initial-copy",
    "incremental-catch-up",
    "consumer-stalled",
    "consumer-recovered",
    "conflict-observed",
    "conflict-repaired",
    "silent-drift-detected",
    "silent-drift-repaired",
    "source-write-fenced",
    "target-sequence-synchronized",
    "simulated-cutover",
    "simulated-rollback",
    "exact-cleanup"
  ],
  "allowed_mutations": [
    "create marker-bound disposable databases and roles on pg-test and pg-meta",
    "create chapter-owned schemas, tables, publication, subscription, and slot",
    "copy and mutate synthetic fixture rows",
    "disable and enable the exact chapter subscription",
    "generate bounded WAL while the exact chapter slot is inactive",
    "inject and repair one exact subscriber insert conflict",
    "inject and repair one exact target-only row drift",
    "revoke and restore DML on the exact source runtime role",
    "synchronize the exact target identity sequence after source fencing",
    "switch a private evidence route file without changing Pigsty routing",
    "write and remove one synthetic target-only cutover canary",
    "ordinary-drop exact marker-bound subscription, slot, databases, and roles"
  ],
  "forbidden_mutations": [
    "ALTER SYSTEM",
    "edit Pigsty inventory",
    "edit Patroni dynamic configuration",
    "reload or restart PostgreSQL",
    "change HAProxy, PgBouncer, DNS, VIP, or application routes",
    "touch production data or traffic",
    "disable an unrelated subscription",
    "drop an unrelated replication slot",
    "terminate an unrelated session",
    "DROP DATABASE FORCE",
    "leave source writes enabled during simulated cutover",
    "drop the source before the rollback observation closes",
    "publish a connection string or fixture password"
  ],
  "evidence": {
    "raw_private": true,
    "public_summary_allowlist": true,
    "source_hash_binding": true,
    "two_cluster_identity": true,
    "logical_manifests": true,
    "bucket_digests": true,
    "slot_lsn_samples": true,
    "conflict_statistics": true,
    "route_history": true,
    "remote_temp_cleanup": true,
    "fixture_cleanup": true
  }
}
