{
  "schemaVersion": 1,
  "sourceRevision": "a41c00a0c0b2dbd57c238cd9b326b167a1d27ca8",
  "purpose": "Retain completed v4 publication receipt independently of next-development and preserve immutable binary publication assets. Scope publication checks to governed Paper repositories without changing generic report lifecycle contracts.",
  "facades": [
    {
      "workflow": ".github/workflows/.release-binary-assets.yml",
      "beforeSha256": "5dfaea0f9cf83500706f423eca08f43594fe3653fa139da359041e88fae49266",
      "afterSha256": "06831b3ec8db28fbf96ffa8907fd58c1a77dd09e8d4fe02100a98febe10dba34",
      "replacements": [
        {
          "before": "          fs.writeFileSync(\".buildchain/publication-authority/capability.json\", `${JSON.stringify(capability, null, 2)}\\n`);\n          NODE\n\n      - name: Upload GitHub Release assets\n        env:\n          GH_TOKEN: ${{ github.token }}\n          RELEASE_TAG: ${{ inputs.release-tag }}\n",
          "after": "          fs.writeFileSync(\".buildchain/publication-authority/capability.json\", `${JSON.stringify(capability, null, 2)}\\n`);\n          NODE\n\n      - uses: actions/setup-node@v6.4.0\n        if: ${{ startsWith(inputs.release-tag, 'v4.') }}\n        with:\n          node-version: \"24\"\n\n      - name: Install exact publication runtime dependencies\n        if: ${{ startsWith(inputs.release-tag, 'v4.') }}\n        run: corepack pnpm@11.7.0 install --frozen-lockfile --ignore-scripts\n\n      - name: Upload immutable GitHub Release assets and verify readback\n        if: ${{ startsWith(inputs.release-tag, 'v4.') }}\n        env:\n          GH_TOKEN: ${{ github.token }}\n          RELEASE_TAG: ${{ inputs.release-tag }}\n        run: node packages/core/publication/commands/binary-publication-evidence.mjs publish\n\n      - name: Retain binary publication readback\n        if: ${{ startsWith(inputs.release-tag, 'v4.') }}\n        uses: actions/upload-artifact@v7.0.1\n        with:\n          name: binary-publication-readback-${{ inputs.release-tag }}\n          path: .buildchain/binary-publication/readback.json\n          include-hidden-files: true\n          if-no-files-found: error\n\n      - name: Upload GitHub Release assets\n        if: ${{ !startsWith(inputs.release-tag, 'v4.') }}\n        env:\n          GH_TOKEN: ${{ github.token }}\n          RELEASE_TAG: ${{ inputs.release-tag }}\n"
        }
      ]
    },
    {
      "workflow": ".github/workflows/.release-promote.yml",
      "beforeSha256": "177b3c50685405e5ed2bf1ac893469fdb3a27e7b03d55025611b2985028cd8cf",
      "afterSha256": "9c7f3586a3444cdad34d2a61be3cb9b0ae271fb56f9e371d9c37940e6b317780",
      "replacements": [
        {
          "before": "      release-candidate-artifact: ${{ needs.qualify.outputs.candidate-artifact }}\n      release-candidate-action: canonical-release-invocation\n      release-candidate-outcome: success\n      promotion-outcome: success\n      finalization-needed: \"false\"\n      release-tail-transaction-state: ${{ steps.provider.outputs.transaction-state || steps.resume.outputs.transaction-state }}\n      release-tail-declaration-root: ${{ steps.provider.outputs.declaration-root || steps.resume.outputs.declaration-root }}\n      release-tail-transaction-root: ${{ steps.provider.outputs.transaction-root || steps.resume.outputs.transaction-root }}\n",
          "after": "      release-candidate-artifact: ${{ needs.qualify.outputs.candidate-artifact }}\n      release-candidate-action: canonical-release-invocation\n      release-candidate-outcome: success\n      promotion-outcome: ${{ steps.publication-settlement.outputs.status == 'complete' && 'success' || 'failure' }}\n      finalization-needed: ${{ steps.publication-settlement.outputs.status != 'complete' }}\n      release-tail-transaction-state: ${{ steps.provider.outputs.transaction-state || steps.resume.outputs.transaction-state }}\n      release-tail-declaration-root: ${{ steps.provider.outputs.declaration-root || steps.resume.outputs.declaration-root }}\n      release-tail-transaction-root: ${{ steps.provider.outputs.transaction-root || steps.resume.outputs.transaction-root }}\n"
        },
        {
          "before": "      release-tail-receipt-roots-json: ${{ steps.provider.outputs.receipt-roots-json || steps.resume.outputs.receipt-roots-json }}\n      release-invocation-root: ${{ steps.provider.outputs.release-invocation-root || steps.resume.outputs.release-invocation-root }}\n      release-transaction-root: ${{ steps.provider.outputs.release-transaction-root || steps.resume.outputs.release-transaction-root }}\n      release-receipt-root: ${{ steps.provider.outputs.release-receipt-root || steps.resume.outputs.release-receipt-root }}\n    steps:\n      - name: Checkout the admitted protected channel state\n        uses: actions/checkout@v7.0.0\n",
          "after": "      release-tail-receipt-roots-json: ${{ steps.provider.outputs.receipt-roots-json || steps.resume.outputs.receipt-roots-json }}\n      release-invocation-root: ${{ steps.provider.outputs.release-invocation-root || steps.resume.outputs.release-invocation-root }}\n      release-transaction-root: ${{ steps.provider.outputs.release-transaction-root || steps.resume.outputs.release-transaction-root }}\n      release-receipt-root: ${{ steps.publication-settlement.outputs.receipt-root || steps.provider.outputs.release-receipt-root || steps.resume.outputs.release-receipt-root }}\n    steps:\n      - name: Checkout the admitted protected channel state\n        uses: actions/checkout@v7.0.0\n"
        },
        {
          "before": "        uses: ./.buildchain/runtime/actions/v4-release-candidate-promote\n        with: *provider-inputs\n\n      - name: Retain canonical APPLY and ReleaseReceipt evidence\n        if: ${{ always() }}\n        uses: actions/upload-artifact@v7.0.1\n",
          "after": "        uses: ./.buildchain/runtime/actions/v4-release-candidate-promote\n        with: *provider-inputs\n\n      - name: Retain completed publication independently of next-development\n        id: publication-settlement\n        if: ${{ always() && hashFiles('.buildchain/release-tail/release-receipt.json') != '' }}\n        env:\n          GH_TOKEN: ${{ github.token }}\n          CANDIDATE_SHA: ${{ needs.qualify.outputs.requested-sha }}\n          APPLY_OUTCOME: ${{ (steps.resume.outcome == 'success' || steps.resume.outcome == 'failure') && steps.resume.outcome || steps.provider.outcome }}\n        run: node .buildchain/runtime/scripts/v4-publication-settlement.mjs .buildchain\n\n      - name: Retain canonical APPLY and ReleaseReceipt evidence\n        if: ${{ always() }}\n        uses: actions/upload-artifact@v7.0.1\n"
        },
        {
          "before": "      controller-receipt-status: ${{ steps.verify.outputs.status || steps.projection-state.outputs.status }}\n    steps:\n      - name: Checkout the admitted receipt verifier\n        if: ${{ needs.apply.result == 'success' }}\n        uses: actions/checkout@v7.0.0\n        with:\n          repository: kungfu-systems/buildchain\n",
          "after": "      controller-receipt-status: ${{ steps.verify.outputs.status || steps.projection-state.outputs.status }}\n    steps:\n      - name: Checkout the admitted receipt verifier\n        if: ${{ needs.qualify.outputs.action == 'promote' && !inputs.dry-run }}\n        uses: actions/checkout@v7.0.0\n        with:\n          repository: kungfu-systems/buildchain\n"
        },
        {
          "before": "          persist-credentials: false\n\n      - name: Restore canonical APPLY evidence\n        if: ${{ needs.apply.result == 'success' }}\n        uses: actions/download-artifact@v7.0.0\n        with:\n          name: buildchain-v4-release-apply-${{ needs.qualify.outputs.requested-sha }}\n",
          "after": "          persist-credentials: false\n\n      - name: Restore canonical APPLY evidence\n        if: ${{ needs.qualify.outputs.action == 'promote' && !inputs.dry-run }}\n        uses: actions/download-artifact@v7.0.0\n        with:\n          name: buildchain-v4-release-apply-${{ needs.qualify.outputs.requested-sha }}\n"
        },
        {
          "before": "\n      - name: Verify the single terminal receipt\n        id: verify\n        if: ${{ needs.apply.result == 'success' }}\n        shell: bash\n        run: |\n          node --input-type=module <<'NODE'\n          import fs from \"node:fs\";\n          import {\n            createV4ReleaseInvocation,\n            createV4ReleaseReceipt,\n            createV4ReleaseTransaction,\n          } from \"./.buildchain/runtime/packages/core/v4-release-invocation.js\";\n          const base = \".buildchain/evidence/release-tail\";\n          const invocation = JSON.parse(fs.readFileSync(`${base}/release-invocation.json`, \"utf8\"));\n          const transaction = JSON.parse(fs.readFileSync(`${base}/release-transaction.json`, \"utf8\"));\n          const storedReceipt = JSON.parse(fs.readFileSync(`${base}/release-receipt.json`, \"utf8\"));\n          const invocationProjection = createV4ReleaseInvocation(invocation);\n          const transactionProjection = createV4ReleaseTransaction({\n            invocationRoot: transaction.invocationRoot,\n            publisherRoot: transaction.publisherRoot,\n            runtimeRoot: transaction.runtimeRoot,\n            providerRoot: transaction.providerRoot,\n            parentRoot: transaction.parentRoot,\n          });\n          const { receiptRoot, ...receipt } = storedReceipt;\n          const receiptProjection = createV4ReleaseReceipt(receipt);\n          if (transaction.invocationRoot !== invocationProjection.roots.invocationRoot ||\n              transaction.transactionRoot !== transactionProjection.transactionRoot ||\n              receipt.transactionRoot !== transactionProjection.transactionRoot ||\n              receiptProjection.receiptRoot !== receiptRoot || receipt.outcome !== \"complete\") {\n            throw new Error(\"terminal ReleaseReceipt lineage does not verify\");\n          }\n          fs.appendFileSync(process.env.GITHUB_OUTPUT,\n            `receipt-json=${JSON.stringify(storedReceipt)}\\nreceipt-root=${receiptRoot}\\nstatus=complete\\n`);\n          NODE\n\n      - name: Record non-terminal projection state\n        id: projection-state\n        if: ${{ needs.apply.result != 'success' }}\n        shell: bash\n        run: |\n          echo \"status=${{ inputs.dry-run && 'dry-run' || needs.qualify.outputs.action == 'noop' && 'noop' || 'blocked' }}\" >> \"$GITHUB_OUTPUT\"\n",
          "after": "\n      - name: Verify the single terminal receipt\n        id: verify\n        env:\n          CANDIDATE_SHA: ${{ needs.qualify.outputs.requested-sha }}\n        if: ${{ needs.qualify.outputs.action == 'promote' && !inputs.dry-run }}\n        shell: bash\n        run: |\n          node --input-type=module <<'NODE'\n          import fs from \"node:fs\";\n          const { readApplyDocuments, verifyPublicationSettlement } = await import(\"./.buildchain/runtime/scripts/v4-publication-settlement.mjs\");\n          const documents = readApplyDocuments(\".buildchain/evidence\");\n          verifyPublicationSettlement(documents, {\n            repository: process.env.GITHUB_REPOSITORY,\n            candidateSha: process.env.CANDIDATE_SHA,\n            tag: documents.invocation.target.tag,\n            sourceSha: documents.product.publication.releaseSha,\n          });\n          const storedReceipt = documents.receipt;\n          const receiptRoot = storedReceipt.receiptRoot;\n          fs.appendFileSync(process.env.GITHUB_OUTPUT,\n            `receipt-json=${JSON.stringify(storedReceipt)}\\nreceipt-root=${receiptRoot}\\nstatus=complete\\n`);\n          NODE\n\n      - name: Record non-terminal projection state\n        id: projection-state\n        if: ${{ always() && steps.verify.outcome != 'success' }}\n        shell: bash\n        run: |\n          echo \"status=${{ inputs.dry-run && 'dry-run' || needs.qualify.outputs.action == 'noop' && 'noop' || 'blocked' }}\" >> \"$GITHUB_OUTPUT\"\n"
        },
        {
          "before": "            .buildchain/evidence/release-tail/release-invocation.json\n            .buildchain/evidence/release-tail/release-transaction.json\n            .buildchain/evidence/release-tail/release-receipt.json\n          if-no-files-found: error\n",
          "after": "            .buildchain/evidence/release-tail/release-invocation.json\n            .buildchain/evidence/release-tail/release-transaction.json\n            .buildchain/evidence/release-tail/release-receipt.json\n            .buildchain/evidence/release-tail/delivery-summary.json\n            .buildchain/evidence/release-tail/buildchain-publication-settlement.json\n          if-no-files-found: error\n"
        }
      ]
    },
    {
      "workflow": ".github/workflows/public-build-check.yml",
      "beforeSha256": "44797c1b64e54806e19cf401300a27e587d6a2f0730ee7509eb84aefb9b60f74",
      "afterSha256": "fbf3549e4f4987733f53ff362bf49d2001d56ae5842bbd1ed343c0fba40d9429",
      "replacements": [
        {
          "before": "          config=\"${BUILDCHAIN_WORKING_DIRECTORY}/.buildchain/buildchain.toml\"\n          if [ -f \"$config\" ] && grep -Eq '^[[:space:]]*type[[:space:]]*=[[:space:]]*\"publication-artifact\"[[:space:]]*$' \"$config\"; then\n            node .buildchain/runtime/bin/buildchain.mjs paper preflight \\\n              --cwd \"$BUILDCHAIN_WORKING_DIRECTORY\" \\\n              --offline \\\n              --ci \\\n              --json\n          else\n            echo \"Buildchain Paper policy: not applicable\"\n          fi\n",
          "after": "          node --input-type=module <<'NODE'\n          import fs from \"node:fs\";\n          import path from \"node:path\";\n          import { loadBuildchainConfig } from \"./.buildchain/runtime/packages/core/consumer/buildchain-config.js\";\n          import { spawnSyncCommand } from \"./.buildchain/runtime/packages/core/runtime/spawn-command.js\";\n          const cwd = path.resolve(process.env.BUILDCHAIN_WORKING_DIRECTORY || \".\");\n          // Validate before deciding applicability; malformed config never skips policy.\n          const config = loadBuildchainConfig(cwd)?.config;\n          const governedPaper = fs.existsSync(path.join(cwd, \".buildchain/paper\"))\n            || config?.publish?.kind === \"npm-paper-package\"\n            || (config?.project?.type === \"publication-artifact\"\n              && (!config.publication || config.publication.kind === \"paper\"));\n          if (governedPaper) {\n            const result = spawnSyncCommand(process.execPath, [\n              \".buildchain/runtime/bin/buildchain.mjs\", \"paper\", \"preflight\",\n              \"--cwd\", cwd, \"--offline\", \"--ci\", \"--json\",\n            ], { stdio: \"inherit\" });\n            if (result.error) throw result.error;\n            process.exitCode = result.status ?? 1;\n          } else {\n            console.log(\"Buildchain Paper policy: not applicable\");\n          }\n          NODE\n"
        }
      ]
    }
  ]
}
