diff --git a/.dialyzer_ignore.exs b/.dialyzer_ignore.exs index f887133..55614aa 100644 --- a/.dialyzer_ignore.exs +++ b/.dialyzer_ignore.exs @@ -10,5 +10,7 @@ # Onchain modules ~r/Function Onchain\./, # Descripex (Discoverable macro) - ~r/Function Descripex\./ + ~r/Function Descripex\./, + # ExRLP (via onchain → cartouche; transitive, only surfaces in test env via test/support) + ~r/Function ExRLP\./ ] diff --git a/.github/workflows/harness.yml b/.github/workflows/harness.yml new file mode 100644 index 0000000..23eed77 --- /dev/null +++ b/.github/workflows/harness.yml @@ -0,0 +1,77 @@ +# Deterministic Elixir harness gate for PRs. +# Closes the Codex-env-blocked-hex.pm gap: every PR push gets format / compile / +# credo / doctor / sobelow / test+cover / dialyzer evidence as PR checks, instead +# of needing a local reviewer to fetch the branch and run the suite. +# +# Versions are sourced from `.tool-versions` (asdf format) at the repo root via +# `setup-beam` — guarantees CI and local dev never drift on `mix format` output. + +name: Harness + +on: + pull_request: + branches: [main] + push: + branches: [main] + +permissions: + contents: read + +concurrency: + group: harness-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + harness: + name: Harness + runs-on: ubuntu-latest + env: + MIX_ENV: test + steps: + - uses: actions/checkout@v4 + + - id: beam + uses: erlef/setup-beam@v1 + with: + version-file: .tool-versions + version-type: strict + + - name: Cache deps & _build (covers dialyxir PLT default path) + uses: actions/cache@v4 + with: + path: | + deps + _build + priv/plts + key: mix-${{ runner.os }}-otp${{ steps.beam.outputs.otp-version }}-elixir${{ steps.beam.outputs.elixir-version }}-${{ hashFiles('**/mix.lock') }} + restore-keys: | + mix-${{ runner.os }}-otp${{ steps.beam.outputs.otp-version }}-elixir${{ steps.beam.outputs.elixir-version }}- + + - run: mix deps.get + + - name: Compile (warnings as errors) + run: mix compile --warnings-as-errors + + - name: Format check + run: mix format --check-formatted + + # TODO/FIXME tags are tracked-debt visibility, not regressions — exclude + # so harness only fails on real Credo issues (see development-philosophy.md + # § "TODO Comment Requirements"). + - name: Credo (strict, excluding TODO/FIXME design tags) + run: mix credo --strict --ignore TagTODO,TagFIXME + + - name: Doctor (--raise overrides .doctor.exs raise=false to gate CI) + run: mix doctor --raise + + - name: Sobelow (honors .sobelow-conf, exit=Low) + run: mix sobelow + + # Coverage floor: 70% — main currently sits at ~74%; raise the floor as + # coverage climbs. `mix test.json`'s test_helper excludes `:integration` + # by default, so we don't need `--exclude integration` here. + - name: Tests + coverage gate (>=70%) + run: mix test.json --cover --cover-threshold 70 --summary-only + + - name: Dialyzer + run: mix dialyzer diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..1057ddf --- /dev/null +++ b/.tool-versions @@ -0,0 +1,2 @@ +erlang 27.3.4.11 +elixir 1.18.4-otp-27