Commit graph

1953 commits

Author SHA1 Message Date
95976b6b90
perf(grid-rs): drop legacy .mp.gz write, parallelize decodes, overlap fetch+decode, cap retries
Some checks failed
Build prop-grid-rs / Test, build, push (push) Successful in 5m3s
Build and Push / Build and Push Docker Image (push) Failing after 5m57s
Four optimisations targeting the 11.4s chain-step critical path:

1. Drop legacy .mp.gz dual-write (~2.5-2.8s, 24% of step)
   The Elixir reader prefers .sgrid; the chunked gzip+msgpack write was
   pure overhead on the Rust write path. Removed scalar_future from both
   run_chain_step and run_analysis_step.

2. Parallelize wgrib2 decodes (~0.5-1s)
   sfc and prs decode ran serially (await sfc, then await prs). Both now
   spawn concurrently on the blocking pool.

3. Overlap sfc decode with prs fetch (~1-2s)
   sfc (9 messages) resolves before prs (39 messages). Start the sfc
   wgrib2 subprocess as soon as the sfc blob lands instead of waiting
   for both blobs. The sfc decode hides behind the remaining prs fetch.

4. Cap grib range retries from 5 to 3
   2^n exponential backoff meant 1+2+4+8+16 = 31s worst-case per failed
   range. Three retries caps at 1+2+4 = 7s. 404s already fail fast.

Also: instrument .sgrid write (observe_stage) so it appears in the
prop_grid_rs_stage_duration_seconds histogram alongside fetch/decode/derive.

Expected mean chain step: ~6-7s (down from 11.4s).
2026-08-01 12:48:01 -05:00
b01757b9e3
fix: revert prop-grid-rs memory limit to 3Gi after OOM at 1.5Gi
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 5m50s
2026-08-01 12:24:05 -05:00
959f3a3f69
Fix LiveView crashes and stabilize test suite
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 4m31s
2026-08-01 09:26:47 -05:00
db57b3a1c7
prop-pipeline: .sgrid dense scalars, HRDPS rotated-pole decode-once, memory trim
Some checks failed
Build prop-grid-rs / Test, build, push (push) Successful in 4m20s
Build and Push / Build and Push Docker Image (push) Failing after 4m35s
Item 1 — .sgrid dense binary scalar format replacing chunked gzip+msgpack
- New rust/prop_grid_rs/src/sgrid.rs: magic SGRD, same header layout as .pgrid,
  20-field cell-major f32 body, write_atomic (tmp+rename, NFS-safe)
- New lib/microwaveprop/weather/sgrid.ex: Elixir reader modeled on pgrid.ex
  (pread single-cell reads, bounds-filtered viewport reads, NaN→nil sentinel)
- ScalarFile updated to prefer .sgrid reads, chunked .mp.gz as fallback
- Pipeline writes .sgrid alongside existing chunked format (all three paths)

Item 2 — HRDPS decode-once + rotated-pole index, restore 0.125° resolution
- New rust/prop_grid_rs/src/rotated_pole.rs: CF-convention geographic→rotated
  transform, OnceLock-cached GDS params parsed from wgrib2 -grid, precomputed
  Vec<u32> lookup table mapping target cells to native grid indices
- Native decode path in decoder.rs: wgrib2 -no_header -order we:sn -bin
  (raw f32 dump, ~0.32 s/message) + indexing via lookup table
- HRDPS_STEP: 0.5° → 0.125° (4× finer, ~57k Canadian cells vs ~3.5k)

Item 3 — k8s memory limits: 3Gi → 1.5Gi
  (per-task grid footprint: ~200-400 MB HashMap → ~18 MB dense planes)

Item 4 — CLAUDE.md and profiles_file.ex documentation drift fixed:
  .pgrid primary, .mp.gz legacy, .sgrid added, write_atomic protocol doc,
  cleanup gaps reorganized, 'Only f00 is persisted' corrected to f00..f48
2026-08-01 09:11:59 -05:00
63f25a9612
perf(grid-rs): dense grid, fused scoring pass, and columnar .pgrid profiles
Some checks failed
Build prop-grid-rs / Test, build, push (push) Successful in 5m54s
Build and Push / Build and Push Docker Image (push) Failing after 4m44s
Reworks the post-fetch half of the propagation pipeline. Fetch and GRIB2
decode were already cheap — measured against a live HRRR cycle, all 39
pressure messages decode via `wgrib2 -lola` in 0.29 s and the 31 MB
byte-range fetch takes ~3 s — so nothing here touches the decoder. All the
cost was downstream.

