defmodule PtcLlmHttp.MixProject do use Mix.Project @app :ptc_llm_http @version "0.1.0" @source_url "https://github.com/andreasronge/ptc_llm_http" # The only consumer and this package use one supported baseline: OTP 29. # Earlier releases were useful during the transport spike, but are not part # of the package contract. Mix has no OTP requirement key, so enforce it here. @minimum_otp 29 if String.to_integer(System.otp_release()) < @minimum_otp do Mix.raise( "ptc_llm_http requires Erlang/OTP #{@minimum_otp} or later, found #{System.otp_release()}" ) end def project do [ app: @app, version: @version, # The consumer surface and development surface intentionally share one # baseline. `scripts/ci/minimum-elixir.sh` proves the library compiles # there with only its runtime dependency fetched. elixir: "~> 1.20", start_permanent: Mix.env() == :prod, elixirc_paths: elixirc_paths(Mix.env()), deps: deps(), aliases: aliases(), releases: releases(), usage_rules: usage_rules(), name: "PtcLlmHttp", description: "Bounded BEAM-native HTTP/1 transport and wire codecs for OpenAI-compatible LLM requests.", source_url: @source_url, docs: docs(), package: package(), test_coverage: [summary: [threshold: 0]], dialyzer: [ plt_core_path: dialyzer_plt_core_path(), plt_file: {:no_warn, "priv/plts/project.plt"}, plt_add_apps: [:ex_unit, :mix, :public_key, :ssl], ignore_warnings: ".dialyzer_ignore.exs", list_unused_filters: true ] ] end # The core PLT (Erlang/Elixir/OTP plus `plt_add_apps`) is identical across # every worktree of this repo, and the plan expects several agents to work in # parallel worktrees. Keeping it worktree-local would rebuild it from scratch # in each one. `plt_file` -- this project's own module signatures -- stays # worktree-local, because it legitimately differs between diverging branches # and concurrent writers would race. # # CI keeps the repo-local "priv/plts" path: `actions/cache` restores and # saves a path inside the checkout, not the user cache directory of an # ephemeral runner. defp dialyzer_plt_core_path do if System.get_env("CI") do "priv/plts" else Path.expand("~/.cache/ptc_llm_http/dialyzer_plts") end end def application do [ mod: {PtcLlmHttp.Application, []}, # `:ssl`/`:public_key`/`:crypto` are the transport's trust and handshake # sources. They are declared here so the minimal-release smoke gate # assembles them from the first commit, before the transport slice lands. extra_applications: [:crypto, :logger, :public_key, :ssl] ] end def cli do [ preferred_envs: [ check: :test, full_check: :test, soak: :test, coverage: :test ] ] end defp elixirc_paths(:test), do: ["lib", "test/support"] defp elixirc_paths(_), do: ["lib"] # Dependency rules injected into AGENTS.md by `mix usage_rules.sync`. The # bulky language and runtime rules are linked rather than inlined so the # repository instructions stay readable. defp usage_rules do [ file: "AGENTS.md", usage_rules: [ {"usage_rules:elixir", link: :markdown, main: false}, {"usage_rules:otp", link: :markdown, main: false} ] ] end # Runtime dependencies stay minimal by contract: JSON only. Req, Finch, # Mint, an HTTP server, a model database, and provider SDKs are not runtime # dependencies of this package and must not become ones. defp deps do [ {:jason, "~> 1.4"}, {:stream_data, "~> 1.1", only: [:dev, :test]}, # Test-only certificate authoring. The TLS conformance suite builds its # own CA, leaves, and adversarial chains in memory at run time, so no # private key or expiring certificate is committed to this repository. {:x509, "~> 0.9", only: :test}, {:credo, "~> 1.7", only: [:dev, :test], runtime: false}, {:ex_dna, "~> 1.5", only: [:dev, :test], runtime: false}, {:ex_slop, "~> 0.4", only: [:dev, :test], runtime: false}, {:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false}, {:ex_doc, "~> 0.31", only: :dev, runtime: false}, # Pulls Igniter, and through it Req/Finch/Mint, into the dev lock. They # are transitive dev tooling, never compiled into this application and # never reachable from `lib/`. Their presence in mix.lock is not # permission to use an HTTP client here: this package implements the # transport it needs. `scripts/ci/minimum-elixir.sh` enforces that. {:usage_rules, "~> 1.2", only: :dev, runtime: false} ] end # The gates are repository-owned shell scripts so the Git hooks, these # aliases, and GitHub Actions all run one implementation. See AGENTS.md. defp aliases do [ check: ["cmd scripts/ci/check.sh"], full_check: ["cmd scripts/ci/full_check.sh"], coverage: ["test --cover"], # Long-running resource/soak suite; excluded from `mix test` by default # (test/test_helper.exs) because its signal is a trend, not a per-commit # pass/fail. soak: ["test --only soak"] ] end # Exists only so `scripts/ci/release.sh` can assemble a minimal release and # prove application startup and TLS trust inside it. This package is a # library; consumers do not deploy this release. defp releases do [ ptc_llm_http: [ include_executables_for: [:unix] ] ] end defp docs do [ main: "readme", source_ref: "v#{@version}", extras: [ "README.md", "CHANGELOG.md", "docs/transport-backend.md", "docs/protocol-evidence.md", "LICENSE" ] ] end defp package do [ files: ~w(lib docs/transport-backend.md docs/protocol-evidence.md .formatter.exs mix.exs README.md LICENSE CHANGELOG.md), licenses: ["MIT"], links: %{ "GitHub" => @source_url, "Changelog" => "#{@source_url}/blob/main/CHANGELOG.md" } ] end end