{
  "schemaVersion": 1,
  "tool": {
    "name": "skewcheck",
    "version": "0.1.0"
  },
  "executionId": "example-G-defective-repair",
  "project": "fixture/G-defective-repair",
  "createdAt": "2026-10-24T18:30:03.210Z",
  "baselineRevision": "shop-v1",
  "candidateRevision": "G-defective-repair",
  "database": {
    "serverVersion": "16.15 (Debian 16.15-1.pgdg12+2)"
  },
  "proposedMigrations": [
    "002_rename_email.sql"
  ],
  "experiment": [
    "control: old application (shop-v1) × baseline schema (1 migrations)",
    "candidate ×2: old application (shop-v1) × proposed schema (2 migrations)",
    "context: current application (G-defective-repair) × proposed schema"
  ],
  "verdict": "UNSAFE",
  "blocking": true,
  "exitCode": 1,
  "summary": "The previous application version reproducibly fails against the proposed schema, and the failure is linked to a specific schema change.",
  "reasons": [
    "test/customers.test.js: SQLSTATE 23502 (not_null_violation) linked to column_added:customers.email_address by R3 not_null_violation ↔ new NOT NULL requirement.",
    "test/orders.test.js: SQLSTATE 23502 (not_null_violation) linked to column_added:customers.email_address by R3 not_null_violation ↔ new NOT NULL requirement."
  ],
  "recommendedAction": "Make the migration backward compatible (expand/contract: keep the old shape until the old version is retired), then re-run the gate.",
  "complete": true,
  "findings": [
    {
      "kind": "regression",
      "test": "test/customers.test.js",
      "facts": [
        "test/customers.test.js passes on the baseline schema and fails in all 2 candidate runs.",
        "New in every candidate run, absent from the control run: SQLSTATE 23502 (not_null_violation): null value in column \"email_address\" of relation \"customers\" violates not-null constraint — statement: INSERT INTO customers (name, email) VALUES ($1, $2) RETURNING id"
      ],
      "interpretation": "Column customers.email_address now requires a value that the old application's statement does not supply.",
      "sqlstate": "23502",
      "changeIds": [
        "column_added:customers.email_address"
      ],
      "rule": "R3 not_null_violation ↔ new NOT NULL requirement",
      "strength": "strong",
      "error": {
        "run": "cand1",
        "test": "test/customers.test.js",
        "sqlstate": "23502",
        "message": "null value in column \"email_address\" of relation \"customers\" violates not-null constraint",
        "detail": "Failing row contains (1, Ada, ada@example.test, null, 2026-10-24 18:30:02.57425+00, null).",
        "statement": "INSERT INTO customers (name, email) VALUES ($1, $2) RETURNING id",
        "fingerprint": "insert into customers ( name , email ) values ( ? ) returning id",
        "key": "23502|null value in column \"email_address\" of relation \"customers\" violates not-null constraint|insert into customers ( name , email ) values ( ? ) returning id",
        "severity": "ERROR",
        "objects": {
          "column": "email_address",
          "relation": "customers"
        }
      }
    },
    {
      "kind": "regression",
      "test": "test/orders.test.js",
      "facts": [
        "test/orders.test.js passes on the baseline schema and fails in all 2 candidate runs.",
        "New in every candidate run, absent from the control run: SQLSTATE 23502 (not_null_violation): null value in column \"email_address\" of relation \"customers\" violates not-null constraint — statement: INSERT INTO customers (name, email) VALUES ($1, $2) RETURNING id"
      ],
      "interpretation": "Column customers.email_address now requires a value that the old application's statement does not supply.",
      "sqlstate": "23502",
      "changeIds": [
        "column_added:customers.email_address"
      ],
      "rule": "R3 not_null_violation ↔ new NOT NULL requirement",
      "strength": "strong",
      "error": {
        "run": "cand1",
        "test": "test/orders.test.js",
        "sqlstate": "23502",
        "message": "null value in column \"email_address\" of relation \"customers\" violates not-null constraint",
        "detail": "Failing row contains (2, Grace, grace@example.test, null, 2026-10-24 18:30:02.671564+00, null).",
        "statement": "INSERT INTO customers (name, email) VALUES ($1, $2) RETURNING id",
        "fingerprint": "insert into customers ( name , email ) values ( ? ) returning id",
        "key": "23502|null value in column \"email_address\" of relation \"customers\" violates not-null constraint|insert into customers ( name , email ) values ( ? ) returning id",
        "severity": "ERROR",
        "objects": {
          "column": "email_address",
          "relation": "customers"
        }
      }
    }
  ],
  "schemaChanges": [
    {
      "id": "column_added:customers.email_address",
      "kind": "column_added",
      "risk": "breaking",
      "schema": "public",
      "table": "customers",
      "column": "email_address",
      "after": "text NOT NULL",
      "exercisedBy": [
        "insert"
      ],
      "note": "NOT NULL without a default: inserts from the old application will omit it."
    }
  ],
  "coverage": [
    {
      "changeId": "column_added:customers.email_address",
      "target": "customers.email_address",
      "risk": "breaking",
      "required": true,
      "exercised": true,
      "statementCount": 2,
      "tests": [
        "test/customers.test.js",
        "test/orders.test.js"
      ],
      "staticReferences": [
        "src/admin.js:5",
        "src/customers.js:4",
        "src/customers.js:9",
        "test/customers.test.js:4",
        "test/orders.test.js:4"
      ]
    }
  ],
  "coverageSummary": "1 of 1 risk-bearing schema change(s) were exercised by the old application's tests in the control run.",
  "runs": [
    {
      "id": "ctl",
      "label": "control (old app × baseline schema)",
      "app": "baseline",
      "schema": "baseline",
      "database": "sc_ctl",
      "revision": "shop-v1",
      "completed": true,
      "migrations": [
        {
          "file": "001_init.sql",
          "ok": true
        }
      ],
      "tests": [
        {
          "test": "test/customers.test.js",
          "outcome": "pass",
          "exitCode": 0,
          "durationMs": 98,
          "outputTail": "TAP version 13\n# Subtest: signs up a customer and finds them by email\nok 1 - signs up a customer and finds them by email\n  ---\n  duration_ms: 10.546774\n  ...\n1..1\n# tests 1\n# suites 0\n# pass 1\n# fail 0\n# cancelled 0\n# skipped 0\n# todo 0\n# duration_ms 71.186076\n"
        },
        {
          "test": "test/orders.test.js",
          "outcome": "pass",
          "exitCode": 0,
          "durationMs": 100,
          "outputTail": "TAP version 13\n# Subtest: new orders start in status \"new\" and can be shipped\nok 1 - new orders start in status \"new\" and can be shipped\n  ---\n  duration_ms: 13.728736\n  ...\n1..1\n# tests 1\n# suites 0\n# pass 1\n# fail 0\n# cancelled 0\n# skipped 0\n# todo 0\n# duration_ms 73.274957\n"
        }
      ],
      "errors": [],
      "statements": 7
    },
    {
      "id": "cand1",
      "label": "candidate #1 (old app × proposed schema)",
      "app": "baseline",
      "schema": "candidate",
      "database": "sc_cand1",
      "revision": "shop-v1",
      "completed": true,
      "migrations": [
        {
          "file": "001_init.sql",
          "ok": true
        },
        {
          "file": "002_rename_email.sql",
          "ok": true
        }
      ],
      "tests": [
        {
          "test": "test/customers.test.js",
          "outcome": "fail",
          "exitCode": 1,
          "durationMs": 99,
          "outputTail": "TAP version 13\n# Subtest: signs up a customer and finds them by email\nnot ok 1 - signs up a customer and finds them by email\n  ---\n  duration_ms: 9.95291\n  location: '<app>/test/customers.test.js:8:1'\n  failureType: 'testCodeFailure'\n  error: 'null value in column \"email_address\" of relation \"customers\" violates not-null constraint'\n  code: '23502'\n  name: 'error'\n  stack: |-\n    <skewcheck>/node_modules/pg-pool/index.js:45:11\n    process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n    async createCustomer (<app>/src/customers.js:4:13)\n    async TestContext.<anonymous> (<app>/test/customers.test.js:9:14)\n    async Test.run (node:internal/test_runner/test:935:9)\n    async startSubtestAfterBootstrap (node:internal/test_runner/harness:296:3)\n  ...\n1..1\n# tests 1\n# suites 0\n# pass 0\n# fail 1\n# cancelled 0\n# skipped 0\n# todo 0\n# duration_ms 73.064371\n"
        },
        {
          "test": "test/orders.test.js",
          "outcome": "fail",
          "exitCode": 1,
          "durationMs": 96,
          "outputTail": "TAP version 13\n# Subtest: new orders start in status \"new\" and can be shipped\nnot ok 1 - new orders start in status \"new\" and can be shipped\n  ---\n  duration_ms: 9.564584\n  location: '<app>/test/orders.test.js:9:1'\n  failureType: 'testCodeFailure'\n  error: 'null value in column \"email_address\" of relation \"customers\" violates not-null constraint'\n  code: '23502'\n  name: 'error'\n  stack: |-\n    <skewcheck>/node_modules/pg-pool/index.js:45:11\n    process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n    async createCustomer (<app>/src/customers.js:4:13)\n    async TestContext.<anonymous> (<app>/test/orders.test.js:10:13)\n    async Test.run (node:internal/test_runner/test:935:9)\n    async startSubtestAfterBootstrap (node:internal/test_runner/harness:296:3)\n  ...\n1..1\n# tests 1\n# suites 0\n# pass 0\n# fail 1\n# cancelled 0\n# skipped 0\n# todo 0\n# duration_ms 69.217495\n"
        }
      ],
      "errors": [
        {
          "run": "cand1",
          "test": "test/customers.test.js",
          "sqlstate": "23502",
          "message": "null value in column \"email_address\" of relation \"customers\" violates not-null constraint",
          "detail": "Failing row contains (1, Ada, ada@example.test, null, 2026-10-24 18:30:02.57425+00, null).",
          "statement": "INSERT INTO customers (name, email) VALUES ($1, $2) RETURNING id",
          "fingerprint": "insert into customers ( name , email ) values ( ? ) returning id",
          "key": "23502|null value in column \"email_address\" of relation \"customers\" violates not-null constraint|insert into customers ( name , email ) values ( ? ) returning id",
          "severity": "ERROR",
          "objects": {
            "column": "email_address",
            "relation": "customers"
          }
        },
        {
          "run": "cand1",
          "test": "test/orders.test.js",
          "sqlstate": "23502",
          "message": "null value in column \"email_address\" of relation \"customers\" violates not-null constraint",
          "detail": "Failing row contains (2, Grace, grace@example.test, null, 2026-10-24 18:30:02.671564+00, null).",
          "statement": "INSERT INTO customers (name, email) VALUES ($1, $2) RETURNING id",
          "fingerprint": "insert into customers ( name , email ) values ( ? ) returning id",
          "key": "23502|null value in column \"email_address\" of relation \"customers\" violates not-null constraint|insert into customers ( name , email ) values ( ? ) returning id",
          "severity": "ERROR",
          "objects": {
            "column": "email_address",
            "relation": "customers"
          }
        }
      ],
      "statements": 2
    },
    {
      "id": "cand2",
      "label": "candidate #2 (old app × proposed schema)",
      "app": "baseline",
      "schema": "candidate",
      "database": "sc_cand2",
      "revision": "shop-v1",
      "completed": true,
      "migrations": [
        {
          "file": "001_init.sql",
          "ok": true
        },
        {
          "file": "002_rename_email.sql",
          "ok": true
        }
      ],
      "tests": [
        {
          "test": "test/customers.test.js",
          "outcome": "fail",
          "exitCode": 1,
          "durationMs": 95,
          "outputTail": "TAP version 13\n# Subtest: signs up a customer and finds them by email\nnot ok 1 - signs up a customer and finds them by email\n  ---\n  duration_ms: 9.600086\n  location: '<app>/test/customers.test.js:8:1'\n  failureType: 'testCodeFailure'\n  error: 'null value in column \"email_address\" of relation \"customers\" violates not-null constraint'\n  code: '23502'\n  name: 'error'\n  stack: |-\n    <skewcheck>/node_modules/pg-pool/index.js:45:11\n    process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n    async createCustomer (<app>/src/customers.js:4:13)\n    async TestContext.<anonymous> (<app>/test/customers.test.js:9:14)\n    async Test.run (node:internal/test_runner/test:935:9)\n    async startSubtestAfterBootstrap (node:internal/test_runner/harness:296:3)\n  ...\n1..1\n# tests 1\n# suites 0\n# pass 0\n# fail 1\n# cancelled 0\n# skipped 0\n# todo 0\n# duration_ms 68.904076\n"
        },
        {
          "test": "test/orders.test.js",
          "outcome": "fail",
          "exitCode": 1,
          "durationMs": 96,
          "outputTail": "TAP version 13\n# Subtest: new orders start in status \"new\" and can be shipped\nnot ok 1 - new orders start in status \"new\" and can be shipped\n  ---\n  duration_ms: 9.608882\n  location: '<app>/test/orders.test.js:9:1'\n  failureType: 'testCodeFailure'\n  error: 'null value in column \"email_address\" of relation \"customers\" violates not-null constraint'\n  code: '23502'\n  name: 'error'\n  stack: |-\n    <skewcheck>/node_modules/pg-pool/index.js:45:11\n    process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n    async createCustomer (<app>/src/customers.js:4:13)\n    async TestContext.<anonymous> (<app>/test/orders.test.js:10:13)\n    async Test.run (node:internal/test_runner/test:935:9)\n    async startSubtestAfterBootstrap (node:internal/test_runner/harness:296:3)\n  ...\n1..1\n# tests 1\n# suites 0\n# pass 0\n# fail 1\n# cancelled 0\n# skipped 0\n# todo 0\n# duration_ms 69.836464\n"
        }
      ],
      "errors": [
        {
          "run": "cand2",
          "test": "test/customers.test.js",
          "sqlstate": "23502",
          "message": "null value in column \"email_address\" of relation \"customers\" violates not-null constraint",
          "detail": "Failing row contains (1, Ada, ada@example.test, null, 2026-10-24 18:30:02.808516+00, null).",
          "statement": "INSERT INTO customers (name, email) VALUES ($1, $2) RETURNING id",
          "fingerprint": "insert into customers ( name , email ) values ( ? ) returning id",
          "key": "23502|null value in column \"email_address\" of relation \"customers\" violates not-null constraint|insert into customers ( name , email ) values ( ? ) returning id",
          "severity": "ERROR",
          "objects": {
            "column": "email_address",
            "relation": "customers"
          }
        },
        {
          "run": "cand2",
          "test": "test/orders.test.js",
          "sqlstate": "23502",
          "message": "null value in column \"email_address\" of relation \"customers\" violates not-null constraint",
          "detail": "Failing row contains (2, Grace, grace@example.test, null, 2026-10-24 18:30:02.90505+00, null).",
          "statement": "INSERT INTO customers (name, email) VALUES ($1, $2) RETURNING id",
          "fingerprint": "insert into customers ( name , email ) values ( ? ) returning id",
          "key": "23502|null value in column \"email_address\" of relation \"customers\" violates not-null constraint|insert into customers ( name , email ) values ( ? ) returning id",
          "severity": "ERROR",
          "objects": {
            "column": "email_address",
            "relation": "customers"
          }
        }
      ],
      "statements": 2
    },
    {
      "id": "cur",
      "label": "current app × proposed schema (context)",
      "app": "current",
      "schema": "candidate",
      "database": "sc_cur",
      "revision": "G-defective-repair",
      "completed": true,
      "migrations": [
        {
          "file": "001_init.sql",
          "ok": true
        },
        {
          "file": "002_rename_email.sql",
          "ok": true
        }
      ],
      "tests": [
        {
          "test": "test/customers.test.js",
          "outcome": "fail",
          "exitCode": 1,
          "durationMs": 99,
          "outputTail": "TAP version 13\n# Subtest: v2 signs up a customer and finds them by email_address\nnot ok 1 - v2 signs up a customer and finds them by email_address\n  ---\n  duration_ms: 9.593146\n  location: '<app>/test/customers.test.js:8:1'\n  failureType: 'testCodeFailure'\n  error: 'null value in column \"email\" of relation \"customers\" violates not-null constraint'\n  code: '23502'\n  name: 'error'\n  stack: |-\n    <skewcheck>/node_modules/pg-pool/index.js:45:11\n    process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n    async createCustomer (<app>/src/customers.js:5:13)\n    async TestContext.<anonymous> (<app>/test/customers.test.js:9:14)\n    async Test.run (node:internal/test_runner/test:935:9)\n    async startSubtestAfterBootstrap (node:internal/test_runner/harness:296:3)\n  ...\n1..1\n# tests 1\n# suites 0\n# pass 0\n# fail 1\n# cancelled 0\n# skipped 0\n# todo 0\n# duration_ms 72.383545\n"
        }
      ],
      "errors": [
        {
          "run": "cur",
          "test": "test/customers.test.js",
          "sqlstate": "23502",
          "message": "null value in column \"email\" of relation \"customers\" violates not-null constraint",
          "detail": "Failing row contains (1, Linus, null, null, 2026-10-24 18:30:03.034106+00, linus@example.test).",
          "statement": "INSERT INTO customers (name, email_address) VALUES ($1, $2) RETURNING id",
          "fingerprint": "insert into customers ( name , email_address ) values ( ? ) returning id",
          "key": "23502|null value in column \"email\" of relation \"customers\" violates not-null constraint|insert into customers ( name , email_address ) values ( ? ) returning id",
          "severity": "ERROR",
          "objects": {
            "column": "email",
            "relation": "customers"
          }
        }
      ],
      "statements": 1
    }
  ],
  "skippedChecks": [
    "Performance / lock-time analysis (out of scope)."
  ],
  "limitations": [
    "Skewcheck only observes code paths that the old application's tests execute; untested paths are reported as coverage gaps, not as safe.",
    "Coverage is identifier-level: a statement \"touches\" a changed object when it names the table (and column, or uses *). It is not a SQL parser.",
    "Correlation between an error and a schema change uses a fixed set of deterministic rules (R1–R6). Anything else is reported as ADVISORY, never UNSAFE.",
    "Performance, locking and migration runtime on production-sized data are not evaluated.",
    "Test files of one run share a database and run sequentially; ordering effects are identical across runs but are not isolated.",
    "Data-only migration effects are detected only when a test asserts on the affected data."
  ],
  "policy": {
    "advisory": "warn",
    "noEvidence": "block",
    "inconclusive": "block",
    "candidateRepeats": 2,
    "testTimeoutMs": 60000,
    "maxBaselineFailureRatio": 0.5,
    "protectedPaths": [],
    "repairBranchPrefixes": [
      "skewcheck-repair/"
    ]
  }
}