content-addressable 0.1.1

IPLD-native content addressing: data that carries its own proof of integrity, intrinsically (BLAKE3 + CIDv1 + canonical dag-cbor).
Documentation
# HOOK PARITY: the cargo fmt/clippy/test/doc jobs AND the `leaf-deps` job are
# mirrored by .githooks/pre-push. When editing those, update the push hook to
# match. The
# build/test/clippy jobs run with `--all-features` so the default-OFF `unstable-merkle`
# feature (src/merkle.rs / MerkleNode) is actually compiled and tested; the
# `test` job additionally runs a plain `cargo test` to keep the default-feature
# surface green and to prove `unstable-merkle` stays off by default. The `doc` job runs
# rustdoc with `-D warnings` (`--all-features`) so a broken intra-doc link fails
# CI — API-surface hygiene (issue #9); it is mirrored in the hook (rustdoc is
# cheap). The `leaf-deps` job runs scripts/check-leaf-deps.sh, which asserts the
# published core crate's dependency closure is registry-only (no path/git deps),
# keeping it a true leaf (issue #13); it reads only `cargo metadata` (no build),
# so it is fast and offline and is mirrored in the hook (true parity).
#
# CI-ONLY jobs (documented exceptions, NOT in the hook):
#   - `msrv` pins `dtolnay/rust-toolchain` to 1.85 and runs build+test so a
#     transitive dep can't silently raise the real MSRV floor above the declared
#     `rust-version = "1.85"` (issue #9, gate item #10). Installing a second
#     toolchain on every push is too heavy for a fast hook, so it is CI-only —
#     the same rationale as the `python` job. The declared floor still lives in
#     Cargo.toml, which the hook respects implicitly.
#   - `python` (maturin + pytest for the PyO3 face) — building the extension
#     module is too heavy for a fast pre-push hook (the pattern kyln uses to keep
#     its p4d suite out of the hook).
# The pre-push hook records both exceptions in its header.
#
# ACTION PINNING: every third-party action is pinned to a full commit SHA with a
# human-readable version tag in a trailing comment. `.github/dependabot.yml`
# opens reviewable PRs to move these pins forward. When bumping a pin, update the
# trailing `# vX.Y.Z` comment to match — the SHA is authoritative, the comment is
# for humans. The release workflow (.github/workflows/release.yml) pins the same
# actions to the same SHAs; keep them in lockstep.
#
# LEAST PRIVILEGE: the default GITHUB_TOKEN is dropped to nothing at the workflow
# level (`permissions: {}`) and each job re-grants only `contents: read`. No CI
# job writes to the repo, publishes packages, or needs an OIDC token.

name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

permissions: {}

env:
  CARGO_TERM_COLOR: always
  RUSTFLAGS: "-D warnings"

jobs:
  build:
    name: build
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # stable
        with:
          toolchain: stable
      - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
      - name: cargo build
        run: cargo build --all-targets --all-features

  test:
    name: test
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # stable
        with:
          toolchain: stable
      - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
      - name: cargo test (default features — proves unstable-merkle stays off)
        run: cargo test
      - name: cargo test --all-features (exercises the unstable-merkle feature)
        run: cargo test --all-features

  msrv:
    name: msrv (1.85)
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      # Pin the declared MSRV floor. If a transitive dependency starts requiring
      # a newer Rust, THIS job fails — surfacing an MSRV bump as an intentional,
      # SemVer-relevant change instead of a silent drift (issue #9, gate #10).
      # These commands resolve to `default-members = ["."]` (the published core
      # crate only); the PyO3 `content-addressable-py` member is NOT built here.
      # Its PyO3/pythonize stack (pyo3 0.29) needs ~1.83, below this 1.85 floor,
      # and it is a maturin-built wheel — not the crates.io LIBRARY whose contract
      # this 1.85 floor is. Keep this job scoped to the core crate.
      - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # 1.85
        with:
          toolchain: "1.85"
      - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
      - name: cargo build (MSRV 1.85, core crate)
        run: cargo build --all-targets --all-features
      - name: cargo test (MSRV 1.85, core crate)
        run: cargo test --all-features

  clippy:
    name: clippy
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # stable
        with:
          toolchain: stable
          components: clippy
      - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
      - name: cargo clippy
        run: cargo clippy --all-targets --all-features -- -D warnings

  doc:
    name: doc (intra-doc links)
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # stable
        with:
          toolchain: stable
      - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
      # `-D warnings` turns broken intra-doc links into a hard CI failure so doc
      # rot can't return (issue #9 — public API surface hygiene).
      - name: cargo doc (deny warnings)
        run: cargo doc --no-deps --all-features
        env:
          RUSTDOCFLAGS: "-D warnings"

  fmt:
    name: fmt
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # stable
        with:
          toolchain: stable
          components: rustfmt
      - name: cargo fmt --check
        run: cargo fmt -- --check

  leaf-deps:
    name: leaf-deps (published core is a true leaf)
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # stable
        with:
          toolchain: stable
      # No build cache and no compilation: the guard only reads `cargo
      # metadata`, asserting the `content-addressable` core's resolved
      # dependency closure is registry-only (no path/git/workspace edges) so it
      # stays a publishable leaf (issue #13). The legitimate
      # `content-addressable-py -> content-addressable` path edge is a REVERSE
      # dep of the core and is never inside the core's forward closure, so the
      # guard tolerates it by construction.
      - name: check published core is a true leaf
        run: ./scripts/check-leaf-deps.sh

  python:
    name: python (PyO3 face)
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # stable
        with:
          toolchain: stable
      - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
      - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
        with:
          python-version: "3.12"
      - name: build the extension and run pytest
        run: |
          python -m venv .venv
          . .venv/bin/activate
          pip install --upgrade pip maturin pytest blake3
          maturin develop -m content-addressable-py/Cargo.toml
          pytest -q