- Bump elixir requirement from ~> 1.19 to ~> 1.20 for gradual typing
- Extract SNMP polling functions from graph_live/show.ex (1492→1118 lines)
into new GraphLive.Polling module (363 lines) — 374 lines net reduction
- Defer subscriber impact API call via start_async/handle_async in
device_live/show.ex, avoiding synchronous Gaiia API call in handle_params
- Add terminate/2 to graph_live/show.ex for live_poll timer cleanup
- Fix .tool-versions to match installed Erlang 27.3.4.2
- Relax AGENTS.md dialyzer policy: allow ignore file for deps/vendored code
The Mix.Tasks.Compile.ToweropsNif module is part of the project source
and isn't on the code path when Mix first resolves compilers in a fresh
build — causes 'could not be found' in CI. NIF compilation is handled by:
- nix/shell.nix shellHook for dev (make -C c_src)
- nix/build.nix preBuild for CI/prod (injects towerops-nif package .so)
Run 'mix compile.towerops_nif' manually when changing C source in dev.
The prod build runs MIX_ENV=prod without make/gcc/net-snmp. The NIF
is pre-built by the towerops-nif Nix package and injected via
build.nix preBuild. Skip the mix compiler task in prod to avoid
'could not be found' CI errors.
oban_pro, oban_met, and oban_web are resolved via path: vendor/...
in mix.exs, so they must not have hex lock entries. The old lock
had oban_pro sourced from 'oban' (getoban.pro/repo) which would
cause hex to contact the live repo on every deps.get.
Add MIX_ENV=test mix deps.compile after NIF build. The _build/test
tree is ephemeral (cleared when nix devShell derivation changes), which
causes 'Mox is not available' errors. This ensures test deps like Mox
are ready before the user ever runs mix test.
- DeepSeek.complete: use Keyword.get/3 instead of || so passing api_key: nil
is respected even when DEEPSEEK_API_KEY env var is set (nil is explicit
'no key', not 'use default'). Also fixed base_url and model for consistency.
- test alias: add ecto.migrate after ecto.load so Oban migrations are applied,
fixing 'Found version 12, but version 14 is required' on oban 2.23
- Change postgresql_16 → postgresql_17 in shell.nix (17.10 available)
- Both postgis and timescaledb confirmed available for PG17
- Remove PG17-only transaction_timeout SET from structure.sql
(dump was already PG17, now compatible with running server)
- Auto-reinit triggers on version file mismatch
Remove conditional oban_repo_configured?() check that would pull
oban_pro from repo.oban.pro when hex config contained credentials.
The root mix.exs already provides oban_pro via vendored path.
- Register :towerops_nif compiler in mix.exs so mix compile/test builds the C NIF
- Add 'make -C c_src' to nix devShell shellHook so NIF is pre-built
- Extract init_mib_resolution/0 from Application.start/2 (reduces CC)
- Wrap NIF calls in try/rescue ErlangError for graceful fallback
- Wrap test_helper.exs NIF calls in try/rescue ErlangError
- Add .nix-postgres-version to .gitignore
Run start-services in a background subshell with stdin closed so
nix develop doesn't wait on daemonized PostgreSQL/Redis child
processes before starting the interactive shell.
The version check was after the early-exit guard, so if services were
already running it never triggered. Now it runs first, stopping and
reinitializing the cluster before checking the flag.
- Write pg derivation path to .nix-postgres-version after init
- On start, compare current pg path with stored version
- If changed (extensions added/removed/version bumped), destroy and
reinitialize the cluster automatically
- Also reinit legacy clusters that have no version file
- Exclude .nix-postgres-version from release builds
When direnv evaluates the shellHook (DIRENV_DIR is set), skip mix local,
service startup, pre-commit install, and the welcome banner. These
operations block direnv and trigger nix profile cleanup hangs on macOS.
Only run them in interactive nix develop sessions.
- Remove 'trap ... EXIT' that kills services when entering the dev shell
- Fix DATABASE_URL: $USER → $USER (no backslash) so bash expands it
instead of passing the literal string 'USER' as the PG role name
- Override mint to 1.9.3 to fix HTTP/1 chunk-size parser CVE-2026-59249
- Remove plug_cowboy dependency by switching PromEx standalone metrics server
to PromEx.Plug in the main endpoint (Bandit), eliminating cowlib CVEs
- Update castore transitive dep 1.0.19→1.0.20
- accounts.ex: convert get_user_by_email_and_password if→with-chain
with explicit User struct match and else→nil. Flatten delete_account
nested if (password check + sole-owner check) into single with-chain
with named else clauses, eliminating do_delete_account indirection.
- organizations.ex: flatten update_member_role nested if/case into
with-chain — parse_role guard → membership fetch → owner check,
each with explicit else branch. Prevents variable shadowing by using
current_role for the membership pattern match.
- capacity.ex: extract calculate_throughput_from_stats inner if into
multi-clause compute_throughput_from_pairs/1 — empty list clause
returns zero_throughput(), non-empty clause handles the computation.
- Replace gray->cool-steel, blue/indigo->cerulean, red->sweet-salmon, yellow/amber->wheat
- Dark sidebar: sidebar/footer use cool-steel-800 bg, text lightened for contrast
- ~11,600 color replacements across ~99 files
- Update tests for new color class names
- Remove daisyUI plugins and theme from app.css
- Define 5 custom color palettes: sweet-salmon, desert-sand, wheat, cool-steel, cerulean
- Add @utility card, badge, btn classes to replace daisyUI components
- Replace all daisyUI classes across 16+ template files
- Update tests for new class return values
- Set light mode as default theme