Also fixes a broken NOTIFY that made every chain step run up to 5 times.

pg_notify
  `NOTIFY propagation_ready, $1` is a Postgres syntax error: NOTIFY is a
  utility statement whose payload must be a literal, so a bind raises
  42601. It shared a transaction with the `status='done'` UPDATE, so every
  successful step rolled back, stayed 'running', and was requeued by
  reclaim_stale_running up to @max_reclaim_attempts times. Elixir's
  NotifyListener never fired either, so ScoreCache warm and the
  "propagation:updated" fan-out were dead.

FieldGrid
  A decoded grid was HashMap<(i32,i32), HashMap<Arc<str>, f32>> — a dense
  rectangular grid stored as ~95k nested hash maps, costing ~4.6M inserts
  on decode, ~3.7M on merge and ~14M lookups across three derivation
  passes. wgrib2 -lola already emits one dense row-major f32 block per
  message, so keep it: dense per-message planes, names hashed once per
  grid into plane ids, NaN as the missing sentinel. This is what forced
  PROP_GRID_RS_PARALLELISM=1 under a 3Gi limit.

Fused pass
  Three 95k-cell derivation passes plus 23 band-major scoring passes over
  a staged Vec<(f64,f64,Conditions,BandInvariants)> (~19MB re-streamed 23
  times) collapse into one pass: levels extracted once per cell, all 23
  bands scored while the cell is hot, scores accumulated cell-major so
  rayon chunks own disjoint slices. Scores land straight in the dense
  score-file body — no ScorePoint scatter.

.pgrid
  The profile artifact was an rmpv tree plus gzip -9, written 30x an hour,
  and ProfilesFile.read_point/3 gunzipped and unpacked the entire 95k-cell
  file to return one cell on every map click and Skew-T load. Replaced
  with a dense cell-major f32 record array carrying a self-describing
  field table. Elixir reads it via :file.pread; .mp.gz and .etf.gz remain
  readable so files written before this drain out of the 48h window.

  Measured on a full CONUS grid (95,073 cells x 48 planes x 23 bands):
    derive + score + build artifacts   0.022 s
    profile write   3.957 s -> 0.006 s (22.0 MB -> 22.4 MB on disk)
    single-cell read   whole-file decode -> 0.5 us
    23 score files     0.003 s

Also
  - hrrr_points: batched UNNEST upsert replacing one awaited INSERT per
    point. Keeps ON CONFLICT DO UPDATE — the PSKR sampler's two-pass loop
    depends on it.
  - fetcher: real semaphore capping in-flight ranges at
    MAX_PARALLEL_RANGES, which the comment claimed but the code did not do
    (it spawned all 27 while the connection pool was sized for 8).
  - metrics: per-stage histogram. Only chain-step and decode durations
    were instrumented, which is why the write cost stayed invisible.
  - profiles_file: parse_valid_time anchors on the known extension set, so
    sibling-suffixed names like <iso>.hrdps.prop no longer parse as
    <iso>.hrdps and vanish from prune and list operations.
  - PROP_GRID_RS_PARALLELISM 1 -> 3. Memory limit held at 3Gi until RSS is
    observed at the new parallelism.
  - cargo fmt over the crate; worker.rs, hrdps_fetcher.rs and nexrad.rs
    were already unformatted at HEAD and the pre-commit hook gates on it.

HRDPS still runs at 0.5 degrees. wgrib2 -lola scales linearly in output
points on rotated lat/lon (12.5 s wall, 202 s CPU for one message at
0.125 degrees) because it has no inverse projection for those grids; a raw
native dump is 0.32 s. The fix is decode-once plus a closed-form
rotated-pole index, left for a follow-up.
2026-08-01 08:23:36 -05:00
ed8bb33acb chore(deps): bump vendored oban_web from 2.12.3 to 2.12.5
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 5m5s
Fixes two vulnerabilities:
- CVE-2026-48592: Missing authorization on save-job event handler
- CVE-2026-48593: Unbounded cron range expansion causing DoS
2026-07-30 08:30:38 -05:00
079346a1b9 fix: resolve all 281 credo issues across source and test files
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 4m38s
- F-level (228): replace length/1 with Enum.count_until/2 or pattern
  matching; convert Enum.flat_map+if to Enum.filter+Enum.map; fix
  identity case in narr_client
