# keripy-diff — nightly behavioral-parity check vs keripy.
#
# Regenerates the differential-test corpus from a PINNED keripy checkout and
# runs the in-crate diff harness against it. Unlike keripy-sync (which tracks
# the latest tag for code-table coverage), differential testing needs a FIXED
# oracle so a byte disagreement is unambiguous. A change to the regenerated
# corpus, or a harness failure, opens a PR for human review.
name: keripy-diff

on:
  schedule:
    # Nightly, 04:23 UTC (off-peak; fixed time for reproducibility).
    - cron: "23 4 * * *"
  workflow_dispatch:

permissions:
  contents: read

concurrency:
  group: keripy-diff
  cancel-in-progress: false

env:
  # The pinned keripy oracle. Bump deliberately (in lockstep with the corpus and
  # the pin recorded in docs/superpowers/specs/2026-07-01-p0.3-differential-testing-design.md).
  KERIPY_REF: v2.0.0.dev5

jobs:
  diff:
    name: Differential parity vs keripy
    runs-on: ubuntu-latest
    steps:
      - name: Checkout cesr
        uses: actions/checkout@v4

      - name: Clone keripy at the pinned tag
        run: |
          git clone --depth 1 --branch "${KERIPY_REF}" \
            https://github.com/WebOfTrust/keripy /tmp/keripy

      # keripy v2.0.0.dev5 requires Python >= 3.14.2.
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.14"

      # pysodium (a keripy dep) dlopen's the native libsodium shared library.
      - name: Install libsodium
        run: sudo apt-get update && sudo apt-get install -y libsodium23

      - name: Install keripy
        run: python -m pip install -e /tmp/keripy

      - name: Regenerate corpus
        run: |
          python scripts/keripy_diff_gen.py --keripy /tmp/keripy --out tests/corpus/keripy
          git --no-pager diff --stat -- tests/corpus/keripy || true

      - name: Install Nix
        uses: DeterminateSystems/nix-installer-action@main

      - name: Run differential harness against the fresh corpus
        run: nix develop --command cargo test --all-features keripy_diff -- --nocapture

      # An App-authored PR (vs the default GITHUB_TOKEN) lets the required
      # `Nix Flake Check` run on it, and sign-commits satisfies the signed-commits
      # branch rule. Reuses the release-plz App (as keripy-sync does).
      - name: Mint App token
        id: app-token
        uses: actions/create-github-app-token@v1
        with:
          app-id: ${{ secrets.RELEASE_PLZ_APP_ID }}
          private-key: ${{ secrets.RELEASE_PLZ_APP_PRIVATE_KEY }}

      - name: Open/update corpus-drift PR
        uses: peter-evans/create-pull-request@v7
        with:
          token: ${{ steps.app-token.outputs.token }}
          branch: keripy-diff/corpus
          base: main
          sign-commits: true
          commit-message: "test(diff): refresh keripy differential corpus"
          title: "test(diff): keripy differential corpus refresh"
          body: |
            Nightly **keripy-diff** regenerated the corpus from keripy `${{ env.KERIPY_REF }}`.

            A non-empty diff means keripy's output moved or the generator surfaced
            new coverage — review the vector delta before merging. If the harness
            step failed, a real cesr↔keripy disagreement exists: do **not** merge;
            file a bug and fix cesr (or `#[ignore]` the case with a tracking issue).
          labels: keripy-diff
          delete-branch: false
