florecon 0.7.0

Reconciliation as partitioning: parse a bag of entries into groups. A small combinator algebra over identity, with a min-cost-flow leaf.
Documentation
name: release

# Fires when you publish a GitHub Release. The tag (vX.Y.Z) must match the
# florecon version (enforced by the guard job). netsimplex carries its own
# version and is published first because florecon depends on it.
on:
  release:
    types: [published]

permissions:
  contents: read

jobs:
  guard:
    name: guard (tag == florecon version)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - name: tag matches Cargo.toml
        run: |
          tag="${{ github.event.release.tag_name }}"
          ver=$(grep -m1 '^version' Cargo.toml | sed -E 's/.*"([^"]+)".*/\1/')
          if [ "$tag" != "v$ver" ]; then
            echo "tag $tag != v$ver (florecon Cargo.toml)" >&2
            exit 1
          fi
          echo "✓ $tag == v$ver"

  ci:
    name: checks
    needs: guard
    uses: ./.github/workflows/checks.yml

  crates:
    name: publish to crates.io
    needs: ci
    runs-on: ubuntu-latest
    environment: release
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
      # netsimplex first (florecon depends on it); cargo publish waits for the
      # index so the florecon resolve succeeds. Skip versions already on
      # crates.io so re-runs / unchanged crates are idempotent.
      - name: publish netsimplex then florecon
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
        run: |
          ver() { grep -m1 '^version' "$1" | sed -E 's/.*"([^"]+)".*/\1/'; }
          publish() {
            local crate="$1" manifest="$2" v
            v=$(ver "$manifest")
            if curl -sf -A "florecon-release-ci" "https://crates.io/api/v1/crates/$crate/$v" >/dev/null; then
              echo "✓ $crate@$v already on crates.io — skipping"
            else
              echo "→ publishing $crate@$v"
              cargo publish -p "$crate"
            fi
          }
          publish netsimplex netsimplex/Cargo.toml
          publish florecon Cargo.toml