- W-level (46): normalize dual atom/string key access in weather_layers,
  beacon_measurements, surface, skewt_live, contact_live/show; add
  :data_provider and weather-map assigns to ignored_assigns in credo
  config (consumed by child components credo can't trace); remove
  weak is_list assertion; remove explicit assert_receive timeout
- R-level (6): replace 'This module provides...' moduledocs with
  meaningful descriptions
- Also fix 4 compile-connected xref issues by deferring
  BandConfig.band_options() from module attribute to runtime

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-29 09:04:21 -05:00
3e51e62a8b chore: add AI-drift guardrails per Zornek article
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 4m31s
- Enable key Jump credo checks: TestHasNoAssertions, VacuousTest,
  WeakAssertion, UnusedLiveViewAssign, UndeclaredExternalResource,
  AssertReceiveTimeout
- Add mix xref graph --label compile-connected --fail-above 4
- Add --warnings-as-errors to mix test step
- Add sobelow and mix_audit deps; wire into audit CI target
2026-07-29 08:00:47 -05:00
d31e783776 fix: resolve 18 bugs across LiveViews, schemas, tests, and logic
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 4m35s
- MonitorLive.Show: safe nil-guard on current_scope for anonymous access
- Admin.MonitorLive.Index: add phx-update=stream to enable stream ops
- ImportLive: require owner/admin authorization, not_found redirect
- MapLive: store timer refs in assigns, cancel before reschedule
- 10 schemas: add missing foreign_key_constraint on belongs_to
- Soundings: preload :station to eliminate N+1 in path analysis
- PathAnalysis: defensive preload of :station on soundings
- GridTaskEnqueuer: wrap reclaim_stale_running in Repo.transaction()
- HrdpsClient: replace String.to_atom with compile-time atom literals
- Contacts: fix extract_latlon false return for lon=0.0
- Tests: remove duplicate Mox.defmock, unblock swallowed task exits,
  bump refute_receive timeouts from 50ms to 200ms
2026-07-29 07:46:54 -05:00
c4e71e41b3 feat: remove skippy HRRR proxy + disk cache, fetch directly from NOAA S3
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 4m45s
- Drop skippy.w5isp.com:8080 as HRRR_BASE_URL in dev/prod config and
  all K8s manifests. Default to direct NOAA S3 reads.
- Strip hrrr_cache_dir disk-caching infrastructure from HrrrClient
  (read_cache, write_cache, download_and_cache_grib_ranges). Files are
  now fetched fresh each time — no local filesystem cache.
- Update stale skippy references in network-policy, test comments, docs.
2026-07-28 14:36:54 -05:00
db6d231887 ci: add postgres health-check options, remove fragile /dev/tcp wait
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 18m2s
2026-07-28 08:31:28 -05:00
1ceb932321 fix: use apply/3 to avoid undefined-module warnings with Conditional ML module
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 3m24s
Microwaveprop.Propagation.Model only exists in lib_ml/ which is excluded
from prod elixirc_paths. Using apply/3 instead of direct @ml_module
calls avoids compile-time warnings when the module is absent. Added
credo:disable-for-next-line inline annotations since Credo flags
apply/3 with known arity but the runtime dispatch is intentional.

Also adds --warnings-as-errors to Dockerfile RUN mix compile so the
build fails on any project-level warning.
2026-07-28 08:19:23 -05:00
9242c58a5a feat(ci): add mix test step with postgres before build-and-push
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 2m36s
Adds a postgres:17-alpine service, a wait-for-postgres step, and a
Run tests step that runs mix ecto.create/migrate/test in the same
docker-run pattern. If tests fail, the Build and push step is
automatically skipped.
2026-07-28 08:05:32 -05:00
486c1e5c66 fix(ci): install build-essential in verify step for bcrypt_elixir NIF compilation
Some checks failed
Build and Push / Build and Push Docker Image (push) Has been cancelled
2026-07-28 08:03:41 -05:00
cfa2b06617 fix(ci): install git+curl in verify-compilation container
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 30s
The hexpm/elixir slim image lacks git (needed for heroicons git dep)
and curl (needed for esbuild/tailwind binary downloads).
2026-07-28 08:02:26 -05:00
31f7db8cb1 fix(ci): replace broken volume mount with tar pipe in verify-compilation step
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 10s
The runner is containerised so the host Docker daemon cannot see its
filesystem. Replace `-v ${{ github.workspace }}:/app` with a
`tar | docker run -i ... tar xf -` pipeline to stream the workspace
into the verification container.
2026-07-28 07:35:54 -05:00
0c3be97abb
fix: resolve 27 security, architecture, test, and performance audit findings
Some checks failed
Build base image / Build and push base image (push) Successful in 3m10s
Build and Push / Build and Push Docker Image (push) Failing after 14s
Build prop-grid-rs / Test, build, push (push) Successful in 12m52s
P0 (security-critical):
- Gate CSV/ADIF upload tabs behind authentication, add 30s cooldown to all upload handlers
- Cap CSV/ADIF imports at 2,000 rows server-side in both parsers
- Add submitter_verified boolean to contacts (client-cannot-set, anonymous=false)
- Create k8s/secret.example.yaml with placeholders, add LIVE_VIEW_SIGNING_SALT

P1 (high-priority):
- Add Mox.verify_on_exit!() to valkey_test.exs
- Replace DateTime.utc_now() truncation with static ~U literals in map_live_test.exs
- Replace Process.sleep with render_async in pskr_spots_live_test.exs (6 occurrences)
- Add MonitorLive.Show test coverage (4 tests: owner view, non-owner redirect, config success/error)
- Extract duct-detection and mechanism-classification logic from ContactLive.Show into Propagation.PathAnalysis
- Split ContactLive.Show render into 12 function components
- Update CLAUDE.md: remove stale ML model, mark HRDPS active, add backtest/pskr dirs
- Batch CSV import enrichment jobs via new enqueue_for_contacts/1

P2 (medium-priority):
- Set secure:true on session and remember-me cookies in production
- Change SMTP TLS from verify_none to verify_peer with public_key cacerts
- Make /metrics fail-closed in production when PROMETHEUS_AUTH_TOKEN unset
- Add RateLimiter (anon_limit:10, auth_limit:60) to /api/contacts/map
- Add content-security-policy-report-only header
- Add comment noting String.to_atom is compile-time safe in hrdps_client.ex
- Delegate duplicated haversine_km to canonical Microwaveprop.Geo.haversine_km/4
- Consolidate score-tier/color/verdict formatting into Microwaveprop.Format
- Update CLAUDE.md testing section to match actual raw-string-matching practice
- Batch HrrrPointEnqueuer Repo.insert_all calls to single round-trip
- Split weather.ex (1696→216 lines) and radio.ex (1285→54 lines) into purpose-based sub-facades

P3 (low-priority):
- Add LIVE_VIEW_SIGNING_SALT warning comment, extend filter_parameters
- Add host/community validation to snmp_client.ex
- Add raw/1 safety comment in algo_live.ex
- Add hex-audit and cargo-audit Makefile targets
- Add privacy_live smoke test
- Replace notify_listener busy-poll loop with Process.monitor/1 + assert_receive
- Add ContactCommonVolumeRadar changeset validation tests (5 tests)
2026-07-27 18:19:37 -05:00
7bda38260d
fix: use full forgejo URL for kaniko-build action instead of github resolution
Some checks failed
Build base image / Build and push base image (push) Failing after 6s
Build and Push / Build and Push Docker Image (push) Failing after 7s
Build prop-grid-rs / Test, build, push (push) Failing after 6m38s
2026-07-27 14:22:14 -05:00
f753de6ff8
fix: use Forgejo checkout mirror instead of bare actions/checkout ref
Some checks failed
Build base image / Build and push base image (push) Failing after 2s
Build prop-grid-rs / Test, build, push (push) Failing after 2s
Build and Push / Build and Push Docker Image (push) Failing after 2s
2026-07-27 12:12:06 -05:00
83d3d68f12 chore: update all dependencies, fix Bandit CVE-2026-65623 HIGH
Some checks failed
Build prop-grid-rs / Test, build, push (push) Failing after 2s
Build and Push / Build and Push Docker Image (push) Failing after 2s
Elixir:
- bandit 1.12.0 → 1.12.4 (fixes quadratic CPU blow-up in WebSocket reassembly)
- phoenix_live_view 1.2.7 → 1.2.8
- plug_crypto 2.1.1 → 2.2.0
- lazy_html, elixir_make, glob_ex, tidewave minor bumps

Rust (83 crates):
- tokio 1.52.3 → 1.53.1
- sqlx → 0.8.6
- aws-lc-rs → 1.17.3
- uuid → 1.24.0, serde → 1.0.229
- hyper → 1.11.0, rustls → 0.23.42

mix hex.audit: clean
cargo clippy --release + cargo test --release: clean, 169 tests pass

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-27 11:35:06 -05:00
5c2ba2cd9f
chore: retrigger CI
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 1s
2026-07-27 10:35:53 -05:00
31b2516d0e
fix: use bare action refs
Some checks failed
Build base image / Build and push base image (push) Failing after 1s
Build prop-grid-rs / Test, build, push (push) Failing after 2s
Build and Push / Build and Push Docker Image (push) Failing after 2s
2026-07-27 10:19:36 -05:00
39f899ce2e
fix: use forgejo action mirrors, add pre-build compile and clippy checks
Some checks failed
Build base image / Build and push base image (push) Failing after 3s
Build prop-grid-rs / Test, build, push (push) Failing after 2s
Build and Push / Build and Push Docker Image (push) Failing after 2s
2026-07-27 08:55:38 -05:00
2af49f2ae4
Replace codeberg.org references with git.mcintire.me in Dockerfile
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 1s
2026-07-25 09:55:45 -05:00
ab23031761 Migrate images from codeberg.org to git.mcintire.me
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 2s
2026-07-24 14:38:54 -05:00
9369257ed3 Migrate images from codeberg.org to git.mcintire.me
Some checks are pending
Build and Push / Build and Push Docker Image (push) Waiting to run
2026-07-24 14:38:53 -05:00
5bb79746a4 Migrate images from codeberg.org to git.mcintire.me
Some checks are pending
Build and Push / Build and Push Docker Image (push) Waiting to run
2026-07-24 14:38:53 -05:00
0b1bc6ae24 Migrate images from codeberg.org to git.mcintire.me
Some checks are pending
Build and Push / Build and Push Docker Image (push) Waiting to run
2026-07-24 14:38:52 -05:00
0643ff76c8 Use Kaniko for Docker builds
Some checks failed
Build prop-grid-rs / Test, build, push (push) Failing after 2s
Build and Push / Build and Push Docker Image (push) Failing after 1s
2026-07-24 14:36:27 -05:00
8597b721c5 Use Kaniko for Docker builds
Some checks are pending
Build base image / Build and push base image (push) Waiting to run
Build and Push / Build and Push Docker Image (push) Waiting to run
2026-07-24 14:36:27 -05:00
6197c649b3 Use Kaniko for Docker builds
Some checks failed
Build prop-grid-rs / Test, build, push (push) Waiting to run
Build and Push / Build and Push Docker Image (push) Waiting to run
Build base image / Build and push base image (push) Failing after 2s
2026-07-24 14:36:26 -05:00
2a177676e5 Migrate from codeberg.org to git.mcintire.me
All checks were successful
Build and Push / Build and Push Docker Image (push) Successful in 3m21s
2026-07-24 14:23:22 -05:00
56b4116f6f Migrate from codeberg.org to git.mcintire.me
Some checks are pending
Build and Push / Build and Push Docker Image (push) Waiting to run
Build prop-grid-rs / Test, build, push (push) Successful in 6m44s
2026-07-24 14:23:21 -05:00
26e1163107 Migrate from codeberg.org to git.mcintire.me
Some checks are pending
Build prop-grid-rs / Test, build, push (push) Waiting to run
Build and Push / Build and Push Docker Image (push) Waiting to run
Build base image / Build and push base image (push) Successful in 4m35s
2026-07-24 14:23:20 -05:00
51678e0fb9
fix: two test issues causing 37 failures
Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 39s
1. RoverPathProfileWorker sandbox ownership: fallback_hits/2 used
   Task.async_stream spawning separate DB-querying processes that
   lacked Ecto sandbox ownership in test mode. Replaced with
   sequential Enum.map since miss list is ≤9 points — no meaningful
   perf impact and eliminates the sandbox race entirely.

2. PSKR client test: asserted '6m' band in defaults, but the actual
   microwave band name is '6cm'. Fixed assertion.
2026-07-22 16:37:17 -05:00
ca842e3add
feat(admin): beacon monitor reassign, token regen, assigned_by display, user monitor management
Uncommitted work from previous session:
- Add list_users_select/0 helper for admin select dropdowns
- Add regenerate_token/1 context function
- Preload assigned_by association on monitor queries
- Add admin nav link to beacon monitors
- Fix JS event targets (remove redundant target: @myself)
- Add reassign user form to admin monitor show page
- Add regenerate token button to admin monitor show page
- Show assigned_by admin on monitor detail page
- Add beacon monitors section to user management edit page
- Add unassign monitor capability from user management
- Add full test coverage for all new functionality
- Fix pre-existing /account route warning (redirect → /users/settings)
2026-07-22 16:27:21 -05:00
f35da3a935
beacon monitor work 2026-07-22 10:30:21 -05:00
Graham McInitre
49ade78766 fix: wire pending_edits_query as data_provider for contact edit review table
The LiveTable on /admin/contact-edits used the bare ContactEdit schema
as its data source, which caused three symptoms:
- '0 pending' counter but stale approved/rejected edits still visible
- Blank contact/submitted-by cells (select_columns stripped preloaded
  associations, cell renderers received flat maps with no :contact/:user)
- Approve/reject didn't remove the row from the table

Fix: assign {Radio, :pending_edits_query, []} as the data_provider in
mount so handle_params threads it to stream_resources. The query variant
of list_resources preserves preloaded associations and includes the
WHERE status = :pending filter.

Added two tests that verify the table rendering and edit removal.
2026-07-22 08:54:46 -05:00
fb49eb016d
feat(monitors): schema migration + remove user self-service creation
- Add hardware/config fields migration to beacon_monitors table
- Update BeaconMonitor schema with provision/config changesets
- Add context functions: create_hardware, update_config, list_all_monitors
- Remove user-facing monitor creation (browser POST + API POST)
- Update settings page: show assigned monitors table with hardware info
- Update profile page: show assigned monitors, remove register links
- Fix all tests to match new API
2026-07-21 18:28:51 -05:00
739984d3bc
feat(profile): show beacon monitors section on own user profile page
Add a Beacon monitors card to /u/:callsign that appears only when the
viewer is the profile owner. Shows registered monitors with truncated
token and last-seen timestamp, with a link to manage monitors in
settings. Includes tests for visibility rules.
2026-07-21 18:08:05 -05:00
Graham McInitre
c193f35a0c k8s/argo optimizations 2026-07-21 12:14:01 -05:00
Graham McInitre
5c6cef2227 refactor: DRY token verification — extract shared verify_hashed_token_query helper
Consolidate verify_magic_link/confirm/password_reset_token_query into
one-line delegations to a private helper, removing 29 lines of
duplicated decode/hash/query logic.
2026-07-21 11:18:15 -05:00
Graham McInitre
aa6f2ea647 fix: run all precommit targets via Makefile, exit with error at end if any fail 2026-07-21 11:15:30 -05:00
Graham McInitre
343c8ea339 fix: use Makefile for precommit — each step runs in isolated shell with MIX_ENV=test 2026-07-21 11:08:45 -05:00
Graham McInitre
e186c4c4ef fix: use sh -c wrapper for cmd in precommit to set MIX_ENV=test 2026-07-21 11:03:33 -05:00
Graham McInitre
b1b9ff63e8 fix: isolate precommit steps with cmd, split test alias from DB setup
- Move ecto.create/ecto.migrate from test alias to test.setup
- Use cmd MIX_ENV=test in precommit to isolate each step in a fresh process
- Move Mox.defmock from test_helper.exs to valkey_test.exs
2026-07-21 11:01:06 -05:00
Graham McInitre
255c99cb36 fix: unwrap Repo.transaction return values for ecto_sql 3.14, fix sandbox deadlock in rover_planning tests
- accounts.ex: Repo.transaction in ecto_sql 3.14 wraps all return values in {:ok, ...},
  causing callers to receive {:ok, {:error, ...}} and {:ok, {:ok, ...}} instead of
  direct tuples. Unwrap in update_user_email and update_user_and_delete_all_tokens.
- rover_planning_test.exs: switch to async: false + Oban.Testing manual mode so
  RoverPathProfileWorker jobs don't deadlock on sandbox connections inside
  Repo.transaction. Introduced create_and_complete_mission!/2 and run_backfill!/1
  helpers that separate transaction lifecycle from worker execution.
2026-07-21 10:24:06 -05:00
Graham McInitre
d30b6d3022 refactor: DRY extract_bearer, reuse validation helpers, add query limits
- Extract shared extract_bearer/1 from api/monitor_auth.ex → api/auth.ex
- Refactor admin_changeset to pipeline through validate_callsign/validate_name/validate_email
- Add limit: 500 to list_beacons/0 and candidate_rover_locations/1
- Combine get_mission_with_paths preloads into single round-trip
2026-07-21 10:06:12 -05:00
Graham McInitre
d3a7cfe733 fix: replace stale Flux reference with ArgoCD in kustomization.yaml 2026-07-21 08:44:19 -05:00
Graham McInitre
ae7969521a update ferqs 2026-07-20 19:55:52 -05:00